8208658: Make CDS archived heap regions usable even if compressed oop encoding has changed
authoriklam
Tue, 14 Aug 2018 09:59:37 -0700
changeset 51491 187c84a5efe1
parent 51490 25048be67f4a
child 51492 fc80fa0ecac8
8208658: Make CDS archived heap regions usable even if compressed oop encoding has changed Summary: Relocate and patch archive regions if necessary Reviewed-by: jiangli, tschatzl
src/hotspot/share/classfile/compactHashtable.cpp
src/hotspot/share/classfile/compactHashtable.inline.hpp
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp
src/hotspot/share/include/cds.h
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/filemap.hpp
src/hotspot/share/memory/heapShared.cpp
src/hotspot/share/memory/heapShared.hpp
src/hotspot/share/memory/heapShared.inline.hpp
src/hotspot/share/memory/metaspaceShared.cpp
src/hotspot/share/memory/metaspaceShared.hpp
src/hotspot/share/memory/universe.cpp
src/hotspot/share/oops/cpCache.cpp
src/hotspot/share/oops/instanceMirrorKlass.cpp
src/hotspot/share/oops/instanceMirrorKlass.hpp
src/hotspot/share/oops/klass.cpp
src/hotspot/share/oops/klass.hpp
src/hotspot/share/runtime/arguments.cpp
src/hotspot/share/utilities/bitMap.cpp
src/hotspot/share/utilities/bitMap.hpp
test/hotspot/jtreg/runtime/appcds/cacheObject/DifferentHeapSizes.java
test/hotspot/jtreg/runtime/appcds/cacheObject/RangeNotWithinHeap.java
test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java
test/lib/jdk/test/lib/cds/CDSTestUtils.java
--- a/src/hotspot/share/classfile/compactHashtable.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -27,6 +27,7 @@
 #include "classfile/compactHashtable.inline.hpp"
 #include "classfile/javaClasses.hpp"
 #include "logging/logMessage.hpp"
+#include "memory/heapShared.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "oops/compressedOops.inline.hpp"
@@ -280,8 +281,9 @@
 public:
   CompactHashtable_OopIterator(OopClosure *cl) : _closure(cl) {}
   inline void do_value(address base_address, u4 offset) const {
-    narrowOop o = (narrowOop)offset;
-    _closure->do_oop(&o);
+    narrowOop v = (narrowOop)offset;
+    oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
+    _closure->do_oop(&obj);
   }
 };
 
--- a/src/hotspot/share/classfile/compactHashtable.inline.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.inline.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -28,7 +28,8 @@
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "memory/allocation.inline.hpp"
-#include "oops/compressedOops.inline.hpp"
+#include "memory/filemap.hpp"
+#include "memory/heapShared.inline.hpp"
 #include "oops/oop.hpp"
 
 template <class T, class N>
@@ -46,8 +47,8 @@
 template <class T, class N>
 inline oop CompactHashtable<T, N>::decode_entry(CompactHashtable<oop, char>* const t,
                                                 u4 offset, const char* name, int len) {
-  narrowOop obj = (narrowOop)offset;
-  oop string = CompressedOops::decode(obj);
+  narrowOop v = (narrowOop)offset;
+  oop string = HeapShared::decode_with_archived_oop_encoding_mode(v);
   if (java_lang_String::equals(string, (jchar*)name, len)) {
     return string;
   }
--- a/src/hotspot/share/classfile/javaClasses.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -1213,7 +1213,7 @@
 bool java_lang_Class::restore_archived_mirror(Klass *k,
                                               Handle class_loader, Handle module,
                                               Handle protection_domain, TRAPS) {
-  oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw());
+  oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
 
   if (m == NULL) {
     return false;
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -59,8 +59,8 @@
  public:
   StringDedupSharedClosure(StringDedupStat* stat) : _stat(stat) {}
 
-  virtual void do_oop(oop* p) { ShouldNotReachHere(); }
-  virtual void do_oop(narrowOop* p) {
+  virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+  virtual void do_oop(oop* p) {
     oop java_string = RawAccess<>::oop_load(p);
     StringDedupTable::deduplicate(java_string, _stat);
   }
--- a/src/hotspot/share/include/cds.h	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/include/cds.h	Tue Aug 14 09:59:37 2018 -0700
@@ -35,7 +35,7 @@
 
 #define NUM_CDS_REGIONS 9
 #define CDS_ARCHIVE_MAGIC 0xf00baba2
-#define CURRENT_CDS_ARCHIVE_VERSION 4
+#define CURRENT_CDS_ARCHIVE_VERSION 5
 #define INVALID_CDS_ARCHIVE_VERSION -1
 
 struct CDSFileMapRegion {
@@ -49,6 +49,8 @@
   size_t     _used;          // for setting space top on read
   int        _read_only;     // read only space?
   int        _allow_exec;    // executable code in space?
+  void*      _oopmap;        // bitmap for relocating embedded oops
+  size_t     _oopmap_size_in_bits;
 };
 
 struct CDSFileMapHeaderBase {
--- a/src/hotspot/share/memory/filemap.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -35,12 +35,15 @@
 #include "logging/logStream.hpp"
 #include "logging/logMessage.hpp"
 #include "memory/filemap.hpp"
+#include "memory/heapShared.inline.hpp"
+#include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceClosure.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/objArrayOop.hpp"
+#include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/java.hpp"
@@ -51,6 +54,7 @@
 #include "utilities/defaultStream.hpp"
 #if INCLUDE_G1GC
 #include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/heapRegion.hpp"
 #endif
 
 # include <sys/stat.h>
@@ -188,6 +192,9 @@
   _shared_path_table_size = mapinfo->_shared_path_table_size;
   _shared_path_table = mapinfo->_shared_path_table;
   _shared_path_entry_size = mapinfo->_shared_path_entry_size;
+  if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+    _heap_reserved = Universe::heap()->reserved_region();
+  }
 
   // The following fields are for sanity checks for whether this archive
   // will function correctly with this JVM and the bootclasspath it's
@@ -653,13 +660,14 @@
 // "_" represented unused spaced in the heap region.
 //
 //
-//    |ah0       | ah1 | ah2| ...... | ahn |
+//    |ah0       | ah1 | ah2| ...... | ahn|
 //    |XXXXXX|__ |XXXXX|XXXX|XXXXXXXX|XXXX|
 //    |<-r0->|   |<- r1 ----------------->|
 //            ^^^
 //             |
 //             +-- gap
 size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+                                               GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
                                                int first_region_id, int max_num_regions) {
   assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
 
@@ -684,6 +692,10 @@
     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);
+    if (size > 0) {
+      space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
+      space_at(i)->_oopmap_size_in_bits = oopmaps->at(arr_idx)._oopmap_size_in_bits;
+    }
   }
   return total_size;
 }
