[liftoff][debug] Implement StepOver at return locations

A StepOver at a return (either explicit return instruction, or implicit
return at the end of the function) should stop again in the caller
frame.

R=thibaudm@chromium.org

Bug: v8:10321
Change-Id: I313e6b612ac52e73b33ef07c6da1ced2aa0db600
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2110250
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66852}
This commit is contained in:
Clemens Backes 2020-03-24 16:44:19 +01:00 committed by Commit Bot
parent 8f68e39214
commit 04774ffaaa
3 changed files with 55 additions and 6 deletions

View File

@ -709,6 +709,15 @@ class DebugInfoImpl {
DCHECK(!it.done());
DCHECK(it.frame()->is_wasm_compiled());
WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());
// If we are at a return instruction, then any stepping action is equivalent
// to StepOut, and we need to flood the parent function.
if (IsAtReturn(frame)) {
it.Advance();
if (it.done() || !it.frame()->is_wasm_compiled()) return;
frame = WasmCompiledFrame::cast(it.frame());
}
if (static_cast<int>(frame->function_index()) != flooded_function_index_) {
FloodWithBreakpoints(frame->function_index(), isolate);
flooded_function_index_ = frame->function_index();
@ -862,6 +871,19 @@ class DebugInfoImpl {
}
}
bool IsAtReturn(WasmCompiledFrame* frame) {
DisallowHeapAllocation no_gc;
int position = frame->position();
NativeModule* native_module =
frame->wasm_instance().module_object().native_module();
uint8_t opcode = native_module->wire_bytes()[position];
if (opcode == kExprReturn) return true;
// Another implicit return is at the last kExprEnd in the function body.
int func_index = frame->function_index();
WireBytesRef code = native_module->module()->functions[func_index].code;
return static_cast<size_t>(position) == code.end_offset() - 1;
}
NativeModule* const native_module_;
// {mutex_} protects all fields below.

View File

@ -25,9 +25,33 @@ Paused at wasm://wasm/42af3c82:0:53
Debugger.stepOver called
Paused at wasm://wasm/42af3c82:0:54
Debugger.stepOver called
Paused at wasm://wasm/42af3c82:0:75
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:59
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:61
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:63
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:65
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:67
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:68
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:70
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:73
Debugger.resume called
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:52
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:53
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:54
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:75
Debugger.stepInto called
Paused at wasm://wasm/42af3c82:0:59
Debugger.resume called
Paused at :0:24
Debugger.resume called

View File

@ -102,11 +102,14 @@ function instantiate(bytes) {
// Step out of wasm_A, back to wasm_B.
// TODO(clemensb/thibaudm): Replace by an actual 'stepOut'.
for (let i = 0; i < 3; ++i) await waitForPauseAndStep('stepOver');
// Step over 10 times.
// TODO(clemensb/thibaudm): Reenable once stepping over return works.
//for (let i = 0; i < 10; ++i) await waitForPauseAndStep('stepOver');
// Resume three more times to continue over other breakpoints.
for (let i = 0; i < 3; ++i) await waitForPauseAndStep('resume');
// Now step 10 times, until we are in wasm_A again.
for (let i = 0; i < 10; ++i) await waitForPauseAndStep('stepInto');
// 3 more times, back to wasm_B.
for (let i = 0; i < 3; ++i) await waitForPauseAndStep('stepInto');
// Then just resume.
await waitForPauseAndStep('resume');
// TODO(clemensb/thibaudm): Figure out what this last break is (at ":0:24").
await waitForPauseAndStep('resume');
InspectorTest.log('exports.main returned!');
InspectorTest.log('Test stepping over a recursive call');