Commit c418902b authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] don't make v8::debug::Call for breakProgram.

We emulate break by callling breakProgramCallback function in debugger context, we can just use HandleDebugBreak.
It allows us to move all stepping logic to debug.cc later and remove one usage of debugger context.
+ two minor issues fixed, see tests.

BUG=v8:5510
R=yangguo@chromium.org

Review-Url: https://codereview.chromium.org/2738503006
Cr-Commit-Position: refs/heads/master@{#43750}
parent 01cc4f9f
...@@ -9105,6 +9105,12 @@ void debug::ClearStepping(Isolate* v8_isolate) { ...@@ -9105,6 +9105,12 @@ void debug::ClearStepping(Isolate* v8_isolate) {
isolate->debug()->ClearStepping(); isolate->debug()->ClearStepping();
} }
void debug::BreakRightNow(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate);
isolate->debug()->HandleDebugBreak(i::kIgnoreIfAllFramesBlackboxed);
}
bool debug::AllFramesOnStackAreBlackboxed(Isolate* v8_isolate) { bool debug::AllFramesOnStackAreBlackboxed(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate); ENTER_V8(isolate);
......
...@@ -103,6 +103,7 @@ enum StepAction { ...@@ -103,6 +103,7 @@ enum StepAction {
void PrepareStep(Isolate* isolate, StepAction action); void PrepareStep(Isolate* isolate, StepAction action);
void ClearStepping(Isolate* isolate); void ClearStepping(Isolate* isolate);
void BreakRightNow(Isolate* isolate);
bool AllFramesOnStackAreBlackboxed(Isolate* isolate); bool AllFramesOnStackAreBlackboxed(Isolate* isolate);
......
...@@ -2132,8 +2132,7 @@ MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { ...@@ -2132,8 +2132,7 @@ MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
argv); argv);
} }
void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode) {
void Debug::HandleDebugBreak() {
// Initialize LiveEdit. // Initialize LiveEdit.
LiveEdit::InitializeThreadLocal(this); LiveEdit::InitializeThreadLocal(this);
// Ignore debug break during bootstrapping. // Ignore debug break during bootstrapping.
...@@ -2154,7 +2153,10 @@ void Debug::HandleDebugBreak() { ...@@ -2154,7 +2153,10 @@ void Debug::HandleDebugBreak() {
// Don't stop in builtin and blackboxed functions. // Don't stop in builtin and blackboxed functions.
Handle<SharedFunctionInfo> shared(JSFunction::cast(fun)->shared(), Handle<SharedFunctionInfo> shared(JSFunction::cast(fun)->shared(),
isolate_); isolate_);
if (IsBlackboxed(shared)) { bool ignore_break = ignore_break_mode == kIgnoreIfTopFrameBlackboxed
? IsBlackboxed(shared)
: AllFramesOnStackAreBlackboxed();
if (ignore_break) {
// Inspector uses pause on next statement for asynchronous breakpoints. // Inspector uses pause on next statement for asynchronous breakpoints.
// When breakpoint is fired we try to break on first not blackboxed // When breakpoint is fired we try to break on first not blackboxed
// statement. To achieve this goal we need to deoptimize current // statement. To achieve this goal we need to deoptimize current
......
...@@ -65,6 +65,11 @@ enum DebugBreakType { ...@@ -65,6 +65,11 @@ enum DebugBreakType {
DEBUG_BREAK_SLOT_AT_TAIL_CALL, DEBUG_BREAK_SLOT_AT_TAIL_CALL,
}; };
enum IgnoreBreakMode {
kIgnoreIfAllFramesBlackboxed,
kIgnoreIfTopFrameBlackboxed
};
class BreakLocation { class BreakLocation {
public: public:
static BreakLocation FromFrame(Handle<DebugInfo> debug_info, static BreakLocation FromFrame(Handle<DebugInfo> debug_info,
...@@ -276,7 +281,7 @@ class Debug { ...@@ -276,7 +281,7 @@ class Debug {
MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun, MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
Handle<Object> data); Handle<Object> data);
Handle<Context> GetDebugContext(); Handle<Context> GetDebugContext();
void HandleDebugBreak(); void HandleDebugBreak(IgnoreBreakMode ignore_break_mode);
// Internal logic // Internal logic
bool Load(); bool Load();
......
...@@ -471,7 +471,7 @@ Object* StackGuard::HandleInterrupts() { ...@@ -471,7 +471,7 @@ Object* StackGuard::HandleInterrupts() {
} }
if (CheckDebugBreak()) { if (CheckDebugBreak()) {
isolate_->debug()->HandleDebugBreak(); isolate_->debug()->HandleDebugBreak(kIgnoreIfTopFrameBlackboxed);
} }
if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
......
...@@ -1309,6 +1309,9 @@ void V8DebuggerAgentImpl::breakProgram( ...@@ -1309,6 +1309,9 @@ void V8DebuggerAgentImpl::breakProgram(
m_debugger->breakProgram(); m_debugger->breakProgram();
popBreakDetails(); popBreakDetails();
m_breakReason.swap(currentScheduledReason); m_breakReason.swap(currentScheduledReason);
if (!m_breakReason.empty()) {
m_debugger->setPauseOnNextStatement(true);
}
} }
void V8DebuggerAgentImpl::breakProgramOnException( void V8DebuggerAgentImpl::breakProgramOnException(
......
...@@ -345,16 +345,7 @@ void V8Debugger::breakProgram() { ...@@ -345,16 +345,7 @@ void V8Debugger::breakProgram() {
// Don't allow nested breaks. // Don't allow nested breaks.
if (isPaused()) return; if (isPaused()) return;
if (!canBreakProgram()) return; if (!canBreakProgram()) return;
v8::debug::BreakRightNow(m_isolate);
v8::HandleScope scope(m_isolate);
v8::Local<v8::Function> breakFunction;
if (!v8::Function::New(m_isolate->GetCurrentContext(),
&V8Debugger::breakProgramCallback,
v8::External::New(m_isolate, this), 0,
v8::ConstructorBehavior::kThrow)
.ToLocal(&breakFunction))
return;
v8::debug::Call(debuggerContext(), breakFunction).ToLocalChecked();
} }
void V8Debugger::continueProgram() { void V8Debugger::continueProgram() {
...@@ -505,25 +496,6 @@ JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) { ...@@ -505,25 +496,6 @@ JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) {
return callFrames; return callFrames;
} }
static V8Debugger* toV8Debugger(v8::Local<v8::Value> data) {
void* p = v8::Local<v8::External>::Cast(data)->Value();
return static_cast<V8Debugger*>(p);
}
void V8Debugger::breakProgramCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
DCHECK_EQ(info.Length(), 2);
V8Debugger* thisPtr = toV8Debugger(info.Data());
if (!thisPtr->enabled()) return;
v8::Local<v8::Context> pausedContext =
thisPtr->m_isolate->GetCurrentContext();
v8::Local<v8::Value> exception;
v8::Local<v8::Array> hitBreakpoints;
thisPtr->handleProgramBreak(pausedContext,
v8::Local<v8::Object>::Cast(info[0]), exception,
hitBreakpoints);
}
void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
v8::Local<v8::Object> executionState, v8::Local<v8::Object> executionState,
v8::Local<v8::Value> exception, v8::Local<v8::Value> exception,
......
...@@ -105,7 +105,6 @@ class V8Debugger : public v8::debug::DebugDelegate { ...@@ -105,7 +105,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
static void v8OOMCallback(void* data); static void v8OOMCallback(void* data);
static void breakProgramCallback(const v8::FunctionCallbackInfo<v8::Value>&);
void handleProgramBreak(v8::Local<v8::Context> pausedContext, void handleProgramBreak(v8::Local<v8::Context> pausedContext,
v8::Local<v8::Object> executionState, v8::Local<v8::Object> executionState,
v8::Local<v8::Value> exception, v8::Local<v8::Value> exception,
......
...@@ -68,7 +68,7 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { ...@@ -68,7 +68,7 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length()); DCHECK_EQ(0, args.length());
if (isolate->debug()->break_points_active()) { if (isolate->debug()->break_points_active()) {
isolate->debug()->HandleDebugBreak(); isolate->debug()->HandleDebugBreak(kIgnoreIfTopFrameBlackboxed);
} }
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
Checks that stepping is cleared after breakProgram.
paused at:
function callBreakProgram() {
#debugger;
breakProgram('reason', '');
paused at:
debugger;
#breakProgram('reason', '');
}
paused at:
debugger;
#breakProgram('reason', '');
}
paused at:
#debugger;
// Copyright 2017 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.
InspectorTest.log('Checks that stepping is cleared after breakProgram.');
InspectorTest.addScript(`
function callBreakProgram() {
debugger;
breakProgram('reason', '');
}`);
InspectorTest.setupScriptMap();
(async function test() {
Protocol.Debugger.enable();
Protocol.Runtime.evaluate({expression: 'callBreakProgram();'});
// Should break at this debugger statement, not at end of callBreakProgram.
Protocol.Runtime.evaluate({expression: 'setTimeout(\'debugger;\', 0);'});
await waitPauseAndDumpLocation();
Protocol.Debugger.stepOver();
await waitPauseAndDumpLocation();
Protocol.Debugger.stepOver();
await waitPauseAndDumpLocation();
Protocol.Debugger.resume();
await waitPauseAndDumpLocation();
InspectorTest.completeTest();
})();
async function waitPauseAndDumpLocation() {
var message = await Protocol.Debugger.oncePaused();
InspectorTest.log('paused at:');
InspectorTest.logSourceLocation(message.params.callFrames[0].location);
return message;
}
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