8212995: Placing the Integer.IntegerCache and cached Integer objects in the closed archive heap region.
authorjiangli
Sat, 03 Nov 2018 15:40:19 -0400
changeset 52402 72d4e10305b9
parent 52401 595ab4f025d7
child 52403 89c73c4b1efe
8212995: Placing the Integer.IntegerCache and cached Integer objects in the closed archive heap region. Summary: Support shareable archive object subgraphs in closed archive heap regions. Reviewed-by: iklam, ccheung
src/hotspot/share/classfile/stringTable.cpp
src/hotspot/share/classfile/stringTable.hpp
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/heapShared.cpp
src/hotspot/share/memory/heapShared.hpp
src/hotspot/share/memory/metaspaceShared.cpp
src/hotspot/share/memory/metaspaceShared.hpp
src/hotspot/share/prims/whitebox.cpp
src/java.base/share/classes/java/lang/Integer.java
--- a/src/hotspot/share/classfile/stringTable.cpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/classfile/stringTable.cpp	Sat Nov 03 15:40:19 2018 -0400
@@ -78,7 +78,6 @@
 
 // --------------------------------------------------------------------------
 StringTable* StringTable::_the_table = NULL;
-volatile bool StringTable::_shared_string_mapped = false;
 volatile bool StringTable::_alt_hash = false;
 
 static juint murmur_seed = 0;
@@ -871,7 +870,7 @@
   if (soc->writing()) {
     // Sanity. Make sure we don't use the shared table at dump time
     _shared_table.reset();
-  } else if (!_shared_string_mapped) {
+  } else if (!HeapShared::closed_archive_heap_region_mapped()) {
     _shared_table.reset();
   }
 }
--- a/src/hotspot/share/classfile/stringTable.hpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/classfile/stringTable.hpp	Sat Nov 03 15:40:19 2018 -0400
@@ -55,7 +55,6 @@
 
   // The string table
   static StringTable* _the_table;
-  static volatile bool _shared_string_mapped;
   static volatile bool _alt_hash;
 
 private:
@@ -166,8 +165,6 @@
   static void copy_shared_string_table(CompactHashtableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN;
  public:
   static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
-  static void set_shared_string_mapped() { _shared_string_mapped = true; }
-  static bool shared_string_mapped()     { return _shared_string_mapped; }
   static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
   static void write_to_archive() NOT_CDS_JAVA_HEAP_RETURN;
   static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
--- a/src/hotspot/share/memory/filemap.cpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/memory/filemap.cpp	Sat Nov 03 15:40:19 2018 -0400
@@ -26,7 +26,6 @@
 #include "jvm.h"
 #include "classfile/classLoader.inline.hpp"
 #include "classfile/classLoaderExt.hpp"
-#include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/altHashing.hpp"
@@ -615,7 +614,7 @@
   } else {
     si->_file_offset = _file_offset;
   }
-  if (MetaspaceShared::is_heap_region(region)) {
+  if (HeapShared::is_heap_region(region)) {
     assert((base - (char*)Universe::narrow_oop_base()) % HeapWordSize == 0, "Sanity");
     if (base != NULL) {
       si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)base);
@@ -814,7 +813,7 @@
                                             "String1", "String2", "OpenArchive1", "OpenArchive2" };
 
 char* FileMapInfo::map_region(int i, char** top_ret) {
-  assert(!MetaspaceShared::is_heap_region(i), "sanity");
+  assert(!HeapShared::is_heap_region(i), "sanity");
   CDSFileMapRegion* si = space_at(i);
   size_t used = si->_used;
   size_t alignment = os::vm_allocation_granularity();
@@ -857,14 +856,14 @@
   }
 }
 
-static MemRegion *string_ranges = NULL;
+static MemRegion *closed_archive_heap_ranges = NULL;
 static MemRegion *open_archive_heap_ranges = NULL;
-static int num_string_ranges = 0;
+static int num_closed_archive_heap_ranges = 0;
 static int num_open_archive_heap_ranges = 0;
 
 #if INCLUDE_CDS_JAVA_HEAP
 bool FileMapInfo::has_heap_regions() {
-  return (_header->_space[MetaspaceShared::first_string]._used > 0);
+  return (_header->_space[MetaspaceShared::first_closed_archive_heap_region]._used > 0);
 }
 
 // Returns the address range of the archived heap regions computed using the
@@ -875,7 +874,9 @@
   address start = (address) max_uintx;
   address end   = NULL;
 
