8179302: Pre-resolve constant pool string entries and cache resolved_reference arrays in CDS archive.
authorjiangli
Mon, 14 Aug 2017 14:32:17 -0400
changeset 46810 7dad333205cd
parent 46809 057f21a10f5f
child 46811 f4ded11e0f74
child 46812 0cffd1dd151d
child 46816 f64eb2bfb250
8179302: Pre-resolve constant pool string entries and cache resolved_reference arrays in CDS archive. 8185924: G1NoteEndOfConcMarkClosure::doHeapRegion() does not do remembered set cleanup work for archive region. Summary: Shared class' constant pool resolved_references array is cached. Reviewed-by: coleenp, iklam, tschatzl Contributed-by: jiangli.zhou@oracle.com, thomas.schatzl@oracle.com
hotspot/src/share/vm/classfile/stringTable.cpp
hotspot/src/share/vm/classfile/stringTable.hpp
hotspot/src/share/vm/gc/g1/g1Allocator.cpp
hotspot/src/share/vm/gc/g1/g1Allocator.hpp
hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp
hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp
hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp
hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp
hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp
hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp
hotspot/src/share/vm/gc/g1/heapRegion.cpp
hotspot/src/share/vm/gc/g1/heapRegion.hpp
hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp
hotspot/src/share/vm/gc/g1/heapRegionType.cpp
hotspot/src/share/vm/gc/g1/heapRegionType.hpp
hotspot/src/share/vm/gc/serial/markSweep.cpp
hotspot/src/share/vm/gc/serial/markSweep.hpp
hotspot/src/share/vm/gc/serial/markSweep.inline.hpp
hotspot/src/share/vm/gc/shared/space.hpp
hotspot/src/share/vm/memory/filemap.cpp
hotspot/src/share/vm/memory/filemap.hpp
hotspot/src/share/vm/memory/metaspace.cpp
hotspot/src/share/vm/memory/metaspaceShared.cpp
hotspot/src/share/vm/memory/metaspaceShared.hpp
hotspot/src/share/vm/memory/universe.cpp
hotspot/src/share/vm/oops/constantPool.cpp
hotspot/src/share/vm/oops/constantPool.hpp
hotspot/src/share/vm/oops/cpCache.cpp
hotspot/src/share/vm/oops/cpCache.hpp
hotspot/src/share/vm/oops/oop.cpp
hotspot/src/share/vm/oops/oop.hpp
hotspot/src/share/vm/oops/oop.inline.hpp
hotspot/src/share/vm/prims/whitebox.cpp
hotspot/src/share/vm/utilities/macros.hpp
--- a/hotspot/src/share/vm/classfile/stringTable.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -90,7 +90,7 @@
 
 // --------------------------------------------------------------------------
 StringTable* StringTable::_the_table = NULL;
-bool StringTable::_ignore_shared_strings = false;
+bool StringTable::_shared_string_mapped = false;
 bool StringTable::_needs_rehashing = false;
 
 volatile int StringTable::_parallel_claimed_idx = 0;
@@ -678,13 +678,30 @@
   }
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
 // Sharing
+oop StringTable::create_archived_string(oop s, Thread* THREAD) {
+  assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+
+  oop new_s = NULL;
+  typeArrayOop v = java_lang_String::value(s);
+  typeArrayOop new_v = (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
+  if (new_v == NULL) {
+    return NULL;
+  }
+  new_s = MetaspaceShared::archive_heap_object(s, THREAD);
+  if (new_s == NULL) {
+    return NULL;
+  }
+
+  // adjust the pointer to the 'value' field in the new String oop
+  java_lang_String::set_value_raw(new_s, new_v);
+  return new_s;
+}
+
 bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
                                      CompactStringTableWriter* writer) {
-#if INCLUDE_CDS && INCLUDE_ALL_GCS && defined(_LP64) && !defined(_WINDOWS)
-  assert(UseG1GC, "Only support G1 GC");
-  assert(UseCompressedOops && UseCompressedClassPointers,
-         "Only support UseCompressedOops and UseCompressedClassPointers enabled");
+  assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
 
   Thread* THREAD = Thread::current();
   G1CollectedHeap::heap()->begin_archive_alloc_range();
@@ -697,94 +714,54 @@
         continue;
       }
 
-      // allocate the new 'value' array first
-      typeArrayOop v = java_lang_String::value(s);
-      int v_len = v->size();
-      typeArrayOop new_v;
-      if (G1CollectedHeap::heap()->is_archive_alloc_too_large(v_len)) {
-        continue; // skip the current String. The 'value' array is too large to handle
-      } else {
-        new_v = (typeArrayOop)G1CollectedHeap::heap()->archive_mem_allocate(v_len);
-        if (new_v == NULL) {
-          return false; // allocation failed
-        }
-      }
-      // now allocate the new String object
-      int s_len = s->size();
-      oop new_s = (oop)G1CollectedHeap::heap()->archive_mem_allocate(s_len);
+      java_lang_String::set_hash(s, hash);
+      oop new_s = create_archived_string(s, THREAD);
       if (new_s == NULL) {
-        return false;
+        continue;
       }
 
-      s->identity_hash();
-      v->identity_hash();
-
-      // copy the objects' data
-      Copy::aligned_disjoint_words((HeapWord*)s, (HeapWord*)new_s, s_len);
-      Copy::aligned_disjoint_words((HeapWord*)v, (HeapWord*)new_v, v_len);
-
-      // adjust the pointer to the 'value' field in the new String oop. Also pre-compute and set the
-      // 'hash' field. That avoids "write" to the shared strings at runtime by the deduplication process.
-      java_lang_String::set_value_raw(new_s, new_v);
-      if (java_lang_String::hash(new_s) == 0) {
-        java_lang_String::set_hash(new_s, hash);
-      }
+      // set the archived string in bucket
+      bucket->set_literal(new_s);
 
       // add to the compact table
       writer->add(hash, new_s);
-
-      MetaspaceShared::relocate_klass_ptr(new_s);
-      MetaspaceShared::relocate_klass_ptr(new_v);
     }
   }
 
   G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
   assert(string_space->length() <= 2, "sanity");
-#endif
   return true;
 }
 
 void StringTable::write_to_archive(GrowableArray<MemRegion> *string_space) {
-#if INCLUDE_CDS
+  assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
+
   _shared_table.reset();
-  if (!(UseG1GC && UseCompressedOops && UseCompressedClassPointers)) {
-      log_info(cds)(
-        "Shared strings are excluded from the archive as UseG1GC, "
-        "UseCompressedOops and UseCompressedClassPointers are required."
-        "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
-        BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
-        BOOL_TO_STR(UseCompressedClassPointers));
-  } else {
-    int num_buckets = the_table()->number_of_entries() /
-                           SharedSymbolTableBucketSize;
-    // calculation of num_buckets can result in zero buckets, we need at least one
-    CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
-                                    &MetaspaceShared::stats()->string);
+  int num_buckets = the_table()->number_of_entries() /
+                         SharedSymbolTableBucketSize;
+  // calculation of num_buckets can result in zero buckets, we need at least one
+  CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
+                                  &MetaspaceShared::stats()->string);
 
-    // Copy the interned strings into the "string space" within the java heap
-    if (copy_shared_string(string_space, &writer)) {
-      writer.dump(&_shared_table);
-    }
+  // Copy the interned strings into the "string space" within the java heap
+  if (copy_shared_string(string_space, &writer)) {
+    writer.dump(&_shared_table);
   }
-#endif
 }
 
 void StringTable::serialize(SerializeClosure* soc) {
-#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
   _shared_table.set_type(CompactHashtable<oop, char>::_string_table);
   _shared_table.serialize(soc);
 
   if (soc->writing()) {
     _shared_table.reset(); // Sanity. Make sure we don't use the shared table at dump time
-  } else if (_ignore_shared_strings) {
+  } else if (!_shared_string_mapped) {
     _shared_table.reset();
   }
-#endif
 }
 
 void StringTable::shared_oops_do(OopClosure* f) {
-#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
   _shared_table.oops_do(f);
-#endif
 }
+#endif //INCLUDE_CDS_JAVA_HEAP
 
--- a/hotspot/src/share/vm/classfile/stringTable.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -43,7 +43,7 @@
 
   // Shared string table
   static CompactHashtable<oop, char> _shared_table;
-  static bool _ignore_shared_strings;
+  static bool _shared_string_mapped;
 
   // Set if one bucket is out of balance due to hash algorithm deficiency
   static bool _needs_rehashing;
@@ -157,13 +157,14 @@
   static int verify_and_compare_entries();
 
   // Sharing
-  static void ignore_shared_strings(bool v) { _ignore_shared_strings = v; }
-  static bool shared_string_ignored()       { return _ignore_shared_strings; }
-  static void shared_oops_do(OopClosure* f);
+  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 bool copy_shared_string(GrowableArray<MemRegion> *string_space,
-                                 CompactStringTableWriter* ch_table);
-  static void write_to_archive(GrowableArray<MemRegion> *string_space);
-  static void serialize(SerializeClosure* soc);
+                                 CompactStringTableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN_(false);
+  static oop  create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+  static void write_to_archive(GrowableArray<MemRegion> *string_space) NOT_CDS_JAVA_HEAP_RETURN;
+  static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
 
   // Rehash the symbol table if it gets out of balance
   static void rehash_table();
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -331,12 +331,13 @@
 }
 
 bool G1ArchiveAllocator::_archive_check_enabled = false;
-G1ArchiveRegionMap G1ArchiveAllocator::_archive_region_map;
+G1ArchiveRegionMap G1ArchiveAllocator::_closed_archive_region_map;
+G1ArchiveRegionMap G1ArchiveAllocator::_open_archive_region_map;
 
-G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h) {
+G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h, bool open) {
   // Create the archive allocator, and also enable archive object checking
   // in mark-sweep, since we will be creating archive regions.
-  G1ArchiveAllocator* result =  new G1ArchiveAllocator(g1h);
+  G1ArchiveAllocator* result =  new G1ArchiveAllocator(g1h, open);
   enable_archive_object_check();
   return result;
 }
@@ -350,7 +351,11 @@
     return false;
   }
   assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index());
-  hr->set_archive();
+  if (_open) {
+    hr->set_open_archive();
+  } else {
+    hr->set_closed_archive();
+  }
   _g1h->old_set_add(hr);
   _g1h->hr_printer()->alloc(hr);
   _allocated_regions.append(hr);
@@ -362,7 +367,7 @@
   _max = _bottom + HeapRegion::min_region_size_in_words();
 
   // Tell mark-sweep that objects in this region are not to be marked.
-  set_range_archive(MemRegion(_bottom, HeapRegion::GrainWords), true);
+  set_range_archive(MemRegion(_bottom, HeapRegion::GrainWords), _open);
 
   // Since we've modified the old set, call update_sizes.
   _g1h->g1mm()->update_sizes();
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -321,11 +321,19 @@
 };
 
 // G1ArchiveAllocator is used to allocate memory in archive
