8207263: Store the Configuration for system modules into CDS archive.
authorjiangli
Fri, 10 Aug 2018 00:35:57 -0400
changeset 51371 3ab8b84e93cd
parent 51370 fbb62267e5e9
child 51372 4737d92d752f
8207263: Store the Configuration for system modules into CDS archive. Summary: Archive boot layer Configuration. Reviewed-by: redestad, iklam, ccheung
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/systemDictionary.hpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/memory/heapShared.cpp
src/hotspot/share/memory/metaspaceShared.cpp
src/java.base/share/classes/java/lang/module/Configuration.java
src/java.base/share/classes/java/util/ImmutableCollections.java
src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java
src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Fri Aug 10 00:35:57 2018 -0400
@@ -4250,6 +4250,11 @@
 int jdk_internal_module_ArchivedModuleGraph::_archivedSystemModules_offset;
 int jdk_internal_module_ArchivedModuleGraph::_archivedModuleFinder_offset;
 int jdk_internal_module_ArchivedModuleGraph::_archivedMainModule_offset;
+int jdk_internal_module_ArchivedModuleGraph::_archivedConfiguration_offset;
+int java_lang_module_Configuration::_EMPTY_CONFIGURATION_offset;
+int java_util_ImmutableCollections_ListN::_EMPTY_LIST_offset;
+int java_util_ImmutableCollections_SetN::_EMPTY_SET_offset;
+int java_util_ImmutableCollections_MapN::_EMPTY_MAP_offset;
 
 #define STACKTRACEELEMENT_FIELDS_DO(macro) \
   macro(declaringClassObject_offset,  k, "declaringClassObject", class_signature, false); \
@@ -4412,20 +4417,81 @@
   return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
 }
 
-#define MODULEBOOTSTRAP_FIELDS_DO(macro) \
+#define ARCHIVEDMODULEGRAPH_FIELDS_DO(macro) \
   macro(_archivedSystemModules_offset,      k, "archivedSystemModules", systemModules_signature, true); \
   macro(_archivedModuleFinder_offset,       k, "archivedModuleFinder",  moduleFinder_signature,  true); \
