JDK-8307125 : compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java hits assert(!Continuation::is_frame_in_continuation(thread(), fr())) failed: No support for deferred values in continuations
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 21
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2023-04-28
  • Updated: 2024-08-20
  • Resolved: 2023-05-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21
21 b25Fixed
Related Reports
Relates :  
Description
Test
compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java when executed with test thread factory plugin
hits 

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (/opt/mach5/mesos/work_dir/slaves/741e9afd-8c02-45c3-b2e2-9db1450d0832-S79032/frameworks/1735e8a2-a1db-478c-8104-60c8b0af87dd-0196/executors/750846d8-d033-408e-81ca-585a129691d7/runs/2557e57f-d43b-4f45-909b-c725b6a3a577/workspace/open/src/hotspot/share/runtime/vframe_hp.cpp:112), pid=430325, tid=430475
#  assert(!Continuation::is_frame_in_continuation(thread(), fr())) failed: No support for deferred values in continuations
#
# JRE version: Java(TM) SE Runtime Environment (21.0) (fastdebug build 21-internal-LTS-2023-04-28-0130129.leonid.mesnik.jdk-ttf-build)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 21-internal-LTS-2023-04-28-0130129.leonid.mesnik.jdk-ttf-build, mixed mode, tiered, jvmci, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V  [libjvm.so+0x181226e]  compiledVFrame::update_deferred_value(BasicType, int, jvalue)+0x33e
 ....

Current thread (0x00007f1bcc5572d0):  JavaThread "ForkJoinPool-1-worker-1" daemon [_thread_in_vm, id=430475, stack(0x00007f1ba5bfb000,0x00007f1ba5cfc000)]

