Skip to content

Commit

Permalink
Merge pull request #18864 from fengxue-IS/18416-jni-local
Browse files Browse the repository at this point in the history
Refactor J9JVMTI_HEAP_EVENT_STACK data parsing
  • Loading branch information
babsingh authored Oct 17, 2024
2 parents 30db706 + 3380c62 commit 64cb0db
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 70 deletions.
35 changes: 30 additions & 5 deletions runtime/gc_base/ReferenceChainWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "Forge.hpp"
#include "GCExtensions.hpp"
#include "Heap.hpp"
#include "HeapIteratorAPI.h"
#include "HeapRegionIterator.hpp"
#include "MixedObjectDeclarationOrderIterator.hpp"
#include "ModronAssertions.h"
Expand All @@ -44,6 +45,9 @@
#include "PointerArrayIterator.hpp"
#include "SlotObject.hpp"
#include "VMThreadIterator.hpp"
#if JAVA_SPEC_VERSION >= 19
#include "ContinuationHelpers.hpp"
#endif /* JAVA_SPEC_VERSION >= 19 */

class GC_HashTableIterator;
class GC_JVMTIObjectTagTableIterator;
Expand Down Expand Up @@ -76,6 +80,7 @@ j9gc_ext_reachable_objects_do(
uintptr_t walkFlags)
{
MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);
Assert_MM_mustHaveExclusiveVMAccess(env->getOmrVMThread());

