Skip to content

Commit f806233

Browse files
authored
Merge pull request #20830 from ThanHenderson/snapmods
Add J9Modules and J9Packages to the VM snapshot
2 parents 81ec96a + 8e9517e commit f806233

16 files changed

+593
-61
lines changed

runtime/j9vm/java11vmi.c

Lines changed: 207 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ extern J9JavaVM *BFUjavaVM; /* from jvm.c */
6161
* b) If performing a hash operation, it assumes the caller has already locked vm->classLoaderModuleAndLocationMutex
6262
*/
6363
static UDATA hashPackageTableDelete(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);
64-
static J9Package * createPackage(J9VMThread * currentThread, J9Module * fromModule, const char *package);
64+
static J9Package *createPackage(J9VMThread *currentThread, J9Module *fromModule, J9UTF8 *package);
6565
static void freePackageDefinition(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);
6666
static BOOLEAN removePackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *packageName);
6767
static BOOLEAN addPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *package);
@@ -80,9 +80,12 @@ static void trcModulesAddModuleExports(J9VMThread * currentThread, J9Module * fr
8080
static void trcModulesAddModulePackage(J9VMThread *currentThread, J9Module *j9mod, const char *package);
8181
static UDATA hashTableAtPut(J9HashTable * table, void * value, BOOLEAN collisionIsFailure);
8282
static void throwExceptionHelper(J9VMThread * currentThread, UDATA errCode);
83-
static void freePackage(J9VMThread * currentThread, J9Package * j9package);
83+
static void freePackage(J9VMThread *currentThread, J9Package *j9package);
8484
static J9ClassLoader * getModuleObjectClassLoader(J9VMThread * currentThread, j9object_t moduleObject);
8585
static J9Module *createModule(J9VMThread *currentThread, j9object_t moduleObject, J9ClassLoader *classLoader, J9UTF8 *moduleName);
86+
#if defined(J9VM_OPT_SNAPSHOTS)
87+
static J9Module *restoreModule(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *moduleName, j9object_t moduleObject, jstring moduleVersion);
88+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
8689
static J9Module * getJ9Module(J9VMThread * currentThread, jobject module);
8790
static BOOLEAN isModuleNameValid(j9object_t moduleName);
8891
static BOOLEAN isModuleJavaBase(j9object_t moduleName);
@@ -200,37 +203,41 @@ throwExceptionHelper(J9VMThread *currentThread, UDATA errCode)
200203
}
201204

202205
static void
203-
freePackage(J9VMThread * currentThread, J9Package * j9package)
206+
freePackage(J9VMThread *currentThread, J9Package *j9package)
204207
{
205208
if (NULL != j9package) {
206-
J9JavaVM * const vm = currentThread->javaVM;
209+
J9JavaVM *const vm = currentThread->javaVM;
207210
PORT_ACCESS_FROM_JAVAVM(vm);
208211

209212
if (NULL != j9package->exportsHashTable) {
210213
hashTableFree(j9package->exportsHashTable);
211214
}
212-
j9mem_free_memory((void *) j9package->packageName);
215+
#if defined(J9VM_OPT_SNAPSHOTS)
216+
if (IS_SNAPSHOTTING_ENABLED(vm)) {
217+
VMSNAPSHOTIMPLPORT_ACCESS_FROM_JAVAVM(vm);
218+
vmsnapshot_free_memory((void *)j9package->packageName);
219+
} else
220+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
221+
{
222+
j9mem_free_memory((void *)j9package->packageName);
223+
}
213224
pool_removeElement(vm->modularityPool, j9package);
214225
}
215226
}
216227

