Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor J9JVMTI_HEAP_EVENT_STACK data parsing #18864

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 */
fengxue-IS marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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