Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8306028: separate ThreadStart/ThreadEnd events posting code in JVMTI …
…VTMS transitions

8304444: Reappearance of NULL in jvmtiThreadState.cpp

Reviewed-by: pchilanomate, lmesnik
  • Loading branch information
Serguei Spitsyn committed May 2, 2023
1 parent 35e75c1 commit 1227a27
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 151 deletions.
4 changes: 3 additions & 1 deletion make/data/hotspot-symbols/symbols-unix
@@ -1,5 +1,5 @@
#
# Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -217,6 +217,8 @@ JVM_DefineModule
JVM_SetBootLoaderUnnamedModule

# Virtual thread notifications for JVMTI
JVM_VirtualThreadStart
JVM_VirtualThreadEnd
JVM_VirtualThreadMount
JVM_VirtualThreadUnmount
JVM_VirtualThreadHideFrames
Expand Down
8 changes: 5 additions & 3 deletions src/hotspot/share/classfile/vmIntrinsics.hpp
Expand Up @@ -584,9 +584,11 @@ class methodHandle;
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) \
do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \
do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \
do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \
do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \
do_intrinsic(_notifyJvmtiVThreadHideFrames, 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
2 changes: 2 additions & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Expand Up @@ -412,6 +412,8 @@
template(run_finalization_name, "runFinalization") \
template(dispatchUncaughtException_name, "dispatchUncaughtException") \
template(loadClass_name, "loadClass") \
template(notifyJvmtiStart_name, "notifyJvmtiStart") \
template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \
template(notifyJvmtiMount_name, "notifyJvmtiMount") \
template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \
template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \
Expand Down
10 changes: 8 additions & 2 deletions src/hotspot/share/include/jvm.h
Expand Up @@ -1144,10 +1144,16 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass);
* Virtual thread support.
*/
JNIEXPORT void JNICALL
JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide, jboolean first_mount);
JVM_VirtualThreadStart(JNIEnv* env, jobject vthread);

JNIEXPORT void JNICALL
JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide, jboolean last_unmount);
JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread);

JNIEXPORT void JNICALL
JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide);

JNIEXPORT void JNICALL
JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide);

JNIEXPORT void JNICALL
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
Expand Down
8 changes: 5 additions & 3 deletions src/hotspot/share/opto/c2compiler.cpp
Expand Up @@ -775,9 +775,11 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method) {
return EnableVectorSupport;
case vmIntrinsics::_blackhole:
#if INCLUDE_JVMTI
case vmIntrinsics::_notifyJvmtiMount:
case vmIntrinsics::_notifyJvmtiUnmount:
case vmIntrinsics::_notifyJvmtiHideFrames:
case vmIntrinsics::_notifyJvmtiVThreadStart:
case vmIntrinsics::_notifyJvmtiVThreadEnd:
case vmIntrinsics::_notifyJvmtiVThreadMount:
case vmIntrinsics::_notifyJvmtiVThreadUnmount:
case vmIntrinsics::_notifyJvmtiVThreadHideFrames:
#endif
break;

Expand Down
23 changes: 13 additions & 10 deletions src/hotspot/share/opto/library_call.cpp
Expand Up @@ -481,11 +481,15 @@ bool LibraryCallKit::try_to_inline(int predicate) {
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();
case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()),
"notifyJvmtiStart", true, false);
case vmIntrinsics::_notifyJvmtiVThreadEnd: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_end()),
"notifyJvmtiEnd", false, true);
case vmIntrinsics::_notifyJvmtiVThreadMount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_mount()),
"notifyJvmtiMount", false, false);
case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()),
"notifyJvmtiUnmount", false, false);
case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide();
#endif

#ifdef JFR_HAVE_INTRINSICS
Expand Down Expand Up @@ -2873,25 +2877,24 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func

