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

Cache rom to ram mappings for exception backtrace #20169

Merged
merged 1 commit into from
Sep 19, 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
14 changes: 14 additions & 0 deletions runtime/nls/shrc/j9shr.nls
Original file line number Diff line number Diff line change
Expand Up @@ -6943,3 +6943,17 @@ J9NLS_SHRC_CM_PRINTSTATS_PAGESIZEE.explanation=NOTAG
J9NLS_SHRC_CM_PRINTSTATS_PAGESIZEE.system_action=
J9NLS_SHRC_CM_PRINTSTATS_PAGESIZEE.user_response=
# END NON-TRANSLATABLE

J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMHASHTABLE=Cannot allocate ROM to RAM class hash table in shrinit
# START NON-TRANSLATABLE
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMHASHTABLE.explanation=The system is unable to obtain sufficient native memory to allocate internal data structures.
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMHASHTABLE.system_action=The JVM terminates, unless you have specified the nonfatal option with "-Xshareclasses:nonfatal", in which case the JVM attempts to start up without using Shared Classes.
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMHASHTABLE.user_response=System is running low on memory resource for the JVM to start up properly. Check system memory configuration. If the situation persists, contact your service representative.
# END NON-TRANSLATABLE

J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMMUTEX=Cannot allocate ROM to RAM class mutex in shrinit
# START NON-TRANSLATABLE
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMMUTEX.explanation=The system is unable to obtain sufficient native memory to allocate internal data structures.
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMMUTEX.system_action=The JVM terminates, unless you have specified the nonfatal option with "-Xshareclasses:nonfatal", in which case the JVM attempts to start up without using Shared Classes.
J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMMUTEX.user_response=System is running low on memory resource for the JVM to start up properly. Check system memory configuration. If the situation persists, contact your service representative.
# END NON-TRANSLATABLE
5 changes: 5 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1417,6 +1417,11 @@ typedef struct J9SharedClassConfig {
const char* cacheName;
I_8 layer;
U_64 readOnlyCacheRuntimeFlags;
/* This table is a cache for exceptiondescribe.c:findJ9ClassForROMClass
* and does not contain mappings for every romClass to ramClass.
*/
struct J9HashTable *romToRamHashTable;
hangshao0 marked this conversation as resolved.
Show resolved Hide resolved
omrthread_rwmutex_t romToRamHashTableMutex;
} J9SharedClassConfig;

typedef struct J9SharedClassPreinitConfig {
Expand Down
12 changes: 12 additions & 0 deletions runtime/shared_common/include/SCQueryFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ j9shr_Query_PopulatePreinitConfigDefaults(J9JavaVM *vm, J9SharedClassPreinitConf
}
#endif

typedef struct RomToRamEntry {
J9Class *ramClass;
} RomToRamEntry;

typedef struct RomToRamQueryEntry {
/* J9ROMClass address | ROM_TO_RAM_QUERY_TAG */
J9ROMClass *romClass;
} RomToRamQueryEntry;

/* Used to tell RomToRamQueryEntry apart from RomToRamEntry. */
#define ROM_TO_RAM_QUERY_TAG 0x1

#ifdef __cplusplus
}/*extern "C"*/
#endif
Expand Down
98 changes: 93 additions & 5 deletions runtime/shared_common/shrinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extern "C" {
#include "simplepool_api.h"
#include "SCStringInternHelpers.h"
#include <string.h>
#include "SCQueryFunctions.h"
#include "util_api.h"
}

Expand Down Expand Up @@ -412,6 +413,12 @@ static char* generateStartupHintsKey(J9JavaVM *vm);
static void fetchStartupHintsFromSharedCache(J9VMThread* vmThread);
static void findExistingCacheLayerNumbers(J9JavaVM* vm, const char* ctrlDirName, const char* cacheName, U_64 runtimeFlags, I_8 *maxLayerNo);
static IDATA sysinfoGetUserNameHelper(J9JavaVM *vm, UDATA verboseFlags, char *buffer, UDATA length);
static UDATA romToRamGetRomAddress(void *item);
static UDATA romToRamHashFn(void *item, void *userData);
static UDATA romToRamEqualFn(void *left, void *right, void *userData);
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
static void romToRamRemoveEntry(J9HookInterface **hookInterface, UDATA eventNum, void *voidData, void *userData);
hangshao0 marked this conversation as resolved.
Show resolved Hide resolved
#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */

typedef struct J9SharedVerifyStringTable {
void *romClassAreaStart;
Expand Down Expand Up @@ -3183,6 +3190,49 @@ j9shr_isBCIEnabled(J9JavaVM *vm)
return (0 != (vm->sharedClassConfig->runtimeFlags & J9SHR_RUNTIMEFLAG_ENABLE_BCI));
}