@@ -762,7 +774,7 @@
   if (!open_for_read()) {
     return false;
   }
-  char *addr = _header->region_addr(idx);
+  char *addr = region_addr(idx);
   char *base = os::remap_memory(_fd, _full_path, si->_file_offset,
                                 addr, size, false /* !read_only */,
                                 si->_allow_exec);
@@ -781,7 +793,7 @@
 
 // Map the whole region at once, assumed to be allocated contiguously.
 ReservedSpace FileMapInfo::reserve_shared_memory() {
-  char* requested_addr = _header->region_addr(0);
+  char* requested_addr = region_addr(0);
   size_t size = FileMapInfo::core_spaces_size();
 
   // Reserve the space first, then map otherwise map will go right over some
@@ -808,7 +820,7 @@
   size_t used = si->_used;
   size_t alignment = os::vm_allocation_granularity();
   size_t size = align_up(used, alignment);
-  char *requested_addr = _header->region_addr(i);
+  char *requested_addr = region_addr(i);
 
   // If a tool agent is in use (debugging enabled), we must map the address space RW
   if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) {
@@ -838,19 +850,57 @@
   return base;
 }
 
+address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
+  if (with_current_oop_encoding_mode) {
+    return (address)CompressedOops::decode_not_null(offset_of_space(spc));
+  } else {
+    return (address)HeapShared::decode_with_archived_oop_encoding_mode(offset_of_space(spc));
+  }
+}
+
 static MemRegion *string_ranges = NULL;
 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
+bool FileMapInfo::has_heap_regions() {
+  return (_header->_space[MetaspaceShared::first_string]._used > 0);
+}
+
+// Returns the address range of the archived heap regions computed using the
+// current oop encoding mode. This range may be different than the one seen at
+// dump time due to encoding mode differences. The result is used in determining
+// if/how these regions should be relocated at run time.
+MemRegion FileMapInfo::get_heap_regions_range_with_current_oop_encoding_mode() {
+  address start = (address) max_uintx;
+  address end   = NULL;
+
+  for (int i = MetaspaceShared::first_string; i <= MetaspaceShared::last_valid_region; i++) {
+    CDSFileMapRegion* si = space_at(i);
+    size_t size = si->_used;
+    if (size > 0) {
+      address s = start_address_with_current_oop_encoding_mode(si);
+      address e = s + size;
+      if (start > s) {
+        start = s;
+      }
+      if (end < e) {
+        end = e;
+      }
+    }
+  }
+  assert(end != NULL, "must have at least one used heap region");
+  return MemRegion((HeapWord*)start, (HeapWord*)end);
+}
+
 //
 // 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 shared strings are mapped close to the end of the java heap top in
+// closed archive regions. The mapped strings contain no out-going references
+// to any other java heap regions. GC does not write into the mapped shared strings.
 //
 // The open archive heap objects are mapped below the shared strings in
 // the runtime java heap. The mapped open archive heap data only contain
@@ -858,54 +908,108 @@
 // 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()) {
-      log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
-                    narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
-      log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
-                    p2i(narrow_klass_base()), narrow_klass_shift());
+void FileMapInfo::map_heap_regions_impl() {
+  if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+    log_info(cds)("CDS heap data is being ignored. UseG1GC, "
+                  "UseCompressedOops and UseCompressedClassPointers are required.");
+    return;
+  }
+
+  MemRegion heap_reserved = Universe::heap()->reserved_region();
+
+  log_info(cds)("CDS archive was created with max heap size = " SIZE_FORMAT "M, and the following configuration:",
+                max_heap_size()/M);
+  log_info(cds)("    narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+                p2i(narrow_klass_base()), narrow_klass_shift());
+  log_info(cds)("    narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+                narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
+
+  log_info(cds)("The current max heap size = " SIZE_FORMAT "M, HeapRegion::GrainBytes = " SIZE_FORMAT,
+                heap_reserved.byte_size()/M, HeapRegion::GrainBytes);
+  log_info(cds)("    narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+                p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
+  log_info(cds)("    narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+                Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()), Universe::narrow_oop_shift());
+
+  if (narrow_klass_base() != Universe::narrow_klass_base() ||
+      narrow_klass_shift() != Universe::narrow_klass_shift()) {
+    log_info(cds)("CDS heap data cannot be used because the archive was created with an incompatible narrow klass encoding mode.");
+    return;
+  }
+
+  if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
+      narrow_oop_base() != Universe::narrow_oop_base() ||
+      narrow_oop_shift() != Universe::narrow_oop_shift()) {
+    log_info(cds)("CDS heap data need to be relocated because the archive was created with an incompatible oop encoding mode.");
+    _heap_pointers_need_patching = true;
+  } else {
+    MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode();
+    if (!heap_reserved.contains(range)) {
+      log_info(cds)("CDS heap data need to be relocated because");
+      log_info(cds)("the desired range " PTR_FORMAT " - "  PTR_FORMAT, p2i(range.start()), p2i(range.end()));
+      log_info(cds)("is outside of the heap " PTR_FORMAT " - "  PTR_FORMAT, p2i(heap_reserved.start()), p2i(heap_reserved.end()));
+      _heap_pointers_need_patching = true;
+    }
+  }
 
-    // Check that all the narrow oop and klass encodings match the archive
-    if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
-        narrow_oop_base() != Universe::narrow_oop_base() ||
-        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) && space_at(MetaspaceShared::first_string)->_used > 0) {
-        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);
-        log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
-                      Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()),
-                      Universe::narrow_oop_shift());
-        log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
-                      p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
-      }
-    } else {
-      // 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();
+  ptrdiff_t delta = 0;
+  if (_heap_pointers_need_patching) {
+    //   dumptime heap end  ------------v
+    //   [      |archived heap regions| ]         runtime heap end ------v
+    //                                       [   |archived heap regions| ]
+    //                                  |<-----delta-------------------->|
+    //
+    // At dump time, the archived heap regions were near the top of the heap.
+    // At run time, they may not be inside the heap, so we move them so
+    // that they are now near the top of the runtime time. This can be done by
+    // the simple math of adding the delta as shown above.
+    address dumptime_heap_end = (address)_header->_heap_reserved.end();
+    address runtime_heap_end = (address)heap_reserved.end();
+    delta = runtime_heap_end - dumptime_heap_end;
+  }
+
+  log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta);
+  HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+
+  CDSFileMapRegion* si = space_at(MetaspaceShared::first_string);
+  address relocated_strings_bottom = start_address_with_archived_oop_encoding_mode(si);
+  if (!is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes)) {
+    // Align the bottom of the string regions at G1 region boundary. This will avoid
+    // the situation where the highest open region and the lowest string region sharing
+    // the same G1 region. Otherwise we will fail to map the open regions.
+    size_t align = size_t(relocated_strings_bottom) % HeapRegion::GrainBytes;
+    delta -= align;
+    assert(is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes), "must be");
 
