8304303: implement VirtualThread class notifyJvmti methods as C2 intrinsics
Reviewed-by: vlivanov, lmesnik
This commit is contained in:
parent
2d0d057d66
commit
bc0ed730f2
@ -218,10 +218,8 @@ JVM_DefineModule
|
||||
JVM_SetBootLoaderUnnamedModule
|
||||
|
||||
# Virtual thread notifications for JVMTI
|
||||
JVM_VirtualThreadMountBegin
|
||||
JVM_VirtualThreadMountEnd
|
||||
JVM_VirtualThreadUnmountBegin
|
||||
JVM_VirtualThreadUnmountEnd
|
||||
JVM_VirtualThreadMount
|
||||
JVM_VirtualThreadUnmount
|
||||
JVM_VirtualThreadHideFrames
|
||||
|
||||
# Scoped values
|
||||
|
@ -1933,34 +1933,23 @@ void java_lang_ThreadGroup::serialize_offsets(SerializeClosure* f) {
|
||||
|
||||
// java_lang_VirtualThread
|
||||
|
||||
int java_lang_VirtualThread::static_notify_jvmti_events_offset;
|
||||
int java_lang_VirtualThread::static_vthread_scope_offset;
|
||||
int java_lang_VirtualThread::_carrierThread_offset;
|
||||
int java_lang_VirtualThread::_continuation_offset;
|
||||
int java_lang_VirtualThread::_state_offset;
|
||||
|
||||
#define VTHREAD_FIELDS_DO(macro) \
|
||||
macro(static_notify_jvmti_events_offset, k, "notifyJvmtiEvents", bool_signature, true); \
|
||||
macro(static_vthread_scope_offset, k, "VTHREAD_SCOPE", continuationscope_signature, true); \
|
||||
macro(_carrierThread_offset, k, "carrierThread", thread_signature, false); \
|
||||
macro(_continuation_offset, k, "cont", continuation_signature, false); \
|
||||
macro(_state_offset, k, "state", int_signature, false)
|
||||
|
||||
static bool vthread_notify_jvmti_events = JNI_FALSE;
|
||||
|
||||
void java_lang_VirtualThread::compute_offsets() {
|
||||
InstanceKlass* k = vmClasses::VirtualThread_klass();
|
||||
VTHREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
void java_lang_VirtualThread::init_static_notify_jvmti_events() {
|
||||
if (vthread_notify_jvmti_events) {
|
||||
InstanceKlass* ik = vmClasses::VirtualThread_klass();
|
||||
oop base = ik->static_field_base_raw();
|
||||
base->release_bool_field_put(static_notify_jvmti_events_offset, vthread_notify_jvmti_events);
|
||||
}
|
||||
}
|
||||
|
||||
bool java_lang_VirtualThread::is_instance(oop obj) {
|
||||
return obj != nullptr && is_subclass(obj->klass());
|
||||
}
|
||||
@ -2013,15 +2002,6 @@ void java_lang_VirtualThread::serialize_offsets(SerializeClosure* f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool java_lang_VirtualThread::notify_jvmti_events() {
|
||||
return vthread_notify_jvmti_events == JNI_TRUE;
|
||||
}
|
||||
|
||||
void java_lang_VirtualThread::set_notify_jvmti_events(bool enable) {
|
||||
vthread_notify_jvmti_events = enable;
|
||||
}
|
||||
|
||||
|
||||
// java_lang_Throwable
|
||||
|
||||
int java_lang_Throwable::_backtrace_offset;
|
||||
@ -5387,6 +5367,5 @@ int InjectedField::compute_offset() {
|
||||
void javaClasses_init() {
|
||||
JavaClasses::compute_offsets();
|
||||
JavaClasses::check_offsets();
|
||||
java_lang_VirtualThread::init_static_notify_jvmti_events();
|
||||
FilteredFieldsMap::initialize(); // must be done after computing offsets.
|
||||
}
|
||||
|
@ -510,7 +510,6 @@ class java_lang_ThreadGroup : AllStatic {
|
||||
|
||||
class java_lang_VirtualThread : AllStatic {
|
||||
private:
|
||||
static int static_notify_jvmti_events_offset;
|
||||
static int static_vthread_scope_offset;
|
||||
static int _carrierThread_offset;
|
||||
static int _continuation_offset;
|
||||
@ -548,9 +547,6 @@ class java_lang_VirtualThread : AllStatic {
|
||||
static oop continuation(oop vthread);
|
||||
static int state(oop vthread);
|
||||
static JavaThreadStatus map_state_to_thread_status(int state);
|
||||
static bool notify_jvmti_events();
|
||||
static void set_notify_jvmti_events(bool enable);
|
||||
static void init_static_notify_jvmti_events();
|
||||
};
|
||||
|
||||
|
||||
|
@ -583,6 +583,11 @@ class methodHandle;
|
||||
do_intrinsic(_Continuation_doYield, jdk_internal_vm_Continuation, doYield_name, continuationDoYield_signature, F_SN) \
|
||||
do_alias( continuationDoYield_signature, void_int_signature) \
|
||||
\
|
||||
/* java/lang/VirtualThread */ \
|
||||
do_intrinsic(_notifyJvmtiMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_bool_void_signature, F_RN) \
|
||||
do_intrinsic(_notifyJvmtiUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_bool_void_signature, F_RN) \
|
||||
do_intrinsic(_notifyJvmtiHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \
|
||||
\
|
||||
/* support for UnsafeConstants */ \
|
||||
do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \
|
||||
\
|
||||
|
@ -412,6 +412,9 @@
|
||||
template(run_finalization_name, "runFinalization") \
|
||||
template(dispatchUncaughtException_name, "dispatchUncaughtException") \
|
||||
template(loadClass_name, "loadClass") \
|
||||
template(notifyJvmtiMount_name, "notifyJvmtiMount") \
|
||||
template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \
|
||||
template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \
|
||||
template(doYield_name, "doYield") \
|
||||
template(enter_name, "enter") \
|
||||
template(enterSpecial_name, "enterSpecial") \
|
||||
@ -550,6 +553,7 @@
|
||||
template(void_float_signature, "()F") \
|
||||
template(void_double_signature, "()D") \
|
||||
template(bool_void_signature, "(Z)V") \
|
||||
template(bool_bool_void_signature, "(ZZ)V") \
|
||||
template(int_void_signature, "(I)V") \
|
||||
template(int_int_signature, "(I)I") \
|
||||
template(char_char_signature, "(C)C") \
|
||||
|
@ -1144,16 +1144,10 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass);
|
||||
* Virtual thread support.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadMountBegin(JNIEnv* env, jobject vthread, jboolean first_mount);
|
||||
JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide, jboolean first_mount);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadMountEnd(JNIEnv* env, jobject vthread, jboolean first_mount);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmount);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount);
|
||||
JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide, jboolean last_unmount);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
|
||||
|
@ -771,6 +771,11 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method) {
|
||||
case vmIntrinsics::_IndexPartiallyInUpperRange:
|
||||
return EnableVectorSupport;
|
||||
case vmIntrinsics::_blackhole:
|
||||
#if INCLUDE_JVMTI
|
||||
case vmIntrinsics::_notifyJvmtiMount:
|
||||
case vmIntrinsics::_notifyJvmtiUnmount:
|
||||
case vmIntrinsics::_notifyJvmtiHideFrames:
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "opto/runtime.hpp"
|
||||
#include "opto/rootnode.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "prims/unsafe.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/objectMonitor.hpp"
|
||||
@ -478,6 +479,14 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_scopedValueCache: return inline_native_scopedValueCache();
|
||||
case vmIntrinsics::_setScopedValueCache: return inline_native_setScopedValueCache();
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
case vmIntrinsics::_notifyJvmtiMount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_mount()),
|
||||
"notifyJvmtiMount");
|
||||
case vmIntrinsics::_notifyJvmtiUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_unmount()),
|
||||
"notifyJvmtiUnmount");
|
||||
case vmIntrinsics::_notifyJvmtiHideFrames: return inline_native_notify_jvmti_hide();
|
||||
#endif
|
||||
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, JfrTime::time_function()), "counterTime");
|
||||
case vmIntrinsics::_getEventWriter: return inline_native_getEventWriter();
|
||||
@ -2841,6 +2850,75 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
|
||||
// When notifications are disabled then just update the VTMS transition bit and return.
|
||||
// Otherwise, the bit is updated in the given function call implementing JVMTI notification protocol.
|
||||
bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName) {
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
return true;
|
||||
}
|
||||
IdealKit ideal(this);
|
||||
|
||||
Node* ONE = ideal.ConI(1);
|
||||
Node* hide = _gvn.transform(argument(1)); // hide argument: true for begin and false for end of VTMS transition
|
||||
Node* addr = makecon(TypeRawPtr::make((address)&JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events));
|
||||
Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw);
|
||||
|
||||
ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); {
|
||||
// if notifyJvmti enabled then make a call to the given SharedRuntime function
|
||||
const TypeFunc* tf = OptoRuntime::notify_jvmti_Type();
|
||||
Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument
|
||||
Node* cond = _gvn.transform(argument(2)); // firstMount or lastUnmount argument
|
||||
|
||||
sync_kit(ideal);
|
||||
make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide, cond);
|
||||
ideal.sync_kit(this);
|
||||
} ideal.else_(); {
|
||||
// set hide value to the VTMS transition bit in current JavaThread
|
||||
Node* thread = ideal.thread();
|
||||
Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset()));
|
||||
const TypePtr *addr_type = _gvn.type(addr)->isa_ptr();
|
||||
|
||||
sync_kit(ideal);
|
||||
access_store_at(nullptr, addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
|
||||
ideal.sync_kit(this);
|
||||
} ideal.end_if();
|
||||
final_sync(ideal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If notifications are enabled then just update the temporary VTMS transition bit.
|
||||
bool LibraryCallKit::inline_native_notify_jvmti_hide() {
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
return true;
|
||||
}
|
||||
IdealKit ideal(this);
|
||||
|
||||
Node* ONE = ideal.ConI(1);
|
||||
Node* addr = makecon(TypeRawPtr::make((address)&JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events));
|
||||
Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw);
|
||||
|
||||
ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); {
|
||||
// set the VTMS temporary transition bit in current JavaThread
|
||||
Node* thread = ideal.thread();
|
||||
Node* hide = _gvn.transform(argument(1)); // hide argument for temporary VTMS transition notification
|
||||
Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_tmp_VTMS_transition_offset()));
|
||||
const TypePtr *addr_type = _gvn.type(addr)->isa_ptr();
|
||||
|
||||
sync_kit(ideal);
|
||||
access_store_at(nullptr, addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
|
||||
ideal.sync_kit(this);
|
||||
} ideal.end_if();
|
||||
final_sync(ideal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
|
||||
/**
|
||||
|
@ -245,6 +245,11 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_native_setScopedValueCache();
|
||||
|
||||
bool inline_native_time_funcs(address method, const char* funcName);
|
||||
#if INCLUDE_JVMTI
|
||||
bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName);
|
||||
bool inline_native_notify_jvmti_hide();
|
||||
#endif
|
||||
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
bool inline_native_classID();
|
||||
bool inline_native_getEventWriter();
|
||||
|
@ -109,6 +109,10 @@ address OptoRuntime::_rethrow_Java = nullptr;
|
||||
|
||||
address OptoRuntime::_slow_arraycopy_Java = nullptr;
|
||||
address OptoRuntime::_register_finalizer_Java = nullptr;
|
||||
#if INCLUDE_JVMTI
|
||||
address OptoRuntime::_notify_jvmti_mount = nullptr;
|
||||
address OptoRuntime::_notify_jvmti_unmount = nullptr;
|
||||
#endif
|
||||
|
||||
ExceptionBlob* OptoRuntime::_exception_blob;
|
||||
|
||||
@ -148,6 +152,10 @@ bool OptoRuntime::generate(ciEnv* env) {
|
||||
gen(env, _multianewarray4_Java , multianewarray4_Type , multianewarray4_C , 0 , true, false);
|
||||
gen(env, _multianewarray5_Java , multianewarray5_Type , multianewarray5_C , 0 , true, false);
|
||||
gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true, false);
|
||||
#if INCLUDE_JVMTI
|
||||
gen(env, _notify_jvmti_mount , notify_jvmti_Type , SharedRuntime::notify_jvmti_mount, 0 , true, false);
|
||||
gen(env, _notify_jvmti_unmount , notify_jvmti_Type , SharedRuntime::notify_jvmti_unmount, 0 , true, false);
|
||||
#endif
|
||||
gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C, 0, false, false);
|
||||
gen(env, _monitor_notify_Java , monitor_notify_Type , monitor_notify_C , 0 , false, false);
|
||||
gen(env, _monitor_notifyAll_Java , monitor_notify_Type , monitor_notifyAll_C , 0 , false, false);
|
||||
@ -1644,6 +1652,24 @@ const TypeFunc *OptoRuntime::class_id_load_barrier_Type() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
const TypeFunc *OptoRuntime::notify_jvmti_Type() {
|
||||
// create input type (domain)
|
||||
const Type **fields = TypeTuple::fields(3);
|
||||
fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // VirtualThread oop
|
||||
fields[TypeFunc::Parms+1] = TypeInt::BOOL; // jboolean
|
||||
fields[TypeFunc::Parms+2] = TypeInt::BOOL; // jboolean
|
||||
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+3,fields);
|
||||
|
||||
// no result type needed
|
||||
fields = TypeTuple::fields(1);
|
||||
fields[TypeFunc::Parms+0] = NULL; // void
|
||||
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
|
||||
|
||||
return TypeFunc::make(domain,range);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Dtrace support. entry and exit probes have the same signature
|
||||
const TypeFunc *OptoRuntime::dtrace_method_entry_exit_Type() {
|
||||
|
@ -135,6 +135,10 @@ class OptoRuntime : public AllStatic {
|
||||
|
||||
static address _slow_arraycopy_Java;
|
||||
static address _register_finalizer_Java;
|
||||
#if INCLUDE_JVMTI
|
||||
static address _notify_jvmti_mount;
|
||||
static address _notify_jvmti_unmount;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Implementation of runtime methods
|
||||
@ -208,6 +212,10 @@ private:
|
||||
|
||||
static address slow_arraycopy_Java() { return _slow_arraycopy_Java; }
|
||||
static address register_finalizer_Java() { return _register_finalizer_Java; }
|
||||
#if INCLUDE_JVMTI
|
||||
static address notify_jvmti_mount() { return _notify_jvmti_mount; }
|
||||
static address notify_jvmti_unmount() { return _notify_jvmti_unmount; }
|
||||
#endif
|
||||
|
||||
static ExceptionBlob* exception_blob() { return _exception_blob; }
|
||||
|
||||
@ -294,6 +302,9 @@ private:
|
||||
static const TypeFunc* register_finalizer_Type();
|
||||
|
||||
JFR_ONLY(static const TypeFunc* class_id_load_barrier_Type();)
|
||||
#if INCLUDE_JVMTI
|
||||
static const TypeFunc* notify_jvmti_Type();
|
||||
#endif
|
||||
|
||||
// Dtrace support
|
||||
static const TypeFunc* dtrace_method_entry_exit_Type();
|
||||
|
@ -3917,123 +3917,60 @@ JVM_LEAF(jint, JVM_FindSignal(const char *name))
|
||||
return os::get_signal_number(name);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_VirtualThreadMountBegin(JNIEnv* env, jobject vthread, jboolean first_mount))
|
||||
// If notifications are disabled then just update the VTMS transition bit and return.
|
||||
// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call.
|
||||
JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide, jboolean first_mount))
|
||||
#if INCLUDE_JVMTI
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
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");
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_VirtualThreadMountEnd(JNIEnv* env, jobject vthread, jboolean first_mount))
|
||||
#if INCLUDE_JVMTI
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||
thread->set_is_in_VTMS_transition(hide);
|
||||
return;
|
||||
}
|
||||
oop vt = JNIHandles::resolve(vthread);
|
||||
|
||||
thread->rebind_to_jvmti_thread_state_of(vt);
|
||||
|
||||
{
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
JvmtiThreadState* state = thread->jvmti_thread_state();
|
||||
if (state != nullptr && state->is_pending_interp_only_mode()) {
|
||||
JvmtiEventController::enter_interp_only_mode();
|
||||
}
|
||||
}
|
||||
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
|
||||
if (JvmtiExport::can_support_virtual_threads()) {
|
||||
JvmtiEventController::thread_started(thread);
|
||||
if (JvmtiExport::should_post_vthread_start()) {
|
||||
JvmtiExport::post_vthread_start(vthread);
|
||||
}
|
||||
} else { // compatibility for vthread unaware agents: legacy thread_start
|
||||
if (PostVirtualThreadCompatibleLifecycleEvents &&
|
||||
JvmtiExport::should_post_thread_life()) {
|
||||
// JvmtiEventController::thread_started is called here
|
||||
JvmtiExport::post_thread_start(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (JvmtiExport::should_post_vthread_mount()) {
|
||||
JvmtiExport::post_vthread_mount(vthread);
|
||||
if (hide) {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(vthread, first_mount);
|
||||
} else {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_end(vthread, first_mount);
|
||||
}
|
||||
#else
|
||||
fatal("Should only be called with JVMTI enabled");
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmount))
|
||||
// If notifications are disabled then just update the VTMS transition bit and return.
|
||||
// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call below.
|
||||
JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide, jboolean last_unmount))
|
||||
#if INCLUDE_JVMTI
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||
return;
|
||||
}
|
||||
HandleMark hm(thread);
|
||||
Handle ct(thread, thread->threadObj());
|
||||
|
||||
if (JvmtiExport::should_post_vthread_unmount()) {
|
||||
JvmtiExport::post_vthread_unmount(vthread);
|
||||
}
|
||||
if (last_unmount) {
|
||||
if (JvmtiExport::can_support_virtual_threads()) {
|
||||
if (JvmtiExport::should_post_vthread_end()) {
|
||||
JvmtiExport::post_vthread_end(vthread);
|
||||
}
|
||||
} else { // compatibility for vthread unaware agents: legacy thread_end
|
||||
if (PostVirtualThreadCompatibleLifecycleEvents &&
|
||||
JvmtiExport::should_post_thread_life()) {
|
||||
JvmtiExport::post_thread_end(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
if (last_unmount && thread->jvmti_thread_state() != nullptr) {
|
||||
JvmtiExport::cleanup_thread(thread);
|
||||
thread->set_jvmti_thread_state(nullptr);
|
||||
oop vt = JNIHandles::resolve(vthread);
|
||||
java_lang_Thread::set_jvmti_thread_state(vt, nullptr);
|
||||
}
|
||||
thread->rebind_to_jvmti_thread_state_of(ct());
|
||||
#else
|
||||
fatal("Should only be called with JVMTI enabled");
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(void, JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount))
|
||||
#if INCLUDE_JVMTI
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||
thread->set_is_in_VTMS_transition(hide);
|
||||
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);
|
||||
if (hide) {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(vthread, last_unmount);
|
||||
} else {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(vthread, last_unmount);
|
||||
}
|
||||
#else
|
||||
fatal("Should only be called with JVMTI enabled");
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
// If notifications are enabled then just update the temporary VTMS transition bit.
|
||||
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;
|
||||
}
|
||||
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||
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();
|
||||
|
@ -379,11 +379,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
|
||||
}
|
||||
if (Continuations::enabled()) {
|
||||
// Virtual threads support. There is a performance impact when VTMS transitions are enabled.
|
||||
java_lang_VirtualThread::set_notify_jvmti_events(true);
|
||||
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
|
||||
ThreadInVMfromNative __tiv(JavaThread::current());
|
||||
java_lang_VirtualThread::init_static_notify_jvmti_events();
|
||||
}
|
||||
JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(true);
|
||||
}
|
||||
|
||||
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "runtime/stackFrameStream.inline.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
@ -219,12 +219,14 @@ volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_count = 0;
|
||||
// VTMS transitions for one virtual thread are disabled while it is positive
|
||||
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0;
|
||||
|
||||
// VTMs transitions for all virtual threads are disabled while it is positive
|
||||
// VTMS transitions for all virtual threads are disabled while it is positive
|
||||
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0;
|
||||
|
||||
// There is an active suspender or resumer.
|
||||
volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false;
|
||||
|
||||
// Notifications from VirtualThread about VTMS events are enabled.
|
||||
bool JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events = false;
|
||||
|
||||
#ifdef ASSERT
|
||||
void
|
||||
@ -509,6 +511,94 @@ JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mou
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread, jboolean first_mount) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
start_VTMS_transition(vthread, /* is_mount */ true);
|
||||
}
|
||||
|
||||
void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread, jboolean first_mount) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
oop vt = JNIHandles::resolve(vthread);
|
||||
|
||||
thread->rebind_to_jvmti_thread_state_of(vt);
|
||||
|
||||
{
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
JvmtiThreadState* state = thread->jvmti_thread_state();
|
||||
if (state != nullptr && state->is_pending_interp_only_mode()) {
|
||||
JvmtiEventController::enter_interp_only_mode();
|
||||
}
|
||||
}
|
||||
assert(thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
finish_VTMS_transition(vthread, /* is_mount */ true);
|
||||
if (first_mount) {
|
||||
// thread start
|
||||
if (JvmtiExport::can_support_virtual_threads()) {
|
||||
JvmtiEventController::thread_started(thread);
|
||||
if (JvmtiExport::should_post_vthread_start()) {
|
||||
JvmtiExport::post_vthread_start(vthread);
|
||||
}
|
||||
} else { // compatibility for vthread unaware agents: legacy thread_start
|
||||
if (PostVirtualThreadCompatibleLifecycleEvents &&
|
||||
JvmtiExport::should_post_thread_life()) {
|
||||
// JvmtiEventController::thread_started is called here
|
||||
JvmtiExport::post_thread_start(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (JvmtiExport::should_post_vthread_mount()) {
|
||||
JvmtiExport::post_vthread_mount(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, jboolean last_unmount) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
HandleMark hm(thread);
|
||||
Handle ct(thread, thread->threadObj());
|
||||
|
||||
if (JvmtiExport::should_post_vthread_unmount()) {
|
||||
JvmtiExport::post_vthread_unmount(vthread);
|
||||
}
|
||||
if (last_unmount) {
|
||||
if (JvmtiExport::can_support_virtual_threads()) {
|
||||
if (JvmtiExport::should_post_vthread_end()) {
|
||||
JvmtiExport::post_vthread_end(vthread);
|
||||
}
|
||||
} else { // compatibility for vthread unaware agents: legacy thread_end
|
||||
if (PostVirtualThreadCompatibleLifecycleEvents &&
|
||||
JvmtiExport::should_post_thread_life()) {
|
||||
JvmtiExport::post_thread_end(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
start_VTMS_transition(vthread, /* is_mount */ false);
|
||||
|
||||
if (last_unmount && thread->jvmti_thread_state() != nullptr) {
|
||||
JvmtiExport::cleanup_thread(thread);
|
||||
thread->set_jvmti_thread_state(nullptr);
|
||||
oop vt = JNIHandles::resolve(vthread);
|
||||
java_lang_Thread::set_jvmti_thread_state(vt, nullptr);
|
||||
}
|
||||
thread->rebind_to_jvmti_thread_state_of(ct());
|
||||
}
|
||||
|
||||
void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread, jboolean last_unmount) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
assert(thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
finish_VTMS_transition(vthread, /* is_mount */ false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Virtual Threads Suspend/Resume management
|
||||
//
|
||||
|
@ -94,6 +94,10 @@ class JvmtiVTMSTransitionDisabler {
|
||||
void VTMS_transition_enable_for_all();
|
||||
|
||||
public:
|
||||
static bool _VTMS_notify_jvmti_events; // enable notifications from VirtualThread about VTMS events
|
||||
static bool VTMS_notify_jvmti_events() { return _VTMS_notify_jvmti_events; }
|
||||
static void set_VTMS_notify_jvmti_events(bool val) { _VTMS_notify_jvmti_events = val; }
|
||||
|
||||
// parameter is_SR: suspender or resumer
|
||||
JvmtiVTMSTransitionDisabler(bool is_SR = false);
|
||||
JvmtiVTMSTransitionDisabler(jthread thread);
|
||||
@ -101,6 +105,11 @@ class JvmtiVTMSTransitionDisabler {
|
||||
|
||||
static void start_VTMS_transition(jthread vthread, bool is_mount);
|
||||
static void finish_VTMS_transition(jthread vthread, bool is_mount);
|
||||
|
||||
static void VTMS_mount_begin(jobject vthread, jboolean first_mount);
|
||||
static void VTMS_mount_end(jobject vthread, jboolean first_mount);
|
||||
static void VTMS_unmount_begin(jobject vthread, jboolean last_unmount);
|
||||
static void VTMS_unmount_end(jobject vthread, jboolean last_unmount);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
@ -811,6 +811,11 @@ private:
|
||||
static ByteSize cont_fastpath_offset() { return byte_offset_of(JavaThread, _cont_fastpath); }
|
||||
static ByteSize held_monitor_count_offset() { return byte_offset_of(JavaThread, _held_monitor_count); }
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); }
|
||||
static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); }
|
||||
#endif
|
||||
|
||||
// Returns the jni environment for this thread
|
||||
JNIEnv* jni_environment() { return &_jni_environment; }
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/forte.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "prims/nativeLookup.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
@ -62,6 +63,7 @@
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stackWatermarkSet.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
@ -623,6 +625,28 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread* current, Symbol*
|
||||
throw_and_post_jvmti_exception(current, h_exception);
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
JRT_ENTRY(void, SharedRuntime::notify_jvmti_mount(oopDesc* vt, jboolean hide, jboolean first_mount, JavaThread* current))
|
||||
jobject vthread = JNIHandles::make_local(const_cast<oopDesc*>(vt));
|
||||
|
||||
if (hide) {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(vthread, first_mount);
|
||||
} else {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_end(vthread, first_mount);
|
||||
}
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, SharedRuntime::notify_jvmti_unmount(oopDesc* vt, jboolean hide, jboolean last_unmount, JavaThread* current))
|
||||
jobject vthread = JNIHandles::make_local(const_cast<oopDesc*>(vt));
|
||||
|
||||
if (hide) {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(vthread, last_unmount);
|
||||
} else {
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(vthread, last_unmount);
|
||||
}
|
||||
JRT_END
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
// The interpreter code to call this tracing function is only
|
||||
// called/generated when UL is on for redefine, class and has the right level
|
||||
// and tags. Since obsolete methods are never compiled, we don't have
|
||||
|
@ -264,6 +264,12 @@ class SharedRuntime: AllStatic {
|
||||
static void throw_and_post_jvmti_exception(JavaThread* current, Handle h_exception);
|
||||
static void throw_and_post_jvmti_exception(JavaThread* current, Symbol* name, const char *message = nullptr);
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
// Functions for JVMTI notifications
|
||||
static void notify_jvmti_mount(oopDesc* vt, jboolean hide, jboolean first_mount, JavaThread* current);
|
||||
static void notify_jvmti_unmount(oopDesc* vt, jboolean hide, jboolean last_unmount, JavaThread* current);
|
||||
#endif
|
||||
|
||||
// RedefineClasses() tracing support for obsolete method entry
|
||||
static int rc_trace_method_entry(JavaThread* thread, Method* m);
|
||||
|
||||
|
@ -56,6 +56,7 @@ import jdk.internal.vm.ThreadContainers;
|
||||
import jdk.internal.vm.annotation.ChangesCurrentThread;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Hidden;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.JvmtiMountTransition;
|
||||
import sun.nio.ch.Interruptible;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
@ -210,7 +211,7 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
|
||||
// notify JVMTI before mount
|
||||
if (notifyJvmtiEvents) notifyJvmtiMountBegin(firstRun);
|
||||
notifyJvmtiMount(true, firstRun);
|
||||
|
||||
try {
|
||||
cont.run();
|
||||
@ -287,11 +288,10 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
@ChangesCurrentThread
|
||||
private void run(Runnable task) {
|
||||
assert state == RUNNING;
|
||||
boolean notifyJvmti = notifyJvmtiEvents;
|
||||
|
||||
// first mount
|
||||
mount();
|
||||
if (notifyJvmti) notifyJvmtiMountEnd(true);
|
||||
notifyJvmtiMount(false, true);
|
||||
|
||||
// emit JFR event if enabled
|
||||
if (VirtualThreadStartEvent.isTurnedOn()) {
|
||||
@ -319,7 +319,7 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
|
||||
} finally {
|
||||
// last unmount
|
||||
if (notifyJvmti) notifyJvmtiUnmountBegin(true);
|
||||
notifyJvmtiUnmount(true, true);
|
||||
unmount();
|
||||
|
||||
// final state
|
||||
@ -381,35 +381,27 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
private void switchToCarrierThread() {
|
||||
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) {
|
||||
private void switchToVirtualThread(VirtualThread vthread) {
|
||||
Thread carrier = vthread.carrierThread;
|
||||
assert carrier == Thread.currentCarrierThread();
|
||||
carrier.setCurrentThread(vthread);
|
||||
if (notifyJvmti) {
|
||||
notifyJvmtiHideFrames(false);
|
||||
}
|
||||
notifyJvmtiHideFrames(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -419,17 +411,15 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
private boolean yieldContinuation() {
|
||||
boolean notifyJvmti = notifyJvmtiEvents;
|
||||
|
||||
// unmount
|
||||
if (notifyJvmti) notifyJvmtiUnmountBegin(false);
|
||||
notifyJvmtiUnmount(true, false);
|
||||
unmount();
|
||||
try {
|
||||
return Continuation.yield(VTHREAD_SCOPE);
|
||||
} finally {
|
||||
// re-mount
|
||||
mount();
|
||||
if (notifyJvmti) notifyJvmtiMountEnd(false);
|
||||
notifyJvmtiMount(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,7 +436,7 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
setState(PARKED);
|
||||
|
||||
// notify JVMTI that unmount has completed, thread is parked
|
||||
if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(false);
|
||||
notifyJvmtiUnmount(false, false);
|
||||
|
||||
// may have been unparked while parking
|
||||
if (parkPermit && compareAndSetState(PARKED, RUNNABLE)) {
|
||||
@ -462,7 +452,7 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
setState(RUNNABLE);
|
||||
|
||||
// notify JVMTI that unmount has completed, thread is runnable
|
||||
if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(false);
|
||||
notifyJvmtiUnmount(false, false);
|
||||
|
||||
// external submit if there are no tasks in the local task queue
|
||||
if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {
|
||||
@ -483,7 +473,7 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
assert (state() == TERMINATED) && (carrierThread == null);
|
||||
|
||||
if (executed) {
|
||||
if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(true);
|
||||
notifyJvmtiUnmount(false, true);
|
||||
}
|
||||
|
||||
// notify anyone waiting for this virtual thread to terminate
|
||||
@ -651,11 +641,11 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
@ChangesCurrentThread
|
||||
private Future<?> scheduleUnpark(Runnable unparker, long nanos) {
|
||||
// need to switch to current carrier thread to avoid nested parking
|
||||
boolean notifyJvmti = switchToCarrierThread();
|
||||
switchToCarrierThread();
|
||||
try {
|
||||
return UNPARKER.schedule(unparker, nanos, NANOSECONDS);
|
||||
} finally {
|
||||
switchToVirtualThread(this, notifyJvmti);
|
||||
switchToVirtualThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,11 +656,11 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
private void cancel(Future<?> future) {
|
||||
if (!future.isDone()) {
|
||||
// need to switch to current carrier thread to avoid nested parking
|
||||
boolean notifyJvmti = switchToCarrierThread();
|
||||
switchToCarrierThread();
|
||||
try {
|
||||
future.cancel(false);
|
||||
} finally {
|
||||
switchToVirtualThread(this, notifyJvmti);
|
||||
switchToVirtualThread(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -690,11 +680,11 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
int s = state();
|
||||
if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) {
|
||||
if (currentThread instanceof VirtualThread vthread) {
|
||||
boolean notifyJvmti = vthread.switchToCarrierThread();
|
||||
vthread.switchToCarrierThread();
|
||||
try {
|
||||
submitRunContinuation();
|
||||
} finally {
|
||||
switchToVirtualThread(vthread, notifyJvmti);
|
||||
switchToVirtualThread(vthread);
|
||||
}
|
||||
} else {
|
||||
submitRunContinuation();
|
||||
@ -1055,20 +1045,15 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
|
||||
// -- JVM TI support --
|
||||
|
||||
private static volatile boolean notifyJvmtiEvents; // set by VM
|
||||
|
||||
@IntrinsicCandidate
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiMountBegin(boolean firstMount);
|
||||
private native void notifyJvmtiMount(boolean hide, boolean firstMount);
|
||||
|
||||
@IntrinsicCandidate
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiMountEnd(boolean firstMount);
|
||||
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiUnmountBegin(boolean lastUnmount);
|
||||
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiUnmountEnd(boolean lastUnmount);
|
||||
private native void notifyJvmtiUnmount(boolean hide, boolean lastUnmount);
|
||||
|
||||
@IntrinsicCandidate
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiHideFrames(boolean hide);
|
||||
|
||||
|
@ -32,11 +32,9 @@
|
||||
#define VIRTUAL_THREAD "Ljava/lang/VirtualThread;"
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{ "notifyJvmtiMountBegin", "(Z)V", (void *)&JVM_VirtualThreadMountBegin },
|
||||
{ "notifyJvmtiMountEnd", "(Z)V", (void *)&JVM_VirtualThreadMountEnd },
|
||||
{ "notifyJvmtiUnmountBegin", "(Z)V", (void *)&JVM_VirtualThreadUnmountBegin },
|
||||
{ "notifyJvmtiUnmountEnd", "(Z)V", (void *)&JVM_VirtualThreadUnmountEnd },
|
||||
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
|
||||
{ "notifyJvmtiMount", "(ZZ)V", (void *)&JVM_VirtualThreadMount },
|
||||
{ "notifyJvmtiUnmount", "(ZZ)V", (void *)&JVM_VirtualThreadUnmount },
|
||||
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
|
||||
};
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
Loading…
Reference in New Issue
Block a user