static UDATA
theresa-m marked this conversation as resolved.
Show resolved Hide resolved
romToRamGetRomAddress(void *item)
{
RomToRamQueryEntry *queryEntry = (RomToRamQueryEntry *)item;
UDATA romAddress = (UDATA)(queryEntry->romClass);
if (J9_ARE_ALL_BITS_SET(romAddress, ROM_TO_RAM_QUERY_TAG)) {
return romAddress & ~ROM_TO_RAM_QUERY_TAG;
} else {
RomToRamEntry *entry = (RomToRamEntry *)item;
return (UDATA)(entry->ramClass->romClass);
}
}

/* THREADING: Must be protected by J9SharedClassConfig.romToRamHashTableMutex */
static UDATA
romToRamHashFn(void *item, void *userData)
{
return romToRamGetRomAddress(item);
}

/* THREADING: Must be protected by J9SharedClassConfig.romToRamHashTableMutex */
static UDATA
romToRamEqualFn(void *left, void *right, void *userData)
{
return (romToRamGetRomAddress(left) == romToRamGetRomAddress(right));
}

#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
static void
romToRamRemoveEntry(J9HookInterface **hookInterface, UDATA eventNum, void *voidData, void *userData)
hangshao0 marked this conversation as resolved.
Show resolved Hide resolved
{
J9VMClassesUnloadEvent *data = (J9VMClassesUnloadEvent *)voidData;
J9SharedClassConfig *config = data->currentThread->javaVM->sharedClassConfig;
omrthread_rwmutex_enter_write(config->romToRamHashTableMutex);
for (J9Class *ramClass = data->classesToUnload; ramClass; ramClass = ramClass->gcLink) {
RomToRamEntry entry;
entry.ramClass = ramClass;
hashTableRemove(config->romToRamHashTable, &entry);
}
omrthread_rwmutex_exit_write(config->romToRamHashTableMutex);
}
#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */

/**
* JVM Initialisation processing for shared classes
*
Expand All @@ -3207,7 +3257,7 @@ j9shr_init(J9JavaVM *vm, UDATA loadFlags, UDATA* nonfatal)
U_64 runtimeFlags = vm->sharedCacheAPI->runtimeFlags;
UDATA verboseFlags = vm->sharedCacheAPI->verboseFlags;
UDATA printStatsOptions = vm->sharedCacheAPI->printStatsOptions;
J9HookInterface** hook = vm->internalVMFunctions->getVMHookInterface(vm);
J9HookInterface** vmHooks = vm->internalVMFunctions->getVMHookInterface(vm);
UDATA parseResult = vm->sharedCacheAPI->parseResult;
IDATA rc, rcStartup = 0;
const char* cacheName = vm->sharedCacheAPI->cacheName;
Expand Down Expand Up @@ -3515,6 +3565,24 @@ j9shr_init(J9JavaVM *vm, UDATA loadFlags, UDATA* nonfatal)
config->jclURLCache = NULL;
config->jclURLHashTable = NULL;
config->jclUTF8HashTable = NULL;
if (J9_ARE_ALL_BITS_SET(runtimeFlags, J9SHR_RUNTIMEFLAG_ENABLE_CACHE_NON_BOOT_CLASSES)) {
if (omrthread_rwmutex_init(&(config->romToRamHashTableMutex), 0, "romToRamHashTable mutex")) {
SHRINIT_ERR_TRACE(verboseFlags, J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMMUTEX);
goto _error;
}
omrthread_rwmutex_enter_write(config->romToRamHashTableMutex);
config->romToRamHashTable = hashTableNew(OMRPORT_FROM_J9PORT(vm->portLibrary),
J9_GET_CALLSITE(), 0, sizeof(RomToRamEntry), sizeof(char *), 0,
J9MEM_CATEGORY_CLASSES, romToRamHashFn, romToRamEqualFn, NULL, NULL);
if (NULL == config->romToRamHashTable) {
omrthread_rwmutex_exit_write(config->romToRamHashTableMutex);
omrthread_rwmutex_destroy(config->romToRamHashTableMutex);
SHRINIT_ERR_TRACE(verboseFlags, J9NLS_SHRC_SHRINIT_FAILURE_CREATE_ROMTORAMHASHTABLE);
goto _error;
}
omrthread_rwmutex_exit_write(config->romToRamHashTableMutex);
}

config->jclJ9ClassPathEntryPool = pool_new(sizeof(struct J9ClassPathEntry), 0, 0, 0, J9_GET_CALLSITE(), J9MEM_CATEGORY_CLASSES, POOL_FOR_PORT(vm->portLibrary));
if (!(config->jclJ9ClassPathEntryPool)) {
SHRINIT_ERR_TRACE(verboseFlags, J9NLS_SHRC_SHRINIT_FAILURE_CREATE_POOL);
Expand Down Expand Up @@ -3556,7 +3624,7 @@ j9shr_init(J9JavaVM *vm, UDATA loadFlags, UDATA* nonfatal)
}

/* Register hooks */
(*hook)->J9HookRegisterWithCallSite(hook, J9HOOK_VM_FIND_LOCALLY_DEFINED_CLASS, hookFindSharedClass, OMR_GET_CALLSITE(), NULL);
(*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_FIND_LOCALLY_DEFINED_CLASS, hookFindSharedClass, OMR_GET_CALLSITE(), NULL);

