RFR: 8369505: jhsdb jstack cannot handle continuation stub

Patricio Chilano Mateo pchilanomate at openjdk.org
Tue Oct 14 18:14:34 UTC 2025


On Sat, 11 Oct 2025 05:09:31 GMT, Chris Plummer <cjplummer at openjdk.org> wrote:

> > @plummercj Did you run `jhsdb jstack --mixed` ? StubRoutine would appear in mixed mode only I think (in Linux, at least).
> 
> I did not, and unfortunately --mixed is not support on OSX.
>
Ok, that’s why I wasn’t seeing `<StubRoutines (continuation stubs)>` either. I removed `—mixed` because it wasn’t working for me, only the top native frame was shown in the stacktrace (on linux-x64). I could still reproduce the assert without `—mixed` so I continued testing that way assuming the output for the `enterSpecial` frame would be the same in both modes. 
Now, testing on linux-aarch64, `—mixed` mode works and I can see `<StubRoutines (continuation stubs)>` for the `enterSpecial` frame. Looking at the code, I see the difference with mixed mode is the way we walk the stack. Even for Java frames the sender is always obtained through this method [1], relying basically on the FP. Then once we get to the frame with pc equal to the return barrier, here [2] we will just branch to the else case and print it as a continuation stub instead of the `enterSpecial` frame.
I was also curious how we can walk compiled frames this way, since the FP will not contain in general a valid link unless `-XX:+PreserveFramePointer` is set. So I added `-Xcomp` to `LingeredApp.startApp` and I see that we indeed fail to walk the stack:


----------------- 2943661 -----------------
"ForkJoinPool-1-worker-2" #30 daemon prio=5 tid=0x0000ffff08007f30 nid=2943661 runnable [0x0000ffff695e1000]
   java.lang.Thread.State: RUNNABLE
   JavaThread state: _thread_in_native
0x0000ffff9bb40b24	__clock_nanosleep + 0x84
0x0000ffff9bb45c0c	__GI___nanosleep + 0x1c
0x0000ffff9bb45acc	__sleep + 0x4c
0x0000ffff836fb338	<nep_invoker_blob>
0x0000ffff7c802ef8	* java.lang.invoke.LambdaForm$MH+0x0000000601047800.invoke(java.lang.Object, long, int) bci:10 (Compiled frame)
                  	* java.lang.invoke.LambdaForm$MH+0x000000060104d400.invokeExact_MT(java.lang.Object, long, int, java.lang.Object) bci:21 (Compiled frame)
0x910023e12a0003e2		????????
----------------- 2943659 -----------------


When setting` -XX:+PreserveFramePointer` we can walk them again (also tweaked the code to print the correct `enterSpecial` frame):


----------------- 2947348 -----------------
"ForkJoinPool-1-worker-2" #30 daemon prio=5 tid=0x0000ffff1c008040 nid=2947348 runnable [0x0000ffff7c8dd000]
   java.lang.Thread.State: RUNNABLE
   JavaThread state: _thread_in_native
0x0000ffffaee18b24	__clock_nanosleep + 0x84
0x0000ffffaee1dc0c	__GI___nanosleep + 0x1c
0x0000ffffaee1dacc	__sleep + 0x4c
0x0000ffff976faa38	<nep_invoker_blob>
0x0000ffff90806f3c	* java.lang.invoke.LambdaForm$MH+0x000007e001047800.invoke(java.lang.Object, long, int) bci:10 (Compiled frame)
0x0000ffff90bad354	* java.lang.invoke.LambdaForm$MH+0x000007e00104d400.invokeExact_MT(java.lang.Object, long, int, java.lang.Object) bci:21 (Compiled frame)
0x0000ffff97597d60	* jdk.internal.foreign.abi.DowncallStub+0x000007e001048800.invoke(java.lang.foreign.SegmentAllocator, java.lang.foreign.MemorySegment, int) bci:44 (Interpreted frame)
0x0000ffff908b7a70	* java.lang.invoke.LambdaForm$DMH+0x000007e001048c00.invokeStaticInit(java.lang.Object, java.lang.Object, java.lang.Object, int) bci:14 (Compiled frame)
0x0000ffff90b9b710	* java.lang.invoke.LambdaForm$MH+0x000007e00104c800.invoke(java.lang.Object, int) bci:44 (Compiled frame)
0x0000ffff90b9041c	* java.lang.invoke.LambdaForm$MH+0x000007e00104c400.invoke_MT(java.lang.Object, int, java.lang.Object) bci:18 (Compiled frame)
0x0000ffff97597f30	* LingeredAppWithVirtualThread.run() bci:15 line:65 (Interpreted frame)
0x0000ffff975963b8	* jdk.internal.vm.Continuation.enterSpecial(jdk.internal.vm.Continuation, boolean, boolean) bci:0 (Compiled frame)
0x0000ffff97fa5fbc	* jdk.internal.vm.Continuation.run() bci:152 line:251 (Compiled frame)
0x0000ffff90b85888	* java.lang.VirtualThread.runContinuation() bci:100 line:293 (Compiled frame)
0x0000ffff97fa3eb0	* java.lang.VirtualThread$$Lambda+0x000007e001034c88.run() bci:4 (Compiled frame)
0x0000ffff90b8445c	* java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec() bci:4 line:1596 (Compiled frame)
0x0000ffff90b83298	* java.util.concurrent.ForkJoinTask.doExec() bci:10 line:511 (Compiled frame)
0x0000ffff90b81e2c	* java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.util.concurrent.ForkJoinTask, int) bci:5 line:1450 (Compiled frame)
                  	* java.util.concurrent.ForkJoinPool.runWorker(java.util.concurrent.ForkJoinPool$WorkQueue) bci:364 line:2019 (Compiled frame)
0x0000ffff97fa03a8	* java.util.concurrent.ForkJoinWorkerThread.run() bci:31 line:187 (Compiled frame)
0x0000ffff9759349c	<StubRoutines (initial stubs)>
0x0000ffffad95020c	JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*) + 0x45c
0x0000ffffad950880	JavaCalls::call_virtual(JavaValue*, Klass*, Symbol*, Symbol*, JavaCallArguments*, JavaThread*) + 0x278
0x0000ffffad950e14	JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, JavaThread*) + 0x8c
0x0000ffffadaee66c	thread_entry(JavaThread*, JavaThread*) + 0xc4
0x0000ffffad98de68	JavaThread::thread_main_inner() + 0x108
0x0000ffffae301efc	Thread::call_run() + 0xac
0x0000ffffadfe105c	thread_native_entry(Thread*) + 0x12c
0x0000ffffaede3b50	start_thread + 0x300

I would have expected that `mixed` mode walked the stack similar to how we do it in the VM with `NativeStackPrinter` using `frame::next_frame()`, i.e we change how we get the sender based on the frame.

Anyways, I was just curious about the difference in output with `mixed` mode.

[1] https://github.com/openjdk/jdk/blob/d6537c6d3ee6d7a59d609b277f0538da0afb0fbf/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java#L56
[2] https://github.com/openjdk/jdk/blob/d6537c6d3ee6d7a59d609b277f0538da0afb0fbf/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java#L148

-------------

PR Comment: https://git.openjdk.org/jdk/pull/27728#issuecomment-3403057882


More information about the serviceability-dev mailing list