-  macro(_archivedMainModule_offset,         k, "archivedMainModule",    string_signature,        true)
+  macro(_archivedMainModule_offset,         k, "archivedMainModule",    string_signature,        true); \
+  macro(_archivedConfiguration_offset,      k, "archivedConfiguration", configuration_signature, true)
 
 void jdk_internal_module_ArchivedModuleGraph::compute_offsets() {
   InstanceKlass* k = SystemDictionary::ArchivedModuleGraph_klass();
   assert(k != NULL, "must be loaded");
-  MODULEBOOTSTRAP_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+  ARCHIVEDMODULEGRAPH_FIELDS_DO(FIELD_COMPUTE_OFFSET);
 }
 
 #if INCLUDE_CDS
 void jdk_internal_module_ArchivedModuleGraph::serialize(SerializeClosure* f) {
-  MODULEBOOTSTRAP_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  ARCHIVEDMODULEGRAPH_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define CONFIGURATION_FIELDS_DO(macro) \
+  macro(_EMPTY_CONFIGURATION_offset, k, "EMPTY_CONFIGURATION", configuration_signature, true)
+
+void java_lang_module_Configuration::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::Configuration_klass();
+  assert(k != NULL, "must be loaded");
+  CONFIGURATION_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_module_Configuration::serialize(SerializeClosure* f) {
+  CONFIGURATION_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define LISTN_FIELDS_DO(macro) \
+  macro(_EMPTY_LIST_offset, k, "EMPTY_LIST", list_signature, true)
+
+void java_util_ImmutableCollections_ListN::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::ImmutableCollections_ListN_klass();
+  assert(k != NULL, "must be loaded");
+  LISTN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_util_ImmutableCollections_ListN::serialize(SerializeClosure* f) {
+  LISTN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define SETN_FIELDS_DO(macro) \
+  macro(_EMPTY_SET_offset, k, "EMPTY_SET", set_signature, true)
+
+void java_util_ImmutableCollections_SetN::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::ImmutableCollections_SetN_klass();
+  assert(k != NULL, "must be loaded");
+  SETN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_util_ImmutableCollections_SetN::serialize(SerializeClosure* f) {
+  SETN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define MAPN_FIELDS_DO(macro) \
+  macro(_EMPTY_MAP_offset, k, "EMPTY_MAP", map_signature, true)
+
+void java_util_ImmutableCollections_MapN::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::ImmutableCollections_MapN_klass();
+  assert(k != NULL, "must be loaded");
+  MAPN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_util_ImmutableCollections_MapN::serialize(SerializeClosure* f) {
+  MAPN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
 }
 #endif
 
@@ -4487,6 +4553,10 @@
   java_lang_LiveStackFrameInfo::compute_offsets();
   java_util_concurrent_locks_AbstractOwnableSynchronizer::compute_offsets();
 
+  java_lang_module_Configuration::compute_offsets();
+  java_util_ImmutableCollections_ListN::compute_offsets();
+  java_util_ImmutableCollections_MapN::compute_offsets();
+  java_util_ImmutableCollections_SetN::compute_offsets();
   jdk_internal_module_ArchivedModuleGraph::compute_offsets();
 
   // generated interpreter code wants to know about the offsets we just computed:
--- a/src/hotspot/share/classfile/javaClasses.hpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Fri Aug 10 00:35:57 2018 -0400
@@ -1490,10 +1490,48 @@
   static int _archivedSystemModules_offset;
   static int _archivedModuleFinder_offset;
   static int _archivedMainModule_offset;
+  static int _archivedConfiguration_offset;
  public:
   static int  archivedSystemModules_offset()      { return _archivedSystemModules_offset; }
   static int  archivedModuleFinder_offset()       { return _archivedModuleFinder_offset; }
   static int  archivedMainModule_offset()         { return _archivedMainModule_offset; }
+  static int  archivedConfiguration_offset()      { return _archivedConfiguration_offset; }
+  static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_lang_module_Configuration: AllStatic {
+ private:
+  static int _EMPTY_CONFIGURATION_offset;
+ public:
+  static int EMPTY_CONFIGURATION_offset() { return _EMPTY_CONFIGURATION_offset; }
+  static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_util_ImmutableCollections_ListN : AllStatic {
+ private:
+  static int _EMPTY_LIST_offset;
+ public:
+  static int EMPTY_LIST_offset() { return _EMPTY_LIST_offset; }
+  static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_util_ImmutableCollections_SetN : AllStatic {
+ private:
+  static int _EMPTY_SET_offset;
+ public:
+  static int EMPTY_SET_offset() { return _EMPTY_SET_offset; }
+  static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+};
+
+class java_util_ImmutableCollections_MapN : AllStatic {
+ private:
+  static int _EMPTY_MAP_offset;
+ public:
+  static int EMPTY_MAP_offset() { return _EMPTY_MAP_offset; }
   static void compute_offsets();
   static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 };
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Fri Aug 10 00:35:57 2018 -0400
@@ -187,6 +187,10 @@
   do_klass(jdk_internal_loader_ClassLoaders_AppClassLoader_klass,      jdk_internal_loader_ClassLoaders_AppClassLoader,       Pre ) \
   do_klass(jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass, jdk_internal_loader_ClassLoaders_PlatformClassLoader,  Pre ) \
   do_klass(CodeSource_klass,                            java_security_CodeSource,                  Pre                 ) \
+  do_klass(Configuration_klass,                         java_lang_module_Configuration,            Pre                 ) \
+  do_klass(ImmutableCollections_ListN_klass,            java_util_ImmutableCollections_ListN,      Pre                 ) \
+  do_klass(ImmutableCollections_MapN_klass,             java_util_ImmutableCollections_MapN,       Pre                 ) \
+  do_klass(ImmutableCollections_SetN_klass,             java_util_ImmutableCollections_SetN,       Pre                 ) \
   do_klass(ArchivedModuleGraph_klass,                   jdk_internal_module_ArchivedModuleGraph,   Pre                 ) \
                                                                                                                          \
   do_klass(StackTraceElement_klass,                     java_lang_StackTraceElement,               Opt                 ) \
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Fri Aug 10 00:35:57 2018 -0400
@@ -648,13 +648,20 @@
   JFR_TEMPLATES(template)                                                                                         \
                                                                                                                   \
   /* cds */                                                                                                       \
+  template(configuration_signature,                "Ljava/lang/module/Configuration;")                            \
+  template(java_lang_module_Configuration,         "java/lang/module/Configuration")                              \
+  template(java_util_ImmutableCollections_ListN,   "java/util/ImmutableCollections$ListN")                        \
+  template(java_util_ImmutableCollections_MapN,    "java/util/ImmutableCollections$MapN")                         \
+  template(java_util_ImmutableCollections_SetN,    "java/util/ImmutableCollections$SetN")                         \
   template(jdk_internal_loader_ClassLoaders,       "jdk/internal/loader/ClassLoaders")                            \
-  template(jdk_vm_cds_SharedClassInfo,             "jdk/vm/cds/SharedClassInfo")                                  \
-  template(url_void_signature,                     "(Ljava/net/URL;)V")                                           \
+  template(list_signature,                         "Ljava/util/List;")                                            \
+  template(map_signature,                          "Ljava/util/Map;")                                             \
+  template(moduleFinder_signature,                 "Ljava/lang/module/ModuleFinder;")                             \
+  template(set_signature,                          "Ljava/util/Set;")                                             \
+  template(systemModules_signature,                "Ljdk/internal/module/SystemModules;")                         \
   template(toFileURL_name,                         "toFileURL")                                                   \
   template(toFileURL_signature,                    "(Ljava/lang/String;)Ljava/net/URL;")                          \
-  template(moduleFinder_signature,                 "Ljava/lang/module/ModuleFinder;")                             \
-  template(systemModules_signature,                "Ljdk/internal/module/SystemModules;")                         \
+  template(url_void_signature,                     "(Ljava/net/URL;)V")                                           \
                                                                                                                   \
   /*end*/
 
--- a/src/hotspot/share/memory/heapShared.cpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/memory/heapShared.cpp	Fri Aug 10 00:35:57 2018 -0400
@@ -104,6 +104,13 @@
   }
 
   assert(relocated_k->is_shared(), "must be a shared class");
+
+  if (_k == relocated_k) {
+    // Don't add the Klass containing the sub-graph to it's own klass
+    // initialization list.
+    return;
+  }
+
   if (relocated_k->is_instance_klass()) {
     assert(InstanceKlass::cast(relocated_k)->is_shared_boot_class(),
           "must be boot class");
@@ -498,7 +505,12 @@
 #define do_module_object_graph(archive_object_graph_do) \
   archive_object_graph_do(SystemDictionary::ArchivedModuleGraph_klass(), jdk_internal_module_ArchivedModuleGraph::archivedSystemModules_offset(), T_OBJECT, CHECK); \
   archive_object_graph_do(SystemDictionary::ArchivedModuleGraph_klass(), jdk_internal_module_ArchivedModuleGraph::archivedModuleFinder_offset(), T_OBJECT, CHECK); \
-  archive_object_graph_do(SystemDictionary::ArchivedModuleGraph_klass(), jdk_internal_module_ArchivedModuleGraph::archivedMainModule_offset(), T_OBJECT, CHECK)
+  archive_object_graph_do(SystemDictionary::ArchivedModuleGraph_klass(), jdk_internal_module_ArchivedModuleGraph::archivedMainModule_offset(), T_OBJECT, CHECK); \
+  archive_object_graph_do(SystemDictionary::ArchivedModuleGraph_klass(), jdk_internal_module_ArchivedModuleGraph::archivedConfiguration_offset(), T_OBJECT, CHECK); \
+  archive_object_graph_do(SystemDictionary::ImmutableCollections_ListN_klass(), java_util_ImmutableCollections_ListN::EMPTY_LIST_offset(), T_OBJECT, CHECK); \
+  archive_object_graph_do(SystemDictionary::ImmutableCollections_MapN_klass(),  java_util_ImmutableCollections_MapN::EMPTY_MAP_offset(), T_OBJECT, CHECK); \
+  archive_object_graph_do(SystemDictionary::ImmutableCollections_SetN_klass(),  java_util_ImmutableCollections_SetN::EMPTY_SET_offset(), T_OBJECT, CHECK); \
+  archive_object_graph_do(SystemDictionary::Configuration_klass(),       java_lang_module_Configuration::EMPTY_CONFIGURATION_offset(), T_OBJECT, CHECK)
 
 void HeapShared::archive_module_graph_objects(Thread* THREAD) {
   do_module_object_graph(archive_reachable_objects_from_static_field);
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Fri Aug 10 00:35:57 2018 -0400
@@ -438,6 +438,7 @@
   java_lang_Thread::serialize(soc);
   java_lang_ThreadGroup::serialize(soc);
   java_lang_AssertionStatusDirectives::serialize(soc);
+  java_lang_module_Configuration::serialize(soc);
   java_lang_ref_SoftReference::serialize(soc);
   java_lang_invoke_MethodHandle::serialize(soc);
   java_lang_invoke_DirectMethodHandle::serialize(soc);
@@ -461,6 +462,9 @@
   java_lang_StackFrameInfo::serialize(soc);
   java_lang_LiveStackFrameInfo::serialize(soc);
   java_util_concurrent_locks_AbstractOwnableSynchronizer::serialize(soc);
+  java_util_ImmutableCollections_ListN::serialize(soc);
+  java_util_ImmutableCollections_MapN::serialize(soc);
+  java_util_ImmutableCollections_SetN::serialize(soc);
   jdk_internal_module_ArchivedModuleGraph::serialize(soc);
 }
 
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Fri Aug 10 00:35:57 2018 -0400
@@ -41,8 +41,10 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import jdk.internal.misc.VM;
 import jdk.internal.module.ModuleReferenceImpl;
 import jdk.internal.module.ModuleTarget;
+import jdk.internal.vm.annotation.Stable;
 
 /**
  * A configuration that is the result of <a href="package-summary.html#resolution">
@@ -103,7 +105,17 @@
 public final class Configuration {
 
     // @see Configuration#empty()
-    private static final Configuration EMPTY_CONFIGURATION = new Configuration();
+    // EMPTY_CONFIGURATION may be initialized from the CDS archive.
+    private static @Stable Configuration EMPTY_CONFIGURATION;
+
+    static {
+        // Initialize EMPTY_CONFIGURATION from the archive.
+        VM.initializeFromArchive(Configuration.class);
+        // Create a new empty Configuration if there is no archived version.
+        if (EMPTY_CONFIGURATION == null) {
+            EMPTY_CONFIGURATION = new Configuration();
+        }
+    }
 
     // parent configurations, in search order
     private final List<Configuration> parents;
--- a/src/java.base/share/classes/java/util/ImmutableCollections.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/java.base/share/classes/java/util/ImmutableCollections.java	Fri Aug 10 00:35:57 2018 -0400
@@ -36,6 +36,7 @@
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.VM;
 import jdk.internal.vm.annotation.Stable;
 
 /**
@@ -409,7 +410,15 @@
     static final class ListN<E> extends AbstractImmutableList<E>
             implements Serializable {
 
-        static final List<?> EMPTY_LIST = new ListN<>();
+        // EMPTY_LIST may be initialized from the CDS archive.
+        static @Stable List<?> EMPTY_LIST;
+
+        static {
+            VM.initializeFromArchive(ListN.class);
+            if (EMPTY_LIST == null) {
+                EMPTY_LIST = new ListN<>();
+            }
+        }
 
         @Stable
         private final E[] elements;
@@ -567,7 +576,15 @@
     static final class SetN<E> extends AbstractImmutableSet<E>
             implements Serializable {
 
-        static final Set<?> EMPTY_SET = new SetN<>();
+        // EMPTY_SET may be initialized from the CDS archive.
+        static @Stable Set<?> EMPTY_SET;
+
+        static {
+            VM.initializeFromArchive(SetN.class);
+            if (EMPTY_SET == null) {
+                EMPTY_SET = new SetN<>();
+            }
+        }
 
         @Stable
         final E[] elements;
@@ -772,7 +789,15 @@
      */
     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
 
-        static final Map<?,?> EMPTY_MAP = new MapN<>();
+        // EMPTY_MAP may be initialized from the CDS archive.
+        static @Stable Map<?,?> EMPTY_MAP;
+
+        static {
+            VM.initializeFromArchive(MapN.class);
+            if (EMPTY_MAP == null) {
+                EMPTY_MAP = new MapN<>();
+            }
+        }
 
         @Stable
         final Object[] table; // pairs of key, value
--- a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java	Fri Aug 10 00:35:57 2018 -0400
@@ -25,6 +25,7 @@
 
 package jdk.internal.module;
 
+import java.lang.module.Configuration;
 import java.lang.module.ModuleFinder;
 import java.util.Objects;
 import jdk.internal.misc.VM;
@@ -36,13 +37,18 @@
     private static String archivedMainModule;
     private static SystemModules archivedSystemModules;
     private static ModuleFinder archivedModuleFinder;
+    private static Configuration archivedConfiguration;
 
     private final SystemModules systemModules;
     private final ModuleFinder finder;
+    private final Configuration configuration;
 
-    private ArchivedModuleGraph(SystemModules modules, ModuleFinder finder) {
+    private ArchivedModuleGraph(SystemModules modules,
+                                ModuleFinder finder,
+                                Configuration configuration) {
         this.systemModules = modules;
         this.finder = finder;
+        this.configuration = configuration;
     }
 
     SystemModules systemModules() {
@@ -53,27 +59,36 @@
         return finder;
     }
 
+    Configuration configuration() {
+        return configuration;
+    }
+
     // A factory method that ModuleBootstrap can use to obtain the
     // ArchivedModuleGraph.
     static ArchivedModuleGraph get(String mainModule) {
         if (Objects.equals(mainModule, archivedMainModule)
                 && archivedSystemModules != null
-                && archivedModuleFinder != null) {
+                && archivedModuleFinder != null
+                && archivedConfiguration != null) {
             return new ArchivedModuleGraph(archivedSystemModules,
-                                           archivedModuleFinder);
+                                           archivedModuleFinder,
+                                           archivedConfiguration);
         } else {
             return null;
         }
     }
 
     // Used at CDS dump time
-    static void archive(String mainModule, SystemModules systemModules,
-                        ModuleFinder finder) {
+    static void archive(String mainModule,
+                        SystemModules systemModules,
+                        ModuleFinder finder,
+                        Configuration configuration) {
         if (archivedMainModule != null)
             throw new UnsupportedOperationException();
         archivedMainModule = mainModule;
         archivedSystemModules = systemModules;
         archivedModuleFinder = finder;
+        archivedConfiguration = configuration;
     }
 
     static {
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Fri Aug 10 00:35:57 2018 -0400
@@ -172,6 +172,7 @@
 
         boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
         boolean needResolution = true;
+        boolean canArchive = false;
 
         // If the java heap was archived at CDS dump time and the environment
         // at dump time matches the current environment then use the archived
@@ -186,7 +187,6 @@
             systemModuleFinder = archivedModuleGraph.finder();
             needResolution = (traceOutput != null);
         } else {
-            boolean canArchive = false;
             if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) {
                 systemModules = SystemModuleFinders.systemModules(mainModule);
                 if (systemModules != null && !isPatched) {
@@ -206,12 +206,6 @@
                 systemModules = new ExplodedSystemModules();
                 systemModuleFinder = SystemModuleFinders.ofSystem();
             }
-
-            // Module graph can be archived at CDS dump time. Only allow the
-            // unnamed module case for now.
-            if (canArchive && (mainModule == null)) {
-                ArchivedModuleGraph.archive(mainModule, systemModules, systemModuleFinder);
-            }
         }
 
         Counters.add("jdk.module.boot.1.systemModulesTime", t1);
@@ -353,8 +347,12 @@
         if (needResolution) {
             cf = JLMA.resolveAndBind(finder, roots, traceOutput);
         } else {
-            Map<String, Set<String>> map = systemModules.moduleReads();
-            cf = JLMA.newConfiguration(systemModuleFinder, map);
+            if (archivedModuleGraph != null) {
+                cf = archivedModuleGraph.configuration();
+            } else {
+                Map<String, Set<String>> map = systemModules.moduleReads();
+                cf = JLMA.newConfiguration(systemModuleFinder, map);
+            }
         }
 
         // check that modules specified to --patch-module are resolved
@@ -436,6 +434,13 @@
                 limitedFinder = new SafeModuleFinder(finder);
         }
 
+        // Module graph can be archived at CDS dump time. Only allow the
+        // unnamed module case for now.
+        if (canArchive && (mainModule == null)) {
+            ArchivedModuleGraph.archive(mainModule, systemModules,
+                                        systemModuleFinder, cf);
+        }
+
         // total time to initialize
         Counters.add("jdk.module.boot.totalTime", t0);
         Counters.publish();
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java	Fri Aug 10 00:35:57 2018 -0400
@@ -54,41 +54,49 @@
         Path userDir = Paths.get(System.getProperty("user.dir"));
         Path moduleDir = Files.createTempDirectory(userDir, "mods");
 
-        // Dump without --module-path
+        //
+        // Dump without --module-path, without --show-module-resolution
+        //
         OutputAnalyzer output = TestCommon.dump(appJar,
                                     TestCommon.list("CheckArchivedModuleApp"),
                                     use_whitebox_jar);
         TestCommon.checkDump(output);
 
         // Test case 1)
-        // - Dump without --module-path
-        // - Run from -cp only, archived boot layer module ModuleDescriptors
-        //   should be used.
+        // - Dump without --module-path, without --show-module-resolution
+        // - Run from -cp only and without --show-module-resolution
+        //     + archived boot layer module ModuleDescriptors should be used
+        //     + archived boot layer configuration should be used
         System.out.println("----------------------- Test case 1 ----------------------");
         output = TestCommon.exec(appJar, use_whitebox_jar,
                                  "-XX:+UnlockDiagnosticVMOptions",
                                  "-XX:+WhiteBoxAPI",
                                  "CheckArchivedModuleApp",
+                                 "yes",
                                  "yes");
         TestCommon.checkExec(output);
 
         // Test case 2)
-        // - Dump without --module-path
-        // - Run from -cp only, archived boot layer module ModuleDescriptors
-        //   should be used with --show-module-resolution (requires resolution).
+        // - Dump without --module-path, without --show-module-resolution
+        // - Run from -cp only and with --show-module-resolution
+        //     + archived boot layer module ModuleDescriptors should be used with
+        //       --show-module-resolution (requires resolution)
+        //     + archived boot layer Configuration should not be disabled
         System.out.println("----------------------- Test case 2 ----------------------");
         output = TestCommon.exec(appJar, use_whitebox_jar,
                                  "--show-module-resolution",
                                  "-XX:+UnlockDiagnosticVMOptions",
                                  "-XX:+WhiteBoxAPI",
                                  "CheckArchivedModuleApp",
-                                 "yes");
-        TestCommon.checkExec(output);
+                                 "yes",
+                                 "no");
+        TestCommon.checkExec(output, "root java.base jrt:/java.base");
 
         // Test case 3)
-        // - Dump without --module-path
-        // - Run with --module-path, archived boot layer module ModuleDescriptors
-        //   should be disabled.
+        // - Dump without --module-path, without --show-module-resolution
+        // - Run with --module-path
+        //    + archived boot layer module ModuleDescriptors should be disabled
+        //    + archived boot layer Configuration should be disabled
         System.out.println("----------------------- Test case 3 ----------------------");
         output = TestCommon.exec(appJar, use_whitebox_jar,
                                  "--module-path",
@@ -96,12 +104,15 @@
                                  "-XX:+UnlockDiagnosticVMOptions",
                                  "-XX:+WhiteBoxAPI",
                                  "CheckArchivedModuleApp",
+                                 "no",
                                  "no");
         TestCommon.checkExec(output);
 
+        //
         // Dump with --module-path specified (test case 4, 5). Use an
         // empty directory as it's simple and still triggers the case
         // where system module objects are not archived.
+        //
         output = TestCommon.dump(appJar,
                                  TestCommon.list("CheckArchivedModuleApp"),
                                  "--module-path",
@@ -112,19 +123,20 @@
         // Test case 4)
         // - Dump with --module-path
         // - Run from -cp only, no archived boot layer module ModuleDescriptors
-        //   should be found.
+        //   and Configuration should be found.
         System.out.println("----------------------- Test case 4 ----------------------");
         output = TestCommon.exec(appJar, use_whitebox_jar,
                                  "-XX:+UnlockDiagnosticVMOptions",
                                  "-XX:+WhiteBoxAPI",
                                  "CheckArchivedModuleApp",
+                                 "no",
                                  "no");
         TestCommon.checkExec(output);
 
         // Test case 5)
         // - Dump with --module-path
         // - Run with --module-path, no archived boot layer module ModuleDescriptors
-        //   should be found.
+        //   and Configuration should be found.
         System.out.println("----------------------- Test case 5 ----------------------");
         output = TestCommon.exec(appJar, use_whitebox_jar,
                                  "--module-path",
@@ -132,7 +144,47 @@
                                  "-XX:+UnlockDiagnosticVMOptions",
                                  "-XX:+WhiteBoxAPI",
                                  "CheckArchivedModuleApp",
+                                 "no",
                                  "no");
         TestCommon.checkExec(output);
+
+        //
+        // Dump without --module-path, with --show-module-resolution
+        //
+        output = TestCommon.dump(appJar,
+                                 TestCommon.list("CheckArchivedModuleApp"),
+                                 "--show-module-resolution",
+                                 use_whitebox_jar);
+        TestCommon.checkDump(output, "root java.base jrt:/java.base");
+
+        // Test case 6)
+        // - Dump without --module-path, with --show-module-resolution
+        // - Run from -cp only and without --show-module-resolution
+        //     + archived boot layer module ModuleDescriptors should be used
+        //     + archived boot layer Configuration should be used
+        System.out.println("----------------------- Test case 6 ----------------------");
+        output = TestCommon.exec(appJar, use_whitebox_jar,
+                                 "-XX:+UnlockDiagnosticVMOptions",
+                                 "-XX:+WhiteBoxAPI",
+                                 "CheckArchivedModuleApp",
+                                 "yes",
+                                 "yes");
+        TestCommon.checkExec(output);
+
+        // Test case 7)
+        // - Dump without --module-path, with --show-module-resolution
+        // - Run from -cp only and with --show-module-resolution
+        //     + archived boot layer module ModuleDescriptors should be used with
+        //       --show-module-resolution (requires resolution)
+        //     + archived boot layer Configuration should be disabled
+        System.out.println("----------------------- Test case 7 ----------------------");
+        output = TestCommon.exec(appJar, use_whitebox_jar,
+                                 "--show-module-resolution",
+                                 "-XX:+UnlockDiagnosticVMOptions",
+                                 "-XX:+WhiteBoxAPI",
+                                 "CheckArchivedModuleApp",
+                                 "yes",
+                                 "no");
+        TestCommon.checkExec(output, "root java.base jrt:/java.base");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java	Fri Aug 10 00:35:57 2018 -0400
@@ -130,6 +130,7 @@
                            "-XX:+UnlockDiagnosticVMOptions",
                            "-XX:+WhiteBoxAPI",
                            "CheckArchivedModuleApp",
+                           "yes",
                            "yes"};
         printCommand(runCmd);
         ProcessBuilder pbRun = new ProcessBuilder();
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java	Thu Aug 09 15:52:23 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java	Fri Aug 10 00:35:57 2018 -0400
@@ -23,7 +23,9 @@
  */
 
 import java.io.File;
+import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
+import java.util.List;
 import java.util.Set;
 import sun.hotspot.WhiteBox;
 
@@ -41,16 +43,23 @@
             return;
         }
 
-        boolean expectArchived = "yes".equals(args[0]);
-        checkModuleDescriptors(expectArchived);
+        if (args.length != 2) {
+           throw new RuntimeException(
+               "FAILED. Incorrect argument length: " + args.length);
+        }
+        boolean expectArchivedDescriptors = "yes".equals(args[0]);
+        boolean expectArchivedConfiguration = "yes".equals(args[1]);
+        checkModuleDescriptors(expectArchivedDescriptors);
+        checkConfiguration(expectArchivedConfiguration);
+        checkEmptyConfiguration(expectArchivedConfiguration);
     }
 
-    private static void checkModuleDescriptors(boolean expectArchived) {
+    private static void checkModuleDescriptors(boolean expectArchivedDescriptors) {
         Set<Module> modules = ModuleLayer.boot().modules();
         for (Module m : modules) {
             ModuleDescriptor md = m.getDescriptor();
             String name = md.name();
-            if (expectArchived) {
+            if (expectArchivedDescriptors) {
                 if (wb.isShared(md)) {
                     System.out.println(name + " is archived. Expected.");
                 } else {
@@ -67,4 +76,58 @@
             }
         }
     }
+
+    private static void checkEmptyConfiguration(boolean expectArchivedConfiguration) {
+        // Configuration.EMPTY_CONFIGURATION uses the singletons,
+        // ListN.EMPTY_LIST, SetN.EMPTY_SET and MapN.EMPTY_MAP in
+        // ImmutableCollections for the 'parents', 'modules' and
+        // 'graph' fields. The ImmutableCollections singletons
+        // can be accessed via List.of(), Set.of() and Map.of() APIs.
+        // Configuration public APIs also allow access to the
+        // EMPTY_CONFIGURATION's 'parents' and 'modules'. When the
+        // archived java heap data is enabled at runtime, make sure
+        // the EMPTY_CONFIGURATION.parents and EMPTY_CONFIGURATION.modules
+        // are the archived ImmutableCollections singletons.
+        Configuration emptyCf = Configuration.empty();
+        List emptyCfParents = emptyCf.parents();
+        Set emptyCfModules = emptyCf.modules();
+        if (expectArchivedConfiguration) {
+            if (emptyCfParents == List.of() &&
+                wb.isShared(emptyCfParents)) {
+                System.out.println("Empty Configuration has expected parents.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. Unexpected parents for empty Configuration.");
+            }
+            if (emptyCfModules == Set.of() &&
+                wb.isShared(emptyCfModules)) {
+                System.out.println("Empty Configuration has expected module set.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. Unexpected module set for empty Configuration.");
+            }
+        }
+    }
+
+
+
+    private static void checkConfiguration(boolean expectArchivedConfiguration) {
+        Configuration cf = ModuleLayer.boot().configuration();
+
+        if (expectArchivedConfiguration) {
+            if (wb.isShared(cf)) {
+                System.out.println("Boot layer configuration is archived. Expected.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. Boot layer configuration is not archived.");
+            }
+        } else {
+            if (!wb.isShared(cf)) {
+                System.out.println("Boot layer configuration is not archived. Expected.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. Boot layer configuration is archived.");
+            }
+        }
+    }
 }