Skip to content

Commit

Permalink
Add J9Modules and J9Packages to the VM snapshot
Browse files Browse the repository at this point in the history
Related: eclipse-openj9#20612
Signed-off-by: Nathan Henderson <[email protected]>
  • Loading branch information
ThanHenderson committed Dec 12, 2024
1 parent e8707b4 commit 23b8f07
Show file tree
Hide file tree
Showing 16 changed files with 546 additions and 61 deletions.
201 changes: 178 additions & 23 deletions runtime/j9vm/java11vmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extern J9JavaVM *BFUjavaVM; /* from jvm.c */
* b) If performing a hash operation, it assumes the caller has already locked vm->classLoaderModuleAndLocationMutex
*/
static UDATA hashPackageTableDelete(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);
static J9Package * createPackage(J9VMThread * currentThread, J9Module * fromModule, const char *package);
static J9Package *createPackage(J9VMThread *currentThread, J9Module *fromModule, J9UTF8 *package);
static void freePackageDefinition(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);
static BOOLEAN removePackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *packageName);
static BOOLEAN addPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *package);
Expand All @@ -80,7 +80,7 @@ static void trcModulesAddModuleExports(J9VMThread * currentThread, J9Module * fr
static void trcModulesAddModulePackage(J9VMThread *currentThread, J9Module *j9mod, const char *package);
static UDATA hashTableAtPut(J9HashTable * table, void * value, BOOLEAN collisionIsFailure);
static void throwExceptionHelper(J9VMThread * currentThread, UDATA errCode);
static void freePackage(J9VMThread * currentThread, J9Package * j9package);
static void freePackage(J9VMThread *currentThread, J9Package *j9package);
static J9ClassLoader * getModuleObjectClassLoader(J9VMThread * currentThread, j9object_t moduleObject);
static J9Module *createModule(J9VMThread *currentThread, j9object_t moduleObject, J9ClassLoader *classLoader, J9UTF8 *moduleName);
static J9Module * getJ9Module(J9VMThread * currentThread, jobject module);
Expand Down Expand Up @@ -200,37 +200,41 @@ throwExceptionHelper(J9VMThread *currentThread, UDATA errCode)
}

static void
freePackage(J9VMThread * currentThread, J9Package * j9package)
freePackage(J9VMThread *currentThread, J9Package *j9package)
{
if (NULL != j9package) {
J9JavaVM * const vm = currentThread->javaVM;
J9JavaVM *const vm = currentThread->javaVM;
PORT_ACCESS_FROM_JAVAVM(vm);

if (NULL != j9package->exportsHashTable) {
hashTableFree(j9package->exportsHashTable);
}
j9mem_free_memory((void *) j9package->packageName);
#if defined(J9VM_OPT_SNAPSHOTS)
if (IS_SNAPSHOTTING_ENABLED(vm)) {
VMSNAPSHOTIMPLPORT_ACCESS_FROM_JAVAVM(vm);
vmsnapshot_free_memory((void *)j9package->packageName);
} else
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
{
j9mem_free_memory((void *)j9package->packageName);
}
pool_removeElement(vm->modularityPool, j9package);
}
}