-        // 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();
-        }
-      }
+    log_info(cds)("CDS heap data need to be relocated lower by a further " SIZE_FORMAT
+                  " bytes to be aligned with HeapRegion::GrainBytes", align);
+
+    HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+    _heap_pointers_need_patching = true;
+  }
+
+  // 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();
+
+    // 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();
     }
-  } else {
-    if (log_is_enabled(Info, cds) && space_at(MetaspaceShared::first_string)->_used > 0) {
-      log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, "
-                    "UseCompressedOops and UseCompressedClassPointers are required.");
-    }
+  }
+}
+
+void FileMapInfo::map_heap_regions() {
+  if (has_heap_regions()) {
+    map_heap_regions_impl();
   }
 
   if (!StringTable::shared_string_mapped()) {
@@ -926,13 +1030,13 @@
   for (int i = first;
            i < first + max; i++) {
     si = space_at(i);
-    size_t used = si->_used;
-    if (used > 0) {
-      size_t size = used;
-      char* requested_addr = (char*)((void*)CompressedOops::decode_not_null(
-                                            (narrowOop)si->_addr._offset));
-      regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+    size_t size = si->_used;
+    if (size > 0) {
+      HeapWord* start = (HeapWord*)start_address_with_archived_oop_encoding_mode(si);
+      regions[region_num] = MemRegion(start, size / HeapWordSize);
       region_num ++;
+      log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes",
+                    i, p2i(start), size);
     }
   }
 
@@ -942,16 +1046,14 @@
 
   // 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.");
+    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.");
+    log_info(cds)("UseSharedSpaces: Unable to allocate region, java heap range is already in use.");
     return false;
   }
 
@@ -967,7 +1069,9 @@
     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.");
+      log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
+                    INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes",
+                    p2i(addr), regions[i].byte_size());
       return false;
     }
   }
@@ -995,6 +1099,31 @@
   return true;
 }
 
+void FileMapInfo::patch_archived_heap_embedded_pointers() {
+  if (!_heap_pointers_need_patching) {
+    return;
+  }
+
+  patch_archived_heap_embedded_pointers(string_ranges,
+                                        num_string_ranges,
+                                        MetaspaceShared::first_string);
+
+  patch_archived_heap_embedded_pointers(open_archive_heap_ranges,
+                                        num_open_archive_heap_ranges,
+                                        MetaspaceShared::first_open_archive_heap_region);
+}
+
+void FileMapInfo::patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
+                                                        int first_region_idx) {
+  for (int i=0; i<num_ranges; i++) {
+    CDSFileMapRegion* si = space_at(i + first_region_idx);
+    HeapShared::patch_archived_heap_embedded_pointers(ranges[i], (address)si->_oopmap,
+                                                      si->_oopmap_size_in_bits);
+  }
+}
+
+// This internally allocates objects using SystemDictionary::Object_klass(), so it
+// must be called after the well-known classes are resolved.
 void FileMapInfo::fixup_mapped_heap_regions() {
   // If any string regions were found, call the fill routine to make them parseable.
   // Note that string_ranges may be non-NULL even if no ranges were found.
@@ -1036,7 +1165,7 @@
        !MetaspaceShared::open_archive_heap_region_mapped())) {
     return true; // archived heap data is not mapped
   }
-  const char* buf = _header->region_addr(i);
+  const char* buf = region_addr(i);
   int crc = ClassLoader::crc32(0, buf, (jint)sz);
   if (crc != space_at(i)->_crc) {
     fail_continue("Checksum verification failed.");
@@ -1057,7 +1186,7 @@
     return;
   }
 
-  char* addr = _header->region_addr(i);
+  char* addr = region_addr(i);
   if (!os::unmap_memory(addr, size)) {
     fail_stop("Unable to unmap shared space.");
   }
@@ -1078,6 +1207,7 @@
 
 
 FileMapInfo* FileMapInfo::_current_info = NULL;
+bool FileMapInfo::_heap_pointers_need_patching = false;
 Array<u8>* FileMapInfo::_shared_path_table = NULL;
 int FileMapInfo::_shared_path_table_size = 0;
 size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
@@ -1107,12 +1237,14 @@
   return true;
 }
 
-char* FileMapHeader::region_addr(int idx) {
+char* FileMapInfo::region_addr(int idx) {
+  CDSFileMapRegion* si = space_at(idx);
   if (MetaspaceShared::is_heap_region(idx)) {
-    return _space[idx]._used > 0 ?
-             (char*)((void*)CompressedOops::decode_not_null((narrowOop)_space[idx]._addr._offset)) : NULL;
+    assert(DumpSharedSpaces, "The following doesn't work at runtime");
+    return si->_used > 0 ?
+          (char*)start_address_with_current_oop_encoding_mode(si) : NULL;
   } else {
-    return _space[idx]._addr._base;
+    return si->_addr._base;
   }
 }
 
@@ -1216,34 +1348,25 @@
          idx == MetaspaceShared::rw ||
          idx == MetaspaceShared::mc ||
          idx == MetaspaceShared::md, "invalid region index");
