< prev index next >

src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java

Print this page

@@ -49,10 +49,12 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.loader.ClassLoaders;
+import jdk.internal.misc.VM;
 import jdk.internal.access.JavaLangAccess;
 import jdk.internal.access.JavaLangModuleAccess;
 import jdk.internal.access.SharedSecrets;
 import jdk.internal.perf.PerfCounter;
 

@@ -131,18 +133,119 @@
         } else {
             return finder;
         }
     }
 
+    private static class ArchivedBootLayer {
+        private static ArchivedBootLayer archivedBootLayer;
+
+        private final ModuleLayer bootLayer;
+        private final ModuleFinder limitedFinder;
+        private final IllegalAccessLogger.Builder builder;
+        private final ModuleFinder unlimitedFinder;
+        private final ServicesCatalog platformCatalog;
+        private final ServicesCatalog appCatalog;
+
+        public ArchivedBootLayer(ModuleLayer bootLayer,
+                                 ModuleFinder limitedFinder,
+                                 ModuleFinder unlimitedFinder,
+                                 IllegalAccessLogger.Builder builder) {
+            this.bootLayer = bootLayer;
+            this.limitedFinder = limitedFinder;
+            this.unlimitedFinder = unlimitedFinder;
+            this.builder = builder;
+
+            this.platformCatalog = ServicesCatalog.getServicesCatalog(ClassLoaders.platformClassLoader());
+            this.appCatalog = ServicesCatalog.getServicesCatalog(ClassLoaders.appClassLoader());
+        }
+
+        static ArchivedBootLayer get() {
+            // The VM will initialize archivedBootLayer only if MetaspaceShared::use_full_module_graph() is true.
+            return archivedBootLayer;
+        }
+
+        static void archive(ArchivedBootLayer layer) {
+            archivedBootLayer = layer;
+        }
+
+        static {
+            VM.initializeFromArchive(ArchivedBootLayer.class);
+        }
+    }
+
+    private static boolean hasProperty(String key) {
+        return System.getProperty(key) != null;
+    }
+
+    private static boolean mayUseArchivedBootLayer() {
+        // If these properties are set, we cannot use the archived boot layer.
+        // The VM should have already checked this before initializing
+        // ArchivedBootLayer::archivedBootLayer.
+        if (hasProperty("jdk.module.upgrade.path") ||
+            hasProperty("jdk.module.main") ||
+            hasProperty("jdk.module.limitmods") ||
+            hasProperty("jdk.module.validation") ||
+            hasProperty("jdk.module.showModuleResolution") ||
+            hasProperty("jdk.module.illegalAccess") ||
+            hasProperty("java.system.class.loader") ||
+            hasProperty("jdk.module.addexports.0") || 
+            hasProperty("jdk.module.addopens.0") ||
+            hasProperty("jdk.module.addreads.0") ||
+            hasProperty("jdk.module.patch.0") ||
+            hasProperty("jdk.module.addmods.0")) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private static ModuleLayer getArchivedBootLayer() {
+        ArchivedBootLayer archivedBootLayer = ArchivedBootLayer.get();
+        if (archivedBootLayer != null) {
+            assert mayUseArchivedBootLayer();
+            Counters.add("jdk.module.boot.0.archivedBootLayer");
+            limitedFinder = archivedBootLayer.limitedFinder;
+            unlimitedFinder = archivedBootLayer.unlimitedFinder;
+            ModuleLayer bootLayer = archivedBootLayer.bootLayer;
+
+            // Trigger BootLoader.<clinit> 
+            BootLoader.getUnnamedModule();
+
+            // BootLoader.SERVICES_CATALOG is saved/restored separately in BootLoader.java
+            ServicesCatalog.setServicesCatalog(ClassLoaders.platformClassLoader(),
+                                               archivedBootLayer.platformCatalog);
+            ServicesCatalog.setServicesCatalog(ClassLoaders.appClassLoader(),
+                                               archivedBootLayer.appCatalog);
+
+            JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+            jla.bindToLoader(bootLayer, ClassLoaders.appClassLoader());
+
+            IllegalAccessLogger.Builder builder = archivedBootLayer.builder;
+            if (builder != null) {
+                builder.complete();
+            }
+
+            Counters.publish("jdk.module.boot.totalTime");
+            return bootLayer;
+        }
+
+        return null;
+    }
+
+
     /**
      * Initialize the module system, returning the boot layer.
      *
      * @see java.lang.System#initPhase2(boolean, boolean)
      */
     public static ModuleLayer boot() throws Exception {
 
         Counters.start();
+        ModuleLayer bootLayer = getArchivedBootLayer();
+        if (bootLayer != null) {
+            return bootLayer;
+        }
 
         // Step 0: Command line options
 
         ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
         ModuleFinder appModulePath = finderFor("jdk.module.path");

@@ -403,11 +506,11 @@
         loadModules(cf, clf);
         Counters.add("jdk.module.boot.5.loadModulesTime");
 
         // Step 6: Define all modules to the VM
 
-        ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf);
+        bootLayer = ModuleLayer.empty().defineModules(cf, clf);
         Counters.add("jdk.module.boot.6.layerCreateTime");
 
         // Step 7: Miscellaneous
 
         // check incubating status

@@ -426,10 +529,11 @@
             exportedPackagesToOpen = archivedModuleGraph.exportedPackagesToOpen();
         } else {
             concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
             exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
         }
+        IllegalAccessLogger.Builder builder =
         addIllegalAccess(upgradeModulePath,
                          concealedPackagesToOpen,
                          exportedPackagesToOpen,
                          bootLayer,
                          extraExportsOrOpens);

@@ -451,10 +555,15 @@
                                             systemModuleFinder,
                                             cf,
                                             clf,
                                             concealedPackagesToOpen,
                                             exportedPackagesToOpen));
+            ArchivedBootLayer.archive(
+                    new ArchivedBootLayer(bootLayer,
+                                          limitedFinder,
+                                          unlimitedFinder,
+                                          builder));
         }
 
         // total time to initialize
         Counters.publish("jdk.module.boot.totalTime");
 

@@ -749,21 +858,22 @@
 
     /**
      * Process the --illegal-access option (and its default) to open packages
      * of system modules in the boot layer to code in unnamed modules.
      */
-    private static void addIllegalAccess(ModuleFinder upgradeModulePath,
+    private static IllegalAccessLogger.Builder
+        addIllegalAccess(ModuleFinder upgradeModulePath,
                                          Map<String, Set<String>> concealedPackagesToOpen,
                                          Map<String, Set<String>> exportedPackagesToOpen,
                                          ModuleLayer bootLayer,
                                          boolean extraExportsOrOpens) {
         String value = getAndRemoveProperty("jdk.module.illegalAccess");
         IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
         if (value != null) {
             switch (value) {
                 case "deny":
-                    return;
+                    return null;
                 case "permit":
                     break;
                 case "warn":
                     mode = IllegalAccessLogger.Mode.WARN;
                     break;

@@ -771,11 +881,11 @@
                     mode = IllegalAccessLogger.Mode.DEBUG;
                     break;
                 default:
                     fail("Value specified to --illegal-access not recognized:"
                             + " '" + value + "'");
-                    return;
+                    return null;
             }
         }
         IllegalAccessLogger.Builder builder
             = new IllegalAccessLogger.Builder(mode, System.err);
 

@@ -839,10 +949,11 @@
             JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
             jla.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
         }
 
         builder.complete();
+        return builder;
     }
 
     /**
      * Decodes the values of --add-reads, -add-exports, --add-opens or
      * --patch-modules options that are encoded in system properties.
< prev index next >