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 Modularity Structures in the Snapshot #20612

Open
babsingh opened this issue Nov 18, 2024 · 3 comments
Open

Cache Modularity Structures in the Snapshot #20612

babsingh opened this issue Nov 18, 2024 · 3 comments

Comments

@babsingh
Copy link
Contributor

babsingh commented Nov 18, 2024

The goal is to cache modularity related structures in the snapshot. From a high level, this requires us to save and restore instances of J9Module, J9Package and J9ModuleExtraInfo.

typedef struct J9Module {
j9object_t moduleName;
j9object_t moduleObject;
j9object_t version;
struct J9ClassLoader* classLoader;
struct J9HashTable* readAccessHashTable;
struct J9HashTable* removeAccessHashTable;
struct J9HashTable* removeExportsHashTable;
BOOLEAN isLoose;
BOOLEAN isOpen;
} J9Module;

typedef struct J9Package {
struct J9UTF8* packageName;
U_32 exportToAll;
U_32 exportToAllUnnamed;
struct J9Module* module;
struct J9HashTable* exportsHashTable;
struct J9ClassLoader* classLoader;
} J9Package;

typedef struct J9ModuleExtraInfo {
struct J9Module* j9module;
struct J9UTF8* jrtURL;
struct J9ClassPathEntry** patchPathEntries;
UDATA patchPathCount;
} J9ModuleExtraInfo;

Implementation

  1. Add new fields in SavedJ9JavaVMStructures to save and restore J9JavaVM->modularityPool, J9JavaVM->javaBaseModule and J9JavaVM->unnamedModuleForSystemLoader.

struct J9Pool* modularityPool;
struct J9Module *javaBaseModule;
struct J9Module *unnamedModuleForSystemLoader;

typedef struct SavedJ9JavaVMStructures {
J9Pool *classLoaderBlocks;

VMSnapshotImpl::saveJ9JavaVMStructures()
{
saveClassLoaderBlocks();

VMSnapshotImpl::restoreJ9JavaVMStructures()
{
bool success = true;
fixupVMStructures();
restoreClassLoaderBlocks();
restoreMemorySegments();
restorePrimitiveAndArrayClasses();

  1. Make sure that the restored fields are not re-initialized during the restore run through proper macros (e.g. IS_RESTORE_RUN).

  2. Use the snapshot port library to allocate J9JavaVM->modularityPool similar to the existing logic that is used for J9JavaVM->classLoaderBlocks.

    openj9/runtime/vm/jvminit.c

    Lines 2641 to 2644 in efaa4f6

    vm->modularityPool = pool_new(OMR_MAX(sizeof(J9Package),sizeof(J9Module)), 0, 0, 0, J9_GET_CALLSITE(), J9MEM_CATEGORY_MODULES, POOL_FOR_PORT(vm->portLibrary));
    if (NULL == vm->modularityPool) {
    goto _error;
    }

  3. Use the snapshot port library to allocate the related hashtables. We already do this for hashPackageTableNew and hashModuleNameTableNew. We want to extend this to hashModuleExtraInfoTableNew and hashModulePointerTableNew.

hashModulePointerTableNew(J9JavaVM *javaVM, U_32 initialSize)
{
U_32 flags = J9HASH_TABLE_ALLOW_SIZE_OPTIMIZATION;
return hashTableNew(
OMRPORT_FROM_J9PORT(javaVM->portLibrary),

hashModuleExtraInfoTableNew(J9JavaVM *javaVM, U_32 initialSize)
{
U_32 flags = J9HASH_TABLE_ALLOW_SIZE_OPTIMIZATION;
return hashTableNew(
OMRPORT_FROM_J9PORT(javaVM->portLibrary),

  1. Similarly, make sure that all the memory, for the internal fields of the above three native structures, is allocated using the snapshot port library. This will allow them to be successfully cached in the snapshot.

  2. If the fields cannot be cached (e.g. the object fields moduleName/moduleObject/version in J9Module), add appropriate code to initialize them during every run once the cached data is loaded.

  3. During the creation paths, add logic to restore the native structures from the snapshot, and then initialize the required fields.

    • For J9Module, createModule will need to be updated to load the cached J9Module during the restore phase. J9ClassLoader->moduleHashTable will be used to find the cached J9Module. J9Module->moduleName will be cleared during shutdown before the snapshot is written, and it is needed for comparisons to resolve hashtable collisions. Since objects can't persist across runs, the module name will need to be stored as a string in J9Module. The moduleName pointer and other GC code to persist the object pointer can be removed. The usage of J9Module->moduleName will need to be replaced by the string that is stored in J9Module. If the moduleName object is needed, it can be accessed through J9Module->moduleObject (via vmconstantpool.xml).
    • The remaining object fields in J9Module will need to be cleared during shutdown and reinitialized once a J9Module entry is restored from the snapshot in createModule.
      createModule(J9VMThread * currentThread, j9object_t moduleObject, J9ClassLoader * classLoader, j9object_t moduleName)
      {
      J9JavaVM * const vm = currentThread->javaVM;
      J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
      J9Module * j9mod = NULL;

      J9Module module = {0};
      J9Module *modulePtr = &module;
      modulePtr->moduleName = moduleName;
      findResult = hashTableFind(classLoader->moduleHashTable, &modulePtr);
      if (NULL != findResult) {
      j9module = *findResult;
      }
    • For J9Package, createPackage will need to be updated similarly, and the cached value can be found using J9ClassLoader->packageHashTable.
      createPackage(J9VMThread * currentThread, J9Module * fromModule, const char *package)
      {
      J9JavaVM * const vm = currentThread->javaVM;
      J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
      J9Package * retval = NULL;

      J9Package*
      hashPackageTableAt(J9VMThread *currentThread, J9ClassLoader *classLoader, const char *packageName)
      {
      J9Package package = {0};
      J9Package *packagePtr = &package;

      hashPackageTableAtWithUTF8Name(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *packageName)
      {
      J9Package package = {0};
      J9Package *packagePtr = &package;
      J9Package **targetPtr = NULL;
    • For J9ModuleExtraInfo, caching the hashtable should be sufficient. The current code checks in the hashtable before creating a new J9ModuleExtraInfo.
    • Memory, for the J9UTF8 strings and other native memory for the fields within these structs, will need to be allocated using the vmsnapshot_allocate_memory.
  4. Make sure that pointers to J9Module stored in other structs are valid and if needed fixed: J9Package->module, J9ModuleExtraInfo->j9module and J9Class->module. No pointers to J9Package and J9ModuleExtraInfo exist in other structs.

  5. Check the exit paths (e.g. where freeJ9Module, freePackage, freeClassLoader are being invoked) to make sure that entities are written to the snapshot and not being freed early.

Copy link

Issue Number: 20612
Status: Open
Recommended Components: comp:vm, comp:test, comp:jvmti

@babsingh
Copy link
Contributor Author

@ThanHenderson
Copy link
Contributor

I've made some pretty good progress towards this last week. I'll have the implementation done this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants