diff --git a/src/hotspot/share/prims/jvmti.xml b/src/hotspot/share/prims/jvmti.xml index e8e127486ca..b63dfdfedb1 100644 --- a/src/hotspot/share/prims/jvmti.xml +++ b/src/hotspot/share/prims/jvmti.xml @@ -3084,6 +3084,9 @@ err = (*jvmti)->Deallocate(jvmti, stack_info); Thread was not suspended and was not the current thread. + + There is already a frame pop event request at the specified depth. + diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index debfc77c32c..ec269e60e1b 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1359,7 +1359,11 @@ JvmtiEnvBase::set_frame_pop(JvmtiThreadState* state, javaVFrame* jvf, jint depth } assert(jvf->frame_pointer() != nullptr, "frame pointer mustn't be null"); int frame_number = (int)get_frame_count(jvf); - state->env_thread_state((JvmtiEnvBase*)this)->set_frame_pop(frame_number); + JvmtiEnvThreadState* ets = state->env_thread_state(this); + if (ets->is_frame_pop(frame_number)) { + return JVMTI_ERROR_DUPLICATE; + } + ets->set_frame_pop(frame_number); return JVMTI_ERROR_NONE; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/MethodExitTest/libMethodExitTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/MethodExitTest/libMethodExitTest.cpp index b7077b10c81..f5e2b267a9f 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/MethodExitTest/libMethodExitTest.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/MethodExitTest/libMethodExitTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -452,13 +452,25 @@ VirtualThreadMount(jvmtiEnv *jvmti, ...) { mname = get_method_name(jvmti, jni, method); cname = get_method_class_name(jvmti, jni, method); + print_frame_event_info(jvmti, jni, thread, method, "VirtualThreadMount", ++vthread_mounted_count); + LOG("\nHit #%d: VirtualThreadMount #%d: enabling FramePop for method: %s::%s on virtual thread: %p\n", - brkptBreakpointHit, ++vthread_mounted_count, cname, mname, (void*)thread); + brkptBreakpointHit, vthread_mounted_count, cname, mname, (void*)thread); err = jvmti->NotifyFramePop(thread, 0); check_jvmti_status(jni, err, "VirtualThreadMount: error in JVMTI NotifyFramePop"); - print_frame_event_info(jvmti, jni, thread, method, "VirtualThreadMount", vthread_mounted_count); + LOG("\nHit #%d: VirtualThreadMount #%d: enabling duplicated FramePop for method: %s::%s on virtual thread: %p\n", + brkptBreakpointHit, vthread_mounted_count, cname, mname, (void*)thread); + + err = jvmti->NotifyFramePop(thread, 0); + if (err == JVMTI_ERROR_DUPLICATE) { + LOG("NotifyFramePop at VirtualThreadUnmount event returned expected JVMTI_ERROR_DUPLICATE\n"); + } else { + LOG("Failed: NotifyFramePop at VirtualThreadUnmount returned %s(%d) instead of expected JVMTI_ERROR_DUPLICATE\n", + TranslateError(err), err); + jni->FatalError("NotifyFramePop error: expected error code JVMTI_ERROR_DUPLICATE"); + } // Test SetThreadLocalStorage for virtual thread. err = jvmti->SetThreadLocalStorage(thread, tls_data2); @@ -497,13 +509,7 @@ VirtualThreadUnmount(jvmtiEnv *jvmti, ...) { mname = get_method_name(jvmti, jni, method); cname = get_method_class_name(jvmti, jni, method); - LOG("\nHit #%d: VirtualThreadUnmount #%d: enabling FramePop for method: %s::%s on virtual thread: %p\n", - brkptBreakpointHit, ++vthread_unmounted_count, cname, mname, (void*)thread); - - err = jvmti->NotifyFramePop(thread, 0); - check_jvmti_status(jni, err, "VirtualThreadUnmount: error in JVMTI NotifyFramePop"); - - print_frame_event_info(jvmti, jni, thread, method, "VirtualThreadUnmount", vthread_unmounted_count); + print_frame_event_info(jvmti, jni, thread, method, "VirtualThreadUnmount", ++vthread_unmounted_count); deallocate(jvmti, jni, (void*)mname); deallocate(jvmti, jni, (void*)cname);