-// regions. Such regions are not modifiable by GC, being neither
-// scavenged nor compacted, or even marked in the object header.
-// They can contain no pointers to non-archive heap regions,
+// regions. Such regions are not scavenged nor compacted by GC.
+// There are two types of archive regions, which are
+// differ in the kind of references allowed for the contained objects:
+//
+// - 'Closed' archive region contain no references outside of other
+//   closed archive regions. The region is immutable by GC. GC does
+//   not mark object header in 'closed' archive region.
+// - An 'open' archive region allow references to any other regions,
+//   including closed archive, open archive and other java heap regions.
+//   GC can adjust pointers and mark object header in 'open' archive region.
 class G1ArchiveAllocator : public CHeapObj<mtGC> {
 protected:
+  bool _open; // Indicate if the region is 'open' archive.
   G1CollectedHeap* _g1h;
 
   // The current allocation region
@@ -347,7 +355,7 @@
   bool alloc_new_region();
 
 public:
-  G1ArchiveAllocator(G1CollectedHeap* g1h) :
+  G1ArchiveAllocator(G1CollectedHeap* g1h, bool open) :
     _g1h(g1h),
     _allocation_region(NULL),
     _allocated_regions((ResourceObj::set_allocation_type((address) &_allocated_regions,
@@ -356,13 +364,14 @@
     _summary_bytes_used(0),
     _bottom(NULL),
     _top(NULL),
-    _max(NULL) { }
+    _max(NULL),
+    _open(open) { }
 
   virtual ~G1ArchiveAllocator() {
     assert(_allocation_region == NULL, "_allocation_region not NULL");
   }
 
-  static G1ArchiveAllocator* create_allocator(G1CollectedHeap* g1h);
+  static G1ArchiveAllocator* create_allocator(G1CollectedHeap* g1h, bool open);
 
   // Allocate memory for an individual object.
   HeapWord* archive_mem_allocate(size_t word_size);
@@ -389,18 +398,26 @@
   static inline void enable_archive_object_check();
 
   // Set the regions containing the specified address range as archive/non-archive.
-  static inline void set_range_archive(MemRegion range, bool is_archive);
+  static inline void set_range_archive(MemRegion range, bool open);
 
+  // Check if the object is in closed archive
+  static inline bool is_closed_archive_object(oop object);
+  // Check if the object is in open archive
+  static inline bool is_open_archive_object(oop object);
+  // Check if the object is either in closed archive or open archive
   static inline bool is_archive_object(oop object);
 
 private:
   static bool _archive_check_enabled;
-  static G1ArchiveRegionMap  _archive_region_map;
+  static G1ArchiveRegionMap  _closed_archive_region_map;
+  static G1ArchiveRegionMap  _open_archive_region_map;
 
-  // Check if an object is in an archive region using the _archive_region_map.
-  static inline bool in_archive_range(oop object);
+  // Check if an object is in a closed archive region using the _closed_archive_region_map.
+  static inline bool in_closed_archive_range(oop object);
+  // Check if an object is in open archive region using the _open_archive_region_map.
+  static inline bool in_open_archive_range(oop object);
 
-  // Check if archive object checking is enabled, to avoid calling in_archive_range
+  // Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range
   // unnecessarily.
   static inline bool archive_check_enabled();
 };
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -55,37 +55,60 @@
   }
 }
 
-// Create the _archive_region_map which is used to identify archive objects.
+// Create the maps which is used to identify archive objects.
 inline void G1ArchiveAllocator::enable_archive_object_check() {
-  assert(!_archive_check_enabled, "archive range check already enabled");
+  if (_archive_check_enabled) {
+    return;
+  }
+
   _archive_check_enabled = true;
   size_t length = Universe::heap()->max_capacity();
-  _archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
-                                 (HeapWord*)Universe::heap()->base() + length,
-                                 HeapRegion::GrainBytes);
+  _closed_archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
+                                        (HeapWord*)Universe::heap()->base() + length,
+                                        HeapRegion::GrainBytes);
+  _open_archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
+                                      (HeapWord*)Universe::heap()->base() + length,
+                                      HeapRegion::GrainBytes);
 }
 
-// Set the regions containing the specified address range as archive/non-archive.
-inline void G1ArchiveAllocator::set_range_archive(MemRegion range, bool is_archive) {
+// Set the regions containing the specified address range as archive.
+inline void G1ArchiveAllocator::set_range_archive(MemRegion range, bool open) {
   assert(_archive_check_enabled, "archive range check not enabled");
-  _archive_region_map.set_by_address(range, is_archive);
+  if (open) {
+    _open_archive_region_map.set_by_address(range, true);
+  } else {
+    _closed_archive_region_map.set_by_address(range, true);
+  }
 }
 
-// Check if an object is in an archive region using the _archive_region_map.
-inline bool G1ArchiveAllocator::in_archive_range(oop object) {
-  // This is the out-of-line part of is_archive_object test, done separately
+// Check if an object is in a closed archive region using the _archive_region_map.
+inline bool G1ArchiveAllocator::in_closed_archive_range(oop object) {
+  // This is the out-of-line part of is_closed_archive_object test, done separately
   // to avoid additional performance impact when the check is not enabled.
-  return _archive_region_map.get_by_address((HeapWord*)object);
+  return _closed_archive_region_map.get_by_address((HeapWord*)object);
 }
 
-// Check if archive object checking is enabled, to avoid calling in_archive_range
+inline bool G1ArchiveAllocator::in_open_archive_range(oop object) {
+  return _open_archive_region_map.get_by_address((HeapWord*)object);
+}
+
+// Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range
 // unnecessarily.
 inline bool G1ArchiveAllocator::archive_check_enabled() {
   return _archive_check_enabled;
 }
 
+inline bool G1ArchiveAllocator::is_closed_archive_object(oop object) {
+  return (archive_check_enabled() && in_closed_archive_range(object));
+}
+
+inline bool G1ArchiveAllocator::is_open_archive_object(oop object) {
+  return (archive_check_enabled() && in_open_archive_range(object));
+}
+
 inline bool G1ArchiveAllocator::is_archive_object(oop object) {
-  return (archive_check_enabled() && in_archive_range(object));
+  return (archive_check_enabled() && (in_closed_archive_range(object) ||
+                                      in_open_archive_range(object)));
 }
 
 #endif // SHARE_VM_GC_G1_G1ALLOCATOR_HPP
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -614,10 +614,10 @@
   return NULL;
 }
 
-void G1CollectedHeap::begin_archive_alloc_range() {
+void G1CollectedHeap::begin_archive_alloc_range(bool open) {
   assert_at_safepoint(true /* should_be_vm_thread */);
   if (_archive_allocator == NULL) {
-    _archive_allocator = G1ArchiveAllocator::create_allocator(this);
+    _archive_allocator = G1ArchiveAllocator::create_allocator(this, open);
   }
 }
 
@@ -661,7 +661,9 @@
   return true;
 }
 
-bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
+bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges,
+                                            size_t count,
+                                            bool open) {
   assert(!is_init_completed(), "Expect to be called at JVM init time");
   assert(ranges != NULL, "MemRegion array NULL");
   assert(count != 0, "No MemRegions provided");
@@ -680,8 +682,8 @@
   G1ArchiveAllocator::enable_archive_object_check();
 
   // For each specified MemRegion range, allocate the corresponding G1
-  // regions and mark them as archive regions. We expect the ranges in
-  // ascending starting address order, without overlap.
+  // regions and mark them as archive regions. We expect the ranges
+  // in ascending starting address order, without overlap.
   for (size_t i = 0; i < count; i++) {
     MemRegion curr_range = ranges[i];
     HeapWord* start_address = curr_range.start();
@@ -726,8 +728,8 @@
 
     }
 
-    // Mark each G1 region touched by the range as archive, add it to the old set,
-    // and set the allocation context and top.
+    // Mark each G1 region touched by the range as archive, add it to
+    // the old set, and set the allocation context and top.
     HeapRegion* curr_region = _hrm.addr_to_region(start_address);
     HeapRegion* last_region = _hrm.addr_to_region(last_address);
     prev_last_region = last_region;
@@ -736,20 +738,30 @@
       assert(curr_region->is_empty() && !curr_region->is_pinned(),
              "Region already in use (index %u)", curr_region->hrm_index());
       curr_region->set_allocation_context(AllocationContext::system());
-      curr_region->set_archive();
+      if (open) {
+        curr_region->set_open_archive();
+      } else {
+        curr_region->set_closed_archive();
+      }
       _hr_printer.alloc(curr_region);
       _old_set.add(curr_region);
+      HeapWord* top;
+      HeapRegion* next_region;
       if (curr_region != last_region) {
-        curr_region->set_top(curr_region->end());
-        curr_region = _hrm.next_region_in_heap(curr_region);
+        top = curr_region->end();
+        next_region = _hrm.next_region_in_heap(curr_region);
       } else {
-        curr_region->set_top(last_address + 1);
-        curr_region = NULL;
+        top = last_address + 1;
+        next_region = NULL;
       }
+      curr_region->set_top(top);
+      curr_region->set_first_dead(top);
+      curr_region->set_end_of_live(top);
+      curr_region = next_region;
     }
 
-    // Notify mark-sweep of the archive range.
-    G1ArchiveAllocator::set_range_archive(curr_range, true);
+    // Notify mark-sweep of the archive
+    G1ArchiveAllocator::set_range_archive(curr_range, open);
   }
   return true;
 }
@@ -5223,12 +5235,8 @@
         // We ignore humongous regions. We left the humongous set unchanged.
       } else {
         assert(r->is_young() || r->is_free() || r->is_old(), "invariant");
-        // We now consider all regions old, so register as such. Leave
-        // archive regions set that way, however, while still adding
-        // them to the old set.
-        if (!r->is_archive()) {
-          r->set_old();
-        }
+        // We now move all (non-humongous, non-old) regions to old gen, and register them as such.
+        r->move_to_old();
         _old_set->add(r);
       }
       _total_used += r->used();
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -681,7 +681,7 @@
   // VM thread at safepoints, without the heap lock held. They can be used
   // to create and archive a set of heap regions which can be mapped at the
   // same fixed addresses in a subsequent JVM invocation.
-  void begin_archive_alloc_range();
+  void begin_archive_alloc_range(bool open = false);
 
   // Check if the requested size would be too large for an archive allocation.
   bool is_archive_alloc_too_large(size_t word_size);
@@ -706,7 +706,7 @@
   // Commit the appropriate G1 regions containing the specified MemRegions
   // and mark them as 'archive' regions. The regions in the array must be
   // non-overlapping and in order of ascending address.
