From 32b8c8f12fbecd2d9862fe95b027f6132ed32aab Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Mon, 16 Mar 2026 09:35:38 -0700 Subject: [PATCH] [vm,dyn_modules] Fix the interpreter case in GenerateResumeStub. Previously, it would always call the ResumeInterpreter runtime entry passing null as the value to return to the resumed code. Instead, appropriately retrieve the to-be-returned value from the stack. Also fixes IL printing to print constants in non-SSA flow graphs and adds Interpreter::TraceStackFrames, which prints the top frames of the current stack, so calls to it can be added for easier debugging in the future. TEST=pkg/vm_service/test/async_star_step_out_test.dart (still fails, but the failure changes due to no longer spuriously calling get:current after the generator finishes) Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try Change-Id: Ibb3524d32c8c4e1320f4f9dfd35947eda7d6ca68 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/488181 Reviewed-by: Alexander Markov Commit-Queue: Tess Strickland --- runtime/vm/compiler/backend/il_printer.cc | 2 +- runtime/vm/compiler/stub_code_compiler.cc | 7 ++-- runtime/vm/interpreter.cc | 48 +++++++++++++++++++++++ runtime/vm/interpreter.h | 9 +++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc index f6c040754c2..54f01fe289c 100644 --- a/runtime/vm/compiler/backend/il_printer.cc +++ b/runtime/vm/compiler/backend/il_printer.cc @@ -34,7 +34,7 @@ DECLARE_FLAG(bool, trace_inlining_intervals); static bool IsRedundant(Instruction* instr) { if (auto constant = instr->AsConstant()) { - return !constant->HasUses(); + return constant->HasSSATemp() && !constant->HasUses(); } else if (auto move = instr->AsParallelMove()) { return move->IsRedundant(); } else { diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index 1ba8908934c..7572a31eef9 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -2542,11 +2542,12 @@ void StubCodeCompiler::GenerateResumeStub() { } SPILLS_RETURN_ADDRESS_FROM_LR_TO_REGISTER({}); // Undo SetReturnAddress(). #endif - __ Comment("Resume interpreter with exception"); + __ Comment("Resume interpreter"); __ Bind(&resume_interpreter); __ PushObject(NullObject()); // Make room for result. - __ PushObject(NullObject()); // Return value. - __ PushRegistersInOrder({kException, kStackTrace}); + // Load the value to pass to the resumed bytecode. + __ LoadFromOffset(kTemp, FPREG, param_offset + 3 * target::kWordSize); + __ PushRegistersInOrder({kTemp, kException, kStackTrace}); __ CallRuntime(kResumeInterpreterRuntimeEntry, /*argument_count=*/3); __ Drop(3); // Drop arguments. __ PopRegister(CallingConventions::kReturnReg); // Get result. diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc index 836edfdfb0e..ea93d56714b 100644 --- a/runtime/vm/interpreter.cc +++ b/runtime/vm/interpreter.cc @@ -439,6 +439,54 @@ DART_NOINLINE void Interpreter::WriteInstructionToTrace(const KBCInstr* pc) { } } +void Interpreter::PrintStackFrames(const ObjectPtr* FP, + const ObjectPtr* SP, + intptr_t depth) { + const word *fp = reinterpret_cast(FP), + *sp = reinterpret_cast(SP); + for (intptr_t i = 0; i < depth; i++) { + const word caller_pc = fp[kKBCSavedCallerPcSlotFromFp]; + const bool is_entry_frame = caller_pc == kEntryFramePcMarker; + // The entry frame slots are printed separately from the rest of the frame. + auto* const frame_end = fp + (is_entry_frame ? kKBCEntrySavedSlots : 0); + + THR_Print("Frame %" Pd "%s:\n", i, is_entry_frame ? " (entry)" : ""); + for (auto* current = sp; current >= frame_end; --current) { + THR_Print(" %#" Px ": %#" Px "\n", reinterpret_cast(current), + *current); + } + + if (is_entry_frame) { + THR_Print(" %#" Px ": %#" Px " (pool pointer)\n", + reinterpret_cast(fp + kKBCSavedPpSlotFromEntryFp), + fp[kKBCSavedPpSlotFromEntryFp]); + THR_Print(" %#" Px ": %#" Px " (args descriptor)\n", + reinterpret_cast(fp + kKBCSavedArgDescSlotFromEntryFp), + fp[kKBCSavedArgDescSlotFromEntryFp]); + THR_Print(" %#" Px ": %#" Px " (exit link)\n", + reinterpret_cast(fp + kKBCExitLinkSlotFromEntryFp), + fp[kKBCExitLinkSlotFromEntryFp]); + } + + THR_Print(" %#" Px ": %#" Px " (saved caller fp)\n", + reinterpret_cast(fp + kKBCSavedCallerFpSlotFromFp), + fp[kKBCSavedCallerFpSlotFromFp]); + THR_Print(" %#" Px ": %#" Px " (saved caller pc)\n", + reinterpret_cast(fp + kKBCSavedCallerPcSlotFromFp), + fp[kKBCSavedCallerPcSlotFromFp]); + if (is_entry_frame) break; + THR_Print(" %#" Px ": %#" Px " (caller pc)\n", + reinterpret_cast(fp + kKBCPcMarkerSlotFromFp), + fp[kKBCPcMarkerSlotFromFp]); + THR_Print(" %#" Px ": %#" Px " (called function)\n", + reinterpret_cast(fp + kKBCFunctionSlotFromFp), + fp[kKBCFunctionSlotFromFp]); + sp = fp + kKBCCallerSpSlotFromFp; + fp = reinterpret_cast(fp[kKBCSavedCallerFpSlotFromFp]); + THR_Print("\n"); + } +} + #endif // defined(DEBUG) // Calls into the Dart runtime are based on this interface. diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h index e030498cd85..11b9f95f335 100644 --- a/runtime/vm/interpreter.h +++ b/runtime/vm/interpreter.h @@ -289,6 +289,15 @@ class Interpreter { void FlushTraceBuffer(); void WriteInstructionToTrace(const KBCInstr* pc); + // Prints at most the requested number of interpreted stack frames + // up to the most recent entry frame. + // + // If [depth] is non-positive, prints all interpreted stack frames + // up to the most recent entry frame. + void PrintStackFrames(const ObjectPtr* FP, + const ObjectPtr* SP, + intptr_t depth = 0); + void* trace_file_; uint64_t trace_file_bytes_written_;