Skip to content

Commit

Permalink
[JDK21] Add support for JVMTI ForceEarlyReturn
Browse files Browse the repository at this point in the history
Previously, ForceEarlyReturn returned JVMTI_ERROR_OPAQUE_FRAME for a
virtual thread.

In JDK21, ForceEarlyReturn 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 unmounted since it won't be able to
  force an early return.
- For a carrier thread with a virtual thread mounted, the details of
  the carrier thread are derived from targetThread->currentContinuation.

Also, there is no need to halt and resume a thread for inspection since
ForceEarlyReturn expects the thread to be suspended as per the JVMTI
spec. If a thread is not suspended,
it returns JVMTI_ERROR_THREAD_NOT_SUSPENDED.

Related: #17713

Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
  • Loading branch information
babsingh committed Jul 27, 2023
1 parent ecfd805 commit dbaf246
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 14 deletions.
48 changes: 36 additions & 12 deletions runtime/jvmti/jvmtiForceEarlyReturn.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,43 @@ jvmtiForceEarlyReturn(jvmtiEnv* env,
ENSURE_CAPABILITY(env, can_force_early_return);

rc = getVMThread(
currentThread, thread, &targetThread, JVMTI_ERROR_OPAQUE_FRAME,
J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD | J9JVMTI_GETVMTHREAD_ERROR_ON_VIRTUALTHREAD);
currentThread, thread, &targetThread, JVMTI_ERROR_NONE,
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)) {
/* A thread other then current must be suspended in order to force early return */
#if JAVA_SPEC_VERSION >= 21
j9object_t threadObject = NULL;
/* Error if a virtual thread is unmounted since it won't be able to
* force an early return.
*/
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 */

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 */
) {
/* All threads except the current thread must be suspended in order to force an early return. */
rc = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
} else {
J9StackWalkState walkState;

rc = findDecompileInfo(currentThread, targetThread, 0, &walkState);
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 */
rc = findDecompileInfo(currentThread, threadToWalk, 0, &walkState);
if (JVMTI_ERROR_NONE == rc) {
J9Method *method = walkState.userData3;
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
Expand Down Expand Up @@ -201,7 +226,7 @@ jvmtiForceEarlyReturn(jvmtiEnv* env,
if (NULL != walkState.jitInfo) {
if (NULL == vm->jitConfig->jitAddDecompilationForFramePop(currentThread, &walkState)) {
rc = JVMTI_ERROR_OUT_OF_MEMORY;
goto resume;
goto release;
}
}
vm->internalVMFunctions->setHaltFlag(targetThread, J9_PUBLIC_FLAGS_POP_FRAMES_INTERRUPT);
Expand Down Expand Up @@ -231,8 +256,7 @@ jvmtiForceEarlyReturn(jvmtiEnv* env,
}
}
}
resume:
vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread);
release:
releaseVMThread(currentThread, targetThread, thread);
}
done:
Expand Down
4 changes: 2 additions & 2 deletions runtime/jvmti/jvmtiStackFrame.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ jvmtiPopFrame(jvmtiEnv* env,
J9VMEntryLocalStorage els = {0};
J9VMContinuation *continuation = getJ9VMContinuationToWalk(currentThread, targetThread, threadObject);
if (NULL != continuation) {
vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);
threadToWalk = &stackThread;
vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);
threadToWalk = &stackThread;
}
#endif /* JAVA_SPEC_VERSION >= 21 */
walkState.walkThread = threadToWalk;
Expand Down

0 comments on commit dbaf246

Please sign in to comment.