8293613: need to properly handle and hide tmp VTMS transitions

Reviewed-by: cjplummer, lmesnik
This commit is contained in:
Serguei Spitsyn 2022-09-28 04:44:43 +00:00
parent 5e1e449c11
commit 79ccc791f2
10 changed files with 145 additions and 68 deletions

View File

@ -224,4 +224,5 @@ JVM_VirtualThreadMountBegin
JVM_VirtualThreadMountEnd JVM_VirtualThreadMountEnd
JVM_VirtualThreadUnmountBegin JVM_VirtualThreadUnmountBegin
JVM_VirtualThreadUnmountEnd JVM_VirtualThreadUnmountEnd
JVM_VirtualThreadHideFrames
# #

View File

@ -1150,6 +1150,9 @@ JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmoun
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount); JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount);
JNIEXPORT void JNICALL
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
/* /*
* Core reflection support. * Core reflection support.
*/ */

View File

@ -3882,6 +3882,8 @@ JVM_ENTRY(void, JVM_VirtualThreadMountBegin(JNIEnv* env, jobject vthread, jboole
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
return; 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); JvmtiVTMSTransitionDisabler::start_VTMS_transition(vthread, /* is_mount */ true);
#else #else
fatal("Should only be called with JVMTI enabled"); 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_VTMS_transition(), "sanity check");
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ true); JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ true);
if (first_mount) { if (first_mount) {
// thread start // 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"); assert(!thread->is_in_VTMS_transition(), "sanity check");
JvmtiVTMSTransitionDisabler::start_VTMS_transition(vthread, /* is_mount */ false); JvmtiVTMSTransitionDisabler::start_VTMS_transition(vthread, /* is_mount */ false);
@ -3977,12 +3980,27 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboole
return; return;
} }
assert(thread->is_in_VTMS_transition(), "sanity check"); 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); JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ false);
#else #else
fatal("Should only be called with JVMTI enabled"); fatal("Should only be called with JVMTI enabled");
#endif #endif
JVM_END 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 * 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 * returned jint contain the class's major version. The high order 16 bits

View File

