[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: I6965ebf2301459c89e3217bd87396ec353d814e9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2653154 Auto-Submit: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#72392}
This commit is contained in:
parent
12f8ac4713
commit
1b4811f716
3
BUILD.gn
3
BUILD.gn
@ -2463,6 +2463,8 @@ v8_source_set("v8_base_without_compiler") {
|
|||||||
"src/api/api-arguments-inl.h",
|
"src/api/api-arguments-inl.h",
|
||||||
"src/api/api-arguments.cc",
|
"src/api/api-arguments.cc",
|
||||||
"src/api/api-arguments.h",
|
"src/api/api-arguments.h",
|
||||||
|
"src/api/api-inl.h",
|
||||||
|
"src/api/api-macros.h",
|
||||||
"src/api/api-natives.cc",
|
"src/api/api-natives.cc",
|
||||||
"src/api/api-natives.h",
|
"src/api/api-natives.h",
|
||||||
"src/api/api.cc",
|
"src/api/api.cc",
|
||||||
@ -2627,6 +2629,7 @@ v8_source_set("v8_base_without_compiler") {
|
|||||||
"src/debug/debug-evaluate.h",
|
"src/debug/debug-evaluate.h",
|
||||||
"src/debug/debug-frames.cc",
|
"src/debug/debug-frames.cc",
|
||||||
"src/debug/debug-frames.h",
|
"src/debug/debug-frames.h",
|
||||||
|
"src/debug/debug-interface.cc",
|
||||||
"src/debug/debug-interface.h",
|
"src/debug/debug-interface.h",
|
||||||
"src/debug/debug-property-iterator.cc",
|
"src/debug/debug-property-iterator.cc",
|
||||||
"src/debug/debug-property-iterator.h",
|
"src/debug/debug-property-iterator.h",
|
||||||
|
@ -480,8 +480,8 @@ def _CheckNoexceptAnnotations(input_api, output_api):
|
|||||||
def FilterFile(affected_file):
|
def FilterFile(affected_file):
|
||||||
return input_api.FilterSourceFile(
|
return input_api.FilterSourceFile(
|
||||||
affected_file,
|
affected_file,
|
||||||
files_to_check=(r'src/.*', r'test/.*'))
|
files_to_check=(r'src/.*', r'test/.*'),
|
||||||
|
files_to_skip=(r'src[\\\/]api[\\\/]api\.cc'))
|
||||||
|
|
||||||
# matches any class name.
|
# matches any class name.
|
||||||
class_name = r'\b([A-Z][A-Za-z0-9_:]*)(?:::\1)?'
|
class_name = r'\b([A-Z][A-Za-z0-9_:]*)(?:::\1)?'
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#define V8_API_API_INL_H_
|
#define V8_API_API_INL_H_
|
||||||
|
|
||||||
#include "src/api/api.h"
|
#include "src/api/api.h"
|
||||||
|
#include "src/execution/microtask-queue.h"
|
||||||
#include "src/handles/handles-inl.h"
|
#include "src/handles/handles-inl.h"
|
||||||
#include "src/objects/foreign-inl.h"
|
#include "src/objects/foreign-inl.h"
|
||||||
#include "src/objects/js-weak-refs.h"
|
#include "src/objects/js-weak-refs.h"
|
||||||
@ -131,6 +132,111 @@ OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
|
|||||||
#undef MAKE_OPEN_HANDLE
|
#undef MAKE_OPEN_HANDLE
|
||||||
#undef OPEN_HANDLE_LIST
|
#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 {
|
namespace internal {
|
||||||
|
|
||||||
Handle<Context> HandleScopeImplementer::LastEnteredContext() {
|
Handle<Context> HandleScopeImplementer::LastEnteredContext() {
|
||||||
|
20
src/api/api-macros-undef.h
Normal file
20
src/api/api-macros-undef.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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
|
132
src/api/api-macros.h
Normal file
132
src/api/api-macros.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// 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
|
1405
src/api/api.cc
1405
src/api/api.cc
File diff suppressed because it is too large
Load Diff
1159
src/debug/debug-interface.cc
Normal file
1159
src/debug/debug-interface.cc
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user