-  char* base = _header->region_addr(idx);
+  char* base = region_addr(idx);
   if (p >= base && p < base + space_at(idx)->_used) {
     return true;
   }
   return false;
 }
 
-void FileMapInfo::print_shared_spaces() {
-  tty->print_cr("Shared Spaces:");
-  for (int i = 0; i < MetaspaceShared::n_regions; i++) {
-    CDSFileMapRegion* si = space_at(i);
-    char *base = _header->region_addr(i);
-    tty->print("  %s " INTPTR_FORMAT "-" INTPTR_FORMAT,
-                        shared_region_name[i],
-                        p2i(base), p2i(base + si->_used));
-  }
-}
-
 // Unmap mapped regions of shared space.
 void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
   FileMapInfo *map_info = FileMapInfo::current_info();
   if (map_info) {
     map_info->fail_continue("%s", msg);
     for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
-      char *addr = map_info->_header->region_addr(i);
-      if (addr != NULL && !MetaspaceShared::is_heap_region(i)) {
-        map_info->unmap_region(i);
-        map_info->space_at(i)->_addr._base = NULL;
+      if (!MetaspaceShared::is_heap_region(i)) {
+        char *addr = map_info->region_addr(i);
+        if (addr != NULL) {
+          map_info->unmap_region(i);
+          map_info->space_at(i)->_addr._base = NULL;
+        }
       }
     }
     // Dealloc the archive heap regions only without unmapping. The regions are part
--- a/src/hotspot/share/memory/filemap.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/filemap.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -88,6 +88,11 @@
   }
 };
 
+struct ArchiveHeapOopmapInfo {
+  address _oopmap;               // bitmap for relocating embedded oops
+  size_t  _oopmap_size_in_bits;
+};
+
 struct FileMapHeader : public CDSFileMapHeaderBase {
   size_t _alignment;                // how shared archive should be aligned
   int    _obj_alignment;            // value of ObjectAlignmentInBytes
@@ -104,6 +109,7 @@
   size_t  _cds_i2i_entry_code_buffers_size;
   size_t  _core_spaces_size;        // number of bytes allocated by the core spaces
                                     // (mc, md, ro, rw and od).
+  MemRegion _heap_reserved;         // reserved region for the entire heap at dump time.
 
   // The following fields are all sanity checks for whether this archive
   // will function correctly with this JVM and the bootclasspath it's
@@ -152,14 +158,16 @@
   jshort max_used_path_index()       { return _max_used_path_index; }
   jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
 
-  char* region_addr(int idx);
-
   bool validate();
   void populate(FileMapInfo* info, size_t alignment);
   int compute_crc();
+
+  CDSFileMapRegion* space_at(int i) {
+    assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
+    return &_space[i];
+  }
 };
 
-
 class FileMapInfo : public CHeapObj<mtInternal> {
 private:
   friend class ManifestStream;
@@ -194,6 +202,7 @@
   char* _paths_misc_info;
 
   static FileMapInfo* _current_info;
+  static bool _heap_pointers_need_patching;
 
   bool  init_from_file(int fd);
   void  align_file_position();
@@ -253,12 +262,19 @@
   void  write_region(int region, char* base, size_t size,
                      bool read_only, bool allow_exec);
   size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+                                    GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
                                     int first_region_id, int max_num_regions);
   void  write_bytes(const void* buffer, size_t count);
   void  write_bytes_aligned(const void* buffer, size_t count);
   char* map_region(int i, char** top_ret);
+  void  map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
   void  map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
   void  fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
+  void  patch_archived_heap_embedded_pointers() NOT_CDS_JAVA_HEAP_RETURN;
+  void  patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
+                                              int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN;
+  bool  has_heap_regions()  NOT_CDS_JAVA_HEAP_RETURN_(false);
+  MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
   void  unmap_region(int i);
   bool  verify_region_checksum(int i);
   void  close();
@@ -274,7 +290,6 @@
   static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
 
   bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
-  void print_shared_spaces() NOT_CDS_RETURN;
 
   // Stop CDS sharing and unmap CDS regions.
   static void stop_sharing_and_unmap(const char* msg);
@@ -303,6 +318,8 @@
     return _shared_path_table_size;
   }
 
+  char* region_addr(int idx);
+
  private:
   bool  map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
                       bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
@@ -310,9 +327,24 @@
   void  dealloc_archive_heap_regions(MemRegion* regions, int num) NOT_CDS_JAVA_HEAP_RETURN;
 
   CDSFileMapRegion* space_at(int i) {
-    assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
-    return &_header->_space[i];
+    return _header->space_at(i);
+  }
+
+  narrowOop offset_of_space(CDSFileMapRegion* spc) {
+    return (narrowOop)(spc->_addr._offset);
   }
+
+  // The starting address of spc, as calculated with CompressedOop::decode_non_null()
+  address start_address_with_current_oop_encoding_mode(CDSFileMapRegion* spc) {
+    return decode_start_address(spc, true);
+  }
+
+  // The starting address of spc, as calculated with HeapShared::decode_with_archived_oop_encoding_mode()
+  address start_address_with_archived_oop_encoding_mode(CDSFileMapRegion* spc) {
+    return decode_start_address(spc, false);
+  }
+
+  address decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode);
 };
 
 #endif // SHARE_VM_MEMORY_FILEMAP_HPP
--- a/src/hotspot/share/memory/heapShared.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/heapShared.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -29,7 +29,7 @@
 #include "logging/log.hpp"
 #include "logging/logMessage.hpp"
 #include "logging/logStream.hpp"
-#include "memory/heapShared.hpp"
+#include "memory/heapShared.inline.hpp"
 #include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceClosure.hpp"
@@ -38,6 +38,7 @@
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
+#include "utilities/bitMap.inline.hpp"
 
 #if INCLUDE_CDS_JAVA_HEAP
 KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL;
@@ -72,6 +73,9 @@
   return info;
 }
 
+address   HeapShared::_narrow_oop_base;
+int       HeapShared::_narrow_oop_shift;
+
 int HeapShared::num_of_subgraph_infos() {
   int num = 0;
   KlassSubGraphInfo* info = _subgraph_info_list;
@@ -320,7 +324,7 @@
           // point. All objects in the subgraph reachable from the object are
           // also 'known' by GC.
           oop v = MetaspaceShared::materialize_archived_object(
-            CompressedOops::decode(entry_field_records->at(i+1)));
+            entry_field_records->at(i+1));
           m->obj_field_put(field_offset, v);
           i += 2;
         }
@@ -601,4 +605,96 @@
     archive_reachable_objects_from_static_field(info->klass, info->offset, info->type, CHECK);
   }
 }
+
+// At dump-time, find the location of all the non-null oop pointers in an archived heap
+// region. This way we can quickly relocate all the pointers without using
+// BasicOopIterateClosure at runtime.
+class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
+  narrowOop* _start;
+  BitMap *_oopmap;
+  int _num_total_oops;
+  int _num_null_oops;
+ public:
+  FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap)
+    : _start(start), _oopmap(oopmap), _num_total_oops(0),  _num_null_oops(0) {}
+
+  virtual bool should_verify_oops(void) {
+    return false;
+  }
+  virtual void do_oop(narrowOop* p) {
+    _num_total_oops ++;
+    narrowOop v = *p;
+    if (!CompressedOops::is_null(v)) {
+      size_t idx = p - _start;
+      _oopmap->set_bit(idx);
+    } else {
+      _num_null_oops ++;
+    }
+  }
+  virtual void do_oop(oop *p) {
+    ShouldNotReachHere();
+  }
+  int num_total_oops() const { return _num_total_oops; }
+  int num_null_oops()  const { return _num_null_oops; }
+};
+
+ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
+  assert(UseCompressedOops, "must be");
+  size_t num_bits = region.byte_size() / sizeof(narrowOop);
+  ResourceBitMap oopmap(num_bits);
+
+  HeapWord* p   = region.start();
+  HeapWord* end = region.end();
+  FindEmbeddedNonNullPointers finder((narrowOop*)p, &oopmap);
+
+  int num_objs = 0;
+  while (p < end) {
+    oop o = (oop)p;
+    o->oop_iterate(&finder);
+    p += o->size();
+    ++ num_objs;
+  }
+
+  log_info(cds, heap)("calculate_oopmap: objects = %6d, embedded oops = %7d, nulls = %7d",
+                      num_objs, finder.num_total_oops(), finder.num_null_oops());
+  return oopmap;
+}
+
+void HeapShared::init_narrow_oop_decoding(address base, int shift) {
+  _narrow_oop_base = base;
+  _narrow_oop_shift = shift;
+}
+
+// Patch all the embedded oop pointers inside an archived heap region,
+// to be consistent with the runtime oop encoding.
+class PatchEmbeddedPointers: public BitMapClosure {
+  narrowOop* _start;
+
+ public:
+  PatchEmbeddedPointers(narrowOop* start) : _start(start) {}
+
+  bool do_bit(size_t offset) {
+    narrowOop* p = _start + offset;
+    narrowOop v = *p;
+    assert(!CompressedOops::is_null(v), "null oops should have been filtered out at dump time");
+    oop o = HeapShared::decode_with_archived_oop_encoding_mode(v);
+    RawAccess<IS_NOT_NULL>::oop_store(p, o);
+    return true;
+  }
+};
+
+void HeapShared::patch_archived_heap_embedded_pointers(MemRegion region, address oopmap,
+                                                       size_t oopmap_size_in_bits) {
+  BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
+
+#ifndef PRODUCT
+  ResourceMark rm;
+  ResourceBitMap checkBm = calculate_oopmap(region);
+  assert(bm.is_same(checkBm), "sanity");
+#endif
+
+  PatchEmbeddedPointers patcher((narrowOop*)region.start());
+  bm.iterate(&patcher);
+}
+
 #endif // INCLUDE_CDS_JAVA_HEAP
--- a/src/hotspot/share/memory/heapShared.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/heapShared.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -30,6 +30,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/oop.hpp"
 #include "oops/typeArrayKlass.hpp"
+#include "utilities/bitMap.hpp"
 #include "utilities/growableArray.hpp"
 
 #if INCLUDE_CDS_JAVA_HEAP
@@ -123,13 +124,33 @@
   static int num_of_subgraph_infos();
 
   static size_t build_archived_subgraph_info_records(int num_records);
+
+  // Used by decode_with_archived_oop_encoding_mode
+  static address _narrow_oop_base;
+  static int     _narrow_oop_shift;
+
 #endif // INCLUDE_CDS_JAVA_HEAP
  public:
   static char* read_archived_subgraph_infos(char* buffer) NOT_CDS_JAVA_HEAP_RETURN_(buffer);
   static void write_archived_subgraph_infos() NOT_CDS_JAVA_HEAP_RETURN;
   static void initialize_from_archived_subgraph(Klass* k) NOT_CDS_JAVA_HEAP_RETURN;
 
