On Wed, 2 Sep 2026 20:11:48 GMT, Shiv Shah <[email protected]> wrote: > When a virtual thread suspended at a breakpoint gets unmounted and mounted > again only the top frame is thawed. The caller stays frozen in the stack > chunk and the popped frame returns into the continuation return barrier. The > interpreter's popframe entry treats that return address like a deoptimized > caller, preserves the arguments, sets the reexecution bit and returns. The > barrier then thawed the caller as a plain return. Arguments and bit left > behind, no reexecution of the invoke, run() went on with a zero result. > > Thaw finishes it now. An interpreted caller gets the preserved arguments back > on its expression stack and its return slot is patched to the interpreter > deopt entry after push_return_frame, the x86 deopt entry reloads rsp from > last_sp for that, aarch64 already does. A compiled caller frozen in the chunk > is deoptimized from UpdateForPopTopFrameClosure::doit the same way > set_frame_pop does it. Thaw leaves the arguments alone in that case and > unpack_on_stack puts them back. A frozen compiled frame being popped stays > opaque. > > A linkTo caller needs one more thing. The linker consumed the trailing > MemberName before the target ran and the preserved arguments are sized by the > target, so the MemberName is not among them. Thaw takes it from the caller's > local 0 the way the interpreter's popframe entry does, the lookup from > member_name_arg_or_null moved into a plain helper both can call. The > arguments go one slot up and the MemberName goes back on top. > > popframes002 runs popframes001 on a virtual thread with the join Chris > Plummer wrote enabled by a property in the debuggee. It unmounts the tested > thread before the breakpoint so the caller is frozen when popped, and run() > is excluded from compilation so this stays the interpreted case. popframes003 > is the compiled caller case, -Xcomp with the breakpoint in a separate stop() > so testedMethod keeps its compiled frame and run() stays frozen, the debugger > pops frame 1 and the debuggee checks with WhiteBox that run() and > testedMethod are compiled and that testedMethod ran twice. > -XX:+PreserveFramePointer keeps the thaw on the slow path. Both fail on > master without the hotspot change. popframes001 itself runs the plain case as > before and is off the virtual problem list. If separate copies of the > debugger and debuggee are preferred over the properties that is easy to > change. PopFrameMethodNameInvariantTest got an unmount mode, the same > linkToStatic pop on a virtual thread that sleeps before the breakpoint so its ca...
src/hotspot/share/runtime/continuationFreezeThaw.cpp line 3114: > 3112: int top_element = f.interpreter_frame_expression_stack_size() - > 1; > 3113: intptr_t* base = > f.interpreter_frame_expression_stack_at(top_element); > 3114: Copy::conjoint_jbytes(_thread->popframe_preserved_args(), base, > words * wordSize); For `linkTo*` calls I see we restore the required trailing `MemberName` in the normal interpreter caller case [(1)](https://github.com/openjdk/jdk/blob/decb49e1f3d05eeae7ef48e43623e3795b21d266/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp#L1529). We would need to do the same here, or alternatively reject this case in the pop frame closure. src/hotspot/share/runtime/continuationFreezeThaw.cpp line 3121: > 3119: } else { > 3120: assert(f.is_deoptimized_frame(), "popframe reexecution into a > frozen compiled caller that was not deoptimized"); > 3121: } This body could be factored out into a separate static method along with the comment above. test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/PopFrames/popframes001a.java line 132: > 130: try { > 131: Method run = > TestedThreadClass.class.getDeclaredMethod("run"); > 132: if > (WhiteBox.getWhiteBox().getMethodCompilationLevel(run) == 0) { Note that this check only verifies that a compiled version of `run()` exists, not that we are running it. But even if we could guarantee that, we always thaw the compiled caller of an interpreted frame. In order to exercise this case we could do something like what you did in `PopFrameMethodNameInvariantTest.java` with an extra `stop()` where we put the breakpoint instead, and then in the `popFrames` request include its caller. You might want to also use `-XX:+PreserveFramePointer` (avoids thawing all frames at once). ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/32661#discussion_r4289045636 PR Review Comment: https://git.openjdk.org/jdk/pull/32661#discussion_r4289038012 PR Review Comment: https://git.openjdk.org/jdk/pull/32661#discussion_r4330891105
