diff --git a/runtime/j9vm/javanextvmi.cpp b/runtime/j9vm/javanextvmi.cpp index 6fd60862d8d..2ea88f277a1 100644 --- a/runtime/j9vm/javanextvmi.cpp +++ b/runtime/j9vm/javanextvmi.cpp @@ -258,7 +258,7 @@ JVM_VirtualThreadMountBegin(JNIEnv *env, jobject thread, jboolean firstMount) f_monitorEnter(vm->liveVirtualThreadListMutex); j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread); - assert(IS_VIRTUAL_THREAD(currentThread, threadObj)); + assert(IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObj)); while (0 != J9OBJECT_I64_LOAD(currentThread, threadObj, vm->virtualThreadInspectorCountOffset)) { /* Thread is being inspected or unmounted, wait. */ diff --git a/runtime/jcl/common/thread.cpp b/runtime/jcl/common/thread.cpp index f5e5497c7a5..d8420160a16 100644 --- a/runtime/jcl/common/thread.cpp +++ b/runtime/jcl/common/thread.cpp @@ -335,7 +335,7 @@ Java_java_lang_Thread_getStackTraceImpl(JNIEnv *env, jobject rcv) #if JAVA_SPEC_VERSION >= 19 BOOLEAN releaseInspector = FALSE; - if (IS_VIRTUAL_THREAD(currentThread, receiverObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, receiverObject)) { omrthread_monitor_enter(vm->liveVirtualThreadListMutex); j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, receiverObject); I_64 vthreadInspectorCount = J9OBJECT_I64_LOAD(currentThread, receiverObject, vm->virtualThreadInspectorCountOffset); diff --git a/runtime/jvmti/jvmtiExtensionMechanism.c b/runtime/jvmti/jvmtiExtensionMechanism.c index 7a07ce3db1a..087d347a10f 100644 --- a/runtime/jvmti/jvmtiExtensionMechanism.c +++ b/runtime/jvmti/jvmtiExtensionMechanism.c @@ -1465,13 +1465,14 @@ jvmtiGetOSThreadID(jvmtiEnv* jvmti_env, ...) ENSURE_PHASE_START_OR_LIVE(jvmti_env); ENSURE_NON_NULL(threadid_ptr); + rc = getVMThread( + currentThread, thread, &targetThread, #if JAVA_SPEC_VERSION >= 19 - if (NULL != thread) { - ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_UNSUPPORTED_OPERATION); - } + JVMTI_ERROR_UNSUPPORTED_OPERATION, +#else /* JAVA_SPEC_VERSION >= 19 */ + JVMTI_ERROR_NONE, #endif /* JAVA_SPEC_VERSION >= 19 */ - - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD); if (rc == JVMTI_ERROR_NONE) { rv_threadid = (jlong) omrthread_get_osId(targetThread->osThread); releaseVMThread(currentThread, targetThread, thread); @@ -1524,7 +1525,9 @@ jvmtiGetStackTraceExtended(jvmtiEnv* env, ...) ENSURE_NON_NULL(frame_buffer); ENSURE_NON_NULL(count_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread); @@ -3455,10 +3458,11 @@ jvmtiGetJ9vmThread(jvmtiEnv *env, ...) vm->internalVMFunctions->internalEnterVMFromJNI(currentThread); ENSURE_PHASE_START_OR_LIVE(env); - ENSURE_JTHREAD_NON_NULL(thread); ENSURE_NON_NULL(vmThreadPtr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { rv_vmThread = targetThread; releaseVMThread(currentThread, targetThread, thread); diff --git a/runtime/jvmti/jvmtiForceEarlyReturn.c b/runtime/jvmti/jvmtiForceEarlyReturn.c index e7b1dad929a..4e2adeabb66 100644 --- a/runtime/jvmti/jvmtiForceEarlyReturn.c +++ b/runtime/jvmti/jvmtiForceEarlyReturn.c @@ -144,18 +144,10 @@ jvmtiForceEarlyReturn(jvmtiEnv* env, ENSURE_PHASE_LIVE(env); ENSURE_CAPABILITY(env, can_force_early_return); - - /* Check if the jthread is really a j.l.Thread. a NULL jthread indicates that - * the user wants to use the current thread hence defer the assignment to getVMThread */ - - if (NULL != thread) { - ENSURE_JTHREAD(currentThread, thread); -#if JAVA_SPEC_VERSION >= 19 - ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_OPAQUE_FRAME); -#endif /* JAVA_SPEC_VERSION >= 19 */ - } - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_OPAQUE_FRAME, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD); if (rc == JVMTI_ERROR_NONE) { /* Does this thread need to be suspended at an event? */ vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread); diff --git a/runtime/jvmti/jvmtiHelpers.c b/runtime/jvmti/jvmtiHelpers.c index 1912cc5a6c5..c19237bbae1 100644 --- a/runtime/jvmti/jvmtiHelpers.c +++ b/runtime/jvmti/jvmtiHelpers.c @@ -95,7 +95,7 @@ static UDATA watchedClassEqual (void *lhsEntry, void *rhsEntry, void *userData); jvmtiError -getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, UDATA allowNull, UDATA mustBeAlive) +getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, jvmtiError vThreadError, UDATA flags) { J9JavaVM *vm = currentThread->javaVM; j9object_t threadObject = NULL; @@ -106,13 +106,30 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, #endif /* JAVA_SPEC_VERSION >= 19 */ if (NULL == thread) { - if (allowNull) { - *vmThreadPtr = currentThread; - return JVMTI_ERROR_NONE; + if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD)) { + return JVMTI_ERROR_INVALID_THREAD; + } +#if JAVA_SPEC_VERSION >= 19 + if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD) + && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, currentThread->threadObject) + ) { + return vThreadError; } - return JVMTI_ERROR_INVALID_THREAD; +#endif /* JAVA_SPEC_VERSION >= 19 */ + *vmThreadPtr = currentThread; + return JVMTI_ERROR_NONE; } else { threadObject = J9_JNI_UNWRAP_REFERENCE(thread); + if (!IS_JAVA_LANG_THREAD(currentThread, threadObject)) { + return JVMTI_ERROR_INVALID_THREAD; + } +#if JAVA_SPEC_VERSION >= 19 + if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD) + && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject) + ) { + return vThreadError; + } +#endif /* JAVA_SPEC_VERSION >= 19 */ if (currentThread->threadObject == threadObject) { *vmThreadPtr = currentThread; return JVMTI_ERROR_NONE; @@ -122,7 +139,7 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, /* Make sure the vmThread stays alive while it is being used. */ omrthread_monitor_enter(vm->vmThreadListMutex); #if JAVA_SPEC_VERSION >= 19 - isVirtualThread = IS_VIRTUAL_THREAD(currentThread, threadObject); + isVirtualThread = IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject); if (isVirtualThread) { omrthread_monitor_enter(vm->liveVirtualThreadListMutex); @@ -148,7 +165,7 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, } if (!isThreadAlive) { - if (mustBeAlive) { + if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD)) { #if JAVA_SPEC_VERSION >= 19 if (isVirtualThread) { omrthread_monitor_exit(vm->liveVirtualThreadListMutex); @@ -174,8 +191,9 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, omrthread_monitor_exit(vm->vmThreadListMutex); #if JAVA_SPEC_VERSION >= 19 - if (mustBeAlive) { - Assert_JVMTI_true((NULL != targetThread) || isVirtualThread); + if (isThreadAlive && !isVirtualThread) { + /* targetThread should not be NULL for alive non-virtual threads. */ + Assert_JVMTI_true(NULL != targetThread); } #endif /* JAVA_SPEC_VERSION >= 19 */ @@ -190,7 +208,7 @@ releaseVMThread(J9VMThread *currentThread, J9VMThread *targetThread, jthread thr #if JAVA_SPEC_VERSION >= 19 if (NULL != thread) { j9object_t threadObject = J9_JNI_UNWRAP_REFERENCE(thread); - if ((currentThread->threadObject != threadObject) && IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if ((currentThread->threadObject != threadObject) && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { J9JavaVM *vm = currentThread->javaVM; I_64 vthreadInspectorCount = 0; /* Release the virtual thread (allow it to die) now that we are no longer inspecting it. */ @@ -788,7 +806,10 @@ getVirtualThreadState(J9VMThread *currentThread, jthread thread) J9VMThread *targetThread = NULL; Assert_JVMTI_notNull(thread); Assert_JVMTI_mustHaveVMAccess(currentThread); - if (JVMTI_ERROR_NONE == getVMThread(currentThread, thread, &targetThread, FALSE, FALSE)) { + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD); + if (JVMTI_ERROR_NONE == rc) { if (NULL != targetThread) { vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread); rc = getThreadState(currentThread, targetThread->carrierThreadObject); @@ -1604,7 +1625,9 @@ setEventNotificationMode(J9JVMTIEnv * j9env, J9VMThread * currentThread, jint mo } else { j9object_t threadObject = J9_JNI_UNWRAP_REFERENCE(event_thread); J9VMThread *vmThreadForTLS = NULL; - rc = getVMThread(currentThread, event_thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, event_thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc != JVMTI_ERROR_NONE) { goto done; } @@ -1616,10 +1639,10 @@ setEventNotificationMode(J9JVMTIEnv * j9env, J9VMThread * currentThread, jint mo goto done; } if (NULL == targetThread) { - /* targetThread is NULL only for virtual threads, as per the assertion in getVMThread, - * when mustBeAlive is TRUE. vmThreadForTLS is only used to acquire J9JavaVM in - * createThreadData and jvmtiTLSGet. If targetThread is NULL, currentThread is passed - * to createThreadData and jvmtiTLSGet for retrieving J9JavaVM in JDK19+. + /* targetThread is NULL only for virtual threads, as per the assertion in getVMThread. + * vmThreadForTLS is only used to acquire J9JavaVM in createThreadData and jvmtiTLSGet. + * If targetThread is NULL, currentThread is passed to createThreadData and jvmtiTLSGet + * for retrieving J9JavaVM in JDK19+. */ vmThreadForTLS = currentThread; } @@ -1915,7 +1938,7 @@ genericWalkStackFramesHelper(J9VMThread *currentThread, J9VMThread *targetThread UDATA rc = J9_STACKWALK_RC_NONE; #if JAVA_SPEC_VERSION >= 19 - if (IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { if (NULL != targetThread) { walkState->walkThread = targetThread; rc = vm->walkStackFrames(currentThread, walkState); @@ -1947,7 +1970,7 @@ J9VMContinuation * getJ9VMContinuationToWalk(J9VMThread *currentThread, J9VMThread *targetThread, j9object_t threadObject) { J9VMContinuation *continuation = NULL; - if (IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { if (NULL == targetThread) { /* An unmounted virtual thread will have a valid J9VMContinuation. */ j9object_t contObject = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, threadObject); diff --git a/runtime/jvmti/jvmtiLocalVariable.c b/runtime/jvmti/jvmtiLocalVariable.c index f6ce04e8d78..faf5bc5bc9f 100644 --- a/runtime/jvmti/jvmtiLocalVariable.c +++ b/runtime/jvmti/jvmtiLocalVariable.c @@ -311,7 +311,9 @@ jvmtiGetOrSetLocal(jvmtiEnv *env, J9VMThread *targetThread = NULL; vm->internalVMFunctions->internalEnterVMFromJNI(currentThread); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { J9StackWalkState walkState = {0}; BOOLEAN objectFetched = FALSE; diff --git a/runtime/jvmti/jvmtiStackFrame.c b/runtime/jvmti/jvmtiStackFrame.c index 21ca771536e..019908e5ce5 100644 --- a/runtime/jvmti/jvmtiStackFrame.c +++ b/runtime/jvmti/jvmtiStackFrame.c @@ -58,7 +58,9 @@ jvmtiGetStackTrace(jvmtiEnv* env, ENSURE_NON_NULL(frame_buffer); ENSURE_NON_NULL(count_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); #if JAVA_SPEC_VERSION >= 19 @@ -216,9 +218,9 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* env, while (0 != thread_count) { jthread thread = *thread_list; - if ((NULL != thread) && IS_VIRTUAL_THREAD(currentThread, J9_JNI_UNWRAP_REFERENCE(thread))) { + if ((NULL != thread) && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, J9_JNI_UNWRAP_REFERENCE(thread))) { J9VMThread *targetThread = NULL; - getVMThread(currentThread, thread, &targetThread, TRUE, FALSE); + getVMThread(currentThread, thread, &targetThread, JVMTI_ERROR_NONE, 0); } ++thread_list; --thread_count; @@ -254,13 +256,13 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* env, } threadObject = J9_JNI_UNWRAP_REFERENCE(thread); - if (!isSameOrSuperClassOf(J9VMJAVALANGTHREAD_OR_NULL(vm), J9OBJECT_CLAZZ(currentThread, threadObject))) { + if (!IS_JAVA_LANG_THREAD(currentThread, threadObject)) { rc = JVMTI_ERROR_INVALID_THREAD; goto deallocate; } #if JAVA_SPEC_VERSION >= 19 - if (IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { isVirtual = TRUE; j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, threadObject); jint vthreadState = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, threadObject); @@ -323,7 +325,7 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* env, if (NULL != thread) { j9object_t threadObject = J9_JNI_UNWRAP_REFERENCE(thread); - if (IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { J9VMThread *targetThread = NULL; j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, threadObject); if (NULL != carrierThread) { @@ -371,7 +373,9 @@ jvmtiGetFrameCount(jvmtiEnv* env, ENSURE_NON_NULL(count_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); J9StackWalkState walkState; @@ -434,13 +438,9 @@ jvmtiPopFrame(jvmtiEnv* env, ENSURE_PHASE_LIVE(env); ENSURE_CAPABILITY(env, can_pop_frame); -#if JAVA_SPEC_VERSION >= 19 - if (NULL != thread) { - ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_OPAQUE_FRAME); - } -#endif /* JAVA_SPEC_VERSION >= 19 */ - - rc = getVMThread(currentThread, thread, &targetThread, FALSE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_OPAQUE_FRAME, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD); if (rc == JVMTI_ERROR_NONE) { /* Does this thread need to be suspended at an event? */ vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread); @@ -500,7 +500,9 @@ jvmtiGetFrameLocation(jvmtiEnv *env, ENSURE_NON_NULL(method_ptr); ENSURE_NON_NULL(location_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); J9StackWalkState walkState = {0}; @@ -574,7 +576,9 @@ jvmtiNotifyFramePop(jvmtiEnv *env, ENSURE_NON_NEGATIVE(depth); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { #if JAVA_SPEC_VERSION >= 19 BOOLEAN isVThreadSuspended = FALSE; diff --git a/runtime/jvmti/jvmtiThread.c b/runtime/jvmti/jvmtiThread.c index 42142992242..8272d1a569f 100644 --- a/runtime/jvmti/jvmtiThread.c +++ b/runtime/jvmti/jvmtiThread.c @@ -52,15 +52,14 @@ jvmtiGetThreadState(jvmtiEnv *env, if (JVMTI_ERROR_NONE == rc) { J9VMThread *targetThread = NULL; j9object_t threadObject = NULL; - j9object_t threadObjectLock = NULL; jboolean threadStartedFlag = JNI_FALSE; + vm->internalVMFunctions->internalEnterVMFromJNI(currentThread); ENSURE_PHASE_LIVE(env); ENSURE_NON_NULL(thread_state_ptr); if (NULL != thread) { - ENSURE_JTHREAD(currentThread, thread); threadObject = J9_JNI_UNWRAP_REFERENCE(thread); } else { /* If the thread is NULL, then use the current thread. */ @@ -68,7 +67,7 @@ jvmtiGetThreadState(jvmtiEnv *env, } #if JAVA_SPEC_VERSION >= 19 - if (IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { /* If thread is NULL, the current thread is used which cannot be a virtual thread. * There is an assertion inside getVirtualThreadState() that thread is not NULL. */ @@ -76,26 +75,21 @@ jvmtiGetThreadState(jvmtiEnv *env, } else #endif /* JAVA_SPEC_VERSION >= 19 */ { - /* Get the lock for the object. */ - threadObjectLock = J9VMJAVALANGTHREAD_LOCK(currentThread,threadObject); - - /* Get the vmThread for the object and whether the thread has been started, we get - * these under the thread object lock so that we get a consistent view of the two values. - */ - if (NULL != threadObjectLock) { - rc = getVMThread(currentThread, thread, &targetThread, TRUE, FALSE); - threadStartedFlag = (jboolean)J9VMJAVALANGTHREAD_STARTED(currentThread, threadObject); - } else { - /* In this case, we must be early in the thread creation. We still need to call getVMThread so that - * the inspection count etc. are handled correctly, however, we just want to fall into the case were - * we return that the thread is NEW so we set the targetThread and threadStartedFlag to false. - */ - rc = getVMThread(currentThread, thread, &targetThread, TRUE, FALSE); - targetThread = NULL; - threadStartedFlag = JNI_FALSE; - } - + rc = getVMThread(currentThread, thread, &targetThread, JVMTI_ERROR_NONE, 0); if (JVMTI_ERROR_NONE == rc) { + /* Get the lock for the object. */ + j9object_t threadObjectLock = J9VMJAVALANGTHREAD_LOCK(currentThread,threadObject); + if (NULL != threadObjectLock) { + threadStartedFlag = (jboolean)J9VMJAVALANGTHREAD_STARTED(currentThread, threadObject); + } else { + /* In this case, we must be early in the thread creation. We still need to call getVMThread so that + * the inspection count etc. are handled correctly, however, we just want to fall into the case were + * we return that the thread is NEW so we set the targetThread and threadStartedFlag to false. + */ + targetThread = NULL; + threadStartedFlag = JNI_FALSE; + } + /* We use the values of targetThread and threadStartedFlag that were obtained while holding the lock on the * thread so that get a consistent view of the values. This is needed because if we don't get a consistent view * we may think the thread is TERMINATED instead of just starting. @@ -367,12 +361,14 @@ jvmtiStopThread(jvmtiEnv *env, ENSURE_JOBJECT_NON_NULL(exception); - ENSURE_JTHREAD_NON_NULL(thread); + rc = getVMThread( + currentThread, thread, &targetThread, #if JAVA_SPEC_VERSION >= 19 - ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_UNSUPPORTED_OPERATION); + JVMTI_ERROR_UNSUPPORTED_OPERATION, +#else /* JAVA_SPEC_VERSION >= 19 */ + JVMTI_ERROR_NONE, #endif /* JAVA_SPEC_VERSION >= 19 */ - - rc = getVMThread(currentThread, thread, &targetThread, FALSE, TRUE); + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD); if (JVMTI_ERROR_NONE == rc) { omrthread_monitor_enter(targetThread->publicFlagsMutex); if (OMR_ARE_NO_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_STOPPED)) { @@ -410,7 +406,9 @@ jvmtiInterruptThread(jvmtiEnv *env, ENSURE_PHASE_LIVE(env); ENSURE_CAPABILITY(env, can_signal_thread); - rc = getVMThread(currentThread, thread, &targetThread, FALSE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { #if JAVA_SPEC_VERSION >= 19 if (NULL != targetThread) @@ -458,7 +456,7 @@ jvmtiGetThreadInfo(jvmtiEnv *env, ENSURE_PHASE_LIVE(env); ENSURE_NON_NULL(info_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, FALSE); + rc = getVMThread(currentThread, thread, &targetThread, JVMTI_ERROR_NONE, 0); if (JVMTI_ERROR_NONE == rc) { char *name = NULL; j9object_t threadObject = (NULL == thread) ? targetThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); @@ -466,7 +464,7 @@ jvmtiGetThreadInfo(jvmtiEnv *env, jobject contextClassLoader = NULL; #if JAVA_SPEC_VERSION >= 19 j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, threadObject); - BOOLEAN isVirtual = IS_VIRTUAL_THREAD(currentThread, threadObject); + BOOLEAN isVirtual = IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject); #endif /* JAVA_SPEC_VERSION >= 19 */ if ((NULL == targetThread) @@ -650,7 +648,9 @@ jvmtiGetOwnedMonitorInfo(jvmtiEnv *env, ENSURE_NON_NULL(owned_monitor_count_ptr); ENSURE_NON_NULL(owned_monitors_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { jobject *locks = NULL; jint count = 0; @@ -662,7 +662,7 @@ jvmtiGetOwnedMonitorInfo(jvmtiEnv *env, j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); J9VMContinuation *continuation = NULL; - if ((NULL == targetThread) && IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if ((NULL == targetThread) && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { goto release; } #endif /* JAVA_SPEC_VERSION >= 19 */ @@ -738,14 +738,12 @@ jvmtiGetOwnedMonitorStackDepthInfo(jvmtiEnv *env, ENSURE_NON_NULL(monitor_info_count_ptr); ENSURE_NON_NULL(monitor_info_ptr); - - if (NULL != thread) { - ENSURE_JTHREAD(currentThread, thread); - } rv_monitor_info_count = 0; - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { IDATA maxRecords = 0; J9ObjectMonitorInfo *monitorEnterRecords = NULL; @@ -758,7 +756,7 @@ jvmtiGetOwnedMonitorStackDepthInfo(jvmtiEnv *env, j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); J9VMContinuation *continuation = NULL; - if ((NULL == targetThread) && IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if ((NULL == targetThread) && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { goto release; } #endif /* JAVA_SPEC_VERSION >= 19 */ @@ -873,7 +871,9 @@ jvmtiGetCurrentContendedMonitor(jvmtiEnv *env, ENSURE_NON_NULL(monitor_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { j9object_t lockObject = NULL; UDATA vmstate = 0; @@ -885,7 +885,7 @@ jvmtiGetCurrentContendedMonitor(jvmtiEnv *env, j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); J9VMContinuation *continuation = NULL; - if ((NULL == targetThread) && IS_VIRTUAL_THREAD(currentThread, threadObject)) { + if ((NULL == targetThread) && IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject)) { goto release; } #endif /* JAVA_SPEC_VERSION >= 19 */ @@ -950,7 +950,8 @@ jvmtiRunAgentThread(jvmtiEnv *env, ENSURE_PHASE_LIVE(env); - ENSURE_JTHREAD_NON_NULL(thread); + ENSURE_JOBJECT_NON_NULL(thread); + ENSURE_JTHREAD(currentThread, thread); #if JAVA_SPEC_VERSION >= 19 ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_UNSUPPORTED_OPERATION); #endif /* JAVA_SPEC_VERSION >= 19 */ @@ -1016,7 +1017,9 @@ jvmtiSetThreadLocalStorage(jvmtiEnv *env, ENSURE_PHASE_START_OR_LIVE(env); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { J9JVMTIEnv *j9env = (J9JVMTIEnv *)env; J9JVMTIThreadData *threadData = NULL; @@ -1076,7 +1079,9 @@ jvmtiGetThreadLocalStorage(jvmtiEnv *env, ENSURE_NON_NULL(data_ptr); - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { J9JVMTIEnv *j9env = (J9JVMTIEnv *)env; J9JVMTIThreadData *threadData = NULL; @@ -1118,7 +1123,9 @@ static jvmtiError resumeThread(J9VMThread *currentThread, jthread thread) { J9VMThread *targetThread = NULL; - jvmtiError rc = getVMThread(currentThread, thread, &targetThread, FALSE, TRUE); + jvmtiError rc = getVMThread( + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (JVMTI_ERROR_NONE == rc) { if (targetThread->publicFlags & J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND) { clearHaltFlag(targetThread, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND); diff --git a/runtime/jvmti/jvmtiThreadGroup.c b/runtime/jvmti/jvmtiThreadGroup.c index b795562e0d7..ec206b3b9f9 100644 --- a/runtime/jvmti/jvmtiThreadGroup.c +++ b/runtime/jvmti/jvmtiThreadGroup.c @@ -302,7 +302,10 @@ getThreadGroupChildrenImpl(J9JavaVM *vm, J9VMThread *currentThread, jobject grou j9object_t thread = J9JAVAARRAYOFOBJECT_LOAD(currentThread, childrenThreads, i); J9VMThread *targetThread = NULL; - if (JVMTI_ERROR_NONE == getVMThread(currentThread, (jthread)&thread, &targetThread, FALSE, TRUE)) { + rc = getVMThread( + currentThread, (jthread)&thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); + if (JVMTI_ERROR_NONE == rc) { threads[numLiveThreads++] = (jthread)vmFuncs->j9jni_createLocalRef((JNIEnv *)currentThread, thread); releaseVMThread(currentThread, targetThread, (jthread)&thread); } diff --git a/runtime/jvmti/jvmtiTimers.c b/runtime/jvmti/jvmtiTimers.c index fa1da57db5d..93973ad051c 100644 --- a/runtime/jvmti/jvmtiTimers.c +++ b/runtime/jvmti/jvmtiTimers.c @@ -146,10 +146,14 @@ jvmtiGetThreadCpuTime(jvmtiEnv* env, ENSURE_NON_NULL(nanos_ptr); rv_nanos = (jlong)omrthread_get_cpu_time(omrthread_self()); } else { + rc = getVMThread( + currentThread, thread, &targetThread, #if JAVA_SPEC_VERSION >= 19 - ENSURE_JTHREAD_NOT_VIRTUAL(currentThread, thread, JVMTI_ERROR_UNSUPPORTED_OPERATION); + JVMTI_ERROR_UNSUPPORTED_OPERATION, +#else /* JAVA_SPEC_VERSION >= 19 */ + JVMTI_ERROR_NONE, #endif /* JAVA_SPEC_VERSION >= 19 */ - rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE); + J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD); if (rc == JVMTI_ERROR_NONE) { if (nanos_ptr == NULL) { rc = JVMTI_ERROR_NULL_POINTER; diff --git a/runtime/jvmti/jvmti_internal.h b/runtime/jvmti/jvmti_internal.h index a5883330a1e..70257241cea 100644 --- a/runtime/jvmti/jvmti_internal.h +++ b/runtime/jvmti/jvmti_internal.h @@ -1205,16 +1205,17 @@ getVirtualThreadState(J9VMThread *currentThread, jthread thread); #endif /* JAVA_SPEC_VERSION >= 19 */ /** - * @brief - * @param currentThread - * @param thread - * @param vmThreadPtr - * @param allowNull - * @param mustBeAlive - * @return jvmtiError + * @brief Get the J9VMThread for the input jthread instance. + * + * @param[in] currentThread the current thread. + * @param[in] thread the input jthread instance. + * @param[out] vmThreadPtr stores the corresponding J9VMThread for the input thread parameter. + * @param[in] vThreadError error to be thrown if virtual threads are excluded. + * @param[in] flags specifies the control logic for error checking. + * @return JVMTI_ERROR_NONE (0) on success; otherwise a non-zero error value on failure. */ jvmtiError -getVMThread(J9VMThread * currentThread, jthread thread, J9VMThread ** vmThreadPtr, UDATA allowNull, UDATA mustBeAlive); +getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, jvmtiError vThreadError, UDATA flags); /** @@ -2723,7 +2724,7 @@ jvmtiIsModifiableModule(jvmtiEnv* env, * @return jvmtiError */ jvmtiError -suspendThread(J9VMThread *currentThread, jthread thread, UDATA allowNull, BOOLEAN *currentThreadSuspended); +suspendThread(J9VMThread *currentThread, jthread thread, BOOLEAN allowNull, BOOLEAN *currentThreadSuspended); /* ---------------- heapify.cpp ---------------- */ /** diff --git a/runtime/jvmti/suspendhelper.cpp b/runtime/jvmti/suspendhelper.cpp index 4acca93b25c..23851a8750a 100644 --- a/runtime/jvmti/suspendhelper.cpp +++ b/runtime/jvmti/suspendhelper.cpp @@ -27,13 +27,17 @@ extern "C" { jvmtiError -suspendThread(J9VMThread *currentThread, jthread thread, UDATA allowNull, BOOLEAN *currentThreadSuspended) +suspendThread(J9VMThread *currentThread, jthread thread, BOOLEAN allowNull, BOOLEAN *currentThreadSuspended) { J9VMThread *targetThread = NULL; jvmtiError rc = JVMTI_ERROR_NONE; + UDATA flags = J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD; *currentThreadSuspended = FALSE; - rc = getVMThread(currentThread, thread, &targetThread, allowNull, TRUE); + if (!allowNull) { + flags |= J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD; + } + rc = getVMThread(currentThread, thread, &targetThread, JVMTI_ERROR_NONE, flags); if (rc == JVMTI_ERROR_NONE) { if (targetThread->publicFlags & J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND) { rc = JVMTI_ERROR_THREAD_SUSPENDED; diff --git a/runtime/oti/j9.h b/runtime/oti/j9.h index e3de0a163f4..880a3b74540 100644 --- a/runtime/oti/j9.h +++ b/runtime/oti/j9.h @@ -356,9 +356,12 @@ static const struct { \ #define J9_IS_HIDDEN_METHOD(method) \ ((NULL != (method)) && (J9ROMCLASS_IS_ANON_OR_HIDDEN(J9_CLASS_FROM_METHOD((method))->romClass) || J9_ARE_ANY_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD((method))->modifiers, J9AccMethodFrameIteratorSkip))) -#define IS_VIRTUAL_THREAD(vmThread, object) \ +#define IS_JAVA_LANG_VIRTUALTHREAD(vmThread, object) \ isSameOrSuperClassOf(J9VMJAVALANGBASEVIRTUALTHREAD((vmThread)->javaVM), J9OBJECT_CLAZZ(vmThread, object)) +#define IS_JAVA_LANG_THREAD(vmThread, object) \ + isSameOrSuperClassOf(J9VMJAVALANGTHREAD_OR_NULL((vmThread)->javaVM), J9OBJECT_CLAZZ(vmThread, object)) + #if defined(OPENJ9_BUILD) #define J9_SHARED_CACHE_DEFAULT_BOOT_SHARING(vm) TRUE #else /* defined(OPENJ9_BUILD) */ diff --git a/runtime/oti/jvmtiInternal.h b/runtime/oti/jvmtiInternal.h index d8f739ab1da..1ab74b5ff5d 100644 --- a/runtime/oti/jvmtiInternal.h +++ b/runtime/oti/jvmtiInternal.h @@ -61,6 +61,9 @@ typedef enum { #define J9JVMTI_UDATA_BITS (sizeof(UDATA) * 8) +#define J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD 0x1 +#define J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD 0x2 +#define J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD 0x4 typedef struct { J9NativeLibrary nativeLib; @@ -454,13 +457,12 @@ typedef struct jvmtiGcp_translation { #define ENSURE_JOBJECT_NON_NULL(var) ENSURE_JNI_OBJECT_NON_NULL((var), JVMTI_ERROR_INVALID_OBJECT) #define ENSURE_JCLASS_NON_NULL(var) ENSURE_JNI_OBJECT_NON_NULL((var), JVMTI_ERROR_INVALID_CLASS) -#define ENSURE_JTHREAD_NON_NULL(var) ENSURE_JNI_OBJECT_NON_NULL((var), JVMTI_ERROR_INVALID_THREAD) #define ENSURE_JTHREADGROUP_NON_NULL(var) ENSURE_JNI_OBJECT_NON_NULL((var), JVMTI_ERROR_INVALID_THREAD_GROUP) #define ENSURE_JOBJECT_NON_NULL(var) ENSURE_JNI_OBJECT_NON_NULL((var), JVMTI_ERROR_INVALID_OBJECT) #define ENSURE_JTHREAD(vmThread, jthrd) \ do { \ - if (!isSameOrSuperClassOf(J9VMJAVALANGTHREAD_OR_NULL((vmThread->javaVM)), J9OBJECT_CLAZZ((vmThread), *((j9object_t *) (jthrd))))) { \ + if (!IS_JAVA_LANG_THREAD((vmThread), J9_JNI_UNWRAP_REFERENCE(jthrd))) { \ JVMTI_ERROR(JVMTI_ERROR_INVALID_THREAD); \ } \ } while(0) @@ -489,14 +491,14 @@ typedef struct jvmtiGcp_translation { #if JAVA_SPEC_VERSION >= 19 #define ENSURE_JTHREAD_NOT_VIRTUAL(vmThread, jthrd, error) \ do { \ - if (IS_VIRTUAL_THREAD((vmThread), J9_JNI_UNWRAP_REFERENCE(jthrd))) { \ + if (IS_JAVA_LANG_VIRTUALTHREAD((vmThread), J9_JNI_UNWRAP_REFERENCE(jthrd))) { \ JVMTI_ERROR(error); \ } \ } while(0) #define ENSURE_JTHREADOBJECT_NOT_VIRTUAL(vmThread, jthrdObject, error) \ do { \ - if (IS_VIRTUAL_THREAD((vmThread), (jthrdObject))) { \ + if (IS_JAVA_LANG_VIRTUALTHREAD((vmThread), (jthrdObject))) { \ JVMTI_ERROR(error); \ } \ } while(0) @@ -515,7 +517,6 @@ typedef struct jvmtiGcp_translation { #define ENSURE_JFIELDID_NON_NULL(var) #define ENSURE_JOBJECT_NON_NULL(var) #define ENSURE_JCLASS_NON_NULL(var) -#define ENSURE_JTHREAD_NON_NULL(var) #define ENSURE_JTHREADGROUP_NON_NULL(var) #define ENSURE_VALID_HEAP_OBJECT_FILTER(var) #define ENSURE_MONITOR_NON_NULL(var) diff --git a/runtime/vm/jnicsup.cpp b/runtime/vm/jnicsup.cpp index 2d2c1df869e..c556d5c0eb6 100644 --- a/runtime/vm/jnicsup.cpp +++ b/runtime/vm/jnicsup.cpp @@ -2492,7 +2492,7 @@ isVirtualThread(JNIEnv *env, jobject obj) if (NULL != obj) { VM_VMAccess::inlineEnterVMFromJNI(vmThread); j9object_t object = J9_JNI_UNWRAP_REFERENCE(obj); - if ((NULL != object) && IS_VIRTUAL_THREAD(vmThread, object)) { + if ((NULL != object) && IS_JAVA_LANG_VIRTUALTHREAD(vmThread, object)) { result = JNI_TRUE; } VM_VMAccess::inlineExitVMToJNI(vmThread);