| Index: src/wasm/wasm-debug.cc
|
| diff --git a/src/wasm/wasm-debug.cc b/src/wasm/wasm-debug.cc
|
| index 38d5a4c876f528854b4af9fee9c9b99939c3c7dd..c4f4c29053e15a63de0f5d79be21bef9d71d7adf 100644
|
| --- a/src/wasm/wasm-debug.cc
|
| +++ b/src/wasm/wasm-debug.cc
|
| @@ -30,6 +30,8 @@ class InterpreterHandle {
|
| WasmInstance instance_;
|
| WasmInterpreter interpreter_;
|
| Isolate* isolate_;
|
| + StepAction next_step_action_ = StepNone;
|
| + int last_step_stack_depth_ = 0;
|
|
|
| public:
|
| // Initialize in the right order, using helper methods to make this possible.
|
| @@ -63,6 +65,18 @@ class InterpreterHandle {
|
| WasmInterpreter* interpreter() { return &interpreter_; }
|
| const WasmModule* module() { return instance_.module; }
|
|
|
| + void PrepareStep(StepAction step_action) {
|
| + next_step_action_ = step_action;
|
| + last_step_stack_depth_ = CurrentStackDepth();
|
| + }
|
| +
|
| + void ClearStepping() { next_step_action_ = StepNone; }
|
| +
|
| + int CurrentStackDepth() {
|
| + DCHECK_EQ(1, interpreter()->GetThreadCount());
|
| + return interpreter()->GetThread(0)->GetFrameCount();
|
| + }
|
| +
|
| void Execute(uint32_t func_index, uint8_t* arg_buffer) {
|
| DCHECK_GE(module()->functions.size(), func_index);
|
| FunctionSig* sig = module()->functions[func_index].sig;
|
| @@ -96,15 +110,17 @@ class InterpreterHandle {
|
| thread->state() == WasmInterpreter::FINISHED);
|
| thread->Reset();
|
| thread->PushFrame(&module()->functions[func_index], wasm_args.start());
|
| - WasmInterpreter::State state;
|
| - do {
|
| - state = thread->Run();
|
| + bool finished = false;
|
| + while (!finished) {
|
| + // TODO(clemensh): Add occasional StackChecks.
|
| + WasmInterpreter::State state = ContinueExecution(thread);
|
| switch (state) {
|
| case WasmInterpreter::State::PAUSED:
|
| - NotifyDebugEventListeners();
|
| + NotifyDebugEventListeners(thread);
|
| break;
|
| case WasmInterpreter::State::FINISHED:
|
| // Perfect, just break the switch and exit the loop.
|
| + finished = true;
|
| break;
|
| case WasmInterpreter::State::TRAPPED:
|
| // TODO(clemensh): Generate appropriate JS exception.
|
| @@ -116,7 +132,7 @@ class InterpreterHandle {
|
| default:
|
| UNREACHABLE();
|
| }
|
| - } while (state != WasmInterpreter::State::FINISHED);
|
| + }
|
|
|
| // Copy back the return value
|
| DCHECK_GE(kV8MaxWasmFunctionReturns, sig->return_count());
|
| @@ -141,6 +157,33 @@ class InterpreterHandle {
|
| }
|
| }
|
|
|
| + WasmInterpreter::State ContinueExecution(WasmInterpreter::Thread* thread) {
|
| + switch (next_step_action_) {
|
| + case StepNone:
|
| + return thread->Run();
|
| + case StepIn:
|
| + return thread->Step();
|
| + case StepOut:
|
| + thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterReturn);
|
| + return thread->Step();
|
| + case StepNext: {
|
| + int stack_depth = thread->GetFrameCount();
|
| + if (stack_depth == last_step_stack_depth_) return thread->Step();
|
| + thread->AddBreakFlags(stack_depth > last_step_stack_depth_
|
| + ? WasmInterpreter::BreakFlag::AfterReturn
|
| + : WasmInterpreter::BreakFlag::AfterCall);
|
| + return thread->Run();
|
| + }
|
| + case StepFrame:
|
| + thread->AddBreakFlags(WasmInterpreter::BreakFlag::AfterCall |
|
| + WasmInterpreter::BreakFlag::AfterReturn);
|
| + return thread->Run();
|
| + default:
|
| + UNREACHABLE();
|
| + return WasmInterpreter::STOPPED;
|
| + }
|
| + }
|
| +
|
| Handle<WasmInstanceObject> GetInstanceObject() {
|
| StackTraceFrameIterator it(isolate_);
|
| WasmInterpreterEntryFrame* frame =
|
| @@ -150,7 +193,7 @@ class InterpreterHandle {
|
| return instance_obj;
|
| }
|
|
|
| - void NotifyDebugEventListeners() {
|
| + void NotifyDebugEventListeners(WasmInterpreter::Thread* thread) {
|
| // Enter the debugger.
|
| DebugScope debug_scope(isolate_->debug());
|
| if (debug_scope.failed()) return;
|
| @@ -158,27 +201,47 @@ class InterpreterHandle {
|
| // Postpone interrupt during breakpoint processing.
|
| PostponeInterruptsScope postpone(isolate_);
|
|
|
| - // If we are paused on a breakpoint, clear all stepping and notify the
|
| - // listeners.
|
| - Handle<WasmCompiledModule> compiled_module(
|
| - GetInstanceObject()->compiled_module(), isolate_);
|
| - int position = GetTopPosition(compiled_module);
|
| - MaybeHandle<FixedArray> hit_breakpoints;
|
| + // Check whether we hit a breakpoint.
|
| if (isolate_->debug()->break_points_active()) {
|
| - hit_breakpoints = compiled_module->CheckBreakPoints(position);
|
| + Handle<WasmCompiledModule> compiled_module(
|
| + GetInstanceObject()->compiled_module(), isolate_);
|
| + int position = GetTopPosition(compiled_module);
|
| + Handle<FixedArray> breakpoints;
|
| + if (compiled_module->CheckBreakPoints(position).ToHandle(&breakpoints)) {
|
| + // We hit one or several breakpoints. Clear stepping, notify the
|
| + // listeners and return.
|
| + ClearStepping();
|
| + Handle<Object> hit_breakpoints_js =
|
| + isolate_->factory()->NewJSArrayWithElements(breakpoints);
|
| + isolate_->debug()->OnDebugBreak(hit_breakpoints_js);
|
| + return;
|
| + }
|
| }
|
|
|
| - // If we hit a breakpoint, pass a JSArray with all breakpoints, otherwise
|
| - // pass undefined.
|
| - Handle<Object> hit_breakpoints_js;
|
| - if (hit_breakpoints.is_null()) {
|
| - hit_breakpoints_js = isolate_->factory()->undefined_value();
|
| - } else {
|
| - hit_breakpoints_js = isolate_->factory()->NewJSArrayWithElements(
|
| - hit_breakpoints.ToHandleChecked());
|
| + // We did not hit a breakpoint, so maybe this pause is related to stepping.
|
| + bool hit_step = false;
|
| + switch (next_step_action_) {
|
| + case StepNone:
|
| + break;
|
| + case StepIn:
|
| + hit_step = true;
|
| + break;
|
| + case StepOut:
|
| + hit_step = thread->GetFrameCount() < last_step_stack_depth_;
|
| + break;
|
| + case StepNext: {
|
| + hit_step = thread->GetFrameCount() == last_step_stack_depth_;
|
| + break;
|
| + }
|
| + case StepFrame:
|
| + hit_step = thread->GetFrameCount() != last_step_stack_depth_;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| }
|
| -
|
| - isolate_->debug()->OnDebugBreak(hit_breakpoints_js);
|
| + if (!hit_step) return;
|
| + ClearStepping();
|
| + isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value());
|
| }
|
|
|
| int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
|
| @@ -352,6 +415,10 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
|
| EnsureRedirectToInterpreter(isolate, debug_info, func_index);
|
| }
|
|
|
| +void WasmDebugInfo::PrepareStep(StepAction step_action) {
|
| + GetInterpreterHandle(this)->PrepareStep(step_action);
|
| +}
|
| +
|
| void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) {
|
| DCHECK_LE(0, func_index);
|
| GetInterpreterHandle(this)->Execute(static_cast<uint32_t>(func_index),
|
|
|