RFR: 8369609: Continuations preempt_epilog is missing a call to invalidate_jvmti_stack [v3]
Patricio Chilano Mateo
pchilanomate at openjdk.org
Thu Oct 23 18:02:27 UTC 2025
On Thu, 23 Oct 2025 17:32:51 GMT, Serguei Spitsyn <sspitsyn at openjdk.org> wrote:
>> Okay, thanks! Did you verify it with run of test `serviceability/jvmti/vthread/ContStackDepthTest`? I see it is still failing with the call to `invalidate_jvmti_stack()` at the end of `jvmti_yield_cleanup()`.
>
> This test does not fail with the following patch:
>
> diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> index 0750f611876..a12e99903af 100644
> --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
> @@ -1626,12 +1626,17 @@ 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);
> }
> + invalidate_jvmti_stack(thread);
> }
>
> static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, frame top) {
> @@ -1685,7 +1690,6 @@ 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()));
> 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);
>
>
> The call to `invalidate_jvmti_stack()` is still needed in the `thaw_slow()`.
> I can go ahead with this update if you are okay with it.
This is the patch I tested out with `serviceability/jvmti/vthread/ContStackDepthTest` (on top of mainline):
diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp
index 00a48dec111..181d77f4d10 100644
--- a/src/hotspot/share/prims/jvmtiThreadState.cpp
+++ b/src/hotspot/share/prims/jvmtiThreadState.cpp
@@ -678,6 +678,10 @@ void
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) {
JavaThread* thread = JavaThread::current();
assert(thread->is_in_VTMS_transition(), "sanity check");
+ JvmtiThreadState *state = thread->jvmti_thread_state();
+ if (state != nullptr) {
+ state->invalidate_cur_stack_depth();
+ }
finish_VTMS_transition(vthread, /* is_mount */ false);
}
diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
index 3e509e71551..a493fca076e 100644
--- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp
+++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp
@@ -1626,13 +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)) {
- int num_frames = num_java_frames(cont);
+ if (!cont.entry()->is_virtual_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);
+ ContinuationWrapper::SafepointOp so(Thread::current(), cont);
+ JvmtiExport::continuation_yield_cleanup(JavaThread::current(), num_frames);
+ }
+ invalidate_jvmti_stack(thread);
}
- invalidate_jvmti_stack(thread);
}
static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, frame top) {
Originally I had `invalidate_jvmti_stack()` before calling `JvmtiExport::continuation_yield_cleanup` so I could reproduce the issue.
I think you are right that for virtual threads we shouldn't need to invalidate the stack, so your patch is an improvement.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/27878#discussion_r2456495915
More information about the hotspot-runtime-dev
mailing list