From b318f52dace572f59b1e72507396f2ffdd9d43e2 Mon Sep 17 00:00:00 2001 From: Babneet Singh Date: Mon, 17 Jul 2023 15:13:32 -0400 Subject: [PATCH] [JDK21] Add support for JVMTI PopFrame Previously, PopFrame returned JVMTI_ERROR_OPAQUE_FRAME for a virtual thread. In JDK21, PopFrame includes support for virtual threads as per the JVMTI specification: - Error if a virtual thread is not suspended and not the current thread. - Error if a virtual thread is unomunted since it won't be able to pop the current frame. - For a carrier thread with a virtual thread mounted, the details of the carrier thread are derived from targetThread->currentContinuation. Related: - #17715 - #17716 Also, there is no need to halt and resume a thread for inspection since PopFrame expects the thread to be suspended as per the JVMTI spec. If a thread is not suspended, it returns JVMTI_ERROR_THREAD_NOT_SUSPENDED. Signed-off-by: Babneet Singh --- runtime/jvmti/jvmtiStackFrame.c | 46 ++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/runtime/jvmti/jvmtiStackFrame.c b/runtime/jvmti/jvmtiStackFrame.c index 50bd74a5f2a..a0f326195c0 100644 --- a/runtime/jvmti/jvmtiStackFrame.c +++ b/runtime/jvmti/jvmtiStackFrame.c @@ -440,17 +440,43 @@ jvmtiPopFrame(jvmtiEnv* env, ENSURE_CAPABILITY(env, can_pop_frame); 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); + currentThread, thread, &targetThread, JVMTI_ERROR_NONE, + J9JVMTI_GETVMTHREAD_ERROR_ON_NULL_JTHREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD); if (rc == JVMTI_ERROR_NONE) { - /* Does this thread need to be suspended at an event? */ - vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread); - if ((currentThread == targetThread) || !(targetThread->publicFlags & J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) { +#if JAVA_SPEC_VERSION >= 21 + j9object_t threadObject = NULL; + /* Error if a virtual thread is unmounted since it won't be able to + * pop the current frame. + */ + if (NULL == targetThread) { + rc = JVMTI_ERROR_OPAQUE_FRAME; + goto release; + } + threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread); +#endif /* JAVA_SPEC_VERSION >= 21 */ + + /* Error if the thread is not suspended and not the current thread. */ + if ((currentThread != targetThread) +#if JAVA_SPEC_VERSION >= 21 + && (0 == J9OBJECT_U32_LOAD(currentThread, threadObject, vm->isSuspendedInternalOffset)) +#else /* JAVA_SPEC_VERSION >= 21 */ + && OMR_ARE_NO_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND) +#endif /* JAVA_SPEC_VERSION >= 21 */ + ) { rc = JVMTI_ERROR_THREAD_NOT_SUSPENDED; } else { - J9StackWalkState walkState; - - walkState.walkThread = targetThread; + J9StackWalkState walkState = {0}; + J9VMThread *threadToWalk = targetThread; +#if JAVA_SPEC_VERSION >= 21 + J9VMThread stackThread = {0}; + J9VMEntryLocalStorage els = {0}; + J9VMContinuation *continuation = getJ9VMContinuationToWalk(currentThread, targetThread, threadObject); + if (NULL != continuation) { + vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation); + threadToWalk = &stackThread; + } +#endif /* JAVA_SPEC_VERSION >= 21 */ + walkState.walkThread = threadToWalk; walkState.userData1 = (void *) JVMTI_ERROR_NO_MORE_FRAMES; walkState.userData2 = (void *) 0; walkState.frameWalkFunction = popFrameCheckIterator; @@ -462,7 +488,9 @@ jvmtiPopFrame(jvmtiEnv* env, vm->internalVMFunctions->setHaltFlag(targetThread, J9_PUBLIC_FLAGS_POP_FRAMES_INTERRUPT); } } - vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread); +#if JAVA_SPEC_VERSION >= 21 +release: +#endif /* JAVA_SPEC_VERSION >= 21 */ releaseVMThread(currentThread, targetThread, thread); } done: