From 2871699e8990c660bb76b77bfc0aff97c8fbd1e3 Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Mon, 15 Sep 2025 04:29:39 -0700 Subject: [PATCH] [vm,dyn_modules] Fix stepping over when debugging the interpreter. Since any instruction is a possible pause point when single stepping in the interpreter, the debugger may pause too early when stepping over an expression; for example, if the value returned from an expression is ignored, stepping over the expression should also step over the following Drop1 instruction (which will have the same source location), but currently does not. To avoid this, set last_stepping_fp_ and last_stepping_pos_ when stepping over either a sync or async expression so that the debugger won't pause until a new source position is reached. TEST=pkg/vm_service/test Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try,vm-dyn-mac-debug-arm64-try Change-Id: I0934f6bda3fc075a225a85b66eccf46b94cb4020 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449420 Reviewed-by: Alexander Markov Commit-Queue: Tess Strickland --- runtime/vm/debugger.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index f40be9c4494..89f4a9a6dfe 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -3091,6 +3091,16 @@ void Debugger::ResumptionBreakpoint() { "ResumptionBreakpoint - hit a breakpoint, continue single " "stepping\n"); } +#if defined(DART_DYNAMIC_MODULES) + if (top_frame->IsInterpreted()) { + // The interpreter calls the single step handler on every instruction, + // so set the last stepping fp/position to the current fp/position when + // stepping over so the debugger doesn't pause until it reaches + // a _new_ source position. + last_stepping_fp_ = top_frame->fp(); + last_stepping_pos_ = top_frame->TokenPos(); + } +#endif EnterSingleStepMode(); return; } @@ -3416,6 +3426,12 @@ void Debugger::SetSyncSteppingFramePointer(DebuggerStackTrace* stack_trace) { stepping_fp_ = frame->fp(); #if defined(DART_DYNAMIC_MODULES) stepping_fp_from_interpreted_frame_ = frame->IsInterpreted(); + // The interpreter calls the single step handler on every instruction, + // so set the last stepping fp/position to the current fp/position when + // stepping over so the debugger doesn't pause until it reaches + // a _new_ source position. + last_stepping_fp_ = frame->fp(); + last_stepping_pos_ = frame->TokenPos(); #endif } else { stepping_fp_ = 0;