+  // NarrowOops stored in the CDS archive may use a different encoding scheme
+  // than Universe::narrow_oop_{base,shift} -- see FileMapInfo::map_heap_regions_impl.
+  // To decode them, do not use CompressedOops::decode_not_null. Use this
+  // function instead.
+  inline static oop decode_with_archived_oop_encoding_mode(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+
+  static void init_narrow_oop_decoding(address base, int shift) NOT_CDS_JAVA_HEAP_RETURN;
+
+  static void patch_archived_heap_embedded_pointers(MemRegion mem, address  oopmap,
+                                                    size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
+
   static void init_archivable_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
   static void archive_module_graph_objects(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
+
+#if INCLUDE_CDS_JAVA_HEAP
+  static ResourceBitMap calculate_oopmap(MemRegion region);
+#endif
 };
 #endif // SHARE_VM_MEMORY_HEAPSHARED_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/heapShared.inline.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
+#define SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
+
+#include "oops/compressedOops.inline.hpp"
+#include "memory/heapShared.hpp"
+
+#if INCLUDE_CDS_JAVA_HEAP
+
+inline oop HeapShared::decode_with_archived_oop_encoding_mode(narrowOop v) {
+  assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
+  oop result = (oop)(void*)((uintptr_t)_narrow_oop_base + ((uintptr_t)v << _narrow_oop_shift));
+  assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
+  return result;
+}
+
+#endif
+
+#endif // SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -39,7 +39,7 @@
 #include "logging/log.hpp"
 #include "logging/logMessage.hpp"
 #include "memory/filemap.hpp"
-#include "memory/heapShared.hpp"
+#include "memory/heapShared.inline.hpp"
 #include "memory/metaspace.hpp"
 #include "memory/metaspaceClosure.hpp"
 #include "memory/metaspaceShared.hpp"
@@ -61,6 +61,7 @@
 #include "runtime/vmThread.hpp"
 #include "runtime/vm_operations.hpp"
 #include "utilities/align.hpp"
+#include "utilities/bitMap.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/hashtable.inline.hpp"
 #if INCLUDE_G1GC
@@ -227,7 +228,7 @@
   // Map in spaces now also
   if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
     size_t cds_total = core_spaces_size();
-    cds_address = (address)mapinfo->header()->region_addr(0);
+    cds_address = (address)mapinfo->region_addr(0);
 #ifdef _LP64
     if (Metaspace::using_class_space()) {
       char* cds_end = (char*)(cds_address + cds_total);
@@ -309,10 +310,10 @@
   Universe::set_narrow_klass_range(cds_total);
 
   Metaspace::initialize_class_space(tmp_class_space);
-  tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+  log_info(cds)("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
                 p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
 
-  tty->print_cr("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
+  log_info(cds)("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
                 CompressedClassSpaceSize, p2i(tmp_class_space.base()));
 #endif
 
@@ -424,6 +425,7 @@
   soc->do_tag(--tag);
 
   JavaClasses::serialize_offsets(soc);
+  InstanceMirrorKlass::serialize_offsets(soc);
   soc->do_tag(--tag);
 
   soc->do_tag(666);
@@ -1017,7 +1019,13 @@
   GrowableArray<MemRegion> *_closed_archive_heap_regions;
   GrowableArray<MemRegion> *_open_archive_heap_regions;
 
+  GrowableArray<ArchiveHeapOopmapInfo> *_closed_archive_heap_oopmaps;
+  GrowableArray<ArchiveHeapOopmapInfo> *_open_archive_heap_oopmaps;
+
   void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
+  void dump_archive_heap_oopmaps() NOT_CDS_JAVA_HEAP_RETURN;
+  void dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
+                                 GrowableArray<ArchiveHeapOopmapInfo>* oopmaps);
   void dump_symbols();
   char* dump_read_only_tables();
   void print_region_stats();
@@ -1329,6 +1337,9 @@
   WriteClosure wc(&_ro_region);
   MetaspaceShared::serialize(&wc);
 
+  // Write the bitmaps for patching the archive heap regions
+  dump_archive_heap_oopmaps();
+
   char* newtop = _ro_region.top();
   ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - oldtop), true);
   return buckets_top;
@@ -1471,10 +1482,12 @@
 
     _total_string_region_size = mapinfo->write_archive_heap_regions(
                                         _closed_archive_heap_regions,
+                                        _closed_archive_heap_oopmaps,
                                         MetaspaceShared::first_string,
                                         MetaspaceShared::max_strings);
     _total_open_archive_region_size = mapinfo->write_archive_heap_regions(
                                         _open_archive_heap_regions,
+                                        _open_archive_heap_oopmaps,
                                         MetaspaceShared::first_open_archive_heap_region,
                                         MetaspaceShared::max_open_archive_heap_region);
   }
@@ -1810,6 +1823,36 @@
   G1HeapVerifier::verify_archive_regions();
 }
 
+void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() {
+  if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+    _closed_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
+    dump_archive_heap_oopmaps(_closed_archive_heap_regions, _closed_archive_heap_oopmaps);
+
+    _open_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
+    dump_archive_heap_oopmaps(_open_archive_heap_regions, _open_archive_heap_oopmaps);
+  }
+}
+
+void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
+                                                           GrowableArray<ArchiveHeapOopmapInfo>* oopmaps) {
+  for (int i=0; i<regions->length(); i++) {
+    ResourceBitMap oopmap = HeapShared::calculate_oopmap(regions->at(i));
+    size_t size_in_bits = oopmap.size();
+    size_t size_in_bytes = oopmap.size_in_bytes();
+    uintptr_t* buffer = (uintptr_t*)_ro_region.allocate(size_in_bytes, sizeof(intptr_t));
+    oopmap.write_to(buffer, size_in_bytes);
+    log_info(cds)("Oopmap = " INTPTR_FORMAT " (" SIZE_FORMAT_W(6) " bytes) for heap region "
+                  INTPTR_FORMAT " (" SIZE_FORMAT_W(8) " bytes)",
+                  p2i(buffer), size_in_bytes,
+                  p2i(regions->at(i).start()), regions->at(i).byte_size());
+
+    ArchiveHeapOopmapInfo info;
+    info._oopmap = (address)buffer;
+    info._oopmap_size_in_bits = size_in_bits;
+    oopmaps->append(info);
+  }
+}
+
 void MetaspaceShared::dump_closed_archive_heap_objects(
                                     GrowableArray<MemRegion> * closed_archive) {
   assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects");
@@ -1896,8 +1939,9 @@
   return archived_oop;
 }
 
-oop MetaspaceShared::materialize_archived_object(oop obj) {
-  if (obj != NULL) {
+oop MetaspaceShared::materialize_archived_object(narrowOop v) {
+  if (!CompressedOops::is_null(v)) {
+    oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
     return G1CollectedHeap::heap()->materialize_archived_object(obj);
   }
   return NULL;
@@ -1973,7 +2017,7 @@
              "Archived heap object is not allowed");
       assert(MetaspaceShared::open_archive_heap_region_mapped(),
              "Open archive heap region is not mapped");
-      *p = CompressedOops::decode_not_null(o);
+      *p = HeapShared::decode_with_archived_oop_encoding_mode(o);
     }
   }
 