Stack: [0x00007f1ba5bfb000,0x00007f1ba5cfc000],  sp=0x00007f1ba5cf7290,  free space=1008k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x181226e]  compiledVFrame::update_deferred_value(BasicType, int, jvalue)+0x33e  (vframe_hp.cpp:112)
V  [libjvm.so+0x1011200]  c2v_materializeVirtualObjects(JNIEnv_*, _jobject*, _jobject*, bool)+0xa00  (jvmciCompilerToVM.cpp:1649)
j  jdk.vm.ci.hotspot.CompilerToVM.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+0 jdk.internal.vm.ci@21-internal
j  jdk.vm.ci.hotspot.CompilerToVMHelper.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+5 jdk.internal.vm.ci@21-internal
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.check(I)V+202
J 578 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.recurse(II)V (70 bytes) @ 0x00007f1bbc7a3c08 [0x00007f1bbc7a3bc0+0x0000000000000048]
J 586 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame2(Ljava/lang/String;I)V (115 bytes) @ 0x00007f1bbc7acdd8 [0x00007f1bbc7acd80+0x0000000000000058]
J 585 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame(Ljava/lang/String;I)V (55 bytes) @ 0x00007f1bbc7a9eac [0x00007f1bbc7a9e60+0x000000000000004c]
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.test()V+117
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.main([Ljava/lang/String;)V+37
j  java.lang.invoke.LambdaForm$DMH+0x00000001000c0000.invokeStatic(Ljava/lang/Object;Ljava/lang/Object;)V+10 java.base@21-internal
j  java.lang.invoke.LambdaForm$MH+0x00000001000c5000.invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+33 java.base@21-internal
j  java.lang.invoke.Invokers$Holder.invokeExact_MT(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+20 java.base@21-internal
j  jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+55 java.base@21-internal
j  jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+23 java.base@21-internal
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+102 java.base@21-internal
j  com.sun.javatest.regtest.agent.MainWrapper$MainTask.run()V+134
j  java.lang.VirtualThread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21-internal
j  java.lang.VirtualThread.run(Ljava/lang/Runnable;)V+65 java.base@21-internal
j  java.lang.VirtualThread$VThreadContinuation$1.run()V+8 java.base@21-internal
j  jdk.internal.vm.Continuation.enter0()V+4 java.base@21-internal
j  jdk.internal.vm.Continuation.enter(Ljdk/internal/vm/Continuation;Z)V+1 java.base@21-internal
J 308  jdk.internal.vm.Continuation.enterSpecial(Ljdk/internal/vm/Continuation;ZZ)V java.base@21-internal (0 bytes) @ 0x00007f1bbc773ec4 [0x00007f1bbc773d60+0x0000000000000164]
j  jdk.internal.vm.Continuation.run()V+122 java.base@21-internal
j  java.lang.VirtualThread.runContinuation()V+76 java.base@21-internal
j  java.lang.VirtualThread$$Lambda+0x00000001000ad970.run()V+4 java.base@21-internal
j  java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec()Z+4 java.base@21-internal
j  java.util.concurrent.ForkJoinTask.doExec()I+10 java.base@21-internal
j  java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Ljava/util/concurrent/ForkJoinTask;Ljava/util/concurrent/ForkJoinPool$WorkQueue;)V+19 java.base@21-internal
j  java.util.concurrent.ForkJoinPool.scan(Ljava/util/concurrent/ForkJoinPool$WorkQueue;II)I+211 java.base@21-internal
j  java.util.concurrent.ForkJoinPool.runWorker(Ljava/util/concurrent/ForkJoinPool$WorkQueue;)V+35 java.base@21-internal
j  java.util.concurrent.ForkJoinWorkerThread.run()V+31 java.base@21-internal
v  ~StubRoutines::call_stub 0x00007f1bbc1c5d21
V  [libjvm.so+0xe55d02]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x462  (javaCalls.cpp:415)
V  [libjvm.so+0xe562e3]  JavaCalls::call_virtual(JavaValue*, Klass*, Symbol*, Symbol*, JavaCallArguments*, JavaThread*)+0x283  (javaCalls.cpp:329)
V  [libjvm.so+0xe564f1]  JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, JavaThread*)+0x71  (javaCalls.cpp:191)
V  [libjvm.so+0xfa5666]  thread_entry(JavaThread*, JavaThread*)+0x96  (jvm.cpp:2918)
V  [libjvm.so+0xe87e9e]  JavaThread::thread_main_inner()+0x17e  (javaThread.cpp:717)
V  [libjvm.so+0x1758538]  Thread::call_run()+0xb8  (thread.cpp:215)
V  [libjvm.so+0x145984a]  thread_native_entry(Thread*)+0x11a  (os_linux.cpp:740)
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  jdk.vm.ci.hotspot.CompilerToVM.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+0 jdk.internal.vm.ci@21-internal
j  jdk.vm.ci.hotspot.CompilerToVMHelper.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+5 jdk.internal.vm.ci@21-internal
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.check(I)V+202
J 578 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.recurse(II)V (70 bytes) @ 0x00007f1bbc7a3c08 [0x00007f1bbc7a3bc0+0x0000000000000048]
J 586 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame2(Ljava/lang/String;I)V (115 bytes) @ 0x00007f1bbc7acdd8 [0x00007f1bbc7acd80+0x0000000000000058]
J 585 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame(Ljava/lang/String;I)V (55 bytes) @ 0x00007f1bbc7a9eac [0x00007f1bbc7a9e60+0x000000000000004c]
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.test()V+117
j  compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.main([Ljava/lang/String;)V+37
j  java.lang.invoke.LambdaForm$DMH+0x00000001000c0000.invokeStatic(Ljava/lang/Object;Ljava/lang/Object;)V+10 java.base@21-internal
j  java.lang.invoke.LambdaForm$MH+0x00000001000c5000.invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+33 java.base@21-internal
j  java.lang.invoke.Invokers$Holder.invokeExact_MT(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+20 java.base@21-internal
j  jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+55 java.base@21-internal
j  jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+23 java.base@21-internal
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+102 java.base@21-internal
j  com.sun.javatest.regtest.agent.MainWrapper$MainTask.run()V+134
j  java.lang.VirtualThread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21-internal
j  java.lang.VirtualThread.run(Ljava/lang/Runnable;)V+65 java.base@21-internal
j  java.lang.VirtualThread$VThreadContinuation$1.run()V+8 java.base@21-internal
j  jdk.internal.vm.Continuation.enter0()V+4 java.base@21-internal
j  jdk.internal.vm.Continuation.enter(Ljdk/internal/vm/Continuation;Z)V+1 java.base@21-internal
J 308  jdk.internal.vm.Continuation.enterSpecial(Ljdk/internal/vm/Continuation;ZZ)V java.base@21-internal (0 bytes) @ 0x00007f1bbc773ec4 [0x00007f1bbc773d60+0x0000000000000164]
j  jdk.internal.vm.Continuation.run()V+122 java.base@21-internal
j  java.lang.VirtualThread.runContinuation()V+76 java.base@21-internal
j  java.lang.VirtualThread$$Lambda+0x00000001000ad970.run()V+4 java.base@21-internal
j  java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec()Z+4 java.base@21-internal
j  java.util.concurrent.ForkJoinTask.doExec()I+10 java.base@21-internal
j  java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Ljava/util/concurrent/ForkJoinTask;Ljava/util/concurrent/ForkJoinPool$WorkQueue;)V+19 java.base@21-internal
j  java.util.concurrent.ForkJoinPool.scan(Ljava/util/concurrent/ForkJoinPool$WorkQueue;II)I+211 java.base@21-internal
j  java.util.concurrent.ForkJoinPool.runWorker(Ljava/util/concurrent/ForkJoinPool$WorkQueue;)V+35 java.base@21-internal
j  java.util.concurrent.ForkJoinWorkerThread.run()V+31 java.base@21-internal
v  ~StubRoutines::call_stub 0x00007f1bbc1c5d21
Registers:
RAX=0x00007f1bd5fa7000, RBX=0x00007f1b748588d0, RCX=0x00007f1bd4eef1e0, RDX=0x00007f1bd4eef210
RSP=0x00007f1ba5cf7290, RBP=0x00007f1ba5cf7330, RSI=0x0000000000000070, RDI=0x00007f1bd4eeef78
R8 =0x0000000000000001, R9 =0x0000000000000000, R10=0x0000000000000000, R11=0x0000000000000000
R12=0x00007f1ba5cf72c0, R13=0x0000000000000000, R14=0x00007f1b74859d40, R15=0x00007f1b748588d0
RIP=0x00007f1bd4be926e, EFLAGS=0x0000000000010202, CSGSFS=0x002b000000000033, ERR=0x0000000000000006
  TRAPNO=0x000000000000000e
Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/13777 Date: 2023-05-03 12:43:29 +0000
20-08-2024

Changeset: 89b3c375 Author: Doug Simon <dnsimon@openjdk.org> Date: 2023-05-25 16:26:26 +0000 URL: https://git.openjdk.org/jdk/commit/89b3c375ac55f960dbeac8a2355e528450e610a1
25-05-2023

To give a bit of context: In Truffle a number of optimizations are reliant on lazily materializing caller frames. As you can imagine keeping frames virtual allows us effective stack allocate them and therefore allows us to be competitive with regular native frames. So we keep frames virtual optimistically until we find out we need to materialize them, which will always be materialized for future frame allocations. We will have a tough time knowing which frames to materialize beforehand. So our peak performance would suffer significantly on VirtualThreads. Likewise, the Truffle debugger also uses this mechanism to inspect and modify Truffle natively compiled frames. We can speculate that we are not executing on VirtualThreads, enabling these optimizations for regular threads and disabling them for VirtualThreads. We can keep the optimized frames read-only for virtual threads for the debugger. All this machinery requires many changes on our end to support. It would be good to know if it is worth it or if VirtualThreads will ultimately support deferred locals. We only need to materialize the VirtualFrame on the stack. We can mark all the locals we may need to materialize of which methods ahead of time. A few more side notes on this: * We want to move away from the JVMCI Frame API in favor of using the StackWalker API. But we miss the capability to modify frames there. I think it is in our interest to move these two worlds together, ultimately. * We currently do not allow Truffle languages to enter virtual threads with the optimized Truffle runtime. We would love to support VirtualThreads and bring it to many of our language implementations. [~rpressler] What would you recommend we do?
03-05-2023

There is no plan to support deferred locals in virtual threads directly. However, we would like to ultimately allow continuations unroll compiled frames that have been marked for deoptimization into interpreted frames before freezing, at least in some situations. As a side effect this will "support" deferred locals as they will be inserted into the interpreted frames when unrolled. However, that work has not started.
03-05-2023

Thanks for the clarification [~rpressler]. This means in the short term we will need to add something jdk.vm.ci.code.stack.InspectedFrame#canMaterializeVirtualObjects which will return false for virtual threads until such time that the necessary support is added. I guess this means there's also no immediate plans to allow local variable reflection in the java.lang.StackWalker API either (whether for virtual or non-virtual threads)? Note that this places a limitation on com.oracle.truffle.api.frame.FrameInstance#getFrame[1] in terms of preventing write access to local variables of frames of virtual threads. (cc [~chumer]) [1] https://github.com/oracle/graal/blob/12022ff745f743894ecbac8db2235a5dfbdc63a4/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java#L97
03-05-2023

[~dnsimon] That is correct, and has always been the case: deferred locals are not supported in virtual threads. That's also why virtual threads do not support setting locals when debugging in frames other than the topmost (current) one. Supporting deferred locals is complicated, and the right way to do it is to allow the continuation code to unroll compiled frames to interpreted frames before they're frozen (as opposed to waiting for the frames to be deoptimized when returned to). We may need the capability to construct interpreted frames on demand if and when we support serialization of continuations, but other than that there is currently no ongoing work to specifically support deferred locals.
03-05-2023

If I interpret this failure correctly, it means jdk.vm.ci.code.stack.InspectedFrame#materializeVirtualObjects cannot work on virtual threads. Is that right [~alanb]?
03-05-2023

I added some tracing and for this stack: Stack: [0x000000016d7f0000,0x000000016d9f3000], sp=0x000000016d9efff0, free space=2047k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.dylib+0x12b08b4] VMError::report_and_die(int, char const*, char const*, char*, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)+0x4bc (vframe_hp.cpp:117) V [libjvm.dylib+0x12b1250] VMError::report_and_die(Thread*, void*, char const*, int, char const*, char const*, char*)+0x40 V [libjvm.dylib+0x66fd94] report_vm_error(char const*, int, char const*, char const*, ...)+0x6c V [libjvm.dylib+0x129cbac] compiledVFrame::update_deferred_value(BasicType, int, jvalue)+0x188 V [libjvm.dylib+0xb568dc] c2v_materializeVirtualObjects(JNIEnv_*, _jobject*, _jobject*, bool)+0xc5c j jdk.vm.ci.hotspot.CompilerToVM.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+0 jdk.internal.vm.ci@21-internal j jdk.vm.ci.hotspot.CompilerToVMHelper.materializeVirtualObjects(Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;Z)V+5 jdk.internal.vm.ci@21-internal j compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.check(I)V+202 J 574 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.recurse(II)V (70 bytes) @ 0x000000011801cbf0 [0x000000011801cb80+0x0000000000000070] J 577 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame2(Ljava/lang/String;I)V (115 bytes) @ 0x000000011802462c [0x00000001180245c0+0x000000000000006c] J 576 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame(Ljava/lang/String;I)V (55 bytes) @ 0x0000000118021a6c [0x0000000118021a00+0x000000000000006c] j compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.test()V+117 j compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.main([Ljava/lang/String;)V+37 j java.lang.invoke.LambdaForm$DMH+0x00000003000c0000.invokeStatic(Ljava/lang/Object;Ljava/lang/Object;)V+10 java.base@21-internal j java.lang.invoke.LambdaForm$MH+0x00000003000c5000.invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+33 java.base@21-internal I see that the assertion is failing for this frame: J 576 c2 compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.testFrame(Ljava/lang/String;I)V (55 bytes) @ 0x0000000118021a6c [0x0000000118021a00+0x000000000000006c] What exactly is Continuation::is_frame_in_continuation testing? Why might it be true for this frame but not the frames for the C2 compiled frames (i.e. MaterializeVirtualObjectTest.testFrame2 and MaterializeVirtualObjectTest.recurse) just below it?
02-05-2023

There's no support for deferred value with virtual threads. This shouldn't be an issue for JVMTI SetLocalXXX as the spec only requires that an implementation support setting locals in the top-most frame of a virtual thread that is suspended at an event. If I read this bug report correctly, it looks like the Graal JIT also makes use of this feature.
02-05-2023

Doug, please have a look.
02-05-2023

ILW = Assert during materialization of virtual objects, JVMCI test with Loom (preview feature), disable thread factory plugin = HLM = P3
02-05-2023

To reproduce fix run test with following command-line: make -- run-test JTREG_TEST_THREAD_FACTORY=Virtual TEST=compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java
28-04-2023