diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index eba7a19226c..de2babed51a 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -224,4 +224,5 @@ JVM_VirtualThreadMountBegin JVM_VirtualThreadMountEnd JVM_VirtualThreadUnmountBegin JVM_VirtualThreadUnmountEnd +JVM_VirtualThreadHideFrames # diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 2f7b79cf34a..07dd0513b96 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1150,6 +1150,9 @@ JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmoun JNIEXPORT void JNICALL JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount); +JNIEXPORT void JNICALL +JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide); + /* * Core reflection support. */ diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 947e48c7492..aa8ddea3d25 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3882,6 +3882,8 @@ JVM_ENTRY(void, JVM_VirtualThreadMountBegin(JNIEnv* env, jobject vthread, jboole assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); return; } + assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); + assert(!thread->is_in_VTMS_transition(), "sanity check"); JvmtiVTMSTransitionDisabler::start_VTMS_transition(vthread, /* is_mount */ true); #else fatal("Should only be called with JVMTI enabled"); @@ -3906,6 +3908,7 @@ JVM_ENTRY(void, JVM_VirtualThreadMountEnd(JNIEnv* env, jobject vthread, jboolean } } assert(thread->is_in_VTMS_transition(), "sanity check"); + assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ true); if (first_mount) { // thread start @@ -3954,7 +3957,7 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboo } } } - + assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); assert(!thread->is_in_VTMS_transition(), "sanity check"); JvmtiVTMSTransitionDisabler::start_VTMS_transition(vthread, /* is_mount */ false); @@ -3977,12 +3980,27 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboole return; } assert(thread->is_in_VTMS_transition(), "sanity check"); + assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ false); #else fatal("Should only be called with JVMTI enabled"); #endif JVM_END +JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide)) +#if INCLUDE_JVMTI + if (!DoJVMTIVirtualThreadTransitions) { + assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); + return; + } + assert(!thread->is_in_VTMS_transition(), "sanity check"); + assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check"); + thread->toggle_is_in_tmp_VTMS_transition(); +#else + fatal("Should only be called with JVMTI enabled"); +#endif +JVM_END + /* * Return the current class's class file version. The low order 16 bits of the * returned jint contain the class's major version. The high order 16 bits diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 016a4e9e3fb..0b7b7c08ae6 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -703,10 +703,14 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) { javaVFrame* JvmtiEnvBase::get_cthread_last_java_vframe(JavaThread* jt, RegisterMap* reg_map_p) { // Strip vthread frames in case of carrier thread with mounted continuation. - javaVFrame *jvf = JvmtiEnvBase::is_cthread_with_continuation(jt) ? - jt->carrier_last_java_vframe(reg_map_p) : - jt->last_java_vframe(reg_map_p); - jvf = check_and_skip_hidden_frames(jt, jvf); + bool cthread_with_cont = JvmtiEnvBase::is_cthread_with_continuation(jt); + javaVFrame *jvf = cthread_with_cont ? jt->carrier_last_java_vframe(reg_map_p) + : jt->last_java_vframe(reg_map_p); + // Skip hidden frames only for carrier threads + // which are in non-temporary VTMS transition. + if (jt->is_in_VTMS_transition()) { + jvf = check_and_skip_hidden_frames(jt, jvf); + } return jvf; } diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index fd833b0ce5d..25b114a780e 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -893,7 +893,7 @@ class JvmtiClassFileLoadHookPoster : public StackObj { _cached_class_file_ptr = cache_ptr; _has_been_modified = false; - assert(!_thread->is_in_VTMS_transition(), "CFLH events are not allowed in VTMS transition"); + assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition"); _state = _thread->jvmti_thread_state(); if (_state != NULL) { _class_being_redefined = _state->get_class_being_redefined(); @@ -1050,6 +1050,9 @@ bool JvmtiExport::post_class_file_load_hook(Symbol* h_name, if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return false; } + if (JavaThread::current()->is_in_tmp_VTMS_transition()) { + return false; // skip CFLH events in tmp VTMS transition + } JvmtiClassFileLoadHookPoster poster(h_name, class_loader, h_protection_domain, @@ -1184,8 +1187,8 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_BREAKPOINT, ("[%s] Trg Breakpoint triggered", @@ -1340,7 +1343,10 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) { if (state == NULL) { return; } - assert(!thread->is_in_VTMS_transition(), "class load events are not allowed in VTMS transition"); + if (thread->is_in_tmp_VTMS_transition()) { + return; // skip ClassLoad events in tmp VTMS transition + } + assert(!thread->is_in_any_VTMS_transition(), "class load events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -1375,7 +1381,10 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) { if (state == NULL) { return; } - assert(!thread->is_in_VTMS_transition(), "class prepare events are not allowed in VTMS transition"); + if (thread->is_in_tmp_VTMS_transition()) { + return; // skip ClassPrepare events in tmp VTMS transition + } + assert(!thread->is_in_any_VTMS_transition(), "class prepare events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -1694,8 +1703,8 @@ void JvmtiExport::post_object_free(JvmtiEnv* env, GrowableArray* objects) assert(objects != NULL, "Nothing to post"); JavaThread *javaThread = JavaThread::current(); - if (javaThread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (javaThread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { return; // the event type has been already disabled @@ -1718,8 +1727,8 @@ void JvmtiExport::post_resource_exhausted(jint resource_exhausted_flags, const c JavaThread *thread = JavaThread::current(); - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } log_error(jvmti)("Posting Resource Exhausted event: %s", @@ -1761,8 +1770,8 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu // for any thread that actually wants method entry, interp_only_mode is set return; } - if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_ENTRY, ("[%s] Trg Method Entry triggered %s.%s", JvmtiTrace::safe_get_thread_name(thread), @@ -1845,8 +1854,8 @@ void JvmtiExport::post_method_exit_inner(JavaThread* thread, bool exception_exit, frame current_frame, jvalue& value) { - if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s", @@ -1921,8 +1930,8 @@ void JvmtiExport::post_single_step(JavaThread *thread, Method* method, address l if (state == NULL) { return; } - if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } JvmtiEnvThreadStateIterator it(state); @@ -1958,8 +1967,8 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_EXCEPTION, ("[%s] Trg Exception thrown triggered", @@ -2080,8 +2089,8 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met assert(!state->is_exception_caught(), "exception must not be caught yet."); state->set_exception_caught(); - if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { @@ -2126,8 +2135,8 @@ void JvmtiExport::post_field_access_by_jni(JavaThread *thread, oop obj, // function don't make the call unless there is a Java context. assert(thread->has_last_Java_frame(), "must be called with a Java context"); - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } ResourceMark rm; @@ -2162,8 +2171,8 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method, if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("[%s] Trg Field Access event triggered", @@ -2212,8 +2221,8 @@ void JvmtiExport::post_field_modification_by_jni(JavaThread *thread, oop obj, // function don't make the call unless there is a Java context. assert(thread->has_last_Java_frame(), "must be called with Java context"); - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } ResourceMark rm; @@ -2243,8 +2252,8 @@ void JvmtiExport::post_raw_field_modification(JavaThread *thread, Method* method address location, Klass* field_klass, Handle object, jfieldID field, char sig_type, jvalue *value) { - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } if (sig_type == JVM_SIGNATURE_INT || sig_type == JVM_SIGNATURE_BOOLEAN || @@ -2318,8 +2327,8 @@ void JvmtiExport::post_field_modification(JavaThread *thread, Method* method, if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_MODIFICATION, @@ -2357,8 +2366,8 @@ void JvmtiExport::post_native_method_bind(Method* method, address* function_ptr) HandleMark hm(thread); methodHandle mh(thread, method); - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } EVT_TRIG_TRACE(JVMTI_EVENT_NATIVE_METHOD_BIND, ("[%s] Trg Native Method Bind event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2431,7 +2440,7 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) { } JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition"); + assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("[%s] method compile load event triggered", @@ -2454,7 +2463,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) { } JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition"); + assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition"); EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("[%s] method compile load event sent %s.%s ", @@ -2479,7 +2488,7 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition"); + assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition"); // In theory everyone coming thru here is in_vm but we need to be certain // because a callee will do a vm->native transition @@ -2527,7 +2536,7 @@ void JvmtiExport::post_dynamic_code_generated(JvmtiEnv* env, const char *name, { JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition"); + assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED, ("[%s] dynamic code generated event triggered (by GenerateEvents)", @@ -2551,7 +2560,7 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na address code_begin, address code_end) { JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition"); + assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition"); // register the stub with the current dynamic code event collector // Cannot take safepoint here so do not use state_for to get @@ -2681,8 +2690,8 @@ void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); @@ -2714,8 +2723,8 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); @@ -2748,8 +2757,8 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object, if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); @@ -2782,8 +2791,8 @@ void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mnt if (state == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); @@ -2814,8 +2823,8 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { if (object == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); Handle h(thread, object); @@ -2848,8 +2857,8 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) { if (object == NULL) { return; } - if (thread->is_in_VTMS_transition()) { - return; // no events should be posted if thread is in a VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } HandleMark hm(thread); Handle h(thread, object); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 0082591a40c..1a5f320cd63 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -269,6 +269,7 @@ JvmtiVTMSTransitionDisabler::disable_VTMS_transitions() { ThreadBlockInVM tbivm(thread); MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); + assert(!thread->is_in_tmp_VTMS_transition(), "sanity check"); assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. ml.wait(10); // Wait while there is an active suspender or resumer. diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index fc1139f27e4..d2d637d1451 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -421,6 +421,7 @@ JavaThread::JavaThread() : #if INCLUDE_JVMTI _carrier_thread_suspended(false), _is_in_VTMS_transition(false), + _is_in_tmp_VTMS_transition(false), #ifdef ASSERT _is_VTMS_transition_disabler(false), #endif diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 6d09c3f2ce3..592f05818de 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -310,6 +310,7 @@ class JavaThread: public Thread { #if INCLUDE_JVMTI volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition + bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition #ifdef ASSERT bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions #endif @@ -643,7 +644,12 @@ private: } bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } + bool is_in_tmp_VTMS_transition() const { return _is_in_tmp_VTMS_transition; } + bool is_in_any_VTMS_transition() const { return _is_in_VTMS_transition || _is_in_tmp_VTMS_transition; } + void set_is_in_VTMS_transition(bool val); + void toggle_is_in_tmp_VTMS_transition() { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; }; + #ifdef ASSERT bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } void set_is_VTMS_transition_disabler(bool val); diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index ed6405c3e20..704910c3c36 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -354,6 +354,39 @@ final class VirtualThread extends BaseVirtualThread { carrier.clearInterrupt(); } + /** + * Sets the current thread to the current carrier thread. + * @return true if JVMTI was notified + */ + @ChangesCurrentThread + @JvmtiMountTransition + private boolean switchToCarrierThread() { + boolean notifyJvmti = notifyJvmtiEvents; + if (notifyJvmti) { + notifyJvmtiHideFrames(true); + } + Thread carrier = this.carrierThread; + assert Thread.currentThread() == this + && carrier == Thread.currentCarrierThread(); + carrier.setCurrentThread(carrier); + return notifyJvmti; + } + + /** + * Sets the current thread to the given virtual thread. + * If {@code notifyJvmti} is true then JVMTI is notified. + */ + @ChangesCurrentThread + @JvmtiMountTransition + private void switchToVirtualThread(VirtualThread vthread, boolean notifyJvmti) { + Thread carrier = vthread.carrierThread; + assert carrier == Thread.currentCarrierThread(); + carrier.setCurrentThread(vthread); + if (notifyJvmti) { + notifyJvmtiHideFrames(false); + } + } + /** * Unmounts this virtual thread, invokes Continuation.yield, and re-mounts the * thread when continued. When enabled, JVMTI must be notified from this method. @@ -526,7 +559,7 @@ final class VirtualThread extends BaseVirtualThread { long startTime = System.nanoTime(); boolean yielded; - Future unparker = scheduleUnpark(nanos); + Future unparker = scheduleUnpark(this::unpark, nanos); setState(PARKING); try { yielded = yieldContinuation(); @@ -579,17 +612,16 @@ final class VirtualThread extends BaseVirtualThread { } /** - * Schedules this thread to be unparked after the given delay. + * Schedule an unpark task to run after a given delay. */ @ChangesCurrentThread - private Future scheduleUnpark(long nanos) { - Thread carrier = this.carrierThread; - // need to switch to current platform thread to avoid nested parking - carrier.setCurrentThread(carrier); + private Future scheduleUnpark(Runnable unparker, long nanos) { + // need to switch to current carrier thread to avoid nested parking + boolean notifyJvmti = switchToCarrierThread(); try { - return UNPARKER.schedule(() -> unpark(), nanos, NANOSECONDS); + return UNPARKER.schedule(unparker, nanos, NANOSECONDS); } finally { - carrier.setCurrentThread(this); + switchToVirtualThread(this, notifyJvmti); } } @@ -599,13 +631,12 @@ final class VirtualThread extends BaseVirtualThread { @ChangesCurrentThread private void cancel(Future future) { if (!future.isDone()) { - Thread carrier = this.carrierThread; - // need to switch to current platform thread to avoid nested parking - carrier.setCurrentThread(carrier); + // need to switch to current carrier thread to avoid nested parking + boolean notifyJvmti = switchToCarrierThread(); try { future.cancel(false); } finally { - carrier.setCurrentThread(this); + switchToVirtualThread(this, notifyJvmti); } } } @@ -625,12 +656,11 @@ final class VirtualThread extends BaseVirtualThread { int s = state(); if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) { if (currentThread instanceof VirtualThread vthread) { - Thread carrier = vthread.carrierThread; - carrier.setCurrentThread(carrier); + boolean notifyJvmti = vthread.switchToCarrierThread(); try { submitRunContinuation(); } finally { - carrier.setCurrentThread(vthread); + switchToVirtualThread(vthread, notifyJvmti); } } else { submitRunContinuation(); @@ -1005,6 +1035,9 @@ final class VirtualThread extends BaseVirtualThread { @JvmtiMountTransition private native void notifyJvmtiUnmountEnd(boolean lastUnmount); + @JvmtiMountTransition + private native void notifyJvmtiHideFrames(boolean hide); + private static native void registerNatives(); static { registerNatives(); diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index d2574c79dd8..1736a829da4 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -36,6 +36,7 @@ static JNINativeMethod methods[] = { { "notifyJvmtiMountEnd", "(Z)V", (void *)&JVM_VirtualThreadMountEnd }, { "notifyJvmtiUnmountBegin", "(Z)V", (void *)&JVM_VirtualThreadUnmountBegin }, { "notifyJvmtiUnmountEnd", "(Z)V", (void *)&JVM_VirtualThreadUnmountEnd }, + { "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames }, }; JNIEXPORT void JNICALL