@@ -2003,13 +2047,6 @@
   return false;
 }
 
-void MetaspaceShared::print_shared_spaces() {
-  if (UseSharedSpaces) {
-    FileMapInfo::current_info()->print_shared_spaces();
-  }
-}
-
-
 // Map shared spaces at requested addresses and return if succeeded.
 bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
   size_t image_alignment = mapinfo->alignment();
@@ -2120,6 +2157,8 @@
   // Initialize the run-time symbol table.
   SymbolTable::create_table();
 
+  mapinfo->patch_archived_heap_embedded_pointers();
+
   // Close the mapinfo file
   mapinfo->close();
 
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -79,6 +79,7 @@
     // mapped java heap regions
     first_string = od + 1, // index of first string region
     max_strings = 2, // max number of string regions in string space
+    last_string = first_string + max_strings - 1,
     first_open_archive_heap_region = first_string + max_strings,
     max_open_archive_heap_region = 2,
 
@@ -111,7 +112,7 @@
   }
   static oop find_archived_heap_object(oop obj);
   static oop archive_heap_object(oop obj, Thread* THREAD);
-  static oop materialize_archived_object(oop obj);
+  static oop materialize_archived_object(narrowOop v);
   static void archive_klass_objects(Thread* THREAD);
 #endif
 
@@ -221,8 +222,6 @@
     NOT_CDS(return false);
   }
 
-  static void print_shared_spaces();
-
   static bool try_link_class(InstanceKlass* ik, TRAPS);
   static void link_and_cleanup_shared_classes(TRAPS);
   static void check_shared_class_loader_type(InstanceKlass* ik);
--- a/src/hotspot/share/memory/universe.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/universe.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -517,8 +517,11 @@
   // that the number of objects allocated at this point is very small.
   assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded");
   HandleMark hm(THREAD);
-  // Cache the start of the static fields
-  InstanceMirrorKlass::init_offset_of_static_fields();
+
+  if (!UseSharedSpaces) {
+    // Cache the start of the static fields
+    InstanceMirrorKlass::init_offset_of_static_fields();
+  }
 
   GrowableArray <Klass*>* list = java_lang_Class::fixup_mirror_list();
   int list_length = list->length();
--- a/src/hotspot/share/oops/cpCache.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/cpCache.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -777,7 +777,7 @@
   if (CompressedOops::is_null(_archived_references)) {
     return NULL;
   }
-  return MetaspaceShared::materialize_archived_object(CompressedOops::decode_not_null(_archived_references));
+  return MetaspaceShared::materialize_archived_object(_archived_references);
 }
 
 void ConstantPoolCache::set_archived_references(oop o) {
--- a/src/hotspot/share/oops/instanceMirrorKlass.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/instanceMirrorKlass.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -66,3 +66,9 @@
   }
   return 0;
 }
+
+#if INCLUDE_CDS
+void InstanceMirrorKlass::serialize_offsets(SerializeClosure* f) {
+  f->do_u4((u4*)&_offset_of_static_fields);
+}
+#endif
--- a/src/hotspot/share/oops/instanceMirrorKlass.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -99,6 +99,8 @@
   void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
 #endif
 
+  static void serialize_offsets(class SerializeClosure* f) NOT_CDS_RETURN;
+
   // Oop fields (and metadata) iterators
   //
   // The InstanceMirrorKlass iterators also visit the hidden Klass pointer.
--- a/src/hotspot/share/oops/klass.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/klass.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -571,6 +571,11 @@
   return CompressedOops::decode(_archived_mirror);
 }
 
+narrowOop Klass::archived_java_mirror_raw_narrow() {
+  assert(has_raw_archived_mirror(), "must have raw archived mirror");
+  return _archived_mirror;
+}
+
 // No GC barrier
 void Klass::set_archived_java_mirror_raw(oop m) {
   assert(DumpSharedSpaces, "called only during runtime");
--- a/src/hotspot/share/oops/klass.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/klass.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -261,6 +261,7 @@
   void set_java_mirror(Handle m);
 
   oop archived_java_mirror_raw() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // no GC barrier
+  narrowOop archived_java_mirror_raw_narrow() NOT_CDS_JAVA_HEAP_RETURN_(0); // no GC barrier
   void set_archived_java_mirror_raw(oop m) NOT_CDS_JAVA_HEAP_RETURN; // no GC barrier
 
   // Temporary mirror switch used by RedefineClasses
--- a/src/hotspot/share/runtime/arguments.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/runtime/arguments.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -1585,7 +1585,7 @@
   if (RequireSharedSpaces) {
     jio_fprintf(defaultStream::error_stream(),
       "Class data sharing is inconsistent with other specified options.\n");
-    vm_exit_during_initialization("Unable to use shared archive.", message);
+    vm_exit_during_initialization("Unable to use shared archive", message);
   } else {
     FLAG_SET_DEFAULT(UseSharedSpaces, false);
   }
--- a/src/hotspot/share/utilities/bitMap.cpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/utilities/bitMap.cpp	Tue Aug 14 09:59:37 2018 -0700
@@ -672,6 +672,11 @@
       prefix, p2i(map()), p2i((char*)map() + (size() >> LogBitsPerByte)));
 }
 
