From e5e7b7eea8d9539860c99e50a97dace67e794291 Mon Sep 17 00:00:00 2001 From: Graham Chapman Date: Mon, 11 Aug 2025 21:58:12 -0400 Subject: [PATCH 1/4] Part 1 of stack walker ROM method cache Signed-off-by: Graham Chapman --- runtime/codert_vm/jswalk.c | 10 ++ runtime/oti/j9modifiers_api.h | 5 +- runtime/oti/j9nonbuilder.h | 35 +++++-- runtime/oti/stackmap_api.h | 29 ++---- runtime/stackmap/mapcache.cpp | 61 ++++++++++- runtime/vm/classallocation.c | 14 +-- runtime/vm/swalk.c | 185 ++++++++++++++++++++++------------ 7 files changed, 231 insertions(+), 108 deletions(-) diff --git a/runtime/codert_vm/jswalk.c b/runtime/codert_vm/jswalk.c index efbfe38f71e..1c46b7afd20 100644 --- a/runtime/codert_vm/jswalk.c +++ b/runtime/codert_vm/jswalk.c @@ -172,6 +172,9 @@ UDATA jitWalkStackFrames(J9StackWalkState *walkState) walkState->dropToCurrentFrame = jitDropToCurrentFrame; while ((walkState->jitInfo = jitGetExceptionTable(walkState)) != NULL) { +#if defined(J9MAPCACHE_DEBUG) + memset(&walkState->romMethodInfo, 0, sizeof(walkState->romMethodInfo)); +#endif /* J9MAPCACHE_DEBUG */ walkState->stackMap = NULL; walkState->inlineMap = NULL; walkState->bp = walkState->unwindSP + getJitTotalFrameSize(walkState->jitInfo); @@ -212,6 +215,8 @@ UDATA jitWalkStackFrames(J9StackWalkState *walkState) lswRecord(walkState, LSW_TYPE_METHOD, walkState->method); lswRecord(walkState, LSW_TYPE_JIT_FRAME_INFO, walkState); #endif + initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + if ((rc = walkFrame(walkState)) != J9_STACKWALK_KEEP_ITERATING) { return rc; } @@ -250,6 +255,7 @@ UDATA jitWalkStackFrames(J9StackWalkState *walkState) #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING lswRecord(walkState, LSW_TYPE_JIT_FRAME_INFO, walkState); #endif + initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); if ((rc = walkFrame(walkState)) != J9_STACKWALK_KEEP_ITERATING) { return rc; } @@ -1977,6 +1983,9 @@ jitWalkOSRFrame(J9StackWalkState *walkState, J9OSRFrame *osrFrame) UDATA *localSlots = ((UDATA*)(osrFrame + 1)) + maxStack; UDATA *nextFrame = localSlots + numberOfLocals; J9MonitorEnterRecord *enterRecord = osrFrame->monitorEnterRecords; + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method); + + initializeBasicROMMethodInfo(walkState, romMethod); #ifdef J9VM_INTERP_STACKWALK_TRACING { @@ -1987,6 +1996,7 @@ jitWalkOSRFrame(J9StackWalkState *walkState, J9OSRFrame *osrFrame) walkState->method = stateMethod; } #endif + walkBytecodeFrameSlots(walkState, method, offsetPC, localSlots - 1, pendingStackHeight, nextFrame - 1, numberOfLocals, TRUE); diff --git a/runtime/oti/j9modifiers_api.h b/runtime/oti/j9modifiers_api.h index 086af962ed0..01042173b34 100644 --- a/runtime/oti/j9modifiers_api.h +++ b/runtime/oti/j9modifiers_api.h @@ -116,8 +116,9 @@ /* Composite Flag checks */ #define J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass) _J9ROMCLASS_SUNMODIFIER_IS_ANY_SET((romClass), J9AccClassArray | J9AccClassInternalPrimitiveType) -#define J9ROMMETHOD_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(romMethod) \ - ((((romMethod)->modifiers) & (J9AccMethodObjectConstructor | J9AccEmptyMethod)) == J9AccMethodObjectConstructor) +#define J9ROMMETHOD_MODIFIERS_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(modifiers) \ + (((modifiers) & (J9AccMethodObjectConstructor | J9AccEmptyMethod)) == J9AccMethodObjectConstructor) +#define J9ROMMETHOD_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(romMethod) J9ROMMETHOD_MODIFIERS_IS_NON_EMPTY_OBJECT_CONSTRUCTOR((romMethod)->modifiers) /* Class instances are allocated via the new bytecode */ #define J9ROMCLASS_ALLOCATES_VIA_NEW(romClass) \ diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 7acbb833c4b..be5f1337c91 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -1147,12 +1147,32 @@ typedef struct J9CudaGlobals { jmethodID runnable_run; } J9CudaGlobals; -#define J9_MAP_CACHE_SLOTS 2 - -typedef struct J9MapCacheEntry { +/* Cache slot sizes must all be multiples of 2 */ +#define J9_STACKMAP_CACHE_SLOTS 2 +#define J9_LOCALMAP_CACHE_SLOTS 2 +#define J9_ARGBITS_CACHE_SLOTS 2 + +/* Flag values for J9ROMMethodInfo */ +#define J9MAPCACHE_STACKMAP_CACHED 1 +#define J9MAPCACHE_LOCALMAP_CACHED 2 +#define J9MAPCACHE_ARGBITS_CACHED 4 +#define J9MAPCACHE_METHOD_IS_CONSTRUCTOR 8 +#define J9MAPCACHE_VALID 128 + +/* J9ROMMethodInfo must be a multiple of 8 bytes in size */ +typedef struct J9ROMMethodInfo { void *key; - U_32 bits[J9_MAP_CACHE_SLOTS]; -} J9MapCacheEntry; + U_32 stackmap[J9_STACKMAP_CACHE_SLOTS]; + U_32 localmap[J9_ARGBITS_CACHE_SLOTS]; + U_32 argbits[J9_ARGBITS_CACHE_SLOTS]; + U_32 modifiers; + U_16 tempCount; + U_8 argCount; + U_8 flags; +#if !defined(J9VM_ENV_DATA64) + U_32 padTo64; +#endif /* !defined(J9VM_ENV_DATA64) */ +} J9ROMMethodInfo; #if defined(J9VM_OPT_SHARED_CLASSES) @@ -2824,6 +2844,7 @@ typedef struct J9StackWalkState { void* stackMap; void* inlineMap; UDATA loopBreaker; + J9ROMMethodInfo romMethodInfo; /* 64-bit aligned */ /* The size of J9StackWalkState must be a multiple of 8 because it is inlined into * J9VMThread where alignment assumotions are being made. */ @@ -3756,9 +3777,7 @@ typedef struct J9ClassLoader { UDATA initClassPathEntryCount; UDATA asyncGetCallTraceUsed; omrthread_monitor_t mapCacheMutex; - struct J9HashTable* localmapCache; - struct J9HashTable* argsbitsCache; - struct J9HashTable* stackmapCache; + struct J9HashTable* romMethodInfoCache; #if defined(J9VM_OPT_JFR) J9HashTable *typeIDs; #endif /* defined(J9VM_OPT_JFR) */ diff --git a/runtime/oti/stackmap_api.h b/runtime/oti/stackmap_api.h index e242adb89e3..d52ac004b8a 100644 --- a/runtime/oti/stackmap_api.h +++ b/runtime/oti/stackmap_api.h @@ -196,30 +196,15 @@ j9stackmap_StackBitsForPC(J9PortLibrary * portLib, UDATA pc, J9ROMClass * romCla UDATA * (* getBuffer) (void * userData), void (* releaseBuffer) (void * userData)); +/* ---------------- mapcache.cpp ---------------- */ -/* ------------------- mapcache.cpp ----------------- */ - -/* These are cache wrapper functions with the same parameters as the j9localmap_ versions, - * with VM and J9ClassLoader added on the end. - */ - -IDATA -j9cached_StackBitsForPC(UDATA pc, J9ROMClass * romClass, J9ROMMethod * romMethod, - U_32 * resultArrayBase, UDATA resultArraySize, - void * userData, - UDATA * (* getBuffer) (void * userData), - void (* releaseBuffer) (void * userData), - J9JavaVM *vm, J9ClassLoader *classLoader); - +/** +* @brief +* @param walkState +* @param romMethod +*/ void -j9cached_ArgBitsForPC0(J9ROMClass *romClass, J9ROMMethod *romMethod, U_32 *resultArrayBase, J9JavaVM *vm, J9ClassLoader *classLoader); - -IDATA -j9cached_LocalBitsForPC(J9ROMClass * romClass, J9ROMMethod * romMethod, UDATA pc, U_32 * resultArrayBase, - void * userData, - UDATA * (* getBuffer) (void * userData), - void (* releaseBuffer) (void * userData), - J9JavaVM *vm, J9ClassLoader * classLoader); +initializeBasicROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod); #ifdef __cplusplus } diff --git a/runtime/stackmap/mapcache.cpp b/runtime/stackmap/mapcache.cpp index bdc312bfec8..5b9a477db1a 100644 --- a/runtime/stackmap/mapcache.cpp +++ b/runtime/stackmap/mapcache.cpp @@ -25,6 +25,60 @@ extern "C" { +void +initializeBasicROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod) +{ + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; + memset(romMethodInfo, 0, sizeof(*romMethodInfo)); + romMethodInfo->argCount = romMethod->argCount; + romMethodInfo->tempCount = romMethod->tempCount; + romMethodInfo->modifiers = romMethod->modifiers; +#if defined(J9MAPCACHE_DEBUG) + romMethodInfo->flags = J9MAPCACHE_VALID; +#endif /* J9MAPCACHE_DEBUG */ + if (!(romMethod->modifiers & J9AccStatic)) { + if (J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod))[0] == '<') { + romMethodInfo->flags |= J9MAPCACHE_METHOD_IS_CONSTRUCTOR; + } + } +} + +void +populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key) +{ + initializeBasicROMMethodInfo(walkState, romMethod); +#if 0 + bool found = false; + J9Method *method = walkState->method; + J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; + + /* If the mapCacheMutex exists, the caching feature is enabled */ + if (NULL != mapCacheMutex) { + omrthread_monitor_enter(mapCacheMutex); + J9HashTable *mapCache = classLoader->romMethodInfoCache; + + /* If the cache exists, check it for this key */ + if (NULL != mapCache) { + J9ROMMethodInfo exemplar = { 0 }; + exemplar.key = key; + J9ROMMethodInfo *entry = (J9ROMMethodInfo*)hashTableFind(mapCache, &exemplar); + + if (NULL != entry) { + /* Cache hit - copy the info */ + *romMethodInfo = *entry; + } else { + /* Cache miss - populate the info and cache it */ + } + } + + omrthread_monitor_exit(mapCacheMutex); + } +#endif +} + +#if 0 + /** * @brief Map cache hash function * @param key J9MapCacheEntry pointer @@ -83,7 +137,7 @@ checkCache(J9JavaVM *vm, J9ClassLoader *classLoader, void *key, J9HashTable *map J9MapCacheEntry *entry = (J9MapCacheEntry*)hashTableFind(mapCache, &exemplar); if (NULL != entry) { - memcpy(resultArrayBase, entry->bits, sizeof(U_32) * mapWords); + memcpy(resultArrayBase, &entry->data.bits, sizeof(U_32) * mapWords); found = true; } } @@ -135,7 +189,7 @@ updateCache(J9JavaVM *vm, J9ClassLoader *classLoader, void *key, J9HashTable **c if (NULL != mapCache) { J9MapCacheEntry entry = { 0 }; entry.key = key; - memcpy(entry.bits, resultArrayBase, sizeof(U_32) * mapWords); + memcpy(&entry.data.bits, resultArrayBase, sizeof(U_32) * mapWords); hashTableAdd(mapCache, &entry); } @@ -201,4 +255,7 @@ j9cached_LocalBitsForPC(J9ROMClass * romClass, J9ROMMethod * romMethod, UDATA pc return rc; } +#endif + + } /* extern "C" */ diff --git a/runtime/vm/classallocation.c b/runtime/vm/classallocation.c index 0d61b465379..da7ec7c5e38 100644 --- a/runtime/vm/classallocation.c +++ b/runtime/vm/classallocation.c @@ -67,17 +67,9 @@ U_32 classPropagationTable[CLASS_PROPAGATION_TABLE_SIZE] = { void freeMapCaches(J9ClassLoader *classLoader) { - if (NULL != classLoader->localmapCache) { - hashTableFree(classLoader->localmapCache); - classLoader->localmapCache = NULL; - } - if (NULL != classLoader->argsbitsCache) { - hashTableFree(classLoader->argsbitsCache); - classLoader->argsbitsCache = NULL; - } - if (NULL != classLoader->stackmapCache) { - hashTableFree(classLoader->stackmapCache); - classLoader->stackmapCache = NULL; + if (NULL != classLoader->romMethodInfoCache) { + hashTableFree(classLoader->romMethodInfoCache); + classLoader->romMethodInfoCache = NULL; } } diff --git a/runtime/vm/swalk.c b/runtime/vm/swalk.c index f29d5025dea..ef28d58217e 100644 --- a/runtime/vm/swalk.c +++ b/runtime/vm/swalk.c @@ -55,6 +55,13 @@ #include +#if defined(J9MAPCACHE_DEBUG) +#define ENSURE_ROM_METHOD_INFO_VALID(romMethodInfo) \ + if (J9_ARE_NO_BITS_SET(romMethodInfo->flags, J9MAPCACHE_VALID)) *(UDATA*)-1=-1 +#else /* J9MAPCACHE_DEBUG */ +#define ENSURE_ROM_METHOD_INFO_VALID(romMethodInfo) +#endif /* J9MAPCACHE_DEBUG */ + #if (defined(J9VM_INTERP_STACKWALK_TRACING)) static void printFrameType (J9StackWalkState * walkState, char * frameType); @@ -309,6 +316,11 @@ UDATA walkStackFrames(J9VMThread *currentThread, J9StackWalkState *walkState) walkState->outgoingArgCount = walkState->argCount; walkState->bytecodePCOffset = -1; +#if defined(J9MAPCACHE_DEBUG) + memset(&walkState->romMethodInfo, 0, sizeof(walkState->romMethodInfo)); +#endif /* J9MAPCACHE_DEBUG */ + + #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING lswFrameNew(vm, walkState, (UDATA)walkState->pc); #endif @@ -489,16 +501,14 @@ UDATA walkFrame(J9StackWalkState * walkState) } if (walkState->flags & J9_STACKWALK_HIDE_EXCEPTION_FRAMES) { - J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); - - if (!(romMethod->modifiers & J9AccStatic)) { - if (J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod))[0] == '<') { - if (*walkState->arg0EA == (UDATA) walkState->restartException) { - return J9_STACKWALK_KEEP_ITERATING; - } + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; + ENSURE_ROM_METHOD_INFO_VALID(romMethodInfo); + if (J9_ARE_ANY_BITS_SET(romMethodInfo->flags, J9MAPCACHE_METHOD_IS_CONSTRUCTOR)) { + if (*walkState->arg0EA == (UDATA) walkState->restartException) { + return J9_STACKWALK_KEEP_ITERATING; } - walkState->flags &= ~J9_STACKWALK_HIDE_EXCEPTION_FRAMES; } + walkState->flags &= ~J9_STACKWALK_HIDE_EXCEPTION_FRAMES; } } @@ -709,6 +719,9 @@ walkMethodFrame(J9StackWalkState * walkState) walkState->frameFlags = methodFrame->specialFrameFlags; MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodFrame->specialFrameFlags)); walkState->method = methodFrame->method; + if (NULL != walkState->method) { + initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + } walkState->unwindSP = (UDATA *) methodFrame; #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING @@ -745,22 +758,31 @@ walkMethodFrame(J9StackWalkState * walkState) } if (walkState->method) { J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; + + initializeBasicROMMethodInfo(walkState, romMethod); walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); - walkState->argCount = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod); + walkState->argCount = romMethodInfo->argCount; if (walkState->flags & J9_STACKWALK_ITERATE_O_SLOTS) { WALK_METHOD_CLASS(walkState); if (walkState->argCount) { /* Max size as argCount always <= 255 */ - U_32 result[8]; + U_32 inlineResult[8]; + U_32 *result = inlineResult; J9Class *methodClass = UNTAGGED_METHOD_CP(walkState->method)->ramClass; #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 4, "\tUsing signature mapper\n"); #endif - j9cached_ArgBitsForPC0(methodClass->romClass, romMethod, result, walkState->javaVM, methodClass->classLoader); + + if (J9_ARE_ANY_BITS_SET(romMethodInfo->flags, J9MAPCACHE_ARGBITS_CACHED)) { + result = romMethodInfo->argbits; + } else { + j9localmap_ArgBitsForPC0(methodClass->romClass, romMethod, result); + } #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 4, "\tArguments starting at %p for %d slots\n", walkState->arg0EA, walkState->argCount); @@ -812,7 +834,7 @@ walkMethodTypeFrame(J9StackWalkState * walkState) MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodTypeFrame->specialFrameFlags)); MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodTypeFrame->argStackSlots)); MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodTypeFrame->descriptionIntCount)); - walkState->method = NULL; + NULL; walkState->unwindSP = (UDATA *) methodTypeFrame; #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING @@ -879,21 +901,20 @@ walkBytecodeFrameSlots(J9StackWalkState *walkState, J9Method *method, UDATA offs { J9JavaVM *vm = walkState->javaVM; PORT_ACCESS_FROM_JAVAVM(vm); + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; UDATA *bp = localBase - numberOfLocals; - J9Class *ramClass = J9_CLASS_FROM_METHOD(method); - J9ROMClass *romClass = ramClass->romClass; - J9ROMMethod *romMethod = getOriginalROMMethod(method); - U_32 smallResult = 0; - U_32 *result = &smallResult; U_32 *globalBuffer = NULL; UDATA numberOfMappedLocals = numberOfLocals; + U_32 modifiers = romMethodInfo->modifiers; + U_32 flags = romMethodInfo->flags; + + ENSURE_ROM_METHOD_INFO_VALID(romMethodInfo); #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 3, "\tBytecode index = %d\n", offsetPC); #endif - - if (romMethod->modifiers & J9AccSynchronized) { + if (modifiers & J9AccSynchronized) { #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 4, "\tSync object for synchronized method\n"); #endif @@ -901,7 +922,7 @@ walkBytecodeFrameSlots(J9StackWalkState *walkState, J9Method *method, UDATA offs walkState->slotIndex = -1; WALK_NAMED_O_SLOT((j9object_t*) (bp + 1), "Sync O-Slot"); numberOfMappedLocals -= 1; - } else if (J9ROMMETHOD_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(romMethod)) { + } else if (J9ROMMETHOD_MODIFIERS_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(modifiers)) { /* Non-empty java.lang.Object. has one hidden temp to hold a copy of the receiver */ #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 4, "\tReceiver object for java.lang.Object.\n"); @@ -912,40 +933,57 @@ walkBytecodeFrameSlots(J9StackWalkState *walkState, J9Method *method, UDATA offs numberOfMappedLocals -= 1; } - if ((numberOfMappedLocals > 32) || (pendingStackHeight > 32)) { - UDATA maxCount = (numberOfMappedLocals > pendingStackHeight) ? numberOfMappedLocals : pendingStackHeight; - result = j9mem_allocate_memory(((maxCount + 31) >> 5) * sizeof(U_32), OMRMEM_CATEGORY_VM); - if (NULL == result) { - globalBuffer = j9mapmemory_GetResultsBuffer(vm); - result = globalBuffer; + { + J9ROMClass *romClass = J9_CLASS_FROM_METHOD(method)->romClass; + J9ROMMethod *romMethod = getOriginalROMMethod(method); + U_32 smallResult = 0; + U_32 *result = &smallResult; + BOOLEAN freeBuffer = FALSE; + + if ((numberOfMappedLocals > 32) || (pendingStackHeight > 32)) { + UDATA maxCount = (numberOfMappedLocals > pendingStackHeight) ? numberOfMappedLocals : pendingStackHeight; + result = j9mem_allocate_memory(((maxCount + 31) >> 5) * sizeof(U_32), OMRMEM_CATEGORY_VM); + if (NULL == result) { + globalBuffer = j9mapmemory_GetResultsBuffer(vm); + result = globalBuffer; + } + freeBuffer = TRUE; } - } - if (0 != numberOfMappedLocals) { - getLocalsMap(walkState, romClass, romMethod, offsetPC, result, numberOfMappedLocals, alwaysLocalMap); + if (0 != numberOfMappedLocals) { + if (J9_ARE_ANY_BITS_SET(flags, J9MAPCACHE_LOCALMAP_CACHED)) { + result = romMethodInfo->localmap; + } else { + getLocalsMap(walkState, romClass, romMethod, offsetPC, result, numberOfMappedLocals, alwaysLocalMap); + } #ifdef J9VM_INTERP_STACKWALK_TRACING - swPrintf(walkState, 4, "\tLocals starting at %p for %d slots\n", localBase, numberOfMappedLocals); + swPrintf(walkState, 4, "\tLocals starting at %p for %d slots\n", localBase, numberOfMappedLocals); #endif - walkState->slotType = J9_STACKWALK_SLOT_TYPE_METHOD_LOCAL; - walkState->slotIndex = 0; - walkDescribedPushes(walkState, localBase, numberOfMappedLocals, result, romMethod->argCount); - } + walkState->slotType = J9_STACKWALK_SLOT_TYPE_METHOD_LOCAL; + walkState->slotIndex = 0; + walkDescribedPushes(walkState, localBase, numberOfMappedLocals, result, romMethodInfo->argCount); + } - if (0 != pendingStackHeight) { - getStackMap(walkState, romClass, romMethod, offsetPC, pendingStackHeight, result); + if (0 != pendingStackHeight) { + if (J9_ARE_ANY_BITS_SET(flags, J9MAPCACHE_STACKMAP_CACHED)) { + result = romMethodInfo->stackmap; + } else { + getStackMap(walkState, romClass, romMethod, offsetPC, pendingStackHeight, result); + } #ifdef J9VM_INTERP_STACKWALK_TRACING - swPrintf(walkState, 4, "\tPending stack starting at %p for %d slots\n", pendingBase, pendingStackHeight); + swPrintf(walkState, 4, "\tPending stack starting at %p for %d slots\n", pendingBase, pendingStackHeight); #endif - walkState->slotType = J9_STACKWALK_SLOT_TYPE_PENDING; - walkState->slotIndex = 0; - walkDescribedPushes(walkState, pendingBase, pendingStackHeight, result, 0); - } + walkState->slotType = J9_STACKWALK_SLOT_TYPE_PENDING; + walkState->slotIndex = 0; + walkDescribedPushes(walkState, pendingBase, pendingStackHeight, result, 0); + } - if (result != &smallResult) { - if (NULL == globalBuffer) { - j9mem_free_memory(result); - } else { - j9mapmemory_ReleaseResultsBuffer(vm); + if (freeBuffer) { + if (NULL == globalBuffer) { + j9mem_free_memory(result); + } else { + j9mapmemory_ReleaseResultsBuffer(vm); + } } } } @@ -985,6 +1023,9 @@ walkBytecodeFrame(J9StackWalkState * walkState) #endif /* defined(J9VM_OPT_METHOD_HANDLE) */ UDATA argTempCount = 0; J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; + + initializeBasicROMMethodInfo(walkState, romMethod); walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); @@ -999,16 +1040,16 @@ walkBytecodeFrame(J9StackWalkState * walkState) walkState->bytecodePCOffset = walkState->pc - (U_8 *) J9_BYTECODE_START_FROM_RAM_METHOD(walkState->method); #endif /* defined(J9VM_OPT_METHOD_HANDLE) */ - walkState->argCount = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod); - argTempCount = J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod) + walkState->argCount; + walkState->argCount = romMethodInfo->argCount; + argTempCount = romMethodInfo->tempCount + walkState->argCount; walkState->bp = walkState->arg0EA - argTempCount; - if (romMethod->modifiers & J9AccSynchronized) { + if (romMethodInfo->modifiers & J9AccSynchronized) { #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING lswRecordSlot(walkState, walkState->bp, LSW_TYPE_O_SLOT, "Sync Object"); #endif argTempCount += 1; walkState->bp -= 1; - } else if (J9ROMMETHOD_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(romMethod)) { + } else if (((romMethodInfo->modifiers) & (J9AccMethodObjectConstructor | J9AccEmptyMethod)) == J9AccMethodObjectConstructor) { /* Non-empty java.lang.Object. has one hidden temp to hold a copy of the receiver */ #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING lswRecordSlot(walkState, walkState->bp, LSW_TYPE_O_SLOT, "Receiver Object"); @@ -1035,8 +1076,8 @@ walkBytecodeFrame(J9StackWalkState * walkState) if (walkState->flags & J9_STACKWALK_ITERATE_O_SLOTS) { WALK_METHOD_CLASS(walkState); - walkBytecodeFrameSlots(walkState, walkState->method, walkState->bytecodePCOffset, - walkState->unwindSP - 1, walkState->unwindSP - walkState->walkSP, + walkBytecodeFrameSlots(walkState, walkState->method, + walkState->bytecodePCOffset, walkState->unwindSP - 1, walkState->unwindSP - walkState->walkSP, walkState->arg0EA, argTempCount, FALSE); } } @@ -1190,6 +1231,9 @@ static void walkJITJNICalloutFrame(J9StackWalkState * walkState) walkState->frameFlags = methodFrame->specialFrameFlags; MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodFrame->specialFrameFlags)); walkState->method = methodFrame->method; + if (NULL != walkState->method) { + initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + } walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); #ifdef J9VM_INTERP_STACKWALK_TRACING printFrameType(walkState, "JIT JNI call-out"); @@ -1500,8 +1544,11 @@ static void getLocalsMap(J9StackWalkState * walkState, J9ROMClass * romClass, J9ROMMethod * romMethod, UDATA offsetPC, U_32 * result, UDATA argTempCount, UDATA alwaysLocalMap) { PORT_ACCESS_FROM_WALKSTATE(walkState); - IDATA errorCode; J9JavaVM *vm = walkState->walkThread->javaVM; + J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; + UDATA copySize = ((argTempCount + 31) / 32) * sizeof(U_32); + + ENSURE_ROM_METHOD_INFO_VALID(romMethodInfo); if (!alwaysLocalMap) { /* Detect method entry vs simply executing at PC 0. If the bytecode frame is invisible (method monitor enter or @@ -1520,9 +1567,16 @@ getLocalsMap(J9StackWalkState * walkState, J9ROMClass * romClass, J9ROMMethod * #endif /* j9localmap_ArgBitsForPC0 only deals with args, so zero out the result array to make sure the temps are non-object */ + memset(result, 0, copySize); + if (J9_ARE_ANY_BITS_SET(romMethodInfo->flags, J9MAPCACHE_ARGBITS_CACHED)) { + if (copySize > sizeof(romMethodInfo->argbits)) { + copySize = sizeof(romMethodInfo->argbits); + } + memcpy(result, romMethodInfo->argbits, copySize); + } else { + j9localmap_ArgBitsForPC0(romClass, romMethod, result); + } - memset(result, 0, ((argTempCount + 31) / 32) * sizeof(U_32)); - j9cached_ArgBitsForPC0(romClass, romMethod, result, walkState->javaVM, UNTAGGED_METHOD_CP(walkState->method)->ramClass->classLoader); return; } } @@ -1530,17 +1584,22 @@ getLocalsMap(J9StackWalkState * walkState, J9ROMClass * romClass, J9ROMMethod * #ifdef J9VM_INTERP_STACKWALK_TRACING swPrintf(walkState, 4, "\tUsing local mapper\n"); #endif - errorCode = j9cached_LocalBitsForPC(romClass, romMethod, offsetPC, result, vm, j9mapmemory_GetBuffer, j9mapmemory_ReleaseBuffer, vm, J9_CLASS_FROM_METHOD(walkState->method)->classLoader); - if (errorCode < 0) { - if (J9_ARE_NO_BITS_SET(walkState->flags, J9_STACKWALK_NO_ERROR_REPORT)) { - /* Local map failed, result = %p - aborting VM - needs new message TBD */ - j9nls_printf(PORTLIB, J9NLS_ERROR, J9NLS_VM_STACK_MAP_FAILED, errorCode); + if (J9_ARE_ANY_BITS_SET(romMethodInfo->flags, J9MAPCACHE_LOCALMAP_CACHED)) { + memcpy(result, romMethodInfo->localmap, copySize); + } else { + IDATA errorCode = vm->localMapFunction(vm->portLibrary, romClass, romMethod, offsetPC, result, vm, j9mapmemory_GetBuffer, j9mapmemory_ReleaseBuffer); + + if (errorCode < 0) { + if (J9_ARE_NO_BITS_SET(walkState->flags, J9_STACKWALK_NO_ERROR_REPORT)) { + /* Local map failed, result = %p - aborting VM - needs new message TBD */ + j9nls_printf(PORTLIB, J9NLS_ERROR, J9NLS_VM_STACK_MAP_FAILED, errorCode); #if defined(J9VM_INTERP_STACKWALK_TRACING) - Assert_VRB_stackMapFailed(); + Assert_VRB_stackMapFailed(); #else /* J9VM_INTERP_STACKWALK_TRACING */ - Assert_VM_stackMapFailed(); + Assert_VM_stackMapFailed(); #endif /* J9VM_INTERP_STACKWALK_TRACING */ + } } } @@ -1554,7 +1613,7 @@ getStackMap(J9StackWalkState * walkState, J9ROMClass * romClass, J9ROMMethod * r PORT_ACCESS_FROM_WALKSTATE(walkState); IDATA errorCode; - errorCode = j9cached_StackBitsForPC(offsetPC, romClass, romMethod, result, pushCount, walkState->javaVM, j9mapmemory_GetBuffer, j9mapmemory_ReleaseBuffer, walkState->javaVM, UNTAGGED_METHOD_CP(walkState->method)->ramClass->classLoader); + errorCode = j9stackmap_StackBitsForPC(PORTLIB, offsetPC, romClass, romMethod, result, pushCount, walkState->javaVM, j9mapmemory_GetBuffer, j9mapmemory_ReleaseBuffer); if (errorCode < 0) { if (J9_ARE_NO_BITS_SET(walkState->flags, J9_STACKWALK_NO_ERROR_REPORT)) { /* Local map failed, result = %p - aborting VM */ From 07d9c6dd8b6a8f153d3a94c785795813162a8ade Mon Sep 17 00:00:00 2001 From: Harshitha Popuri Date: Tue, 11 Nov 2025 07:35:33 -0800 Subject: [PATCH 2/4] Implement ROMMethodInfo caching support in mapcache --- runtime/oti/stackmap_api.h | 17 ++++ runtime/stackmap/mapcache.cpp | 177 +++++++++++++++++++++++++++++++++- runtime/vm/swalk.c | 8 +- 3 files changed, 195 insertions(+), 7 deletions(-) diff --git a/runtime/oti/stackmap_api.h b/runtime/oti/stackmap_api.h index d52ac004b8a..e67394e64c5 100644 --- a/runtime/oti/stackmap_api.h +++ b/runtime/oti/stackmap_api.h @@ -206,6 +206,23 @@ j9stackmap_StackBitsForPC(J9PortLibrary * portLib, UDATA pc, J9ROMClass * romCla void initializeBasicROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod); +/** + * @brief + * @param walkState + * @param romMethod + */ +void +getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod); + +/** + * @brief + * @param walkState + * @param romMethod + * @param pc + */ +void +getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMethod, UDATA pc); + #ifdef __cplusplus } #endif diff --git a/runtime/stackmap/mapcache.cpp b/runtime/stackmap/mapcache.cpp index 5b9a477db1a..e1f197c0124 100644 --- a/runtime/stackmap/mapcache.cpp +++ b/runtime/stackmap/mapcache.cpp @@ -22,7 +22,6 @@ #include "rommeth.h" #include "stackmap_api.h" - extern "C" { void @@ -43,11 +42,183 @@ initializeBasicROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod } } +static UDATA +romMethodInfoHashFn(void *key, void *userData) +{ + J9ROMMethodInfo *entry = (J9ROMMethodInfo *)key; + return (UDATA)entry->key; +} + +static UDATA +romMethodInfoEqualFn(void *leftKey, void *rightKey, void *userData) +{ + J9ROMMethodInfo *left = (J9ROMMethodInfo *)leftKey; + J9ROMMethodInfo *right = (J9ROMMethodInfo *)rightKey; + return (left->key == right->key); +} + +static bool +checkROMMethodInfoCache(J9ClassLoader *classLoader, void *key, J9ROMMethodInfo *outInfo) +{ + bool found = false; + omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; + + if (NULL != mapCacheMutex) { + omrthread_monitor_enter(mapCacheMutex); + + J9HashTable *cache = classLoader->romMethodInfoCache; + if (NULL != cache) { + J9ROMMethodInfo exemplar = {0}; + exemplar.key = key; + J9ROMMethodInfo *entry = (J9ROMMethodInfo *)hashTableFind(cache, &exemplar); + if (NULL != entry) { + *outInfo = *entry; + found = true; + } + } + + omrthread_monitor_exit(mapCacheMutex); + } + + return found; +} + +static void +updateROMMethodInfoCache(J9JavaVM *vm, J9ClassLoader *classLoader, J9ROMMethodInfo *info) +{ + omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; + if (NULL == mapCacheMutex) { + return; /* caching disabled */ + } + + omrthread_monitor_enter(mapCacheMutex); + + J9HashTable *cache = classLoader->romMethodInfoCache; + if (NULL == cache) { + /* Create the cache if it doesn't exist */ + cache = hashTableNew( + OMRPORT_FROM_J9PORT(vm->portLibrary), + J9_GET_CALLSITE(), + 0, + sizeof(J9ROMMethodInfo), + sizeof(J9ROMMethodInfo *), + 0, + J9MEM_CATEGORY_VM, + romMethodInfoHashFn, + romMethodInfoEqualFn, + NULL, + NULL); + classLoader->romMethodInfoCache = cache; + } + + if (NULL != cache) { + hashTableAdd(cache, info); + } + + omrthread_monitor_exit(mapCacheMutex); +} + +static void +populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key, UDATA pc, bool computeStackAndLocals) +{ + J9Method *method = walkState->method; + J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + J9JavaVM *vm = walkState->javaVM; + + J9ROMMethodInfo newInfo = {0}; + newInfo.key = key; + J9ROMClass *romClass = J9_CLASS_FROM_METHOD(method)->romClass; + + /* Always compute argument bits */ + j9localmap_ArgBitsForPC0(romClass, romMethod, newInfo.argbits); + + if (computeStackAndLocals && pc < (UDATA)J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod)) { + /* Compute stack map for this PC */ + j9stackmap_StackBitsForPC( + vm->portLibrary, + pc, + romClass, + romMethod, + newInfo.stackmap, + J9_STACKMAP_CACHE_SLOTS << 5, + NULL, + NULL, + NULL); + + /* Compute local variable map for this PC */ + vm->localMapFunction( + vm->portLibrary, + romClass, + romMethod, + pc, + newInfo.localmap, + NULL, + NULL, + NULL); + } + + /* Copy metadata */ + newInfo.modifiers = romMethod->modifiers; + newInfo.argCount = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod); + newInfo.tempCount = J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod); + + /* Insert into cache */ + updateROMMethodInfoCache(vm, classLoader, &newInfo); + + /* Reflect into current walkState */ + walkState->romMethodInfo = newInfo; +} + void -populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key) +getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod) { initializeBasicROMMethodInfo(walkState, romMethod); + J9Method *method = walkState->method; + J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + + void *key = (void *)romMethod; + J9ROMMethodInfo tmp = {0}; + + /* Check cache first */ + if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { + /* Cache miss or not populated: populate argbits only */ + populateROMMethodInfo(walkState, romMethod, key, 0, false); + } else { + walkState->romMethodInfo = tmp; + } +} + +/* Bytecode PC: compute argbits + stackmap + localmap */ +void +getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMethod, UDATA pc) +{ + initializeBasicROMMethodInfo(walkState, romMethod); + if (pc <= J9SF_MAX_SPECIAL_FRAME_TYPE || pc >= (UDATA)J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod)) { + return; + } + + J9Method *method = walkState->method; + J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + + void *key = (void *)( (uintptr_t)J9_BYTECODE_START_FROM_ROM_METHOD(romMethod) + (uintptr_t)pc ); + J9ROMMethodInfo tmp = {0}; + + /* Check cache first */ + if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { + /* Cache miss or not populated: compute stack/local maps */ + populateROMMethodInfo(walkState, romMethod, key, pc, true); + } else { + walkState->romMethodInfo = tmp; + } +} + #if 0 + +void +populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key) +{ + initializeBasicROMMethodInfo(walkState, romMethod); + bool found = false; J9Method *method = walkState->method; J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; @@ -74,10 +245,8 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void omrthread_monitor_exit(mapCacheMutex); } -#endif } -#if 0 /** * @brief Map cache hash function diff --git a/runtime/vm/swalk.c b/runtime/vm/swalk.c index ef28d58217e..ec54ab8b37b 100644 --- a/runtime/vm/swalk.c +++ b/runtime/vm/swalk.c @@ -760,7 +760,8 @@ walkMethodFrame(J9StackWalkState * walkState) J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; - initializeBasicROMMethodInfo(walkState, romMethod); + //initializeBasicROMMethodInfo(walkState, romMethod); + getROMMethodInfoForROMMethod(walkState, romMethod); walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); walkState->argCount = romMethodInfo->argCount; @@ -1025,8 +1026,9 @@ walkBytecodeFrame(J9StackWalkState * walkState) J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); J9ROMMethodInfo *romMethodInfo = &walkState->romMethodInfo; - initializeBasicROMMethodInfo(walkState, romMethod); - + //initializeBasicROMMethodInfo(walkState, romMethod); + UDATA pcOffset = walkState->pc - J9_BYTECODE_START_FROM_RAM_METHOD(walkState->method); + getROMMethodInfoForBytecodePC(walkState, romMethod, pcOffset); walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); #if defined(J9VM_OPT_METHOD_HANDLE) From f7946db0dcb7ac4f8af5adc2dbc8ca6fd8dd1b27 Mon Sep 17 00:00:00 2001 From: Harshitha Popuri Date: Tue, 25 Nov 2025 03:04:47 -0800 Subject: [PATCH 3/4] fixup --- runtime/stackmap/mapcache.cpp | 226 ++-------------------------------- runtime/vm/swalk.c | 8 +- 2 files changed, 13 insertions(+), 221 deletions(-) diff --git a/runtime/stackmap/mapcache.cpp b/runtime/stackmap/mapcache.cpp index e1f197c0124..a1818598f03 100644 --- a/runtime/stackmap/mapcache.cpp +++ b/runtime/stackmap/mapcache.cpp @@ -132,7 +132,7 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void /* Always compute argument bits */ j9localmap_ArgBitsForPC0(romClass, romMethod, newInfo.argbits); - if (computeStackAndLocals && pc < (UDATA)J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod)) { + if (computeStackAndLocals) { /* Compute stack map for this PC */ j9stackmap_StackBitsForPC( vm->portLibrary, @@ -172,7 +172,6 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void void getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod) { - initializeBasicROMMethodInfo(walkState, romMethod); J9Method *method = walkState->method; J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; @@ -181,9 +180,11 @@ getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod /* Check cache first */ if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { - /* Cache miss or not populated: populate argbits only */ + /* Cache miss or not populated */ + initializeBasicROMMethodInfo(walkState, romMethod); populateROMMethodInfo(walkState, romMethod, key, 0, false); } else { + /* Cache hit */ walkState->romMethodInfo = tmp; } } @@ -192,7 +193,6 @@ getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod void getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMethod, UDATA pc) { - initializeBasicROMMethodInfo(walkState, romMethod); if (pc <= J9SF_MAX_SPECIAL_FRAME_TYPE || pc >= (UDATA)J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod)) { return; } @@ -205,226 +205,14 @@ getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMetho /* Check cache first */ if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { - /* Cache miss or not populated: compute stack/local maps */ + /* Cache miss or not populated */ + initializeBasicROMMethodInfo(walkState, romMethod); populateROMMethodInfo(walkState, romMethod, key, pc, true); } else { + /* Cache hit */ walkState->romMethodInfo = tmp; } } -#if 0 - -void -populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key) -{ - initializeBasicROMMethodInfo(walkState, romMethod); - - bool found = false; - J9Method *method = walkState->method; - J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; - omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; - - /* If the mapCacheMutex exists, the caching feature is enabled */ - if (NULL != mapCacheMutex) { - omrthread_monitor_enter(mapCacheMutex); - J9HashTable *mapCache = classLoader->romMethodInfoCache; - - /* If the cache exists, check it for this key */ - if (NULL != mapCache) { - J9ROMMethodInfo exemplar = { 0 }; - exemplar.key = key; - J9ROMMethodInfo *entry = (J9ROMMethodInfo*)hashTableFind(mapCache, &exemplar); - - if (NULL != entry) { - /* Cache hit - copy the info */ - *romMethodInfo = *entry; - } else { - /* Cache miss - populate the info and cache it */ - } - } - - omrthread_monitor_exit(mapCacheMutex); - } -} - - -/** - * @brief Map cache hash function - * @param key J9MapCacheEntry pointer - * @param userData not used - * @return hash value - */ -static UDATA -localMapHashFn(void *key, void *userData) -{ - J9MapCacheEntry *entry = (J9MapCacheEntry*)key; - - return (UDATA)entry->key; -} - -/** - * @brief Map cache comparator function - * @param leftKey J9MapCacheEntry pointer - * @param rightKey J9MapCacheEntry pointer - * @param userData not used - * @return 0 if comparision fails, non-zero if succeess - */ -static UDATA -localMapHashEqualFn(void *leftKey, void *rightKey, void *userData) -{ - J9MapCacheEntry *leftEntry = (J9MapCacheEntry*)leftKey; - J9MapCacheEntry *rightEntry = (J9MapCacheEntry*)rightKey; - - return (leftEntry->key == rightEntry->key); -} - -/** -* @brief Check the given cache for the key. If found, populate the resultArray. -* @param vm the J9JavaVM -* @param classLoader the J9ClassLoader -* @param key the cache key -* @param mapCache the cache to search -* @param resultArrayBase the result array -* @param mapWords the numhber of U_32 in the result array -* @return true on cache hit, false on miss -*/ -static bool -checkCache(J9JavaVM *vm, J9ClassLoader *classLoader, void *key, J9HashTable *mapCache, U_32 *resultArrayBase, UDATA mapWords) -{ - bool found = false; - omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; - - /* If the mapCacheMutex exists, the caching feature is enabled */ - if (NULL != mapCacheMutex) { - if (mapWords <= J9_MAP_CACHE_SLOTS) { - omrthread_monitor_enter(mapCacheMutex); - - /* If the cache exists, check it for this key */ - if (NULL != mapCache) { - J9MapCacheEntry exemplar = { 0 }; - exemplar.key = key; - J9MapCacheEntry *entry = (J9MapCacheEntry*)hashTableFind(mapCache, &exemplar); - - if (NULL != entry) { - memcpy(resultArrayBase, &entry->data.bits, sizeof(U_32) * mapWords); - found = true; - } - } - - omrthread_monitor_exit(mapCacheMutex); - } - } - - return found; -} - -/** -* @brief Cache a result in the given cache for the key. -* @param vm the J9JavaVM -* @param classLoader the J9ClassLoader -* @param key the cache key -* @param cacheSlot pointer to the slot holding the cache pointer -* @param resultArrayBase the result array -* @param mapWords the numhber of U_32 in the result array -*/ -static void -updateCache(J9JavaVM *vm, J9ClassLoader *classLoader, void *key, J9HashTable **cacheSlot, U_32 *resultArrayBase, UDATA mapWords) -{ - omrthread_monitor_t mapCacheMutex = classLoader->mapCacheMutex; - - /* If the mapCacheMutex exists, the caching feature is enabled */ - if (NULL != mapCacheMutex) { - if (mapWords <= J9_MAP_CACHE_SLOTS) { - omrthread_monitor_enter(mapCacheMutex); - - /* Create the cache if necessary - failure is non-fatal */ - J9HashTable *mapCache = *cacheSlot; - if (NULL == mapCache) { - mapCache = hashTableNew(OMRPORT_FROM_J9PORT(vm->portLibrary), - J9_GET_CALLSITE(), - 0, - sizeof(J9MapCacheEntry), - sizeof(J9MapCacheEntry *), - 0, - J9MEM_CATEGORY_VM, - localMapHashFn, - localMapHashEqualFn, - NULL, - NULL); - *cacheSlot = mapCache; - } - - /* If the cache exists, attempt to add and entry for this map - failure is non-fatal */ - if (NULL != mapCache) { - J9MapCacheEntry entry = { 0 }; - entry.key = key; - memcpy(&entry.data.bits, resultArrayBase, sizeof(U_32) * mapWords); - hashTableAdd(mapCache, &entry); - } - - omrthread_monitor_exit(mapCacheMutex); - } - } -} - -IDATA -j9cached_StackBitsForPC(UDATA pc, J9ROMClass * romClass, J9ROMMethod * romMethod, - U_32 * resultArrayBase, UDATA resultArraySize, - void * userData, - UDATA * (* getBuffer) (void * userData), - void (* releaseBuffer) (void * userData), - J9JavaVM *vm, J9ClassLoader *classLoader) -{ - UDATA mapWords = (resultArraySize + 31) >> 5; - void *bytecodePC = (void*)(J9_BYTECODE_START_FROM_ROM_METHOD(romMethod) + pc); - IDATA rc = 0; - - if (!checkCache(vm, classLoader, bytecodePC, classLoader->stackmapCache, resultArrayBase, mapWords)) { - /* Cache miss - perform the map and attempt to cache the result if successful */ - rc = j9stackmap_StackBitsForPC(vm->portLibrary, pc, romClass, romMethod, - resultArrayBase, resultArraySize, userData, getBuffer, releaseBuffer); - if (0 == rc) { - updateCache(vm, classLoader, bytecodePC, &classLoader->stackmapCache, resultArrayBase, mapWords); - } - } - return rc; -} - -void -j9cached_ArgBitsForPC0(J9ROMClass *romClass, J9ROMMethod *romMethod, U_32 *resultArrayBase, J9JavaVM *vm, J9ClassLoader *classLoader) -{ - UDATA mapWords = (J9_ARG_COUNT_FROM_ROM_METHOD(romMethod) + 31) >> 5; - - if (!checkCache(vm, classLoader, (void*)romMethod, classLoader->argsbitsCache, resultArrayBase, mapWords)) { - /* Cache miss - perform the map and attempt to cache the result */ - j9localmap_ArgBitsForPC0(romClass, romMethod, resultArrayBase); - updateCache(vm, classLoader, (void*)romMethod, &classLoader->argsbitsCache, resultArrayBase, mapWords); - } -} - -IDATA -j9cached_LocalBitsForPC(J9ROMClass * romClass, J9ROMMethod * romMethod, UDATA pc, U_32 * resultArrayBase, - void * userData, - UDATA * (* getBuffer) (void * userData), - void (* releaseBuffer) (void * userData), - J9JavaVM *vm, J9ClassLoader * classLoader) -{ - IDATA rc = 0; - void *bytecodePC = (void*)(J9_BYTECODE_START_FROM_ROM_METHOD(romMethod) + pc); - UDATA mapWords = (UDATA) ((J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod) + J9_ARG_COUNT_FROM_ROM_METHOD(romMethod) + 31) >> 5); - - if (!checkCache(vm, classLoader, bytecodePC, classLoader->localmapCache, resultArrayBase, mapWords)) { - /* Cache miss - perform the map and attempt to cache the result if successful */ - rc = vm->localMapFunction(vm->portLibrary, romClass, romMethod, pc, resultArrayBase, userData, getBuffer, releaseBuffer); - if (0 == rc) { - updateCache(vm, classLoader, bytecodePC, &classLoader->localmapCache, resultArrayBase, mapWords); - } - } - - return rc; -} - -#endif - } /* extern "C" */ diff --git a/runtime/vm/swalk.c b/runtime/vm/swalk.c index ec54ab8b37b..6724cd0e91a 100644 --- a/runtime/vm/swalk.c +++ b/runtime/vm/swalk.c @@ -720,7 +720,9 @@ walkMethodFrame(J9StackWalkState * walkState) MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodFrame->specialFrameFlags)); walkState->method = methodFrame->method; if (NULL != walkState->method) { - initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); + getROMMethodInfoForROMMethod(walkState, romMethod); + //initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); } walkState->unwindSP = (UDATA *) methodFrame; @@ -1234,7 +1236,9 @@ static void walkJITJNICalloutFrame(J9StackWalkState * walkState) MARK_SLOT_AS_OBJECT(walkState, (j9object_t*) &(methodFrame->specialFrameFlags)); walkState->method = methodFrame->method; if (NULL != walkState->method) { - initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method); + getROMMethodInfoForROMMethod(walkState, romMethod); + //initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); } walkState->constantPool = UNTAGGED_METHOD_CP(walkState->method); #ifdef J9VM_INTERP_STACKWALK_TRACING From 54734e95525da277962f60d12f25245cf1cce778 Mon Sep 17 00:00:00 2001 From: Harshitha Popuri Date: Tue, 25 Nov 2025 12:24:16 -0800 Subject: [PATCH 4/4] Add third entry point getROMMethodInfoForOSRFrame --- runtime/codert_vm/jswalk.c | 9 ++-- runtime/oti/stackmap_api.h | 8 ++++ runtime/stackmap/mapcache.cpp | 82 +++++++++++++++++++++++++++++++---- 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/runtime/codert_vm/jswalk.c b/runtime/codert_vm/jswalk.c index 1c46b7afd20..a99f1d34340 100644 --- a/runtime/codert_vm/jswalk.c +++ b/runtime/codert_vm/jswalk.c @@ -215,7 +215,8 @@ UDATA jitWalkStackFrames(J9StackWalkState *walkState) lswRecord(walkState, LSW_TYPE_METHOD, walkState->method); lswRecord(walkState, LSW_TYPE_JIT_FRAME_INFO, walkState); #endif - initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + //initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + getROMMethodInfoForBytecodePC(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method), walkState->bytecodePCOffset); if ((rc = walkFrame(walkState)) != J9_STACKWALK_KEEP_ITERATING) { return rc; @@ -255,7 +256,8 @@ UDATA jitWalkStackFrames(J9StackWalkState *walkState) #ifdef J9VM_INTERP_LINEAR_STACKWALK_TRACING lswRecord(walkState, LSW_TYPE_JIT_FRAME_INFO, walkState); #endif - initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + //initializeBasicROMMethodInfo(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)); + getROMMethodInfoForBytecodePC(walkState, J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method), walkState->bytecodePCOffset); if ((rc = walkFrame(walkState)) != J9_STACKWALK_KEEP_ITERATING) { return rc; } @@ -1985,7 +1987,8 @@ jitWalkOSRFrame(J9StackWalkState *walkState, J9OSRFrame *osrFrame) J9MonitorEnterRecord *enterRecord = osrFrame->monitorEnterRecords; J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method); - initializeBasicROMMethodInfo(walkState, romMethod); + //initializeBasicROMMethodInfo(walkState, romMethod); + getROMMethodInfoForOSRFrame(walkState, osrFrame); #ifdef J9VM_INTERP_STACKWALK_TRACING { diff --git a/runtime/oti/stackmap_api.h b/runtime/oti/stackmap_api.h index e67394e64c5..c4ef8a37fe5 100644 --- a/runtime/oti/stackmap_api.h +++ b/runtime/oti/stackmap_api.h @@ -223,6 +223,14 @@ getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod void getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMethod, UDATA pc); +/** + * @brief + * @param walkState + * @param osrFrame + */ +void +getROMMethodInfoForOSRFrame(J9StackWalkState *walkState, J9OSRFrame *osrFrame); + #ifdef __cplusplus } #endif diff --git a/runtime/stackmap/mapcache.cpp b/runtime/stackmap/mapcache.cpp index a1818598f03..2693fe5ba70 100644 --- a/runtime/stackmap/mapcache.cpp +++ b/runtime/stackmap/mapcache.cpp @@ -112,14 +112,17 @@ updateROMMethodInfoCache(J9JavaVM *vm, J9ClassLoader *classLoader, J9ROMMethodIn } if (NULL != cache) { - hashTableAdd(cache, info); + PORT_ACCESS_FROM_JAVAVM(vm); + J9ROMMethodInfo *copy = (J9ROMMethodInfo *) j9mem_allocate_memory(sizeof(J9ROMMethodInfo), J9MEM_CATEGORY_VM); + *copy = *info; + hashTableAdd(cache, copy); } omrthread_monitor_exit(mapCacheMutex); } static void -populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key, UDATA pc, bool computeStackAndLocals) +populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void *key, UDATA pc, bool computeStackAndLocals, UDATA pendingCount, UDATA numberOfLocals) { J9Method *method = walkState->method; J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; @@ -131,7 +134,6 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void /* Always compute argument bits */ j9localmap_ArgBitsForPC0(romClass, romMethod, newInfo.argbits); - if (computeStackAndLocals) { /* Compute stack map for this PC */ j9stackmap_StackBitsForPC( @@ -146,6 +148,7 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void NULL); /* Compute local variable map for this PC */ + vm->localMapFunction( vm->portLibrary, romClass, @@ -163,10 +166,39 @@ populateROMMethodInfo(J9StackWalkState *walkState, J9ROMMethod *romMethod, void newInfo.tempCount = J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod); /* Insert into cache */ - updateROMMethodInfoCache(vm, classLoader, &newInfo); + //updateROMMethodInfoCache(vm, classLoader, &newInfo); + PORT_ACCESS_FROM_JAVAVM(vm); + J9ROMMethodInfo *stored = (J9ROMMethodInfo *) j9mem_allocate_memory(sizeof(J9ROMMethodInfo), J9MEM_CATEGORY_VM); + if (NULL == stored) { + walkState->romMethodInfo = newInfo; + } else { + *stored = newInfo; + updateROMMethodInfoCache(vm, classLoader, stored); + walkState->romMethodInfo = *stored; + } +} + +static UDATA +computePendingCountForBytecode(J9ROMMethod *romMethod) +{ + UDATA pendingCount = 0; - /* Reflect into current walkState */ - walkState->romMethodInfo = newInfo; + UDATA argCount = romMethod->argCount; + UDATA tempCount = romMethod->tempCount; + + pendingCount = argCount + tempCount; + + UDATA modifiers = romMethod->modifiers; + + if (modifiers & J9AccSynchronized) { + /* Add monitor slot for synchronized methods */ + pendingCount += 1; + } else if ((modifiers & (J9AccMethodObjectConstructor | J9AccEmptyMethod)) == J9AccMethodObjectConstructor) { + /* Add extra receiver temp for non-empty Object. */ + pendingCount += 1; + } + + return pendingCount; } void @@ -174,7 +206,9 @@ getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod { J9Method *method = walkState->method; J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; - + if (NULL == walkState->method || walkState->pc == NULL) { + return; // avoid dereference + } void *key = (void *)romMethod; J9ROMMethodInfo tmp = {0}; @@ -182,7 +216,8 @@ getROMMethodInfoForROMMethod(J9StackWalkState *walkState, J9ROMMethod *romMethod if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { /* Cache miss or not populated */ initializeBasicROMMethodInfo(walkState, romMethod); - populateROMMethodInfo(walkState, romMethod, key, 0, false); + populateROMMethodInfo(walkState, romMethod, key, 0, false, 0, 0); + //populateROMMethodInfo(walkState, romMethod, key, 0, false); } else { /* Cache hit */ walkState->romMethodInfo = tmp; @@ -194,11 +229,15 @@ void getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMethod, UDATA pc) { if (pc <= J9SF_MAX_SPECIAL_FRAME_TYPE || pc >= (UDATA)J9_BYTECODE_SIZE_FROM_ROM_METHOD(romMethod)) { + initializeBasicROMMethodInfo(walkState, romMethod); return; } J9Method *method = walkState->method; J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + if (NULL == walkState->method || walkState->pc == NULL) { + return; // avoid dereference + } void *key = (void *)( (uintptr_t)J9_BYTECODE_START_FROM_ROM_METHOD(romMethod) + (uintptr_t)pc ); J9ROMMethodInfo tmp = {0}; @@ -207,12 +246,37 @@ getROMMethodInfoForBytecodePC(J9StackWalkState *walkState, J9ROMMethod *romMetho if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { /* Cache miss or not populated */ initializeBasicROMMethodInfo(walkState, romMethod); - populateROMMethodInfo(walkState, romMethod, key, pc, true); + UDATA pendingCount = computePendingCountForBytecode(romMethod); + UDATA numberOfLocals = romMethod->tempCount + romMethod->argCount; + populateROMMethodInfo(walkState, romMethod, key, pc, true, pendingCount, numberOfLocals); + //populateROMMethodInfo(walkState, romMethod, key, pc, true); } else { /* Cache hit */ walkState->romMethodInfo = tmp; } } +void +getROMMethodInfoForOSRFrame(J9StackWalkState *walkState, J9OSRFrame *osrFrame) +{ + J9Method *method = osrFrame->method; + J9ClassLoader *classLoader = J9_CLASS_FROM_METHOD(method)->classLoader; + J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method); + + /* Use the ROMMethod pointer plus bytecode offset as key */ + void *key = (void *)((uintptr_t)J9_BYTECODE_START_FROM_ROM_METHOD(romMethod) + (uintptr_t)osrFrame->bytecodePCOffset); + J9ROMMethodInfo tmp = {0}; + + /* Check the cache first */ + if (!checkROMMethodInfoCache(classLoader, key, &tmp)) { + /* Cache miss or not populated */ + initializeBasicROMMethodInfo(walkState, romMethod); + populateROMMethodInfo(walkState, romMethod, key, osrFrame->bytecodePCOffset, true, osrFrame->pendingStackHeight, osrFrame->numberOfLocals); + //populateROMMethodInfo(walkState, romMethod, key, osrFrame->bytecodePCOffset,true); + } else { + /* Cache hit */ + walkState->romMethodInfo = tmp; + } +} } /* extern "C" */