-  bool alloc_archive_regions(MemRegion* range, size_t count);
+  bool alloc_archive_regions(MemRegion* range, size_t count, bool open);
 
   // Insert any required filler objects in the G1 regions around the specified
   // ranges to make the regions parseable. This must be called after
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1134,13 +1134,10 @@
   const uint humongous_regions_removed() { return _humongous_regions_removed; }
 
   bool doHeapRegion(HeapRegion *hr) {
-    if (hr->is_archive()) {
-      return false;
-    }
     _g1->reset_gc_time_stamps(hr);
     hr->note_end_of_marking();
 
-    if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) {
+    if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young() && !hr->is_archive()) {
       _freed_bytes += hr->used();
       hr->set_containing_set(NULL);
       if (hr->is_humongous()) {
--- a/hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,9 @@
     StartsHumongous,
     ContinuesHumongous,
     Old,
-    Archive,
+    Pinned,
+    OpenArchive,
+    ClosedArchive,
     G1HeapRegionTypeEndSentinel
   };
 
@@ -49,7 +51,9 @@
       case StartsHumongous:    return "Starts Humongous";
       case ContinuesHumongous: return "Continues Humongous";
       case Old:                return "Old";
-      case Archive:            return "Archive";
+      case Pinned:             return "Pinned";
+      case OpenArchive:        return "OpenArchive";
+      case ClosedArchive:      return "ClosedArchive";
       default: ShouldNotReachHere(); return NULL;
     }
   }
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -234,30 +234,63 @@
 };
 
 class VerifyArchiveOopClosure: public OopClosure {
+  HeapRegion* _hr;
 public:
-  VerifyArchiveOopClosure(HeapRegion *hr) { }
+  VerifyArchiveOopClosure(HeapRegion *hr)
+    : _hr(hr) { }
   void do_oop(narrowOop *p) { do_oop_work(p); }
   void do_oop(      oop *p) { do_oop_work(p); }
 
   template <class T> void do_oop_work(T *p) {
     oop obj = oopDesc::load_decode_heap_oop(p);
-    guarantee(obj == NULL || G1ArchiveAllocator::is_archive_object(obj),
-              "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
-              p2i(p), p2i(obj));
+
+    if (_hr->is_open_archive()) {
+      guarantee(obj == NULL || G1ArchiveAllocator::is_archive_object(obj),
+                "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
+                p2i(p), p2i(obj));
+    } else {
+      assert(_hr->is_closed_archive(), "should be closed archive region");
+      guarantee(obj == NULL || G1ArchiveAllocator::is_closed_archive_object(obj),
+                "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
+                p2i(p), p2i(obj));
+    }
   }
 };
 