217228
static J9Package *
218-
createPackage(J9VMThread * currentThread, J9Module * fromModule, const char *package)
229+
createPackage(J9VMThread *currentThread, J9Module *fromModule, J9UTF8 *packageName)
219230
{
220-
J9JavaVM * const vm = currentThread->javaVM;
221-
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
222-
J9Package * retval = NULL;
231+
J9JavaVM *const vm = currentThread->javaVM;
232+
J9InternalVMFunctions const *const vmFuncs = vm->internalVMFunctions;
233+
J9Package *retval = NULL;
223234

224-
J9ClassLoader * const classLoader = fromModule->classLoader;
225-
J9Package * j9package = pool_newElement(vm->modularityPool);
235+
J9Package *j9package = pool_newElement(vm->modularityPool);
226236

227237
if (NULL != j9package) {
228238
j9package->module = fromModule;
229239
j9package->classLoader = fromModule->classLoader;
230-
if (!addUTFNameToPackage(currentThread, j9package, package, NULL, 0)) {
231-
freePackage(currentThread, j9package);
232-
return retval;
233-
}
240+
j9package->packageName = packageName;
234241
j9package->exportsHashTable = vmFuncs->hashModulePointerTableNew(vm, INITIAL_INTERNAL_MODULE_HASHTABLE_SIZE);
235242
if (NULL != j9package->exportsHashTable) {
236243
retval = j9package;
@@ -315,6 +322,107 @@ createModule(J9VMThread *currentThread, j9object_t moduleObject, J9ClassLoader *
315322
return retval;
316323
}
317324

325+
#if defined(J9VM_OPT_SNAPSHOTS)
326+
static J9Module *
327+
restoreModule(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *moduleName, j9object_t moduleObject, jstring moduleVersion)
328+
{
329+
J9JavaVM *vm = currentThread->javaVM;
330+
J9InternalVMFunctions const *const vmFuncs = vm->internalVMFunctions;
331+
J9ClassLoader *systemClassLoader = vm->systemClassLoader;
332+
BOOLEAN firstModule = J9_ARE_NO_BITS_SET(vm->runtimeFlags, J9_RUNTIME_JAVA_BASE_MODULE_CREATED);
333+
J9Module *ret = NULL;
334+
PORT_ACCESS_FROM_VMC(currentThread);
335+
336+
J9Module *module = hashModuleTableAtWithUTF8Name(currentThread, classLoader, moduleName);
337+
338+
if (NULL != module) {
339+
const char *moduleNameData = (const char *)J9UTF8_DATA(moduleName);
340+
module->moduleObject = moduleObject;
341+
/* Bind J9Module and module object via the hidden field. */
342+
J9OBJECT_ADDRESS_STORE(currentThread, moduleObject, vm->modulePointerOffset, module);
343+
344+
if (NULL != moduleVersion) {
345+
module->version = J9_JNI_UNWRAP_REFERENCE(moduleVersion);
346+
}
347+
348+
if (firstModule) {
349+
/* The first module must be "java.base". */
350+
J9ClassWalkState classWalkState = {0};
351+
J9Class *clazz = NULL;
352+
353+
Assert_SC_true(0 == strcmp(moduleNameData, JAVA_BASE_MODULE));
354+
355+
clazz = vmFuncs->allClassesStartDo(&classWalkState, vm, systemClassLoader);
356+
/* TODO: There are clazz objects from systemClassLoader that are not in the java.base
357+
* module (e.g. other modules include openj9.jvm and jdk.proxy1). For now, rather than
358+
* asserting like the non-persisted path, do a string compare with the moduleName so
359+
* that only the proper clazz->classObjects are being restored.
360+
* Revisit this to ensure proper functionality. Also, clean this up. There is duplicated
361+
* code with with non-restore (and else) path.
362+
*/
363+
while (NULL != clazz) {
364+
J9Module *clazzModule = clazz->module;
365+
366+
if (NULL != clazzModule) {
367+
const char *clazzModuleName = (const char *)J9UTF8_DATA(clazzModule->moduleName);
368+
369+
if (0 == strcmp(clazzModuleName, JAVA_BASE_MODULE)) {
370+
J9VMJAVALANGCLASS_SET_MODULE(currentThread, clazz->classObject, moduleObject);
371+
} else {
372+
if (classLoader == systemClassLoader) {
373+
const char *moduleName = "openj9.sharedclasses";
374+
375+
if (0 == strcmp(moduleNameData, moduleName)) {
376+
J9VMDllLoadInfo *entry = FIND_DLL_TABLE_ENTRY(J9_SHARED_DLL_NAME);
377+
378+
if ((NULL == entry) || (J9_ARE_ALL_BITS_SET(entry->loadFlags, FAILED_TO_LOAD))) {
379+
j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_FAILED_TO_LOAD_MODULE_REQUIRED_DLL, J9_SHARED_DLL_NAME, moduleName);
380+
}
381+
}
382+
}
383+
}
384+
}
385+
clazz = vmFuncs->allClassesNextDo(&classWalkState);
386+
}
387+
vmFuncs->allClassesEndDo(&classWalkState);
388+
389+
if (vm->anonClassCount > 0) {
390+
J9ClassWalkState classWalkStateAnon = {0};
391+
J9Class *clazzAnon = NULL;
392+
393+
Assert_SC_notNull(vm->anonClassLoader);
394+
clazzAnon = vmFuncs->allClassesStartDo(&classWalkStateAnon, vm, vm->anonClassLoader);
395+
while (NULL != clazzAnon) {
396+
Assert_SC_true(clazzAnon->module == vm->javaBaseModule);
397+
J9VMJAVALANGCLASS_SET_MODULE(currentThread, clazzAnon->classObject, moduleObject);
398+
clazzAnon = vmFuncs->allClassesNextDo(&classWalkStateAnon);
399+
}
400+
vmFuncs->allClassesEndDo(&classWalkStateAnon);
401+
}
402+
vm->runtimeFlags |= J9_RUNTIME_JAVA_BASE_MODULE_CREATED;
403+
Trc_MODULE_defineModule(currentThread, "java.base", module);
404+
} else {
405+
Trc_MODULE_defineModule(currentThread, moduleNameData, module);
406+
if (classLoader == systemClassLoader) {
407+
const char *moduleName = "openj9.sharedclasses";
408+
409+
if (0 == strcmp(moduleNameData, moduleName)) {
410+
J9VMDllLoadInfo *entry = FIND_DLL_TABLE_ENTRY(J9_SHARED_DLL_NAME);
411+
412+
if ((NULL == entry) || (J9_ARE_ALL_BITS_SET(entry->loadFlags, FAILED_TO_LOAD))) {
413+
j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_FAILED_TO_LOAD_MODULE_REQUIRED_DLL, J9_SHARED_DLL_NAME, moduleName);
414+
}
415+
}
416+
}
417+
}
418+
TRIGGER_J9HOOK_VM_MODULE_LOAD(vm->hookInterface, currentThread, module);
419+
ret = module;
420+
}
421+
422+
return ret;
423+
}
424+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
425+
318426
static void
319427
freePackageDefinition(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName)
320428
{
@@ -348,13 +456,54 @@ trcModulesCreationPackage(J9VMThread *currentThread, J9Module *fromModule, const
348456
}
349457

350458
static BOOLEAN
351-
addPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const char *package)
459+
addPackageDefinition(J9VMThread *currentThread, J9Module *fromModule, const char *package)
352460
{
353-
J9ClassLoader * const classLoader = fromModule->classLoader;
461+
J9JavaVM *vm = currentThread->javaVM;
462+
J9InternalVMFunctions const *const vmFuncs = vm->internalVMFunctions;
463+
J9ClassLoader *const classLoader = fromModule->classLoader;
354464

355465
BOOLEAN retval = FALSE;
356466

357-
J9Package * j9package = createPackage(currentThread, fromModule, package);
467+
PORT_ACCESS_FROM_VMC(currentThread);
468+
#if defined(J9VM_OPT_SNAPSHOTS)
469+
VMSNAPSHOTIMPLPORT_ACCESS_FROM_JAVAVM(vm);
470+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
471+
J9Package *j9package = NULL;
472+
J9UTF8 *packageName = NULL;
473+
UDATA packageNameLength = strlen(package);
474+
if (packageNameLength < J9VM_PACKAGE_NAME_BUFFER_LENGTH) {
475+
UDATA packageNameJ9UTF8Size = packageNameLength + sizeof(J9UTF8) + 1; /* +1 for null-terminator. */
476+
#if defined(J9VM_OPT_SNAPSHOTS)
477+
if (IS_SNAPSHOTTING_ENABLED(vm)) {
478+
packageName = (J9UTF8 *)vmsnapshot_allocate_memory(packageNameJ9UTF8Size, OMRMEM_CATEGORY_VM);
479+
} else
480+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
481+
{
482+
packageName = (J9UTF8 *)j9mem_allocate_memory(packageNameJ9UTF8Size, OMRMEM_CATEGORY_VM);
483+
}
484+
if (NULL == packageName) {
485+
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
486+
return retval;
487+
}
488+
memcpy(J9UTF8_DATA(packageName), (void *)package, packageNameLength);
489+
J9UTF8_DATA(packageName)[packageNameLength] = '\0';
490+
J9UTF8_SET_LENGTH(packageName, (U_16)packageNameLength);
491+
} else {
492+
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, NULL);
493+
return retval;
494+
}
495+
496+
#if defined(J9VM_OPT_SNAPSHOTS)
497+
if (IS_RESTORE_RUN(vm)) {
498+
j9package = hashPackageTableAtWithUTF8Name(currentThread, classLoader, packageName);
499+
if (NULL != j9package) {
500+
vmsnapshot_free_memory(packageName);
501+
return TRUE;
502+
}
503+
}
504+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
505+
506+
j9package = createPackage(currentThread, fromModule, packageName);
358507

359508
if (NULL != j9package) {
360509
Trc_MODULE_invokeHashTableAtPut(currentThread, "addPackageDefinition", classLoader, classLoader->packageHashTable, &j9package, j9package, "true");
@@ -810,8 +959,17 @@ JVM_DefineModule(JNIEnv * env, jobject module, jboolean isOpen, jstring version,
810959
/* An exception should be pending if classLoader is null */
811960
Assert_SC_true(NULL != currentThread->currentException);
812961
} else {
813-
J9UTF8 *moduleName = vmFuncs->copyStringToJ9UTF8WithMemAlloc(
814-
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, NULL, 0);
962+
J9UTF8 *moduleName = NULL;
963+
#if defined(J9VM_OPT_SNAPSHOTS)
964+
if (IS_SNAPSHOTTING_ENABLED(vm)) {
965+
moduleName = vmFuncs->copyStringToJ9UTF8WithPortLib(
966+
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, VMSNAPSHOTIMPL_OMRPORT_FROM_JAVAVM(vm));
967+
} else
968+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
969+
{
970+
moduleName = vmFuncs->copyStringToJ9UTF8WithMemAlloc(
971+
currentThread, moduleNameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, NULL, 0);
972+
}
815973
if (NULL == moduleName) {
816974
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
817975
goto done;
@@ -820,7 +978,18 @@ JVM_DefineModule(JNIEnv * env, jobject module, jboolean isOpen, jstring version,
820978
if ((classLoader != systemClassLoader) && (0 == strcmp(moduleNameData, JAVA_BASE_MODULE))) {
821979
vmFuncs->setCurrentExceptionNLS(currentThread, J9VMCONSTANTPOOL_JAVALANGLAYERINSTANTIATIONEXCEPTION, J9NLS_VM_ONLY_BOOTCLASSLOADER_LOAD_MODULE_JAVABASE);
822980
} else {
823-
J9Module *j9mod = createModule(currentThread, modObj, classLoader, moduleName);
981+
J9Module *j9mod = NULL;
982+
983+
#if defined(J9VM_OPT_SNAPSHOTS)
984+
if (IS_RESTORE_RUN(vm)) {
985+
j9mod = restoreModule(currentThread, classLoader, moduleName, modObj, version);
986+
if (NULL != j9mod) {
987+
goto done;
988+
}
989+
}
990+
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
991+
992+
j9mod = createModule(currentThread, modObj, classLoader, moduleName);
824993
if (NULL != j9mod) {
825994
BOOLEAN success = FALSE;
826995
UDATA rc = addModuleDefinition(currentThread, j9mod, packages, (U_32) numPackages, version);
@@ -1488,13 +1657,28 @@ JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)
14881657
} else if (NULL != unnamedModuleForSystemLoader->moduleObject) {
14891658
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGINTERNALERROR, "module is already set in the unnamedModuleForSystemLoader");
14901659
} else {
1491-
J9Module *j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
1660+
J9Module *j9mod = NULL;
1661+
if (IS_RESTORE_RUN(vm)) {
1662+
j9mod = unnamedModuleForSystemLoader;
1663+
/* Bind J9Module and module object via the hidden field. */
1664+
J9OBJECT_ADDRESS_STORE(currentThread, modObj, vm->modulePointerOffset, j9mod);
1665+
} else {
1666+
j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
1667+
}
14921668
unnamedModuleForSystemLoader->moduleObject = modObj;
14931669
Trc_MODULE_setUnnamedModuleForSystemLoaderModuleObject(currentThread, j9mod, unnamedModuleForSystemLoader);
14941670
}
14951671
#else /* JAVA_SPEC_VERSION >= 21 */
14961672
if (NULL == J9VMJAVALANGCLASSLOADER_UNNAMEDMODULE(currentThread, systemClassLoader->classLoaderObject)) {
1497-
J9Module *j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
1673+
J9Module *j9mod = NULL;
1674+
if (IS_RESTORE_RUN(vm)) {
1675+
j9mod = vm->unnamedModuleForSystemLoader;
1676+
vm->unnamedModuleForSystemLoader->moduleObject = modObj;
1677+
/* Bind J9Module and module object via the hidden field. */
1678+
J9OBJECT_ADDRESS_STORE(currentThread, modObj, vm->modulePointerOffset, j9mod);
1679+
} else {
1680+
j9mod = createModule(currentThread, modObj, systemClassLoader, NULL /* NULL name field */);
1681+
}
14981682
J9VMJAVALANGCLASSLOADER_SET_UNNAMEDMODULE(currentThread, systemClassLoader->classLoaderObject, modObj);
14991683
Trc_MODULE_setBootloaderUnnamedModule(currentThread, j9mod);
15001684
} else {

runtime/oti/SnapshotFileFormat.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ typedef struct SavedJ9JavaVMStructures {
5757
J9ClassLoader *extensionClassLoader;
5858
J9ClassLoader *applicationClassLoader;
5959
J9HiddenInstanceField *hiddenInstanceFields;
60+
#if JAVA_SPEC_VERSION > 8
61+
J9Pool *modularityPool;
62+
J9Module *javaBaseModule;
63+
J9Module *unnamedModuleForSystemLoader;
64+
#endif /* JAVA_SPEC_VERSION > 8 */
6065
} SavedJ9JavaVMStructures;
6166

6267
/*

runtime/oti/j9nonbuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4859,8 +4859,10 @@ typedef struct J9InternalVMFunctions {
48594859
IDATA ( *javaThreadProc)(void *entryarg) ;
48604860
char* ( *copyStringToUTF8WithMemAlloc)(struct J9VMThread *currentThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength, UDATA *utf8Length) ;
48614861
J9UTF8* ( *copyStringToJ9UTF8WithMemAlloc)(struct J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
4862+
J9UTF8* ( *copyStringToJ9UTF8WithPortLib)(struct J9VMThread *vmThread, j9object_t string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib) ;
48624863
char* ( *copyJ9UTF8ToUTF8WithMemAlloc)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
48634864
J9UTF8* ( *copyJ9UTF8WithMemAlloc)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, char *buffer, UDATA bufferLength) ;
4865+
J9UTF8* ( *copyJ9UTF8WithPortLib)(struct J9VMThread *vmThread, J9UTF8 *string, UDATA stringFlags, const char *prependStr, UDATA prependStrLength, OMRPortLibrary *portLib) ;
48644866
void ( *internalAcquireVMAccess)(struct J9VMThread * currentThread) ;
48654867
void ( *internalAcquireVMAccessWithMask)(struct J9VMThread * currentThread, UDATA haltFlags) ;
48664868
void ( *internalAcquireVMAccessNoMutexWithMask)(struct J9VMThread * vmThread, UDATA haltFlags) ;

runtime/oti/util_api.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,6 +2912,31 @@ getPackageDefinition(J9VMThread * currentThread, J9Module * fromModule, const ch
29122912
*/
29132913
J9Package*
29142914
hashPackageTableAt(J9VMThread * currentThread, J9ClassLoader * classLoader, const char *packageName);
2915+
2916+
/**
2917+
* Look up a J9Package in a classloader's package hashtable based on the package name
2918+
*
2919+
* @param[in] currentThread the current J9VMThread
2920+
* @param[in] classLoader the classloader with the target package hashtable
2921+
* @param[in] packageName the package name for the query
2922+
*
2923+
* @return a pointer to the J9Package if found or NULL
2924+
*/
2925+
J9Package *
2926+
hashPackageTableAtWithUTF8Name(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *packageName);
2927+
2928+
/**
2929+
* Look up a J9Module in a classloader's module hashtable based on the module name
2930+
*
2931+
* @param[in] currentThread the current J9VMThread
2932+
* @param[in] classLoader the classloader with the target module hashtable
2933+
* @param[in] moduleName the module name for the query
2934+
*
2935+
* @return a pointer to the J9Module if found or NULL
2936+
*/
2937+
J9Module *
2938+
hashModuleTableAtWithUTF8Name(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *moduleName);
2939+
29152940
/**
29162941
* Add UTF package name to construct a J9Package for hashtable query
29172942
*

0 commit comments

Comments
 (0)