diff --git a/runtime/j9vm/javanextvmi.cpp b/runtime/j9vm/javanextvmi.cpp index 5474dc3a701..fa426f76e43 100644 --- a/runtime/j9vm/javanextvmi.cpp +++ b/runtime/j9vm/javanextvmi.cpp @@ -325,49 +325,25 @@ JVM_VirtualThreadMountEnd(JNIEnv *env, jobject thread, jboolean firstMount) } if (firstMount) { - if (NULL == vm->liveVirtualThreadList) { - J9Class *virtualThreadClass = J9OBJECT_CLAZZ(currentThread, J9_JNI_UNWRAP_REFERENCE(thread)); - J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions; - - /* Allocate empty virtual thread and create a global reference to it as root for the linked list. - * This prevents the root reference from becoming stale if the GC moves the object. - */ - j9object_t rootVirtualThread = mmFuncs->J9AllocateObject(currentThread, virtualThreadClass, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); - if (NULL != rootVirtualThread) { - /* The global ref will be freed at vm death. */ - jobject globalRef = vmFuncs->j9jni_createGlobalRef((JNIEnv *)currentThread, rootVirtualThread, JNI_FALSE); - if (NULL != globalRef) { - vm->liveVirtualThreadList = (j9object_t *)globalRef; - - /* Set linkNext/linkPrevious to itself. */ - J9OBJECT_OBJECT_STORE(currentThread, rootVirtualThread, vm->virtualThreadLinkNextOffset, rootVirtualThread); - J9OBJECT_OBJECT_STORE(currentThread, rootVirtualThread, vm->virtualThreadLinkPreviousOffset, rootVirtualThread); - } else { - vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0); - } - } else { - vmFuncs->setHeapOutOfMemoryError(currentThread); - } - } - - if (NULL != vm->liveVirtualThreadList) { - j9object_t threadPrev = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset); - j9object_t threadNext = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkNextOffset); - - /* Non-null previous and next elements in the list suggest that the thread has - * already been added to the list. Only add to the list if the previous and - * next elements in the list are null. - */ - Assert_SC_true((NULL == threadPrev) && (NULL == threadNext)); - j9object_t root = *(vm->liveVirtualThreadList); - j9object_t rootPrev = J9OBJECT_OBJECT_LOAD(currentThread, root, vm->virtualThreadLinkPreviousOffset); - - /* Add thread to the end of the list. */ - J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkNextOffset, root); - J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset, rootPrev); - J9OBJECT_OBJECT_STORE(currentThread, rootPrev, vm->virtualThreadLinkNextOffset, threadObj); - J9OBJECT_OBJECT_STORE(currentThread, root, vm->virtualThreadLinkPreviousOffset, threadObj); - } + /* vm->liveVirtualThreadList should be initialized in stdinit.c::standardInit. */ + Assert_SC_true(NULL != vm->liveVirtualThreadList); + + j9object_t threadPrev = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset); + j9object_t threadNext = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkNextOffset); + + /* Non-null previous and next elements in the list suggest that the thread has + * already been added to the list. Only add to the list if the previous and + * next elements in the list are null. + */ + Assert_SC_true((NULL == threadPrev) && (NULL == threadNext)); + j9object_t root = *(vm->liveVirtualThreadList); + j9object_t rootPrev = J9OBJECT_OBJECT_LOAD(currentThread, root, vm->virtualThreadLinkPreviousOffset); + + /* Add thread to the end of the list. */ + J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkNextOffset, root); + J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset, rootPrev); + J9OBJECT_OBJECT_STORE(currentThread, rootPrev, vm->virtualThreadLinkNextOffset, threadObj); + J9OBJECT_OBJECT_STORE(currentThread, root, vm->virtualThreadLinkPreviousOffset, threadObj); TRIGGER_J9HOOK_VM_VIRTUAL_THREAD_STARTED(vm->hookInterface, currentThread); } @@ -439,23 +415,24 @@ JVM_VirtualThreadUnmountBegin(JNIEnv *env, jobject thread, jboolean lastUnmount) J9OBJECT_I64_STORE(currentThread, threadObj, vm->virtualThreadInspectorCountOffset, -1); if (lastUnmount) { - if (NULL != vm->liveVirtualThreadList) { - j9object_t threadPrev = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset); - j9object_t threadNext = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkNextOffset); - - /* Non-null previous and next elements in the list suggest that the thread has - * been added to the list. Only remove from the list if the previous and next - * elements in the list are non-null. - */ - Assert_SC_true((NULL != threadPrev) && (NULL != threadNext)); - /* Remove thread from the list. The root will never be removed. */ - J9OBJECT_OBJECT_STORE(currentThread, threadPrev, vm->virtualThreadLinkNextOffset, threadNext); - J9OBJECT_OBJECT_STORE(currentThread, threadNext, vm->virtualThreadLinkPreviousOffset, threadPrev); - - /* Reset previous and next fields in the thread object to null. */ - J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkNextOffset, NULL); - J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset, NULL); - } + /* vm->liveVirtualThreadList should be initialized in stdinit.c::standardInit. */ + Assert_SC_true(NULL != vm->liveVirtualThreadList); + + j9object_t threadPrev = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset); + j9object_t threadNext = J9OBJECT_OBJECT_LOAD(currentThread, threadObj, vm->virtualThreadLinkNextOffset); + + /* Non-null previous and next elements in the list suggest that the thread has + * been added to the list. Only remove from the list if the previous and next + * elements in the list are non-null. + */ + Assert_SC_true((NULL != threadPrev) && (NULL != threadNext)); + /* Remove thread from the list. The root will never be removed. */ + J9OBJECT_OBJECT_STORE(currentThread, threadPrev, vm->virtualThreadLinkNextOffset, threadNext); + J9OBJECT_OBJECT_STORE(currentThread, threadNext, vm->virtualThreadLinkPreviousOffset, threadPrev); + + /* Reset previous and next fields in the thread object to null. */ + J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkNextOffset, NULL); + J9OBJECT_OBJECT_STORE(currentThread, threadObj, vm->virtualThreadLinkPreviousOffset, NULL); TRIGGER_J9HOOK_VM_VIRTUAL_THREAD_END(vm->hookInterface, currentThread); } diff --git a/runtime/jcl/common/stdinit.c b/runtime/jcl/common/stdinit.c index 142b2179766..c6c890cc7b5 100644 --- a/runtime/jcl/common/stdinit.c +++ b/runtime/jcl/common/stdinit.c @@ -319,6 +319,39 @@ standardInit(J9JavaVM *vm, char *dllName) } else { goto _fail; } + + /* vm->liveVirtualThreadList should not be set at this point. */ + if (NULL != vm->liveVirtualThreadList) { + goto _fail; + } + + /* vm->liveVirtualThreadList is maintained in javanextvmi.cpp::JVM_VirtualThread* functions. */ + clazz = (*(JNIEnv*)vmThread)->FindClass((JNIEnv*)vmThread, "java/lang/VirtualThread"); + if (NULL != clazz) { + J9Class *virtualThreadClass = J9VM_J9CLASS_FROM_JCLASS(vmThread, clazz); + + /* Allocate empty virtual thread and create a global reference to it as root for the linked list. + * This prevents the root reference from becoming stale if the GC moves the object. + */ + j9object_t rootVirtualThread = vm->memoryManagerFunctions->J9AllocateObject(vmThread, virtualThreadClass, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE); + if (NULL != rootVirtualThread) { + /* The global ref will be freed at VM death. */ + jobject globalRef = vmFuncs->j9jni_createGlobalRef((JNIEnv*)vmThread, rootVirtualThread, JNI_FALSE); + if (NULL != globalRef) { + vm->liveVirtualThreadList = (j9object_t*)globalRef; + + /* Set linkNext/linkPrevious to itself. */ + J9OBJECT_OBJECT_STORE(vmThread, rootVirtualThread, vm->virtualThreadLinkNextOffset, rootVirtualThread); + J9OBJECT_OBJECT_STORE(vmThread, rootVirtualThread, vm->virtualThreadLinkPreviousOffset, rootVirtualThread); + } + } + (*(JNIEnv*)vmThread)->DeleteLocalRef((JNIEnv*)vmThread, clazz); + if (NULL == vm->liveVirtualThreadList) { + goto _fail; + } + } else { + goto _fail; + } #endif /* JAVA_SPEC_VERSION >= 19 */ #endif /* !J9VM_IVE_RAW_BUILD */ }