/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/debug/debug-interface.cc
1 516 строк
58 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2021 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 "src/debug/debug-interface.h" #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/base/utils/random-number-generator.h" #include "src/codegen/compiler.h" #include "src/codegen/script-details.h" #include "src/date/date.h" #include "src/debug/debug-coverage.h" #include "src/debug/debug-evaluate.h" #include "src/debug/debug-property-iterator.h" #include "src/debug/debug-stack-trace-iterator.h" #include "src/debug/debug.h" #include "src/execution/vm-state-inl.h" #include "src/heap/heap.h" #include "src/objects/js-generator-inl.h" #include "src/profiler/heap-profiler.h" #include "src/strings/string-builder-inl.h" #if V8_ENABLE_WEBASSEMBLY #include "src/debug/debug-wasm-objects-inl.h" #include "src/wasm/wasm-disassembler.h" #include "src/wasm/wasm-engine.h" #endif // V8_ENABLE_WEBASSEMBLY namespace v8 { namespace debug { void SetContextId(Local<Context> context, int id) { auto v8_context = Utils::OpenDirectHandle(*context); auto* i_isolate = i::Isolate::Current(); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); v8_context->set_debug_context_id(i::Smi::FromInt(id)); } int GetContextId(Local<Context> context) { auto v8_context = Utils::OpenDirectHandle(*context); auto* i_isolate = i::Isolate::Current(); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); i::Tagged<i::Object> value = v8_context->debug_context_id(); return (IsSmi(value)) ? i::Smi::ToInt(value) : 0; } void SetInspector(Isolate* isolate, v8_inspector::V8Inspector* inspector) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); if (inspector == nullptr) { i_isolate->set_inspector(nullptr); } else { i_isolate->set_inspector(inspector); } } v8_inspector::V8Inspector* GetInspector(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); return i_isolate->inspector(); } namespace { i::Handle<i::String> GetBigIntStringPresentationHandle( i::Isolate* i_isolate, i::DirectHandle<i::BigInt> i_bigint) { // For large BigInts computing the decimal string representation // can take a long time, so we go with hexadecimal in that case. int radix = (i_bigint->Words64Count() > 100 * 1000) ? 16 : 10; i::Handle<i::String> string_value = i::BigInt::ToString(i_isolate, i_bigint, radix, i::kDontThrow) .ToHandleChecked(); if (radix == 16) { if (i_bigint->IsNegative()) { string_value = i_isolate->factory() ->NewConsString( i_isolate->factory()->NewStringFromAsciiChecked("-0x"), i_isolate->factory()->NewProperSubString( string_value, 1, string_value->length() - 1)) .ToHandleChecked(); } else { string_value = i_isolate->factory() ->NewConsString( i_isolate->factory()->NewStringFromAsciiChecked("0x"), string_value) .ToHandleChecked(); } } return string_value; } } // namespace Local<String> GetBigIntStringValue(Isolate* isolate, Local<BigInt> bigint) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); EnterV8NoScriptNoExceptionScope api_scope(i_isolate); i::DirectHandle<i::BigInt> i_bigint = Utils::OpenDirectHandle(*bigint); i::DirectHandle<i::String> string_value = GetBigIntStringPresentationHandle(i_isolate, i_bigint); return Utils::ToLocal(string_value); } Local<String> GetBigIntDescription(Isolate* isolate, Local<BigInt> bigint) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); EnterV8NoScriptNoExceptionScope api_scope(i_isolate); i::DirectHandle<i::BigInt> i_bigint = Utils::OpenDirectHandle(*bigint); i::Handle<i::String> string_value = GetBigIntStringPresentationHandle(i_isolate, i_bigint); i::DirectHandle<i::String> description = i_isolate->factory() ->NewConsString(string_value, i_isolate->factory()->n_string()) .ToHandleChecked(); return Utils::ToLocal(description); } Local<String> GetDateDescription(Local<Date> date) { auto receiver = Utils::OpenDirectHandle(*date); auto jsdate = i::Cast<i::JSDate>(receiver); i::Isolate* i_isolate = i::Isolate::Current(); EnterV8NoScriptNoExceptionScope api_scope(i_isolate); auto buffer = i::ToDateString(jsdate->value(), i_isolate->date_cache(), i::ToDateStringMode::kLocalDateAndTime); return Utils::ToLocal(i_isolate->factory() ->NewStringFromUtf8(base::VectorOf(buffer)) .ToHandleChecked()); } Local<String> GetFunctionDescription(Local<Function> function) { auto receiver = Utils::OpenHandle(*function); auto i_isolate = i::Isolate::Current(); EnterV8NoScriptNoExceptionScope api_scope(i_isolate); if (IsJSBoundFunction(*receiver)) { return Utils::ToLocal(i::JSBoundFunction::ToString( i_isolate, i::Cast<i::JSBoundFunction>(receiver))); } if (IsJSFunction(*receiver)) { auto js_function = i::Cast<i::JSFunction>(receiver); #if V8_ENABLE_WEBASSEMBLY if (js_function->shared()->HasWasmExportedFunctionData(i_isolate)) { i::DirectHandle<i::WasmExportedFunctionData> function_data( js_function->shared()->wasm_exported_function_data(), i_isolate); int func_index = function_data->function_index(); i::DirectHandle<i::WasmTrustedInstanceData> instance_data( function_data->instance_data(), i_isolate); if (instance_data->module()->origin == i::wasm::kWasmOrigin) { // For asm.js functions, we can still print the source // code (hopefully), so don't bother with them here. auto debug_name = i::GetWasmFunctionDebugName(i_isolate, instance_data, func_index); i::IncrementalStringBuilder builder(i_isolate); builder.AppendCStringLiteral("function "); builder.AppendString(debug_name); builder.AppendCStringLiteral("() { [native code] }"); return Utils::ToLocal(builder.Finish().ToHandleChecked()); } } #endif // V8_ENABLE_WEBASSEMBLY return Utils::ToLocal(i::JSFunction::ToString(i_isolate, js_function)); } return Utils::ToLocal(i_isolate->factory()->function_native_code_string()); } void SetBreakOnNextFunctionCall(Isolate* isolate) { auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); i_isolate->debug()->SetBreakOnNextFunctionCall(); } void ClearBreakOnNextFunctionCall(Isolate* isolate) { auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); i_isolate->debug()->ClearBreakOnNextFunctionCall(); } MaybeLocal<Array> GetInternalProperties(Isolate* v8_isolate, Local<Value> value) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); i::DirectHandle<i::Object> val = Utils::OpenDirectHandle(*value); i::DirectHandle<i::JSArray> result; if (!i::Runtime::GetInternalProperties(isolate, val).ToHandle(&result)) return MaybeLocal<Array>(); return Utils::ToLocal(result); } namespace { using FlagFilter = std::function<bool(i::IsStaticFlag)>; using VariableModeFilter = std::function<bool(i::VariableMode)>; using ContextLocalIterator = std::function<void( i::VariableMode, i::Handle<i::String>, i::Handle<i::Object>)>; void ForEachContextLocal(i::Isolate* isolate, i::DirectHandle<i::Context> context, const VariableModeFilter& var_mode_filter, const FlagFilter& flag_filter, const ContextLocalIterator& context_local_it) { i::DisallowJavascriptExecutionDebugOnly no_execution(isolate); i::DisallowExceptionsDebugOnly no_exceptions(isolate); i::DirectHandle<i::ScopeInfo> scope_info(context->scope_info(), isolate); for (auto it : i::ScopeInfo::IterateLocalNames(scope_info)) { i::Handle<i::String> name(it->name(), isolate); i::VariableMode mode = scope_info->ContextLocalMode(it->index()); if (!var_mode_filter(mode)) { continue; } i::IsStaticFlag flag = scope_info->ContextLocalIsStaticFlag(it->index()); if (!flag_filter(flag)) { continue; } int context_index = scope_info->ContextHeaderLength() + it->index(); i::Handle<i::Object> slot_value(context->GetNoCell(context_index), isolate); context_local_it(mode, name, slot_value); } } } // namespace bool GetPrivateMembers(Local<Context> context, Local<Object> object, int filter, LocalVector<Value>* names_out, LocalVector<Value>* values_out) { i::Isolate* isolate = i::Isolate::Current(); ApiRuntimeCallStatsScope rcs_scope( isolate, i::RuntimeCallCounterId::kAPI_debug_GetPrivateMembers); EnterV8NoScriptNoExceptionScope api_scope(isolate); bool include_methods = filter & static_cast<int>(PrivateMemberFilter::kPrivateMethods); bool include_fields = filter & static_cast<int>(PrivateMemberFilter::kPrivateFields); bool include_accessors = filter & static_cast<int>(PrivateMemberFilter::kPrivateAccessors); bool include_methods_or_accessors = include_methods || include_accessors; auto var_mode_filter = include_methods ? (include_accessors ? i::IsPrivateMethodOrAccessorVariableMode : i::IsPrivateMethodVariableMode) : i::IsPrivateAccessorVariableMode; auto constexpr instance_filter = [](i::IsStaticFlag flag) { return flag == i::IsStaticFlag::kNotStatic; }; auto constexpr static_filter = [](i::IsStaticFlag flag) { return flag == i::IsStaticFlag::kStatic; }; i::DirectHandle<i::JSReceiver> receiver = Utils::OpenDirectHandle(*object); i::PropertyFilter key_filter = static_cast<i::PropertyFilter>(i::PropertyFilter::PRIVATE_NAMES_ONLY); i::DirectHandle<i::FixedArray> keys; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, keys, i::KeyAccumulator::GetKeys(isolate, receiver, i::KeyCollectionMode::kOwnOnly, key_filter, i::GetKeysConversion::kConvertToString), false); // Estimate number of private fields and private instance methods/accessors. int private_entries_count = 0; auto count_private_entry = [&](i::VariableMode mode, i::DirectHandle<i::String>, i::DirectHandle<i::Object>) { private_entries_count++; }; for (int i = 0; i < keys->length(); ++i) { // Exclude the private brand symbols. i::DirectHandle<i::Symbol> key(i::Cast<i::Symbol>(keys->get(i)), isolate); if (key->is_private_brand()) { if (include_methods_or_accessors) { i::DirectHandle<i::Object> value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value, i::Object::GetProperty(isolate, receiver, key), false); i::DirectHandle<i::Context> value_context(i::Cast<i::Context>(*value), isolate); ForEachContextLocal(isolate, value_context, var_mode_filter, instance_filter, count_private_entry); } } else if (include_fields) { private_entries_count++; } } // Estimate number of static private methods/accessors for classes. bool has_static_private_methods_or_accessors = false; if (include_methods_or_accessors) { if (IsJSFunction(*receiver)) { i::DirectHandle<i::JSFunction> func(i::Cast<i::JSFunction>(*receiver), isolate); i::DirectHandle<i::SharedFunctionInfo> shared(func->shared(), isolate); if (shared->is_class_constructor() && shared->has_static_private_methods_or_accessors()) { has_static_private_methods_or_accessors = true; i::DirectHandle<i::Context> func_context(func->context(), isolate); ForEachContextLocal(isolate, func_context, var_mode_filter, static_filter, count_private_entry); } } } DCHECK(names_out->empty()); names_out->reserve(private_entries_count); DCHECK(values_out->empty()); values_out->reserve(private_entries_count); auto add_private_entry = [&](i::VariableMode mode, i::DirectHandle<i::String> name, i::DirectHandle<i::Object> value) { DCHECK_IMPLIES(mode == i::VariableMode::kPrivateMethod, IsJSFunction(*value)); DCHECK_IMPLIES(mode != i::VariableMode::kPrivateMethod, IsAccessorPair(*value)); names_out->push_back(Utils::ToLocal(name)); values_out->push_back(Utils::ToLocal(value)); }; if (has_static_private_methods_or_accessors) { i::DirectHandle<i::Context> receiver_context( i::Cast<i::JSFunction>(*receiver)->context(), isolate); ForEachContextLocal(isolate, receiver_context, var_mode_filter, static_filter, add_private_entry); } for (int i = 0; i < keys->length(); ++i) { i::DirectHandle<i::Object> obj_key(keys->get(i), isolate); i::DirectHandle<i::Symbol> key(i::Cast<i::Symbol>(*obj_key), isolate); CHECK(key->is_any_private_name()); i::DirectHandle<i::Object> value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value, i::Object::GetProperty(isolate, receiver, key), false); if (key->is_private_brand()) { if (include_methods_or_accessors) { DCHECK(IsContext(*value)); i::DirectHandle<i::Context> value_context(i::Cast<i::Context>(*value), isolate); ForEachContextLocal(isolate, value_context, var_mode_filter, instance_filter, add_private_entry); } } else if (include_fields) { // Private fields i::DirectHandle<i::String> name( i::Cast<i::String>(i::Cast<i::Symbol>(*key)->description()), isolate); names_out->push_back(Utils::ToLocal(name)); values_out->push_back(Utils::ToLocal(value)); } } DCHECK_EQ(names_out->size(), values_out->size()); DCHECK_LE(names_out->size(), private_entries_count); return true; } MaybeLocal<Context> GetCreationContext(Local<Object> value) { if (IsJSGlobalProxy(*Utils::OpenDirectHandle(*value))) { return MaybeLocal<Context>(); } START_ALLOW_USE_DEPRECATED(); return value->GetCreationContext(); END_ALLOW_USE_DEPRECATED(); } void ChangeBreakOnException(Isolate* isolate, ExceptionBreakState type) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(i_isolate); i::DisallowExceptionsDebugOnly no_exceptions(i_isolate); i_isolate->debug()->ChangeBreakOnException( i::BreakCaughtException, type == BreakOnCaughtException || type == BreakOnAnyException); i_isolate->debug()->ChangeBreakOnException( i::BreakUncaughtException, type == BreakOnUncaughtException || type == BreakOnAnyException); } void SetBreakPointsActive(Isolate* v8_isolate, bool is_active) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); isolate->debug()->set_break_points_active(is_active); } void PrepareStep(Isolate* v8_isolate, StepAction action) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8BasicScope api_scope(isolate); CHECK(isolate->debug()->CheckExecutionState()); // Clear all current stepping setup. isolate->debug()->ClearStepping(); // Prepare step. isolate->debug()->PrepareStep(static_cast<i::StepAction>(action)); } bool PrepareRestartFrame(Isolate* v8_isolate, int callFrameOrdinal) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8BasicScope api_scope(isolate); CHECK(isolate->debug()->CheckExecutionState()); i::DebugStackTraceIterator it(isolate, callFrameOrdinal); if (it.Done() || !it.CanBeRestarted()) return false; // Clear all current stepping setup. isolate->debug()->ClearStepping(); it.PrepareRestart(); return true; } void ClearStepping(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); // Clear all current stepping setup. isolate->debug()->ClearStepping(); } void BreakRightNow(Isolate* v8_isolate, base::EnumSet<debug::BreakReason> break_reasons) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8BasicScope api_scope(isolate); isolate->debug()->HandleDebugBreak(i::kIgnoreIfAllFramesBlackboxed, break_reasons); } void SetTerminateOnResume(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); isolate->debug()->SetTerminateOnResume(); } bool CanBreakProgram(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8BasicScope api_scope(isolate); return !isolate->debug()->AllFramesOnStackAreBlackboxed(); } size_t ScriptSource::Length() const { auto source = Utils::OpenDirectHandle(this); if (IsString(*source)) { return i::Cast<i::String>(source)->length(); } return Size(); } size_t ScriptSource::Size() const { #if V8_ENABLE_WEBASSEMBLY MemorySpan<const uint8_t> wasm_bytecode; if (WasmBytecode().To(&wasm_bytecode)) { return wasm_bytecode.size(); } #endif // V8_ENABLE_WEBASSEMBLY auto source = Utils::OpenDirectHandle(this); if (!IsString(*source)) return 0; auto string = i::Cast<i::String>(source); return string->length() * (string->IsTwoByteRepresentation() ? 2 : 1); } MaybeLocal<String> ScriptSource::JavaScriptCode() const { i::DirectHandle<i::HeapObject> source = Utils::OpenDirectHandle(this); if (!IsString(*source)) return MaybeLocal<String>(); return Utils::ToLocal(i::Cast<i::String>(source)); } #if V8_ENABLE_WEBASSEMBLY Maybe<MemorySpan<const uint8_t>> ScriptSource::WasmBytecode() const { auto source = Utils::OpenDirectHandle(this); if (!IsForeign(*source)) return {}; base::Vector<const uint8_t> wire_bytes = i::Cast<i::Managed<i::wasm::NativeModule>>(*source)->raw()->wire_bytes(); return Just(MemorySpan<const uint8_t>{wire_bytes.begin(), wire_bytes.size()}); } #endif // V8_ENABLE_WEBASSEMBLY ScriptOriginOptions Script::OriginOptions() const { return Utils::OpenDirectHandle(this)->origin_options(); } bool Script::WasCompiled() const { return Utils::OpenDirectHandle(this)->compilation_state() == i::Script::CompilationState::kCompiled; } bool Script::IsEmbedded() const { auto script = Utils::OpenDirectHandle(this); return script->context_data() == i::GetReadOnlyRoots().uninitialized_symbol(); } int Script::Id() const { return Utils::OpenDirectHandle(this)->id(); } int Script::StartLine() const { return Utils::OpenDirectHandle(this)->line_offset(); } int Script::StartColumn() const { return Utils::OpenDirectHandle(this)->column_offset(); } int Script::EndLine() const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) return 0; #endif // V8_ENABLE_WEBASSEMBLY if (!IsString(script->source())) { return script->line_offset(); } i::Isolate* isolate = i::Isolate::Current(); i::HandleScope scope(isolate); i::Script::PositionInfo info; i::Script::GetPositionInfo( script, i::Cast<i::String>(script->source())->length(), &info); return info.line; } int Script::EndColumn() const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) { return script->wasm_native_module()->wire_bytes().length(); } #endif // V8_ENABLE_WEBASSEMBLY if (!IsString(script->source())) { return script->column_offset(); } i::Isolate* isolate = i::Isolate::Current(); i::HandleScope scope(isolate); i::Script::PositionInfo info; i::Script::GetPositionInfo( script, i::Cast<i::String>(script->source())->length(), &info); return info.column; } MaybeLocal<String> Script::Name() const { auto script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Object> value(script->name(), isolate); if (!IsString(*value)) return MaybeLocal<String>(); return Utils::ToLocal(i::Cast<i::String>(value)); } MaybeLocal<String> Script::SourceURL() const { auto script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::PrimitiveHeapObject> value(script->source_url(), isolate); if (!IsString(*value)) return MaybeLocal<String>(); return Utils::ToLocal(i::Cast<i::String>(value)); } MaybeLocal<String> Script::SourceMappingURL() const { auto script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Object> value(script->source_mapping_url(), isolate); if (!IsString(*value)) return MaybeLocal<String>(); return Utils::ToLocal(i::Cast<i::String>(value)); } MaybeLocal<String> Script::DebugId() const { auto script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Object> value(script->debug_id(), isolate); if (!IsString(*value)) return MaybeLocal<String>(); return Utils::ToLocal(i::Cast<i::String>(value)); } MaybeLocal<String> Script::GetSha256Hash() const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::String> value = i::Script::GetScriptHash(isolate, script, /* forceForInspector: */ true); return Utils::ToLocal(value); } Maybe<int> Script::ContextId() const { auto script = Utils::OpenDirectHandle(this); i::Tagged<i::Object> value = script->context_data(); if (IsSmi(value)) return Just(i::Smi::ToInt(value)); return {}; } Local<ScriptSource> Script::Source() const { auto script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) { i::DirectHandle<i::Object> wasm_native_module( script->wasm_managed_native_module(), isolate); return Utils::Convert<i::Object, ScriptSource>(wasm_native_module); } #endif // V8_ENABLE_WEBASSEMBLY i::DirectHandle<i::PrimitiveHeapObject> source(script->source(), isolate); return Utils::Convert<i::PrimitiveHeapObject, ScriptSource>(source); } #if V8_ENABLE_WEBASSEMBLY bool Script::IsWasm() const { return Utils::OpenDirectHandle(this)->type() == i::Script::Type::kWasm; } #endif // V8_ENABLE_WEBASSEMBLY bool Script::IsModule() const { return Utils::OpenDirectHandle(this)->origin_options().IsModule(); } namespace { int GetSmiValue(i::DirectHandle<i::FixedArray> array, int index) { return i::Smi::ToInt(array->get(index)); } bool CompareBreakLocation(const i::BreakLocation& loc1, const i::BreakLocation& loc2) { return loc1.position() < loc2.position(); } } // namespace bool Script::GetPossibleBreakpoints( const Location& start, const Location& end, bool restrict_to_function, std::vector<BreakLocation>* locations) const { CHECK(!start.IsEmpty()); i::Handle<i::Script> script = Utils::OpenHandle(this); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) { i::wasm::NativeModule* native_module = script->wasm_native_module(); return i::WasmScript::GetPossibleBreakpoints(native_module, start, end, locations); } #endif // V8_ENABLE_WEBASSEMBLY i::Isolate* isolate = i::Isolate::Current(); int start_offset, end_offset; if (!GetSourceOffset(start, GetSourceOffsetMode::kClamp).To(&start_offset)) { return false; } if (end.IsEmpty()) { end_offset = std::numeric_limits<int>::max(); } else if (!GetSourceOffset(end, GetSourceOffsetMode::kClamp) .To(&end_offset)) { return false; } if (start_offset >= end_offset) return true; std::vector<i::BreakLocation> v8_locations; if (!isolate->debug()->GetPossibleBreakpoints( script, start_offset, end_offset, restrict_to_function, &v8_locations)) { return false; } std::sort(v8_locations.begin(), v8_locations.end(), CompareBreakLocation); for (const auto& v8_location : v8_locations) { Location location = GetSourceLocation(v8_location.position()); locations->emplace_back(location.GetLineNumber(), location.GetColumnNumber(), v8_location.type()); } return true; } Maybe<int> Script::GetSourceOffset(const Location& location, GetSourceOffsetMode mode) const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) { return location.GetLineNumber() == 0 ? Just(location.GetColumnNumber()) : Nothing<int>(); } #endif // V8_ENABLE_WEBASSEMBLY int line = location.GetLineNumber(); int column = location.GetColumnNumber(); if (!script->HasSourceURLComment()) { // Line/column number for inline <script>s with sourceURL annotation // are supposed to be related to the <script> tag, otherwise they // are relative to the parent file. Keep this in sync with the logic // in GetSourceLocation() below. line -= script->line_offset(); if (line == 0) column -= script->column_offset(); } i::Isolate* isolate = i::Isolate::Current(); i::Script::InitLineEnds(isolate, script); auto line_ends = i::Cast<i::FixedArray>(i::direct_handle(script->line_ends(), isolate)); if (line < 0) { if (mode == GetSourceOffsetMode::kClamp) { return Just(0); } return {}; } if (line >= line_ends->length()) { if (mode == GetSourceOffsetMode::kClamp) { return Just(GetSmiValue(line_ends, line_ends->length() - 1)); } return {}; } if (column < 0) { if (mode != GetSourceOffsetMode::kClamp) { return {}; } column = 0; } int offset = column; if (line > 0) { int prev_line_end_offset = GetSmiValue(line_ends, line - 1); offset += prev_line_end_offset + 1; } int line_end_offset = GetSmiValue(line_ends, line); if (offset > line_end_offset) { // Be permissive with columns that don't exist, // as long as they are clearly within the range // of the script. if (line < line_ends->length() - 1 || mode == GetSourceOffsetMode::kClamp) { return Just(line_end_offset); } return {}; } return Just(offset); } Location Script::GetSourceLocation(int offset) const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); i::Script::PositionInfo info; i::Script::GetPositionInfo(script, offset, &info); if (script->HasSourceURLComment()) { // Line/column number for inline <script>s with sourceURL annotation // are supposed to be related to the <script> tag, otherwise they // are relative to the parent file. Keep this in sync with the logic // in GetSourceOffset() above. info.line -= script->line_offset(); if (info.line == 0) info.column -= script->column_offset(); } return Location(info.line, info.column); } bool Script::SetScriptSource(Local<String> newSource, bool preview, bool allow_top_frame_live_editing, LiveEditResult* result) const { i::Handle<i::Script> script = Utils::OpenHandle(this); i::Isolate* isolate = i::Isolate::Current(); return isolate->debug()->SetScriptSource( script, Utils::OpenHandle(*newSource), preview, allow_top_frame_live_editing, result); } bool Script::SetBreakpoint(Local<String> condition, Location* location, BreakpointId* id) const { i::Handle<i::Script> script = Utils::OpenHandle(this); i::Isolate* isolate = i::Isolate::Current(); int offset; if (!GetSourceOffset(*location).To(&offset)) { return false; } if (!isolate->debug()->SetBreakPointForScript( script, Utils::OpenDirectHandle(*condition), &offset, id)) { return false; } *location = GetSourceLocation(offset); return true; } bool Script::SetInstrumentationBreakpoint(BreakpointId* id) const { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); #if V8_ENABLE_WEBASSEMBLY if (script->type() == i::Script::Type::kWasm) { isolate->debug()->SetInstrumentationBreakpointForWasmScript(script, id); return true; } #endif // V8_ENABLE_WEBASSEMBLY i::SharedFunctionInfo::ScriptIterator it(isolate, *script); for (i::Tagged<i::SharedFunctionInfo> sfi = it.Next(); !sfi.is_null(); sfi = it.Next()) { if (sfi->is_toplevel()) { return isolate->debug()->SetBreakpointForFunction( handle(sfi, isolate), isolate->factory()->empty_string(), id, internal::Debug::kInstrumentation); } } return false; } #if V8_ENABLE_WEBASSEMBLY void Script::RemoveWasmBreakpoint(BreakpointId id) { i::DirectHandle<i::Script> script = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); isolate->debug()->RemoveBreakpointForWasmScript(script, id); } #endif // V8_ENABLE_WEBASSEMBLY void RemoveBreakpoint(Isolate* v8_isolate, BreakpointId id) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::HandleScope handle_scope(isolate); isolate->debug()->RemoveBreakpoint(id); } Platform* GetCurrentPlatform() { return i::V8::GetCurrentPlatform(); } void ForceGarbageCollection(Isolate* isolate, StackState embedder_stack_state) { i::EmbedderStackStateScope stack_scope( reinterpret_cast<i::Isolate*>(isolate)->heap(), i::EmbedderStackStateOrigin::kImplicitThroughTask, embedder_stack_state); isolate->LowMemoryNotification(); } #if V8_ENABLE_WEBASSEMBLY WasmScript* WasmScript::Cast(Script* script) { CHECK(script->IsWasm()); return static_cast<WasmScript*>(script); } Maybe<WasmScript::DebugSymbols::Type> GetDebugSymbolType( i::wasm::WasmDebugSymbols::Type type) { switch (type) { case i::wasm::WasmDebugSymbols::Type::EmbeddedDWARF: return Just(WasmScript::DebugSymbols::Type::EmbeddedDWARF); case i::wasm::WasmDebugSymbols::Type::ExternalDWARF: return Just(WasmScript::DebugSymbols::Type::ExternalDWARF); case i::wasm::WasmDebugSymbols::Type::SourceMap: return Just(WasmScript::DebugSymbols::Type::SourceMap); case i::wasm::WasmDebugSymbols::Type::None: return {}; } } std::vector<WasmScript::DebugSymbols> WasmScript::GetDebugSymbols() const { auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); std::vector<WasmScript::DebugSymbols> debug_symbols; auto symbols = script->wasm_native_module()->module()->debug_symbols; for (size_t i = 0; i < symbols.size(); ++i) { const i::wasm::WasmDebugSymbols& symbol = symbols[i]; Maybe<WasmScript::DebugSymbols::Type> type = GetDebugSymbolType(symbol.type); if (type.IsNothing()) continue; internal::wasm::ModuleWireBytes wire_bytes( script->wasm_native_module()->wire_bytes()); i::wasm::WasmName external_url = wire_bytes.GetNameOrNull(symbol.external_url); MemorySpan<const char> span = {external_url.data(), external_url.size()}; debug_symbols.push_back({type.FromJust(), span}); } return debug_symbols; } int WasmScript::NumFunctions() const { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); DCHECK_GE(i::kMaxInt, module->functions.size()); return static_cast<int>(module->functions.size()); } int WasmScript::NumImportedFunctions() const { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); DCHECK_GE(i::kMaxInt, module->num_imported_functions); return static_cast<int>(module->num_imported_functions); } std::pair<int, int> WasmScript::GetFunctionRange(int function_index) const { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); DCHECK_LE(0, function_index); DCHECK_GT(module->functions.size(), function_index); const i::wasm::WasmFunction& func = module->functions[function_index]; DCHECK_GE(i::kMaxInt, func.code.offset()); DCHECK_GE(i::kMaxInt, func.code.end_offset()); return std::make_pair(static_cast<int>(func.code.offset()), static_cast<int>(func.code.end_offset())); } int WasmScript::GetContainingFunction(int byte_offset) const { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); DCHECK_LE(0, byte_offset); return i::wasm::GetContainingWasmFunction(module, byte_offset); } void WasmScript::Disassemble(DisassemblyCollector* collector, std::vector<int>* function_body_offsets) { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); i::wasm::ModuleWireBytes wire_bytes(native_module->wire_bytes()); i::wasm::Disassemble(module, wire_bytes, native_module->GetNamesProvider(), collector, function_body_offsets); } void Disassemble(base::Vector<const uint8_t> wire_bytes, DisassemblyCollector* collector, std::vector<int>* function_body_offsets) { i::wasm::Disassemble(wire_bytes, collector, function_body_offsets); } uint32_t WasmScript::GetFunctionHash(int function_index) { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); DCHECK_LE(0, function_index); DCHECK_GT(module->functions.size(), function_index); const i::wasm::WasmFunction& func = module->functions[function_index]; i::wasm::ModuleWireBytes wire_bytes(native_module->wire_bytes()); base::Vector<const uint8_t> function_bytes = wire_bytes.GetFunctionBytes(&func); // TODO(herhut): Maybe also take module, name and signature into account. return i::StringHasher::HashSequentialString(function_bytes.begin(), function_bytes.length(), internal::HashSeed::Default()); } Maybe<v8::MemorySpan<const uint8_t>> WasmScript::GetModuleBuildId() const { i::DisallowGarbageCollection no_gc; auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* wasm_module = native_module->module(); const i::wasm::WireBytesRef& build_id = wasm_module->build_id; if (build_id.is_empty()) { return {}; } return Just(MemorySpan<const uint8_t>{ native_module->wire_bytes().begin() + build_id.offset(), build_id.length()}); } int WasmScript::CodeOffset() const { auto script = Utils::OpenDirectHandle(this); DCHECK_EQ(i::Script::Type::kWasm, script->type()); i::wasm::NativeModule* native_module = script->wasm_native_module(); const i::wasm::WasmModule* module = native_module->module(); // If the module contains at least one function, the code offset must have // been initialized, and it cannot be zero. DCHECK_IMPLIES(module->num_declared_functions > 0, module->code.offset() != 0); return module->code.offset(); } #endif // V8_ENABLE_WEBASSEMBLY Location::Location(int line_number, int column_number) : line_number_(line_number), column_number_(column_number), is_empty_(false) {} Location::Location() : line_number_(Function::kLineOffsetNotFound), column_number_(Function::kLineOffsetNotFound), is_empty_(true) {} int Location::GetLineNumber() const { DCHECK(!IsEmpty()); return line_number_; } int Location::GetColumnNumber() const { DCHECK(!IsEmpty()); return column_number_; } bool Location::IsEmpty() const { return is_empty_; } void GetLoadedScripts(Isolate* v8_isolate, std::vector<v8::Global<Script>>& scripts) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); { i::DisallowGarbageCollection no_gc; i::Script::Iterator iterator(isolate); for (i::Tagged<i::Script> script = iterator.Next(); !script.is_null(); script = iterator.Next()) { #if V8_ENABLE_WEBASSEMBLY if (script->type() != i::Script::Type::kNormal && script->type() != i::Script::Type::kWasm) { continue; } #else if (script->type() != i::Script::Type::kNormal) continue; #endif // V8_ENABLE_WEBASSEMBLY if (!script->HasValidSource()) continue; i::HandleScope handle_scope(isolate); i::DirectHandle<i::Script> script_handle(script, isolate); scripts.emplace_back(v8_isolate, ToApiHandle<Script>(script_handle)); } } } std::optional<v8::ScriptOrigin> GetScriptOrigin(Isolate* v8_isolate, int script_id) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); { i::DisallowGarbageCollection no_gc; i::Script::Iterator iterator(isolate); for (i::Tagged<i::Script> script = iterator.Next(); !script.is_null(); script = iterator.Next()) { if (script->id() == script_id) { i::DirectHandle<i::Object> scriptName(script->GetNameOrSourceURL(), isolate); i::DirectHandle<i::Object> source_map_url(script->source_mapping_url(), isolate); i::DirectHandle<i::Object> host_defined_options( script->host_defined_options(), isolate); ScriptOriginOptions options(script->origin_options()); bool is_wasm = false; #if V8_ENABLE_WEBASSEMBLY is_wasm = script->type() == i::Script::Type::kWasm; #endif // V8_ENABLE_WEBASSEMBLY v8::ScriptOrigin origin( Utils::ToLocal(scriptName), script->line_offset(), script->column_offset(), options.IsSharedCrossOrigin(), script->id(), Utils::ToLocal(source_map_url), options.IsOpaque(), is_wasm, options.IsModule(), Utils::ToLocal(host_defined_options)); return origin; } } } return std::nullopt; } MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* v8_isolate, Local<String> source) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); v8::Local<v8::Context> context = Utils::ToLocal(isolate->native_context()); PrepareForDebugInterfaceExecutionScope api_scope(isolate, context); i::Handle<i::String> str = Utils::OpenHandle(*source); i::DirectHandle<i::SharedFunctionInfo> result; { i::AlignedCachedData* cached_data = nullptr; ScriptCompiler::CompilationDetails compilation_details; i::MaybeDirectHandle<i::SharedFunctionInfo> maybe_function_info = i::Compiler::GetSharedFunctionInfoForScriptWithCachedData( isolate, str, i::ScriptDetails(), cached_data, ScriptCompiler::kNoCompileOptions, ScriptCompiler::kNoCacheBecauseInspector, i::v8_flags.expose_inspector_scripts ? i::NOT_NATIVES_CODE : i::INSPECTOR_CODE, &compilation_details); bool has_exception = !maybe_function_info.ToHandle(&result); if (has_exception) return {}; } return api_scope.Escape(ToApiHandle<UnboundScript>(result)); } #if V8_ENABLE_WEBASSEMBLY void EnterDebuggingForIsolate(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::wasm::GetWasmEngine()->EnterDebuggingForIsolate(isolate); } void LeaveDebuggingForIsolate(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::wasm::GetWasmEngine()->LeaveDebuggingForIsolate(isolate); } #endif // V8_ENABLE_WEBASSEMBLY void SetDebugDelegate(Isolate* v8_isolate, DebugDelegate* delegate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); isolate->debug()->SetDebugDelegate(delegate); } void SetAsyncEventDelegate(Isolate* v8_isolate, AsyncEventDelegate* delegate) { reinterpret_cast<i::Isolate*>(v8_isolate)->set_async_event_delegate(delegate); } void ResetBlackboxedStateCache(Isolate* v8_isolate, Local<Script> script) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); i::DisallowGarbageCollection no_gc; i::SharedFunctionInfo::ScriptIterator iter(isolate, *Utils::OpenDirectHandle(*script)); for (i::Tagged<i::SharedFunctionInfo> info = iter.Next(); !info.is_null(); info = iter.Next()) { if (auto debug_info = isolate->debug()->TryGetDebugInfo(info)) { debug_info.value()->set_computed_debug_is_blackboxed(false); } } } int EstimatedValueSize(Isolate* v8_isolate, Local<Value> value) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); auto object = Utils::OpenDirectHandle(*value); if (IsSmi(*object)) return i::kTaggedSize; CHECK(IsHeapObject(*object)); return i::Cast<i::HeapObject>(object)->Size(); } void AccessorPair::CheckCast(Value* that) { auto obj = Utils::OpenDirectHandle(that); Utils::ApiCheck(i::IsAccessorPair(*obj), "v8::debug::AccessorPair::Cast", "Value is not a v8::debug::AccessorPair"); } #if V8_ENABLE_WEBASSEMBLY void WasmValueObject::CheckCast(Value* that) { auto obj = Utils::OpenDirectHandle(that); Utils::ApiCheck(i::IsWasmValueObject(*obj), "v8::debug::WasmValueObject::Cast", "Value is not a v8::debug::WasmValueObject"); } bool WasmValueObject::IsWasmValueObject(Local<Value> that) { auto obj = Utils::OpenDirectHandle(*that); return i::IsWasmValueObject(*obj); } Local<String> WasmValueObject::type() const { auto object = i::Cast<i::WasmValueObject>(Utils::OpenDirectHandle(this)); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::String> type(object->type(), isolate); return Utils::ToLocal(type); } #endif // V8_ENABLE_WEBASSEMBLY Local<Function> GetBuiltin(Isolate* v8_isolate, Builtin requested_builtin) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); i::HandleScope handle_scope(isolate); CHECK_EQ(requested_builtin, kStringToLowerCase); i::Builtin builtin = i::Builtin::kStringPrototypeToLocaleLowerCase; i::Factory* factory = isolate->factory(); i::DirectHandle<i::String> name = isolate->factory()->empty_string(); i::DirectHandle<i::NativeContext> context(isolate->native_context()); i::DirectHandle<i::SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin(name, builtin, 0, i::kAdapt); info->set_language_mode(i::LanguageMode::kStrict); i::Handle<i::JSFunction> fun = i::Factory::JSFunctionBuilder{isolate, info, context} .set_map(isolate->strict_function_without_prototype_map()) .Build(); return Utils::ToLocal(handle_scope.CloseAndEscape(fun)); } void SetConsoleDelegate(Isolate* v8_isolate, ConsoleDelegate* delegate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::DisallowJavascriptExecutionDebugOnly no_execution(isolate); i::DisallowExceptionsDebugOnly no_exceptions(isolate); if (delegate == nullptr) { isolate->set_console_delegate(nullptr); } else { isolate->set_console_delegate(delegate); } } ConsoleCallArguments::ConsoleCallArguments( const v8::FunctionCallbackInfo<v8::Value>& info) : isolate_(info.GetIsolate()), values_(info.address_of_first_argument()), length_(info.Length()) {} ConsoleCallArguments::ConsoleCallArguments( i::Isolate* isolate, const internal::BuiltinArguments& args) : isolate_(reinterpret_cast<v8::Isolate*>(isolate)), values_(args.length() > 1 ? args.address_of_first_argument() : nullptr), length_(args.length() - 1) {} v8::Local<v8::Message> CreateMessageFromException( Isolate* v8_isolate, v8::Local<v8::Value> v8_error) { i::DirectHandle<i::Object> obj = Utils::OpenDirectHandle(*v8_error); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8NoScriptNoExceptionScope api_scope(isolate); i::HandleScope scope(isolate); return Utils::MessageToLocal( scope.CloseAndEscape(isolate->CreateMessageFromException(obj))); } MaybeLocal<Script> GeneratorObject::Script() { auto obj = Utils::OpenDirectHandle(this); i::Tagged<i::Object> maybe_script = obj->function()->shared()->script(); if (!IsScript(maybe_script)) return {}; i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Script> script(i::Cast<i::Script>(maybe_script), isolate); return ToApiHandle<v8::debug::Script>(script); } Local<Function> GeneratorObject::Function() { auto obj = Utils::OpenDirectHandle(this); return Utils::ToLocal(direct_handle(obj->function(), i::Isolate::Current())); } Location GeneratorObject::SuspendedLocation() { auto obj = Utils::OpenDirectHandle(this); CHECK(obj->is_suspended()); i::Tagged<i::Object> maybe_script = obj->function()->shared()->script(); if (!IsScript(maybe_script)) return Location(); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Script> script(i::Cast<i::Script>(maybe_script), isolate); i::Script::PositionInfo info; i::SharedFunctionInfo::EnsureSourcePositionsAvailable( isolate, i::direct_handle(obj->function()->shared(), isolate)); i::Script::GetPositionInfo(script, obj->source_position(), &info); return Location(info.line, info.column); } bool GeneratorObject::IsSuspended() { return Utils::OpenDirectHandle(this)->is_suspended(); } v8::Local<GeneratorObject> GeneratorObject::Cast(v8::Local<v8::Value> value) { CHECK(value->IsGeneratorObject()); return ToApiHandle<GeneratorObject>(Utils::OpenDirectHandle(*value)); } MaybeLocal<Value> CallFunctionOn(Local<Context> context, Local<Function> function, Local<Value> recv, base::Vector<Local<Value>> args, bool throw_on_side_effect) { auto isolate = i::Isolate::Current(); PrepareForDebugInterfaceExecutionScope api_scope(isolate, context); auto self = Utils::OpenHandle(*function); auto recv_obj = Utils::OpenHandle(*recv); static_assert(sizeof(v8::Global<v8::Value>) == sizeof(i::Handle<i::Object>)); auto arguments = reinterpret_cast<i::DirectHandle<i::Object>*>(args.data()); // Disable breaks in side-effect free mode. i::DisableBreak disable_break_scope(isolate->debug(), throw_on_side_effect); if (throw_on_side_effect) { isolate->debug()->StartSideEffectCheckMode(); } MaybeLocal<Value> result = Utils::ToMaybeLocal( i::Execution::Call(isolate, self, recv_obj, {arguments, args.size()})); if (throw_on_side_effect) { isolate->debug()->StopSideEffectCheckMode(); } return api_scope.EscapeMaybe(result); } MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate, v8::Local<v8::String> source, EvaluateGlobalMode mode, bool repl) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); v8::Local<v8::Context> context = Utils::ToLocal(i_isolate->native_context()); PrepareForDebugInterfaceExecutionScope api_scope(i_isolate, context); i::REPLMode repl_mode = repl ? i::REPLMode::kYes : i::REPLMode::kNo; MaybeLocal<Value> result = Utils::ToMaybeLocal(i::DebugEvaluate::Global( i_isolate, Utils::OpenHandle(*source), mode, repl_mode)); return api_scope.EscapeMaybe(result); } void GlobalLexicalScopeNames(v8::Local<v8::Context> v8_context, std::vector<v8::Global<v8::String>>* names) { auto context = Utils::OpenDirectHandle(*v8_context); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::ScriptContextTable> table( context->native_context()->script_context_table(), isolate); for (int i = 0; i < table->length(kAcquireLoad); i++) { i::DirectHandle<i::Context> script_context(table->get(i), isolate); DCHECK(script_context->IsScriptContext()); i::DirectHandle<i::ScopeInfo> scope_info(script_context->scope_info(), isolate); for (auto it : i::ScopeInfo::IterateLocalNames(scope_info)) { if (i::ScopeInfo::VariableIsSynthetic(it->name())) continue; names->emplace_back(reinterpret_cast<Isolate*>(isolate), Utils::ToLocal(direct_handle(it->name(), isolate))); } } } void SetReturnValue(v8::Isolate* v8_isolate, v8::Local<v8::Value> value) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); isolate->debug()->set_return_value(*Utils::OpenDirectHandle(*value)); } int64_t GetNextRandomInt64(v8::Isolate* v8_isolate) { return reinterpret_cast<i::Isolate*>(v8_isolate) ->random_number_generator() ->NextInt64(); } int GetDebuggingId(v8::Local<v8::Function> function) { auto callable = v8::Utils::OpenDirectHandle(*function); if (!IsJSFunction(*callable)) return i::DebugInfo::kNoDebuggingId; auto func = i::Cast<i::JSFunction>(callable); int id = i::Isolate::Current()->debug()->GetFunctionDebuggingId(func); DCHECK_NE(i::DebugInfo::kNoDebuggingId, id); return id; } bool SetFunctionBreakpoint(v8::Local<v8::Function> function, v8::Local<v8::String> condition, BreakpointId* id) { auto callable = Utils::OpenDirectHandle(*function); if (!IsJSFunction(*callable)) return false; auto jsfunction = i::Cast<i::JSFunction>(callable); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::String> condition_string = condition.IsEmpty() ? i::DirectHandle<i::String>(isolate->factory()->empty_string()) : Utils::OpenDirectHandle(*condition); return isolate->debug()->SetBreakpointForFunction( handle(jsfunction->shared(), isolate), condition_string, id); } PostponeInterruptsScope::PostponeInterruptsScope(v8::Isolate* isolate) : scope_( new i::PostponeInterruptsScope(reinterpret_cast<i::Isolate*>(isolate), i::StackGuard::API_INTERRUPT)) {} PostponeInterruptsScope::~PostponeInterruptsScope() = default; DisableBreakScope::DisableBreakScope(v8::Isolate* isolate) : scope_(std::make_unique<i::DisableBreak>( reinterpret_cast<i::Isolate*>(isolate)->debug())) {} DisableBreakScope::~DisableBreakScope() = default; int Coverage::BlockData::StartOffset() const { return block_->start; } int Coverage::BlockData::EndOffset() const { return block_->end; } uint32_t Coverage::BlockData::Count() const { return block_->count; } int Coverage::FunctionData::StartOffset() const { return function_->start; } int Coverage::FunctionData::EndOffset() const { return function_->end; } uint32_t Coverage::FunctionData::Count() const { return function_->count; } MaybeLocal<String> Coverage::FunctionData::Name() const { return ToApiHandle<String>(function_->name); } size_t Coverage::FunctionData::BlockCount() const { return function_->blocks.size(); } bool Coverage::FunctionData::HasBlockCoverage() const { return function_->has_block_coverage; } Coverage::BlockData Coverage::FunctionData::GetBlockData(size_t i) const { return BlockData(&function_->blocks.at(i), coverage_); } Local<Script> Coverage::ScriptData::GetScript() const { return ToApiHandle<Script>(script_->script); } size_t Coverage::ScriptData::FunctionCount() const { return script_->functions.size(); } Coverage::FunctionData Coverage::ScriptData::GetFunctionData(size_t i) const { return FunctionData(&script_->functions.at(i), coverage_); } Coverage::ScriptData::ScriptData(size_t index, std::shared_ptr<i::Coverage> coverage) : script_(&coverage->at(index)), coverage_(std::move(coverage)) {} size_t Coverage::ScriptCount() const { return coverage_->size(); } Coverage::ScriptData Coverage::GetScriptData(size_t i) const { return ScriptData(i, coverage_); } Coverage Coverage::CollectPrecise(Isolate* isolate) { return Coverage( i::Coverage::CollectPrecise(reinterpret_cast<i::Isolate*>(isolate))); } Coverage Coverage::CollectBestEffort(Isolate* isolate) { return Coverage( i::Coverage::CollectBestEffort(reinterpret_cast<i::Isolate*>(isolate))); } #if V8_ENABLE_WEBASSEMBLY Coverage Coverage::CollectWasmData(Isolate* isolate) { return Coverage( i::Coverage::CollectWasmData(reinterpret_cast<i::Isolate*>(isolate))); } #endif // V8_ENABLE_WEBASSEMBLY void Coverage::SelectMode(Isolate* isolate, CoverageMode mode) { i::Coverage::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode); } MaybeLocal<v8::Value> EphemeronTable::Get(v8::Isolate* isolate, v8::Local<v8::Value> key) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); auto self = i::Cast<i::EphemeronHashTable>(Utils::OpenDirectHandle(this)); i::DirectHandle<i::Object> internal_key = Utils::OpenDirectHandle(*key); DCHECK(IsJSReceiver(*internal_key)); i::DirectHandle<i::Object> value(self->Lookup(internal_key), i_isolate); if (IsTheHole(*value)) return {}; return Utils::ToLocal(value); } Local<EphemeronTable> EphemeronTable::Set(v8::Isolate* isolate, v8::Local<v8::Value> key, v8::Local<v8::Value> value) { auto self = i::Cast<i::EphemeronHashTable>(Utils::OpenHandle(this)); i::DirectHandle<i::Object> internal_key = Utils::OpenDirectHandle(*key); i::DirectHandle<i::Object> internal_value = Utils::OpenDirectHandle(*value); DCHECK(IsJSReceiver(*internal_key)); i::DirectHandle<i::EphemeronHashTable> result( i::EphemeronHashTable::Put(reinterpret_cast<i::Isolate*>(isolate), self, internal_key, internal_value)); return ToApiHandle<EphemeronTable>(result); } Local<EphemeronTable> EphemeronTable::New(v8::Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); EnterV8NoScriptNoExceptionScope api_scope(i_isolate); i::DirectHandle<i::EphemeronHashTable> table = i::EphemeronHashTable::New(i_isolate, 0); return ToApiHandle<EphemeronTable>(table); } Local<Value> AccessorPair::getter() { auto accessors = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Object> getter(accessors->getter(), isolate); return Utils::ToLocal(getter); } Local<Value> AccessorPair::setter() { auto accessors = Utils::OpenDirectHandle(this); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Object> setter(accessors->setter(), isolate); return Utils::ToLocal(setter); } bool AccessorPair::IsAccessorPair(Local<Value> that) { return i::IsAccessorPair(*Utils::OpenDirectHandle(*that)); } MaybeLocal<Message> GetMessageFromPromise(Local<Promise> p) { i::DirectHandle<i::JSPromise> promise = Utils::OpenDirectHandle(*p); i::Isolate* isolate = i::Isolate::Current(); i::DirectHandle<i::Symbol> key = isolate->factory()->promise_debug_message_symbol(); i::DirectHandle<i::Object> maybeMessage = i::JSReceiver::GetDataProperty(isolate, promise, key); if (!IsJSMessageObject(*maybeMessage, isolate)) return MaybeLocal<Message>(); return ToApiHandle<Message>(i::Cast<i::JSMessageObject>(maybeMessage)); } void RecordAsyncStackTaggingCreateTaskCall(v8::Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); isolate->CountUsage(v8::Isolate::kAsyncStackTaggingCreateTaskCall); } uint64_t GetIsolateId(v8::Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); return isolate->debug()->IsolateId(); } void SetIsolateId(v8::Isolate* v8_isolate, uint64_t id) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); isolate->debug()->SetIsolateId(id); } std::unique_ptr<PropertyIterator> PropertyIterator::Create( Local<Context> context, Local<Object> object, bool skip_indices) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(i::Isolate::Current()); if (isolate->is_execution_terminating()) { return nullptr; } CallDepthScope<false> call_depth_scope(isolate, context); return i::DebugPropertyIterator::Create( isolate, Utils::OpenDirectHandle(*object), skip_indices); } } // namespace debug namespace internal { Maybe<bool> DebugPropertyIterator::Advance() { if (isolate_->is_execution_terminating()) { return {}; } Local<v8::Context> context = Utils::ToLocal( direct_handle(isolate_->context()->native_context(), isolate_)); CallDepthScope<false> call_depth_scope(isolate_, context); if (!AdvanceInternal()) { DCHECK(isolate_->has_exception()); return {}; } return Just(true); } } // namespace internal } // namespace v8