// 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) {
bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end) {
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* hide = is_start ? ideal.ConI(0) : (is_end ? ideal.ConI(1) : _gvn.transform(argument(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); {
// if notifyJvmti enabled then make a call to the given SharedRuntime function
const TypeFunc* tf = OptoRuntime::notify_jvmti_Type();
const TypeFunc* tf = OptoRuntime::notify_jvmti_vthread_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);
make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide);
ideal.sync_kit(this);
} ideal.else_(); {
// set hide value to the VTMS transition bit in current JavaThread and VirtualThread object
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/library_call.hpp
Expand Up @@ -246,7 +246,7 @@ class LibraryCallKit : public GraphKit {

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_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end);
bool inline_native_notify_jvmti_hide();
#endif

Expand Down
45 changes: 23 additions & 22 deletions src/hotspot/share/opto/runtime.cpp
Expand Up @@ -111,8 +111,10 @@ address OptoRuntime::_slow_arraycopy_Java = nullptr;
address OptoRuntime::_register_finalizer_Java = nullptr;
#if INCLUDE_JVMTI
address OptoRuntime::_notify_jvmti_object_alloc = nullptr;
address OptoRuntime::_notify_jvmti_mount = nullptr;
address OptoRuntime::_notify_jvmti_unmount = nullptr;
address OptoRuntime::_notify_jvmti_vthread_start = nullptr;
address OptoRuntime::_notify_jvmti_vthread_end = nullptr;
address OptoRuntime::_notify_jvmti_vthread_mount = nullptr;
address OptoRuntime::_notify_jvmti_vthread_unmount = nullptr;
#endif

ExceptionBlob* OptoRuntime::_exception_blob;
Expand Down Expand Up @@ -155,8 +157,10 @@ bool OptoRuntime::generate(ciEnv* env) {
gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true, false);
#if INCLUDE_JVMTI
gen(env, _notify_jvmti_object_alloc , notify_jvmti_object_alloc_Type, SharedRuntime::notify_jvmti_object_alloc, 0, true, false);
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);
gen(env, _notify_jvmti_vthread_start , notify_jvmti_vthread_Type , SharedRuntime::notify_jvmti_vthread_start, 0, true, false);
gen(env, _notify_jvmti_vthread_end , notify_jvmti_vthread_Type , SharedRuntime::notify_jvmti_vthread_end, 0, true, false);
gen(env, _notify_jvmti_vthread_mount , notify_jvmti_vthread_Type , SharedRuntime::notify_jvmti_vthread_mount, 0, true, false);
gen(env, _notify_jvmti_vthread_unmount , notify_jvmti_vthread_Type , SharedRuntime::notify_jvmti_vthread_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);
Expand Down Expand Up @@ -491,6 +495,21 @@ const TypeFunc *OptoRuntime::notify_jvmti_object_alloc_Type() {

return TypeFunc::make(domain, range);
}

const TypeFunc *OptoRuntime::notify_jvmti_vthread_Type() {
// create input type (domain)
const Type **fields = TypeTuple::fields(2);
fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // VirtualThread oop
fields[TypeFunc::Parms+1] = TypeInt::BOOL; // jboolean
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2,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

const TypeFunc *OptoRuntime::athrow_Type() {
Expand Down Expand Up @@ -1670,24 +1689,6 @@ 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
14 changes: 9 additions & 5 deletions src/hotspot/share/opto/runtime.hpp
Expand Up @@ -137,8 +137,10 @@ class OptoRuntime : public AllStatic {
static address _register_finalizer_Java;
#if INCLUDE_JVMTI
static address _notify_jvmti_object_alloc;
static address _notify_jvmti_mount;
static address _notify_jvmti_unmount;
static address _notify_jvmti_vthread_start;
static address _notify_jvmti_vthread_end;
static address _notify_jvmti_vthread_mount;
static address _notify_jvmti_vthread_unmount;
#endif

//
Expand Down Expand Up @@ -215,8 +217,10 @@ class OptoRuntime : public AllStatic {
static address register_finalizer_Java() { return _register_finalizer_Java; }
#if INCLUDE_JVMTI
static address notify_jvmti_object_alloc() { return _notify_jvmti_object_alloc; }
static address notify_jvmti_mount() { return _notify_jvmti_mount; }
static address notify_jvmti_unmount() { return _notify_jvmti_unmount; }
static address notify_jvmti_vthread_start() { return _notify_jvmti_vthread_start; }
static address notify_jvmti_vthread_end() { return _notify_jvmti_vthread_end; }
static address notify_jvmti_vthread_mount() { return _notify_jvmti_vthread_mount; }
static address notify_jvmti_vthread_unmount() { return _notify_jvmti_vthread_unmount; }
#endif

static ExceptionBlob* exception_blob() { return _exception_blob; }
Expand Down Expand Up @@ -306,7 +310,7 @@ class OptoRuntime : public AllStatic {
JFR_ONLY(static const TypeFunc* class_id_load_barrier_Type();)
#if INCLUDE_JVMTI
static const TypeFunc* notify_jvmti_object_alloc_Type();
static const TypeFunc* notify_jvmti_Type();
static const TypeFunc* notify_jvmti_vthread_Type();
#endif

// Dtrace support
Expand Down
62 changes: 43 additions & 19 deletions src/hotspot/share/prims/jvm.cpp
Expand Up @@ -3910,48 +3910,72 @@ JVM_LEAF(jint, JVM_FindSignal(const char *name))
return os::get_signal_number(name);
JVM_END

// 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))
JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread))
#if INCLUDE_JVMTI
if (!DoJVMTIVirtualThreadTransitions) {
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
return;
}
if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
thread->set_is_in_VTMS_transition(hide);
oop vt = JNIHandles::resolve_external_guard(vthread);
java_lang_Thread::set_is_in_VTMS_transition(vt, hide);
if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread);
} else {
// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false);
}
#else
fatal("Should only be called with JVMTI enabled");
#endif
JVM_END

JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread))
#if INCLUDE_JVMTI
if (!DoJVMTIVirtualThreadTransitions) {
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
return;
}
if (hide) {
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(vthread, first_mount);
if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread);
} else {
JvmtiVTMSTransitionDisabler::VTMS_mount_end(vthread, first_mount);
// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true);
}
#else
fatal("Should only be called with JVMTI enabled");
#endif
JVM_END

// 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))
// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call.
JVM_ENTRY(void, JVM_VirtualThreadMount(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()) {
thread->set_is_in_VTMS_transition(hide);
oop vt = JNIHandles::resolve_external_guard(vthread);
java_lang_Thread::set_is_in_VTMS_transition(vt, hide);
if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide);
} else {
// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide);
}
#else
fatal("Should only be called with JVMTI enabled");
#endif
JVM_END

// 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))
#if INCLUDE_JVMTI
if (!DoJVMTIVirtualThreadTransitions) {
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
return;
}
if (hide) {
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(vthread, last_unmount);
if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide);
} else {
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(vthread, last_unmount);
// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object
JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide);
}
#else
fatal("Should only be called with JVMTI enabled");
Expand Down

1 comment on commit 1227a27

@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.