RFR: 8369609: Continuations preempt_epilog is missing a call to invalidate_jvmti_stack [v3]

Patricio Chilano Mateo pchilanomate at openjdk.org
Thu Oct 23 14:27:02 UTC 2025


On Thu, 23 Oct 2025 03:56:07 GMT, Serguei Spitsyn <sspitsyn at openjdk.org> wrote:

>> Strangely, the test `serviceability/jvmti/vthread/ContStackDepthTest` is failing with the `assert(_cur_stack_depth == num_frames)`. Obviously, some of the code paths is missed to call `invalidate_jvmti_stack()`.
>
> As I see, the calls to `invalidate_jvmti_stack()` are needed for plain continuations only (under condition `if (!cont.entry()->is_virtual_thread()`).
> 
> The following patch does not cause regressions in mach5 tier 6 (mach5 tiers 1-5 are in progress):
> 
> diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp
> index 0884fce2ff7..dbbf5526602 100644
> --- a/src/hotspot/share/prims/jvmtiExport.cpp
> +++ b/src/hotspot/share/prims/jvmtiExport.cpp
> @@ -1711,7 +1711,6 @@ void JvmtiExport::continuation_yield_cleanup(JavaThread* thread, jint continuati
>    if (state == nullptr) {
>      return;
>    }
> -  state->invalidate_cur_stack_depth();
>  
>    // Clear frame_pop requests in frames popped by yield
>    if (can_post_frame_pop()) {
> diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> index 0750f611876..f8406fb33c1 100644
> --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> @@ -1626,11 +1626,15 @@ static void invalidate_jvmti_stack(JavaThread* thread) {
>  }
>  
>  static void jvmti_yield_cleanup(JavaThread* thread, ContinuationWrapper& cont) {
> -  if (!cont.entry()->is_virtual_thread() && JvmtiExport::has_frame_pops(thread)) {
> +  if (cont.entry()->is_virtual_thread()) {
> +    return;
> +  }
> +  invalidate_jvmti_stack(thread);
> +  if (JvmtiExport::has_frame_pops(thread)) {
>      int num_frames = num_java_frames(cont);
>  
>      ContinuationWrapper::SafepointOp so(Thread::current(), cont);
> -    JvmtiExport::continuation_yield_cleanup(JavaThread::current(), num_frames);
> +    JvmtiExport::continuation_yield_cleanup(thread, num_frames);
>    }
>  }
>  
> @@ -1685,7 +1689,7 @@ static inline freeze_result freeze_epilog(ContinuationWrapper& cont) {
>  
>    log_develop_debug(continuations)("=== End of freeze cont ### #" INTPTR_FORMAT, cont.hash());
>  
> -  JVMTI_ONLY(invalidate_jvmti_stack(JavaThread::current()));
> +  JVMTI_ONLY(if (!cont.entry()->is_virtual_thread()) invalidate_jvmti_stack(JavaThread::current()));
>    return freeze_ok;
>  }
>  
> @@ -2311,7 +2315,7 @@ NOINLINE intptr_t* Thaw<ConfigT>::thaw_slow(stackChunkOop chunk, Continuation::t
>  
>    assert(_cont.chunk_invariant(), "");
>  
> -  JVMTI_ONLY(invalidate_jvmti_stack(_thread));
> +  JVMTI_ONLY(if (!_cont.entry()->is_virtual_thread()) invalidate_jvmti_stack(_thread));
>  
>    _thread->set_cont_fastpath(_fastpath);
>  ```

Ah, we need to call `invalidate_jvmti_stack` at the end in `jvmti_yield_cleanup`! The problem is that in `JvmtiExport::continuation_yield_cleanup` we are setting again the stack depth when calling `state->cur_stack_depth()`. We count the enterSpecial frame at the top but we don’t decrement the depth when removing it (done in assembly code).

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

PR Review Comment: https://git.openjdk.org/jdk/pull/27878#discussion_r2455332318


More information about the hotspot-runtime-dev mailing list