-class VerifyArchiveRegionClosure: public ObjectClosure {
+class VerifyObjectInArchiveRegionClosure: public ObjectClosure {
+  HeapRegion* _hr;
 public:
-  VerifyArchiveRegionClosure(HeapRegion *hr) { }
+  VerifyObjectInArchiveRegionClosure(HeapRegion *hr, bool verbose)
+    : _hr(hr) { }
   // Verify that all object pointers are to archive regions.
   void do_object(oop o) {
-    VerifyArchiveOopClosure checkOop(NULL);
+    VerifyArchiveOopClosure checkOop(_hr);
     assert(o != NULL, "Should not be here for NULL oops");
     o->oop_iterate_no_header(&checkOop);
   }
 };
 
+// Should be only used at CDS dump time
+class VerifyArchivePointerRegionClosure: public HeapRegionClosure {
+private:
+  G1CollectedHeap* _g1h;
+public:
+  VerifyArchivePointerRegionClosure(G1CollectedHeap* g1h) { }
+  virtual bool doHeapRegion(HeapRegion* r) {
+   if (r->is_archive()) {
+      VerifyObjectInArchiveRegionClosure verify_oop_pointers(r, false);
+      r->object_iterate(&verify_oop_pointers);
+    }
+    return false;
+  }
+};
+
+void G1HeapVerifier::verify_archive_regions() {
+  G1CollectedHeap*  g1h = G1CollectedHeap::heap();
+  VerifyArchivePointerRegionClosure cl(NULL);
+  g1h->heap_region_iterate(&cl);
+}
+
 class VerifyRegionClosure: public HeapRegionClosure {
 private:
   bool             _par;
@@ -279,12 +312,15 @@
   bool doHeapRegion(HeapRegion* r) {
     // For archive regions, verify there are no heap pointers to
     // non-pinned regions. For all others, verify liveness info.
-    if (r->is_archive()) {
-      VerifyArchiveRegionClosure verify_oop_pointers(r);
+    if (r->is_closed_archive()) {
+      VerifyObjectInArchiveRegionClosure verify_oop_pointers(r, false);
       r->object_iterate(&verify_oop_pointers);
       return true;
-    }
-    if (!r->is_continues_humongous()) {
+    } else if (r->is_open_archive()) {
+      VerifyObjsInRegionClosure verify_open_archive_oop(r, _vo);
+      r->object_iterate(&verify_open_archive_oop);
+      return true;
+    } else if (!r->is_continues_humongous()) {
       bool failures = false;
       r->verify(_vo, &failures);
       if (failures) {
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -109,6 +109,8 @@
   void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
   void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
   void verify_dirty_young_regions() PRODUCT_RETURN;
+
+  static void verify_archive_regions();
 };
 
 #endif // SHARE_VM_GC_G1_G1HEAPVERIFIER_HPP
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -222,7 +222,7 @@
         // point all the oops to the new location
         MarkSweep::adjust_pointers(obj);
       }
-    } else if (!r->is_pinned()) {
+    } else if (!r->is_closed_archive()) {
       // This really ought to be "as_CompactibleSpace"...
       r->adjust_pointers();
     }
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -185,14 +185,25 @@
   _type.set_survivor();
 }
 
+void HeapRegion::move_to_old() {
+  if (_type.relabel_as_old()) {
+    report_region_type_change(G1HeapRegionTraceType::Old);
+  }
+}
+
 void HeapRegion::set_old() {
   report_region_type_change(G1HeapRegionTraceType::Old);
   _type.set_old();
 }
 
-void HeapRegion::set_archive() {
-  report_region_type_change(G1HeapRegionTraceType::Archive);
-  _type.set_archive();
+void HeapRegion::set_open_archive() {
+  report_region_type_change(G1HeapRegionTraceType::OpenArchive);
+  _type.set_open_archive();
+}
+
+void HeapRegion::set_closed_archive() {
+  report_region_type_change(G1HeapRegionTraceType::ClosedArchive);
+  _type.set_closed_archive();
 }
 
 void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -433,7 +433,9 @@
   // An archive region is a pinned region, also tagged as old, which
   // should not be marked during mark/sweep. This allows the address
   // space to be shared by JVM instances.
-  bool is_archive() const { return _type.is_archive(); }
+  bool is_archive()        const { return _type.is_archive(); }
+  bool is_open_archive()   const { return _type.is_open_archive(); }
+  bool is_closed_archive() const { return _type.is_closed_archive(); }
 
   // For a humongous region, region in which it starts.
   HeapRegion* humongous_start_region() const {
@@ -618,9 +620,11 @@
   void set_eden_pre_gc();
   void set_survivor();
 
+  void move_to_old();
   void set_old();
 
-  void set_archive();
+  void set_open_archive();
+  void set_closed_archive();
 
   // Determine if an object has been allocated since the last
   // mark performed by the collector. This returns true iff the object
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -117,7 +117,8 @@
   HeapWord* addr = (HeapWord*) obj;
 
   assert(addr < top(), "must be");
-  assert(!is_archive(), "Archive regions should not have references into interesting regions.");
+  assert(!is_closed_archive(),
+         "Closed archive regions should not have references into other regions");
   assert(!is_humongous(), "Humongous objects not handled here");
   bool obj_is_dead = is_obj_dead(obj, prev_bitmap);
 
@@ -162,7 +163,9 @@
 
 inline bool HeapRegion::is_obj_dead(const oop obj, const G1CMBitMap* const prev_bitmap) const {
   assert(is_in_reserved(obj), "Object " PTR_FORMAT " must be in region", p2i(obj));
-  return !obj_allocated_since_prev_marking(obj) && !prev_bitmap->is_marked((HeapWord*)obj);
+  return !obj_allocated_since_prev_marking(obj) &&
+         !prev_bitmap->is_marked((HeapWord*)obj) &&
+         !is_open_archive();
 }
 
 inline size_t HeapRegion::block_size(const HeapWord *addr) const {
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -34,7 +34,8 @@
     case StartsHumongousTag:
     case ContinuesHumongousTag:
     case OldTag:
-    case ArchiveTag:
+    case OpenArchiveTag:
+    case ClosedArchiveTag:
       return true;
     default:
       return false;
@@ -50,7 +51,8 @@
     case StartsHumongousTag:    return "HUMS";
     case ContinuesHumongousTag: return "HUMC";
     case OldTag:                return "OLD";
-    case ArchiveTag:            return "ARC";
+    case OpenArchiveTag:        return "OARC";
+    case ClosedArchiveTag:      return "CARC";
     default:
       ShouldNotReachHere();
       return NULL; // keep some compilers happy
@@ -66,7 +68,8 @@
     case StartsHumongousTag:    return "HS";
     case ContinuesHumongousTag: return "HC";
     case OldTag:                return "O";
-    case ArchiveTag:            return "A";
+    case OpenArchiveTag:        return "OA";
+    case ClosedArchiveTag:      return "CA";
     default:
       ShouldNotReachHere();
       return NULL; // keep some compilers happy
@@ -82,7 +85,8 @@
     case StartsHumongousTag:    return G1HeapRegionTraceType::StartsHumongous;
     case ContinuesHumongousTag: return G1HeapRegionTraceType::ContinuesHumongous;
     case OldTag:                return G1HeapRegionTraceType::Old;
-    case ArchiveTag:            return G1HeapRegionTraceType::Archive;
+    case OpenArchiveTag:        return G1HeapRegionTraceType::OpenArchive;
+    case ClosedArchiveTag:      return G1HeapRegionTraceType::ClosedArchive;
     default:
       ShouldNotReachHere();
       return G1HeapRegionTraceType::Free; // keep some compilers happy
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,20 +43,23 @@
   // future, we'll have to increase the size of the latter and hence
   // decrease the size of the former.
   //
-  // 0000 0 [ 0] Free
+  // 00000 0 [ 0] Free
   //
-  // 0001 0 [ 2] Young Mask
-  // 0001 0 [ 2] Eden
-  // 0001 1 [ 3] Survivor
+  // 00001 0 [ 2] Young Mask
+  // 00001 0 [ 2] Eden
+  // 00001 1 [ 3] Survivor
   //
-  // 0010 0 [ 4] Humongous Mask
-  // 0100 0 [ 8] Pinned Mask
-  // 0110 0 [12] Starts Humongous
-  // 0110 1 [13] Continues Humongous
+  // 00010 0 [ 4] Humongous Mask
+  // 00100 0 [ 8] Pinned Mask
+  // 00110 0 [12] Starts Humongous
+  // 00110 1 [13] Continues Humongous
   //
-  // 1000 0 [16] Old Mask
+  // 01000 0 [16] Old Mask
   //
-  // 1100 0 [24] Archive
+  // 10000 0 [32] Archive Mask
+  // 11100 0 [56] Open Archive
+  // 11100 1 [57] Closed Archive
+  //
   typedef enum {
     FreeTag               = 0,
 
@@ -72,7 +75,18 @@
     OldMask               = 16,
     OldTag                = OldMask,
 
-    ArchiveTag            = PinnedMask | OldMask
+    // Archive regions are regions with immutable content (i.e. not reclaimed, and
+    // not allocated into during regular operation). They differ in the kind of references
+    // allowed for the contained objects:
+    // - Closed archive regions form a separate self-contained (closed) object graph
+    // within the set of all of these regions. No references outside of closed
+    // archive regions are allowed.
+    // - Open archive regions have no restrictions on the references of their objects.
+    // Objects within these regions are allowed to have references to objects
+    // contained in any other kind of regions.
+    ArchiveMask           = 32,
+    OpenArchiveTag        = ArchiveMask | PinnedMask | OldMask,
+    ClosedArchiveTag      = ArchiveMask | PinnedMask | OldMask + 1
   } Tag;
 
   volatile Tag _tag;
@@ -115,7 +129,9 @@
   bool is_starts_humongous()    const { return get() == StartsHumongousTag;    }
   bool is_continues_humongous() const { return get() == ContinuesHumongousTag; }
 
-  bool is_archive() const { return get() == ArchiveTag; }
+  bool is_archive()        const { return (get() & ArchiveMask) != 0; }
+  bool is_open_archive()   const { return get() == OpenArchiveTag; }
+  bool is_closed_archive() const { return get() == ClosedArchiveTag; }
 
   // is_old regions may or may not also be pinned
   bool is_old() const { return (get() & OldMask) != 0; }
@@ -138,7 +154,27 @@
 
   void set_old() { set(OldTag); }
 
-  void set_archive() { set_from(ArchiveTag, FreeTag); }
+  // Change the current region type to be of an old region type if not already done so.
+  // Returns whether the region type has been changed or not.
+  bool relabel_as_old() {
+    //assert(!is_free(), "Should not try to move Free region");
+    assert(!is_humongous(), "Should not try to move Humongous region");
+    if (is_old()) {
+      return false;
+    }
+    if (is_eden()) {
+      set_from(OldTag, EdenTag);
+      return true;
+    } else if (is_free()) {
+      set_from(OldTag, FreeTag);
+      return true;
+    } else {
+      set_from(OldTag, SurvTag);
+      return true;
+    }
+  }
+  void set_open_archive()   { set_from(OpenArchiveTag, FreeTag); }
+  void set_closed_archive() { set_from(ClosedArchiveTag, FreeTag); }
 
   // Misc
 
--- a/hotspot/src/share/vm/gc/serial/markSweep.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -87,7 +87,7 @@
   if (!oopDesc::is_null(heap_oop)) {
     oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
     if (!obj->mark()->is_marked() &&
-        !is_archive_object(obj)) {
+        !is_closed_archive_object(obj)) {
       mark_object(obj);
       _marking_stack.push(obj);
     }
@@ -184,7 +184,7 @@
   if (!oopDesc::is_null(heap_oop)) {
     oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
     if (!obj->mark()->is_marked() &&
-        !is_archive_object(obj)) {
+        !is_closed_archive_object(obj)) {
       mark_object(obj);
       follow_object(obj);
     }
@@ -268,7 +268,7 @@
 
 MarkSweep::IsAliveClosure   MarkSweep::is_alive;
 
-bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked() || is_archive_object(p); }
+bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked() || is_closed_archive_object(p); }
 
 MarkSweep::KeepAliveClosure MarkSweep::keep_alive;
 
--- a/hotspot/src/share/vm/gc/serial/markSweep.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -134,6 +134,8 @@
   static void set_ref_processor(ReferenceProcessor* rp);
 
   // Archive Object handling
+  static inline bool is_closed_archive_object(oop object);
+  static inline bool is_open_archive_object(oop object);
   static inline bool is_archive_object(oop object);
 
   static STWGCTimer* gc_timer() { return _gc_timer; }
--- a/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_SERIAL_MARKSWEEP_INLINE_HPP
 
 #include "gc/serial/markSweep.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/universe.hpp"
 #include "oops/markOop.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -33,6 +34,22 @@
 #include "gc/g1/g1Allocator.inline.hpp"
 #endif // INCLUDE_ALL_GCS
 
+inline bool MarkSweep::is_closed_archive_object(oop object) {
+#if INCLUDE_ALL_GCS
+  return G1ArchiveAllocator::is_closed_archive_object(object);
+#else
+  return false;
+#endif
+}
+
+inline bool MarkSweep::is_open_archive_object(oop object) {
+#if INCLUDE_ALL_GCS
+  return G1ArchiveAllocator::is_open_archive_object(object);
+#else
+  return false;
+#endif
+}
+
 inline bool MarkSweep::is_archive_object(oop object) {
 #if INCLUDE_ALL_GCS
   return G1ArchiveAllocator::is_archive_object(object);
@@ -52,14 +69,24 @@
     assert(Universe::heap()->is_in(obj), "should be in heap");
 
     oop new_obj = oop(obj->mark()->decode_pointer());
-    assert(is_archive_object(obj) ||                  // no forwarding of archive objects
+
+    assert(is_archive_object(obj) ||             // no forwarding of archive objects
            new_obj != NULL ||                         // is forwarding ptr?
            obj->mark() == markOopDesc::prototype() || // not gc marked?
            (UseBiasedLocking && obj->mark()->has_bias_pattern()),
            // not gc marked?
            "should be forwarded");
+
+#ifndef PRODUCT
+    // open_archive objects are marked by GC. Their mark should
+    // not have forwarding ptr.
+    if (is_open_archive_object(obj)) {
+      assert(new_obj == NULL, "archive heap object has forwarding ptr");
+    }
+#endif
+
     if (new_obj != NULL) {
-      if (!is_archive_object(obj)) {
+      if (!is_closed_archive_object(obj)) {
         assert(Universe::heap()->is_in_reserved(new_obj),
               "should be in object space");
         oopDesc::encode_store_heap_oop_not_null(p, new_obj);
--- a/hotspot/src/share/vm/gc/shared/space.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/space.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -447,6 +447,9 @@
   // Return a size with adjustments as required of the space.
   virtual size_t adjust_object_size_v(size_t size) const { return size; }
 
+  void set_first_dead(HeapWord* value) { _first_dead = value; }
+  void set_end_of_live(HeapWord* value) { _end_of_live = value; }
+
 protected:
   // Used during compaction.
   HeapWord* _first_dead;
--- a/hotspot/src/share/vm/memory/filemap.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/filemap.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -351,7 +351,8 @@
   size_t len = lseek(fd, 0, SEEK_END);
   struct FileMapInfo::FileMapHeader::space_info* si =
     &_header->_space[MetaspaceShared::last_valid_region];
-  if (si->_file_offset >= len || len - si->_file_offset < si->_used) {
+  // The last space might be empty
+  if (si->_file_offset > len || len - si->_file_offset < si->_used) {
     fail_continue("The shared archive file has been truncated.");
     return false;
   }
@@ -443,7 +444,7 @@
   } else {
     si->_file_offset = _file_offset;
   }
-  if (MetaspaceShared::is_string_region(region)) {
+  if (MetaspaceShared::is_heap_region(region)) {
     assert((base - (char*)Universe::narrow_oop_base()) % HeapWordSize == 0, "Sanity");
     if (base != NULL) {
       si->_addr._offset = (intx)oopDesc::encode_heap_oop_not_null((oop)base);
@@ -460,76 +461,66 @@
   write_bytes_aligned(base, (int)size);
 }
 
-// Write the string space. The string space contains one or multiple GC(G1) regions.
-// When the total string space size is smaller than one GC region of the dump time,
-// only one string region is used for shared strings.
+// Write out the given archive heap memory regions.  GC code combines multiple
+// consecutive archive GC regions into one MemRegion whenever possible and
+// produces the 'heap_mem' array.
+//
+// If the archive heap memory size is smaller than a single dump time GC region
+// size, there is only one MemRegion in the array.
 //
-// If the total string space size is bigger than one GC region, there would be more
-// than one GC regions allocated for shared strings. The first/bottom GC region might
-// be a partial GC region with the empty portion at the higher address within that region.
-// The non-empty portion of the first region is written into the archive as one string
-// region. The rest are consecutive full GC regions if they exist, which can be written
-// out in one chunk as another string region.
+// If the archive heap memory size is bigger than one dump time GC region size,
+// the 'heap_mem' array may contain more than one consolidated MemRegions. When
+// the first/bottom archive GC region is a partial GC region (with the empty
+// portion at the higher address within the region), one MemRegion is used for
+// the bottom partial archive GC region. The rest of the consecutive archive
+// GC regions are combined into another MemRegion.
 //
-// Here's the mapping from (GrowableArray<MemRegion> *regions) -> (metaspace string regions).
-//   + We have 1 or more heap regions: r0, r1, r2 ..... rn
-//   + We have 2 metaspace string regions: s0 and s1
+// Here's the mapping from (archive heap GC regions) -> (GrowableArray<MemRegion> *regions).
+//   + We have 1 or more archive heap regions: ah0, ah1, ah2 ..... ahn
+//   + We have 1 or 2 consolidated heap memory regions: r0 and r1
 //
-// If there's a single heap region (r0), then s0 == r0, and s1 is empty.
+// If there's a single archive GC region (ah0), then r0 == ah0, and r1 is empty.
 // Otherwise:
 //
 // "X" represented space that's occupied by heap objects.
 // "_" represented unused spaced in the heap region.
 //
 //
-//    |r0        | r1  | r2 | ...... | rn |
+//    |ah0       | ah1 | ah2| ...... | ahn |
 //    |XXXXXX|__ |XXXXX|XXXX|XXXXXXXX|XXXX|
-//    |<-s0->|   |<- s1 ----------------->|
+//    |<-r0->|   |<- r1 ----------------->|
 //            ^^^
 //             |
-//             +-- unmapped space
-void FileMapInfo::write_string_regions(GrowableArray<MemRegion> *regions,
-                                       char** st0_start, char** st0_top, char** st0_end,
-                                       char** st1_start, char** st1_top, char** st1_end) {
-  *st0_start = *st0_top = *st0_end = NULL;
-  *st1_start = *st1_top = *st1_end = NULL;
+//             +-- gap
+size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+                                               int first_region_id, int max_num_regions) {
+  assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
 
-  assert(MetaspaceShared::max_strings == 2, "this loop doesn't work for any other value");
-  for (int i = MetaspaceShared::first_string;
-           i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+  int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
+  if(arr_len > max_num_regions) {
+    fail_stop("Unable to write archive heap memory regions: "
+              "number of memory regions exceeds maximum due to fragmentation");
+  }
+
+  size_t total_size = 0;
+  for (int i = first_region_id, arr_idx = 0;
+           i < first_region_id + max_num_regions;
+           i++, arr_idx++) {
     char* start = NULL;
     size_t size = 0;
-    int len = regions->length();
-    if (len > 0) {
-      if (i == MetaspaceShared::first_string) {
-        MemRegion first = regions->first();
-        start = (char*)first.start();
-        size = first.byte_size();
-        *st0_start = start;
-        *st0_top = start + size;
-        if (len > 1) {
-          *st0_end = (char*)regions->at(1).start();
-        } else {
-          *st0_end = start + size;
-        }
-      } else {
-        assert(i == MetaspaceShared::first_string + 1, "must be");
-        if (len > 1) {
-          start = (char*)regions->at(1).start();
-          size = (char*)regions->at(len - 1).end() - start;
-          *st1_start = start;
-          *st1_top = start + size;
-          *st1_end = start + size;
-        }
-      }
+    if (arr_idx < arr_len) {
+      start = (char*)heap_mem->at(arr_idx).start();
+      size = heap_mem->at(arr_idx).byte_size();
+      total_size += size;
     }
-    log_info(cds)("String region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
+
+    log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
                   i, p2i(start), p2i(start + size), size);
     write_region(i, start, size, false, false);
   }
+  return total_size;
 }
 
-
 // Dump bytes to file -- at the current file position.
 
 void FileMapInfo::write_bytes(const void* buffer, int nbytes) {
@@ -641,11 +632,11 @@
 }
 
 // Memory map a region in the address space.
-static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
-                                            "String1", "String2", "OptionalData" };
+static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
+                                            "String1", "String2", "OpenArchive1", "OpenArchive2" };
 
 char* FileMapInfo::map_region(int i) {
-  assert(!MetaspaceShared::is_string_region(i), "sanity");
+  assert(!MetaspaceShared::is_heap_region(i), "sanity");
   struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t alignment = os::vm_allocation_granularity();
@@ -675,101 +666,144 @@
 }
 
 static MemRegion *string_ranges = NULL;
-static int num_ranges = 0;
-bool FileMapInfo::map_string_regions() {
-#if INCLUDE_ALL_GCS
-  if (UseG1GC && UseCompressedOops && UseCompressedClassPointers) {
+static MemRegion *open_archive_heap_ranges = NULL;
+static int num_string_ranges = 0;
+static int num_open_archive_heap_ranges = 0;
+
+#if INCLUDE_CDS_JAVA_HEAP
+//
+// Map the shared string objects and open archive heap objects to the runtime
+// java heap.
+//
+// The shared strings are mapped near the runtime java heap top. The
+// mapped strings contain no out-going references to any other java heap
+// regions. GC does not write into the mapped shared strings.
+//
+// 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.
+// 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.
+void FileMapInfo::map_heap_regions() {
+  if (MetaspaceShared::is_heap_object_archiving_allowed()) {
     // Check that all the narrow oop and klass encodings match the archive
     if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
         narrow_oop_shift() != Universe::narrow_oop_shift() ||
         narrow_klass_base() != Universe::narrow_klass_base() ||
         narrow_klass_shift() != Universe::narrow_klass_shift()) {
       if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
-        log_info(cds)("Shared string data from the CDS archive is being ignored. "
+        log_info(cds)("Cached heap data from the CDS archive is being ignored. "
                       "The current CompressedOops/CompressedClassPointers encoding differs from "
                       "that archived due to heap size change. The archive was dumped using max heap "
                       "size " UINTX_FORMAT "M.", max_heap_size()/M);
       }
     } else {
-      string_ranges = new MemRegion[MetaspaceShared::max_strings];
-      struct FileMapInfo::FileMapHeader::space_info* si;
+      // 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();
 
-      for (int i = MetaspaceShared::first_string;
-               i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
-        si = &_header->_space[i];
-        size_t used = si->_used;
-        if (used > 0) {
-          size_t size = used;
-          char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
-                                                 (narrowOop)si->_addr._offset));
-          string_ranges[num_ranges] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
-          num_ranges ++;
+        // Now, map open_archive heap regions, GC can write into the regions.
+        if (map_heap_data(&open_archive_heap_ranges,
+                          MetaspaceShared::first_open_archive_heap_region,
+                          MetaspaceShared::max_open_archive_heap_region,
+                          &num_open_archive_heap_ranges,
+                          true /* open */)) {
+          MetaspaceShared::set_open_archive_heap_region_mapped();
         }
       }
-
-      if (num_ranges == 0) {
-        StringTable::ignore_shared_strings(true);
-        return true; // no shared string data
-      }
-
-      // Check that ranges are within the java heap
-      if (!G1CollectedHeap::heap()->check_archive_addresses(string_ranges, num_ranges)) {
-        fail_continue("Unable to allocate shared string space: range is not "
-                      "within java heap.");
-        return false;
-      }
-
-      // allocate from java heap
-      if (!G1CollectedHeap::heap()->alloc_archive_regions(string_ranges, num_ranges)) {
-        fail_continue("Unable to allocate shared string space: range is "
-                      "already in use.");
-        return false;
-      }
-
-      // Map the string data. No need to call MemTracker::record_virtual_memory_type()
-      // for mapped string regions as they are part of the reserved java heap, which
-      // is already recorded.
-      for (int i = 0; i < num_ranges; i++) {
-        si = &_header->_space[MetaspaceShared::first_string + i];
-        char* addr = (char*)string_ranges[i].start();
-        char* base = os::map_memory(_fd, _full_path, si->_file_offset,
-                                    addr, string_ranges[i].byte_size(), si->_read_only,
-                                    si->_allow_exec);
-        if (base == NULL || base != addr) {
-          // dealloc the string regions from java heap
-          dealloc_string_regions();
-          fail_continue("Unable to map shared string space at required address.");
-          return false;
-        }
-      }
-
-      if (!verify_string_regions()) {
-        // dealloc the string regions from java heap
-        dealloc_string_regions();
-        fail_continue("Shared string regions are corrupt");
-        return false;
-      }
-
-      // the shared string data is mapped successfully
-      return true;
     }
   } else {
     if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
-      log_info(cds)("Shared string data from the CDS archive is being ignored. UseG1GC, "
+      log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, "
                     "UseCompressedOops and UseCompressedClassPointers are required.");
     }
   }
 
-  // if we get here, the shared string data is not mapped
-  assert(string_ranges == NULL && num_ranges == 0, "sanity");
-  StringTable::ignore_shared_strings(true);
-#endif
+  if (!StringTable::shared_string_mapped()) {
+    assert(string_ranges == NULL && num_string_ranges == 0, "sanity");
+  }
+
+  if (!MetaspaceShared::open_archive_heap_region_mapped()) {
+    assert(open_archive_heap_ranges == NULL && num_open_archive_heap_ranges == 0, "sanity");
+  }
+}
+
+bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
+                                int max, int* num, bool is_open_archive) {
+  MemRegion * regions = new MemRegion[max];
+  struct FileMapInfo::FileMapHeader::space_info* si;
+  int region_num = 0;
+
+  for (int i = first;
+           i < first + max; i++) {
+    si = &_header->_space[i];
+    size_t used = si->_used;
+    if (used > 0) {
+      size_t size = used;
+      char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
+                                            (narrowOop)si->_addr._offset));
+      regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+      region_num ++;
+    }
+  }
+
+  if (region_num == 0) {
+    return false; // no archived java heap data
+  }
+
+  // Check that ranges are within the java heap
+  if (!G1CollectedHeap::heap()->check_archive_addresses(regions, region_num)) {
+    log_info(cds)("UseSharedSpaces: Unable to allocate region, "
+                  "range is not within java heap.");
+    return false;
+  }
+
+  // allocate from java heap
+  if (!G1CollectedHeap::heap()->alloc_archive_regions(
+             regions, region_num, is_open_archive)) {
+    log_info(cds)("UseSharedSpaces: Unable to allocate region, "
+                  "java heap range is already in use.");
+    return false;
+  }
+
+  // Map the archived heap data. No need to call MemTracker::record_virtual_memory_type()
+  // for mapped regions as they are part of the reserved java heap, which is
+  // already recorded.
+  for (int i = 0; i < region_num; i++) {
+    si = &_header->_space[first + i];
+    char* addr = (char*)regions[i].start();
+    char* base = os::map_memory(_fd, _full_path, si->_file_offset,
+                                addr, regions[i].byte_size(), si->_read_only,
+                                si->_allow_exec);
+    if (base == NULL || base != addr) {
+      // dealloc the regions from java heap
+      dealloc_archive_heap_regions(regions, region_num);
+      log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap.");
+      return false;
+    }
+  }
+
+  if (!verify_mapped_heap_regions(first, region_num)) {
+    // dealloc the regions from java heap
+    dealloc_archive_heap_regions(regions, region_num);
+    log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
+    return false;
+  }
+
+  // the shared heap data is mapped successfully
+  *heap_mem = regions;
+  *num = region_num;
   return true;
 }
 
-bool FileMapInfo::verify_string_regions() {
-  for (int i = MetaspaceShared::first_string;
-           i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
+  for (int i = first;
+           i <= first + num; i++) {
     if (!verify_region_checksum(i)) {
       return false;
     }
@@ -777,17 +811,31 @@
   return true;
 }
 
-void FileMapInfo::fixup_string_regions() {
-#if INCLUDE_ALL_GCS
+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_ranges != 0) {
+  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_ranges);
+    G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_string_ranges);
+  }
+
+  // do the same for mapped open archive heap regions
+  if (num_open_archive_heap_ranges != 0) {
+    assert(open_archive_heap_ranges != NULL, "NULL open_archive_heap_ranges array with non-zero count");
+    G1CollectedHeap::heap()->fill_archive_regions(open_archive_heap_ranges,
+                                                  num_open_archive_heap_ranges);
   }
-#endif
 }
 
+// dealloc the archive regions from java heap
+void FileMapInfo::dealloc_archive_heap_regions(MemRegion* regions, int num) {
+  if (num > 0) {
+    assert(regions != NULL, "Null archive ranges array with non-zero count");
+    G1CollectedHeap::heap()->dealloc_archive_regions(regions, num);
+  }
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
+
 bool FileMapInfo::verify_region_checksum(int i) {
   if (!VerifySharedSpaces) {
     return true;
@@ -798,8 +846,11 @@
   if (sz == 0) {
     return true; // no data
   }
-  if (MetaspaceShared::is_string_region(i) && StringTable::shared_string_ignored()) {
-    return true; // shared string data are not mapped
+  if ((MetaspaceShared::is_string_region(i) &&
+       !StringTable::shared_string_mapped()) ||
+      (MetaspaceShared::is_open_archive_heap_region(i) &&
+       !MetaspaceShared::open_archive_heap_region_mapped())) {
+    return true; // archived heap data is not mapped
   }
   const char* buf = _header->region_addr(i);
   int crc = ClassLoader::crc32(0, buf, (jint)sz);
@@ -813,7 +864,7 @@
 // Unmap a memory region in the address space.
 
 void FileMapInfo::unmap_region(int i) {
-  assert(!MetaspaceShared::is_string_region(i), "sanity");
+  assert(!MetaspaceShared::is_heap_region(i), "sanity");
   struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t size = align_up(used, os::vm_allocation_granularity());
@@ -828,16 +879,6 @@
   }
 }
 
-// dealloc the archived string region from java heap
-void FileMapInfo::dealloc_string_regions() {
-#if INCLUDE_ALL_GCS
-  if (num_ranges > 0) {
-    assert(string_ranges != NULL, "Null string_ranges array with non-zero count");
-    G1CollectedHeap::heap()->dealloc_archive_regions(string_ranges, num_ranges);
-  }
-#endif
-}
-
 void FileMapInfo::assert_mark(bool check) {
   if (!check) {
     fail_stop("Mark mismatch while restoring from shared file.");
@@ -883,9 +924,9 @@
 }
 
 char* FileMapInfo::FileMapHeader::region_addr(int idx) {
-  if (MetaspaceShared::is_string_region(idx)) {
-    return (char*)((void*)oopDesc::decode_heap_oop_not_null(
-              (narrowOop)_space[idx]._addr._offset));
+  if (MetaspaceShared::is_heap_region(idx)) {
+    return _space[idx]._used > 0 ?
+             (char*)((void*)oopDesc::decode_heap_oop_not_null((narrowOop)_space[idx]._addr._offset)) : NULL;
   } else {
     return _space[idx]._addr._base;
   }
@@ -965,15 +1006,15 @@
 }
 
 // The following method is provided to see whether a given pointer
-// falls in the mapped shared space.
+// falls in the mapped shared metadata space.
 // Param:
 // p, The given pointer
 // Return:
 // True if the p is within the mapped shared space, otherwise, false.
 bool FileMapInfo::is_in_shared_space(const void* p) {
-  for (int i = 0; i < MetaspaceShared::n_regions; i++) {
+  for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
     char *base;
-    if (MetaspaceShared::is_string_region(i) && _header->_space[i]._used == 0) {
+    if (_header->_space[i]._used == 0) {
       continue;
     }
     base = _header->region_addr(i);
@@ -985,7 +1026,7 @@
   return false;
 }
 
-// Check if a given address is within one of the shared regions ( ro, rw, mc or md)
+// Check if a given address is within one of the shared regions
 bool FileMapInfo::is_in_shared_region(const void* p, int idx) {
   assert(idx == MetaspaceShared::ro ||
          idx == MetaspaceShared::rw ||
@@ -1014,16 +1055,18 @@
   FileMapInfo *map_info = FileMapInfo::current_info();
   if (map_info) {
     map_info->fail_continue("%s", msg);
-    for (int i = 0; i < MetaspaceShared::num_non_strings; i++) {
+    for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
       char *addr = map_info->_header->region_addr(i);
-      if (addr != NULL && !MetaspaceShared::is_string_region(i)) {
+      if (addr != NULL && !MetaspaceShared::is_heap_region(i)) {
         map_info->unmap_region(i);
         map_info->_header->_space[i]._addr._base = NULL;
       }
     }
-    // Dealloc the string regions only without unmapping. The string regions are part
+    // Dealloc the archive heap regions only without unmapping. The regions are part
     // of the java heap. Unmapping of the heap regions are managed by GC.
-    map_info->dealloc_string_regions();
+    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);
   } else if (DumpSharedSpaces) {
     fail_stop("%s", msg);
   }
--- a/hotspot/src/share/vm/memory/filemap.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/filemap.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -242,17 +242,14 @@
   void  write_header();
   void  write_region(int region, char* base, size_t size,
                      bool read_only, bool allow_exec);
-  void  write_string_regions(GrowableArray<MemRegion> *regions,
-                             char** s0_start, char** s0_top, char** s0_end,
-                             char** s1_start, char** s1_top, char** s1_end);
+  size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+                                    int first_region_id, int max_num_regions);
   void  write_bytes(const void* buffer, int count);
   void  write_bytes_aligned(const void* buffer, int count);
   char* map_region(int i);
-  bool  map_string_regions();
-  bool  verify_string_regions();
-  void  fixup_string_regions();
+  void  map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
+  void  fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
   void  unmap_region(int i);
-  void  dealloc_string_regions();
   bool  verify_region_checksum(int i);
   void  close();
   bool  is_open() { return _file_open; }
@@ -294,6 +291,12 @@
   static int get_number_of_share_classpaths() {
     return _classpath_entry_table_size;
   }
+
+ private:
+  bool  map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
+                      bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
+  bool  verify_mapped_heap_regions(int first, int num) NOT_CDS_JAVA_HEAP_RETURN_(false);
+  void  dealloc_archive_heap_regions(MemRegion* regions, int num) NOT_CDS_JAVA_HEAP_RETURN;
 };
 
 #endif // SHARE_VM_MEMORY_FILEMAP_HPP
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -3347,9 +3347,9 @@
         // If UseCompressedClassPointers is set then allocate the metaspace area
         // above the heap and above the CDS area (if it exists).
         allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
-        // Map the shared string space after compressed pointers
-        // because it relies on compressed class pointers setting to work
-        mapinfo->map_string_regions();
+        // map_heap_regions() compares the current narrow oop and klass encodings
+        // with the archived ones, so it must be done after all encodings are determined.
+        mapinfo->map_heap_regions();
       }
 #endif // _LP64
     } else {
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -34,6 +34,11 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "code/codeCache.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1Allocator.inline.hpp"
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif
 #include "gc/shared/gcLocker.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/bytecodes.hpp"
@@ -68,21 +73,24 @@
 bool MetaspaceShared::_has_error_classes;
 bool MetaspaceShared::_archive_loading_failed = false;
 bool MetaspaceShared::_remapped_readwrite = false;
+bool MetaspaceShared::_open_archive_heap_region_mapped = false;
 address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
 size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
 size_t MetaspaceShared::_core_spaces_size = 0;
 
 // The CDS archive is divided into the following regions:
-//     mc - misc code (the method entry trampolines)
-//     rw - read-write metadata
-//     ro - read-only metadata and read-only tables
-//     md - misc data (the c++ vtables)
-//     od - optional data (original class files)
+//     mc  - misc code (the method entry trampolines)
+//     rw  - read-write metadata
+//     ro  - read-only metadata and read-only tables
+//     md  - misc data (the c++ vtables)
+//     od  - optional data (original class files)
 //
-//     s0 - shared strings #0
-//     s1 - shared strings #1 (may be empty)
+//     s0  - shared strings(closed archive heap space) #0
+//     s1  - shared strings(closed archive heap space) #1 (may be empty)
+//     oa0 - open archive heap space #0
+//     oa1 - open archive heap space #1 (may be empty)
 //
-// Except for the s0/s1 regions, the other 5 regions are linearly allocated, starting from
+// The mc, rw, ro, md and od regions are linearly allocated, starting from
 // SharedBaseAddress, in the order of mc->rw->ro->md->od. The size of these 5 regions
 // are page-aligned, and there's no gap between any consecutive regions.
 //
@@ -97,8 +105,8 @@
 // [5] C++ vtables are copied into the md region.
 // [6] Original class files are copied into the od region.
 //
-// The s0/s1 regions are populated inside MetaspaceShared::dump_string_and_symbols. Their
-// layout is independent of the other 5 regions.
+// The s0/s1 and oa0/oa1 regions are populated inside MetaspaceShared::dump_java_heap_objects.
+// Their layout is independent of the other 5 regions.
 
 class DumpRegion {
 private:
@@ -194,8 +202,9 @@
   }
 };
 
+
 DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
-DumpRegion _s0_region("s0"), _s1_region("s1");
+size_t _total_string_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);
@@ -856,10 +865,14 @@
 class VM_PopulateDumpSharedSpace: public VM_Operation {
 private:
   GrowableArray<MemRegion> *_string_regions;
+  GrowableArray<MemRegion> *_open_archive_heap_regions;
 
-  void dump_string_and_symbols();
+  void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
+  void dump_symbols();
   char* dump_read_only_tables();
   void print_region_stats();
+  void print_heap_region_stats(GrowableArray<MemRegion> *heap_mem,
+                               const char *name, const size_t total_size);
 public:
 
   VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
@@ -1072,9 +1085,8 @@
   }
 
   // We must relocate the System::_well_known_klasses only after we have copied the
-  // strings in during dump_string_and_symbols(): during the string copy, we operate on old
-  // String objects which assert that their klass is the old
-  // SystemDictionary::String_klass().
+  // java objects in during dump_java_heap_objects(): during the object copy, we operate on
+  // old objects which assert that their klass is the original klass.
   static void relocate_well_known_klasses() {
     {
       tty->print_cr("Relocating SystemDictionary::_well_known_klasses[] ... ");
@@ -1127,16 +1139,11 @@
   mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), read_only, allow_exec);
 }
 
-void VM_PopulateDumpSharedSpace::dump_string_and_symbols() {
-  tty->print_cr("Dumping string and symbol tables ...");
+void VM_PopulateDumpSharedSpace::dump_symbols() {
+  tty->print_cr("Dumping symbol table ...");
 
   NOT_PRODUCT(SymbolTable::verify());
-  NOT_PRODUCT(StringTable::verify());
   SymbolTable::write_to_archive();
-
-  // The string space has maximum two regions. See FileMapInfo::write_string_regions() for details.
-  _string_regions = new GrowableArray<MemRegion>(2);
-  StringTable::write_to_archive(_string_regions);
 }
 
 char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
@@ -1206,7 +1213,6 @@
     tty->print_cr("    type array classes = %5d", num_type_array);
   }
 
-
   // Ensure the ConstMethods won't be modified at run-time
   tty->print("Updating ConstMethods ... ");
   rewrite_nofast_bytecodes_and_calculate_fingerprints();
@@ -1220,7 +1226,13 @@
   ArchiveCompactor::initialize();
   ArchiveCompactor::copy_and_compact();
 
-  dump_string_and_symbols();
+  dump_symbols();
+
+  // Dump supported java heap objects
+  _string_regions = NULL;
+  _open_archive_heap_regions = NULL;
+  dump_java_heap_objects();
+
   ArchiveCompactor::relocate_well_known_klasses();
 
   char* read_only_tables_start = dump_read_only_tables();
@@ -1258,9 +1270,6 @@
   mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size());
   mapinfo->set_core_spaces_size(core_spaces_size);
 
-  char* s0_start, *s0_top, *s0_end;
-  char* s1_start, *s1_top, *s1_end;
-
   for (int pass=1; pass<=2; pass++) {
     if (pass == 1) {
       // The first pass doesn't actually write the data to disk. All it
@@ -1282,9 +1291,14 @@
     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);
 
-    mapinfo->write_string_regions(_string_regions,
-                                  &s0_start, &s0_top, &s0_end,
-                                  &s1_start, &s1_top, &s1_end);
+    _total_string_region_size = mapinfo->write_archive_heap_regions(
+                                        _string_regions,
+                                        MetaspaceShared::first_string,
+                                        MetaspaceShared::max_strings);
+    _total_open_archive_region_size = mapinfo->write_archive_heap_regions(
+                                        _open_archive_heap_regions,
+                                        MetaspaceShared::first_open_archive_heap_region,
+                                        MetaspaceShared::max_open_archive_heap_region);
   }
 
   mapinfo->close();
@@ -1292,8 +1306,6 @@
   // Restore the vtable in case we invoke any virtual methods.
   MetaspaceShared::clone_cpp_vtables((intptr_t*)vtbl_list);
 
-  _s0_region.init(s0_start, s0_top, s0_end);
-  _s1_region.init(s1_start, s1_top, s1_end);
   print_region_stats();
 
   if (log_is_enabled(Info, cds)) {
@@ -1304,14 +1316,16 @@
 
 void VM_PopulateDumpSharedSpace::print_region_stats() {
   // Print statistics of all the regions
-  const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
-                                _mc_region.reserved() + _md_region.reserved() +
-                                _od_region.reserved() +
-                                _s0_region.reserved() + _s1_region.reserved();
-  const size_t total_bytes = _ro_region.used() + _rw_region.used() +
-                             _mc_region.used() + _md_region.used() +
-                             _od_region.used() +
-                             _s0_region.used() + _s1_region.used();
+  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_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_open_archive_region_size;
   const double total_u_perc = total_bytes / double(total_reserved) * 100.0;
 
   _mc_region.print(total_reserved);
@@ -1319,13 +1333,25 @@
   _ro_region.print(total_reserved);
   _md_region.print(total_reserved);
   _od_region.print(total_reserved);
-  _s0_region.print(total_reserved);
-  _s1_region.print(total_reserved);
+  print_heap_region_stats(_string_regions, "st", 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]",
                  total_bytes, total_reserved, total_u_perc);
 }
 
+void VM_PopulateDumpSharedSpace::print_heap_region_stats(GrowableArray<MemRegion> *heap_mem,
+                                                         const char *name, const size_t total_size) {
+  int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
+  for (int i = 0; i < arr_len; i++) {
+      char* start = (char*)heap_mem->at(i).start();
+      size_t size = heap_mem->at(i).byte_size();
+      char* top = start + size;
+      tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100%% used] at " INTPTR_FORMAT,
+                    name, i, size, size/double(total_size)*100.0, size, p2i(start));
+
+  }
+}
 
 // Update a Java object to point its Klass* to the new location after
 // shared archive has been compacted.
@@ -1352,6 +1378,8 @@
       // to -Xverify setting.
       _made_progress |= MetaspaceShared::try_link_class(ik, THREAD);
       guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
+
+      ik->constants()->resolve_class_constants(THREAD);
     }
   }
 };
@@ -1556,6 +1584,98 @@
   }
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
+  if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+    if (log_is_enabled(Info, cds)) {
+      log_info(cds)(
+        "Archived java heap is not supported as UseG1GC, "
+        "UseCompressedOops and UseCompressedClassPointers are required."
+        "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
+        BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
+        BOOL_TO_STR(UseCompressedClassPointers));
+    }
+    return;
+  }
+
+  {
+    NoSafepointVerifier nsv;
+
+    // Cache for recording where the archived objects are copied to
+    MetaspaceShared::create_archive_object_cache();
+
+    tty->print_cr("Dumping String objects to closed archive heap region ...");
+    NOT_PRODUCT(StringTable::verify());
+    // The string space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
+    _string_regions = new GrowableArray<MemRegion>(2);
+    StringTable::write_to_archive(_string_regions);
+
+    tty->print_cr("Dumping objects to open archive heap region ...");
+    _open_archive_heap_regions = new GrowableArray<MemRegion>(2);
+    MetaspaceShared::dump_open_archive_heap_objects(_open_archive_heap_regions);
+  }
+
+  G1HeapVerifier::verify_archive_regions();
+}
+
+void MetaspaceShared::dump_open_archive_heap_objects(
+                                    GrowableArray<MemRegion> * open_archive) {
+  assert(UseG1GC, "Only support G1 GC");
+  assert(UseCompressedOops && UseCompressedClassPointers,
+         "Only support UseCompressedOops and UseCompressedClassPointers enabled");
+
+  Thread* THREAD = Thread::current();
+  G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */);
+
+  MetaspaceShared::archive_resolved_constants(THREAD);
+
+  G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
+                                                   os::vm_allocation_granularity());
+}
+
+MetaspaceShared::ArchivedObjectCache* MetaspaceShared::_archive_object_cache = NULL;
+oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
+  assert(DumpSharedSpaces, "dump-time only");
+
+  ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
+  oop* p = cache->get(obj);
+  if (p != NULL) {
+    // already archived
+    return *p;
+  }
+
+  int len = obj->size();
+  if (G1CollectedHeap::heap()->is_archive_alloc_too_large(len)) {
+    return NULL;
+  }
+
+  int hash = obj->identity_hash();
+  oop archived_oop = (oop)G1CollectedHeap::heap()->archive_mem_allocate(len);
+  if (archived_oop != NULL) {
+    Copy::aligned_disjoint_words((HeapWord*)obj, (HeapWord*)archived_oop, len);
+    relocate_klass_ptr(archived_oop);
+    cache->put(obj, archived_oop);
+  }
+  return archived_oop;
+}
+
+void MetaspaceShared::archive_resolved_constants(Thread* THREAD) {
+  int i;
+  for (i = 0; i < _global_klass_objects->length(); i++) {
+    Klass* k = _global_klass_objects->at(i);
+    if (k->is_instance_klass()) {
+      InstanceKlass* ik = InstanceKlass::cast(k);
+      ik->constants()->archive_resolved_references(THREAD);
+    }
+  }
+}
+
+void MetaspaceShared::fixup_mapped_heap_regions() {
+  FileMapInfo *mapinfo = FileMapInfo::current_info();
+  mapinfo->fixup_mapped_heap_regions();
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
+
 // Closure for serializing initialization data in from a data area
 // (ptr_array) read from the shared file.
 
@@ -1743,11 +1863,6 @@
   }
 }
 
