Skip to content

Commit

Permalink
Pass threadObject to walkContinuationStackFrames
Browse files Browse the repository at this point in the history
threadObject is required in jvmtiFollowReferences to get thread
specific details such as the TID.

So, threadObject needs to be passed via walkContinuationStackFrames
so that it is accessible in jvmtiFollowReferences.

walkContinuationStackFrames is invoked either for a
[1] J9VMContinuation in the Continuation object or
[2] J9VMThread->currentContinuation

In [1], if the Continuation is fully mounted, then it stores the state
of the CarrierThread. Otherwise, it stores the state of the
VirtualThread.

In [2], if J9VMThread->currentContinuation is not NULL, then it stores
the state of the CarrierThread because the VirtualThread is mounted on
the J9VMThread. The CarrierThread is retrieved from
J9VMThread->carrierThreadObject.

We have assumed that the state of the Continuation or J9VMContinuation
doesn't change while walkContinuationStackFrames is invoked i.e. the
VirtualThread shouldn't be mounted or unmounted. Otherwise, the values
of the VirtualThread and CarrierThread objects accessed via the
Continuation object and J9VMThread->carrierThreadObject can vary and
cause a crash during walkContinuationStackFrames.

Related: eclipse-openj9#17712

Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
  • Loading branch information
babsingh committed Oct 4, 2023
1 parent 6b03df7 commit 618c2f4
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 32 deletions.
44 changes: 26 additions & 18 deletions runtime/compiler/control/HookedByTheJit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "vmaccess.h"
#if JAVA_SPEC_VERSION >= 19
#include "HeapIteratorAPI.h"
#include "ContinuationHelpers.hpp"
#endif /* JAVA_SPEC_VERSION >= 19 */
#include "codegen/CodeGenerator.hpp"
#include "compile/CompilationTypes.hpp"
Expand Down Expand Up @@ -6604,25 +6605,29 @@ static UDATA jitReleaseCodeStackWalkFrame(J9VMThread *vmThread, J9StackWalkState

#if JAVA_SPEC_VERSION >= 19
static void jitWalkContinuationStackFrames(J9HookInterface **hookInterface, UDATA eventNum, void *eventData, void *userData)
{
MM_ContinuationIteratingEvent *continuationIteratingEvent = (MM_ContinuationIteratingEvent *)eventData;
J9VMThread * vmThread = continuationIteratingEvent->vmThread;
J9InternalVMFunctions *vmFuncs = vmThread->javaVM->internalVMFunctions;
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationIteratingEvent->object);
if (NULL != continuation) {
J9StackWalkState walkState;
walkState.flags = J9_STACKWALK_ITERATE_HIDDEN_JIT_FRAMES | J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_SKIP_INLINES;
walkState.skipCount = 0;
walkState.frameWalkFunction = jitReleaseCodeStackWalkFrame;

vmFuncs->walkContinuationStackFrames(vmThread, continuation, &walkState);
}
}
{
MM_ContinuationIteratingEvent *continuationIteratingEvent = (MM_ContinuationIteratingEvent *)eventData;
J9VMThread * vmThread = continuationIteratingEvent->vmThread;
J9InternalVMFunctions *vmFuncs = vmThread->javaVM->internalVMFunctions;
j9object_t continuationObj = continuationIteratingEvent->object;
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationObj);
if (NULL != continuation)
{
J9StackWalkState walkState;
walkState.flags = J9_STACKWALK_ITERATE_HIDDEN_JIT_FRAMES | J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_SKIP_INLINES;
walkState.skipCount = 0;
walkState.frameWalkFunction = jitReleaseCodeStackWalkFrame;

j9object_t threadObject = VM_ContinuationHelpers::getThreadObjectForContinuation(vmThread, continuation, continuationObj);
vmFuncs->walkContinuationStackFrames(vmThread, continuation, threadObject, &walkState);
}
}

