From 9581f21bde6fb4d181bcbbfb42deb24224a48e6b Mon Sep 17 00:00:00 2001 From: Jack Lu Date: Tue, 25 Apr 2023 14:33:23 -0400 Subject: [PATCH] Refactor getStackTraceImpl to remove use of VThreadInspector Signed-off-by: Jack Lu --- runtime/jcl/common/getstacktrace.c | 46 +++++++++++++++++++++++------- runtime/jcl/common/thread.cpp | 39 +++---------------------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/runtime/jcl/common/getstacktrace.c b/runtime/jcl/common/getstacktrace.c index e558ddf22a5..b3e0143b60d 100644 --- a/runtime/jcl/common/getstacktrace.c +++ b/runtime/jcl/common/getstacktrace.c @@ -48,22 +48,44 @@ getStackTraceForThread(J9VMThread *currentThread, J9VMThread *targetThread, UDAT j9object_t throwable = NULL; J9StackWalkState walkState = {0}; UDATA rc = J9_STACKWALK_RC_NONE; + #if JAVA_SPEC_VERSION >= 19 - J9VMContinuation *continuation = targetThread->currentContinuation; + BOOLEAN isVirtual = IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject); + if (isVirtual) { + /* Return NULL if a valid CarrierThread object cannot be found through VirtualThread object, + * the caller of getStackTraceImpl will handle whether to retry or get the stack using the unmounted path. + */ + j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, threadObject); + /* Ensure the VirtualThread is mounted and not during transition. */ + if (NULL == carrierThread) { + goto done; + } + /* Gets targetThread from the carrierThread object. */ + targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, carrierThread); + Assert_JCL_notNull(targetThread); + } + PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, threadObject); #endif /* JAVA_SPEC_VERSION >= 19 */ - /* Halt the target thread */ + /* Halt the target thread. */ vmfns->haltThreadForInspection(currentThread, targetThread); - /* walk stack and cache PCs */ + /* walk stack and cache PCs. */ walkState.flags = J9_STACKWALK_CACHE_PCS | J9_STACKWALK_WALK_TRANSLATE_PC | J9_STACKWALK_SKIP_INLINES | J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_VISIBLE_ONLY; #if JAVA_SPEC_VERSION >= 19 - if ((NULL != continuation) && (threadObject != targetThread->threadObject)) { - /* If targetThread has a continuation mounted and its current threadObject doesn't match the - * target threadObject, then the carrier thread's stacktrace is retrieved through the cached - * state in the continuation. + threadObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread); + /* Re-check thread state. */ + if ((NULL != targetThread->currentContinuation) && (threadObject == targetThread->carrierThreadObject)) { + /* If targetThread has a continuation mounted and its threadObject matches its carrierThreadObject, + * then the carrier thread's stacktrace is retrieved through the cached state in the continuation. */ walkState.skipCount = 0; - rc = vmfns->walkContinuationStackFrames(currentThread, continuation, &walkState); + rc = vmfns->walkContinuationStackFrames(currentThread, targetThread->currentContinuation, &walkState); + } else if (isVirtual && (threadObject != targetThread->threadObject)) { + /* If the virtual thread object doesn't match the current thread object, it must have unmounted + * from this carrier thread, return NULL and the JCL code will handle the retry. + */ + vmfns->resumeThreadForInspection(currentThread, targetThread); + goto done; } else #endif /* JAVA_SPEC_VERSION >= 19 */ { @@ -71,10 +93,10 @@ getStackTraceForThread(J9VMThread *currentThread, J9VMThread *targetThread, UDAT walkState.skipCount = skipCount; rc = vm->walkStackFrames(currentThread, &walkState); } - /* Now that the stack trace has been copied, resume the thread */ + /* Now that the stack trace has been copied, resume the thread. */ vmfns->resumeThreadForInspection(currentThread, targetThread); - /* Check for stack walk failure */ + /* Check for stack walk failure. */ if (rc != J9_STACKWALK_RC_NONE) { vmfns->setNativeOutOfMemoryError(currentThread, 0, 0); goto fail; @@ -84,7 +106,9 @@ getStackTraceForThread(J9VMThread *currentThread, J9VMThread *targetThread, UDAT fail: vmfns->freeStackWalkCaches(currentThread, &walkState); - +#if JAVA_SPEC_VERSION >= 19 +done: +#endif /* JAVA_SPEC_VERSION >= 19 */ /* Return the result - any pending exception will be checked by the caller and the result discarded */ return throwable; } diff --git a/runtime/jcl/common/thread.cpp b/runtime/jcl/common/thread.cpp index 5dd617e2005..0bebeb8141d 100644 --- a/runtime/jcl/common/thread.cpp +++ b/runtime/jcl/common/thread.cpp @@ -336,45 +336,14 @@ Java_java_lang_Thread_getStackTraceImpl(JNIEnv *env, jobject rcv) /* Assume the thread is alive (guaranteed by java caller). */ J9VMThread *targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, receiverObject); -#if JAVA_SPEC_VERSION >= 19 - BOOLEAN releaseInspector = FALSE; - if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, receiverObject)) { - /* Do not spin when acquiring access, if acquire failed, return NULL. - * The caller of getStackTraceImpl will handle if should retry or get stack using unmounted path. - */ - if (!vmFuncs->acquireVThreadInspector(currentThread, rcv, FALSE)) { - goto done; - } - j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, receiverObject); - /* Ensure virtual thread is mounted and not during transition. */ - if (NULL != carrierThread) { - releaseInspector = TRUE; - } else { - vmFuncs->releaseVThreadInspector(currentThread, rcv); - goto done; - } - /* Gets targetThread from the carrierThread object. */ - targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, carrierThread); - Assert_JCL_notNull(targetThread); - } - { -#endif /* JAVA_SPEC_VERSION >= 19 */ + /* If calling getStackTrace on the current Thread, drop the first element, which is this method. */ + UDATA skipCount = (currentThread == targetThread) ? 1 : 0; - /* If calling getStackTrace on the current Thread, drop the first element, which is this method. */ - UDATA skipCount = (currentThread == targetThread) ? 1 : 0; + j9object_t resultObject = getStackTraceForThread(currentThread, targetThread, skipCount, receiverObject); - j9object_t resultObject = getStackTraceForThread(currentThread, targetThread, skipCount, receiverObject); + if (NULL != resultObject) { result = vmFuncs->j9jni_createLocalRef(env, resultObject); - -#if JAVA_SPEC_VERSION >= 19 } - if (releaseInspector) { - receiverObject = J9_JNI_UNWRAP_REFERENCE(rcv); - /* Release the virtual thread (allow it to die) now that we are no longer inspecting it. */ - vmFuncs->releaseVThreadInspector(currentThread, rcv); - } -done: -#endif /* JAVA_SPEC_VERSION >= 19 */ vmFuncs->internalExitVMToJNI(currentThread); return result;