/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/builtins/builtins-console.cc
321 строка
12 KB
Michaël Zasso
deps: update V8 to 13.7.152.9
18 май 2025, 10:42
18 май 2025, 10:42
fff0d15
Код
Авторство
О чём код?
// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <stack> #include "src/api/api-inl.h" #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/debug/interface-types.h" #include "src/logging/counters.h" #include "src/logging/log.h" #include "src/objects/objects-inl.h" namespace v8 { namespace internal { // ----------------------------------------------------------------------------- // Console #define CONSOLE_METHOD_LIST(V) \ V(Dir, dir) \ V(DirXml, dirXml) \ V(Table, table) \ V(GroupEnd, groupEnd) \ V(Clear, clear) \ V(Count, count) \ V(CountReset, countReset) \ V(Profile, profile) \ V(ProfileEnd, profileEnd) #define CONSOLE_METHOD_WITH_FORMATTER_LIST(V) \ V(Debug, debug, 1) \ V(Error, error, 1) \ V(Info, info, 1) \ V(Log, log, 1) \ V(Warn, warn, 1) \ V(Trace, trace, 1) \ V(Group, group, 1) \ V(GroupCollapsed, groupCollapsed, 1) \ V(Assert, assert, 2) namespace { // 2.2 Formatter(args) [https://console.spec.whatwg.org/#formatter] // // This implements the formatter operation defined in the Console // specification to the degree that it makes sense for V8. That // means we primarily deal with %s, %i, %f, and %d, and any side // effects caused by the type conversions, and we preserve the %o, // %c, and %O specifiers and their parameters unchanged, and instead // leave it to the debugger front-end to make sense of those. // // Chrome also supports the non-standard bypass format specifier %_ // which just skips over the parameter. // // This implementation updates the |args| in-place with the results // from the conversion. // // The |index| describes the position of the format string within, // |args| (starting with 1, since |args| also includes the receiver), // which is different for example in case of `console.log` where it // is 1 compared to `console.assert` where it is 2. bool Formatter(Isolate* isolate, BuiltinArguments& args, int index) { if (args.length() < index + 2 || !IsString(args[index])) { return true; } struct State { IndirectHandle<String> str; int off; }; std::stack<State> states; HandleScope scope(isolate); auto percent = isolate->factory()->percent_sign_string(); states.push({args.at<String>(index++), 0}); while (!states.empty() && index < args.length()) { State& state = states.top(); state.off = String::IndexOf(isolate, state.str, percent, state.off); if (state.off < 0 || state.off == static_cast<int>(state.str->length()) - 1) { states.pop(); continue; } IndirectHandle<Object> current = args.at(index); uint16_t specifier = state.str->Get(state.off + 1, isolate); if (specifier == 'd' || specifier == 'f' || specifier == 'i') { if (IsSymbol(*current)) { current = isolate->factory()->nan_value(); } else { DirectHandle<Object> params[] = { current, isolate->factory()->NewNumberFromInt(10)}; auto builtin = specifier == 'f' ? isolate->global_parse_float_fun() : isolate->global_parse_int_fun(); if (!Execution::CallBuiltin(isolate, builtin, isolate->factory()->undefined_value(), base::VectorOf(params)) .ToHandle(¤t)) { return false; } } } else if (specifier == 's') { DirectHandle<Object> params[] = {current}; if (!Execution::CallBuiltin(isolate, isolate->string_function(), isolate->factory()->undefined_value(), base::VectorOf(params)) .ToHandle(¤t)) { return false; } // Recurse into string results from type conversions, as they // can themselves contain formatting specifiers. states.push({Cast<String>(current), 0}); } else if (specifier == 'c' || specifier == 'o' || specifier == 'O' || specifier == '_') { // We leave the interpretation of %c (CSS), %o (optimally useful // formatting), and %O (generic JavaScript object formatting) as // well as the non-standard %_ (bypass formatter in Chrome) to // the debugger front-end, and preserve these specifiers as well // as their arguments verbatim. index++; state.off += 2; continue; } else if (specifier == '%') { // Chrome also supports %% as a way to generate a single % in the // output. state.off += 2; continue; } else { state.off++; continue; } // Replace the |specifier| (including the '%' character) in |target| // with the |current| value. We perform the replacement only morally // by updating the argument to the conversion result, but leave it to // the debugger front-end to perform the actual substitution. args.set_at(index++, *current); state.off += 2; } return true; } // The closures installed on objects returned from `console.context()` // get a special builtin context with 2 slots, to hold the unique ID of // the console context and its name. enum { CONSOLE_CONTEXT_ID_INDEX = Context::MIN_CONTEXT_SLOTS, CONSOLE_CONTEXT_NAME_INDEX, CONSOLE_CONTEXT_SLOTS, }; void ConsoleCall( Isolate* isolate, const internal::BuiltinArguments& args, void (debug::ConsoleDelegate::*func)(const v8::debug::ConsoleCallArguments&, const v8::debug::ConsoleContext&)) { if (isolate->is_execution_terminating()) return; CHECK(!isolate->has_exception()); if (!isolate->console_delegate()) return; HandleScope scope(isolate); int context_id = 0; DirectHandle<String> context_name = isolate->factory()->anonymous_string(); if (!IsNativeContext(args.target()->context())) { DirectHandle<Context> context(args.target()->context(), isolate); CHECK_EQ(CONSOLE_CONTEXT_SLOTS, context->length()); context_id = Cast<Smi>(context->GetNoCell(CONSOLE_CONTEXT_ID_INDEX)).value(); context_name = direct_handle( Cast<String>(context->GetNoCell(CONSOLE_CONTEXT_NAME_INDEX)), isolate); } (isolate->console_delegate()->*func)( debug::ConsoleCallArguments(isolate, args), v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name))); } void LogTimerEvent(Isolate* isolate, BuiltinArguments args, v8::LogEventStatus se) { if (!v8_flags.log_timer_events) return; HandleScope scope(isolate); std::unique_ptr<char[]> name; const char* raw_name = "default"; if (args.length() > 1 && IsString(args[1])) { // Try converting the first argument to a string. name = args.at<String>(1)->ToCString(); raw_name = name.get(); } LOG(isolate, TimerEvent(se, raw_name)); } } // namespace #define CONSOLE_BUILTIN_IMPLEMENTATION(call, name) \ BUILTIN(Console##call) { \ ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \ RETURN_FAILURE_IF_EXCEPTION(isolate); \ return ReadOnlyRoots(isolate).undefined_value(); \ } CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION) #undef CONSOLE_BUILTIN_IMPLEMENTATION #define CONSOLE_BUILTIN_IMPLEMENTATION(call, name, index) \ BUILTIN(Console##call) { \ if (!Formatter(isolate, args, index)) { \ return ReadOnlyRoots(isolate).exception(); \ } \ ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \ RETURN_FAILURE_IF_EXCEPTION(isolate); \ return ReadOnlyRoots(isolate).undefined_value(); \ } CONSOLE_METHOD_WITH_FORMATTER_LIST(CONSOLE_BUILTIN_IMPLEMENTATION) #undef CONSOLE_BUILTIN_IMPLEMENTATION BUILTIN(ConsoleTime) { LogTimerEvent(isolate, args, v8::LogEventStatus::kStart); ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time); RETURN_FAILURE_IF_EXCEPTION(isolate); return ReadOnlyRoots(isolate).undefined_value(); } BUILTIN(ConsoleTimeEnd) { LogTimerEvent(isolate, args, v8::LogEventStatus::kEnd); ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd); RETURN_FAILURE_IF_EXCEPTION(isolate); return ReadOnlyRoots(isolate).undefined_value(); } BUILTIN(ConsoleTimeLog) { LogTimerEvent(isolate, args, v8::LogEventStatus::kLog); ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeLog); RETURN_FAILURE_IF_EXCEPTION(isolate); return ReadOnlyRoots(isolate).undefined_value(); } BUILTIN(ConsoleTimeStamp) { ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp); RETURN_FAILURE_IF_EXCEPTION(isolate); return ReadOnlyRoots(isolate).undefined_value(); } namespace { void InstallContextFunction(Isolate* isolate, DirectHandle<JSObject> target, const char* name, Builtin builtin, DirectHandle<Context> context) { Factory* const factory = isolate->factory(); DirectHandle<Map> map = isolate->sloppy_function_without_prototype_map(); DirectHandle<String> name_string = factory->InternalizeUtf8String(name); DirectHandle<SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin(name_string, builtin, 1, kDontAdapt); info->set_language_mode(LanguageMode::kSloppy); info->set_native(true); DirectHandle<JSFunction> fun = Factory::JSFunctionBuilder{isolate, info, context}.set_map(map).Build(); JSObject::AddProperty(isolate, target, name_string, fun, NONE); } } // namespace BUILTIN(ConsoleContext) { HandleScope scope(isolate); Factory* const factory = isolate->factory(); isolate->CountUsage(v8::Isolate::UseCounterFeature::kConsoleContext); // Generate a unique ID for the new `console.context` // and convert the parameter to a string (defaults to // 'anonymous' if unspecified). DirectHandle<String> context_name = factory->anonymous_string(); if (args.length() > 1) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, context_name, Object::ToString(isolate, args.at(1))); } int context_id = isolate->last_console_context_id() + 1; isolate->set_last_console_context_id(context_id); DirectHandle<SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin( factory->InternalizeUtf8String("Context"), Builtin::kIllegal, 0, kDontAdapt); info->set_language_mode(LanguageMode::kSloppy); DirectHandle<JSFunction> cons = Factory::JSFunctionBuilder{isolate, info, isolate->native_context()} .Build(); DirectHandle<JSObject> prototype = factory->NewJSObject(isolate->object_function()); JSFunction::SetPrototype(isolate, cons, prototype); DirectHandle<JSObject> console_context = factory->NewJSObject(cons, AllocationType::kOld); DCHECK(IsJSObject(*console_context)); DirectHandle<Context> context = factory->NewBuiltinContext( isolate->native_context(), CONSOLE_CONTEXT_SLOTS); context->SetNoCell(CONSOLE_CONTEXT_ID_INDEX, Smi::FromInt(context_id)); context->SetNoCell(CONSOLE_CONTEXT_NAME_INDEX, *context_name); #define CONSOLE_BUILTIN_SETUP(call, name, ...) \ InstallContextFunction(isolate, console_context, #name, \ Builtin::kConsole##call, context); CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP) CONSOLE_METHOD_WITH_FORMATTER_LIST(CONSOLE_BUILTIN_SETUP) CONSOLE_BUILTIN_SETUP(Time, time) CONSOLE_BUILTIN_SETUP(TimeLog, timeLog) CONSOLE_BUILTIN_SETUP(TimeEnd, timeEnd) CONSOLE_BUILTIN_SETUP(TimeStamp, timeStamp) #undef CONSOLE_BUILTIN_SETUP return *console_context; } #undef CONSOLE_METHOD_LIST } // namespace internal } // namespace v8