Skip to content

Commit

Permalink
8304303: implement VirtualThread class notifyJvmti methods as C2 intr…
Browse files Browse the repository at this point in the history
…insics

Reviewed-by: vlivanov, lmesnik
  • Loading branch information
Serguei Spitsyn committed Mar 20, 2023
1 parent 2d0d057 commit bc0ed73
Show file tree
Hide file tree
Showing 20 changed files with 324 additions and 173 deletions.
6 changes: 2 additions & 4 deletions make/data/hotspot-symbols/symbols-unix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 0 additions & 21 deletions src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
}
4 changes: 0 additions & 4 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
};


Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/classfile/vmIntrinsics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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") \
\
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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") \
Expand Down Expand Up @@ -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") \
Expand Down
10 changes: 2 additions & 8 deletions src/hotspot/share/include/jvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/opto/c2compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
78 changes: 78 additions & 0 deletions src/hotspot/share/opto/library_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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

/**
Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/opto/library_call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
26 changes: 26 additions & 0 deletions src/hotspot/share/opto/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Expand Down
11 changes: 11 additions & 0 deletions src/hotspot/share/opto/runtime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -208,6 +212,10 @@ class OptoRuntime : public AllStatic {

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; }

Expand Down Expand Up @@ -294,6 +302,9 @@ class OptoRuntime : public AllStatic {
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();
Expand Down
Loading

1 comment on commit bc0ed73

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.