-void MetaspaceShared::fixup_shared_string_regions() {
-  FileMapInfo *mapinfo = FileMapInfo::current_info();
-  mapinfo->fixup_string_regions();
-}
-
 // JVM/TI RedefineClasses() support:
 bool MetaspaceShared::remap_shared_readonly_as_readwrite() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -31,6 +31,7 @@
 #include "memory/virtualspace.hpp"
 #include "utilities/exceptions.hpp"
 #include "utilities/macros.hpp"
+#include "utilities/resourceHash.hpp"
 
 #define MAX_SHARED_DELTA                (0x7FFFFFFF)
 
@@ -56,23 +57,32 @@
   static bool _has_error_classes;
   static bool _archive_loading_failed;
   static bool _remapped_readwrite;
+  static bool _open_archive_heap_region_mapped;
   static address _cds_i2i_entry_code_buffers;
   static size_t  _cds_i2i_entry_code_buffers_size;
   static size_t  _core_spaces_size;
  public:
   enum {
+    // core archive spaces
     mc = 0,  // miscellaneous code for method trampolines
     rw = 1,  // read-write shared space in the heap
     ro = 2,  // read-only shared space in the heap
     md = 3,  // miscellaneous data for initializing tables, etc.
+    num_core_spaces = 4, // number of non-string regions
+
+    // optional mapped spaces
+    // Currently it only contains class file data.
+    od = num_core_spaces,
+    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
-    num_non_strings = 4, // number of non-string regions
-    first_string = num_non_strings, // index of first string region
-    // The optional data region is the last region.
-    // Currently it only contains class file data.
-    od = max_strings + num_non_strings,
-    last_valid_region = od,
-    n_regions = od + 1 // total number of regions
+    first_open_archive_heap_region = first_string + max_strings,
+    max_open_archive_heap_region = 2,
+
+    last_valid_region = first_open_archive_heap_region + max_open_archive_heap_region - 1,
+    n_regions =  last_valid_region + 1 // total number of regions
   };
 
   static void prepare_for_dumping() NOT_CDS_RETURN;
@@ -80,6 +90,45 @@
   static int preload_classes(const char * class_list_path,
                              TRAPS) NOT_CDS_RETURN_(0);
 
+#if INCLUDE_CDS_JAVA_HEAP
+ private:
+  static bool obj_equals(oop const& p1, oop const& p2) {
+    return p1 == p2;
+  }
+  static unsigned obj_hash(oop const& p) {
+    unsigned hash = (unsigned)((uintptr_t)&p);
+    return hash ^ (hash >> LogMinObjAlignment);
+  }
+  typedef ResourceHashtable<oop, oop,
+      MetaspaceShared::obj_hash, MetaspaceShared::obj_equals> ArchivedObjectCache;
+  static ArchivedObjectCache* _archive_object_cache;
+
+ public:
+  static ArchivedObjectCache* archive_object_cache() {
+    return _archive_object_cache;
+  }
+  static oop archive_heap_object(oop obj, Thread* THREAD);
+  static void archive_resolved_constants(Thread* THREAD);
+#endif
+  static bool is_heap_object_archiving_allowed() {
+    CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);)
+    NOT_CDS_JAVA_HEAP(return false;)
+  }
+  static void create_archive_object_cache() {
+    CDS_JAVA_HEAP_ONLY(_archive_object_cache = new ArchivedObjectCache(););
+  }
+  static void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
+
+  static void dump_open_archive_heap_objects(GrowableArray<MemRegion> * open_archive) NOT_CDS_JAVA_HEAP_RETURN;
+  static void set_open_archive_heap_region_mapped() {
+    CDS_JAVA_HEAP_ONLY(_open_archive_heap_region_mapped = true);
+    NOT_CDS_JAVA_HEAP_RETURN;
+  }
+  static bool open_archive_heap_region_mapped() {
+    CDS_JAVA_HEAP_ONLY(return _open_archive_heap_region_mapped);
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+
   static ReservedSpace* shared_rs() {
     CDS_ONLY(return &_shared_rs);
     NOT_CDS(return NULL);
@@ -104,16 +153,29 @@
   }
   static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false);
   static void initialize_shared_spaces() NOT_CDS_RETURN;
-  static void fixup_shared_string_regions() NOT_CDS_RETURN;
 
   // Return true if given address is in the mapped shared space.
   static bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
 
   // 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_ONLY(return (idx >= first_string && idx < first_string + max_strings));
-      NOT_CDS(return false);
+    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);
 
@@ -124,7 +186,6 @@
   static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
   static void serialize(SerializeClosure* sc);
 
-
   static MetaspaceSharedStats* stats() {
     return &_stats;
   }
--- a/hotspot/src/share/vm/memory/universe.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/universe.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -370,7 +370,7 @@
              SystemDictionary::Cloneable_klass(), "u3");
       assert(_the_array_interfaces_array->at(1) ==
              SystemDictionary::Serializable_klass(), "u3");
-      MetaspaceShared::fixup_shared_string_regions();
+      MetaspaceShared::fixup_mapped_heap_regions();
     } else
 #endif
     {
--- a/hotspot/src/share/vm/oops/constantPool.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -33,6 +33,7 @@
 #include "memory/heapInspection.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceClosure.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/constantPool.hpp"
@@ -47,6 +48,9 @@
 #include "runtime/signature.hpp"
 #include "runtime/vframe.hpp"
 #include "utilities/copy.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif // INCLUDE_ALL_GCS
 
 ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
   Array<u1>* tags = MetadataFactory::new_array<u1>(loader_data, length, 0, CHECK_NULL);
@@ -238,11 +242,53 @@
   release_tag_at_put(class_index, JVM_CONSTANT_Class);
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+// Archive the resolved references
+void ConstantPool::archive_resolved_references(Thread* THREAD) {
+  if (_cache == NULL) {
+    return; // nothing to do
+  }
+
+  InstanceKlass *ik = pool_holder();
+  if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
+        ik->is_shared_app_class())) {
+    // Archiving resolved references for classes from non-builtin loaders
+    // is not yet supported.
+    set_resolved_references(NULL);
+    return;
+  }
+
+  objArrayOop rr = resolved_references();
+  if (rr != NULL) {
+    for (int i = 0; i < rr->length(); i++) {
+      oop p = rr->obj_at(i);
+      if (p != NULL) {
+        int index = object_to_cp_index(i);
+        if (tag_at(index).is_string()) {
+          oop op = StringTable::create_archived_string(p, THREAD);
+          // If the String object is not archived (possibly too large),
+          // NULL is returned. Also set it in the array, so we won't
+          // have a 'bad' reference in the archived resolved_reference
+          // array.
+          rr->obj_at_put(i, op);
+        } else {
+          rr->obj_at_put(i, NULL);
+        }
+      }
+    }
+    oop archived = MetaspaceShared::archive_heap_object(rr, THREAD);
+    _cache->set_archived_references(archived);
+    set_resolved_references(NULL);
+  }
+}
+#endif
+
 // CDS support. Create a new resolved_references array.
 void ConstantPool::restore_unshareable_info(TRAPS) {
   assert(is_constantPool(), "ensure C++ vtable is restored");
   assert(on_stack(), "should always be set for shared constant pools");
   assert(is_shared(), "should always be set for shared constant pools");
+  assert(_cache != NULL, "constant pool _cache should not be NULL");
 
   // Only create the new resolved references array if it hasn't been attempted before
   if (resolved_references() != NULL) return;
@@ -251,14 +297,30 @@
   restore_vtable();
 
   if (SystemDictionary::Object_klass_loaded()) {
-    // Recreate the object array and add to ClassLoaderData.
-    int map_length = resolved_reference_length();
-    if (map_length > 0) {
-      objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
-      Handle refs_handle (THREAD, (oop)stom);  // must handleize.
-
-      ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+    ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+#if INCLUDE_CDS_JAVA_HEAP
+    if (MetaspaceShared::open_archive_heap_region_mapped() &&
+        _cache->archived_references() != NULL) {
+      oop archived = _cache->archived_references();
+      // Make sure GC knows the cached object is now live. This is necessary after
+      // initial GC marking and during concurrent marking as strong roots are only
+      // scanned during initial marking (at the start of the GC marking).
+      assert(UseG1GC, "Requires G1 GC");
+      G1SATBCardTableModRefBS::enqueue(archived);
+      // Create handle for the archived resolved reference array object
+      Handle refs_handle(THREAD, (oop)archived);
       set_resolved_references(loader_data->add_handle(refs_handle));
+    } else
+#endif
+    {
+      // No mapped archived resolved reference array
+      // Recreate the object array and add to ClassLoaderData.
+      int map_length = resolved_reference_length();
+      if (map_length > 0) {
+        objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
+        Handle refs_handle(THREAD, (oop)stom);  // must handleize.
+        set_resolved_references(loader_data->add_handle(refs_handle));
+      }
     }
   }
 }
@@ -266,10 +328,18 @@
 void ConstantPool::remove_unshareable_info() {
   // Resolved references are not in the shared archive.
   // Save the length for restoration.  It is not necessarily the same length
-  // as reference_map.length() if invokedynamic is saved.
+  // as reference_map.length() if invokedynamic is saved. It is needed when
+  // re-creating the resolved reference array if archived heap data cannot be map
+  // at runtime.
   set_resolved_reference_length(
     resolved_references() != NULL ? resolved_references()->length() : 0);
-  set_resolved_references(NULL);
+
+  // If archiving heap objects is not allowed, clear the resolved references.
+  // Otherwise, it is cleared after the resolved references array is cached
+  // (see archive_resolved_references()).
+  if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+    set_resolved_references(NULL);
+  }
 
   // Shared ConstantPools are in the RO region, so the _flags cannot be modified.
   // The _on_stack flag is used to prevent ConstantPools from deallocation during
@@ -619,19 +689,19 @@
   }
 }
 
-// Resolve all the classes in the constant pool.  If they are all resolved,
-// the constant pool is read-only.  Enhancement: allocate cp entries to
-// another metaspace, and copy to read-only or read-write space if this
-// bit is set.
 bool ConstantPool::resolve_class_constants(TRAPS) {
   constantPoolHandle cp(THREAD, this);
   for (int index = 1; index < length(); index++) { // Index 0 is unused
-    if (tag_at(index).is_unresolved_klass() &&
-        klass_at_if_loaded(cp, index) == NULL) {
-      return false;
+    if (tag_at(index).is_string()) {
+      Symbol* sym = cp->unresolved_string_at(index);
+      // Look up only. Only resolve references to already interned strings.
+      oop str = StringTable::lookup(sym);
+      if (str != NULL) {
+        int cache_index = cp->cp_to_object_index(index);
+        cp->string_at_put(index, cache_index, str);
+      }
+    }
   }
-  }
-  // set_preresolution(); or some bit for future use
   return true;
 }
 
--- a/hotspot/src/share/vm/oops/constantPool.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -714,6 +714,7 @@
   }
 
   // CDS support
+  void archive_resolved_references(Thread *THREAD) NOT_CDS_JAVA_HEAP_RETURN;
   void remove_unshareable_info();
   void restore_unshareable_info(TRAPS);
   bool resolve_class_constants(TRAPS);
--- a/hotspot/src/share/vm/oops/cpCache.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/cpCache.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -608,6 +608,18 @@
   }
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+oop ConstantPoolCache::archived_references() {
+  assert(UseSharedSpaces, "UseSharedSpaces expected.");
+  return oopDesc::decode_heap_oop(_archived_references);
+}
+
+void ConstantPoolCache::set_archived_references(oop o) {
+  assert(DumpSharedSpaces, "called only during runtime");
+  _archived_references = oopDesc::encode_heap_oop(o);
+}
+#endif
+
 #if INCLUDE_JVMTI
 // RedefineClasses() API support:
 // If any entry of this ConstantPoolCache points to any of
--- a/hotspot/src/share/vm/oops/cpCache.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/cpCache.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -415,6 +415,9 @@
   // object index to original constant pool index
   jobject              _resolved_references;
   Array<u2>*           _reference_map;
+  // The narrowOop pointer to the archived resolved_references. Set at CDS dump
+  // time when caching java heap object is supported.
+  CDS_JAVA_HEAP_ONLY(narrowOop _archived_references;)
 
   // Sizing
   debug_only(friend class ClassVerifier;)
@@ -426,6 +429,7 @@
                     const intStack& invokedynamic_references_map) :
                           _length(length),
                           _constant_pool(NULL) {
+    CDS_JAVA_HEAP_ONLY(_archived_references = 0;)
     initialize(inverse_index_map, invokedynamic_inverse_index_map,
                invokedynamic_references_map);
     for (int i = 0; i < length; i++) {
@@ -444,9 +448,12 @@
                                      const intStack& invokedynamic_references_map, TRAPS);
   bool is_constantPoolCache() const { return true; }
 
-  int length() const                             { return _length; }
+  int length() const                      { return _length; }
   void metaspace_pointers_do(MetaspaceClosure* it);
-  MetaspaceObj::Type type() const                { return ConstantPoolCacheType; }
+  MetaspaceObj::Type type() const         { return ConstantPoolCacheType; }
+
+  oop  archived_references() NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+  void set_archived_references(oop o) NOT_CDS_JAVA_HEAP_RETURN;
 
   jobject resolved_references()           { return _resolved_references; }
   void set_resolved_references(jobject s) { _resolved_references = s; }
--- a/hotspot/src/share/vm/oops/oop.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -31,6 +31,9 @@
 #include "runtime/handles.inline.hpp"
 #include "runtime/thread.inline.hpp"
 #include "utilities/copy.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1Allocator.inline.hpp"
+#endif
 
 bool always_do_update_barrier = false;
 
@@ -138,3 +141,9 @@
   // Only has a klass gap when compressed class pointers are used.
   return UseCompressedClassPointers;
 }
+
+#if INCLUDE_CDS_JAVA_HEAP
+bool oopDesc::is_archive_object(oop p) {
+  return (p == NULL) ? false : G1ArchiveAllocator::is_archive_object(p);
+}
+#endif
--- a/hotspot/src/share/vm/oops/oop.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -389,6 +389,8 @@
     assert(has_klass_gap(), "only applicable to compressed klass pointers");
     return klass_offset_in_bytes() + sizeof(narrowKlass);
   }
+
+  static bool is_archive_object(oop p) NOT_CDS_JAVA_HEAP_RETURN_(false);
 };
 
 #endif // SHARE_VM_OOPS_OOP_HPP
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -590,6 +590,9 @@
          "forwarding to something not aligned");
   assert(Universe::heap()->is_in_reserved(p),
          "forwarding to something not in heap");
+  assert(!is_archive_object(oop(this)) &&
+         !is_archive_object(p),
+         "forwarding archive object");
   markOop m = markOopDesc::encode_pointer_as_mark(p);
   assert(m->decode_pointer() == p, "encoding must be reversable");
   set_mark(m);
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Mon Aug 14 14:32:17 2017 -0400
@@ -1689,7 +1689,7 @@
 
 WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj))
   oop obj_oop = JNIHandles::resolve(obj);
-  return MetaspaceShared::is_in_shared_space((void*)obj_oop);
+  return oopDesc::is_archive_object(obj_oop);
 WB_END
 
 WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz))
@@ -1697,7 +1697,19 @@
 WB_END
 
 WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env))
-  return StringTable::shared_string_ignored();
+  return !StringTable::shared_string_mapped();
+WB_END
+
+WB_ENTRY(jobject, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass clazz))
+  Klass *k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));
+  if (k->is_instance_klass()) {
+    InstanceKlass *ik = InstanceKlass::cast(k);
+    ConstantPool *cp = ik->constants();
+    objArrayOop refs =  cp->resolved_references();
+    return (jobject)JNIHandles::make_local(env, refs);
+  } else {
+    return NULL;
+  }
 WB_END
 
 WB_ENTRY(jboolean, WB_IsCDSIncludedInVmBuild(JNIEnv* env))
@@ -2001,6 +2013,7 @@
   {CC"isShared",           CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared },
   {CC"isSharedClass",      CC"(Ljava/lang/Class;)Z",  (void*)&WB_IsSharedClass },
   {CC"areSharedStringsIgnored",           CC"()Z",    (void*)&WB_AreSharedStringsIgnored },
+  {CC"getResolvedReferences", CC"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)&WB_GetResolvedReferences},
   {CC"isCDSIncludedInVmBuild",            CC"()Z",    (void*)&WB_IsCDSIncludedInVmBuild },
   {CC"clearInlineCaches0",  CC"(Z)V",                 (void*)&WB_ClearInlineCaches },
   {CC"addCompilerDirective",    CC"(Ljava/lang/String;)I",
--- a/hotspot/src/share/vm/utilities/macros.hpp	Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/utilities/macros.hpp	Mon Aug 14 14:32:17 2017 -0400
@@ -536,4 +536,18 @@
     non_atomic_decl
 #endif
 
+#if INCLUDE_CDS && INCLUDE_ALL_GCS && defined(_LP64) && !defined(_WINDOWS)
+#define INCLUDE_CDS_JAVA_HEAP 1
+#define CDS_JAVA_HEAP_ONLY(x) x
+#define NOT_CDS_JAVA_HEAP(x)
+#define NOT_CDS_JAVA_HEAP_RETURN
+#define NOT_CDS_JAVA_HEAP_RETURN_(code)
+#else
+#define INCLUDE_CDS_JAVA_HEAP 0
+#define CDS_JAVA_HEAP_ONLY(x)
+#define NOT_CDS_JAVA_HEAP(x) x
+#define NOT_CDS_JAVA_HEAP_RETURN        {}
+#define NOT_CDS_JAVA_HEAP_RETURN_(code) { return code; }
+#endif
+
 #endif // SHARE_VM_UTILITIES_MACROS_HPP