@ -703,10 +703,14 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) {
javaVFrame* javaVFrame*
JvmtiEnvBase::get_cthread_last_java_vframe(JavaThread* jt, RegisterMap* reg_map_p) { JvmtiEnvBase::get_cthread_last_java_vframe(JavaThread* jt, RegisterMap* reg_map_p) {
// Strip vthread frames in case of carrier thread with mounted continuation. // Strip vthread frames in case of carrier thread with mounted continuation.
javaVFrame *jvf = JvmtiEnvBase::is_cthread_with_continuation(jt) ? bool cthread_with_cont = JvmtiEnvBase::is_cthread_with_continuation(jt);
jt->carrier_last_java_vframe(reg_map_p) : javaVFrame *jvf = cthread_with_cont ? jt->carrier_last_java_vframe(reg_map_p)
jt->last_java_vframe(reg_map_p); : jt->last_java_vframe(reg_map_p);
jvf = check_and_skip_hidden_frames(jt, jvf); // 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; return jvf;
} }

View File

@ -893,7 +893,7 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
_cached_class_file_ptr = cache_ptr; _cached_class_file_ptr = cache_ptr;
_has_been_modified = false; _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(); _state = _thread->jvmti_thread_state();
if (_state != NULL) { if (_state != NULL) {
_class_being_redefined = _state->get_class_being_redefined(); _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) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return false; 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, JvmtiClassFileLoadHookPoster poster(h_name, class_loader,
h_protection_domain, h_protection_domain,
@ -1184,8 +1187,8 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", 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) { if (state == NULL) {
return; 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", EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered",
JvmtiTrace::safe_get_thread_name(thread))); JvmtiTrace::safe_get_thread_name(thread)));
@ -1375,7 +1381,10 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) {
if (state == NULL) { if (state == NULL) {
return; 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", EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered",
JvmtiTrace::safe_get_thread_name(thread))); JvmtiTrace::safe_get_thread_name(thread)));
@ -1694,8 +1703,8 @@ void JvmtiExport::post_object_free(JvmtiEnv* env, GrowableArray<jlong>* objects)
assert(objects != NULL, "Nothing to post"); assert(objects != NULL, "Nothing to post");
JavaThread *javaThread = JavaThread::current(); JavaThread *javaThread = JavaThread::current();
if (javaThread->is_in_VTMS_transition()) { if (javaThread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) {
return; // the event type has been already disabled 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(); JavaThread *thread = JavaThread::current();
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
log_error(jvmti)("Posting Resource Exhausted event: %s", 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 // for any thread that actually wants method entry, interp_only_mode is set
return; return;
} }
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_ENTRY, ("[%s] Trg Method Entry triggered %s.%s",
JvmtiTrace::safe_get_thread_name(thread), JvmtiTrace::safe_get_thread_name(thread),
@ -1845,8 +1854,8 @@ void JvmtiExport::post_method_exit_inner(JavaThread* thread,
bool exception_exit, bool exception_exit,
frame current_frame, frame current_frame,
jvalue& value) { jvalue& value) {
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", 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) { if (state == NULL) {
return; return;
} }
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
JvmtiEnvThreadStateIterator it(state); JvmtiEnvThreadStateIterator it(state);
@ -1958,8 +1967,8 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", 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."); assert(!state->is_exception_caught(), "exception must not be caught yet.");
state->set_exception_caught(); state->set_exception_caught();
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) { if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
JvmtiEnvThreadStateIterator it(state); JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { 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. // 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"); assert(thread->has_last_Java_frame(), "must be called with a Java context");
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
ResourceMark rm; ResourceMark rm;
@ -2162,8 +2171,8 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method,
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", 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. // function don't make the call unless there is a Java context.
assert(thread->has_last_Java_frame(), "must be called with Java context"); assert(thread->has_last_Java_frame(), "must be called with Java context");
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
ResourceMark rm; 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, address location, Klass* field_klass, Handle object, jfieldID field,
char sig_type, jvalue *value) { char sig_type, jvalue *value) {
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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 || 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) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_MODIFICATION, 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); HandleMark hm(thread);
methodHandle mh(thread, method); methodHandle mh(thread, method);
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a 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", EVT_TRIG_TRACE(JVMTI_EVENT_NATIVE_METHOD_BIND, ("[%s] Trg Native Method Bind event triggered",
JvmtiTrace::safe_get_thread_name(thread))); JvmtiTrace::safe_get_thread_name(thread)));
@ -2431,7 +2440,7 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) {
} }
JavaThread* thread = JavaThread::current(); 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, EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
("[%s] method compile load event triggered", ("[%s] method compile load event triggered",
@ -2454,7 +2463,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) {
} }
JavaThread* thread = JavaThread::current(); 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, EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
("[%s] method compile load event sent %s.%s ", ("[%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(); 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 // In theory everyone coming thru here is in_vm but we need to be certain
// because a callee will do a vm->native transition // 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(); 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, EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
("[%s] dynamic code generated event triggered (by GenerateEvents)", ("[%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) address code_begin, address code_end)
{ {
JavaThread* thread = JavaThread::current(); 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 // register the stub with the current dynamic code event collector
// Cannot take safepoint here so do not use state_for to get // 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) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
@ -2714,8 +2723,8 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
@ -2748,8 +2757,8 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object,
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
@ -2782,8 +2791,8 @@ void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mnt
if (state == NULL) { if (state == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
@ -2814,8 +2823,8 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) {
if (object == NULL) { if (object == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
Handle h(thread, object); Handle h(thread, object);
@ -2848,8 +2857,8 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) {
if (object == NULL) { if (object == NULL) {
return; return;
} }
if (thread->is_in_VTMS_transition()) { if (thread->is_in_any_VTMS_transition()) {
return; // no events should be posted if thread is in a VTMS transition return; // no events should be posted if thread is in any VTMS transition
} }
HandleMark hm(thread); HandleMark hm(thread);
Handle h(thread, object); Handle h(thread, object);

View File

@ -269,6 +269,7 @@ JvmtiVTMSTransitionDisabler::disable_VTMS_transitions() {
ThreadBlockInVM tbivm(thread); ThreadBlockInVM tbivm(thread);
MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); 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"); assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check");
while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist.
ml.wait(10); // Wait while there is an active suspender or resumer. ml.wait(10); // Wait while there is an active suspender or resumer.

View File

@ -421,6 +421,7 @@ JavaThread::JavaThread() :
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
_carrier_thread_suspended(false), _carrier_thread_suspended(false),
_is_in_VTMS_transition(false), _is_in_VTMS_transition(false),
_is_in_tmp_VTMS_transition(false),
#ifdef ASSERT #ifdef ASSERT
_is_VTMS_transition_disabler(false), _is_VTMS_transition_disabler(false),
#endif #endif

View File

@ -310,6 +310,7 @@ class JavaThread: public Thread {
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended 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_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 #ifdef ASSERT
bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions
#endif #endif
@ -643,7 +644,12 @@ private:
} }
bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } 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 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 #ifdef ASSERT
bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; }
void set_is_VTMS_transition_disabler(bool val); void set_is_VTMS_transition_disabler(bool val);

View File

@ -354,6 +354,39 @@ final class VirtualThread extends BaseVirtualThread {
carrier.clearInterrupt(); 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 * Unmounts this virtual thread, invokes Continuation.yield, and re-mounts the
* thread when continued. When enabled, JVMTI must be notified from this method. * 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(); long startTime = System.nanoTime();
boolean yielded; boolean yielded;
Future<?> unparker = scheduleUnpark(nanos); Future<?> unparker = scheduleUnpark(this::unpark, nanos);
setState(PARKING); setState(PARKING);
try { try {
yielded = yieldContinuation(); 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 @ChangesCurrentThread
private Future<?> scheduleUnpark(long nanos) { private Future<?> scheduleUnpark(Runnable unparker, long nanos) {
Thread carrier = this.carrierThread; // need to switch to current carrier thread to avoid nested parking
// need to switch to current platform thread to avoid nested parking boolean notifyJvmti = switchToCarrierThread();
carrier.setCurrentThread(carrier);
try { try {
return UNPARKER.schedule(() -> unpark(), nanos, NANOSECONDS); return UNPARKER.schedule(unparker, nanos, NANOSECONDS);
} finally { } finally {
carrier.setCurrentThread(this); switchToVirtualThread(this, notifyJvmti);
} }
} }
@ -599,13 +631,12 @@ final class VirtualThread extends BaseVirtualThread {
@ChangesCurrentThread @ChangesCurrentThread
private void cancel(Future<?> future) { private void cancel(Future<?> future) {
if (!future.isDone()) { if (!future.isDone()) {
Thread carrier = this.carrierThread; // need to switch to current carrier thread to avoid nested parking
// need to switch to current platform thread to avoid nested parking boolean notifyJvmti = switchToCarrierThread();
carrier.setCurrentThread(carrier);
try { try {
future.cancel(false); future.cancel(false);
} finally { } finally {
carrier.setCurrentThread(this); switchToVirtualThread(this, notifyJvmti);
} }
} }
} }
@ -625,12 +656,11 @@ final class VirtualThread extends BaseVirtualThread {
int s = state(); int s = state();
if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) { if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) {
if (currentThread instanceof VirtualThread vthread) { if (currentThread instanceof VirtualThread vthread) {
Thread carrier = vthread.carrierThread; boolean notifyJvmti = vthread.switchToCarrierThread();
carrier.setCurrentThread(carrier);
try { try {
submitRunContinuation(); submitRunContinuation();
} finally { } finally {
carrier.setCurrentThread(vthread); switchToVirtualThread(vthread, notifyJvmti);
} }
} else { } else {
submitRunContinuation(); submitRunContinuation();
@ -1005,6 +1035,9 @@ final class VirtualThread extends BaseVirtualThread {
@JvmtiMountTransition @JvmtiMountTransition
private native void notifyJvmtiUnmountEnd(boolean lastUnmount); private native void notifyJvmtiUnmountEnd(boolean lastUnmount);
@JvmtiMountTransition
private native void notifyJvmtiHideFrames(boolean hide);
private static native void registerNatives(); private static native void registerNatives();
static { static {
registerNatives(); registerNatives();

View File

@ -36,6 +36,7 @@ static JNINativeMethod methods[] = {
{ "notifyJvmtiMountEnd", "(Z)V", (void *)&JVM_VirtualThreadMountEnd }, { "notifyJvmtiMountEnd", "(Z)V", (void *)&JVM_VirtualThreadMountEnd },
{ "notifyJvmtiUnmountBegin", "(Z)V", (void *)&JVM_VirtualThreadUnmountBegin }, { "notifyJvmtiUnmountBegin", "(Z)V", (void *)&JVM_VirtualThreadUnmountBegin },
{ "notifyJvmtiUnmountEnd", "(Z)V", (void *)&JVM_VirtualThreadUnmountEnd }, { "notifyJvmtiUnmountEnd", "(Z)V", (void *)&JVM_VirtualThreadUnmountEnd },
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
}; };
JNIEXPORT void JNICALL JNIEXPORT void JNICALL