/* Make sure the heap is walkable (flush TLH's, secure heap integrity) */
vmThread->javaVM->memoryManagerFunctions->j9gc_flush_caches_for_walk(vmThread->javaVM);
Expand All @@ -87,6 +92,9 @@ j9gc_ext_reachable_objects_do(
#endif /* J9VM_OPT_JVMTI */
referenceChainWalker.setTrackVisibleStackFrameDepth(0 != (walkFlags & J9_MU_WALK_TRACK_VISIBLE_FRAME_DEPTH));
referenceChainWalker.setPreindexInterfaceFields(0 != (walkFlags & J9_MU_WALK_PREINDEX_INTERFACE_FIELDS));
#if JAVA_SPEC_VERSION >= 19
referenceChainWalker.includeVThreadObject();
#endif /* JAVA_SPEC_VERSION >= 19 */
/* walker configuration complete. Scan objects... */
referenceChainWalker.scanReachableObjects(env);
referenceChainWalker.tearDown(env);
Expand All @@ -112,13 +120,17 @@ j9gc_ext_reachable_from_object_do(
uintptr_t walkFlags)
{
MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);
Assert_MM_mustHaveExclusiveVMAccess(env->getOmrVMThread());

/* Make sure the heap is walkable (flush TLH's, secure heap integrity) */
vmThread->javaVM->memoryManagerFunctions->j9gc_flush_caches_for_walk(vmThread->javaVM);

MM_ReferenceChainWalker referenceChainWalker(env, TEMP_RCW_STACK_SIZE, userCallback, userData);
if (referenceChainWalker.initialize(env)) {
referenceChainWalker.setPreindexInterfaceFields(0 != (walkFlags & J9_MU_WALK_PREINDEX_INTERFACE_FIELDS));
#if JAVA_SPEC_VERSION >= 19
referenceChainWalker.includeVThreadObject();
#endif /* JAVA_SPEC_VERSION >= 19 */
/* walker configuration complete. Scan objects... */
referenceChainWalker.scanReachableFromObject(env, objectPtr);
referenceChainWalker.tearDown(env);
Expand Down Expand Up @@ -400,7 +412,11 @@ MM_ReferenceChainWalker::scanContinuationNativeSlots(J9Object *objectPtr)
if (MM_GCExtensions::needScanStacksForContinuationObject(currentThread, objectPtr, isConcurrentGC, isGlobalGC, beingMounted)) {
StackIteratorData localData;
localData.rootScanner = this;

#if JAVA_SPEC_VERSION >= 19
if (_includeVThreadObject) {
_vThreadObject = VM_ContinuationHelpers::getThreadObjectForContinuation(currentThread, NULL, objectPtr);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
GC_VMThreadStackSlotIterator::scanContinuationSlots(currentThread, objectPtr, (void *)&localData, stackSlotIteratorForReferenceChainWalker, false, _trackVisibleStackFrameDepth);
}
}
Expand Down Expand Up @@ -645,10 +661,17 @@ MM_ReferenceChainWalker::doStackSlot(J9Object **slotPtr, void *walkState, const

/* Only report heap objects */
if (isHeapObject(slotValue) && !_heap->objectIsInGap(slotValue)) {
#if JAVA_SPEC_VERSION >= 19
if (_includeVThreadObject && (NULL == ((J9StackWalkState *)walkState)->walkThread->threadObject)) {
/* Fill in the virtual thread object for jvmtiFollowReferences calls. */
((J9StackWalkState *)walkState)->walkThread->threadObject = _vThreadObject;
}
#endif /* JAVA_SPEC_VERSION >= 19 */
J9MM_StackSlotDescriptor stackSlotDescriptor = {((J9StackWalkState *)walkState)->walkThread, (J9StackWalkState *)walkState};
if (J9_STACKWALK_SLOT_TYPE_JNI_LOCAL == ((J9StackWalkState *)walkState)->slotType) {
doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_LOCAL, -1, NULL);
doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_LOCAL, -1, (J9Object *)&stackSlotDescriptor);
} else {
doSlot(slotPtr, J9GC_ROOT_TYPE_STACK_SLOT, -1, (J9Object *)walkState);
doSlot(slotPtr, J9GC_ROOT_TYPE_STACK_SLOT, -1, (J9Object *)&stackSlotDescriptor);
}
}
}
Expand Down Expand Up @@ -676,9 +699,11 @@ MM_ReferenceChainWalker::doVMThreadSlot(J9Object **slotPtr, GC_VMThreadIterator
case vmthreaditerator_state_slots:
doSlot(slotPtr, J9GC_ROOT_TYPE_THREAD_SLOT, -1, NULL);
break;
case vmthreaditerator_state_jni_slots:
doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_LOCAL, -1, NULL);
case vmthreaditerator_state_jni_slots: {
J9MM_StackSlotDescriptor stackSlotDescriptor = {vmThreadIterator->getVMThread(), NULL};
doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_LOCAL, -1, (J9Object *)&stackSlotDescriptor);
break;
}
#if defined(J9VM_INTERP_HOT_CODE_REPLACEMENT)
case vmthreaditerator_state_monitor_records:
if (isHeapObject(slotValue) && !_heap->objectIsInGap(slotValue)) {
Expand Down
13 changes: 13 additions & 0 deletions runtime/gc_base/ReferenceChainWalker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,16 @@ class MM_ReferenceChainWalker : public MM_RootScanner
bool _isProcessingOverflow; /**< Set when the queue is currently processing the overflow */
bool _isTerminating; /**< Set when no more callbacks should be queued */
bool _shouldPreindexInterfaceFields; /**< if true, indexes interface fields of the class being visited before class and superclass fields, otherwise, returns them in the order they appear in an object instance (CMVC 142897) */
#if JAVA_SPEC_VERSION >= 19
bool _includeVThreadObject; /**< Set when VirtualThread object is needed by callback function */
J9Object *_vThreadObject; /**< Cached object ref of VirtualThread object */
#endif /* JAVA_SPEC_VERSION >= 19 */
MM_ReferenceChainWalkerMarkMap *_markMap; /**< Mark Map created for Reference Chain Walker */
MM_Heap *_heap; /**< Cached pointer to the heap */
void *_heapBase; /**< Cached value of the heap base */
void *_heapTop; /**< Cached value of the heap top */


void clearQueue();
void pushObject(J9Object *obj);
J9Object *popObject();
Expand Down Expand Up @@ -235,6 +240,10 @@ class MM_ReferenceChainWalker : public MM_RootScanner
_isProcessingOverflow(false),
_isTerminating(false),
_shouldPreindexInterfaceFields(true), /* default to behaviour required for Java6/heap11 */
#if JAVA_SPEC_VERSION >= 19
_includeVThreadObject(false),
_vThreadObject(NULL),
#endif /* JAVA_SPEC_VERSION >= 19 */
_markMap(NULL),
_heap(NULL),
_heapBase(NULL),
Expand All @@ -259,6 +268,10 @@ class MM_ReferenceChainWalker : public MM_RootScanner
completeScan();
}