static J9Package *
createPackage(J9VMThread * currentThread, J9Module * fromModule, const char *package)
createPackage(J9VMThread *currentThread, J9Module *fromModule, J9UTF8 *packageName)
{
J9JavaVM * const vm = currentThread->javaVM;
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
J9Package * retval = NULL;
J9JavaVM *const vm = currentThread->javaVM;
J9InternalVMFunctions const *const vmFuncs = vm->internalVMFunctions;
J9Package *retval = NULL;

J9ClassLoader * const classLoader = fromModule->classLoader;
J9Package * j9package = pool_newElement(vm->modularityPool);
J9Package *j9package = pool_newElement(vm->modularityPool);

if (NULL != j9package) {
j9package->module = fromModule;
j9package->classLoader = fromModule->classLoader;
if (!addUTFNameToPackage(currentThread, j9package, package, NULL, 0)) {
freePackage(currentThread, j9package);
return retval;
}
j9package->packageName = packageName;
j9package->exportsHashTable = vmFuncs->hashModulePointerTableNew(vm, INITIAL_INTERNAL_MODULE_HASHTABLE_SIZE);
if (NULL != j9package->exportsHashTable) {
retval = j9package;
Expand Down Expand Up @@ -348,13 +352,54 @@ trcModulesCreationPackage(J9VMThread *currentThread, J9Module *fromModule, const
}

static BOOLEAN
addPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *package)
addPackageDefinition(J9VMThread *currentThread, J9Module *fromModule, const char *package)
{
J9ClassLoader * const classLoader = fromModule->classLoader;
J9JavaVM *vm = currentThread->javaVM;
J9InternalVMFunctions const *const vmFuncs = vm->internalVMFunctions;
J9ClassLoader *const classLoader = fromModule->classLoader;

BOOLEAN retval = FALSE;

J9Package * j9package = createPackage(currentThread, fromModule, package);
PORT_ACCESS_FROM_VMC(currentThread);
#if defined(J9VM_OPT_SNAPSHOTS)
VMSNAPSHOTIMPLPORT_ACCESS_FROM_JAVAVM(vm);
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
J9Package *j9package = NULL;
J9UTF8 *packageName = NULL;
UDATA packageNameLength = strlen(package);
if (packageNameLength < J9VM_PACKAGE_NAME_BUFFER_LENGTH) {
UDATA packageNameJ9UTF8Size = packageNameLength + sizeof(J9UTF8) + 1; /* +1 for null-terminator. */
#if defined(J9VM_OPT_SNAPSHOTS)
if (IS_SNAPSHOTTING_ENABLED(vm)) {
packageName = (J9UTF8 *)vmsnapshot_allocate_memory(packageNameJ9UTF8Size, OMRMEM_CATEGORY_VM);
} else
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
{
packageName = (J9UTF8 *)j9mem_allocate_memory(packageNameJ9UTF8Size, OMRMEM_CATEGORY_VM);
}
if (NULL == packageName) {
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
return retval;
}
memcpy(J9UTF8_DATA(packageName), (void *)package, packageNameLength);
J9UTF8_DATA(packageName)[packageNameLength] = '\0';
J9UTF8_SET_LENGTH(packageName, (U_16)packageNameLength);
} else {
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL);
return retval;
}

#if defined(J9VM_OPT_SNAPSHOTS)
if (IS_RESTORE_RUN(vm)) {
j9package = hashPackageTableAtWithUTF8Name(currentThread, classLoader, packageName);
if (NULL != j9package) {
vmsnapshot_free_memory(packageName);
return TRUE;
}
}
#endif /* defined(J9VM_OPT_SNAPSHOTS) */

j9package = createPackage(currentThread, fromModule, packageName);

if (NULL != j9package) {
Trc_MODULE_invokeHashTableAtPut(currentThread, "addPackageDefinition", classLoader, classLoader->packageHashTable, &j9package, j9package, "true");
Expand Down Expand Up @@ -810,8 +855,17 @@ JVM_DefineModule(JNIEnv * env, jobject module, jboolean isOpen, jstring version,
/* An exception should be pending if classLoader is null */
Assert_SC_true(NULL != currentThread->currentException);
} else {
J9UTF8 *moduleName = vmFuncs->copyStringToJ9UTF8WithMemAlloc(
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, NULL, 0);
J9UTF8 *moduleName = NULL;
#if defined(J9VM_OPT_SNAPSHOTS)
if (IS_SNAPSHOTTING_ENABLED(vm)) {
moduleName = vmFuncs->copyStringToJ9UTF8WithPortLib(
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, VMSNAPSHOTIMPL_OMRPORT_FROM_JAVAVM(vm));
} else
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
{
moduleName = vmFuncs->copyStringToJ9UTF8WithMemAlloc(
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, NULL, 0);
}
if (NULL == moduleName) {
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
goto done;
Expand All @@ -820,7 +874,93 @@ JVM_DefineModule(JNIEnv * env, jobject module, jboolean isOpen, jstring version,
if ((classLoader != systemClassLoader) && (0 == strcmp(moduleNameData, JAVA_BASE_MODULE))) {
vmFuncs->setCurrentExceptionNLS(currentThread, J9VMCONSTANTPOOL_JAVALANGLAYERINSTANTIATIONEXCEPTION, J9NLS_VM_ONLY_BOOTCLASSLOADER_LOAD_MODULE_JAVABASE);
} else {
J9Module *j9mod = createModule(currentThread, modObj, classLoader, moduleName);
J9Module *j9mod = NULL;

if (IS_RESTORE_RUN(vm)) {
j9mod = hashModuleTableAtWithUTF8Name(currentThread, classLoader, moduleName);
if (NULL != j9mod) {
j9mod->moduleObject = modObj;
/* Bind J9Module and module object via the hidden field. */
J9OBJECT_ADDRESS_STORE(currentThread, modObj, vm->modulePointerOffset, j9mod);

if (NULL != version) {
j9mod->version = J9_JNI_UNWRAP_REFERENCE(version);
}

if (firstModule) {
/* The first module must be "java.base". */
J9ClassWalkState classWalkState = {0};
J9Class *clazz = NULL;

Assert_SC_true(0 == strcmp(moduleNameData, JAVA_BASE_MODULE));

clazz = vmFuncs->allClassesStartDo(&classWalkState, vm, systemClassLoader);
/* TODO There are clazz objects from systemClassLoader that are not in the java.base
* module (e.g. other modules include openj9.jvm and jdk.proxy1). For now, rather than
* asserting like the non-persisted path, do a string compare with the moduleName so
* that only the proper clazz->classObjects are being restored.
* Revisit this to ensure proper functionality. Also, clean this up. There is duplicated
* code with with non-restore (and else) path.
*/
while (NULL != clazz) {
J9Module *clazzModule = clazz->module;
if (NULL != clazzModule) {
const char *clazzModuleName = (const char *)J9UTF8_DATA(clazzModule->moduleName);
if (0 == strcmp(clazzModuleName, JAVA_BASE_MODULE)) {
J9VMJAVALANGCLASS_SET_MODULE(currentThread, clazz->classObject, modObj);
} else {
if (classLoader == systemClassLoader) {
const char *moduleName = "openj9.sharedclasses";

if (0 == strcmp(moduleNameData, moduleName)) {
J9VMDllLoadInfo *entry = FIND_DLL_TABLE_ENTRY(J9_SHARED_DLL_NAME);

if ((NULL == entry) || (J9_ARE_ALL_BITS_SET(entry->loadFlags, FAILED_TO_LOAD))) {
j9nls_printf( PORTLIB, J9NLS_WARNING, J9NLS_VM_FAILED_TO_LOAD_MODULE_REQUIRED_DLL, J9_SHARED_DLL_NAME, moduleName);
}
}
}
}
}
clazz = vmFuncs->allClassesNextDo(&classWalkState);
}
vmFuncs->allClassesEndDo(&classWalkState);

if (vm->anonClassCount > 0) {
J9ClassWalkState classWalkStateAnon = {0};
J9Class *clazzAnon = NULL;

Assert_SC_notNull(vm->anonClassLoader);
clazzAnon = vmFuncs->allClassesStartDo(&classWalkStateAnon, vm, vm->anonClassLoader);
while (NULL != clazzAnon) {
Assert_SC_true(clazzAnon->module == vm->javaBaseModule);
J9VMJAVALANGCLASS_SET_MODULE(currentThread, clazzAnon->classObject, modObj);
clazzAnon = vmFuncs->allClassesNextDo(&classWalkStateAnon);
}
vmFuncs->allClassesEndDo(&classWalkStateAnon);
}
vm->runtimeFlags |= J9_RUNTIME_JAVA_BASE_MODULE_CREATED;
Trc_MODULE_defineModule(currentThread, "java.base", j9mod);
} else {
Trc_MODULE_defineModule(currentThread, moduleNameData, j9mod);
if (classLoader == systemClassLoader) {
const char *moduleName = "openj9.sharedclasses";

if (0 == strcmp(moduleNameData, moduleName)) {
J9VMDllLoadInfo *entry = FIND_DLL_TABLE_ENTRY(J9_SHARED_DLL_NAME);

if ((NULL == entry) || (J9_ARE_ALL_BITS_SET(entry->loadFlags, FAILED_TO_LOAD))) {
j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_FAILED_TO_LOAD_MODULE_REQUIRED_DLL, J9_SHARED_DLL_NAME, moduleName);
}
}
}
}
TRIGGER_J9HOOK_VM_MODULE_LOAD(vm->hookInterface, currentThread, j9mod);
goto done;
}
}

j9mod = createModule(currentThread, modObj, classLoader, moduleName);
if (NULL != j9mod) {
BOOLEAN success = FALSE;
UDATA rc = addModuleDefinition(currentThread, j9mod, packages, (U_32) numPackages, version);
Expand Down Expand Up @@ -1488,13 +1628,28 @@ JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)
} else if (NULL != unnamedModuleForSystemLoader->moduleObject) {
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, "module is already set in the unnamedModuleForSystemLoader");
} else {
J9Module *j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
J9Module *j9mod = NULL;
if (IS_RESTORE_RUN(vm)) {
j9mod = unnamedModuleForSystemLoader;
/* Bind J9Module and module object via the hidden field. */
J9OBJECT_ADDRESS_STORE(currentThread, modObj, vm->modulePointerOffset, j9mod);
} else {
j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
}
unnamedModuleForSystemLoader->moduleObject = modObj;
Trc_MODULE_setUnnamedModuleForSystemLoaderModuleObject(currentThread, j9mod, unnamedModuleForSystemLoader);
}
#else /* JAVA_SPEC_VERSION >= 21 */
if (NULL == J9VMJAVALANGCLASSLOADER_UNNAMEDMODULE(currentThread, systemClassLoader->classLoaderObject)) {
J9Module *j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
J9Module *j9mod = NULL;
if (IS_RESTORE_RUN(vm)) {
j9mod = vm->unnamedModuleForSystemLoader;
vm->unnamedModuleForSystemLoader->moduleObject = modObj;
/* Bind J9Module and module object via the hidden field. */
J9OBJECT_ADDRESS_STORE(currentThread, modObj, vm->modulePointerOffset, j9mod);
} else {
j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
}
J9VMJAVALANGCLASSLOADER_SET_UNNAMEDMODULE(currentThread, systemClassLoader->classLoaderObject, modObj);
Trc_MODULE_setBootloaderUnnamedModule(currentThread, j9mod);
} else {
Expand Down
5 changes: 5 additions & 0 deletions runtime/oti/SnapshotFileFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ typedef struct SavedJ9JavaVMStructures {
J9ClassLoader *extensionClassLoader;
J9ClassLoader *applicationClassLoader;
J9HiddenInstanceField *hiddenInstanceFields;
#if JAVA_SPEC_VERSION > 8
J9Pool *modularityPool;
J9Module *javaBaseModule;
J9Module *unnamedModuleForSystemLoader;
#endif /* JAVA_SPEC_VERSION > 8 */
} SavedJ9JavaVMStructures;

/*
Expand Down
2 changes: 2 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -4859,8 +4859,10 @@ typedef struct J9InternalVMFunctions {
IDATA ( *javaThreadProc)(void *entryarg) ;
char* ( *copyStringToUTF8WithMemAlloc)(struct J9VMThread *currentThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength, UDATA *utf8Length) ;
J9UTF8* ( *copyStringToJ9UTF8WithMemAlloc)(struct J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
J9UTF8* ( *copyStringToJ9UTF8WithPortLib)(struct J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib) ;
char* ( *copyJ9UTF8ToUTF8WithMemAlloc)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
J9UTF8* ( *copyJ9UTF8WithMemAlloc)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
J9UTF8* ( *copyJ9UTF8WithPortLib)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib) ;
void ( *internalAcquireVMAccess)(struct J9VMThread * currentThread) ;
void ( *internalAcquireVMAccessWithMask)(struct J9VMThread * currentThread, UDATA haltFlags) ;
void ( *internalAcquireVMAccessNoMutexWithMask)(struct J9VMThread * vmThread, UDATA haltFlags) ;
Expand Down
7 changes: 7 additions & 0 deletions runtime/oti/util_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2912,6 +2912,13 @@ getPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const ch
*/
J9Package*
hashPackageTableAt(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);

J9Package *
hashPackageTableAtWithUTF8Name(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *packageName);

J9Module *
hashModuleTableAtWithUTF8Name(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *moduleName);

/**
* Add UTF package name to construct a J9Package for hashtable query
*
Expand Down
40 changes: 40 additions & 0 deletions runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -3577,6 +3577,26 @@ copyStringToUTF8WithMemAlloc(J9VMThread *vmThread, j9object_t string, UDATA stri
J9UTF8*
copyStringToJ9UTF8WithMemAlloc(J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength);

/**
* Copy a string object to a J9UTF8 allocated via a port library, and optionally prepend a string
* before it.
*
* @note The caller must free the memory from this pointer from the same port library memory allocator.
*
* @param[in] currentThread the current J9VMThread
* @param[in] string a string object to be copied
* it can't be NULL
* @param[in] stringFlags the flag to determine performing '.' --> '/' or NULL termination
* @param[in] prependStr the string to be prepended before the string object to be copied
* it can't be NULL but can be an empty string ""
* @param[in] prependStrLength the length of prependStr as computed by strlen
* @param[in] portLib the OMRPortLibrary from which to allocate the buffer
*
* @return a J9UTF8 pointer to the string
*/
J9UTF8 *
copyStringToJ9UTF8WithPortLib(J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib);

/**
* Copy a J9UTF8 to a UTF8 data buffer, and optionally prepend a string before it.
*
Expand Down Expand Up @@ -3619,6 +3639,26 @@ copyJ9UTF8ToUTF8WithMemAlloc(J9VMThread *vmThread, J9UTF8 *string, UDATA stringF
J9UTF8 *
copyJ9UTF8WithMemAlloc(J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength);

/**
* Creates a fresh copy of a J9UTF8 allocated via a specified port library, and optionally prepend
* a string it.
*
* @note The caller must free the memory from this pointer from the same port library memory allocator.
*
* @param[in] currentThread the current J9VMThread
* @param[in] string a J9UTF8 pointer to the data to be copied
* it can't be NULL
* @param[in] stringFlags the flag to determine performing '.' --> '/' or NULL termination
* @param[in] prependStr the string to be prepended before the string object to be copied
* it can't be NULL but can be an empty string ""
* @param[in] prependStrLength The length of prependStr as computed by strlen.
* @param[in] portLib the OMRPortLibrary from which to allocate the buffer
*
* @return a J9UTF8 pointer to the string
*/
J9UTF8 *
copyJ9UTF8WithPortLib(J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib);

/**
* Copy a Unicode String to a UTF8 data buffer.
*
Expand Down
Loading

0 comments on commit 23b8f07

Please sign in to comment.