/* We don't need the string table when running with -Xshareclasses:print<XXXX>Stats.
* This is because the JVM is terminated, after displaying the requested information.
Expand Down Expand Up @@ -3710,10 +3778,13 @@ j9shr_init(J9JavaVM *vm, UDATA loadFlags, UDATA* nonfatal)
}

if (0 != (runtimeFlags & J9SHR_RUNTIMEFLAG_ADD_TEST_JITHINT)) {
J9HookInterface** hook = vm->internalVMFunctions->getVMHookInterface(vm);
(*hook)->J9HookRegisterWithCallSite(hook, J9HOOK_VM_FIND_LOCALLY_DEFINED_CLASS, addTestJitHint, OMR_GET_CALLSITE(), NULL);
(*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_FIND_LOCALLY_DEFINED_CLASS, addTestJitHint, OMR_GET_CALLSITE(), NULL);
}

#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
if (NULL != vm->sharedClassConfig->romToRamHashTable) {
(*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_CLASSES_UNLOAD, romToRamRemoveEntry, OMR_GET_CALLSITE(), NULL);
}
#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */
if (doPrintStats) {
if (j9shr_print_stats(vm, parseResult, runtimeFlags, printStatsOptions) != -1) {
*nonfatal = 0; /* Nonfatal should be ignored for stats utilities */
Expand Down Expand Up @@ -4137,6 +4208,11 @@ j9shr_guaranteed_exit(J9JavaVM *vm, BOOLEAN exitForDebug)
*/
J9HookInterface** hook = vm->internalVMFunctions->getVMHookInterface(vm);
(*hook)->J9HookUnregister(hook, J9HOOK_VM_FIND_LOCALLY_DEFINED_CLASS, hookFindSharedClass, NULL);
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
if (NULL != vm->sharedClassConfig->romToRamHashTable) {
(*hook)->J9HookUnregister(hook, J9HOOK_VM_CLASSES_UNLOAD, romToRamRemoveEntry, NULL);
}
#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */
J9HookInterface **shcHooks;
shcHooks = zip_getVMZipCachePoolHookInterface((J9ZipCachePool *)vm->zipCachePool);
(*shcHooks)->J9HookUnregister(shcHooks, J9HOOK_VM_ZIP_LOAD, j9shr_hookZipLoadEvent, NULL);
Expand Down Expand Up @@ -4207,6 +4283,8 @@ j9shr_shutdown(J9JavaVM *vm)
J9SharedStringFarm* jclStringFarm = config->jclStringFarm;
J9HashTable* urlHashTable = config->jclURLHashTable;
J9HashTable* utfHashTable = config->jclUTF8HashTable;
J9HashTable *romToRamHashTable = config->romToRamHashTable;
omrthread_rwmutex_t romToRamHashTableMutex = config->romToRamHashTableMutex;
J9VMThread* currentThread = vm->internalVMFunctions->currentVMThread(vm);

/* Free all of the cached ClasspathItems */
Expand Down Expand Up @@ -4251,6 +4329,16 @@ j9shr_shutdown(J9JavaVM *vm)
if (utfHashTable) {
hashTableFree(utfHashTable);
}
if (NULL != romToRamHashTable) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked to @theresa-m, it is possible that the hashtable is freed by another thread after line 4286, so this check and the following if (romToRamHashTable) { won't work as it is checking the local variable romToRamHashTable whose value might become stale already.

omrthread_rwmutex_enter_write(romToRamHashTableMutex);
config->romToRamHashTable = NULL;
config->romToRamHashTableMutex = NULL;
if (romToRamHashTable) {
hashTableFree(romToRamHashTable);
}
omrthread_rwmutex_exit_write(romToRamHashTableMutex);
omrthread_rwmutex_destroy(romToRamHashTableMutex);
}

/* Kill the string farm */

Expand Down
8 changes: 8 additions & 0 deletions runtime/util/hshelp.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "j2sever.h"
#include "vrfytbl.h"
#include "bytecodewalk.h"
#include "../shared_common/include/SCQueryFunctions.h"

/* Static J9ITable used as a non-NULL iTable cache value by classes that don't implement any interfaces */
const J9ITable invalidITable = { (J9Class *) (UDATA) 0xDEADBEEF, 0, (J9ITable *) NULL };
Expand Down Expand Up @@ -2641,6 +2642,13 @@ recreateRAMClasses(J9VMThread * currentThread, J9HashTable * classHashTable, J9H
/* Delete original class from defining loader's class table */
if (!fastHCR) {
vmFuncs->hashClassTableDelete(classLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
if ((NULL != vm->sharedClassConfig) && (NULL != vm->sharedClassConfig->romToRamHashTable)) {
omrthread_rwmutex_enter_write(vm->sharedClassConfig->romToRamHashTableMutex);
RomToRamEntry entry;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly legal C code: declarations must be at the beginning of a block.

Moving the initialization of entry before acquiring the mutex also slightly reduces the size of that critical section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Keith, I will open a pull request to update this.

entry.ramClass = originalRAMClass;
hashTableRemove(vm->sharedClassConfig->romToRamHashTable, &entry);
omrthread_rwmutex_exit_write(vm->sharedClassConfig->romToRamHashTableMutex);
}
}

/* Create new RAM class */
Expand Down
37 changes: 33 additions & 4 deletions runtime/vm/exceptiondescribe.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,33 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
{
theresa-m marked this conversation as resolved.
Show resolved Hide resolved
J9UTF8 const *utfClassName = J9ROMCLASS_CLASSNAME(romClass);
J9JavaVM *vm = vmThread->javaVM;
J9SharedClassConfig *config = vm->sharedClassConfig;
J9Class* ret = NULL;
if (j9shr_Query_IsAddressInCache(vm, romClass, romClass->romSize)) {

if (_J9ROMCLASS_J9MODIFIER_IS_SET(romClass, J9AccClassAnonClass)) {
/* Anonymous classes are not allowed in any class loader hash table. */
return NULL;
}

if (j9shr_Query_IsAddressInCache(vm, romClass, romClass->romSize)
&& (NULL != config->romToRamHashTable)
) {
J9ClassLoaderWalkState walkState;
J9ClassLoader* classLoader = NULL;
BOOLEAN fastMode = J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_FAST_CLASS_HASH_TABLE);
J9Class* ramClass = NULL;
RomToRamEntry *resultEntry;
RomToRamQueryEntry searchEntry;
searchEntry.romClass = (J9ROMClass *)((UDATA)romClass | ROM_TO_RAM_QUERY_TAG);

omrthread_rwmutex_enter_read(config->romToRamHashTableMutex);
resultEntry = hashTableFind(config->romToRamHashTable, &searchEntry);
omrthread_rwmutex_exit_read(config->romToRamHashTableMutex);
if (NULL != resultEntry) {
ret = resultEntry->ramClass;
goto done;
}

if (!fastMode) {
omrthread_monitor_enter(vm->classTableMutex);
}
Expand All @@ -259,7 +280,7 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
if (!fastMode) {
omrthread_monitor_exit(vm->classTableMutex);
}
goto done;
goto cacheresult;
}

ramClass = hashClassTableAt(vm->extensionClassLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
Expand All @@ -271,7 +292,7 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
if (!fastMode) {
omrthread_monitor_exit(vm->classTableMutex);
}
goto done;
goto cacheresult;
}

ramClass = hashClassTableAt(vm->applicationClassLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
Expand All @@ -283,7 +304,7 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
if (!fastMode) {
omrthread_monitor_exit(vm->classTableMutex);
}
goto done;
goto cacheresult;
}

classLoader = vm->internalVMFunctions->allClassLoadersStartDo(&walkState, vm, 0);
Expand All @@ -307,6 +328,14 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
if (!fastMode) {
omrthread_monitor_exit(vm->classTableMutex);
}
cacheresult:
if (NULL != ret) {
RomToRamEntry newEntry;
newEntry.ramClass = ret;
omrthread_rwmutex_enter_write(config->romToRamHashTableMutex);
hashTableAdd(config->romToRamHashTable, &newEntry);
omrthread_rwmutex_exit_write(config->romToRamHashTableMutex);
}
} else {
ret = peekClassHashTable(vmThread, *resultClassLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
}
Expand Down