-  for (int i = MetaspaceShared::first_string; i <= MetaspaceShared::last_valid_region; i++) {
+  for (int i = MetaspaceShared::first_closed_archive_heap_region;
+           i <= MetaspaceShared::last_valid_region;
+           i++) {
     CDSFileMapRegion* si = space_at(i);
     size_t size = si->_used;
     if (size > 0) {
@@ -894,16 +895,16 @@
 }
 
 //
-// Map the shared string objects and open archive heap objects to the runtime
-// java heap.
+// Map the closed and open archive heap objects to the runtime java heap.
 //
-// The shared strings are mapped close to the end of the java heap top in
-// closed archive regions. The mapped strings contain no out-going references
-// to any other java heap regions. GC does not write into the mapped shared strings.
+// The shared objects are mapped at (or close to ) the java heap top in
+// closed archive regions. The mapped objects contain no out-going
+// references to any other java heap regions. GC does not write into the
+// mapped closed archive heap region.
 //
-// The open archive heap objects are mapped below the shared strings in
-// the runtime java heap. The mapped open archive heap data only contain
-// references to the shared strings and open archive objects initially.
+// The open archive heap objects are mapped below the shared objects in
+// the runtime java heap. The mapped open archive heap data only contains
+// references to the shared objects and open archive objects initially.
 // During runtime execution, out-going references to any other java heap
 // regions may be added. GC may mark and update references in the mapped
 // open archive objects.
@@ -983,29 +984,31 @@
   log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta);
   HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
 
-  CDSFileMapRegion* si = space_at(MetaspaceShared::first_string);
-  address relocated_strings_bottom = start_address_as_decoded_from_archive(si);
-  if (!is_aligned(relocated_strings_bottom, HeapRegion::GrainBytes)) {
-    // Align the bottom of the string regions at G1 region boundary. This will avoid
-    // the situation where the highest open region and the lowest string region sharing
-    // the same G1 region. Otherwise we will fail to map the open regions.
-    size_t align = size_t(relocated_strings_bottom) % HeapRegion::GrainBytes;
+  CDSFileMapRegion* si = space_at(MetaspaceShared::first_closed_archive_heap_region);
+  address relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si);
+  if (!is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes)) {
+    // Align the bottom of the closed archive heap regions at G1 region boundary.
+    // This will avoid the situation where the highest open region and the lowest
+    // closed region sharing the same G1 region. Otherwise we will fail to map the
+    // open regions.
+    size_t align = size_t(relocated_closed_heap_region_bottom) % HeapRegion::GrainBytes;
     delta -= align;
     log_info(cds)("CDS heap data need to be relocated lower by a further " SIZE_FORMAT
-                  " bytes to " INTX_FORMAT " to be aligned with HeapRegion::GrainBytes", align, delta);
+                  " bytes to " INTX_FORMAT " to be aligned with HeapRegion::GrainBytes",
+                  align, delta);
     HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
     _heap_pointers_need_patching = true;
-    relocated_strings_bottom = start_address_as_decoded_from_archive(si);
+    relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si);
   }
-  assert(is_aligned(relocated_strings_bottom, HeapRegion::GrainBytes), "must be");
+  assert(is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes),
+         "must be");
 
