Commit 0bd19ddb authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

Revert "[debug] only break on entry when immediately called from JS"

This reverts commit e66cee7e.

Reason for revert: Speculative revert for https://ci.chromium.org/p/chromium/builders/try/linux-rel/173349

Original change's description:
> [debug] only break on entry when immediately called from JS
> 
> When we break on function entry, check whether the target function is being
> called from JS after entering V8 through V8's API. We implement this by
> keeping track of the stack height when we enter V8 through the API, and compare
> the caller JS frame's stack height with that.
> 
> R=​szuend@chromium.org
> 
> Bug: chromium:991217, chromium:992406
> Change-Id: I258ad9cef11fe0ef48de6fd5055790792fd0ec0c
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1762298
> Commit-Queue: Yang Guo <yangguo@chromium.org>
> Reviewed-by: Simon Zünd <szuend@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#63331}

TBR=yangguo@chromium.org,szuend@chromium.org

Change-Id: I4bfb42f7ce1484807696048a09609f14113d10f4
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:991217, chromium:992406
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1762525Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63341}
parent 614171c2
...@@ -129,7 +129,6 @@ class PropertyCallbackArguments; ...@@ -129,7 +129,6 @@ class PropertyCallbackArguments;
class FunctionCallbackArguments; class FunctionCallbackArguments;
class GlobalHandles; class GlobalHandles;
class ScopedExternalStringLock; class ScopedExternalStringLock;
class ThreadLocalTop;
namespace wasm { namespace wasm {
class NativeModule; class NativeModule;
...@@ -7665,9 +7664,6 @@ class V8_EXPORT Isolate { ...@@ -7665,9 +7664,6 @@ class V8_EXPORT Isolate {
private: private:
internal::Isolate* const isolate_; internal::Isolate* const isolate_;
internal::MicrotaskQueue* const microtask_queue_; internal::MicrotaskQueue* const microtask_queue_;
internal::Address previous_stack_height_;
friend class internal::ThreadLocalTop;
}; };
/** /**
......
...@@ -262,7 +262,7 @@ void CheckMicrotasksScopesConsistency(i::MicrotaskQueue* microtask_queue) { ...@@ -262,7 +262,7 @@ void CheckMicrotasksScopesConsistency(i::MicrotaskQueue* microtask_queue) {
template <bool do_callback> template <bool do_callback>
class CallDepthScope { class CallDepthScope {
public: public:
CallDepthScope(i::Isolate* isolate, Local<Context> context) explicit CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate), : isolate_(isolate),
context_(context), context_(context),
escaped_(false), escaped_(false),
...@@ -273,7 +273,7 @@ class CallDepthScope { ...@@ -273,7 +273,7 @@ class CallDepthScope {
? i::InterruptsScope::kRunInterrupts ? i::InterruptsScope::kRunInterrupts
: i::InterruptsScope::kPostponeInterrupts) : i::InterruptsScope::kPostponeInterrupts)
: i::InterruptsScope::kNoop) { : i::InterruptsScope::kNoop) {
isolate_->thread_local_top()->IncrementCallDepth(this); isolate_->handle_scope_implementer()->IncrementCallDepth();
isolate_->set_next_v8_call_is_safe_for_termination(false); isolate_->set_next_v8_call_is_safe_for_termination(false);
if (!context.IsEmpty()) { if (!context.IsEmpty()) {
i::Handle<i::Context> env = Utils::OpenHandle(*context); i::Handle<i::Context> env = Utils::OpenHandle(*context);
...@@ -297,7 +297,7 @@ class CallDepthScope { ...@@ -297,7 +297,7 @@ class CallDepthScope {
i::Handle<i::Context> env = Utils::OpenHandle(*context_); i::Handle<i::Context> env = Utils::OpenHandle(*context_);
microtask_queue = env->native_context().microtask_queue(); microtask_queue = env->native_context().microtask_queue();
} }
if (!escaped_) isolate_->thread_local_top()->DecrementCallDepth(this); if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth();
if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue); if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
// TODO(jochen): This should be #ifdef DEBUG // TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY #ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
...@@ -309,10 +309,11 @@ class CallDepthScope { ...@@ -309,10 +309,11 @@ class CallDepthScope {
void Escape() { void Escape() {
DCHECK(!escaped_); DCHECK(!escaped_);
escaped_ = true; escaped_ = true;
auto thread_local_top = isolate_->thread_local_top(); auto handle_scope_implementer = isolate_->handle_scope_implementer();
thread_local_top->DecrementCallDepth(this); handle_scope_implementer->DecrementCallDepth();
bool clear_exception = thread_local_top->CallDepthIsZero() && bool clear_exception =
thread_local_top->try_catch_handler_ == nullptr; handle_scope_implementer->CallDepthIsZero() &&
isolate_->thread_local_top()->try_catch_handler_ == nullptr;
isolate_->OptionalRescheduleException(clear_exception); isolate_->OptionalRescheduleException(clear_exception);
} }
...@@ -323,12 +324,6 @@ class CallDepthScope { ...@@ -323,12 +324,6 @@ class CallDepthScope {
bool do_callback_; bool do_callback_;
bool safe_for_termination_; bool safe_for_termination_;
i::InterruptsScope interrupts_scope_; i::InterruptsScope interrupts_scope_;
i::Address previous_stack_height_;
friend class i::ThreadLocalTop;
DISALLOW_NEW_AND_DELETE()
DISALLOW_COPY_AND_ASSIGN(CallDepthScope);
}; };
} // namespace } // namespace
...@@ -8073,13 +8068,13 @@ Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope( ...@@ -8073,13 +8068,13 @@ Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope(
Isolate* isolate) Isolate* isolate)
: isolate_(reinterpret_cast<i::Isolate*>(isolate)), : isolate_(reinterpret_cast<i::Isolate*>(isolate)),
microtask_queue_(isolate_->default_microtask_queue()) { microtask_queue_(isolate_->default_microtask_queue()) {
isolate_->thread_local_top()->IncrementCallDepth(this); isolate_->handle_scope_implementer()->IncrementCallDepth();
microtask_queue_->IncrementMicrotasksSuppressions(); microtask_queue_->IncrementMicrotasksSuppressions();
} }
Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() { Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() {
microtask_queue_->DecrementMicrotasksSuppressions(); microtask_queue_->DecrementMicrotasksSuppressions();
isolate_->thread_local_top()->DecrementCallDepth(this); isolate_->handle_scope_implementer()->DecrementCallDepth();
} }
Isolate::SafeForTerminationScope::SafeForTerminationScope(v8::Isolate* isolate) Isolate::SafeForTerminationScope::SafeForTerminationScope(v8::Isolate* isolate)
......
...@@ -357,6 +357,7 @@ class HandleScopeImplementer { ...@@ -357,6 +357,7 @@ class HandleScopeImplementer {
explicit HandleScopeImplementer(Isolate* isolate) explicit HandleScopeImplementer(Isolate* isolate)
: isolate_(isolate), : isolate_(isolate),
spare_(nullptr), spare_(nullptr),
call_depth_(0),
last_handle_before_deferred_block_(nullptr) {} last_handle_before_deferred_block_(nullptr) {}
~HandleScopeImplementer() { DeleteArray(spare_); } ~HandleScopeImplementer() { DeleteArray(spare_); }
...@@ -375,6 +376,11 @@ class HandleScopeImplementer { ...@@ -375,6 +376,11 @@ class HandleScopeImplementer {
inline internal::Address* GetSpareOrNewBlock(); inline internal::Address* GetSpareOrNewBlock();
inline void DeleteExtensions(internal::Address* prev_limit); inline void DeleteExtensions(internal::Address* prev_limit);
// Call depth represents nested v8 api calls.
inline void IncrementCallDepth() { call_depth_++; }
inline void DecrementCallDepth() { call_depth_--; }
inline bool CallDepthIsZero() { return call_depth_ == 0; }
inline void EnterContext(Context context); inline void EnterContext(Context context);
inline void LeaveContext(); inline void LeaveContext();
inline bool LastEnteredContextWas(Context context); inline bool LastEnteredContextWas(Context context);
...@@ -411,6 +417,7 @@ class HandleScopeImplementer { ...@@ -411,6 +417,7 @@ class HandleScopeImplementer {
saved_contexts_.detach(); saved_contexts_.detach();
spare_ = nullptr; spare_ = nullptr;
last_handle_before_deferred_block_ = nullptr; last_handle_before_deferred_block_ = nullptr;
call_depth_ = 0;
} }
void Free() { void Free() {
...@@ -427,7 +434,7 @@ class HandleScopeImplementer { ...@@ -427,7 +434,7 @@ class HandleScopeImplementer {
DeleteArray(spare_); DeleteArray(spare_);
spare_ = nullptr; spare_ = nullptr;
} }
DCHECK(isolate_->thread_local_top()->CallDepthIsZero()); DCHECK_EQ(call_depth_, 0);
} }
void BeginDeferredScope(); void BeginDeferredScope();
...@@ -447,6 +454,8 @@ class HandleScopeImplementer { ...@@ -447,6 +454,8 @@ class HandleScopeImplementer {
// Used as a stack to keep track of saved contexts. // Used as a stack to keep track of saved contexts.
DetachableVector<Context> saved_contexts_; DetachableVector<Context> saved_contexts_;
Address* spare_; Address* spare_;
int call_depth_;
Address* last_handle_before_deferred_block_; Address* last_handle_before_deferred_block_;
// This is only used for threading support. // This is only used for threading support.
HandleScopeData handle_scope_data_; HandleScopeData handle_scope_data_;
......
...@@ -375,8 +375,6 @@ class V8_EXPORT_PRIVATE Debug { ...@@ -375,8 +375,6 @@ class V8_EXPORT_PRIVATE Debug {
return thread_local_.break_on_next_function_call_; return thread_local_.break_on_next_function_call_;
} }
inline bool break_disabled() const { return break_disabled_; }
DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } DebugFeatureTracker* feature_tracker() { return &feature_tracker_; }
// For functions in which we cannot set a break point, use a canonical // For functions in which we cannot set a break point, use a canonical
...@@ -401,6 +399,7 @@ class V8_EXPORT_PRIVATE Debug { ...@@ -401,6 +399,7 @@ class V8_EXPORT_PRIVATE Debug {
return is_suppressed_ || !is_active_ || return is_suppressed_ || !is_active_ ||
isolate_->debug_execution_mode() == DebugInfo::kSideEffects; isolate_->debug_execution_mode() == DebugInfo::kSideEffects;
} }
inline bool break_disabled() const { return break_disabled_; }
void clear_suspended_generator() { void clear_suspended_generator() {
thread_local_.suspended_generator_ = Smi::kZero; thread_local_.suspended_generator_ = Smi::kZero;
......
...@@ -2023,7 +2023,7 @@ void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) { ...@@ -2023,7 +2023,7 @@ void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) {
DCHECK_EQ(scheduled_exception(), DCHECK_EQ(scheduled_exception(),
ReadOnlyRoots(heap()).termination_exception()); ReadOnlyRoots(heap()).termination_exception());
// Clear termination once we returned from all V8 frames. // Clear termination once we returned from all V8 frames.
if (thread_local_top()->CallDepthIsZero()) { if (handle_scope_implementer()->CallDepthIsZero()) {
thread_local_top()->external_caught_exception_ = false; thread_local_top()->external_caught_exception_ = false;
clear_scheduled_exception(); clear_scheduled_exception();
} }
...@@ -4250,7 +4250,7 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) { ...@@ -4250,7 +4250,7 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
} }
void Isolate::FireCallCompletedCallback(MicrotaskQueue* microtask_queue) { void Isolate::FireCallCompletedCallback(MicrotaskQueue* microtask_queue) {
if (!thread_local_top()->CallDepthIsZero()) return; if (!handle_scope_implementer()->CallDepthIsZero()) return;
bool run_microtasks = bool run_microtasks =
microtask_queue && microtask_queue->size() && microtask_queue && microtask_queue->size() &&
......
...@@ -26,15 +26,5 @@ void ThreadLocalTop::Free() { ...@@ -26,15 +26,5 @@ void ThreadLocalTop::Free() {
while (promise_on_stack_) isolate_->PopPromise(); while (promise_on_stack_) isolate_->PopPromise();
} }
#if defined(USE_SIMULATOR)
void ThreadLocalTop::StoreCurrentStackPosition() {
last_api_entry_ = simulator_->get_sp();
}
#elif defined(V8_USE_ADDRESS_SANITIZER)
void ThreadLocalTop::StoreCurrentStackPosition() {
last_api_entry_ = reinterpret_cast<Address>(GetCurrentStackPosition());
}
#endif
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/thread-id.h" #include "src/execution/thread-id.h"
#include "src/objects/contexts.h" #include "src/objects/contexts.h"
#include "src/utils/utils.h"
namespace v8 { namespace v8 {
...@@ -26,7 +25,7 @@ class ThreadLocalTop { ...@@ -26,7 +25,7 @@ class ThreadLocalTop {
// TODO(all): This is not particularly beautiful. We should probably // TODO(all): This is not particularly beautiful. We should probably
// refactor this to really consist of just Addresses and 32-bit // refactor this to really consist of just Addresses and 32-bit
// integer fields. // integer fields.
static constexpr uint32_t kSizeInBytes = 24 * kSystemPointerSize; static constexpr uint32_t kSizeInBytes = 23 * kSystemPointerSize;
// Does early low-level initialization that does not depend on the // Does early low-level initialization that does not depend on the
// isolate being present. // isolate being present.
...@@ -57,31 +56,6 @@ class ThreadLocalTop { ...@@ -57,31 +56,6 @@ class ThreadLocalTop {
v8::TryCatch::JSStackComparableAddress(try_catch_handler_)); v8::TryCatch::JSStackComparableAddress(try_catch_handler_));
} }
// Call depth represents nested v8 api calls. Instead of storing the nesting
// level as an integer, we store the stack height of the last API entry. This
// additional information is used when we decide whether to trigger a debug
// break at a function entry.
template <typename Scope>
void IncrementCallDepth(Scope* stack_allocated_scope) {
stack_allocated_scope->previous_stack_height_ = last_api_entry_;
#if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER)
StoreCurrentStackPosition();
#else
last_api_entry_ = reinterpret_cast<i::Address>(stack_allocated_scope);
#endif
}
#if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER)
void StoreCurrentStackPosition();
#endif
template <typename Scope>
void DecrementCallDepth(Scope* stack_allocated_scope) {
last_api_entry_ = stack_allocated_scope->previous_stack_height_;
}
bool CallDepthIsZero() const { return last_api_entry_ == kNullAddress; }
void Free(); void Free();
Isolate* isolate_ = nullptr; Isolate* isolate_ = nullptr;
...@@ -103,8 +77,6 @@ class ThreadLocalTop { ...@@ -103,8 +77,6 @@ class ThreadLocalTop {
Address pending_handler_fp_ = kNullAddress; Address pending_handler_fp_ = kNullAddress;
Address pending_handler_sp_ = kNullAddress; Address pending_handler_sp_ = kNullAddress;
Address last_api_entry_ = kNullAddress;
// Communication channel between Isolate::Throw and message consumers. // Communication channel between Isolate::Throw and message consumers.
Object pending_message_obj_; Object pending_message_obj_;
bool rethrowing_message_ = false; bool rethrowing_message_ = false;
......
...@@ -115,17 +115,10 @@ RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) { ...@@ -115,17 +115,10 @@ RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) {
DCHECK(function->shared().HasDebugInfo()); DCHECK(function->shared().HasDebugInfo());
DCHECK(function->shared().GetDebugInfo().BreakAtEntry()); DCHECK(function->shared().GetDebugInfo().BreakAtEntry());
// Get the top-most JavaScript frame. This is the debug target function. // Get the top-most JavaScript frame.
JavaScriptFrameIterator it(isolate); JavaScriptFrameIterator it(isolate);
DCHECK_EQ(*function, it.frame()->function()); DCHECK_EQ(*function, it.frame()->function());
// Check whether the next JS frame is closer than the last API entry. isolate->debug()->Break(it.frame(), function);
// if yes, then the call to the debug target came from JavaScript. Otherwise,
// the call to the debug target came from API. Do not break for the latter.
it.Advance();
if (!it.done() &&
it.frame()->fp() < isolate->thread_local_top()->last_api_entry_) {
isolate->debug()->Break(it.frame(), function);
}
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
......
...@@ -1097,15 +1097,14 @@ TEST(BreakPointApiFunction) { ...@@ -1097,15 +1097,14 @@ TEST(BreakPointApiFunction) {
ExpectInt32("f()", 2); ExpectInt32("f()", 2);
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// Direct call through API does not trigger breakpoint.
function->Call(env.local(), v8::Undefined(env->GetIsolate()), 0, nullptr) function->Call(env.local(), v8::Undefined(env->GetIsolate()), 0, nullptr)
.ToLocalChecked(); .ToLocalChecked();
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
// Run without breakpoints. // Run without breakpoints.
ClearBreakPoint(bp); ClearBreakPoint(bp);
ExpectInt32("f()", 2); ExpectInt32("f()", 2);
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded(); CheckDebuggerUnloaded();
...@@ -1138,14 +1137,13 @@ TEST(BreakPointApiConstructor) { ...@@ -1138,14 +1137,13 @@ TEST(BreakPointApiConstructor) {
CompileRun("new f()"); CompileRun("new f()");
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// Direct call through API does not trigger breakpoint.
function->NewInstance(env.local()).ToLocalChecked(); function->NewInstance(env.local()).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
// Run without breakpoints. // Run without breakpoints.
ClearBreakPoint(bp); ClearBreakPoint(bp);
CompileRun("new f()"); CompileRun("new f()");
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded(); CheckDebuggerUnloaded();
...@@ -1190,16 +1188,15 @@ TEST(BreakPointApiGetter) { ...@@ -1190,16 +1188,15 @@ TEST(BreakPointApiGetter) {
// Run with breakpoint. // Run with breakpoint.
bp = SetBreakPoint(function, 0); bp = SetBreakPoint(function, 0);
CompileRun("get_wrapper(o, 'f')"); CompileRun("get_wrapper(o, 'f')");
CHECK_EQ(0, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
CompileRun("o.f"); CompileRun("o.f");
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// Run without breakpoints. // Run without breakpoints.
ClearBreakPoint(bp); ClearBreakPoint(bp);
CompileRun("get_wrapper(o, 'f', 2)"); CompileRun("get_wrapper(o, 'f', 2)");
CompileRun("o.f"); CHECK_EQ(2, break_point_hit_count);
CHECK_EQ(1, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded(); CheckDebuggerUnloaded();
...@@ -1248,12 +1245,12 @@ TEST(BreakPointApiSetter) { ...@@ -1248,12 +1245,12 @@ TEST(BreakPointApiSetter) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
CompileRun("set_wrapper(o, 'f', 2)"); CompileRun("set_wrapper(o, 'f', 2)");
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// Run without breakpoints. // Run without breakpoints.
ClearBreakPoint(bp); ClearBreakPoint(bp);
CompileRun("o.f = 3"); CompileRun("o.f = 3");
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// === Test API builtin as setter, with condition === // === Test API builtin as setter, with condition ===
break_point_hit_count = 0; break_point_hit_count = 0;
...@@ -1264,16 +1261,15 @@ TEST(BreakPointApiSetter) { ...@@ -1264,16 +1261,15 @@ TEST(BreakPointApiSetter) {
CHECK_EQ(0, break_point_hit_count); CHECK_EQ(0, break_point_hit_count);
CompileRun("set_wrapper(o, 'f', 3)"); CompileRun("set_wrapper(o, 'f', 3)");
CHECK_EQ(0, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
CompileRun("o.f = 3"); CompileRun("o.f = 3");
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
// Run without breakpoints. // Run without breakpoints.
ClearBreakPoint(bp); ClearBreakPoint(bp);
CompileRun("set_wrapper(o, 'f', 2)"); CompileRun("set_wrapper(o, 'f', 2)");
CompileRun("o.f = 3"); CHECK_EQ(2, break_point_hit_count);
CHECK_EQ(1, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded(); CheckDebuggerUnloaded();
......
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