#if JAVA_SPEC_VERSION >= 19
void includeVThreadObject() { _includeVThreadObject = true; }
#endif /* JAVA_SPEC_VERSION >= 19 */

/**
* Added to support bi-modal interface indexing in JVMTI (CMVC 142897).
* Detail: heap10 requires no pre-indexing in order to preserve Java5 behaviour but heap11 requires pre-indexing to pass a Java6 JCK
Expand Down
5 changes: 5 additions & 0 deletions runtime/gc_include/HeapIteratorAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ typedef struct J9MM_HeapRootSlotDescriptor {
UDATA slotReachability; /**< Reachability of slot */
} J9MM_HeapRootSlotDescriptor;

typedef struct J9MM_StackSlotDescriptor {
J9VMThread *vmThread; /**< Thread containing the stack slot */
J9StackWalkState *walkState; /**< WalkState that found the slot, or null if found directly in thread local tables */
} J9MM_StackSlotDescriptor;

typedef jvmtiIterationControl (*rootIteratorCallBackFunc)(void* ptr, J9MM_HeapRootSlotDescriptor *rootDesc, void *userData);

/**
Expand Down
76 changes: 41 additions & 35 deletions runtime/jvmti/jvmtiHeap.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ static jvmtiError getArrayPrimitiveElements(J9JVMTIHeapData * iteratorData, jvmt
static jvmtiIterationControl followReferencesCallback(j9object_t * slotPtr, j9object_t referrer, void *userData, IDATA type, IDATA referrerIndex, IDATA wasReportedBefore);
static void mapEventType(J9JVMTIHeapData * data, IDATA type, jint index, j9object_t referrer, j9object_t object);
static void jvmtiFollowRefs_getTags(J9JVMTIHeapData * iteratorData, j9object_t referrer, j9object_t object);
static UDATA jvmtiHeapFollowRefs_getStackData(J9JVMTIHeapData * iteratorData, J9StackWalkState *walkState);
static UDATA jvmtiHeapFollowRefs_getStackData(J9JVMTIHeapData * iteratorData, J9MM_StackSlotDescriptor *stackSlotDescriptor);
static IDATA heapReferenceFilter(J9JVMTIHeapData * iteratorData);


Expand Down Expand Up @@ -756,7 +756,7 @@ wrap_heapReferenceCallback(J9JavaVM * vm, J9JVMTIHeapData * iteratorData)
case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
if (iteratorData->referrer) {
/* fill in the stack local and jni local data */
if (jvmtiHeapFollowRefs_getStackData(iteratorData, (J9StackWalkState *) iteratorData->referrer) == 0)
if (jvmtiHeapFollowRefs_getStackData(iteratorData, (J9MM_StackSlotDescriptor *) iteratorData->referrer) == 0)
return JVMTI_ITERATION_IGNORE;
} else {
/* No reference info available for heap roots, slime some bogus values
Expand Down Expand Up @@ -840,64 +840,70 @@ wrap_heapReferenceCallback(J9JavaVM * vm, J9JVMTIHeapData * iteratorData)
*
*/
static UDATA
jvmtiHeapFollowRefs_getStackData(J9JVMTIHeapData * iteratorData, J9StackWalkState *walkState)
jvmtiHeapFollowRefs_getStackData(J9JVMTIHeapData *iteratorData, J9MM_StackSlotDescriptor *stackSlotDescriptor)
{
J9JVMTIHeapEvent * e = &iteratorData->event;
jint slot = (jint) walkState->slotIndex;
jint depth = (jint) walkState->framesWalked;
J9Method * ramMethod = walkState->method;
jmethodID method;
J9JVMTIObjectTag search;
J9JVMTIObjectTag * result;
jlong threadID;


/* Convert internal slot type to JVMTI type */
switch (walkState->slotType) {
jint slot = -1;
jint depth = -1;
J9Method *ramMethod = NULL;
jmethodID method = (jmethodID) -1;
J9JVMTIObjectTag search = {NULL, 0};
J9JVMTIObjectTag *result = NULL;
jlong threadID = 0;
J9StackWalkState *walkState = stackSlotDescriptor->walkState;

if (NULL != walkState) {
slot = (jint) walkState->slotIndex;
depth = (jint) walkState->framesWalked;
ramMethod = walkState->method;

/* Convert internal slot type to JVMTI type. */

switch (walkState->slotType) {
case J9_STACKWALK_SLOT_TYPE_JNI_LOCAL:
e->refKind = JVMTI_HEAP_REFERENCE_JNI_LOCAL;
break;
case J9_STACKWALK_SLOT_TYPE_METHOD_LOCAL:
e->refKind = JVMTI_HEAP_REFERENCE_STACK_LOCAL;
break;
default:
/* Do not callback with stack slot types other then JNI or STACK Local */
/* Do not callback with stack slot types other then JNI or STACK Local. */
return 0;
}
}

/* If there's no method, set slot, method and depth to -1 */
/* If there's no method, slot, method and depth are set to -1 by default. */

if (ramMethod == NULL) {
slot = -1;
depth = -1;
method = (jmethodID) -1;
} else {
/* Cheating here - should be current thread, but the walk thread will do */
method = getCurrentMethodID(walkState->walkThread, ramMethod);
if (method == NULL) {
slot = -1;
depth = -1;
method = (jmethodID) -1;
if (NULL != ramMethod) {
/* Cheating here - should be current thread, but the walk thread will do. */
method = getCurrentMethodID(walkState->walkThread, ramMethod);
if (NULL == method) {
method = (jmethodID) -1;
}
}
}

/* Find thread tag */

search.ref = (j9object_t ) walkState->walkThread->threadObject;
result = hashTableFind(iteratorData->env->objectTagTable, &search);
search.ref = (j9object_t)stackSlotDescriptor->vmThread->threadObject;

/* Figure out the Thread ID */
if (NULL != search.ref) {
result = hashTableFind(iteratorData->env->objectTagTable, &search);

threadID = J9VMJAVALANGTHREAD_TID(iteratorData->currentThread, walkState->walkThread->threadObject);

/* Retrieve the Thread ID. */
threadID = J9VMJAVALANGTHREAD_TID(iteratorData->currentThread, stackSlotDescriptor->vmThread->threadObject);
} else {
/* Set 0 for tag/ID since ref to threadObject can be lost while walking a continuation. */
result = NULL;
threadID = 0;
}

switch (e->refKind) {
case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
e->refInfo.stack_local.thread_tag = (result) ? result->tag : 0;
e->refInfo.stack_local.thread_id = threadID;
e->refInfo.stack_local.depth = depth;
e->refInfo.stack_local.method = method;
e->refInfo.stack_local.location = (jlocation) walkState->bytecodePCOffset;
e->refInfo.stack_local.location = (jlocation) ((walkState) ? walkState->bytecodePCOffset : 0);
e->refInfo.stack_local.slot = slot;
break;

Expand Down Expand Up @@ -1096,7 +1102,7 @@ mapEventType(J9JVMTIHeapData * data, IDATA type, jint index, j9object_t referrer
break;

case J9GC_ROOT_TYPE_JNI_LOCAL:
event->type = J9JVMTI_HEAP_EVENT_ROOT;
event->type = J9JVMTI_HEAP_EVENT_STACK;
event->refKind = JVMTI_HEAP_REFERENCE_JNI_LOCAL;
event->hasRefInfo = TRUE;
break;
Expand Down
59 changes: 29 additions & 30 deletions runtime/jvmti/jvmtiHeap10.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ typedef struct J9JVMTIHeapEvent {
} J9JVMTIHeapEvent;

static jvmtiIterationControl processHeapRoot (J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlong size, jlong classTag, jvmtiHeapRootKind kind);
static jvmtiIterationControl processStackRoot (J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlong size, jlong classTag, J9StackWalkState * walkState);
static jvmtiIterationControl processStackRoot (J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlong size, jlong classTag, jvmtiHeapRootKind kind, J9MM_StackSlotDescriptor * walkState);
static jvmtiIterationControl wrapHeapIterationCallback(J9JavaVM * vm, J9MM_IterateObjectDescriptor *objectDesc, void * userData);
static J9JVMTIHeapEvent mapEventType (J9VMThread *vmThread, J9JVMTIObjectIteratorData * data, IDATA type, IDATA index, j9object_t referrer, j9object_t object);
static jvmtiIterationControl wrapObjectIterationCallback (j9object_t *slotPtr, j9object_t referrer, void *userData, IDATA type, IDATA referrerIndex, IDATA wasReportedBefore);
Expand Down Expand Up @@ -309,7 +309,7 @@ mapEventType(J9VMThread *vmThread, J9JVMTIObjectIteratorData * data, IDATA type,
break;

case J9GC_ROOT_TYPE_JNI_LOCAL:
event.type = J9JVMTI_HEAP_EVENT_ROOT;
event.type = J9JVMTI_HEAP_EVENT_STACK;
event.rootKind = JVMTI_HEAP_ROOT_JNI_LOCAL;
break;

Expand Down Expand Up @@ -462,19 +462,24 @@ processObjectRef(J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlo


static jvmtiIterationControl
processStackRoot(J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlong size, jlong classTag, J9StackWalkState * walkState)
processStackRoot(J9JVMTIObjectIteratorData *data, J9JVMTIObjectTag *entry, jlong size, jlong classTag, jvmtiHeapRootKind kind, J9MM_StackSlotDescriptor *stackSlotDescriptor)
{
jvmtiHeapRootKind kind;
jint slot = (jint) walkState->slotIndex;
jint depth = (jint) walkState->framesWalked;
J9Method * ramMethod = walkState->method;
jmethodID method;
J9JVMTIObjectTag search;
J9JVMTIObjectTag * result;

/* Convert internal slot type to JVMTI type */

switch (walkState->slotType) {
jint slot = -1;
jint depth = -1;
J9Method *ramMethod = NULL;
jmethodID method = (jmethodID) -1;
J9JVMTIObjectTag search = {NULL, 0};
J9JVMTIObjectTag *result = NULL;

if (NULL != stackSlotDescriptor->walkState) {
J9StackWalkState *walkState = stackSlotDescriptor->walkState;
slot = (jint) walkState->slotIndex;
depth = (jint) walkState->framesWalked;
ramMethod = walkState->method;

/* Convert internal slot type to JVMTI type. */

switch (walkState->slotType) {
case J9_STACKWALK_SLOT_TYPE_JNI_LOCAL:
kind = JVMTI_HEAP_ROOT_JNI_LOCAL;
break;
Expand All @@ -485,27 +490,21 @@ processStackRoot(J9JVMTIObjectIteratorData * data, J9JVMTIObjectTag * entry, jlo
kind = JVMTI_HEAP_ROOT_JNI_LOCAL;
ramMethod = NULL;
break;
}
}

/* If there's no method, set slot, method and depth to -1 */

if (ramMethod == NULL) {
slot = -1;
depth = -1;
method = (jmethodID) -1;
} else {
/* Cheating here - should be current thread, but the walk thread will do */
method = getCurrentMethodID(walkState->walkThread, ramMethod);
if (method == NULL) {
slot = -1;
depth = -1;
method = (jmethodID) -1;
/* If there's no method, slot, method and depth are set to -1 by default. */
if (NULL != ramMethod) {
/* Cheating here - should be current thread, but the walk thread will do. */
method = getCurrentMethodID(walkState->walkThread, ramMethod);
if (NULL == method) {
method = (jmethodID) -1;
}
}
}

/* Find thread tag */

search.ref = (j9object_t) walkState->walkThread->threadObject;
search.ref = (j9object_t)stackSlotDescriptor->vmThread->threadObject;
result = hashTableFind(data->env->objectTagTable, &search);

/* Call the callback */
Expand Down Expand Up @@ -639,7 +638,7 @@ wrapObjectIterationCallback(j9object_t *slotPtr, j9object_t referrer, void *user
returnCode = processHeapRoot(iteratorData, result, objectSize, classTag, event.rootKind);
break;
case J9JVMTI_HEAP_EVENT_STACK:
returnCode = processStackRoot(iteratorData, result, objectSize, classTag, (J9StackWalkState *) referrer);
returnCode = processStackRoot(iteratorData, result, objectSize, classTag, event.rootKind, (J9MM_StackSlotDescriptor *)referrer);
break;
case J9JVMTI_HEAP_EVENT_OBJECT:
returnCode = processObjectRef(iteratorData, result, objectSize, classTag, event.refKind, referrerTag, (jint)event.index);
Expand Down

0 comments on commit 64cb0db

Please sign in to comment.