-  // First, map string regions as closed archive heap regions.
-  // GC does not write into the regions.
-  if (map_heap_data(&string_ranges,
-                    MetaspaceShared::first_string,
-                    MetaspaceShared::max_strings,
-                    &num_string_ranges)) {
-    StringTable::set_shared_string_mapped();
+  // Map the closed_archive_heap regions, GC does not write into the regions.
+  if (map_heap_data(&closed_archive_heap_ranges,
+                    MetaspaceShared::first_closed_archive_heap_region,
+                    MetaspaceShared::max_closed_archive_heap_region,
+                    &num_closed_archive_heap_ranges)) {
+    HeapShared::set_closed_archive_heap_region_mapped();
 
     // Now, map open_archive heap regions, GC can write into the regions.
     if (map_heap_data(&open_archive_heap_ranges,
@@ -1023,8 +1026,9 @@
     map_heap_regions_impl();
   }
 
-  if (!StringTable::shared_string_mapped()) {
-    assert(string_ranges == NULL && num_string_ranges == 0, "sanity");
+  if (!HeapShared::closed_archive_heap_region_mapped()) {
+    assert(closed_archive_heap_ranges == NULL &&
+           num_closed_archive_heap_ranges == 0, "sanity");
   }
 
   if (!HeapShared::open_archive_heap_region_mapped()) {
@@ -1115,9 +1119,9 @@
     return;
   }
 
-  patch_archived_heap_embedded_pointers(string_ranges,
-                                        num_string_ranges,
-                                        MetaspaceShared::first_string);
+  patch_archived_heap_embedded_pointers(closed_archive_heap_ranges,
+                                        num_closed_archive_heap_ranges,
+                                        MetaspaceShared::first_closed_archive_heap_region);
 
   patch_archived_heap_embedded_pointers(open_archive_heap_ranges,
                                         num_open_archive_heap_ranges,
@@ -1136,11 +1140,13 @@
 // This internally allocates objects using SystemDictionary::Object_klass(), so it
 // must be called after the well-known classes are resolved.
 void FileMapInfo::fixup_mapped_heap_regions() {
-  // If any string regions were found, call the fill routine to make them parseable.
-  // Note that string_ranges may be non-NULL even if no ranges were found.
-  if (num_string_ranges != 0) {
-    assert(string_ranges != NULL, "Null string_ranges array with non-zero count");
-    G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_string_ranges);
+  // If any closed regions were found, call the fill routine to make them parseable.
+  // Note that closed_archive_heap_ranges may be non-NULL even if no ranges were found.
+  if (num_closed_archive_heap_ranges != 0) {
+    assert(closed_archive_heap_ranges != NULL,
+           "Null closed_archive_heap_ranges array with non-zero count");
+    G1CollectedHeap::heap()->fill_archive_regions(closed_archive_heap_ranges,
+                                                  num_closed_archive_heap_ranges);
   }
 
   // do the same for mapped open archive heap regions
@@ -1170,9 +1176,9 @@
   if (sz == 0) {
     return true; // no data
   }
-  if ((MetaspaceShared::is_string_region(i) &&
-       !StringTable::shared_string_mapped()) ||
-      (MetaspaceShared::is_open_archive_heap_region(i) &&
+  if ((HeapShared::is_closed_archive_heap_region(i) &&
+       !HeapShared::closed_archive_heap_region_mapped()) ||
+      (HeapShared::is_open_archive_heap_region(i) &&
        !HeapShared::open_archive_heap_region_mapped())) {
     return true; // archived heap data is not mapped
   }
@@ -1188,7 +1194,7 @@
 // Unmap a memory region in the address space.
 
 void FileMapInfo::unmap_region(int i) {
-  assert(!MetaspaceShared::is_heap_region(i), "sanity");
+  assert(!HeapShared::is_heap_region(i), "sanity");
   CDSFileMapRegion* si = space_at(i);
   size_t used = si->_used;
   size_t size = align_up(used, os::vm_allocation_granularity());
@@ -1259,7 +1265,7 @@
 
 char* FileMapInfo::region_addr(int idx) {
   CDSFileMapRegion* si = space_at(idx);
-  if (MetaspaceShared::is_heap_region(idx)) {
+  if (HeapShared::is_heap_region(idx)) {
     assert(DumpSharedSpaces, "The following doesn't work at runtime");
     return si->_used > 0 ?
           (char*)start_address_as_decoded_with_current_oop_encoding_mode(si) : NULL;
@@ -1326,7 +1332,7 @@
   if (prop != NULL) {
     warning("Archived non-system classes are disabled because the "
             "java.system.class.loader property is specified (value = \"%s\"). "
-            "To use archived non-system classes, this property must be not be set", prop);
+            "To use archived non-system classes, this property must not be set", prop);
     _has_platform_or_app_classes = false;
   }
 
@@ -1383,7 +1389,7 @@
   if (map_info) {
     map_info->fail_continue("%s", msg);
     for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
-      if (!MetaspaceShared::is_heap_region(i)) {
+      if (!HeapShared::is_heap_region(i)) {
         char *addr = map_info->region_addr(i);
         if (addr != NULL) {
           map_info->unmap_region(i);
@@ -1395,7 +1401,8 @@
     // of the java heap. Unmapping of the heap regions are managed by GC.
     map_info->dealloc_archive_heap_regions(open_archive_heap_ranges,
                                            num_open_archive_heap_ranges);
-    map_info->dealloc_archive_heap_regions(string_ranges, num_string_ranges);
+    map_info->dealloc_archive_heap_regions(closed_archive_heap_ranges,
+                                           num_closed_archive_heap_ranges);
   } else if (DumpSharedSpaces) {
     fail_stop("%s", msg);
   }
--- a/src/hotspot/share/memory/heapShared.cpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/memory/heapShared.cpp	Sat Nov 03 15:40:19 2018 -0400
@@ -37,6 +37,7 @@
 #include "memory/metaspaceClosure.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/compressedOops.inline.hpp"
+#include "oops/fieldStreams.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/safepointVerifiers.hpp"
@@ -47,12 +48,40 @@
 
 #if INCLUDE_CDS_JAVA_HEAP
 
+bool HeapShared::_closed_archive_heap_region_mapped = false;
 bool HeapShared::_open_archive_heap_region_mapped = false;
 bool HeapShared::_archive_heap_region_fixed = false;
 
 address   HeapShared::_narrow_oop_base;
 int       HeapShared::_narrow_oop_shift;
 
+//
+// If you add new entries to the following tables, you should know what you're doing!
+//
+
+// Entry fields for shareable subgraphs archived in the closed archive heap
+// region. Warning: Objects in the subgraphs should not have reference fields
+// assigned at runtime.
+static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = {
+  {"java/lang/Integer$IntegerCache",           "archivedCache"},
+};
+// Entry fields for subgraphs archived in the open archive heap region.
+static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
+  {"jdk/internal/module/ArchivedModuleGraph",  "archivedSystemModules"},
+  {"jdk/internal/module/ArchivedModuleGraph",  "archivedModuleFinder"},
+  {"jdk/internal/module/ArchivedModuleGraph",  "archivedMainModule"},
+  {"jdk/internal/module/ArchivedModuleGraph",  "archivedConfiguration"},
+  {"java/util/ImmutableCollections$ListN",     "EMPTY_LIST"},
+  {"java/util/ImmutableCollections$MapN",      "EMPTY_MAP"},
+  {"java/util/ImmutableCollections$SetN",      "EMPTY_SET"},
+  {"java/lang/module/Configuration",           "EMPTY_CONFIGURATION"},
+};
+
+const static int num_closed_archive_subgraph_entry_fields =
+  sizeof(closed_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
+const static int num_open_archive_subgraph_entry_fields =
+  sizeof(open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
+
 ////////////////////////////////////////////////////////////////
 //
 // Java heap object archiving support
@@ -189,6 +218,10 @@
   // Archive interned string objects
   StringTable::write_to_archive();
 
+  archive_object_subgraphs(closed_archive_subgraph_entry_fields,
+                           num_closed_archive_subgraph_entry_fields,
+                           true /* is_closed_archive */, THREAD);
+
   G1CollectedHeap::heap()->end_archive_alloc_range(closed_archive,
                                                    os::vm_allocation_granularity());
 }
@@ -204,7 +237,10 @@
 
   archive_klass_objects(THREAD);
 
-  archive_object_subgraphs(THREAD);
+  archive_object_subgraphs(open_archive_subgraph_entry_fields,
+                           num_open_archive_subgraph_entry_fields,
+                           false /* is_closed_archive */,
+                           THREAD);
 
   G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
                                                    os::vm_allocation_granularity());
@@ -237,7 +273,8 @@
 }
 
 // Add an entry field to the current KlassSubGraphInfo.
-void KlassSubGraphInfo::add_subgraph_entry_field(int static_field_offset, oop v) {
+void KlassSubGraphInfo::add_subgraph_entry_field(
+      int static_field_offset, oop v, bool is_closed_archive) {
   assert(DumpSharedSpaces, "dump time only");
   if (_subgraph_entry_fields == NULL) {
     _subgraph_entry_fields =
@@ -245,6 +282,7 @@
   }
   _subgraph_entry_fields->append((juint)static_field_offset);
   _subgraph_entry_fields->append(CompressedOops::encode(v));
+  _subgraph_entry_fields->append(is_closed_archive ? 1 : 0);
 }
 
 // Add the Klass* for an object in the current KlassSubGraphInfo's subgraphs.
@@ -315,7 +353,7 @@
   GrowableArray<juint>* entry_fields = info->subgraph_entry_fields();
   if (entry_fields != NULL) {
     int num_entry_fields = entry_fields->length();
-    assert(num_entry_fields % 2 == 0, "sanity");
+    assert(num_entry_fields % 3 == 0, "sanity");
     _entry_field_records =
       MetaspaceShared::new_ro_array<juint>(num_entry_fields);
     for (int i = 0 ; i < num_entry_fields; i++) {
@@ -365,8 +403,8 @@
 // Build the records of archived subgraph infos, which include:
 // - Entry points to all subgraphs from the containing class mirror. The entry
 //   points are static fields in the mirror. For each entry point, the field
-//   offset and value are recorded in the sub-graph info. The value are stored
-//   back to the corresponding field at runtime.
+//   offset, value and is_closed_archive flag are recorded in the sub-graph
+//   info. The value is stored back to the corresponding field at runtime.
 // - A list of klasses that need to be loaded/initialized before archived
 //   java object sub-graph can be accessed at runtime.
 void HeapShared::write_subgraph_info_table() {
@@ -448,15 +486,25 @@
     Array<juint>* entry_field_records = record->entry_field_records();
     if (entry_field_records != NULL) {
       int efr_len = entry_field_records->length();
-      assert(efr_len % 2 == 0, "sanity");
+      assert(efr_len % 3 == 0, "sanity");
       for (i = 0; i < efr_len;) {
         int field_offset = entry_field_records->at(i);
-        // The object refereced by the field becomes 'known' by GC from this
-        // point. All objects in the subgraph reachable from the object are
-        // also 'known' by GC.
-        oop v = materialize_archived_object(entry_field_records->at(i+1));
+        narrowOop nv = entry_field_records->at(i+1);
+        int is_closed_archive = entry_field_records->at(i+2);
+        oop v;
+        if (is_closed_archive == 0) {
+          // It's an archived object in the open archive heap regions, not shared.
+          // The object refereced by the field becomes 'known' by GC from this
+          // point. All objects in the subgraph reachable from the object are
+          // also 'known' by GC.
+          v = materialize_archived_object(nv);
+        } else {
+          // Shared object in the closed archive heap regions. Decode directly.
+          assert(!CompressedOops::is_null(nv), "shared object is null");
+          v = HeapShared::decode_from_archive(nv);
+        }
         m->obj_field_put(field_offset, v);
-        i += 2;
+        i += 3;
 
         log_debug(cds, heap)("  " PTR_FORMAT " init field @ %2d = " PTR_FORMAT, p2i(k), field_offset, p2i(v));
       }
@@ -469,16 +517,20 @@
 
 class WalkOopAndArchiveClosure: public BasicOopIterateClosure {
   int _level;
+  bool _is_closed_archive;
   bool _record_klasses_only;
   KlassSubGraphInfo* _subgraph_info;
   oop _orig_referencing_obj;
   oop _archived_referencing_obj;
   Thread* _thread;
  public:
-  WalkOopAndArchiveClosure(int level, bool record_klasses_only,
+  WalkOopAndArchiveClosure(int level,
+                           bool is_closed_archive,
+                           bool record_klasses_only,
                            KlassSubGraphInfo* subgraph_info,
                            oop orig, oop archived, TRAPS) :
-    _level(level), _record_klasses_only(record_klasses_only),
+    _level(level), _is_closed_archive(is_closed_archive),
+    _record_klasses_only(record_klasses_only),
     _subgraph_info(subgraph_info),
     _orig_referencing_obj(orig), _archived_referencing_obj(archived),
     _thread(THREAD) {}
@@ -506,7 +558,8 @@
         obj->print_on(&out);
       }
 
-      oop archived = HeapShared::archive_reachable_objects_from(_level + 1, _subgraph_info, obj, THREAD);
+      oop archived = HeapShared::archive_reachable_objects_from(
+          _level + 1, _subgraph_info, obj, _is_closed_archive, THREAD);
       assert(archived != NULL, "VM should have exited with unarchivable objects for _level > 1");
       assert(HeapShared::is_archived_object(archived), "must be");
 
@@ -520,11 +573,32 @@
   }
 };
 
+void HeapShared::check_closed_archive_heap_region_object(InstanceKlass* k,
+                                                         Thread* THREAD) {
+  // Check fields in the object
+  for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
+    if (!fs.access_flags().is_static()) {
+      BasicType ft = fs.field_descriptor().field_type();
+      if (!fs.access_flags().is_final() && (ft == T_ARRAY || T_OBJECT)) {
+        ResourceMark rm(THREAD);
+        log_warning(cds, heap)(
+          "Please check reference field in %s instance in closed archive heap region: %s %s",
+          k->external_name(), (fs.name())->as_C_string(),
+          (fs.signature())->as_C_string());
+      }
+    }
+  }
+}
+
 // (1) If orig_obj has not been archived yet, archive it.
 // (2) If orig_obj has not been seen yet (since start_recording_subgraph() was called),
 //     trace all  objects that are reachable from it, and make sure these objects are archived.
 // (3) Record the klasses of all orig_obj and all reachable objects.
-oop HeapShared::archive_reachable_objects_from(int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, TRAPS) {
+oop HeapShared::archive_reachable_objects_from(int level,
+                                               KlassSubGraphInfo* subgraph_info,
+                                               oop orig_obj,
+                                               bool is_closed_archive,
+                                               TRAPS) {
   assert(orig_obj != NULL, "must be");
   assert(!is_archived_object(orig_obj), "sanity");
 
@@ -578,8 +652,12 @@
   Klass *relocated_k = archived_obj->klass();
   subgraph_info->add_subgraph_object_klass(orig_k, relocated_k);
 
-  WalkOopAndArchiveClosure walker(level, record_klasses_only, subgraph_info, orig_obj, archived_obj, THREAD);
+  WalkOopAndArchiveClosure walker(level, is_closed_archive, record_klasses_only,
+                                  subgraph_info, orig_obj, archived_obj, THREAD);
   orig_obj->oop_iterate(&walker);
+  if (is_closed_archive && orig_k->is_instance_klass()) {
+    check_closed_archive_heap_region_object(InstanceKlass::cast(orig_k), THREAD);
+  }
   return archived_obj;
 }
 
@@ -621,15 +699,12 @@
                                                              const char* klass_name,
                                                              int field_offset,
                                                              const char* field_name,
+                                                             bool is_closed_archive,
                                                              TRAPS) {
   assert(DumpSharedSpaces, "dump time only");
   assert(k->is_shared_boot_class(), "must be boot class");
 
   oop m = k->java_mirror();
-  oop archived_m = find_archived_heap_object(m);
-  if (CompressedOops::is_null(archived_m)) {
-    return;
-  }
 
   KlassSubGraphInfo* subgraph_info = get_subgraph_info(k);
   oop f = m->obj_field(field_offset);
@@ -643,7 +718,8 @@
       f->print_on(&out);
     }
 
-    oop af = archive_reachable_objects_from(1, subgraph_info, f, CHECK);
+    oop af = archive_reachable_objects_from(1, subgraph_info, f,
+                                            is_closed_archive, CHECK);
 
     if (af == NULL) {
       log_error(cds, heap)("Archiving failed %s::%s (some reachable objects cannot be archived)",
@@ -652,13 +728,13 @@
       // Note: the field value is not preserved in the archived mirror.
       // Record the field as a new subGraph entry point. The recorded
       // information is restored from the archive at runtime.
-      subgraph_info->add_subgraph_entry_field(field_offset, af);
+      subgraph_info->add_subgraph_entry_field(field_offset, af, is_closed_archive);
       log_info(cds, heap)("Archived field %s::%s => " PTR_FORMAT, klass_name, field_name, p2i(af));
     }
   } else {
     // The field contains null, we still need to record the entry point,
     // so it can be restored at runtime.
-    subgraph_info->add_subgraph_entry_field(field_offset, NULL);
+    subgraph_info->add_subgraph_entry_field(field_offset, NULL, false);
   }
 }
 
@@ -687,10 +763,6 @@
   assert(k->is_shared_boot_class(), "must be boot class");
 
   oop m = k->java_mirror();
-  oop archived_m = find_archived_heap_object(m);
-  if (CompressedOops::is_null(archived_m)) {
-    return;
-  }
   oop f = m->obj_field(field_offset);
   if (!CompressedOops::is_null(f)) {
     verify_subgraph_from(f);
@@ -783,30 +855,6 @@
   _num_total_recorded_klasses +=  num_new_recorded_klasses;
 }
 
-struct ArchivableStaticFieldInfo {
-  const char* klass_name;
-  const char* field_name;
-  InstanceKlass* klass;
-  int offset;
-  BasicType type;
-};
-
-// If you add new entries to this table, you should know what you're doing!
-static ArchivableStaticFieldInfo archivable_static_fields[] = {
-  {"jdk/internal/module/ArchivedModuleGraph",  "archivedSystemModules"},
-  {"jdk/internal/module/ArchivedModuleGraph",  "archivedModuleFinder"},
-  {"jdk/internal/module/ArchivedModuleGraph",  "archivedMainModule"},
-  {"jdk/internal/module/ArchivedModuleGraph",  "archivedConfiguration"},
-  {"java/util/ImmutableCollections$ListN",     "EMPTY_LIST"},
-  {"java/util/ImmutableCollections$MapN",      "EMPTY_MAP"},
-  {"java/util/ImmutableCollections$SetN",      "EMPTY_SET"},
-  {"java/lang/Integer$IntegerCache",           "archivedCache"},
-  {"java/lang/module/Configuration",           "EMPTY_CONFIGURATION"},
-};
-
-const static int num_archivable_static_fields =
-  sizeof(archivable_static_fields) / sizeof(ArchivableStaticFieldInfo);
-
 class ArchivableStaticFieldFinder: public FieldClosure {
   InstanceKlass* _ik;
   Symbol* _field_name;
@@ -828,11 +876,10 @@
   int offset()     { return _offset; }
 };
 
-void HeapShared::init_archivable_static_fields(Thread* THREAD) {
-  _dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
-
-  for (int i = 0; i < num_archivable_static_fields; i++) {
-    ArchivableStaticFieldInfo* info = &archivable_static_fields[i];
+void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
+                                            int num, Thread* THREAD) {
+  for (int i = 0; i < num; i++) {
+    ArchivableStaticFieldInfo* info = &fields[i];
     TempNewSymbol klass_name =  SymbolTable::new_symbol(info->klass_name, THREAD);
     TempNewSymbol field_name =  SymbolTable::new_symbol(info->field_name, THREAD);
 
@@ -849,7 +896,26 @@
   }
 }
 
-void HeapShared::archive_object_subgraphs(Thread* THREAD) {
+void HeapShared::init_subgraph_entry_fields(Thread* THREAD) {
+  _dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
+
+  init_subgraph_entry_fields(closed_archive_subgraph_entry_fields,
+                             num_closed_archive_subgraph_entry_fields,
+                             THREAD);
+  init_subgraph_entry_fields(open_archive_subgraph_entry_fields,
+                             num_open_archive_subgraph_entry_fields,
+                             THREAD);
+}
+
+void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
+                                          int num, bool is_closed_archive,
+                                          Thread* THREAD) {
+  _num_total_subgraph_recordings = 0;
+  _num_total_walked_objs = 0;
+  _num_total_archived_objs = 0;
+  _num_total_recorded_klasses = 0;
+  _num_total_verifications = 0;
+
   // For each class X that has one or more archived fields:
   // [1] Dump the subgraph of each archived field
   // [2] Create a list of all the class of the objects that can be reached
@@ -857,38 +923,40 @@
   //     At runtime, these classes are initialized before X's archived fields
   //     are restored by HeapShared::initialize_from_archived_subgraph().
   int i;
-  for (i = 0; i < num_archivable_static_fields; ) {
-    ArchivableStaticFieldInfo* info = &archivable_static_fields[i];
+  for (i = 0; i < num; ) {
+    ArchivableStaticFieldInfo* info = &fields[i];
     const char* klass_name = info->klass_name;
     start_recording_subgraph(info->klass, klass_name);
 
     // If you have specified consecutive fields of the same klass in
-    // archivable_static_fields[], these will be archived in the same
+    // fields[], these will be archived in the same
     // {start_recording_subgraph ... done_recording_subgraph} pass to
     // save time.
-    for (; i < num_archivable_static_fields; i++) {
-      ArchivableStaticFieldInfo* f = &archivable_static_fields[i];
+    for (; i < num; i++) {
+      ArchivableStaticFieldInfo* f = &fields[i];
       if (f->klass_name != klass_name) {
         break;
       }
       archive_reachable_objects_from_static_field(f->klass, f->klass_name,
-                                                  f->offset, f->field_name, CHECK);
+                                                  f->offset, f->field_name,
+                                                  is_closed_archive, CHECK);
     }
     done_recording_subgraph(info->klass, klass_name);
   }
 
-  log_info(cds, heap)("Performed subgraph records = %d times", _num_total_subgraph_recordings);
-  log_info(cds, heap)("Walked %d objects", _num_total_walked_objs);
-  log_info(cds, heap)("Archived %d objects", _num_total_archived_objs);
-  log_info(cds, heap)("Recorded %d klasses", _num_total_recorded_klasses);
-
+  log_info(cds, heap)("Archived subgraph records in %s archive heap region = %d",
+                      is_closed_archive ? "closed" : "open",
+                      _num_total_subgraph_recordings);
+  log_info(cds, heap)("  Walked %d objects", _num_total_walked_objs);
+  log_info(cds, heap)("  Archived %d objects", _num_total_archived_objs);
+  log_info(cds, heap)("  Recorded %d klasses", _num_total_recorded_klasses);
 
 #ifndef PRODUCT
-  for (int i = 0; i < num_archivable_static_fields; i++) {
-    ArchivableStaticFieldInfo* f = &archivable_static_fields[i];
+  for (int i = 0; i < num; i++) {
+    ArchivableStaticFieldInfo* f = &fields[i];
     verify_subgraph_from_static_field(f->klass, f->offset);
   }
-  log_info(cds, heap)("Verified %d references", _num_total_verifications);
+  log_info(cds, heap)("  Verified %d references", _num_total_verifications);
 #endif
 }
 
--- a/src/hotspot/share/memory/heapShared.hpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/memory/heapShared.hpp	Sat Nov 03 15:40:19 2018 -0400
@@ -28,6 +28,7 @@
 #include "classfile/compactHashtable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "memory/allocation.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/universe.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/oop.hpp"
@@ -37,6 +38,14 @@
 #include "utilities/resourceHash.hpp"
 
 #if INCLUDE_CDS_JAVA_HEAP
+struct ArchivableStaticFieldInfo {
+  const char* klass_name;
+  const char* field_name;
+  InstanceKlass* klass;
+  int offset;
+  BasicType type;
+};
+
 // A dump time sub-graph info for Klass _k. It includes the entry points
 // (static fields in _k's mirror) of the archived sub-graphs reachable
 // from _k's mirror. It also contains a list of Klasses of the objects
@@ -50,7 +59,8 @@
   // object sub-graphs can be accessed at runtime.
   GrowableArray<Klass*>* _subgraph_object_klasses;
   // A list of _k's static fields as the entry points of archived sub-graphs.
-  // For each entry field, it is a pair of field_offset and field_value.
+  // For each entry field, it is a tuple of field_offset, field_value and
+  // is_closed_archive flag.
   GrowableArray<juint>*  _subgraph_entry_fields;
 
  public:
@@ -73,7 +83,8 @@
   GrowableArray<juint>*  subgraph_entry_fields() {
     return _subgraph_entry_fields;
   }
-  void add_subgraph_entry_field(int static_field_offset, oop v);
+  void add_subgraph_entry_field(int static_field_offset, oop v,
+                                bool is_closed_archive);
   void add_subgraph_object_klass(Klass *orig_k, Klass *relocated_k);
   int num_subgraph_object_klasses() {
     return _subgraph_object_klasses == NULL ? 0 :
@@ -109,6 +120,7 @@
  private:
 
 #if INCLUDE_CDS_JAVA_HEAP
+  static bool _closed_archive_heap_region_mapped;
   static bool _open_archive_heap_region_mapped;
   static bool _archive_heap_region_fixed;
 
@@ -160,21 +172,34 @@
   static DumpTimeKlassSubGraphInfoTable* _dump_time_subgraph_info_table;
   static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table;
 
+  static void check_closed_archive_heap_region_object(InstanceKlass* k,
+                                                      Thread* THREAD);
+
+  static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
+                                       int num,
+                                       bool is_closed_archive,
+                                       Thread* THREAD);
+
   // Archive object sub-graph starting from the given static field
   // in Klass k's mirror.
   static void archive_reachable_objects_from_static_field(
     InstanceKlass* k, const char* klass_name,
-    int field_offset, const char* field_name, TRAPS);
+    int field_offset, const char* field_name,
+    bool is_closed_archive, TRAPS);
+
   static void verify_subgraph_from_static_field(
     InstanceKlass* k, int field_offset) PRODUCT_RETURN;
-
   static void verify_reachable_objects_from(oop obj, bool is_archived) PRODUCT_RETURN;
+  static void verify_subgraph_from(oop orig_obj) PRODUCT_RETURN;
 
   static KlassSubGraphInfo* get_subgraph_info(Klass *k);
   static int num_of_subgraph_infos();
 
   static void build_archived_subgraph_info_records(int num_records);
 
+  static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
+                                         int num, Thread* THREAD);
+
   // Used by decode_from_archive
   static address _narrow_oop_base;
   static int     _narrow_oop_shift;
@@ -245,6 +270,14 @@
                                         GrowableArray<MemRegion> *open);
   static void copy_closed_archive_heap_objects(GrowableArray<MemRegion> * closed_archive);
   static void copy_open_archive_heap_objects(GrowableArray<MemRegion> * open_archive);
+
+  static oop archive_reachable_objects_from(int level,
+                                            KlassSubGraphInfo* subgraph_info,
+                                            oop orig_obj,
+                                            bool is_closed_archive,
+                                            TRAPS);
+
+  static ResourceBitMap calculate_oopmap(MemRegion region);
 #endif // INCLUDE_CDS_JAVA_HEAP
 
  public:
@@ -253,6 +286,30 @@
     NOT_CDS_JAVA_HEAP(return false;)
   }
 
+  static bool is_heap_region(int idx) {
+    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_closed_archive_heap_region &&
+                               idx <= MetaspaceShared::last_open_archive_heap_region));
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+  static bool is_closed_archive_heap_region(int idx) {
+    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_closed_archive_heap_region &&
+                               idx <= MetaspaceShared::last_closed_archive_heap_region));
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+  static bool is_open_archive_heap_region(int idx) {
+    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_open_archive_heap_region &&
+                               idx <= MetaspaceShared::last_open_archive_heap_region));
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+
+  static void set_closed_archive_heap_region_mapped() {
+    CDS_JAVA_HEAP_ONLY(_closed_archive_heap_region_mapped = true);
+    NOT_CDS_JAVA_HEAP_RETURN;
+  }
+  static bool closed_archive_heap_region_mapped() {
+    CDS_JAVA_HEAP_ONLY(return _closed_archive_heap_region_mapped);
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
   static void set_open_archive_heap_region_mapped() {
     CDS_JAVA_HEAP_ONLY(_open_archive_heap_region_mapped = true);
     NOT_CDS_JAVA_HEAP_RETURN;
@@ -283,15 +340,8 @@
   static void patch_archived_heap_embedded_pointers(MemRegion mem, address  oopmap,
                                                     size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
 
-  static void init_archivable_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
-  static void archive_object_subgraphs(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
+  static void init_subgraph_entry_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
   static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
   static void serialize_subgraph_info_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
-
-#if INCLUDE_CDS_JAVA_HEAP
-  static ResourceBitMap calculate_oopmap(MemRegion region);
-  static oop archive_reachable_objects_from(int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, TRAPS);
-  static void verify_subgraph_from(oop orig_obj) PRODUCT_RETURN;
-#endif
 };
 #endif // SHARE_VM_MEMORY_HEAPSHARED_HPP
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Sat Nov 03 15:40:19 2018 -0400
@@ -86,8 +86,8 @@
 //     md  - misc data (the c++ vtables)
 //     od  - optional data (original class files)
 //
-//     s0  - shared strings(closed archive heap space) #0
-//     s1  - shared strings(closed archive heap space) #1 (may be empty)
+//     ca0 - closed archive heap space #0
+//     ca1 - closed archive heap space #1 (may be empty)
 //     oa0 - open archive heap space #0
 //     oa1 - open archive heap space #1 (may be empty)
 //
@@ -198,7 +198,7 @@
 
 
 DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
-size_t _total_string_region_size = 0, _total_open_archive_region_size = 0;
+size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0;
 
 char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) {
   return _mc_region.allocate(num_bytes);
@@ -1274,9 +1274,8 @@
     // NOTE: after this point, we shouldn't have any globals that can reach the old
     // objects.
 
-    // We cannot use any of the objects in the heap anymore (except for the objects
-    // in the CDS shared string regions) because their headers no longer point to
-    // valid Klasses.
+    // We cannot use any of the objects in the heap anymore (except for the
+    // shared strings) because their headers no longer point to valid Klasses.
   }
 
   static void iterate_roots(MetaspaceClosure* it) {
@@ -1491,11 +1490,11 @@
     write_region(mapinfo, MetaspaceShared::md, &_md_region, /*read_only=*/false,/*allow_exec=*/false);
     write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false);
 
-    _total_string_region_size = mapinfo->write_archive_heap_regions(
+    _total_closed_archive_region_size = mapinfo->write_archive_heap_regions(
                                         _closed_archive_heap_regions,
                                         _closed_archive_heap_oopmaps,
-                                        MetaspaceShared::first_string,
-                                        MetaspaceShared::max_strings);
+                                        MetaspaceShared::first_closed_archive_heap_region,
+                                        MetaspaceShared::max_closed_archive_heap_region);
     _total_open_archive_region_size = mapinfo->write_archive_heap_regions(
                                         _open_archive_heap_regions,
                                         _open_archive_heap_oopmaps,
@@ -1529,12 +1528,12 @@
   const size_t total_reserved = _ro_region.reserved()  + _rw_region.reserved() +
                                 _mc_region.reserved()  + _md_region.reserved() +
                                 _od_region.reserved()  +
-                                _total_string_region_size +
+                                _total_closed_archive_region_size +
                                 _total_open_archive_region_size;
   const size_t total_bytes = _ro_region.used()  + _rw_region.used() +
                              _mc_region.used()  + _md_region.used() +
                              _od_region.used()  +
-                             _total_string_region_size +
+                             _total_closed_archive_region_size +
                              _total_open_archive_region_size;
   const double total_u_perc = percent_of(total_bytes, total_reserved);
 
@@ -1543,7 +1542,7 @@
   _ro_region.print(total_reserved);
   _md_region.print(total_reserved);
   _od_region.print(total_reserved);
-  print_heap_region_stats(_closed_archive_heap_regions, "st", total_reserved);
+  print_heap_region_stats(_closed_archive_heap_regions, "ca", total_reserved);
   print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
 
   tty->print_cr("total    : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
@@ -1715,7 +1714,7 @@
     tty->print_cr("Rewriting and linking classes: done");
 
     SystemDictionary::clear_invoke_method_table();
-    HeapShared::init_archivable_static_fields(THREAD);
+    HeapShared::init_subgraph_entry_fields(THREAD);
 
     VM_PopulateDumpSharedSpace op;
     VMThread::execute(&op);
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Sat Nov 03 15:40:19 2018 -0400
@@ -76,13 +76,14 @@
     num_non_heap_spaces = od + 1,
 
     // mapped java heap regions
-    first_string = od + 1, // index of first string region
-    max_strings = 2, // max number of string regions in string space
-    last_string = first_string + max_strings - 1,
-    first_open_archive_heap_region = first_string + max_strings,
+    first_closed_archive_heap_region = od + 1,
+    max_closed_archive_heap_region = 2,
+    last_closed_archive_heap_region = first_closed_archive_heap_region + max_closed_archive_heap_region - 1,
+    first_open_archive_heap_region = last_closed_archive_heap_region + 1,
     max_open_archive_heap_region = 2,
+    last_open_archive_heap_region = first_open_archive_heap_region + max_open_archive_heap_region - 1,
 
-    last_valid_region = first_open_archive_heap_region + max_open_archive_heap_region - 1,
+    last_valid_region = last_open_archive_heap_region,
     n_regions =  last_valid_region + 1 // total number of regions
   };
 
@@ -131,23 +132,6 @@
   // Return true if given address is in the shared region corresponding to the idx
   static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
 
-  static bool is_heap_region(int idx) {
-    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_string &&
-                               idx < MetaspaceShared::first_open_archive_heap_region +
-                                     MetaspaceShared::max_open_archive_heap_region));
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
-  static bool is_string_region(int idx) {
-    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_string &&
-                               idx < MetaspaceShared::first_string + MetaspaceShared::max_strings));
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
-  static bool is_open_archive_heap_region(int idx) {
-    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_open_archive_heap_region &&
-                               idx < MetaspaceShared::first_open_archive_heap_region +
-                                     MetaspaceShared::max_open_archive_heap_region));
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
   static bool is_in_trampoline_frame(address addr) NOT_CDS_RETURN_(false);
 
   static void allocate_cpp_vtable_clones();
--- a/src/hotspot/share/prims/whitebox.cpp	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/hotspot/share/prims/whitebox.cpp	Sat Nov 03 15:40:19 2018 -0400
@@ -1774,7 +1774,7 @@
 WB_END
 
 WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env))
-  return !StringTable::shared_string_mapped();
+  return !HeapShared::closed_archive_heap_region_mapped();
 WB_END
 
 WB_ENTRY(jobject, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass clazz))
--- a/src/java.base/share/classes/java/lang/Integer.java	Sat Nov 03 12:37:55 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Integer.java	Sat Nov 03 15:40:19 2018 -0400
@@ -992,6 +992,12 @@
      * During VM initialization, java.lang.Integer.IntegerCache.high property
      * may be set and saved in the private system properties in the
      * jdk.internal.misc.VM class.
+     *
+     * WARNING: The cache is archived with CDS and reloaded from the shared
+     * archive at runtime. The archived cache (Integer[]) and Integer objects
+     * reside in the closed archive heap regions. Care should be taken when
+     * changing the implementation and the cache array should not be assigned
+     * with new Integer object(s) after initialization.
      */
 
     private static class IntegerCache {