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
|
JVM_SetBootLoaderUnnamedModule
|
||||||
|
|
||||||
# Virtual thread notifications for JVMTI
|
# Virtual thread notifications for JVMTI
|
||||||
JVM_VirtualThreadMountBegin
|
JVM_VirtualThreadMount
|
||||||
JVM_VirtualThreadMountEnd
|
JVM_VirtualThreadUnmount
|
||||||
JVM_VirtualThreadUnmountBegin
|
|
||||||
JVM_VirtualThreadUnmountEnd
|
|
||||||
JVM_VirtualThreadHideFrames
|
JVM_VirtualThreadHideFrames
|
||||||
|
|
||||||
# Scoped values
|
# Scoped values
|
||||||
|
@ -1933,34 +1933,23 @@ void java_lang_ThreadGroup::serialize_offsets(SerializeClosure* f) {
|
|||||||
|
|
||||||
// java_lang_VirtualThread
|
// java_lang_VirtualThread
|
||||||
|
|
||||||
int java_lang_VirtualThread::static_notify_jvmti_events_offset;
|
|
||||||
int java_lang_VirtualThread::static_vthread_scope_offset;
|
int java_lang_VirtualThread::static_vthread_scope_offset;
|
||||||
int java_lang_VirtualThread::_carrierThread_offset;
|
int java_lang_VirtualThread::_carrierThread_offset;
|
||||||
int java_lang_VirtualThread::_continuation_offset;
|
int java_lang_VirtualThread::_continuation_offset;
|
||||||
int java_lang_VirtualThread::_state_offset;
|
int java_lang_VirtualThread::_state_offset;
|
||||||
|
|
||||||
#define VTHREAD_FIELDS_DO(macro) \
|
#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(static_vthread_scope_offset, k, "VTHREAD_SCOPE", continuationscope_signature, true); \
|
||||||
macro(_carrierThread_offset, k, "carrierThread", thread_signature, false); \
|
macro(_carrierThread_offset, k, "carrierThread", thread_signature, false); \
|
||||||
macro(_continuation_offset, k, "cont", continuation_signature, false); \
|
macro(_continuation_offset, k, "cont", continuation_signature, false); \
|
||||||
macro(_state_offset, k, "state", int_signature, false)
|
macro(_state_offset, k, "state", int_signature, false)
|
||||||
|
|
||||||
static bool vthread_notify_jvmti_events = JNI_FALSE;
|
|
||||||
|
|
||||||
void java_lang_VirtualThread::compute_offsets() {
|
void java_lang_VirtualThread::compute_offsets() {
|
||||||
InstanceKlass* k = vmClasses::VirtualThread_klass();
|
InstanceKlass* k = vmClasses::VirtualThread_klass();
|
||||||
VTHREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
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) {
|
bool java_lang_VirtualThread::is_instance(oop obj) {
|
||||||
return obj != nullptr && is_subclass(obj->klass());
|
return obj != nullptr && is_subclass(obj->klass());
|
||||||
}
|
}
|
||||||
@ -2013,15 +2002,6 @@ void java_lang_VirtualThread::serialize_offsets(SerializeClosure* f) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
// java_lang_Throwable
|
||||||
|
|
||||||
int java_lang_Throwable::_backtrace_offset;
|
int java_lang_Throwable::_backtrace_offset;
|
||||||
@ -5387,6 +5367,5 @@ int InjectedField::compute_offset() {
|
|||||||
void javaClasses_init() {
|
void javaClasses_init() {
|
||||||
JavaClasses::compute_offsets();
|
JavaClasses::compute_offsets();
|
||||||
JavaClasses::check_offsets();
|
JavaClasses::check_offsets();
|
||||||
java_lang_VirtualThread::init_static_notify_jvmti_events();
|
|
||||||
FilteredFieldsMap::initialize(); // must be done after computing offsets.
|
FilteredFieldsMap::initialize(); // must be done after computing offsets.
|
||||||
}
|
}
|
||||||
|
@ -510,7 +510,6 @@ class java_lang_ThreadGroup : AllStatic {
|
|||||||
|
|
||||||
class java_lang_VirtualThread : AllStatic {
|
class java_lang_VirtualThread : AllStatic {
|
||||||
private:
|
private:
|
||||||
static int static_notify_jvmti_events_offset;
|
|
||||||
static int static_vthread_scope_offset;
|
static int static_vthread_scope_offset;
|
||||||
static int _carrierThread_offset;
|
static int _carrierThread_offset;
|
||||||
static int _continuation_offset;
|
static int _continuation_offset;
|
||||||
@ -548,9 +547,6 @@ class java_lang_VirtualThread : AllStatic {
|
|||||||
static oop continuation(oop vthread);
|
static oop continuation(oop vthread);
|
||||||
static int state(oop vthread);
|
static int state(oop vthread);
|
||||||
static JavaThreadStatus map_state_to_thread_status(int state);
|
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_intrinsic(_Continuation_doYield, jdk_internal_vm_Continuation, doYield_name, continuationDoYield_signature, F_SN) \
|
||||||
do_alias( continuationDoYield_signature, void_int_signature) \
|
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 */ \
|
/* support for UnsafeConstants */ \
|
||||||
do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \
|
do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \
|
||||||
\
|
\
|
||||||
|
@ -412,6 +412,9 @@
|
|||||||
template(run_finalization_name, "runFinalization") \
|
template(run_finalization_name, "runFinalization") \
|
||||||
template(dispatchUncaughtException_name, "dispatchUncaughtException") \
|
template(dispatchUncaughtException_name, "dispatchUncaughtException") \
|
||||||
template(loadClass_name, "loadClass") \
|
template(loadClass_name, "loadClass") \
|
||||||
|
template(notifyJvmtiMount_name, "notifyJvmtiMount") \
|
||||||
|
template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \
|
||||||
|
template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \
|
||||||
template(doYield_name, "doYield") \
|
template(doYield_name, "doYield") \
|
||||||
template(enter_name, "enter") \
|
template(enter_name, "enter") \
|
||||||
template(enterSpecial_name, "enterSpecial") \
|
template(enterSpecial_name, "enterSpecial") \
|
||||||
@ -550,6 +553,7 @@
|
|||||||
template(void_float_signature, "()F") \
|
template(void_float_signature, "()F") \
|
||||||
template(void_double_signature, "()D") \
|
template(void_double_signature, "()D") \
|
||||||
template(bool_void_signature, "(Z)V") \
|
template(bool_void_signature, "(Z)V") \
|
||||||
|
template(bool_bool_void_signature, "(ZZ)V") \
|
||||||
template(int_void_signature, "(I)V") \
|
template(int_void_signature, "(I)V") \
|
||||||
template(int_int_signature, "(I)I") \
|
template(int_int_signature, "(I)I") \
|
||||||
template(char_char_signature, "(C)C") \
|
template(char_char_signature, "(C)C") \
|
||||||
|
@ -1144,16 +1144,10 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass);
|
|||||||
* Virtual thread support.
|
* Virtual thread support.
|
||||||
*/
|
*/
|
||||||
JNIEXPORT void JNICALL
|
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
|
JNIEXPORT void JNICALL
|
||||||
JVM_VirtualThreadMountEnd(JNIEnv* env, jobject vthread, jboolean first_mount);
|
JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide, jboolean last_unmount);
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmount);
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount);
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
|
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
|
||||||
|
@ -771,6 +771,11 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method) {
|
|||||||
case vmIntrinsics::_IndexPartiallyInUpperRange:
|
case vmIntrinsics::_IndexPartiallyInUpperRange:
|
||||||
return EnableVectorSupport;
|
return EnableVectorSupport;
|
||||||
case vmIntrinsics::_blackhole:
|
case vmIntrinsics::_blackhole:
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
case vmIntrinsics::_notifyJvmtiMount:
|
||||||
|
case vmIntrinsics::_notifyJvmtiUnmount:
|
||||||
|
case vmIntrinsics::_notifyJvmtiHideFrames:
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
|
#include "prims/jvmtiThreadState.hpp"
|
||||||
#include "prims/unsafe.hpp"
|
#include "prims/unsafe.hpp"
|
||||||
#include "runtime/jniHandles.inline.hpp"
|
#include "runtime/jniHandles.inline.hpp"
|
||||||
#include "runtime/objectMonitor.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::_scopedValueCache: return inline_native_scopedValueCache();
|
||||||
case vmIntrinsics::_setScopedValueCache: return inline_native_setScopedValueCache();
|
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
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, JfrTime::time_function()), "counterTime");
|
case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, JfrTime::time_function()), "counterTime");
|
||||||
case vmIntrinsics::_getEventWriter: return inline_native_getEventWriter();
|
case vmIntrinsics::_getEventWriter: return inline_native_getEventWriter();
|
||||||
@ -2841,6 +2850,75 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func
|
|||||||
return true;
|
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
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,6 +245,11 @@ class LibraryCallKit : public GraphKit {
|
|||||||
bool inline_native_setScopedValueCache();
|
bool inline_native_setScopedValueCache();
|
||||||
|
|
||||||
bool inline_native_time_funcs(address method, const char* funcName);
|
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
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
bool inline_native_classID();
|
bool inline_native_classID();
|
||||||
bool inline_native_getEventWriter();
|
bool inline_native_getEventWriter();
|
||||||
|
@ -109,6 +109,10 @@ address OptoRuntime::_rethrow_Java = nullptr;
|
|||||||
|
|
||||||
address OptoRuntime::_slow_arraycopy_Java = nullptr;
|
address OptoRuntime::_slow_arraycopy_Java = nullptr;
|
||||||
address OptoRuntime::_register_finalizer_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;
|
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, _multianewarray4_Java , multianewarray4_Type , multianewarray4_C , 0 , true, false);
|
||||||
gen(env, _multianewarray5_Java , multianewarray5_Type , multianewarray5_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);
|
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, _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_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);
|
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
|
#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
|
// Dtrace support. entry and exit probes have the same signature
|
||||||
const TypeFunc *OptoRuntime::dtrace_method_entry_exit_Type() {
|
const TypeFunc *OptoRuntime::dtrace_method_entry_exit_Type() {
|
||||||
|
@ -135,6 +135,10 @@ class OptoRuntime : public AllStatic {
|
|||||||
|
|
||||||
static address _slow_arraycopy_Java;
|
static address _slow_arraycopy_Java;
|
||||||
static address _register_finalizer_Java;
|
static address _register_finalizer_Java;
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
static address _notify_jvmti_mount;
|
||||||
|
static address _notify_jvmti_unmount;
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Implementation of runtime methods
|
// Implementation of runtime methods
|
||||||
@ -208,6 +212,10 @@ private:
|
|||||||
|
|
||||||
static address slow_arraycopy_Java() { return _slow_arraycopy_Java; }
|
static address slow_arraycopy_Java() { return _slow_arraycopy_Java; }
|
||||||
static address register_finalizer_Java() { return _register_finalizer_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; }
|
static ExceptionBlob* exception_blob() { return _exception_blob; }
|
||||||
|
|
||||||
@ -294,6 +302,9 @@ private:
|
|||||||
static const TypeFunc* register_finalizer_Type();
|
static const TypeFunc* register_finalizer_Type();
|
||||||
|
|
||||||
JFR_ONLY(static const TypeFunc* class_id_load_barrier_Type();)
|
JFR_ONLY(static const TypeFunc* class_id_load_barrier_Type();)
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
static const TypeFunc* notify_jvmti_Type();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Dtrace support
|
// Dtrace support
|
||||||
static const TypeFunc* dtrace_method_entry_exit_Type();
|
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);
|
return os::get_signal_number(name);
|
||||||
JVM_END
|
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 INCLUDE_JVMTI
|
||||||
if (!DoJVMTIVirtualThreadTransitions) {
|
if (!DoJVMTIVirtualThreadTransitions) {
|
||||||
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");
|
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
thread->set_is_in_VTMS_transition(hide);
|
||||||
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");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
oop vt = JNIHandles::resolve(vthread);
|
if (hide) {
|
||||||
|
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(vthread, first_mount);
|
||||||
thread->rebind_to_jvmti_thread_state_of(vt);
|
} else {
|
||||||
|
JvmtiVTMSTransitionDisabler::VTMS_mount_end(vthread, first_mount);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
#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_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 INCLUDE_JVMTI
|
||||||
if (!DoJVMTIVirtualThreadTransitions) {
|
if (!DoJVMTIVirtualThreadTransitions) {
|
||||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HandleMark hm(thread);
|
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||||
Handle ct(thread, thread->threadObj());
|
thread->set_is_in_VTMS_transition(hide);
|
||||||
|
|
||||||
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");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(thread->is_in_VTMS_transition(), "sanity check");
|
if (hide) {
|
||||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(vthread, last_unmount);
|
||||||
JvmtiVTMSTransitionDisabler::finish_VTMS_transition(vthread, /* is_mount */ false);
|
} else {
|
||||||
|
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(vthread, last_unmount);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
fatal("Should only be called with JVMTI enabled");
|
fatal("Should only be called with JVMTI enabled");
|
||||||
#endif
|
#endif
|
||||||
JVM_END
|
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))
|
JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide))
|
||||||
#if INCLUDE_JVMTI
|
#if INCLUDE_JVMTI
|
||||||
if (!DoJVMTIVirtualThreadTransitions) {
|
if (!DoJVMTIVirtualThreadTransitions) {
|
||||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||||
assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check");
|
assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check");
|
||||||
thread->toggle_is_in_tmp_VTMS_transition();
|
thread->toggle_is_in_tmp_VTMS_transition();
|
||||||
|
@ -379,11 +379,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
|
|||||||
}
|
}
|
||||||
if (Continuations::enabled()) {
|
if (Continuations::enabled()) {
|
||||||
// Virtual threads support. There is a performance impact when VTMS transitions are enabled.
|
// Virtual threads support. There is a performance impact when VTMS transitions are enabled.
|
||||||
java_lang_VirtualThread::set_notify_jvmti_events(true);
|
JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(true);
|
||||||
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
|
|
||||||
ThreadInVMfromNative __tiv(JavaThread::current());
|
|
||||||
java_lang_VirtualThread::init_static_notify_jvmti_events();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
|
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include "prims/jvmtiThreadState.inline.hpp"
|
#include "prims/jvmtiThreadState.inline.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/interfaceSupport.inline.hpp"
|
#include "runtime/interfaceSupport.inline.hpp"
|
||||||
#include "runtime/jniHandles.hpp"
|
#include "runtime/jniHandles.inline.hpp"
|
||||||
#include "runtime/safepointVerifiers.hpp"
|
#include "runtime/safepointVerifiers.hpp"
|
||||||
#include "runtime/stackFrameStream.inline.hpp"
|
#include "runtime/stackFrameStream.inline.hpp"
|
||||||
#include "runtime/vframe.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
|
// VTMS transitions for one virtual thread are disabled while it is positive
|
||||||
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0;
|
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;
|
volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0;
|
||||||
|
|
||||||
// There is an active suspender or resumer.
|
// There is an active suspender or resumer.
|
||||||
volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false;
|
volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false;
|
||||||
|
|
||||||
|
// Notifications from VirtualThread about VTMS events are enabled.
|
||||||
|
bool JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events = false;
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
void
|
void
|
||||||
@ -509,6 +511,94 @@ JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mou
|
|||||||
#endif
|
#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
|
// Virtual Threads Suspend/Resume management
|
||||||
//
|
//
|
||||||
|
@ -94,6 +94,10 @@ class JvmtiVTMSTransitionDisabler {
|
|||||||
void VTMS_transition_enable_for_all();
|
void VTMS_transition_enable_for_all();
|
||||||
|
|
||||||
public:
|
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
|
// parameter is_SR: suspender or resumer
|
||||||
JvmtiVTMSTransitionDisabler(bool is_SR = false);
|
JvmtiVTMSTransitionDisabler(bool is_SR = false);
|
||||||
JvmtiVTMSTransitionDisabler(jthread thread);
|
JvmtiVTMSTransitionDisabler(jthread thread);
|
||||||
@ -101,6 +105,11 @@ class JvmtiVTMSTransitionDisabler {
|
|||||||
|
|
||||||
static void start_VTMS_transition(jthread vthread, bool is_mount);
|
static void start_VTMS_transition(jthread vthread, bool is_mount);
|
||||||
static void finish_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 cont_fastpath_offset() { return byte_offset_of(JavaThread, _cont_fastpath); }
|
||||||
static ByteSize held_monitor_count_offset() { return byte_offset_of(JavaThread, _held_monitor_count); }
|
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
|
// Returns the jni environment for this thread
|
||||||
JNIEnv* jni_environment() { return &_jni_environment; }
|
JNIEnv* jni_environment() { return &_jni_environment; }
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "prims/forte.hpp"
|
#include "prims/forte.hpp"
|
||||||
#include "prims/jvmtiExport.hpp"
|
#include "prims/jvmtiExport.hpp"
|
||||||
|
#include "prims/jvmtiThreadState.hpp"
|
||||||
#include "prims/methodHandles.hpp"
|
#include "prims/methodHandles.hpp"
|
||||||
#include "prims/nativeLookup.hpp"
|
#include "prims/nativeLookup.hpp"
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
@ -62,6 +63,7 @@
|
|||||||
#include "runtime/interfaceSupport.inline.hpp"
|
#include "runtime/interfaceSupport.inline.hpp"
|
||||||
#include "runtime/java.hpp"
|
#include "runtime/java.hpp"
|
||||||
#include "runtime/javaCalls.hpp"
|
#include "runtime/javaCalls.hpp"
|
||||||
|
#include "runtime/jniHandles.hpp"
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
#include "runtime/stackWatermarkSet.hpp"
|
#include "runtime/stackWatermarkSet.hpp"
|
||||||
#include "runtime/stubRoutines.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);
|
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
|
// The interpreter code to call this tracing function is only
|
||||||
// called/generated when UL is on for redefine, class and has the right level
|
// 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
|
// 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, Handle h_exception);
|
||||||
static void throw_and_post_jvmti_exception(JavaThread* current, Symbol* name, const char *message = nullptr);
|
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
|
// RedefineClasses() tracing support for obsolete method entry
|
||||||
static int rc_trace_method_entry(JavaThread* thread, Method* m);
|
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.ChangesCurrentThread;
|
||||||
import jdk.internal.vm.annotation.ForceInline;
|
import jdk.internal.vm.annotation.ForceInline;
|
||||||
import jdk.internal.vm.annotation.Hidden;
|
import jdk.internal.vm.annotation.Hidden;
|
||||||
|
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||||
import jdk.internal.vm.annotation.JvmtiMountTransition;
|
import jdk.internal.vm.annotation.JvmtiMountTransition;
|
||||||
import sun.nio.ch.Interruptible;
|
import sun.nio.ch.Interruptible;
|
||||||
import sun.security.action.GetPropertyAction;
|
import sun.security.action.GetPropertyAction;
|
||||||
@ -210,7 +211,7 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notify JVMTI before mount
|
// notify JVMTI before mount
|
||||||
if (notifyJvmtiEvents) notifyJvmtiMountBegin(firstRun);
|
notifyJvmtiMount(true, firstRun);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cont.run();
|
cont.run();
|
||||||
@ -287,11 +288,10 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
@ChangesCurrentThread
|
@ChangesCurrentThread
|
||||||
private void run(Runnable task) {
|
private void run(Runnable task) {
|
||||||
assert state == RUNNING;
|
assert state == RUNNING;
|
||||||
boolean notifyJvmti = notifyJvmtiEvents;
|
|
||||||
|
|
||||||
// first mount
|
// first mount
|
||||||
mount();
|
mount();
|
||||||
if (notifyJvmti) notifyJvmtiMountEnd(true);
|
notifyJvmtiMount(false, true);
|
||||||
|
|
||||||
// emit JFR event if enabled
|
// emit JFR event if enabled
|
||||||
if (VirtualThreadStartEvent.isTurnedOn()) {
|
if (VirtualThreadStartEvent.isTurnedOn()) {
|
||||||
@ -319,7 +319,7 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
// last unmount
|
// last unmount
|
||||||
if (notifyJvmti) notifyJvmtiUnmountBegin(true);
|
notifyJvmtiUnmount(true, true);
|
||||||
unmount();
|
unmount();
|
||||||
|
|
||||||
// final state
|
// final state
|
||||||
@ -381,35 +381,27 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current thread to the current carrier thread.
|
* Sets the current thread to the current carrier thread.
|
||||||
* @return true if JVMTI was notified
|
|
||||||
*/
|
*/
|
||||||
@ChangesCurrentThread
|
@ChangesCurrentThread
|
||||||
@JvmtiMountTransition
|
@JvmtiMountTransition
|
||||||
private boolean switchToCarrierThread() {
|
private void switchToCarrierThread() {
|
||||||
boolean notifyJvmti = notifyJvmtiEvents;
|
notifyJvmtiHideFrames(true);
|
||||||
if (notifyJvmti) {
|
|
||||||
notifyJvmtiHideFrames(true);
|
|
||||||
}
|
|
||||||
Thread carrier = this.carrierThread;
|
Thread carrier = this.carrierThread;
|
||||||
assert Thread.currentThread() == this
|
assert Thread.currentThread() == this
|
||||||
&& carrier == Thread.currentCarrierThread();
|
&& carrier == Thread.currentCarrierThread();
|
||||||
carrier.setCurrentThread(carrier);
|
carrier.setCurrentThread(carrier);
|
||||||
return notifyJvmti;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current thread to the given virtual thread.
|
* Sets the current thread to the given virtual thread.
|
||||||
* If {@code notifyJvmti} is true then JVMTI is notified.
|
|
||||||
*/
|
*/
|
||||||
@ChangesCurrentThread
|
@ChangesCurrentThread
|
||||||
@JvmtiMountTransition
|
@JvmtiMountTransition
|
||||||
private void switchToVirtualThread(VirtualThread vthread, boolean notifyJvmti) {
|
private void switchToVirtualThread(VirtualThread vthread) {
|
||||||
Thread carrier = vthread.carrierThread;
|
Thread carrier = vthread.carrierThread;
|
||||||
assert carrier == Thread.currentCarrierThread();
|
assert carrier == Thread.currentCarrierThread();
|
||||||
carrier.setCurrentThread(vthread);
|
carrier.setCurrentThread(vthread);
|
||||||
if (notifyJvmti) {
|
notifyJvmtiHideFrames(false);
|
||||||
notifyJvmtiHideFrames(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,17 +411,15 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
*/
|
*/
|
||||||
@ChangesCurrentThread
|
@ChangesCurrentThread
|
||||||
private boolean yieldContinuation() {
|
private boolean yieldContinuation() {
|
||||||
boolean notifyJvmti = notifyJvmtiEvents;
|
|
||||||
|
|
||||||
// unmount
|
// unmount
|
||||||
if (notifyJvmti) notifyJvmtiUnmountBegin(false);
|
notifyJvmtiUnmount(true, false);
|
||||||
unmount();
|
unmount();
|
||||||
try {
|
try {
|
||||||
return Continuation.yield(VTHREAD_SCOPE);
|
return Continuation.yield(VTHREAD_SCOPE);
|
||||||
} finally {
|
} finally {
|
||||||
// re-mount
|
// re-mount
|
||||||
mount();
|
mount();
|
||||||
if (notifyJvmti) notifyJvmtiMountEnd(false);
|
notifyJvmtiMount(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +436,7 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
setState(PARKED);
|
setState(PARKED);
|
||||||
|
|
||||||
// notify JVMTI that unmount has completed, thread is parked
|
// notify JVMTI that unmount has completed, thread is parked
|
||||||
if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(false);
|
notifyJvmtiUnmount(false, false);
|
||||||
|
|
||||||
// may have been unparked while parking
|
// may have been unparked while parking
|
||||||
if (parkPermit && compareAndSetState(PARKED, RUNNABLE)) {
|
if (parkPermit && compareAndSetState(PARKED, RUNNABLE)) {
|
||||||
@ -462,7 +452,7 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
setState(RUNNABLE);
|
setState(RUNNABLE);
|
||||||
|
|
||||||
// notify JVMTI that unmount has completed, thread is 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
|
// external submit if there are no tasks in the local task queue
|
||||||
if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {
|
if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {
|
||||||
@ -483,7 +473,7 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
assert (state() == TERMINATED) && (carrierThread == null);
|
assert (state() == TERMINATED) && (carrierThread == null);
|
||||||
|
|
||||||
if (executed) {
|
if (executed) {
|
||||||
if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(true);
|
notifyJvmtiUnmount(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify anyone waiting for this virtual thread to terminate
|
// notify anyone waiting for this virtual thread to terminate
|
||||||
@ -651,11 +641,11 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
@ChangesCurrentThread
|
@ChangesCurrentThread
|
||||||
private Future<?> scheduleUnpark(Runnable unparker, long nanos) {
|
private Future<?> scheduleUnpark(Runnable unparker, long nanos) {
|
||||||
// need to switch to current carrier thread to avoid nested parking
|
// need to switch to current carrier thread to avoid nested parking
|
||||||
boolean notifyJvmti = switchToCarrierThread();
|
switchToCarrierThread();
|
||||||
try {
|
try {
|
||||||
return UNPARKER.schedule(unparker, nanos, NANOSECONDS);
|
return UNPARKER.schedule(unparker, nanos, NANOSECONDS);
|
||||||
} finally {
|
} finally {
|
||||||
switchToVirtualThread(this, notifyJvmti);
|
switchToVirtualThread(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,11 +656,11 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
private void cancel(Future<?> future) {
|
private void cancel(Future<?> future) {
|
||||||
if (!future.isDone()) {
|
if (!future.isDone()) {
|
||||||
// need to switch to current carrier thread to avoid nested parking
|
// need to switch to current carrier thread to avoid nested parking
|
||||||
boolean notifyJvmti = switchToCarrierThread();
|
switchToCarrierThread();
|
||||||
try {
|
try {
|
||||||
future.cancel(false);
|
future.cancel(false);
|
||||||
} finally {
|
} finally {
|
||||||
switchToVirtualThread(this, notifyJvmti);
|
switchToVirtualThread(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -690,11 +680,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) {
|
||||||
boolean notifyJvmti = vthread.switchToCarrierThread();
|
vthread.switchToCarrierThread();
|
||||||
try {
|
try {
|
||||||
submitRunContinuation();
|
submitRunContinuation();
|
||||||
} finally {
|
} finally {
|
||||||
switchToVirtualThread(vthread, notifyJvmti);
|
switchToVirtualThread(vthread);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
submitRunContinuation();
|
submitRunContinuation();
|
||||||
@ -1055,20 +1045,15 @@ final class VirtualThread extends BaseVirtualThread {
|
|||||||
|
|
||||||
// -- JVM TI support --
|
// -- JVM TI support --
|
||||||
|
|
||||||
private static volatile boolean notifyJvmtiEvents; // set by VM
|
@IntrinsicCandidate
|
||||||
|
|
||||||
@JvmtiMountTransition
|
@JvmtiMountTransition
|
||||||
private native void notifyJvmtiMountBegin(boolean firstMount);
|
private native void notifyJvmtiMount(boolean hide, boolean firstMount);
|
||||||
|
|
||||||
|
@IntrinsicCandidate
|
||||||
@JvmtiMountTransition
|
@JvmtiMountTransition
|
||||||
private native void notifyJvmtiMountEnd(boolean firstMount);
|
private native void notifyJvmtiUnmount(boolean hide, boolean lastUnmount);
|
||||||
|
|
||||||
@JvmtiMountTransition
|
|
||||||
private native void notifyJvmtiUnmountBegin(boolean lastUnmount);
|
|
||||||
|
|
||||||
@JvmtiMountTransition
|
|
||||||
private native void notifyJvmtiUnmountEnd(boolean lastUnmount);
|
|
||||||
|
|
||||||
|
@IntrinsicCandidate
|
||||||
@JvmtiMountTransition
|
@JvmtiMountTransition
|
||||||
private native void notifyJvmtiHideFrames(boolean hide);
|
private native void notifyJvmtiHideFrames(boolean hide);
|
||||||
|
|
||||||
|
@ -32,11 +32,9 @@
|
|||||||
#define VIRTUAL_THREAD "Ljava/lang/VirtualThread;"
|
#define VIRTUAL_THREAD "Ljava/lang/VirtualThread;"
|
||||||
|
|
||||||
static JNINativeMethod methods[] = {
|
static JNINativeMethod methods[] = {
|
||||||
{ "notifyJvmtiMountBegin", "(Z)V", (void *)&JVM_VirtualThreadMountBegin },
|
{ "notifyJvmtiMount", "(ZZ)V", (void *)&JVM_VirtualThreadMount },
|
||||||
{ "notifyJvmtiMountEnd", "(Z)V", (void *)&JVM_VirtualThreadMountEnd },
|
{ "notifyJvmtiUnmount", "(ZZ)V", (void *)&JVM_VirtualThreadUnmount },
|
||||||
{ "notifyJvmtiUnmountBegin", "(Z)V", (void *)&JVM_VirtualThreadUnmountBegin },
|
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
|
||||||
{ "notifyJvmtiUnmountEnd", "(Z)V", (void *)&JVM_VirtualThreadUnmountEnd },
|
|
||||||
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
Loading…
Reference in New Issue
Block a user