+void BitMap::write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const {
+  assert(buffer_size_in_bytes == size_in_bytes(), "must be");
+  memcpy(buffer, _map, size_in_bytes());
+}
+
 #ifndef PRODUCT
 
 void BitMap::print_on(outputStream* st) const {
--- a/src/hotspot/share/utilities/bitMap.hpp	Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/utilities/bitMap.hpp	Tue Aug 14 09:59:37 2018 -0700
@@ -288,6 +288,7 @@
   bool is_full() const;
   bool is_empty() const;
 
+  void write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const;
   void print_on_error(outputStream* st, const char* prefix) const;
 
 #ifndef PRODUCT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/DifferentHeapSizes.java	Tue Aug 14 09:59:37 2018 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test automatic relocation of archive heap regions dur to heap size changes.
+ * @requires vm.cds.archived.java.heap
+ * @requires (vm.gc=="null")
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DifferentHeapSizes
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+import jdk.test.lib.cds.CDSTestUtils;
+
+public class DifferentHeapSizes {
+    static class Scenario {
+        int dumpSize;   // in MB
+        int runSizes[]; // in MB
+        Scenario(int ds, int... rs) {
+            dumpSize = ds;
+            runSizes = rs;
+        }
+    }
+
+    static Scenario[] scenarios = {
+        //           dump -Xmx ,         run -Xmx
+        new Scenario(        32,         32, 64, 512, 2048, 4097, 16374, 31000),
+        new Scenario(       128,         32, 64, 512, 2048, 4097, 16374, 31000, 40000),
+        new Scenario(      2048,         32, 512, 2600, 4097, 8500, 31000,      40000),
+        new Scenario(     17000,         32, 512, 2048, 4097, 8500, 31000,      40000),
+        new Scenario(     31000,         32, 512, 2048, 4097, 8500, 17000,      40000)
+    };
+
+    public static void main(String[] args) throws Exception {
+        String dedup = "-XX:+UseStringDeduplication"; // This increases code coverage.
+        JarBuilder.getOrCreateHelloJar();
+        String appJar = TestCommon.getTestJar("hello.jar");
+        String appClasses[] = TestCommon.list("Hello");
+
+        for (Scenario s : scenarios) {
+            String dumpXmx = "-Xmx" + s.dumpSize + "m";
+            OutputAnalyzer output = TestCommon.dump(appJar, appClasses, dumpXmx);
+
+            for (int runSize : s.runSizes) {
+                String runXmx = "-Xmx" + runSize + "m";
+                CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion",
+                        "-Xlog:cds", runXmx, dedup, "Hello");
+                if (runSize < 32768) {
+                    result
+                        .assertNormalExit("Hello World")
+                        .assertNormalExit(out -> {
+                            out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
+                            out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
+                        });
+                } else {
+                    result.assertAbnormalExit("Unable to use shared archive: UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.");
+                }
+            }
+        }
+        String flag = "HeapBaseMinAddress";
+        String xxflag = "-XX:" + flag + "=";
+        String mx = "-Xmx128m";
+        long base = WhiteBox.getWhiteBox().getSizeTVMFlag(flag).longValue();
+
+        TestCommon.dump(appJar, appClasses, mx, xxflag + base);
+        TestCommon.run("-cp", appJar, "-showversion", "-Xlog:cds", mx, xxflag + (base + 256 * 1024 * 1024), dedup, "Hello")
+            .assertNormalExit("Hello World")
+            .assertNormalExit(out -> {
+                    out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
+                    out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
+                });
+    }
+}
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/RangeNotWithinHeap.java	Wed Aug 22 16:06:51 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2017, 2018, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/*
- * @test
- * @summary Shared classes can still be used when archived heap regions cannot be
- *          mapped due to out of range, and -Xshare:on should not fail. Test on
- *          linux 64-bit only since the HeapBaseMinAddress value is platform specific.
- *          The value used in the test may cause different behavior on other platforms.
- * @requires vm.cds.archived.java.heap
- * @requires os.family == "linux"
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @modules java.base/jdk.internal.misc
- * @modules java.management
- *          jdk.jartool/sun.tools.jar
- * @compile ../test-classes/Hello.java
- * @run main RangeNotWithinHeap
- */
-
-import jdk.test.lib.process.OutputAnalyzer;
-
-public class RangeNotWithinHeap {
-    public static void main(String[] args) throws Exception {
-        JarBuilder.getOrCreateHelloJar();
-        String appJar = TestCommon.getTestJar("hello.jar");
-        String appClasses[] = TestCommon.list("Hello");
-
-        OutputAnalyzer output = TestCommon.dump(appJar, appClasses,
-                    "-XX:HeapBaseMinAddress=0x600000000", "-Xmx6G", "-Xlog:gc+heap=trace");
-        TestCommon.checkDump(output, "oa0 space:");
-
-        // Force archive region out of runtime java heap
-        output = TestCommon.exec(appJar, "Hello");
-        TestCommon.checkExec(output, "Hello World");
-        output = TestCommon.exec(appJar,
-                    "-XX:HeapBaseMinAddress=0x600000000", "-Xmx2G", "-Xlog:gc+heap=trace,cds", "Hello");
-        TestCommon.checkExec(output, "Hello World");
-        try {
-            output.shouldContain(
-                "UseSharedSpaces: Unable to allocate region, range is not within java heap.");
-        } catch (Exception e) {
-            // In rare case the heap data is not used.
-            if (output.getOutput().contains("Cached heap data from the CDS archive is being ignored")) {
-                return;
-            }
-            // Check for common shared class data mapping failures.
-            TestCommon.checkCommonExecExceptions(output, e);
-        }
-    }
-}
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java	Wed Aug 22 16:06:51 2018 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java	Tue Aug 14 09:59:37 2018 -0700
@@ -141,10 +141,10 @@
         // main class param, and fails with "Could not find or load main class"
         if (!extraOption.isEmpty()) {
             output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
-                collectorOption, extraOption, "HelloString");
+                collectorOption, "-Xlog:cds", extraOption, "HelloString");
         } else {
             output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
-                collectorOption, "HelloString");
+                collectorOption, "-Xlog:cds", "HelloString");
         }
 
         if (expectedWarning != null)
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Wed Aug 22 16:06:51 2018 +0100
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Tue Aug 14 09:59:37 2018 -0700
@@ -36,6 +36,11 @@
 
 // This class contains common test utilities for testing CDS
 public class CDSTestUtils {
+    public static final String MSG_RANGE_NOT_WITHIN_HEAP =
+        "UseSharedSpaces: Unable to allocate region, range is not within java heap.";
+    public static final String MSG_RANGE_ALREADT_IN_USE =
+        "Unable to allocate region, java heap range is already in use.";
+
     public interface Checker {
         public void check(OutputAnalyzer output) throws Exception;
     }