static jvmtiIterationControl jitWalkContinuationCallBack(J9VMThread *vmThread, J9MM_IterateObjectDescriptor *object, void *userData)
{
J9InternalVMFunctions *vmFuncs = vmThread->javaVM->internalVMFunctions;
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, object->object);
j9object_t continuationObj = object->object;
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationObj);
if (NULL != continuation)
{
bool yieldHappened = false;
Expand All @@ -6632,7 +6637,10 @@ static jvmtiIterationControl jitWalkContinuationCallBack(J9VMThread *vmThread, J
walkState.flags = J9_STACKWALK_ITERATE_HIDDEN_JIT_FRAMES | J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_SKIP_INLINES;
walkState.skipCount = 0;
walkState.frameWalkFunction = jitReleaseCodeStackWalkFrame;
vmFuncs->walkContinuationStackFrames(vmThread, continuation, &walkState);

j9object_t threadObject = VM_ContinuationHelpers::getThreadObjectForContinuation(vmThread, continuation, continuationObj);
vmFuncs->walkContinuationStackFrames(vmThread, continuation, threadObject, &walkState);

continuation->dropFlags = 0x1;
condYieldFromGCFunctionPtr condYield = (condYieldFromGCFunctionPtr)userData;
yieldHappened = condYield(vmThread->omrVMThread, J9_GC_METRONOME_UTILIZATION_COMPONENT_JIT);
Expand Down Expand Up @@ -6695,14 +6703,14 @@ static void jitReleaseCodeStackWalk(OMR_VMThread *omrVMThread, condYieldFromGCFu
thread->dropFlags |= 0x1;
}

if ((NULL!= thread->currentContinuation) && ((thread->currentContinuation->dropFlags & 0x1) ? false : true))
if ((NULL != thread->currentContinuation) && ((thread->currentContinuation->dropFlags & 0x1) ? false : true))
/* If a continuation is mounted, always walk the continuation as that represent the CarrierThread */
{
J9StackWalkState walkState;
walkState.flags = J9_STACKWALK_ITERATE_HIDDEN_JIT_FRAMES | J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_SKIP_INLINES;
walkState.skipCount = 0;
walkState.frameWalkFunction = jitReleaseCodeStackWalkFrame;
vmFuncs->walkContinuationStackFrames(vmThread, thread->currentContinuation, &walkState);
vmFuncs->walkContinuationStackFrames(vmThread, thread->currentContinuation, thread->carrierThreadObject, &walkState);
thread->currentContinuation->dropFlags |= 0x1;
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/gc_base/RootScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ MM_RootScanner::scanOneThread(MM_EnvironmentBase *env, J9VMThread* walkThread, v
{
/* At this point we know that a virtual thread is mounted. We previously scanned its stack,
* and now we will scan carrier's stack, that continuation struct is currently pointing to. */
GC_VMThreadStackSlotIterator::scanSlots(currentThread, walkThread->currentContinuation, localData, stackSlotIterator, isStackFrameClassWalkNeeded(), _trackVisibleStackFrameDepth);
GC_VMThreadStackSlotIterator::scanSlots(currentThread, walkThread, walkThread->currentContinuation, localData, stackSlotIterator, isStackFrameClassWalkNeeded(), _trackVisibleStackFrameDepth);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
return false;
Expand Down
2 changes: 1 addition & 1 deletion runtime/gc_glue_java/ConcurrentMarkingDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ MM_ConcurrentMarkingDelegate::scanThreadRoots(MM_EnvironmentBase *env)

#if JAVA_SPEC_VERSION >= 19
if (NULL != vmThread->currentContinuation) {
GC_VMThreadStackSlotIterator::scanSlots(vmThread, vmThread->currentContinuation, (void *)&localData, concurrentStackSlotIterator, true, false);
GC_VMThreadStackSlotIterator::scanSlots(vmThread, vmThread, vmThread->currentContinuation, (void *)&localData, concurrentStackSlotIterator, true, false);
}
#endif /* JAVA_SPEC_VERSION >= 19 */

Expand Down
10 changes: 8 additions & 2 deletions runtime/gc_structs/VMThreadStackSlotIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
#include "VMThreadStackSlotIterator.hpp"
#include "VMHelpers.hpp"

#if JAVA_SPEC_VERSION >= 19
#include "ContinuationHelpers.hpp"
#endif /* JAVA_SPEC_VERSION >= 19 */

extern "C" {

/**
Expand Down Expand Up @@ -144,14 +148,16 @@ GC_VMThreadStackSlotIterator::scanContinuationSlots(

#if JAVA_SPEC_VERSION >= 19
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationObjectPtr);
vmThread->javaVM->internalVMFunctions->walkContinuationStackFrames(vmThread, continuation, &stackWalkState);
j9object_t threadObject = VM_ContinuationHelpers::getThreadObjectForContinuation(vmThread, continuation, continuationObjectPtr);
vmThread->javaVM->internalVMFunctions->walkContinuationStackFrames(vmThread, continuation, threadObject, &stackWalkState);
#endif /* JAVA_SPEC_VERSION >= 19 */
}

#if JAVA_SPEC_VERSION >= 19
void
GC_VMThreadStackSlotIterator::scanSlots(
J9VMThread *vmThread,
J9VMThread *walkThread,
J9VMContinuation *continuation,
void *userData,
J9MODRON_OSLOTITERATOR *oSlotIterator,
Expand All @@ -162,6 +168,6 @@ GC_VMThreadStackSlotIterator::scanSlots(
J9StackWalkState stackWalkState;
initializeStackWalkState(&stackWalkState, vmThread, userData, oSlotIterator, includeStackFrameClassReferences, trackVisibleFrameDepth);

vmThread->javaVM->internalVMFunctions->walkContinuationStackFrames(vmThread, continuation, &stackWalkState);
vmThread->javaVM->internalVMFunctions->walkContinuationStackFrames(vmThread, continuation, walkThread->carrierThreadObject, &stackWalkState);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
1 change: 1 addition & 0 deletions runtime/gc_structs/VMThreadStackSlotIterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class GC_VMThreadStackSlotIterator
#if JAVA_SPEC_VERSION >= 19
static void scanSlots(
J9VMThread *vmThread,
J9VMThread *walkThread,
J9VMContinuation *continuation,
void *userData,
J9MODRON_OSLOTITERATOR *oSlotIterator,
Expand Down
2 changes: 1 addition & 1 deletion runtime/jcl/common/getstacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ getStackTraceForThread(J9VMThread *currentThread, J9VMThread *targetThread, UDAT
* then the carrier thread's stacktrace is retrieved through the cached state in the continuation.
*/
walkState.skipCount = 0;
rc = vmfns->walkContinuationStackFrames(currentThread, targetThread->currentContinuation, &walkState);
rc = vmfns->walkContinuationStackFrames(currentThread, targetThread->currentContinuation, threadObject, &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.
Expand Down
4 changes: 2 additions & 2 deletions runtime/jvmti/jvmtiHelpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2035,15 +2035,15 @@ genericWalkStackFramesHelper(J9VMThread *currentThread, J9VMThread *targetThread
} else {
j9object_t contObject = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, threadObject);
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(currentThread, contObject);
vm->internalVMFunctions->walkContinuationStackFrames(currentThread, continuation, walkState);
vm->internalVMFunctions->walkContinuationStackFrames(currentThread, continuation, threadObject, walkState);
}
} else
#endif /* JAVA_SPEC_VERSION >= 19 */
{
#if JAVA_SPEC_VERSION >= 19
J9VMContinuation *currentContinuation = targetThread->currentContinuation;
if (NULL != currentContinuation) {
rc = vm->internalVMFunctions->walkContinuationStackFrames(currentThread, currentContinuation, walkState);
rc = vm->internalVMFunctions->walkContinuationStackFrames(currentThread, currentContinuation, threadObject, walkState);
} else
#endif /* JAVA_SPEC_VERSION >= 19 */
{
Expand Down
26 changes: 26 additions & 0 deletions runtime/oti/ContinuationHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,32 @@ class VM_ContinuationHelpers {
{
*continuationStatePtr &= ~J9_GC_CONTINUATION_STATE_CARRIERID_MASK;
}

/**
* Return the thread object whose state is stored in the J9VMContinuation.
*
* @param[in] vmThread the current thread
* @param[in] continuation the native continuation structure
* @param[in] continuationObject the continuation object
* @return the thread object whose state is stored in the continuation
*/
static VMINLINE j9object_t
getThreadObjectForContinuation(J9VMThread *vmThread, J9VMContinuation *continuation, j9object_t continuationObject)
{
/* threadObject points to the virtual thread. */
j9object_t threadObject = (j9object_t)J9VMJDKINTERNALVMCONTINUATION_VTHREAD(vmThread, continuationObject);
ContinuationState volatile *continuationStatePtr = getContinuationStateAddress(vmThread, continuationObject);
ContinuationState continuationState = *continuationStatePtr;

if (isFullyMounted(continuationState)) {
/* If the continuation is fully mounted, then the continuation stores the state of the carrier thread.
* Below, threadObject points to the carrier thread.
*/
threadObject = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(vmThread, threadObject);
}

return threadObject;
}
};

#endif /* CONTINUATIONHELPERS_HPP_ */
2 changes: 1 addition & 1 deletion runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5047,7 +5047,7 @@ typedef struct J9InternalVMFunctions {
void (*freeContinuation)(struct J9VMThread *currentThread, j9object_t continuationObject, BOOLEAN skipLocalCache);
void (*recycleContinuation)(struct J9JavaVM *vm, struct J9VMThread *vmThread, struct J9VMContinuation *continuation, BOOLEAN skipLocalCache);
void (*freeTLS)(struct J9VMThread *currentThread, j9object_t threadObj);
UDATA (*walkContinuationStackFrames)(struct J9VMThread *currentThread, struct J9VMContinuation *continuation, J9StackWalkState *walkState);
UDATA (*walkContinuationStackFrames)(struct J9VMThread *currentThread, struct J9VMContinuation *continuation, j9object_t threadObject, J9StackWalkState *walkState);
UDATA (*walkAllStackFrames)(struct J9VMThread *currentThread, J9StackWalkState *walkState);
BOOLEAN (*acquireVThreadInspector)(struct J9VMThread *currentThread, jobject thread, BOOLEAN spin);
void (*releaseVThreadInspector)(struct J9VMThread *currentThread, jobject thread);
Expand Down
3 changes: 2 additions & 1 deletion runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4470,10 +4470,11 @@ copyFieldsFromContinuation(J9VMThread *currentThread, J9VMThread *vmThread, J9VM
*
* @param currentThread current thread
* @param continuation the continuation to be walked
* @param threadObject the thread object whose state is stored in the continuation
* @return 0 on success and non-zero on failure
*/
UDATA
walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continuation, J9StackWalkState *walkState);
walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continuation, j9object_t threadObject, J9StackWalkState *walkState);

/**
* @brief Walk all stackframes in the VM.
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/BytecodeInterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3194,7 +3194,7 @@ class INTERPRETER_CLASS
) {
continuationWalkState.flags = walkFlags;
continuationWalkRC = _vm->internalVMFunctions->walkContinuationStackFrames(
_currentThread, _currentThread->currentContinuation, &continuationWalkState);
_currentThread, _currentThread->currentContinuation, _currentThread->carrierThreadObject, &continuationWalkState);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
/* No need for VMStructHasBeenUpdated as the above walk cannot change the roots */
Expand Down
10 changes: 6 additions & 4 deletions runtime/vm/ContinuationHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ copyFieldsFromContinuation(J9VMThread *currentThread, J9VMThread *vmThread, J9VM
}

UDATA
walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continuation, J9StackWalkState *walkState)
walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continuation, j9object_t threadObject, J9StackWalkState *walkState)
{
Assert_VM_notNull(currentThread);

Expand All @@ -467,7 +467,7 @@ walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continu
J9VMEntryLocalStorage els = {0};

copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);

stackThread.threadObject = threadObject;
walkState->walkThread = &stackThread;
rc = currentThread->javaVM->walkStackFrames(currentThread, walkState);
}
Expand All @@ -479,11 +479,13 @@ walkContinuationStackFrames(J9VMThread *currentThread, J9VMContinuation *continu
jvmtiIterationControl
walkContinuationCallBack(J9VMThread *vmThread, J9MM_IterateObjectDescriptor *object, void *userData)
{
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, object->object);
j9object_t continuationObj = object->object;
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationObj);
if (NULL != continuation) {
J9StackWalkState localWalkState = *(J9StackWalkState*)userData;
/* Walk non-null continuation's stack */
walkContinuationStackFrames(vmThread, continuation, &localWalkState);
j9object_t threadObject = VM_ContinuationHelpers::getThreadObjectForContinuation(vmThread, continuation, continuationObj);
walkContinuationStackFrames(vmThread, continuation, threadObject, &localWalkState);
}
return JVMTI_ITERATION_CONTINUE;
}
Expand Down

0 comments on commit 618c2f4

Please sign in to comment.