Skip to content

Commit

Permalink
Update jvmtiGetOrSetLocal and jvmtiNotifyFramePop for virtual threads
Browse files Browse the repository at this point in the history
Adds virtual thread support for GetOrSetLocal and NotifyFramePop

As walkState->walkThread will be used by some jit functions after
stackwalk, we can't use walkContinuationStackFrames which will cause
dangling pointer. Instead we need to stack-allocate manually if a
J9VMContinuation needs to be walked, so we created a helper
getJ9VMContinuationToWalk to get the J9VMContinuation.

Also fix coding style of surrounding code

Issues: eclipse-openj9#15759 eclipse-openj9#15183

Co-authored-by: Babneet Singh <sbabneet@ca.ibm.com>
Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
  • Loading branch information
thallium and babsingh committed Sep 22, 2022
1 parent 5a2eb17 commit 06d73f9
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 43 deletions.
75 changes: 48 additions & 27 deletions runtime/jvmti/jvmtiLocalVariable.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,48 +290,65 @@ jvmtiSetLocalDouble(jvmtiEnv* env,
TRACE_JVMTI_RETURN(jvmtiSetLocalDouble);
}


#if (defined(J9VM_OPT_DEBUG_INFO_SERVER))
static jvmtiError
jvmtiGetOrSetLocal(jvmtiEnv* env,
jvmtiGetOrSetLocal(jvmtiEnv *env,
jthread thread,
jint depth,
jint slot,
void* value_ptr,
void *value_ptr,
char signature,
jboolean isSet,
jboolean getLocalInstance)
{
J9JVMTIEnv * j9env = (J9JVMTIEnv *) env;
J9JavaVM * vm = j9env->vm;
jvmtiError rc;
J9VMThread * currentThread;
J9JVMTIEnv *j9env = (J9JVMTIEnv *)env;
J9JavaVM *vm = j9env->vm;
jvmtiError rc = JVMTI_ERROR_NONE;
J9VMThread *currentThread = NULL;

rc = getCurrentVMThread(vm, &currentThread);
if (rc == JVMTI_ERROR_NONE) {
if (JVMTI_ERROR_NONE == rc) {
J9VMThread *targetThread = NULL;

vm->internalVMFunctions->internalEnterVMFromJNI(currentThread);
rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE);
if (rc == JVMTI_ERROR_NONE) {
J9StackWalkState walkState;
UDATA objectFetched = FALSE;
J9StackWalkState walkState = {0};
BOOLEAN objectFetched = FALSE;
J9VMThread *threadToWalk = targetThread;

#if JAVA_SPEC_VERSION >= 19
J9VMThread stackThread = {0};
J9VMEntryLocalStorage els = {0};
j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread);
J9VMContinuation *continuation = getJ9VMContinuationToWalk(currentThread, targetThread, threadObject);
if (NULL != continuation) {
vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);
threadToWalk = &stackThread;
}
#endif /* JAVA_SPEC_VERSION >= 19 */

#if JAVA_SPEC_VERSION >= 19
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread);
}

vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread);
rc = findDecompileInfo(currentThread, targetThread, (UDATA)depth, &walkState);
rc = findDecompileInfo(currentThread, threadToWalk, (UDATA)depth, &walkState);
if (JVMTI_ERROR_NONE == rc) {
UDATA validateRC;
UDATA slotValid = TRUE;
UDATA * slotAddress;
UDATA validateRC = 0;
BOOLEAN slotValid = TRUE;
UDATA *slotAddress = NULL;
J9Method *ramMethod = walkState.userData3;
U_32 offsetPC = (U_32)(UDATA)walkState.userData4;
J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(ramMethod);
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(ramMethod);

if (getLocalInstance) {
if (romMethod->modifiers & J9AccStatic) {
if (OMR_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccStatic)) {
/* GetLocalInstance illegal on static methods */
validateRC = J9_SLOT_VALIDATE_ERROR_INVALID_SLOT;
} else if (romMethod->modifiers & J9AccNative) {
} else if (OMR_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccNative)) {
/* GetLocalInstance legal on non-static native methods */
validateRC = J9_SLOT_VALIDATE_ERROR_NONE;
} else {
Expand All @@ -341,6 +358,7 @@ jvmtiGetOrSetLocal(jvmtiEnv* env,
} else {
validateRC = validateLocalSlot(currentThread, ramMethod, offsetPC, (U_32) slot, signature, TRUE);
}

switch (validateRC) {
case J9_SLOT_VALIDATE_ERROR_LOCAL_MAP_MISMATCH:
slotValid = FALSE;
Expand All @@ -366,17 +384,17 @@ jvmtiGetOrSetLocal(jvmtiEnv* env,
break;
case 'L':
/* Perform type check? */
*((j9object_t*) slotAddress) = (value_ptr == NULL ? NULL : *((j9object_t*) value_ptr));
*((j9object_t *)slotAddress) = (NULL == value_ptr) ? NULL : *((j9object_t *)value_ptr);
break;
default:
*((jint *) slotAddress) = *((jint *) value_ptr);
*((jint *)slotAddress) = *((jint *)value_ptr);
break;
}
#ifdef J9VM_JIT_FULL_SPEED_DEBUG
if (J9_FSD_ENABLED(vm)) {
vm->jitConfig->jitStackLocalsModified(currentThread, &walkState);
}
#endif
#endif /* J9VM_JIT_FULL_SPEED_DEBUG */
}
} else {
switch(signature) {
Expand All @@ -391,10 +409,10 @@ jvmtiGetOrSetLocal(jvmtiEnv* env,
case 'L':
/* CMVC 109592 - Must not modify the stack while a thread is halted for inspection - this includes creation of JNI local refs */
objectFetched = TRUE;
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, (slotValid ? *((j9object_t*) slotAddress) : NULL));
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, slotValid ? *((j9object_t *)slotAddress) : NULL);
break;
default:
*((jint *) value_ptr) = (slotValid ? *((jint *) slotAddress) : 0);
*((jint *)value_ptr) = (slotValid ? *((jint *)slotAddress) : 0);
break;
}
}
Expand All @@ -419,11 +437,15 @@ jvmtiGetOrSetLocal(jvmtiEnv* env,
rc = JVMTI_ERROR_NO_MORE_FRAMES;
}

vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread);
#if JAVA_SPEC_VERSION >= 19
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread);
}
if (objectFetched) {
j9object_t obj = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);

*((jobject *) value_ptr) = vm->internalVMFunctions->j9jni_createLocalRef((JNIEnv *) currentThread, obj);
*((jobject *)value_ptr) = vm->internalVMFunctions->j9jni_createLocalRef((JNIEnv *)currentThread, obj);
}
releaseVMThread(currentThread, targetThread, thread);
}
Expand All @@ -434,4 +456,3 @@ jvmtiGetOrSetLocal(jvmtiEnv* env,
}

#endif /* J9VM_OPT_DEBUG_INFO_SERVER */

67 changes: 51 additions & 16 deletions runtime/jvmti/jvmtiStackFrame.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,18 +553,18 @@ jvmtiGetFrameLocation(jvmtiEnv *env,


jvmtiError JNICALL
jvmtiNotifyFramePop(jvmtiEnv* env,
jvmtiNotifyFramePop(jvmtiEnv *env,
jthread thread,
jint depth)
{
J9JavaVM * vm = JAVAVM_FROM_ENV(env);
jvmtiError rc;
J9VMThread * currentThread;
J9JavaVM *vm = JAVAVM_FROM_ENV(env);
jvmtiError rc = JVMTI_ERROR_NONE;
J9VMThread *currentThread = NULL;

Trc_JVMTI_jvmtiNotifyFramePop_Entry(env);

rc = getCurrentVMThread(vm, &currentThread);
if (rc == JVMTI_ERROR_NONE) {
if (JVMTI_ERROR_NONE == rc) {
J9VMThread *targetThread = NULL;

vm->internalVMFunctions->internalEnterVMFromJNI(currentThread);
Expand All @@ -575,24 +575,55 @@ jvmtiNotifyFramePop(jvmtiEnv* env,
ENSURE_NON_NEGATIVE(depth);

rc = getVMThread(currentThread, thread, &targetThread, TRUE, TRUE);
if (rc == JVMTI_ERROR_NONE) {
vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread);
if ((currentThread == targetThread) || (targetThread->publicFlags & J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) {
J9StackWalkState walkState;
if (JVMTI_ERROR_NONE == rc) {
#if JAVA_SPEC_VERSION >= 19
BOOLEAN isVThreadSuspended = FALSE;
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
vm->internalVMFunctions->haltThreadForInspection(currentThread, targetThread);
}
#if JAVA_SPEC_VERSION >= 19
if ((NULL != thread) && (NULL == targetThread)) {
/* The assert in getVMThread will assure that this is a virtual thread */
jint vthreadState = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, J9_JNI_UNWRAP_REFERENCE(thread));
isVThreadSuspended = OMR_ARE_ANY_BITS_SET(vthreadState, JVMTI_VTHREAD_STATE_SUSPENDED);
}
#endif /* JAVA_SPEC_VERSION >= 19 */

if ((currentThread == targetThread)
#if JAVA_SPEC_VERSION >= 19
|| isVThreadSuspended
#endif /* JAVA_SPEC_VERSION >= 19 */
|| ((NULL != targetThread) && OMR_ARE_ANY_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND))
) {
J9StackWalkState walkState = {0};
J9VMThread *threadToWalk = targetThread;

#if JAVA_SPEC_VERSION >= 19
J9VMThread stackThread = {0};
J9VMEntryLocalStorage els = {0};
j9object_t threadObject = (NULL == thread) ? currentThread->threadObject : J9_JNI_UNWRAP_REFERENCE(thread);
J9VMContinuation *continuation = getJ9VMContinuationToWalk(currentThread, targetThread, threadObject);
if (NULL != continuation) {
vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);
threadToWalk = &stackThread;
}
#endif /* JAVA_SPEC_VERSION >= 19 */

rc = findDecompileInfo(currentThread, targetThread, (UDATA)depth, &walkState);
rc = findDecompileInfo(currentThread, threadToWalk, (UDATA)depth, &walkState);
if (JVMTI_ERROR_NONE == rc) {
J9ROMMethod* romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState.method);
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState.method);

if (romMethod->modifiers & J9AccNative) {
if (OMR_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccNative)) {
rc = JVMTI_ERROR_OPAQUE_FRAME;
} else {
#ifdef J9VM_JIT_FULL_SPEED_DEBUG
if (walkState.jitInfo != NULL) {
if (NULL != walkState.jitInfo) {
UDATA inlineDepth = (UDATA)walkState.userData2;
vm->jitConfig->jitFramePopNotificationAdded(currentThread, &walkState, inlineDepth);
} else
#endif
#endif /* J9VM_JIT_FULL_SPEED_DEBUG */
{
*walkState.bp |= J9SF_A0_REPORT_FRAME_POP_TAG;
}
Expand All @@ -601,8 +632,12 @@ jvmtiNotifyFramePop(jvmtiEnv* env,
} else {
rc = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}

vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread);
#if JAVA_SPEC_VERSION >= 19
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
vm->internalVMFunctions->resumeThreadForInspection(currentThread, targetThread);
}
releaseVMThread(currentThread, targetThread, thread);
}
done:
Expand Down

0 comments on commit 06d73f9

Please sign in to comment.