Commit 9d3cd57f authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

Reland "[debug][api] Move debugger support to debug-interface.cc."

Previously we had the debugger / inspector support declared in
debug-interface.h, but the implementation was sprinkled all across
api.cc, which was quite messy. This moves the relevant macros and
other bits into api-macros.h (with api-macros-undef.h to support
jumbo builds), and moves the debugger interface implementation to
src/debug/debug-interface.cc.

Bug: chromium:1162229
Change-Id: If2698cba7bcc0b54b0f889220588ec214405848b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2656256
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72402}
parent 5154f22c
......@@ -2463,6 +2463,8 @@ v8_source_set("v8_base_without_compiler") {
"src/api/api-arguments-inl.h",
"src/api/api-arguments.cc",
"src/api/api-arguments.h",
"src/api/api-inl.h",
"src/api/api-macros.h",
"src/api/api-natives.cc",
"src/api/api-natives.h",
"src/api/api.cc",
......@@ -2627,6 +2629,7 @@ v8_source_set("v8_base_without_compiler") {
"src/debug/debug-evaluate.h",
"src/debug/debug-frames.cc",
"src/debug/debug-frames.h",
"src/debug/debug-interface.cc",
"src/debug/debug-interface.h",
"src/debug/debug-property-iterator.cc",
"src/debug/debug-property-iterator.h",
......
......@@ -6,6 +6,7 @@
#define V8_API_API_INL_H_
#include "src/api/api.h"
#include "src/execution/microtask-queue.h"
#include "src/handles/handles-inl.h"
#include "src/objects/foreign-inl.h"
#include "src/objects/js-weak-refs.h"
......@@ -131,6 +132,111 @@ OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
#undef MAKE_OPEN_HANDLE
#undef OPEN_HANDLE_LIST
template <bool do_callback>
class V8_NODISCARD CallDepthScope {
public:
CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate),
context_(context),
escaped_(false),
safe_for_termination_(isolate->next_v8_call_is_safe_for_termination()),
interrupts_scope_(isolate_, i::StackGuard::TERMINATE_EXECUTION,
isolate_->only_terminate_in_safe_scope()
? (safe_for_termination_
? i::InterruptsScope::kRunInterrupts
: i::InterruptsScope::kPostponeInterrupts)
: i::InterruptsScope::kNoop) {
isolate_->thread_local_top()->IncrementCallDepth(this);
isolate_->set_next_v8_call_is_safe_for_termination(false);
if (!context.IsEmpty()) {
i::Handle<i::Context> env = Utils::OpenHandle(*context);
i::HandleScopeImplementer* impl = isolate->handle_scope_implementer();
if (!isolate->context().is_null() &&
isolate->context().native_context() == env->native_context()) {
context_ = Local<Context>();
} else {
impl->SaveContext(isolate->context());
isolate->set_context(*env);
}
}
if (do_callback) isolate_->FireBeforeCallEnteredCallback();
}
~CallDepthScope() {
i::MicrotaskQueue* microtask_queue = isolate_->default_microtask_queue();
if (!context_.IsEmpty()) {
i::HandleScopeImplementer* impl = isolate_->handle_scope_implementer();
isolate_->set_context(impl->RestoreContext());
i::Handle<i::Context> env = Utils::OpenHandle(*context_);
microtask_queue = env->native_context().microtask_queue();
}
if (!escaped_) isolate_->thread_local_top()->DecrementCallDepth(this);
if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
// TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
if (do_callback) {
if (microtask_queue && microtask_queue->microtasks_policy() ==
v8::MicrotasksPolicy::kScoped) {
DCHECK(microtask_queue->GetMicrotasksScopeDepth() ||
!microtask_queue->DebugMicrotasksScopeDepthIsZero());
}
}
#endif
DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue));
isolate_->set_next_v8_call_is_safe_for_termination(safe_for_termination_);
}
CallDepthScope(const CallDepthScope&) = delete;
CallDepthScope& operator=(const CallDepthScope&) = delete;
void Escape() {
DCHECK(!escaped_);
escaped_ = true;
auto thread_local_top = isolate_->thread_local_top();
thread_local_top->DecrementCallDepth(this);
bool clear_exception = thread_local_top->CallDepthIsZero() &&
thread_local_top->try_catch_handler_ == nullptr;
isolate_->OptionalRescheduleException(clear_exception);
}
private:
bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint(
i::MicrotaskQueue* microtask_queue) {
bool did_perform_microtask_checkpoint =
isolate_->thread_local_top()->CallDepthIsZero() && do_callback &&
microtask_queue &&
microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto;
return !did_perform_microtask_checkpoint ||
isolate_->heap()->weak_refs_keep_during_job().IsUndefined(isolate_);
}
i::Isolate* const isolate_;
Local<Context> context_;
bool escaped_;
bool do_callback_;
bool safe_for_termination_;
i::InterruptsScope interrupts_scope_;
i::Address previous_stack_height_;
friend class i::ThreadLocalTop;
DISALLOW_NEW_AND_DELETE()
};
class V8_NODISCARD InternalEscapableScope : public EscapableHandleScope {
public:
explicit inline InternalEscapableScope(i::Isolate* isolate)
: EscapableHandleScope(reinterpret_cast<v8::Isolate*>(isolate)) {}
};
inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) {
if (isolate->has_scheduled_exception()) {
return isolate->scheduled_exception() ==
i::ReadOnlyRoots(isolate).termination_exception();
}
return false;
}
namespace internal {
Handle<Context> HandleScopeImplementer::LastEnteredContext() {
......
// 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.
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD
#undef LOG_API
#undef ENTER_V8_DO_NOT_USE
#undef ENTER_V8_HELPER_DO_NOT_USE
#undef PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE
#undef PREPARE_FOR_EXECUTION_WITH_CONTEXT
#undef PREPARE_FOR_EXECUTION
#undef ENTER_V8
#undef ENTER_V8_NO_SCRIPT
#undef ENTER_V8_NO_SCRIPT_NO_EXCEPTION
#undef ENTER_V8_FOR_NEW_CONTEXT
#undef EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE
#undef RETURN_ON_FAILED_EXECUTION
#undef RETURN_ON_FAILED_EXECUTION_PRIMITIVE
#undef RETURN_ESCAPED
// 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.
// Note 1: Any file that includes this one should include api-macros-undef.h
// at the bottom.
// Note 2: This file is deliberately missing the include guards (the undeffing
// approach wouldn't work otherwise).
//
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD
/*
* Most API methods should use one of the three macros:
*
* ENTER_V8, ENTER_V8_NO_SCRIPT, ENTER_V8_NO_SCRIPT_NO_EXCEPTION.
*
* The latter two assume that no script is executed, and no exceptions are
* scheduled in addition (respectively). Creating a pending exception and
* removing it before returning is ok.
*
* Exceptions should be handled either by invoking one of the
* RETURN_ON_FAILED_EXECUTION* macros.
*
* Don't use macros with DO_NOT_USE in their name.
*
* TODO(jochen): Document debugger specific macros.
* TODO(jochen): Document LOG_API and other RuntimeCallStats macros.
* TODO(jochen): All API methods should invoke one of the ENTER_V8* macros.
* TODO(jochen): Remove calls form API methods to DO_NOT_USE macros.
*/
#define LOG_API(isolate, class_name, function_name) \
i::RuntimeCallTimerScope _runtime_timer( \
isolate, i::RuntimeCallCounterId::kAPI_##class_name##_##function_name); \
LOG(isolate, ApiEntryCall("v8::" #class_name "::" #function_name))
#define ENTER_V8_DO_NOT_USE(isolate) i::VMState<v8::OTHER> __state__((isolate))
#define ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, \
function_name, bailout_value, \
HandleScopeClass, do_callback) \
if (IsExecutionTerminatingCheck(isolate)) { \
return bailout_value; \
} \
HandleScopeClass handle_scope(isolate); \
CallDepthScope<do_callback> call_depth_scope(isolate, context); \
LOG_API(isolate, class_name, function_name); \
i::VMState<v8::OTHER> __state__((isolate)); \
bool has_pending_exception = false
#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, T) \
if (IsExecutionTerminatingCheck(isolate)) { \
return MaybeLocal<T>(); \
} \
InternalEscapableScope handle_scope(isolate); \
CallDepthScope<false> call_depth_scope(isolate, v8::Local<v8::Context>()); \
i::VMState<v8::OTHER> __state__((isolate)); \
bool has_pending_exception = false
#define PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \
bailout_value, HandleScopeClass, \
do_callback) \
auto isolate = context.IsEmpty() \
? i::Isolate::Current() \
: reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, do_callback);
#define PREPARE_FOR_EXECUTION(context, class_name, function_name, T) \
PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \
MaybeLocal<T>(), InternalEscapableScope, \
false)
#define ENTER_V8(isolate, context, class_name, function_name, bailout_value, \
HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, true)
#ifdef DEBUG
#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, false); \
i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate))
// Lightweight version for APIs that don't require an active context.
#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate)); \
i::DisallowExceptions __no_exceptions__((isolate))
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::VMState<v8::OTHER> __state__((isolate)); \
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate)
#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \
i::VMState<v8::OTHER> __state__((isolate)); \
i::DisallowExceptions __no_exceptions__((isolate))
#else
#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, false)
#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate)
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::VMState<v8::OTHER> __state__((isolate));
#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \
i::VMState<v8::OTHER> __state__((isolate));
#endif // DEBUG
#define EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, value) \
do { \
if (has_pending_exception) { \
call_depth_scope.Escape(); \
return value; \
} \
} while (false)
#define RETURN_ON_FAILED_EXECUTION(T) \
EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, MaybeLocal<T>())
#define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \
EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, Nothing<T>())
#define RETURN_ESCAPED(value) return handle_scope.Escape(value);
// TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
#endif
......@@ -34,11 +34,6 @@
#include "src/common/globals.h"
#include "src/compiler-dispatcher/compiler-dispatcher.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-type-profile.h"
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/diagnostics/gdb-jit.h"
......@@ -74,7 +69,6 @@
#include "src/objects/heap-object.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/js-generator-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-weak-refs-inl.h"
......@@ -140,6 +134,9 @@
#endif // V8_OS_WIN64
#endif // V8_OS_WIN
// Has to be the last include (doesn't have include guards):
#include "src/api/api-macros.h"
#define TRACE_BS(...) \
do { \
if (i::FLAG_trace_backing_store) PrintF(__VA_ARGS__); \
......@@ -147,229 +144,6 @@
namespace v8 {
/*
* Most API methods should use one of the three macros:
*
* ENTER_V8, ENTER_V8_NO_SCRIPT, ENTER_V8_NO_SCRIPT_NO_EXCEPTION.
*
* The latter two assume that no script is executed, and no exceptions are
* scheduled in addition (respectively). Creating a pending exception and
* removing it before returning is ok.
*
* Exceptions should be handled either by invoking one of the
* RETURN_ON_FAILED_EXECUTION* macros.
*
* Don't use macros with DO_NOT_USE in their name.
*
* TODO(jochen): Document debugger specific macros.
* TODO(jochen): Document LOG_API and other RuntimeCallStats macros.
* TODO(jochen): All API methods should invoke one of the ENTER_V8* macros.
* TODO(jochen): Remove calls form API methods to DO_NOT_USE macros.
*/
#define LOG_API(isolate, class_name, function_name) \
i::RuntimeCallTimerScope _runtime_timer( \
isolate, i::RuntimeCallCounterId::kAPI_##class_name##_##function_name); \
LOG(isolate, ApiEntryCall("v8::" #class_name "::" #function_name))
#define ENTER_V8_DO_NOT_USE(isolate) i::VMState<v8::OTHER> __state__((isolate))
#define ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, \
function_name, bailout_value, \
HandleScopeClass, do_callback) \
if (IsExecutionTerminatingCheck(isolate)) { \
return bailout_value; \
} \
HandleScopeClass handle_scope(isolate); \
CallDepthScope<do_callback> call_depth_scope(isolate, context); \
LOG_API(isolate, class_name, function_name); \
i::VMState<v8::OTHER> __state__((isolate)); \
bool has_pending_exception = false
#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, T) \
if (IsExecutionTerminatingCheck(isolate)) { \
return MaybeLocal<T>(); \
} \
InternalEscapableScope handle_scope(isolate); \
CallDepthScope<false> call_depth_scope(isolate, v8::Local<v8::Context>()); \
i::VMState<v8::OTHER> __state__((isolate)); \
bool has_pending_exception = false
#define PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \
bailout_value, HandleScopeClass, \
do_callback) \
auto isolate = context.IsEmpty() \
? i::Isolate::Current() \
: reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, do_callback);
#define PREPARE_FOR_EXECUTION(context, class_name, function_name, T) \
PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \
MaybeLocal<T>(), InternalEscapableScope, \
false)
#define ENTER_V8(isolate, context, class_name, function_name, bailout_value, \
HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, true)
#ifdef DEBUG
#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, false); \
i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate))
// Lightweight version for APIs that don't require an active context.
#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::DisallowJavascriptExecutionDebugOnly __no_script__((isolate)); \
i::DisallowExceptions __no_exceptions__((isolate))
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::VMState<v8::OTHER> __state__((isolate)); \
ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate)
#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \
i::VMState<v8::OTHER> __state__((isolate)); \
i::DisallowExceptions __no_exceptions__((isolate))
#else
#define ENTER_V8_NO_SCRIPT(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass) \
ENTER_V8_HELPER_DO_NOT_USE(isolate, context, class_name, function_name, \
bailout_value, HandleScopeClass, false)
#define ASSERT_NO_SCRIPT_NO_EXCEPTION(isolate)
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate) \
i::VMState<v8::OTHER> __state__((isolate));
#define ENTER_V8_FOR_NEW_CONTEXT(isolate) \
i::VMState<v8::OTHER> __state__((isolate));
#endif // DEBUG
#define EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, value) \
do { \
if (has_pending_exception) { \
call_depth_scope.Escape(); \
return value; \
} \
} while (false)
#define RETURN_ON_FAILED_EXECUTION(T) \
EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, MaybeLocal<T>())
#define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \
EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(isolate, Nothing<T>())
#define RETURN_ESCAPED(value) return handle_scope.Escape(value);
namespace {
class V8_NODISCARD InternalEscapableScope : public v8::EscapableHandleScope {
public:
explicit inline InternalEscapableScope(i::Isolate* isolate)
: v8::EscapableHandleScope(reinterpret_cast<v8::Isolate*>(isolate)) {}
};
// TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
void CheckMicrotasksScopesConsistency(i::MicrotaskQueue* microtask_queue) {
if (microtask_queue &&
microtask_queue->microtasks_policy() == v8::MicrotasksPolicy::kScoped) {
DCHECK(microtask_queue->GetMicrotasksScopeDepth() ||
!microtask_queue->DebugMicrotasksScopeDepthIsZero());
}
}
#endif
template <bool do_callback>
class V8_NODISCARD CallDepthScope {
public:
CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate),
context_(context),
escaped_(false),
safe_for_termination_(isolate->next_v8_call_is_safe_for_termination()),
interrupts_scope_(isolate_, i::StackGuard::TERMINATE_EXECUTION,
isolate_->only_terminate_in_safe_scope()
? (safe_for_termination_
? i::InterruptsScope::kRunInterrupts
: i::InterruptsScope::kPostponeInterrupts)
: i::InterruptsScope::kNoop) {
isolate_->thread_local_top()->IncrementCallDepth(this);
isolate_->set_next_v8_call_is_safe_for_termination(false);
if (!context.IsEmpty()) {
i::Handle<i::Context> env = Utils::OpenHandle(*context);
i::HandleScopeImplementer* impl = isolate->handle_scope_implementer();
if (!isolate->context().is_null() &&
isolate->context().native_context() == env->native_context()) {
context_ = Local<Context>();
} else {
impl->SaveContext(isolate->context());
isolate->set_context(*env);
}
}
if (do_callback) isolate_->FireBeforeCallEnteredCallback();
}
~CallDepthScope() {
i::MicrotaskQueue* microtask_queue = isolate_->default_microtask_queue();
if (!context_.IsEmpty()) {
i::HandleScopeImplementer* impl = isolate_->handle_scope_implementer();
isolate_->set_context(impl->RestoreContext());
i::Handle<i::Context> env = Utils::OpenHandle(*context_);
microtask_queue = env->native_context().microtask_queue();
}
if (!escaped_) isolate_->thread_local_top()->DecrementCallDepth(this);
if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
// TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
if (do_callback) CheckMicrotasksScopesConsistency(microtask_queue);
#endif
DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue));
isolate_->set_next_v8_call_is_safe_for_termination(safe_for_termination_);
}
CallDepthScope(const CallDepthScope&) = delete;
CallDepthScope& operator=(const CallDepthScope&) = delete;
void Escape() {
DCHECK(!escaped_);
escaped_ = true;
auto thread_local_top = isolate_->thread_local_top();
thread_local_top->DecrementCallDepth(this);
bool clear_exception = thread_local_top->CallDepthIsZero() &&
thread_local_top->try_catch_handler_ == nullptr;
isolate_->OptionalRescheduleException(clear_exception);
}
private:
bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint(
i::MicrotaskQueue* microtask_queue) {
bool did_perform_microtask_checkpoint =
isolate_->thread_local_top()->CallDepthIsZero() &&
do_callback && microtask_queue &&
microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto;
return !did_perform_microtask_checkpoint ||
isolate_->heap()->weak_refs_keep_during_job().IsUndefined(isolate_);
}
i::Isolate* const isolate_;
Local<Context> context_;
bool escaped_;
bool do_callback_;
bool safe_for_termination_;
i::InterruptsScope interrupts_scope_;
i::Address previous_stack_height_;
friend class i::ThreadLocalTop;
DISALLOW_NEW_AND_DELETE()
};
} // namespace
static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate,
i::Handle<i::Script> script) {
i::Handle<i::Object> scriptName(script->GetNameOrSourceURL(), isolate);
......@@ -535,14 +309,6 @@ void Utils::ReportOOMFailure(i::Isolate* isolate, const char* location,
isolate->SignalFatalError();
}
static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) {
if (isolate->has_scheduled_exception()) {
return isolate->scheduled_exception() ==
i::ReadOnlyRoots(isolate).termination_exception();
}
return false;
}
void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) {
i::V8::SetSnapshotBlob(snapshot_blob);
}
......@@ -3929,12 +3695,6 @@ void v8::WasmModuleObject::CheckCast(Value* that) {
"Value is not a WasmModuleObject");
}
void v8::debug::AccessorPair::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsAccessorPair(), "v8::AccessorPair::Cast",
"Value is not a debug::AccessorPair");
}
v8::BackingStore::~BackingStore() {
auto i_this = reinterpret_cast<const i::BackingStore*>(this);
i_this->~BackingStore(); // manually call internal destructor
......@@ -9566,729 +9326,6 @@ Local<StackTrace> Exception::GetStackTrace(Local<Value> exception) {
return Utils::StackTraceToLocal(isolate->GetDetailedStackTrace(js_obj));
}
// --- D e b u g S u p p o r t ---
void debug::SetContextId(Local<Context> context, int id) {
Utils::OpenHandle(*context)->set_debug_context_id(i::Smi::FromInt(id));
}
int debug::GetContextId(Local<Context> context) {
i::Object value = Utils::OpenHandle(*context)->debug_context_id();
return (value.IsSmi()) ? i::Smi::ToInt(value) : 0;
}
void debug::SetInspector(Isolate* isolate,
v8_inspector::V8Inspector* inspector) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i_isolate->set_inspector(inspector);
}
v8_inspector::V8Inspector* debug::GetInspector(Isolate* isolate) {
return reinterpret_cast<i::Isolate*>(isolate)->inspector();
}
void debug::SetBreakOnNextFunctionCall(Isolate* isolate) {
reinterpret_cast<i::Isolate*>(isolate)->debug()->SetBreakOnNextFunctionCall();
}
void debug::ClearBreakOnNextFunctionCall(Isolate* isolate) {
reinterpret_cast<i::Isolate*>(isolate)
->debug()
->ClearBreakOnNextFunctionCall();
}
MaybeLocal<Array> debug::GetInternalProperties(Isolate* v8_isolate,
Local<Value> value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> val = Utils::OpenHandle(*value);
i::Handle<i::JSArray> result;
if (!i::Runtime::GetInternalProperties(isolate, val).ToHandle(&result))
return MaybeLocal<Array>();
return Utils::ToLocal(result);
}
namespace {
void CollectPrivateMethodsAndAccessorsFromContext(
i::Isolate* isolate, i::Handle<i::Context> context,
i::IsStaticFlag is_static_flag, std::vector<Local<Value>>* names_out,
std::vector<Local<Value>>* values_out) {
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::VariableMode mode = scope_info->ContextLocalMode(j);
i::IsStaticFlag flag = scope_info->ContextLocalIsStaticFlag(j);
if (!i::IsPrivateMethodOrAccessorVariableMode(mode) ||
flag != is_static_flag) {
continue;
}
i::Handle<i::String> name(scope_info->ContextLocalName(j), isolate);
int context_index = scope_info->ContextHeaderLength() + j;
i::Handle<i::Object> slot_value(context->get(context_index), isolate);
DCHECK_IMPLIES(mode == i::VariableMode::kPrivateMethod,
slot_value->IsJSFunction());
DCHECK_IMPLIES(mode != i::VariableMode::kPrivateMethod,
slot_value->IsAccessorPair());
names_out->push_back(Utils::ToLocal(name));
values_out->push_back(Utils::ToLocal(slot_value));
}
}
} // anonymous namespace
bool debug::GetPrivateMembers(Local<Context> context, Local<Object> value,
std::vector<Local<Value>>* names_out,
std::vector<Local<Value>>* values_out) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
LOG_API(isolate, debug, GetPrivateMembers);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::JSReceiver> receiver = Utils::OpenHandle(*value);
i::Handle<i::JSArray> names;
i::Handle<i::FixedArray> values;
i::PropertyFilter key_filter =
static_cast<i::PropertyFilter>(i::PropertyFilter::PRIVATE_NAMES_ONLY);
i::Handle<i::FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, keys,
i::KeyAccumulator::GetKeys(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;
for (int i = 0; i < keys->length(); ++i) {
// Exclude the private brand symbols.
i::Handle<i::Symbol> key(i::Symbol::cast(keys->get(i)), isolate);
if (key->is_private_brand()) {
i::Handle<i::Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value, i::Object::GetProperty(isolate, receiver, key),
false);
i::Handle<i::Context> context(i::Context::cast(*value), isolate);
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
// At least one slot contains the brand symbol so it does not count.
private_entries_count += (scope_info->ContextLocalCount() - 1);
} else {
private_entries_count++;
}
}
// Estimate number of static private methods/accessors for classes.
bool has_static_private_methods_or_accessors = false;
if (receiver->IsJSFunction()) {
i::Handle<i::JSFunction> func(i::JSFunction::cast(*receiver), isolate);
i::Handle<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::Handle<i::Context> context(func->context(), isolate);
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::VariableMode mode = scope_info->ContextLocalMode(j);
i::IsStaticFlag is_static_flag =
scope_info->ContextLocalIsStaticFlag(j);
if (i::IsPrivateMethodOrAccessorVariableMode(mode) &&
is_static_flag == i::IsStaticFlag::kStatic) {
private_entries_count += local_count;
break;
}
}
}
}
DCHECK(names_out->empty());
names_out->reserve(private_entries_count);
DCHECK(values_out->empty());
values_out->reserve(private_entries_count);
if (has_static_private_methods_or_accessors) {
i::Handle<i::Context> context(i::JSFunction::cast(*receiver).context(),
isolate);
CollectPrivateMethodsAndAccessorsFromContext(
isolate, context, i::IsStaticFlag::kStatic, names_out, values_out);
}
for (int i = 0; i < keys->length(); ++i) {
i::Handle<i::Object> obj_key(keys->get(i), isolate);
i::Handle<i::Symbol> key(i::Symbol::cast(*obj_key), isolate);
CHECK(key->is_private_name());
i::Handle<i::Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value, i::Object::GetProperty(isolate, receiver, key), false);
if (key->is_private_brand()) {
DCHECK(value->IsContext());
i::Handle<i::Context> context(i::Context::cast(*value), isolate);
CollectPrivateMethodsAndAccessorsFromContext(
isolate, context, i::IsStaticFlag::kNotStatic, names_out, values_out);
} else { // Private fields
i::Handle<i::String> name(
i::String::cast(i::Symbol::cast(*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;
}
Local<Context> debug::GetCreationContext(Local<Object> value) {
i::Handle<i::Object> val = Utils::OpenHandle(*value);
if (val->IsJSGlobalProxy()) {
return Local<Context>();
}
return value->CreationContext();
}
void debug::ChangeBreakOnException(Isolate* isolate, ExceptionBreakState type) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->debug()->ChangeBreakOnException(
i::BreakException, type == BreakOnAnyException);
internal_isolate->debug()->ChangeBreakOnException(i::BreakUncaughtException,
type != NoBreakOnException);
}
void debug::SetBreakPointsActive(Isolate* v8_isolate, bool is_active) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->debug()->set_break_points_active(is_active);
}
void debug::PrepareStep(Isolate* v8_isolate, StepAction action) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate);
CHECK(isolate->debug()->CheckExecutionState());
// Clear all current stepping setup.
isolate->debug()->ClearStepping();
// Prepare step.
isolate->debug()->PrepareStep(static_cast<i::StepAction>(action));
}
void debug::ClearStepping(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
// Clear all current stepping setup.
isolate->debug()->ClearStepping();
}
void debug::BreakRightNow(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate);
isolate->debug()->HandleDebugBreak(i::kIgnoreIfAllFramesBlackboxed);
}
void debug::SetTerminateOnResume(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->debug()->SetTerminateOnResume();
}
bool debug::CanBreakProgram(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate);
// We cannot break a program if we are currently running a regexp.
// TODO(yangguo): fix this exception.
return !isolate->regexp_stack()->is_in_use() &&
isolate->debug()->AllFramesOnStackAreBlackboxed();
}
v8::Isolate* debug::Script::GetIsolate() const {
return reinterpret_cast<v8::Isolate*>(Utils::OpenHandle(this)->GetIsolate());
}
ScriptOriginOptions debug::Script::OriginOptions() const {
return Utils::OpenHandle(this)->origin_options();
}
bool debug::Script::WasCompiled() const {
return Utils::OpenHandle(this)->compilation_state() ==
i::Script::COMPILATION_STATE_COMPILED;
}
bool debug::Script::IsEmbedded() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
return script->context_data() ==
script->GetReadOnlyRoots().uninitialized_symbol();
}
int debug::Script::Id() const { return Utils::OpenHandle(this)->id(); }
int debug::Script::LineOffset() const {
return Utils::OpenHandle(this)->line_offset();
}
int debug::Script::ColumnOffset() const {
return Utils::OpenHandle(this)->column_offset();
}
std::vector<int> debug::Script::LineEnds() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) return std::vector<int>();
i::Isolate* isolate = script->GetIsolate();
i::HandleScope scope(isolate);
i::Script::InitLineEnds(isolate, script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends(i::FixedArray::cast(script->line_ends()),
isolate);
std::vector<int> result(line_ends->length());
for (int i = 0; i < line_ends->length(); ++i) {
i::Smi line_end = i::Smi::cast(line_ends->get(i));
result[i] = line_end.value();
}
return result;
}
MaybeLocal<String> debug::Script::Name() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->name(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
MaybeLocal<String> debug::Script::SourceURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source_url(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
MaybeLocal<String> debug::Script::SourceMappingURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source_mapping_url(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
Maybe<int> debug::Script::ContextId() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Object value = script->context_data();
if (value.IsSmi()) return Just(i::Smi::ToInt(value));
return Nothing<int>();
}
MaybeLocal<String> debug::Script::Source() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
bool debug::Script::IsWasm() const {
return Utils::OpenHandle(this)->type() == i::Script::TYPE_WASM;
}
bool debug::Script::IsModule() const {
return Utils::OpenHandle(this)->origin_options().IsModule();
}
namespace {
int GetSmiValue(i::Handle<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 debug::Script::GetPossibleBreakpoints(
const debug::Location& start, const debug::Location& end,
bool restrict_to_function,
std::vector<debug::BreakLocation>* locations) const {
CHECK(!start.IsEmpty());
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
i::wasm::NativeModule* native_module = script->wasm_native_module();
return i::WasmScript::GetPossibleBreakpoints(native_module, start, end,
locations);
}
i::Isolate* isolate = script->GetIsolate();
i::Script::InitLineEnds(isolate, script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends =
i::Handle<i::FixedArray>::cast(i::handle(script->line_ends(), isolate));
CHECK(line_ends->length());
int start_offset = GetSourceOffset(start);
int end_offset = end.IsEmpty()
? GetSmiValue(line_ends, line_ends->length() - 1) + 1
: GetSourceOffset(end);
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);
int current_line_end_index = 0;
for (const auto& v8_location : v8_locations) {
int offset = v8_location.position();
while (offset > GetSmiValue(line_ends, current_line_end_index)) {
++current_line_end_index;
CHECK(current_line_end_index < line_ends->length());
}
int line_offset = 0;
if (current_line_end_index > 0) {
line_offset = GetSmiValue(line_ends, current_line_end_index - 1) + 1;
}
locations->emplace_back(
current_line_end_index + script->line_offset(),
offset - line_offset +
(current_line_end_index == 0 ? script->column_offset() : 0),
v8_location.type());
}
return true;
}
int debug::Script::GetSourceOffset(const debug::Location& location) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
DCHECK_EQ(0, location.GetLineNumber());
return location.GetColumnNumber();
}
int line = std::max(location.GetLineNumber() - script->line_offset(), 0);
int column = location.GetColumnNumber();
if (line == 0) {
column = std::max(0, column - script->column_offset());
}
i::Script::InitLineEnds(script->GetIsolate(), script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends = i::Handle<i::FixedArray>::cast(
i::handle(script->line_ends(), script->GetIsolate()));
CHECK(line_ends->length());
if (line >= line_ends->length())
return GetSmiValue(line_ends, line_ends->length() - 1);
int line_offset = GetSmiValue(line_ends, line);
if (line == 0) return std::min(column, line_offset);
int prev_line_offset = GetSmiValue(line_ends, line - 1);
return std::min(prev_line_offset + column + 1, line_offset);
}
v8::debug::Location debug::Script::GetSourceLocation(int offset) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Script::PositionInfo info;
i::Script::GetPositionInfo(script, offset, &info, i::Script::WITH_OFFSET);
return debug::Location(info.line, info.column);
}
bool debug::Script::SetScriptSource(v8::Local<v8::String> newSource,
bool preview,
debug::LiveEditResult* result) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
return isolate->debug()->SetScriptSource(
script, Utils::OpenHandle(*newSource), preview, result);
}
bool debug::Script::SetBreakpoint(v8::Local<v8::String> condition,
debug::Location* location,
debug::BreakpointId* id) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
int offset = GetSourceOffset(*location);
if (!isolate->debug()->SetBreakPointForScript(
script, Utils::OpenHandle(*condition), &offset, id)) {
return false;
}
*location = GetSourceLocation(offset);
return true;
}
bool debug::Script::SetBreakpointOnScriptEntry(BreakpointId* id) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::SharedFunctionInfo::ScriptIterator it(isolate, *script);
for (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);
}
}
return false;
}
void debug::Script::RemoveWasmBreakpoint(debug::BreakpointId id) {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
isolate->debug()->RemoveBreakpointForWasmScript(script, id);
}
void debug::RemoveBreakpoint(Isolate* v8_isolate, BreakpointId id) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::HandleScope handle_scope(isolate);
isolate->debug()->RemoveBreakpoint(id);
}
v8::Platform* debug::GetCurrentPlatform() {
return i::V8::GetCurrentPlatform();
}
void debug::ForceGarbageCollection(
v8::Isolate* isolate,
v8::EmbedderHeapTracer::EmbedderStackState embedder_stack_state) {
i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
heap->SetEmbedderStackStateForNextFinalization(embedder_stack_state);
isolate->LowMemoryNotification();
}
debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) {
CHECK(script->IsWasm());
return static_cast<WasmScript*>(script);
}
debug::WasmScript::DebugSymbolsType debug::WasmScript::GetDebugSymbolType()
const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
switch (script->wasm_native_module()->module()->debug_symbols.type) {
case i::wasm::WasmDebugSymbols::Type::None:
return debug::WasmScript::DebugSymbolsType::None;
case i::wasm::WasmDebugSymbols::Type::EmbeddedDWARF:
return debug::WasmScript::DebugSymbolsType::EmbeddedDWARF;
case i::wasm::WasmDebugSymbols::Type::ExternalDWARF:
return debug::WasmScript::DebugSymbolsType::ExternalDWARF;
case i::wasm::WasmDebugSymbols::Type::SourceMap:
return debug::WasmScript::DebugSymbolsType::SourceMap;
}
}
MemorySpan<const char> debug::WasmScript::ExternalSymbolsURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
const i::wasm::WasmDebugSymbols& symbols =
script->wasm_native_module()->module()->debug_symbols;
if (symbols.external_url.is_empty()) return {};
internal::wasm::ModuleWireBytes wire_bytes(
script->wasm_native_module()->wire_bytes());
i::wasm::WasmName external_url =
wire_bytes.GetNameOrNull(symbols.external_url);
return {external_url.data(), external_url.size()};
}
int debug::WasmScript::NumFunctions() const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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 debug::WasmScript::NumImportedFunctions() const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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);
}
MemorySpan<const uint8_t> debug::WasmScript::Bytecode() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Vector<const uint8_t> wire_bytes =
script->wasm_native_module()->wire_bytes();
return {wire_bytes.begin(), wire_bytes.size()};
}
std::pair<int, int> debug::WasmScript::GetFunctionRange(
int function_index) const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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 debug::WasmScript::GetContainingFunction(int byte_offset) const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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);
}
uint32_t debug::WasmScript::GetFunctionHash(int function_index) {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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());
i::Vector<const i::byte> 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(), 0);
}
int debug::WasmScript::CodeOffset() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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();
}
debug::Location::Location(int line_number, int column_number)
: line_number_(line_number),
column_number_(column_number),
is_empty_(false) {}
debug::Location::Location()
: line_number_(v8::Function::kLineOffsetNotFound),
column_number_(v8::Function::kLineOffsetNotFound),
is_empty_(true) {}
int debug::Location::GetLineNumber() const {
DCHECK(!IsEmpty());
return line_number_;
}
int debug::Location::GetColumnNumber() const {
DCHECK(!IsEmpty());
return column_number_;
}
bool debug::Location::IsEmpty() const { return is_empty_; }
void debug::GetLoadedScripts(v8::Isolate* v8_isolate,
PersistentValueVector<debug::Script>& scripts) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
{
i::DisallowGarbageCollection no_gc;
i::Script::Iterator iterator(isolate);
for (i::Script script = iterator.Next(); !script.is_null();
script = iterator.Next()) {
if (script.type() == i::Script::TYPE_NORMAL ||
script.type() == i::Script::TYPE_WASM) {
if (script.HasValidSource()) {
i::HandleScope handle_scope(isolate);
i::Handle<i::Script> script_handle(script, isolate);
scripts.Append(ToApiHandle<Script>(script_handle));
}
}
}
}
}
MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
Local<String> source) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, UnboundScript);
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Handle<i::SharedFunctionInfo> result;
{
ScriptOriginOptions origin_options;
i::ScriptData* script_data = nullptr;
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, i::Compiler::ScriptDetails(), origin_options, nullptr,
script_data, ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheBecauseInspector,
i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE
: i::INSPECTOR_CODE);
has_pending_exception = !maybe_function_info.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(UnboundScript);
}
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
}
void debug::TierDownAllModulesPerIsolate(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->wasm_engine()->TierDownAllModulesPerIsolate(isolate);
}
void debug::TierUpAllModulesPerIsolate(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->wasm_engine()->TierUpAllModulesPerIsolate(isolate);
}
void debug::SetDebugDelegate(Isolate* v8_isolate,
debug::DebugDelegate* delegate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->debug()->SetDebugDelegate(delegate);
}
void debug::SetAsyncEventDelegate(Isolate* v8_isolate,
debug::AsyncEventDelegate* delegate) {
reinterpret_cast<i::Isolate*>(v8_isolate)->set_async_event_delegate(delegate);
}
void debug::ResetBlackboxedStateCache(Isolate* v8_isolate,
v8::Local<debug::Script> script) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::DisallowGarbageCollection no_gc;
i::SharedFunctionInfo::ScriptIterator iter(isolate,
*Utils::OpenHandle(*script));
for (i::SharedFunctionInfo info = iter.Next(); !info.is_null();
info = iter.Next()) {
if (info.HasDebugInfo()) {
info.GetDebugInfo().set_computed_debug_is_blackboxed(false);
}
}
}
int debug::EstimatedValueSize(Isolate* v8_isolate, v8::Local<v8::Value> value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> object = Utils::OpenHandle(*value);
if (object->IsSmi()) return i::kTaggedSize;
CHECK(object->IsHeapObject());
return i::Handle<i::HeapObject>::cast(object)->Size();
}
v8::MaybeLocal<v8::Array> v8::Object::PreviewEntries(bool* is_key_value) {
if (IsMap()) {
*is_key_value = true;
......@@ -10329,206 +9366,6 @@ v8::MaybeLocal<v8::Array> v8::Object::PreviewEntries(bool* is_key_value) {
return v8::MaybeLocal<v8::Array>();
}
Local<Function> debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope handle_scope(isolate);
CHECK_EQ(builtin, kStringToLowerCase);
i::Builtins::Name builtin_id = i::Builtins::kStringPrototypeToLocaleLowerCase;
i::Factory* factory = isolate->factory();
i::Handle<i::String> name = isolate->factory()->empty_string();
i::Handle<i::NativeContext> context(isolate->native_context());
i::Handle<i::SharedFunctionInfo> info =
factory->NewSharedFunctionInfoForBuiltin(name, builtin_id);
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();
fun->shared().set_internal_formal_parameter_count(0);
fun->shared().set_length(0);
return Utils::ToLocal(handle_scope.CloseAndEscape(fun));
}
void debug::SetConsoleDelegate(Isolate* v8_isolate, ConsoleDelegate* delegate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->set_console_delegate(delegate);
}
debug::ConsoleCallArguments::ConsoleCallArguments(
const v8::FunctionCallbackInfo<v8::Value>& info)
: v8::FunctionCallbackInfo<v8::Value>(nullptr, info.values_, info.length_) {
}
debug::ConsoleCallArguments::ConsoleCallArguments(
const internal::BuiltinArguments& args)
: v8::FunctionCallbackInfo<v8::Value>(
nullptr,
// Drop the first argument (receiver, i.e. the "console" object).
args.length() > 1 ? args.address_of_first_argument() : nullptr,
args.length() - 1) {}
// Marked V8_DEPRECATED.
int debug::GetStackFrameId(v8::Local<v8::StackFrame> frame) { return 0; }
v8::Local<v8::StackTrace> debug::GetDetailedStackTrace(
Isolate* v8_isolate, v8::Local<v8::Object> v8_error) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Handle<i::JSReceiver> error = Utils::OpenHandle(*v8_error);
if (!error->IsJSObject()) {
return v8::Local<v8::StackTrace>();
}
i::Handle<i::FixedArray> stack_trace =
isolate->GetDetailedStackTrace(i::Handle<i::JSObject>::cast(error));
return Utils::StackTraceToLocal(stack_trace);
}
MaybeLocal<debug::Script> debug::GeneratorObject::Script() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
i::Object maybe_script = obj->function().shared().script();
if (!maybe_script.IsScript()) return MaybeLocal<debug::Script>();
i::Handle<i::Script> script(i::Script::cast(maybe_script), obj->GetIsolate());
return ToApiHandle<debug::Script>(script);
}
Local<Function> debug::GeneratorObject::Function() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
return Utils::ToLocal(handle(obj->function(), obj->GetIsolate()));
}
debug::Location debug::GeneratorObject::SuspendedLocation() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
CHECK(obj->is_suspended());
i::Object maybe_script = obj->function().shared().script();
if (!maybe_script.IsScript()) return debug::Location();
i::Isolate* isolate = obj->GetIsolate();
i::Handle<i::Script> script(i::Script::cast(maybe_script), isolate);
i::Script::PositionInfo info;
i::SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate, i::handle(obj->function().shared(), isolate));
i::Script::GetPositionInfo(script, obj->source_position(), &info,
i::Script::WITH_OFFSET);
return debug::Location(info.line, info.column);
}
bool debug::GeneratorObject::IsSuspended() {
return Utils::OpenHandle(this)->is_suspended();
}
v8::Local<debug::GeneratorObject> debug::GeneratorObject::Cast(
v8::Local<v8::Value> value) {
CHECK(value->IsGeneratorObject());
return ToApiHandle<debug::GeneratorObject>(Utils::OpenHandle(*value));
}
MaybeLocal<v8::Value> debug::EvaluateGlobal(v8::Isolate* isolate,
v8::Local<v8::String> source,
EvaluateGlobalMode mode,
bool repl) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(internal_isolate, Value);
i::REPLMode repl_mode = repl ? i::REPLMode::kYes : i::REPLMode::kNo;
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
i::DebugEvaluate::Global(internal_isolate, Utils::OpenHandle(*source),
mode, repl_mode),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
void debug::QueryObjects(v8::Local<v8::Context> v8_context,
QueryObjectPredicate* predicate,
PersistentValueVector<v8::Object>* objects) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_context->GetIsolate());
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->heap_profiler()->QueryObjects(Utils::OpenHandle(*v8_context),
predicate, objects);
}
void debug::GlobalLexicalScopeNames(
v8::Local<v8::Context> v8_context,
v8::PersistentValueVector<v8::String>* names) {
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
i::Isolate* isolate = context->GetIsolate();
i::Handle<i::ScriptContextTable> table(
context->global_object().native_context().script_context_table(),
isolate);
for (int i = 0; i < table->synchronized_used(); i++) {
i::Handle<i::Context> context =
i::ScriptContextTable::GetContext(isolate, table, i);
DCHECK(context->IsScriptContext());
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::String name = scope_info->ContextLocalName(j);
if (i::ScopeInfo::VariableIsSynthetic(name)) continue;
names->Append(Utils::ToLocal(handle(name, isolate)));
}
}
}
void debug::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::OpenHandle(*value));
}
int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) {
return reinterpret_cast<i::Isolate*>(v8_isolate)
->random_number_generator()
->NextInt64();
}
void debug::EnumerateRuntimeCallCounters(v8::Isolate* v8_isolate,
RuntimeCallCounterCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
if (isolate->counters()) {
isolate->counters()->runtime_call_stats()->EnumerateCounters(callback);
}
}
int debug::GetDebuggingId(v8::Local<v8::Function> function) {
i::Handle<i::JSReceiver> callable = v8::Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return i::DebugInfo::kNoDebuggingId;
i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(callable);
int id = func->GetIsolate()->debug()->GetFunctionDebuggingId(func);
DCHECK_NE(i::DebugInfo::kNoDebuggingId, id);
return id;
}
bool debug::SetFunctionBreakpoint(v8::Local<v8::Function> function,
v8::Local<v8::String> condition,
BreakpointId* id) {
i::Handle<i::JSReceiver> callable = Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return false;
i::Handle<i::JSFunction> jsfunction =
i::Handle<i::JSFunction>::cast(callable);
i::Isolate* isolate = jsfunction->GetIsolate();
i::Handle<i::String> condition_string =
condition.IsEmpty() ? isolate->factory()->empty_string()
: Utils::OpenHandle(*condition);
return isolate->debug()->SetBreakpointForFunction(
handle(jsfunction->shared(), isolate), condition_string, id);
}
debug::PostponeInterruptsScope::PostponeInterruptsScope(v8::Isolate* isolate)
: scope_(
new i::PostponeInterruptsScope(reinterpret_cast<i::Isolate*>(isolate),
i::StackGuard::API_INTERRUPT)) {}
debug::PostponeInterruptsScope::~PostponeInterruptsScope() = default;
debug::DisableBreakScope::DisableBreakScope(v8::Isolate* isolate)
: scope_(std::make_unique<i::DisableBreak>(
reinterpret_cast<i::Isolate*>(isolate)->debug())) {}
debug::DisableBreakScope::~DisableBreakScope() = default;
Local<String> CpuProfileNode::GetFunctionName() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate();
......@@ -10538,193 +9375,6 @@ Local<String> CpuProfileNode::GetFunctionName() const {
return ToApiHandle<String>(name);
}
int debug::Coverage::BlockData::StartOffset() const { return block_->start; }
int debug::Coverage::BlockData::EndOffset() const { return block_->end; }
uint32_t debug::Coverage::BlockData::Count() const { return block_->count; }
int debug::Coverage::FunctionData::StartOffset() const {
return function_->start;
}
int debug::Coverage::FunctionData::EndOffset() const { return function_->end; }
uint32_t debug::Coverage::FunctionData::Count() const {
return function_->count;
}
MaybeLocal<String> debug::Coverage::FunctionData::Name() const {
return ToApiHandle<String>(function_->name);
}
size_t debug::Coverage::FunctionData::BlockCount() const {
return function_->blocks.size();
}
bool debug::Coverage::FunctionData::HasBlockCoverage() const {
return function_->has_block_coverage;
}
debug::Coverage::BlockData debug::Coverage::FunctionData::GetBlockData(
size_t i) const {
return BlockData(&function_->blocks.at(i), coverage_);
}
Local<debug::Script> debug::Coverage::ScriptData::GetScript() const {
return ToApiHandle<debug::Script>(script_->script);
}
size_t debug::Coverage::ScriptData::FunctionCount() const {
return script_->functions.size();
}
debug::Coverage::FunctionData debug::Coverage::ScriptData::GetFunctionData(
size_t i) const {
return FunctionData(&script_->functions.at(i), coverage_);
}
debug::Coverage::ScriptData::ScriptData(size_t index,
std::shared_ptr<i::Coverage> coverage)
: script_(&coverage->at(index)), coverage_(std::move(coverage)) {}
size_t debug::Coverage::ScriptCount() const { return coverage_->size(); }
debug::Coverage::ScriptData debug::Coverage::GetScriptData(size_t i) const {
return ScriptData(i, coverage_);
}
debug::Coverage debug::Coverage::CollectPrecise(Isolate* isolate) {
return Coverage(
i::Coverage::CollectPrecise(reinterpret_cast<i::Isolate*>(isolate)));
}
debug::Coverage debug::Coverage::CollectBestEffort(Isolate* isolate) {
return Coverage(
i::Coverage::CollectBestEffort(reinterpret_cast<i::Isolate*>(isolate)));
}
void debug::Coverage::SelectMode(Isolate* isolate, debug::CoverageMode mode) {
i::Coverage::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
}
int debug::TypeProfile::Entry::SourcePosition() const {
return entry_->position;
}
std::vector<MaybeLocal<String>> debug::TypeProfile::Entry::Types() const {
std::vector<MaybeLocal<String>> result;
for (const internal::Handle<internal::String>& type : entry_->types) {
result.emplace_back(ToApiHandle<String>(type));
}
return result;
}
debug::TypeProfile::ScriptData::ScriptData(
size_t index, std::shared_ptr<i::TypeProfile> type_profile)
: script_(&type_profile->at(index)),
type_profile_(std::move(type_profile)) {}
Local<debug::Script> debug::TypeProfile::ScriptData::GetScript() const {
return ToApiHandle<debug::Script>(script_->script);
}
std::vector<debug::TypeProfile::Entry> debug::TypeProfile::ScriptData::Entries()
const {
std::vector<debug::TypeProfile::Entry> result;
for (const internal::TypeProfileEntry& entry : script_->entries) {
result.push_back(debug::TypeProfile::Entry(&entry, type_profile_));
}
return result;
}
debug::TypeProfile debug::TypeProfile::Collect(Isolate* isolate) {
return TypeProfile(
i::TypeProfile::Collect(reinterpret_cast<i::Isolate*>(isolate)));
}
void debug::TypeProfile::SelectMode(Isolate* isolate,
debug::TypeProfileMode mode) {
i::TypeProfile::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
}
size_t debug::TypeProfile::ScriptCount() const { return type_profile_->size(); }
debug::TypeProfile::ScriptData debug::TypeProfile::GetScriptData(
size_t i) const {
return ScriptData(i, type_profile_);
}
v8::MaybeLocal<v8::Value> debug::WeakMap::Get(v8::Local<v8::Context> context,
v8::Local<v8::Value> key) {
PREPARE_FOR_EXECUTION(context, WeakMap, Get, Value);
auto self = Utils::OpenHandle(this);
Local<Value> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)};
has_pending_exception =
!ToLocal<Value>(i::Execution::CallBuiltin(isolate, isolate->weakmap_get(),
self, arraysize(argv), argv),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
v8::MaybeLocal<debug::WeakMap> debug::WeakMap::Set(
v8::Local<v8::Context> context, v8::Local<v8::Value> key,
v8::Local<v8::Value> value) {
PREPARE_FOR_EXECUTION(context, WeakMap, Set, WeakMap);
auto self = Utils::OpenHandle(this);
i::Handle<i::Object> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key),
Utils::OpenHandle(*value)};
has_pending_exception =
!i::Execution::CallBuiltin(isolate, isolate->weakmap_set(), self,
arraysize(argv), argv)
.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(WeakMap);
RETURN_ESCAPED(Local<WeakMap>::Cast(Utils::ToLocal(result)));
}
Local<debug::WeakMap> debug::WeakMap::New(v8::Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, WeakMap, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::JSWeakMap> obj = i_isolate->factory()->NewJSWeakMap();
return ToApiHandle<debug::WeakMap>(obj);
}
debug::WeakMap* debug::WeakMap::Cast(v8::Value* value) {
return static_cast<debug::WeakMap*>(value);
}
Local<Value> debug::AccessorPair::getter() {
i::Handle<i::AccessorPair> accessors = Utils::OpenHandle(this);
i::Isolate* isolate = accessors->GetIsolate();
i::Handle<i::Object> getter(accessors->getter(), isolate);
return Utils::ToLocal(getter);
}
Local<Value> debug::AccessorPair::setter() {
i::Handle<i::AccessorPair> accessors = Utils::OpenHandle(this);
i::Isolate* isolate = accessors->GetIsolate();
i::Handle<i::Object> setter(accessors->setter(), isolate);
return Utils::ToLocal(setter);
}
bool debug::AccessorPair::IsAccessorPair(Local<Value> that) {
i::Handle<i::Object> obj = Utils::OpenHandle(*that);
return obj->IsAccessorPair();
}
MaybeLocal<Message> debug::GetMessageFromPromise(Local<Promise> p) {
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*p);
i::Isolate* isolate = promise->GetIsolate();
i::Handle<i::Symbol> key = isolate->factory()->promise_debug_message_symbol();
i::Handle<i::Object> maybeMessage =
i::JSReceiver::GetDataProperty(promise, key);
if (!maybeMessage->IsJSMessageObject(isolate)) return MaybeLocal<Message>();
return ToApiHandle<Message>(
i::Handle<i::JSMessageObject>::cast(maybeMessage));
}
const char* CpuProfileNode::GetFunctionNameStr() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
return node->entry()->name();
......@@ -11349,24 +9999,6 @@ RegisterState& RegisterState::operator=(const RegisterState& other) {
return *this;
}
std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
Local<Context> context, Local<Object> object) {
internal::Isolate* isolate =
reinterpret_cast<internal::Isolate*>(object->GetIsolate());
if (IsExecutionTerminatingCheck(isolate)) {
return nullptr;
}
CallDepthScope<false> call_depth_scope(isolate, context);
auto result = internal::DebugPropertyIterator::Create(
isolate, Utils::OpenHandle(*object));
if (!result) {
DCHECK(isolate->has_pending_exception());
call_depth_scope.Escape();
}
return result;
}
namespace internal {
const size_t HandleScopeImplementer::kEnteredContextsOffset =
......@@ -11547,37 +10179,7 @@ void InvokeFinalizationRegistryCleanupFromTask(
}
}
Maybe<bool> DebugPropertyIterator::Advance() {
if (IsExecutionTerminatingCheck(isolate_)) {
return Nothing<bool>();
}
Local<v8::Context> context =
Utils::ToLocal(handle(isolate_->context(), isolate_));
CallDepthScope<false> call_depth_scope(isolate_, context);
if (!AdvanceInternal()) {
DCHECK(isolate_->has_pending_exception());
call_depth_scope.Escape();
return Nothing<bool>();
}
return Just(true);
}
// Undefine macros for jumbo build.
#undef LOG_API
#undef ENTER_V8_DO_NOT_USE
#undef ENTER_V8_HELPER_DO_NOT_USE
#undef PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE
#undef PREPARE_FOR_EXECUTION_WITH_CONTEXT
#undef PREPARE_FOR_EXECUTION
#undef ENTER_V8
#undef ENTER_V8_NO_SCRIPT
#undef ENTER_V8_NO_SCRIPT_NO_EXCEPTION
#undef ENTER_V8_FOR_NEW_CONTEXT
#undef EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE
#undef RETURN_ON_FAILED_EXECUTION
#undef RETURN_ON_FAILED_EXECUTION_PRIMITIVE
#undef RETURN_ESCAPED
#undef SET_FIELD_WRAPPED
#undef NEW_STRING
#undef CALLBACK_SETTER
......@@ -11586,3 +10188,4 @@ Maybe<bool> DebugPropertyIterator::Advance() {
} // namespace v8
#undef TRACE_BS
#include "src/api/api-macros-undef.h"
// 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 "src/api/api-inl.h"
#include "src/debug/debug-coverage.h"
#include "src/debug/debug-evaluate.h"
#include "src/debug/debug-property-iterator.h"
#include "src/debug/debug-type-profile.h"
#include "src/debug/debug.h"
#include "src/execution/vm-state-inl.h"
#include "src/objects/js-generator-inl.h"
#include "src/regexp/regexp-stack.h"
// Has to be the last include (doesn't have include guards):
#include "src/api/api-macros.h"
namespace v8 {
namespace debug {
void SetContextId(Local<Context> context, int id) {
Utils::OpenHandle(*context)->set_debug_context_id(i::Smi::FromInt(id));
}
int GetContextId(Local<Context> context) {
i::Object value = Utils::OpenHandle(*context)->debug_context_id();
return (value.IsSmi()) ? i::Smi::ToInt(value) : 0;
}
void SetInspector(Isolate* isolate, v8_inspector::V8Inspector* inspector) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i_isolate->set_inspector(inspector);
}
v8_inspector::V8Inspector* GetInspector(Isolate* isolate) {
return reinterpret_cast<i::Isolate*>(isolate)->inspector();
}
void SetBreakOnNextFunctionCall(Isolate* isolate) {
reinterpret_cast<i::Isolate*>(isolate)->debug()->SetBreakOnNextFunctionCall();
}
void ClearBreakOnNextFunctionCall(Isolate* isolate) {
reinterpret_cast<i::Isolate*>(isolate)
->debug()
->ClearBreakOnNextFunctionCall();
}
MaybeLocal<Array> GetInternalProperties(Isolate* v8_isolate,
Local<Value> value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> val = Utils::OpenHandle(*value);
i::Handle<i::JSArray> result;
if (!i::Runtime::GetInternalProperties(isolate, val).ToHandle(&result))
return MaybeLocal<Array>();
return Utils::ToLocal(result);
}
namespace {
void CollectPrivateMethodsAndAccessorsFromContext(
i::Isolate* isolate, i::Handle<i::Context> context,
i::IsStaticFlag is_static_flag, std::vector<Local<Value>>* names_out,
std::vector<Local<Value>>* values_out) {
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::VariableMode mode = scope_info->ContextLocalMode(j);
i::IsStaticFlag flag = scope_info->ContextLocalIsStaticFlag(j);
if (!i::IsPrivateMethodOrAccessorVariableMode(mode) ||
flag != is_static_flag) {
continue;
}
i::Handle<i::String> name(scope_info->ContextLocalName(j), isolate);
int context_index = scope_info->ContextHeaderLength() + j;
i::Handle<i::Object> slot_value(context->get(context_index), isolate);
DCHECK_IMPLIES(mode == i::VariableMode::kPrivateMethod,
slot_value->IsJSFunction());
DCHECK_IMPLIES(mode != i::VariableMode::kPrivateMethod,
slot_value->IsAccessorPair());
names_out->push_back(Utils::ToLocal(name));
values_out->push_back(Utils::ToLocal(slot_value));
}
}
} // namespace
bool GetPrivateMembers(Local<Context> context, Local<Object> value,
std::vector<Local<Value>>* names_out,
std::vector<Local<Value>>* values_out) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
LOG_API(isolate, debug, GetPrivateMembers);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::JSReceiver> receiver = Utils::OpenHandle(*value);
i::Handle<i::JSArray> names;
i::Handle<i::FixedArray> values;
i::PropertyFilter key_filter =
static_cast<i::PropertyFilter>(i::PropertyFilter::PRIVATE_NAMES_ONLY);
i::Handle<i::FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, keys,
i::KeyAccumulator::GetKeys(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;
for (int i = 0; i < keys->length(); ++i) {
// Exclude the private brand symbols.
i::Handle<i::Symbol> key(i::Symbol::cast(keys->get(i)), isolate);
if (key->is_private_brand()) {
i::Handle<i::Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value, i::Object::GetProperty(isolate, receiver, key),
false);
i::Handle<i::Context> context(i::Context::cast(*value), isolate);
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
// At least one slot contains the brand symbol so it does not count.
private_entries_count += (scope_info->ContextLocalCount() - 1);
} else {
private_entries_count++;
}
}
// Estimate number of static private methods/accessors for classes.
bool has_static_private_methods_or_accessors = false;
if (receiver->IsJSFunction()) {
i::Handle<i::JSFunction> func(i::JSFunction::cast(*receiver), isolate);
i::Handle<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::Handle<i::Context> context(func->context(), isolate);
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::VariableMode mode = scope_info->ContextLocalMode(j);
i::IsStaticFlag is_static_flag =
scope_info->ContextLocalIsStaticFlag(j);
if (i::IsPrivateMethodOrAccessorVariableMode(mode) &&
is_static_flag == i::IsStaticFlag::kStatic) {
private_entries_count += local_count;
break;
}
}
}
}
DCHECK(names_out->empty());
names_out->reserve(private_entries_count);
DCHECK(values_out->empty());
values_out->reserve(private_entries_count);
if (has_static_private_methods_or_accessors) {
i::Handle<i::Context> context(i::JSFunction::cast(*receiver).context(),
isolate);
CollectPrivateMethodsAndAccessorsFromContext(
isolate, context, i::IsStaticFlag::kStatic, names_out, values_out);
}
for (int i = 0; i < keys->length(); ++i) {
i::Handle<i::Object> obj_key(keys->get(i), isolate);
i::Handle<i::Symbol> key(i::Symbol::cast(*obj_key), isolate);
CHECK(key->is_private_name());
i::Handle<i::Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value, i::Object::GetProperty(isolate, receiver, key), false);
if (key->is_private_brand()) {
DCHECK(value->IsContext());
i::Handle<i::Context> context(i::Context::cast(*value), isolate);
CollectPrivateMethodsAndAccessorsFromContext(
isolate, context, i::IsStaticFlag::kNotStatic, names_out, values_out);
} else { // Private fields
i::Handle<i::String> name(
i::String::cast(i::Symbol::cast(*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;
}
Local<Context> GetCreationContext(Local<Object> value) {
i::Handle<i::Object> val = Utils::OpenHandle(*value);
if (val->IsJSGlobalProxy()) {
return Local<Context>();
}
return value->CreationContext();
}
void ChangeBreakOnException(Isolate* isolate, ExceptionBreakState type) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->debug()->ChangeBreakOnException(
i::BreakException, type == BreakOnAnyException);
internal_isolate->debug()->ChangeBreakOnException(i::BreakUncaughtException,
type != NoBreakOnException);
}
void SetBreakPointsActive(Isolate* v8_isolate, bool is_active) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(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);
ENTER_V8_DO_NOT_USE(isolate);
CHECK(isolate->debug()->CheckExecutionState());
// Clear all current stepping setup.
isolate->debug()->ClearStepping();
// Prepare step.
isolate->debug()->PrepareStep(static_cast<i::StepAction>(action));
}
void ClearStepping(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
// Clear all current stepping setup.
isolate->debug()->ClearStepping();
}
void BreakRightNow(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate);
isolate->debug()->HandleDebugBreak(i::kIgnoreIfAllFramesBlackboxed);
}
void SetTerminateOnResume(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->debug()->SetTerminateOnResume();
}
bool CanBreakProgram(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate);
// We cannot break a program if we are currently running a regexp.
// TODO(yangguo): fix this exception.
return !isolate->regexp_stack()->is_in_use() &&
isolate->debug()->AllFramesOnStackAreBlackboxed();
}
Isolate* Script::GetIsolate() const {
return reinterpret_cast<Isolate*>(Utils::OpenHandle(this)->GetIsolate());
}
ScriptOriginOptions Script::OriginOptions() const {
return Utils::OpenHandle(this)->origin_options();
}
bool Script::WasCompiled() const {
return Utils::OpenHandle(this)->compilation_state() ==
i::Script::COMPILATION_STATE_COMPILED;
}
bool Script::IsEmbedded() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
return script->context_data() ==
script->GetReadOnlyRoots().uninitialized_symbol();
}
int Script::Id() const { return Utils::OpenHandle(this)->id(); }
int Script::LineOffset() const {
return Utils::OpenHandle(this)->line_offset();
}
int Script::ColumnOffset() const {
return Utils::OpenHandle(this)->column_offset();
}
std::vector<int> Script::LineEnds() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) return std::vector<int>();
i::Isolate* isolate = script->GetIsolate();
i::HandleScope scope(isolate);
i::Script::InitLineEnds(isolate, script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends(i::FixedArray::cast(script->line_ends()),
isolate);
std::vector<int> result(line_ends->length());
for (int i = 0; i < line_ends->length(); ++i) {
i::Smi line_end = i::Smi::cast(line_ends->get(i));
result[i] = line_end.value();
}
return result;
}
MaybeLocal<String> Script::Name() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->name(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
MaybeLocal<String> Script::SourceURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source_url(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
MaybeLocal<String> Script::SourceMappingURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source_mapping_url(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
Maybe<int> Script::ContextId() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Object value = script->context_data();
if (value.IsSmi()) return Just(i::Smi::ToInt(value));
return Nothing<int>();
}
MaybeLocal<String> Script::Source() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> value(script->source(), isolate);
if (!value->IsString()) return MaybeLocal<String>();
return Utils::ToLocal(
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
bool Script::IsWasm() const {
return Utils::OpenHandle(this)->type() == i::Script::TYPE_WASM;
}
bool Script::IsModule() const {
return Utils::OpenHandle(this)->origin_options().IsModule();
}
namespace {
int GetSmiValue(i::Handle<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 (script->type() == i::Script::TYPE_WASM) {
i::wasm::NativeModule* native_module = script->wasm_native_module();
return i::WasmScript::GetPossibleBreakpoints(native_module, start, end,
locations);
}
i::Isolate* isolate = script->GetIsolate();
i::Script::InitLineEnds(isolate, script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends =
i::Handle<i::FixedArray>::cast(i::handle(script->line_ends(), isolate));
CHECK(line_ends->length());
int start_offset = GetSourceOffset(start);
int end_offset = end.IsEmpty()
? GetSmiValue(line_ends, line_ends->length() - 1) + 1
: GetSourceOffset(end);
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);
int current_line_end_index = 0;
for (const auto& v8_location : v8_locations) {
int offset = v8_location.position();
while (offset > GetSmiValue(line_ends, current_line_end_index)) {
++current_line_end_index;
CHECK(current_line_end_index < line_ends->length());
}
int line_offset = 0;
if (current_line_end_index > 0) {
line_offset = GetSmiValue(line_ends, current_line_end_index - 1) + 1;
}
locations->emplace_back(
current_line_end_index + script->line_offset(),
offset - line_offset +
(current_line_end_index == 0 ? script->column_offset() : 0),
v8_location.type());
}
return true;
}
int Script::GetSourceOffset(const Location& location) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
DCHECK_EQ(0, location.GetLineNumber());
return location.GetColumnNumber();
}
int line = std::max(location.GetLineNumber() - script->line_offset(), 0);
int column = location.GetColumnNumber();
if (line == 0) {
column = std::max(0, column - script->column_offset());
}
i::Script::InitLineEnds(script->GetIsolate(), script);
CHECK(script->line_ends().IsFixedArray());
i::Handle<i::FixedArray> line_ends = i::Handle<i::FixedArray>::cast(
i::handle(script->line_ends(), script->GetIsolate()));
CHECK(line_ends->length());
if (line >= line_ends->length())
return GetSmiValue(line_ends, line_ends->length() - 1);
int line_offset = GetSmiValue(line_ends, line);
if (line == 0) return std::min(column, line_offset);
int prev_line_offset = GetSmiValue(line_ends, line - 1);
return std::min(prev_line_offset + column + 1, line_offset);
}
Location Script::GetSourceLocation(int offset) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Script::PositionInfo info;
i::Script::GetPositionInfo(script, offset, &info, i::Script::WITH_OFFSET);
return Location(info.line, info.column);
}
bool Script::SetScriptSource(Local<String> newSource, bool preview,
LiveEditResult* result) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
return isolate->debug()->SetScriptSource(
script, Utils::OpenHandle(*newSource), preview, result);
}
bool Script::SetBreakpoint(Local<String> condition, Location* location,
BreakpointId* id) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
int offset = GetSourceOffset(*location);
if (!isolate->debug()->SetBreakPointForScript(
script, Utils::OpenHandle(*condition), &offset, id)) {
return false;
}
*location = GetSourceLocation(offset);
return true;
}
bool Script::SetBreakpointOnScriptEntry(BreakpointId* id) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
i::SharedFunctionInfo::ScriptIterator it(isolate, *script);
for (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);
}
}
return false;
}
void Script::RemoveWasmBreakpoint(BreakpointId id) {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
isolate->debug()->RemoveBreakpointForWasmScript(script, id);
}
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,
EmbedderHeapTracer::EmbedderStackState embedder_stack_state) {
i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
heap->SetEmbedderStackStateForNextFinalization(embedder_stack_state);
isolate->LowMemoryNotification();
}
WasmScript* WasmScript::Cast(Script* script) {
CHECK(script->IsWasm());
return static_cast<WasmScript*>(script);
}
WasmScript::DebugSymbolsType WasmScript::GetDebugSymbolType() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
switch (script->wasm_native_module()->module()->debug_symbols.type) {
case i::wasm::WasmDebugSymbols::Type::None:
return WasmScript::DebugSymbolsType::None;
case i::wasm::WasmDebugSymbols::Type::EmbeddedDWARF:
return WasmScript::DebugSymbolsType::EmbeddedDWARF;
case i::wasm::WasmDebugSymbols::Type::ExternalDWARF:
return WasmScript::DebugSymbolsType::ExternalDWARF;
case i::wasm::WasmDebugSymbols::Type::SourceMap:
return WasmScript::DebugSymbolsType::SourceMap;
}
}
MemorySpan<const char> WasmScript::ExternalSymbolsURL() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
const i::wasm::WasmDebugSymbols& symbols =
script->wasm_native_module()->module()->debug_symbols;
if (symbols.external_url.is_empty()) return {};
internal::wasm::ModuleWireBytes wire_bytes(
script->wasm_native_module()->wire_bytes());
i::wasm::WasmName external_url =
wire_bytes.GetNameOrNull(symbols.external_url);
return {external_url.data(), external_url.size()};
}
int WasmScript::NumFunctions() const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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);
}
MemorySpan<const uint8_t> WasmScript::Bytecode() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Vector<const uint8_t> wire_bytes =
script->wasm_native_module()->wire_bytes();
return {wire_bytes.begin(), wire_bytes.size()};
}
std::pair<int, int> WasmScript::GetFunctionRange(int function_index) const {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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);
}
uint32_t WasmScript::GetFunctionHash(int function_index) {
i::DisallowGarbageCollection no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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());
i::Vector<const i::byte> 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(), 0);
}
int WasmScript::CodeOffset() const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, 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();
}
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,
PersistentValueVector<Script>& scripts) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
{
i::DisallowGarbageCollection no_gc;
i::Script::Iterator iterator(isolate);
for (i::Script script = iterator.Next(); !script.is_null();
script = iterator.Next()) {
if (script.type() == i::Script::TYPE_NORMAL ||
script.type() == i::Script::TYPE_WASM) {
if (script.HasValidSource()) {
i::HandleScope handle_scope(isolate);
i::Handle<i::Script> script_handle(script, isolate);
scripts.Append(ToApiHandle<Script>(script_handle));
}
}
}
}
}
MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* v8_isolate,
Local<String> source) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(isolate, UnboundScript);
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Handle<i::SharedFunctionInfo> result;
{
ScriptOriginOptions origin_options;
i::ScriptData* script_data = nullptr;
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, i::Compiler::ScriptDetails(), origin_options, nullptr,
script_data, ScriptCompiler::kNoCompileOptions,
ScriptCompiler::kNoCacheBecauseInspector,
i::FLAG_expose_inspector_scripts ? i::NOT_NATIVES_CODE
: i::INSPECTOR_CODE);
has_pending_exception = !maybe_function_info.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(UnboundScript);
}
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
}
void TierDownAllModulesPerIsolate(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->wasm_engine()->TierDownAllModulesPerIsolate(isolate);
}
void TierUpAllModulesPerIsolate(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->wasm_engine()->TierUpAllModulesPerIsolate(isolate);
}
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);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::DisallowGarbageCollection no_gc;
i::SharedFunctionInfo::ScriptIterator iter(isolate,
*Utils::OpenHandle(*script));
for (i::SharedFunctionInfo info = iter.Next(); !info.is_null();
info = iter.Next()) {
if (info.HasDebugInfo()) {
info.GetDebugInfo().set_computed_debug_is_blackboxed(false);
}
}
}
int EstimatedValueSize(Isolate* v8_isolate, Local<Value> value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::Handle<i::Object> object = Utils::OpenHandle(*value);
if (object->IsSmi()) return i::kTaggedSize;
CHECK(object->IsHeapObject());
return i::Handle<i::HeapObject>::cast(object)->Size();
}
void AccessorPair::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsAccessorPair(), "v8::debug::AccessorPair::Cast",
"Value is not a v8::debug::AccessorPair");
}
Local<Function> GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope handle_scope(isolate);
CHECK_EQ(builtin, kStringToLowerCase);
i::Builtins::Name builtin_id = i::Builtins::kStringPrototypeToLocaleLowerCase;
i::Factory* factory = isolate->factory();
i::Handle<i::String> name = isolate->factory()->empty_string();
i::Handle<i::NativeContext> context(isolate->native_context());
i::Handle<i::SharedFunctionInfo> info =
factory->NewSharedFunctionInfoForBuiltin(name, builtin_id);
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();
fun->shared().set_internal_formal_parameter_count(0);
fun->shared().set_length(0);
return Utils::ToLocal(handle_scope.CloseAndEscape(fun));
}
void SetConsoleDelegate(Isolate* v8_isolate, ConsoleDelegate* delegate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->set_console_delegate(delegate);
}
ConsoleCallArguments::ConsoleCallArguments(
const v8::FunctionCallbackInfo<v8::Value>& info)
: v8::FunctionCallbackInfo<v8::Value>(nullptr, info.values_, info.length_) {
}
ConsoleCallArguments::ConsoleCallArguments(
const internal::BuiltinArguments& args)
: v8::FunctionCallbackInfo<v8::Value>(
nullptr,
// Drop the first argument (receiver, i.e. the "console" object).
args.length() > 1 ? args.address_of_first_argument() : nullptr,
args.length() - 1) {}
// Marked V8_DEPRECATED.
int GetStackFrameId(v8::Local<v8::StackFrame> frame) { return 0; }
v8::Local<v8::StackTrace> GetDetailedStackTrace(
Isolate* v8_isolate, v8::Local<v8::Object> v8_error) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Handle<i::JSReceiver> error = Utils::OpenHandle(*v8_error);
if (!error->IsJSObject()) {
return v8::Local<v8::StackTrace>();
}
i::Handle<i::FixedArray> stack_trace =
isolate->GetDetailedStackTrace(i::Handle<i::JSObject>::cast(error));
return Utils::StackTraceToLocal(stack_trace);
}
MaybeLocal<Script> GeneratorObject::Script() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
i::Object maybe_script = obj->function().shared().script();
if (!maybe_script.IsScript()) return {};
i::Handle<i::Script> script(i::Script::cast(maybe_script), obj->GetIsolate());
return ToApiHandle<v8::debug::Script>(script);
}
Local<Function> GeneratorObject::Function() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
return Utils::ToLocal(handle(obj->function(), obj->GetIsolate()));
}
Location GeneratorObject::SuspendedLocation() {
i::Handle<i::JSGeneratorObject> obj = Utils::OpenHandle(this);
CHECK(obj->is_suspended());
i::Object maybe_script = obj->function().shared().script();
if (!maybe_script.IsScript()) return Location();
i::Isolate* isolate = obj->GetIsolate();
i::Handle<i::Script> script(i::Script::cast(maybe_script), isolate);
i::Script::PositionInfo info;
i::SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate, i::handle(obj->function().shared(), isolate));
i::Script::GetPositionInfo(script, obj->source_position(), &info,
i::Script::WITH_OFFSET);
return Location(info.line, info.column);
}
bool GeneratorObject::IsSuspended() {
return Utils::OpenHandle(this)->is_suspended();
}
v8::Local<GeneratorObject> GeneratorObject::Cast(v8::Local<v8::Value> value) {
CHECK(value->IsGeneratorObject());
return ToApiHandle<GeneratorObject>(Utils::OpenHandle(*value));
}
MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
v8::Local<v8::String> source,
EvaluateGlobalMode mode, bool repl) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(internal_isolate, Value);
i::REPLMode repl_mode = repl ? i::REPLMode::kYes : i::REPLMode::kNo;
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
i::DebugEvaluate::Global(internal_isolate, Utils::OpenHandle(*source),
mode, repl_mode),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
void QueryObjects(v8::Local<v8::Context> v8_context,
QueryObjectPredicate* predicate,
PersistentValueVector<v8::Object>* objects) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_context->GetIsolate());
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
isolate->heap_profiler()->QueryObjects(Utils::OpenHandle(*v8_context),
predicate, objects);
}
void GlobalLexicalScopeNames(v8::Local<v8::Context> v8_context,
v8::PersistentValueVector<v8::String>* names) {
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
i::Isolate* isolate = context->GetIsolate();
i::Handle<i::ScriptContextTable> table(
context->global_object().native_context().script_context_table(),
isolate);
for (int i = 0; i < table->synchronized_used(); i++) {
i::Handle<i::Context> context =
i::ScriptContextTable::GetContext(isolate, table, i);
DCHECK(context->IsScriptContext());
i::Handle<i::ScopeInfo> scope_info(context->scope_info(), isolate);
int local_count = scope_info->ContextLocalCount();
for (int j = 0; j < local_count; ++j) {
i::String name = scope_info->ContextLocalName(j);
if (i::ScopeInfo::VariableIsSynthetic(name)) continue;
names->Append(Utils::ToLocal(handle(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::OpenHandle(*value));
}
int64_t GetNextRandomInt64(v8::Isolate* v8_isolate) {
return reinterpret_cast<i::Isolate*>(v8_isolate)
->random_number_generator()
->NextInt64();
}
void EnumerateRuntimeCallCounters(v8::Isolate* v8_isolate,
RuntimeCallCounterCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
if (isolate->counters()) {
isolate->counters()->runtime_call_stats()->EnumerateCounters(callback);
}
}
int GetDebuggingId(v8::Local<v8::Function> function) {
i::Handle<i::JSReceiver> callable = v8::Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return i::DebugInfo::kNoDebuggingId;
i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(callable);
int id = func->GetIsolate()->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) {
i::Handle<i::JSReceiver> callable = Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return false;
i::Handle<i::JSFunction> jsfunction =
i::Handle<i::JSFunction>::cast(callable);
i::Isolate* isolate = jsfunction->GetIsolate();
i::Handle<i::String> condition_string =
condition.IsEmpty() ? isolate->factory()->empty_string()
: Utils::OpenHandle(*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)));
}
void Coverage::SelectMode(Isolate* isolate, CoverageMode mode) {
i::Coverage::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
}
int TypeProfile::Entry::SourcePosition() const { return entry_->position; }
std::vector<MaybeLocal<String>> TypeProfile::Entry::Types() const {
std::vector<MaybeLocal<String>> result;
for (const internal::Handle<internal::String>& type : entry_->types) {
result.emplace_back(ToApiHandle<String>(type));
}
return result;
}
TypeProfile::ScriptData::ScriptData(
size_t index, std::shared_ptr<i::TypeProfile> type_profile)
: script_(&type_profile->at(index)),
type_profile_(std::move(type_profile)) {}
Local<Script> TypeProfile::ScriptData::GetScript() const {
return ToApiHandle<Script>(script_->script);
}
std::vector<TypeProfile::Entry> TypeProfile::ScriptData::Entries() const {
std::vector<TypeProfile::Entry> result;
for (const internal::TypeProfileEntry& entry : script_->entries) {
result.push_back(TypeProfile::Entry(&entry, type_profile_));
}
return result;
}
TypeProfile TypeProfile::Collect(Isolate* isolate) {
return TypeProfile(
i::TypeProfile::Collect(reinterpret_cast<i::Isolate*>(isolate)));
}
void TypeProfile::SelectMode(Isolate* isolate, TypeProfileMode mode) {
i::TypeProfile::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
}
size_t TypeProfile::ScriptCount() const { return type_profile_->size(); }
TypeProfile::ScriptData TypeProfile::GetScriptData(size_t i) const {
return ScriptData(i, type_profile_);
}
v8::MaybeLocal<v8::Value> WeakMap::Get(v8::Local<v8::Context> context,
v8::Local<v8::Value> key) {
PREPARE_FOR_EXECUTION(context, WeakMap, Get, Value);
auto self = Utils::OpenHandle(this);
Local<Value> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key)};
has_pending_exception =
!ToLocal<Value>(i::Execution::CallBuiltin(isolate, isolate->weakmap_get(),
self, arraysize(argv), argv),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
v8::MaybeLocal<WeakMap> WeakMap::Set(v8::Local<v8::Context> context,
v8::Local<v8::Value> key,
v8::Local<v8::Value> value) {
PREPARE_FOR_EXECUTION(context, WeakMap, Set, WeakMap);
auto self = Utils::OpenHandle(this);
i::Handle<i::Object> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*key),
Utils::OpenHandle(*value)};
has_pending_exception =
!i::Execution::CallBuiltin(isolate, isolate->weakmap_set(), self,
arraysize(argv), argv)
.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(WeakMap);
RETURN_ESCAPED(Local<WeakMap>::Cast(Utils::ToLocal(result)));
}
Local<WeakMap> WeakMap::New(v8::Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, WeakMap, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::JSWeakMap> obj = i_isolate->factory()->NewJSWeakMap();
return ToApiHandle<WeakMap>(obj);
}
WeakMap* WeakMap::Cast(v8::Value* value) {
return static_cast<WeakMap*>(value);
}
Local<Value> AccessorPair::getter() {
i::Handle<i::AccessorPair> accessors = Utils::OpenHandle(this);
i::Isolate* isolate = accessors->GetIsolate();
i::Handle<i::Object> getter(accessors->getter(), isolate);
return Utils::ToLocal(getter);
}
Local<Value> AccessorPair::setter() {
i::Handle<i::AccessorPair> accessors = Utils::OpenHandle(this);
i::Isolate* isolate = accessors->GetIsolate();
i::Handle<i::Object> setter(accessors->setter(), isolate);
return Utils::ToLocal(setter);
}
bool AccessorPair::IsAccessorPair(Local<Value> that) {
i::Handle<i::Object> obj = Utils::OpenHandle(*that);
return obj->IsAccessorPair();
}
MaybeLocal<Message> GetMessageFromPromise(Local<Promise> p) {
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*p);
i::Isolate* isolate = promise->GetIsolate();
i::Handle<i::Symbol> key = isolate->factory()->promise_debug_message_symbol();
i::Handle<i::Object> maybeMessage =
i::JSReceiver::GetDataProperty(promise, key);
if (!maybeMessage->IsJSMessageObject(isolate)) return MaybeLocal<Message>();
return ToApiHandle<Message>(
i::Handle<i::JSMessageObject>::cast(maybeMessage));
}
std::unique_ptr<PropertyIterator> PropertyIterator::Create(
Local<Context> context, Local<Object> object) {
internal::Isolate* isolate =
reinterpret_cast<i::Isolate*>(object->GetIsolate());
if (IsExecutionTerminatingCheck(isolate)) {
return nullptr;
}
CallDepthScope<false> call_depth_scope(isolate, context);
auto result =
i::DebugPropertyIterator::Create(isolate, Utils::OpenHandle(*object));
if (!result) {
DCHECK(isolate->has_pending_exception());
call_depth_scope.Escape();
}
return result;
}
} // namespace debug
namespace internal {
Maybe<bool> DebugPropertyIterator::Advance() {
if (IsExecutionTerminatingCheck(isolate_)) {
return Nothing<bool>();
}
Local<v8::Context> context =
Utils::ToLocal(handle(isolate_->context(), isolate_));
CallDepthScope<false> call_depth_scope(isolate_, context);
if (!AdvanceInternal()) {
DCHECK(isolate_->has_pending_exception());
call_depth_scope.Escape();
return Nothing<bool>();
}
return Just(true);
}
} // namespace internal
} // namespace v8
#include "src/api/api-macros-undef.h"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment