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: Yang Guo <yangguo@chromium.org> Auto-Submit: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#72402}
This commit is contained in:
parent
5154f22c8c
commit
9d3cd57fda
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.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() {
|
||||
|
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