From ac05bc8605bcf343f0c230868af3056f03461e01 Mon Sep 17 00:00:00 2001
From: Ioi Lam <iklam@openjdk.org>
Date: Fri, 2 Sep 2022 23:47:48 +0000
Subject: [PATCH] 8293293: Move archive heap loading code out of heapShared.cpp

Reviewed-by: erikj, coleenp
---
 make/hotspot/lib/JvmFeatures.gmk              |   4 -
 src/hotspot/share/cds/archiveHeapLoader.cpp   | 437 ++++++++++++++++++
 src/hotspot/share/cds/archiveHeapLoader.hpp   | 170 +++++++
 ...nline.hpp => archiveHeapLoader.inline.hpp} |  13 +-
 src/hotspot/share/cds/archiveUtils.cpp        |  15 +-
 src/hotspot/share/cds/filemap.cpp             |  27 +-
 src/hotspot/share/cds/heapShared.cpp          | 408 +---------------
 src/hotspot/share/cds/heapShared.hpp          | 106 +----
 src/hotspot/share/cds/metaspaceShared.cpp     |   5 +-
 .../share/classfile/compactHashtable.cpp      |   1 -
 src/hotspot/share/classfile/javaClasses.cpp   |   8 +-
 src/hotspot/share/classfile/stringTable.cpp   |  11 +-
 .../classfile/systemDictionaryShared.cpp      |   7 +-
 src/hotspot/share/classfile/vmClasses.cpp     |   7 +-
 src/hotspot/share/memory/universe.cpp         |   7 +-
 src/hotspot/share/oops/constantPool.cpp       |   3 +-
 src/hotspot/share/oops/klass.cpp              |   4 +-
 src/hotspot/share/prims/whitebox.cpp          |   7 +-
 18 files changed, 680 insertions(+), 560 deletions(-)
 create mode 100644 src/hotspot/share/cds/archiveHeapLoader.cpp
 create mode 100644 src/hotspot/share/cds/archiveHeapLoader.hpp
 rename src/hotspot/share/cds/{heapShared.inline.hpp => archiveHeapLoader.inline.hpp} (85%)

diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 5daff5e380d..105ec18eb59 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -120,12 +120,8 @@ endif
 ifneq ($(call check-jvm-feature, cds), true)
   JVM_CFLAGS_FEATURES += -DINCLUDE_CDS=0
   JVM_EXCLUDE_FILES += \
-      cdsProtectionDomain.cpp \
       classLoaderDataShared.cpp \
       classLoaderExt.cpp \
-      dumpTimeSharedClassInfo.cpp \
-      lambdaProxyClassDictionary.cpp \
-      runTimeSharedClassInfo.cpp \
       systemDictionaryShared.cpp
   JVM_EXCLUDE_PATTERNS += cds/
 endif
diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp
new file mode 100644
index 00000000000..393734de7a4
--- /dev/null
+++ b/src/hotspot/share/cds/archiveHeapLoader.cpp
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2018, 2022, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "cds/archiveHeapLoader.inline.hpp"
+#include "cds/filemap.hpp"
+#include "cds/heapShared.hpp"
+#include "cds/metaspaceShared.hpp"
+#include "classfile/classLoaderDataShared.hpp"
+#include "classfile/systemDictionaryShared.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "logging/log.hpp"
+#include "memory/iterator.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
+#include "utilities/bitMap.inline.hpp"
+#include "utilities/copy.hpp"
+
+#if INCLUDE_CDS_JAVA_HEAP
+
+bool ArchiveHeapLoader::_closed_regions_mapped = false;
+bool ArchiveHeapLoader::_open_regions_mapped = false;
+bool ArchiveHeapLoader::_is_loaded = false;
+address ArchiveHeapLoader::_narrow_oop_base;
+int     ArchiveHeapLoader::_narrow_oop_shift;
+
+// Support for loaded heap.
+uintptr_t ArchiveHeapLoader::_loaded_heap_bottom = 0;
+uintptr_t ArchiveHeapLoader::_loaded_heap_top = 0;
+uintptr_t ArchiveHeapLoader::_dumptime_base_0 = UINTPTR_MAX;
+uintptr_t ArchiveHeapLoader::_dumptime_base_1 = UINTPTR_MAX;
+uintptr_t ArchiveHeapLoader::_dumptime_base_2 = UINTPTR_MAX;
+uintptr_t ArchiveHeapLoader::_dumptime_base_3 = UINTPTR_MAX;
+uintptr_t ArchiveHeapLoader::_dumptime_top    = 0;
+intx ArchiveHeapLoader::_runtime_offset_0 = 0;
+intx ArchiveHeapLoader::_runtime_offset_1 = 0;
+intx ArchiveHeapLoader::_runtime_offset_2 = 0;
+intx ArchiveHeapLoader::_runtime_offset_3 = 0;
+bool ArchiveHeapLoader::_loading_failed = false;
+
+// Support for mapped heap (!UseCompressedOops only)
+ptrdiff_t ArchiveHeapLoader::_runtime_delta = 0;
+
+void ArchiveHeapLoader::init_narrow_oop_decoding(address base, int shift) {
+  _narrow_oop_base = base;
+  _narrow_oop_shift = shift;
+}
+
+void ArchiveHeapLoader::fixup_regions() {
+  FileMapInfo* mapinfo = FileMapInfo::current_info();
+  if (is_mapped()) {
+    mapinfo->fixup_mapped_heap_regions();
+  } else if (_loading_failed) {
+    fill_failed_loaded_region();
+  }
+  if (is_fully_available()) {
+    if (!MetaspaceShared::use_full_module_graph()) {
+      // Need to remove all the archived java.lang.Module objects from HeapShared::roots().
+      ClassLoaderDataShared::clear_archived_oops();
+    }
+  }
+  SystemDictionaryShared::update_archived_mirror_native_pointers();
+}
+
+// ------------------ Support for Region MAPPING -----------------------------------------
+
+// Patch all the embedded oop pointers inside an archived heap region,
+// to be consistent with the runtime oop encoding.
+class PatchCompressedEmbeddedPointers: public BitMapClosure {
+  narrowOop* _start;
+
+ public:
+  PatchCompressedEmbeddedPointers(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 = ArchiveHeapLoader::decode_from_archive(v);
+    RawAccess<IS_NOT_NULL>::oop_store(p, o);
+    return true;
+  }
+};
+
+class PatchUncompressedEmbeddedPointers: public BitMapClosure {
+  oop* _start;
+
+ public:
+  PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {}
+
+  bool do_bit(size_t offset) {
+    oop* p = _start + offset;
+    intptr_t dumptime_oop = (intptr_t)((void*)*p);
+    assert(dumptime_oop != 0, "null oops should have been filtered out at dump time");
+    intptr_t runtime_oop = dumptime_oop + ArchiveHeapLoader::runtime_delta();
+    RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(runtime_oop));
+    return true;
+  }
+};
+
+// Patch all the non-null pointers that are embedded in the archived heap objects
+// in this (mapped) region
+void ArchiveHeapLoader::patch_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 = HeapShared::calculate_oopmap(region);
+  assert(bm.is_same(checkBm), "sanity");
+#endif
+
+  if (UseCompressedOops) {
+    PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
+    bm.iterate(&patcher);
+  } else {
+    PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
+    bm.iterate(&patcher);
+  }
+}
+
+// ------------------ Support for Region LOADING -----------------------------------------
+
+// The CDS archive remembers each heap object by its address at dump time, but
+// the heap object may be loaded at a different address at run time. This structure is used
+// to translate the dump time addresses for all objects in FileMapInfo::space_at(region_index)
+// to their runtime addresses.
+struct LoadedArchiveHeapRegion {
+  int       _region_index;   // index for FileMapInfo::space_at(index)
+  size_t    _region_size;    // number of bytes in this region
+  uintptr_t _dumptime_base;  // The dump-time (decoded) address of the first object in this region
+  intx      _runtime_offset; // If an object's dump time address P is within in this region, its
+                             // runtime address is P + _runtime_offset
+
+  static int comparator(const void* a, const void* b) {
+    LoadedArchiveHeapRegion* reg_a = (LoadedArchiveHeapRegion*)a;
+    LoadedArchiveHeapRegion* reg_b = (LoadedArchiveHeapRegion*)b;
+    if (reg_a->_dumptime_base < reg_b->_dumptime_base) {
+      return -1;
+    } else if (reg_a->_dumptime_base == reg_b->_dumptime_base) {
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  uintptr_t top() {
+    return _dumptime_base + _region_size;
+  }
+};
+
+void ArchiveHeapLoader::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loaded_regions,
+                                             int num_loaded_regions) {
+  _dumptime_base_0 = loaded_regions[0]._dumptime_base;
+  _dumptime_base_1 = loaded_regions[1]._dumptime_base;
+  _dumptime_base_2 = loaded_regions[2]._dumptime_base;
+  _dumptime_base_3 = loaded_regions[3]._dumptime_base;
+  _dumptime_top = loaded_regions[num_loaded_regions-1].top();
+
+  _runtime_offset_0 = loaded_regions[0]._runtime_offset;
+  _runtime_offset_1 = loaded_regions[1]._runtime_offset;
+  _runtime_offset_2 = loaded_regions[2]._runtime_offset;
+  _runtime_offset_3 = loaded_regions[3]._runtime_offset;
+
+  assert(2 <= num_loaded_regions && num_loaded_regions <= 4, "must be");
+  if (num_loaded_regions < 4) {
+    _dumptime_base_3 = UINTPTR_MAX;
+  }
+  if (num_loaded_regions < 3) {
+    _dumptime_base_2 = UINTPTR_MAX;
+  }
+}
+
+bool ArchiveHeapLoader::can_load() {
+  return Universe::heap()->can_load_archived_objects();
+}
+
+template <int NUM_LOADED_REGIONS>
+class PatchLoadedRegionPointers: public BitMapClosure {
+  narrowOop* _start;
+  intx _offset_0;
+  intx _offset_1;
+  intx _offset_2;
+  intx _offset_3;
+  uintptr_t _base_0;
+  uintptr_t _base_1;
+  uintptr_t _base_2;
+  uintptr_t _base_3;
+  uintptr_t _top;
+
+  static_assert(MetaspaceShared::max_num_heap_regions == 4, "can't handle more than 4 regions");
+  static_assert(NUM_LOADED_REGIONS >= 2, "we have at least 2 loaded regions");
+  static_assert(NUM_LOADED_REGIONS <= 4, "we have at most 4 loaded regions");
+
+ public:
+  PatchLoadedRegionPointers(narrowOop* start, LoadedArchiveHeapRegion* loaded_regions)
+    : _start(start),
+      _offset_0(loaded_regions[0]._runtime_offset),
+      _offset_1(loaded_regions[1]._runtime_offset),
+      _offset_2(loaded_regions[2]._runtime_offset),
+      _offset_3(loaded_regions[3]._runtime_offset),
+      _base_0(loaded_regions[0]._dumptime_base),
+      _base_1(loaded_regions[1]._dumptime_base),
+      _base_2(loaded_regions[2]._dumptime_base),
+      _base_3(loaded_regions[3]._dumptime_base) {
+    _top = loaded_regions[NUM_LOADED_REGIONS-1].top();
+  }
+
+  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");
+    uintptr_t o = cast_from_oop<uintptr_t>(ArchiveHeapLoader::decode_from_archive(v));
+    assert(_base_0 <= o && o < _top, "must be");
+
+
+    // We usually have only 2 regions for the default archive. Use template to avoid unnecessary comparisons.
+    if (NUM_LOADED_REGIONS > 3 && o >= _base_3) {
+      o += _offset_3;
+    } else if (NUM_LOADED_REGIONS > 2 && o >= _base_2) {
+      o += _offset_2;
+    } else if (o >= _base_1) {
+      o += _offset_1;
+    } else {
+      o += _offset_0;
+    }
+    ArchiveHeapLoader::assert_in_loaded_heap(o);
+    RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(o));
+    return true;
+  }
+};
+
+int ArchiveHeapLoader::init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
+                                           MemRegion& archive_space) {
+  size_t total_bytes = 0;
+  int num_loaded_regions = 0;
+  for (int i = MetaspaceShared::first_archive_heap_region;
+       i <= MetaspaceShared::last_archive_heap_region; i++) {
+    FileMapRegion* r = mapinfo->space_at(i);
+    r->assert_is_heap_region();
+    if (r->used() > 0) {
+      assert(is_aligned(r->used(), HeapWordSize), "must be");
+      total_bytes += r->used();
+      LoadedArchiveHeapRegion* ri = &loaded_regions[num_loaded_regions++];
+      ri->_region_index = i;
+      ri->_region_size = r->used();
+      ri->_dumptime_base = (uintptr_t)mapinfo->start_address_as_decoded_from_archive(r);
+    }
+  }
+
+  assert(is_aligned(total_bytes, HeapWordSize), "must be");
+  size_t word_size = total_bytes / HeapWordSize;
+  HeapWord* buffer = Universe::heap()->allocate_loaded_archive_space(word_size);
+  if (buffer == nullptr) {
+    return 0;
+  }
+
+  archive_space = MemRegion(buffer, word_size);
+  _loaded_heap_bottom = (uintptr_t)archive_space.start();
+  _loaded_heap_top    = _loaded_heap_bottom + total_bytes;
+
+  return num_loaded_regions;
+}
+
+void ArchiveHeapLoader::sort_loaded_regions(LoadedArchiveHeapRegion* loaded_regions, int num_loaded_regions,
+                                            uintptr_t buffer) {
+  // Find the relocation offset of the pointers in each region
+  qsort(loaded_regions, num_loaded_regions, sizeof(LoadedArchiveHeapRegion),
+        LoadedArchiveHeapRegion::comparator);
+
+  uintptr_t p = buffer;
+  for (int i = 0; i < num_loaded_regions; i++) {
+    // This region will be loaded at p, so all objects inside this
+    // region will be shifted by ri->offset
+    LoadedArchiveHeapRegion* ri = &loaded_regions[i];
+    ri->_runtime_offset = p - ri->_dumptime_base;
+    p += ri->_region_size;
+  }
+  assert(p == _loaded_heap_top, "must be");
+}
+
+bool ArchiveHeapLoader::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
+                                     int num_loaded_regions, uintptr_t buffer) {
+  uintptr_t bitmap_base = (uintptr_t)mapinfo->map_bitmap_region();
+  if (bitmap_base == 0) {
+    _loading_failed = true;
+    return false; // OOM or CRC error
+  }
+  uintptr_t load_address = buffer;
+  for (int i = 0; i < num_loaded_regions; i++) {
+    LoadedArchiveHeapRegion* ri = &loaded_regions[i];
+    FileMapRegion* r = mapinfo->space_at(ri->_region_index);
+
+    if (!mapinfo->read_region(ri->_region_index, (char*)load_address, r->used(), /* do_commit = */ false)) {
+      // There's no easy way to free the buffer, so we will fill it with zero later
+      // in fill_failed_loaded_region(), and it will eventually be GC'ed.
+      log_warning(cds)("Loading of heap region %d has failed. Archived objects are disabled", i);
+      _loading_failed = true;
+      return false;
+    }
+    log_info(cds)("Loaded heap    region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT
+                  " size " SIZE_FORMAT_W(6) " delta " INTX_FORMAT,
+                  ri->_region_index, load_address, load_address + ri->_region_size,
+                  ri->_region_size, ri->_runtime_offset);
+
+    uintptr_t oopmap = bitmap_base + r->oopmap_offset();
+    BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
+
+    if (num_loaded_regions == 4) {
+      PatchLoadedRegionPointers<4> patcher((narrowOop*)load_address, loaded_regions);
+      bm.iterate(&patcher);
+    } else if (num_loaded_regions == 3) {
+      PatchLoadedRegionPointers<3> patcher((narrowOop*)load_address, loaded_regions);
+      bm.iterate(&patcher);
+    } else {
+      assert(num_loaded_regions == 2, "must be");
+      PatchLoadedRegionPointers<2> patcher((narrowOop*)load_address, loaded_regions);
+      bm.iterate(&patcher);
+    }
+
+    load_address += r->used();
+  }
+
+  return true;
+}
+
+bool ArchiveHeapLoader::load_heap_regions(FileMapInfo* mapinfo) {
+  init_narrow_oop_decoding(mapinfo->narrow_oop_base(), mapinfo->narrow_oop_shift());
+
+  LoadedArchiveHeapRegion loaded_regions[MetaspaceShared::max_num_heap_regions];
+  memset(loaded_regions, 0, sizeof(loaded_regions));
+
+  MemRegion archive_space;
+  int num_loaded_regions = init_loaded_regions(mapinfo, loaded_regions, archive_space);
+  if (num_loaded_regions <= 0) {
+    return false;
+  }
+  sort_loaded_regions(loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start());
+  if (!load_regions(mapinfo, loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start())) {
+    assert(_loading_failed, "must be");
+    return false;
+  }
+
+  init_loaded_heap_relocation(loaded_regions, num_loaded_regions);
+  _is_loaded = true;
+
+  return true;
+}
+
+class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure {
+  ResourceHashtable<uintptr_t, bool>* _table;
+
+ public:
+  VerifyLoadedHeapEmbeddedPointers(ResourceHashtable<uintptr_t, bool>* table) : _table(table) {}
+
+  virtual void do_oop(narrowOop* p) {
+    // This should be called before the loaded regions are modified, so all the embedded pointers
+    // must be NULL, or must point to a valid object in the loaded regions.
+    narrowOop v = *p;
+    if (!CompressedOops::is_null(v)) {
+      oop o = CompressedOops::decode_not_null(v);
+      uintptr_t u = cast_from_oop<uintptr_t>(o);
+      ArchiveHeapLoader::assert_in_loaded_heap(u);
+      guarantee(_table->contains(u), "must point to beginning of object in loaded archived regions");
+    }
+  }
+  virtual void do_oop(oop* p) {
+    ShouldNotReachHere();
+  }
+};
+
+void ArchiveHeapLoader::finish_initialization() {
+  if (is_loaded()) {
+    HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
+    HeapWord* top    = (HeapWord*)_loaded_heap_top;
+
+    MemRegion archive_space = MemRegion(bottom, top);
+    Universe::heap()->complete_loaded_archive_space(archive_space);
+  }
+
+  if (VerifyArchivedFields <= 0 || !is_loaded()) {
+    return;
+  }
+
+  log_info(cds, heap)("Verify all oops and pointers in loaded heap");
+
+  ResourceMark rm;
+  ResourceHashtable<uintptr_t, bool> table;
+  VerifyLoadedHeapEmbeddedPointers verifier(&table);
+  HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
+  HeapWord* top    = (HeapWord*)_loaded_heap_top;
+
+  for (HeapWord* p = bottom; p < top; ) {
+    oop o = cast_to_oop(p);
+    table.put(cast_from_oop<uintptr_t>(o), true);
+    p += o->size();
+  }
+
+  for (HeapWord* p = bottom; p < top; ) {
+    oop o = cast_to_oop(p);
+    o->oop_iterate(&verifier);
+    p += o->size();
+  }
+}
+
+void ArchiveHeapLoader::fill_failed_loaded_region() {
+  assert(_loading_failed, "must be");
+  if (_loaded_heap_bottom != 0) {
+    assert(_loaded_heap_top != 0, "must be");
+    HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
+    HeapWord* top = (HeapWord*)_loaded_heap_top;
+    Universe::heap()->fill_with_objects(bottom, top - bottom);
+  }
+}
+
+#endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/archiveHeapLoader.hpp b/src/hotspot/share/cds/archiveHeapLoader.hpp
new file mode 100644
index 00000000000..890ec1c57c1
--- /dev/null
+++ b/src/hotspot/share/cds/archiveHeapLoader.hpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2018, 2022, 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_CDS_ARCHIVEHEAPLOADER_HPP
+#define SHARE_CDS_ARCHIVEHEAPLOADER_HPP
+
+#include "gc/shared/gc_globals.hpp"
+#include "memory/allocation.hpp"
+#include "memory/allStatic.hpp"
+#include "runtime/globals.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "memory/memRegion.hpp"
+#include "utilities/macros.hpp"
+
+class  FileMapInfo;
+struct LoadedArchiveHeapRegion;
+
+class ArchiveHeapLoader : AllStatic {
+public:
+  // At runtime, heap regions in the CDS archive can be used in two different ways,
+  // depending on the GC type:
+  // - Mapped: (G1 only) the regions are directly mapped into the Java heap
+  // - Loaded: At VM start-up, the objects in the heap regions are copied into the
+  //           Java heap. This is easier to implement than mapping but
+  //           slightly less efficient, as the embedded pointers need to be relocated.
+  static bool can_use() { return can_map() || can_load(); }
+
+  // Can this VM map archived heap regions? Currently only G1+compressed{oops,cp}
+  static bool can_map() {
+    CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);)
+    NOT_CDS_JAVA_HEAP(return false;)
+  }
+  static bool is_mapped() {
+    return closed_regions_mapped() && open_regions_mapped();
+  }
+
+  // Can this VM load the objects from archived heap regions into the heap at start-up?
+  static bool can_load()  NOT_CDS_JAVA_HEAP_RETURN_(false);
+  static void finish_initialization() NOT_CDS_JAVA_HEAP_RETURN;
+  static bool is_loaded() {
+    CDS_JAVA_HEAP_ONLY(return _is_loaded;)
+    NOT_CDS_JAVA_HEAP(return false;)
+  }
+
+  static bool are_archived_strings_available() {
+    return is_loaded() || closed_regions_mapped();
+  }
+  static bool are_archived_mirrors_available() {
+    return is_fully_available();
+  }
+  static bool is_fully_available() {
+    return is_loaded() || is_mapped();
+  }
+
+  static ptrdiff_t runtime_delta() {
+    assert(!UseCompressedOops, "must be");
+    CDS_JAVA_HEAP_ONLY(return _runtime_delta;)
+    NOT_CDS_JAVA_HEAP_RETURN_(0L);
+  }
+
+  static void set_closed_regions_mapped() {
+    CDS_JAVA_HEAP_ONLY(_closed_regions_mapped = true;)
+    NOT_CDS_JAVA_HEAP_RETURN;
+  }
+  static bool closed_regions_mapped() {
+    CDS_JAVA_HEAP_ONLY(return _closed_regions_mapped;)
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+  static void set_open_regions_mapped() {
+    CDS_JAVA_HEAP_ONLY(_open_regions_mapped = true;)
+    NOT_CDS_JAVA_HEAP_RETURN;
+  }
+  static bool open_regions_mapped() {
+    CDS_JAVA_HEAP_ONLY(return _open_regions_mapped;)
+    NOT_CDS_JAVA_HEAP_RETURN_(false);
+  }
+
+  // NarrowOops stored in the CDS archive may use a different encoding scheme
+  // than CompressedOops::{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_from_archive(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_embedded_pointers(MemRegion region, address oopmap,
+                                      size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
+
+  static void fixup_regions() NOT_CDS_JAVA_HEAP_RETURN;
+
+#if INCLUDE_CDS_JAVA_HEAP
+private:
+  static bool _closed_regions_mapped;
+  static bool _open_regions_mapped;
+  static bool _is_loaded;
+
+  // Support for loaded archived heap. These are cached values from
+  // LoadedArchiveHeapRegion's.
+  static uintptr_t _dumptime_base_0;
+  static uintptr_t _dumptime_base_1;
+  static uintptr_t _dumptime_base_2;
+  static uintptr_t _dumptime_base_3;
+  static uintptr_t _dumptime_top;
+  static intx _runtime_offset_0;
+  static intx _runtime_offset_1;
+  static intx _runtime_offset_2;
+  static intx _runtime_offset_3;
+
+  static uintptr_t _loaded_heap_bottom;
+  static uintptr_t _loaded_heap_top;
+  static bool _loading_failed;
+
+  // UseCompressedOops only: Used by decode_from_archive
+  static address _narrow_oop_base;
+  static int     _narrow_oop_shift;
+
+  // !UseCompressedOops only: used to relocate pointers to the archived objects
+  static ptrdiff_t _runtime_delta;
+
+  static int init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
+                                 MemRegion& archive_space);
+  static void sort_loaded_regions(LoadedArchiveHeapRegion* loaded_regions, int num_loaded_regions,
+                                  uintptr_t buffer);
+  static bool load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
+                           int num_loaded_regions, uintptr_t buffer);
+  static void init_loaded_heap_relocation(LoadedArchiveHeapRegion* reloc_info,
+                                          int num_loaded_regions);
+  static void fill_failed_loaded_region();
+
+  static bool is_in_loaded_heap(uintptr_t o) {
+    return (_loaded_heap_bottom <= o && o < _loaded_heap_top);
+  }
+
+public:
+
+  static bool load_heap_regions(FileMapInfo* mapinfo);
+  static void assert_in_loaded_heap(uintptr_t o) {
+    assert(is_in_loaded_heap(o), "must be");
+  }
+
+  static void set_runtime_delta(ptrdiff_t delta) {
+    assert(!UseCompressedOops, "must be");
+    _runtime_delta = delta;
+  }
+#endif // INCLUDE_CDS_JAVA_HEAP
+
+};
+
+#endif // SHARE_CDS_ARCHIVEHEAPLOADER_HPP
diff --git a/src/hotspot/share/cds/heapShared.inline.hpp b/src/hotspot/share/cds/archiveHeapLoader.inline.hpp
similarity index 85%
rename from src/hotspot/share/cds/heapShared.inline.hpp
rename to src/hotspot/share/cds/archiveHeapLoader.inline.hpp
index 25f53aa0288..52346c8c90e 100644
--- a/src/hotspot/share/cds/heapShared.inline.hpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2022, 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
@@ -22,16 +22,17 @@
  *
  */
 
-#ifndef SHARE_CDS_HEAPSHARED_INLINE_HPP
-#define SHARE_CDS_HEAPSHARED_INLINE_HPP
+#ifndef SHARE_CDS_ARCHIVEHEAPLOADER_INLINE_HPP
+#define SHARE_CDS_ARCHIVEHEAPLOADER_INLINE_HPP
+
+#include "cds/archiveHeapLoader.hpp"
 
-#include "cds/heapShared.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "utilities/align.hpp"
 
 #if INCLUDE_CDS_JAVA_HEAP
 
-inline oop HeapShared::decode_from_archive(narrowOop v) {
+inline oop ArchiveHeapLoader::decode_from_archive(narrowOop v) {
   assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
   uintptr_t p = ((uintptr_t)_narrow_oop_base) + ((uintptr_t)v << _narrow_oop_shift);
   if (p >= _dumptime_base_0) {
@@ -54,4 +55,4 @@ inline oop HeapShared::decode_from_archive(narrowOop v) {
 
 #endif
 
-#endif // SHARE_CDS_HEAPSHARED_INLINE_HPP
+#endif // SHARE_CDS_ARCHIVEHEAPLOADER_INLINE_HPP
diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
index 971fef4fd4e..d1de6885291 100644
--- a/src/hotspot/share/cds/archiveUtils.cpp
+++ b/src/hotspot/share/cds/archiveUtils.cpp
@@ -24,12 +24,13 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.inline.hpp"
 #include "cds/archiveUtils.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/vmClasses.hpp"
@@ -315,19 +316,19 @@ void ReadClosure::do_tag(int tag) {
 void ReadClosure::do_oop(oop *p) {
   if (UseCompressedOops) {
     narrowOop o = CompressedOops::narrow_oop_cast(nextPtr());
-    if (CompressedOops::is_null(o) || !HeapShared::is_fully_available()) {
+    if (CompressedOops::is_null(o) || !ArchiveHeapLoader::is_fully_available()) {
       *p = NULL;
     } else {
-      assert(HeapShared::can_use(), "sanity");
-      assert(HeapShared::is_fully_available(), "must be");
-      *p = HeapShared::decode_from_archive(o);
+      assert(ArchiveHeapLoader::can_use(), "sanity");
+      assert(ArchiveHeapLoader::is_fully_available(), "must be");
+      *p = ArchiveHeapLoader::decode_from_archive(o);
     }
   } else {
     intptr_t dumptime_oop = nextPtr();
-    if (dumptime_oop == 0 || !HeapShared::is_fully_available()) {
+    if (dumptime_oop == 0 || !ArchiveHeapLoader::is_fully_available()) {
       *p = NULL;
     } else {
-      intptr_t runtime_oop = dumptime_oop + HeapShared::runtime_delta();
+      intptr_t runtime_oop = dumptime_oop + ArchiveHeapLoader::runtime_delta();
       *p = cast_to_oop(runtime_oop);
     }
   }
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index a5672f75375..f0a5d3c66ae 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -25,11 +25,12 @@
 #include "precompiled.hpp"
 #include "jvm.h"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.inline.hpp"
 #include "cds/archiveUtils.inline.hpp"
 #include "cds/cds_globals.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/altHashing.hpp"
 #include "classfile/classFileStream.hpp"
@@ -1970,7 +1971,7 @@ address FileMapInfo::decode_start_address(FileMapRegion* spc, bool with_current_
   if (with_current_oop_encoding_mode) {
     return cast_from_oop<address>(CompressedOops::decode_raw_not_null(n));
   } else {
-    return cast_from_oop<address>(HeapShared::decode_from_archive(n));
+    return cast_from_oop<address>(ArchiveHeapLoader::decode_from_archive(n));
   }
 }
 
@@ -2016,10 +2017,10 @@ void FileMapInfo::map_or_load_heap_regions() {
   bool success = false;
 
   if (can_use_heap_regions()) {
-    if (HeapShared::can_map()) {
+    if (ArchiveHeapLoader::can_map()) {
       success = map_heap_regions();
-    } else if (HeapShared::can_load()) {
-      success = HeapShared::load_heap_regions(this);
+    } else if (ArchiveHeapLoader::can_load()) {
+      success = ArchiveHeapLoader::load_heap_regions(this);
     } else {
       log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC or UseParallelGC are required.");
     }
@@ -2085,15 +2086,15 @@ address FileMapInfo::heap_region_runtime_start_address(FileMapRegion* spc) {
     return start_address_as_decoded_from_archive(spc);
   } else {
     assert(is_aligned(spc->mapping_offset(), sizeof(HeapWord)), "must be");
-    return header()->heap_begin() + spc->mapping_offset() + HeapShared::runtime_delta();
+    return header()->heap_begin() + spc->mapping_offset() + ArchiveHeapLoader::runtime_delta();
   }
 }
 
 void FileMapInfo::set_shared_heap_runtime_delta(ptrdiff_t delta) {
   if (UseCompressedOops) {
-    HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+    ArchiveHeapLoader::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
   } else {
-    HeapShared::set_runtime_delta(delta);
+    ArchiveHeapLoader::set_runtime_delta(delta);
   }
 }
 
@@ -2209,14 +2210,14 @@ void FileMapInfo::map_heap_regions_impl() {
                        MetaspaceShared::max_num_closed_heap_regions,
                        /*is_open_archive=*/ false,
                        &closed_heap_regions, &num_closed_heap_regions)) {
-    HeapShared::set_closed_regions_mapped();
+    ArchiveHeapLoader::set_closed_regions_mapped();
 
     // Now, map the open heap regions: GC can write into these regions.
     if (map_heap_regions(MetaspaceShared::first_open_heap_region,
                          MetaspaceShared::max_num_open_heap_regions,
                          /*is_open_archive=*/ true,
                          &open_heap_regions, &num_open_heap_regions)) {
-      HeapShared::set_open_regions_mapped();
+      ArchiveHeapLoader::set_open_regions_mapped();
     }
   }
 }
@@ -2224,12 +2225,12 @@ void FileMapInfo::map_heap_regions_impl() {
 bool FileMapInfo::map_heap_regions() {
   map_heap_regions_impl();
 
-  if (!HeapShared::closed_regions_mapped()) {
+  if (!ArchiveHeapLoader::closed_regions_mapped()) {
     assert(closed_heap_regions == NULL &&
            num_closed_heap_regions == 0, "sanity");
   }
 
-  if (!HeapShared::open_regions_mapped()) {
+  if (!ArchiveHeapLoader::open_regions_mapped()) {
     assert(open_heap_regions == NULL && num_open_heap_regions == 0, "sanity");
     return false;
   } else {
@@ -2336,7 +2337,7 @@ void FileMapInfo::patch_heap_embedded_pointers(MemRegion* regions, int num_regio
   assert(bitmap_base != NULL, "must have already been mapped");
   for (int i=0; i<num_regions; i++) {
     FileMapRegion* si = space_at(i + first_region_idx);
-    HeapShared::patch_embedded_pointers(
+    ArchiveHeapLoader::patch_embedded_pointers(
       regions[i],
       (address)(space_at(MetaspaceShared::bm)->mapped_base()) + si->oopmap_offset(),
       si->oopmap_size_in_bits());
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 9899523264b..59f2cb5ce04 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -24,10 +24,10 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveUtils.hpp"
 #include "cds/cdsHeapVerifier.hpp"
-#include "cds/filemap.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/classLoaderDataShared.hpp"
@@ -45,8 +45,6 @@
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/iterator.inline.hpp"
-#include "memory/metadataFactory.hpp"
-#include "memory/metaspaceClosure.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/compressedOops.inline.hpp"
@@ -56,9 +54,7 @@
 #include "oops/typeArrayOop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
-#include "runtime/globals_extension.hpp"
 #include "runtime/init.hpp"
-#include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/safepointVerifiers.hpp"
 #include "utilities/bitMap.inline.hpp"
@@ -69,31 +65,9 @@
 
 #if INCLUDE_CDS_JAVA_HEAP
 
-bool HeapShared::_closed_regions_mapped = false;
-bool HeapShared::_open_regions_mapped = false;
-bool HeapShared::_is_loaded = false;
 bool HeapShared::_disable_writing = false;
-address   HeapShared::_narrow_oop_base;
-int       HeapShared::_narrow_oop_shift;
 DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
 
-// Support for loaded heap.
-uintptr_t HeapShared::_loaded_heap_bottom = 0;
-uintptr_t HeapShared::_loaded_heap_top = 0;
-uintptr_t HeapShared::_dumptime_base_0 = UINTPTR_MAX;
-uintptr_t HeapShared::_dumptime_base_1 = UINTPTR_MAX;
-uintptr_t HeapShared::_dumptime_base_2 = UINTPTR_MAX;
-uintptr_t HeapShared::_dumptime_base_3 = UINTPTR_MAX;
-uintptr_t HeapShared::_dumptime_top    = 0;
-intx HeapShared::_runtime_offset_0 = 0;
-intx HeapShared::_runtime_offset_1 = 0;
-intx HeapShared::_runtime_offset_2 = 0;
-intx HeapShared::_runtime_offset_3 = 0;
-bool HeapShared::_loading_failed = false;
-
-// Support for mapped heap (!UseCompressedOops only)
-ptrdiff_t HeapShared::_runtime_delta = 0;
-
 //
 // If you add new entries to the following tables, you should know what you're doing!
 //
@@ -162,22 +136,6 @@ bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) {
                                    num_fmg_open_archive_subgraph_entry_fields, ik);
 }
 
-void HeapShared::fixup_regions() {
-  FileMapInfo* mapinfo = FileMapInfo::current_info();
-  if (is_mapped()) {
-    mapinfo->fixup_mapped_heap_regions();
-  } else if (_loading_failed) {
-    fill_failed_loaded_region();
-  }
-  if (is_fully_available()) {
-    if (!MetaspaceShared::use_full_module_graph()) {
-      // Need to remove all the archived java.lang.Module objects from HeapShared::roots().
-      ClassLoaderDataShared::clear_archived_oops();
-    }
-  }
-  SystemDictionaryShared::update_archived_mirror_native_pointers();
-}
-
 unsigned HeapShared::oop_hash(oop const& p) {
   // Do not call p->identity_hash() as that will update the
   // object header.
@@ -293,7 +251,7 @@ oop HeapShared::get_root(int index, bool clear) {
 void HeapShared::clear_root(int index) {
   assert(index >= 0, "sanity");
   assert(UseSharedSpaces, "must be");
-  if (is_fully_available()) {
+  if (ArchiveHeapLoader::is_fully_available()) {
     if (log_is_enabled(Debug, cds, heap)) {
       oop old = roots()->obj_at(index);
       log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old));
@@ -438,7 +396,7 @@ void HeapShared::check_enum_obj(int level,
 
 // See comments in HeapShared::check_enum_obj()
 bool HeapShared::initialize_enum_klass(InstanceKlass* k, TRAPS) {
-  if (!is_fully_available()) {
+  if (!ArchiveHeapLoader::is_fully_available()) {
     return false;
   }
 
@@ -585,11 +543,6 @@ void HeapShared::copy_roots() {
   log_info(cds)("archived obj roots[%d] = " SIZE_FORMAT " words, klass = %p, obj = %p", length, size, k, mem);
 }
 
-void HeapShared::init_narrow_oop_decoding(address base, int shift) {
-  _narrow_oop_base = base;
-  _narrow_oop_shift = shift;
-}
-
 //
 // Subgraph archiving support
 //
@@ -810,7 +763,7 @@ void HeapShared::serialize(SerializeClosure* soc) {
     assert(oopDesc::is_oop_or_null(roots_oop), "is oop");
     // Create an OopHandle only if we have actually mapped or loaded the roots
     if (roots_oop != NULL) {
-      assert(HeapShared::is_fully_available(), "must be");
+      assert(ArchiveHeapLoader::is_fully_available(), "must be");
       _roots = OopHandle(Universe::vm_global(), roots_oop);
     }
   } else {
@@ -856,7 +809,7 @@ static void verify_the_heap(Klass* k, const char* which) {
 // ClassFileLoadHook is enabled, it's possible for this class to be dynamically replaced. In
 // this case, we will not load the ArchivedKlassSubGraphInfoRecord and will clear its roots.
 void HeapShared::resolve_classes(JavaThread* THREAD) {
-  if (!is_fully_available()) {
+  if (!ArchiveHeapLoader::is_fully_available()) {
     return; // nothing to do
   }
   resolve_classes_for_subgraphs(closed_archive_subgraph_entry_fields,
@@ -894,7 +847,7 @@ void HeapShared::resolve_classes_for_subgraph_of(Klass* k, JavaThread* THREAD) {
 }
 
 void HeapShared::initialize_from_archived_subgraph(Klass* k, JavaThread* THREAD) {
-  if (!is_fully_available()) {
+  if (!ArchiveHeapLoader::is_fully_available()) {
     return; // nothing to do
   }
 
@@ -1663,351 +1616,4 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
   return oopmap;
 }
 
-// Patch all the embedded oop pointers inside an archived heap region,
-// to be consistent with the runtime oop encoding.
-class PatchCompressedEmbeddedPointers: public BitMapClosure {
-  narrowOop* _start;
-
- public:
-  PatchCompressedEmbeddedPointers(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_from_archive(v);
-    RawAccess<IS_NOT_NULL>::oop_store(p, o);
-    return true;
-  }
-};
-
-class PatchUncompressedEmbeddedPointers: public BitMapClosure {
-  oop* _start;
-
- public:
-  PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {}
-
-  bool do_bit(size_t offset) {
-    oop* p = _start + offset;
-    intptr_t dumptime_oop = (intptr_t)((void*)*p);
-    assert(dumptime_oop != 0, "null oops should have been filtered out at dump time");
-    intptr_t runtime_oop = dumptime_oop + HeapShared::runtime_delta();
-    RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(runtime_oop));
-    return true;
-  }
-};
-
-// Patch all the non-null pointers that are embedded in the archived heap objects
-// in this region
-void HeapShared::patch_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
-
-  if (UseCompressedOops) {
-    PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
-    bm.iterate(&patcher);
-  } else {
-    PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
-    bm.iterate(&patcher);
-  }
-}
-
-// The CDS archive remembers each heap object by its address at dump time, but
-// the heap object may be loaded at a different address at run time. This structure is used
-// to translate the dump time addresses for all objects in FileMapInfo::space_at(region_index)
-// to their runtime addresses.
-struct LoadedArchiveHeapRegion {
-  int       _region_index;   // index for FileMapInfo::space_at(index)
-  size_t    _region_size;    // number of bytes in this region
-  uintptr_t _dumptime_base;  // The dump-time (decoded) address of the first object in this region
-  intx      _runtime_offset; // If an object's dump time address P is within in this region, its
-                             // runtime address is P + _runtime_offset
-
-  static int comparator(const void* a, const void* b) {
-    LoadedArchiveHeapRegion* reg_a = (LoadedArchiveHeapRegion*)a;
-    LoadedArchiveHeapRegion* reg_b = (LoadedArchiveHeapRegion*)b;
-    if (reg_a->_dumptime_base < reg_b->_dumptime_base) {
-      return -1;
-    } else if (reg_a->_dumptime_base == reg_b->_dumptime_base) {
-      return 0;
-    } else {
-      return 1;
-    }
-  }
-
-  uintptr_t top() {
-    return _dumptime_base + _region_size;
-  }
-};
-
-void HeapShared::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loaded_regions,
-                                             int num_loaded_regions) {
-  _dumptime_base_0 = loaded_regions[0]._dumptime_base;
-  _dumptime_base_1 = loaded_regions[1]._dumptime_base;
-  _dumptime_base_2 = loaded_regions[2]._dumptime_base;
-  _dumptime_base_3 = loaded_regions[3]._dumptime_base;
-  _dumptime_top = loaded_regions[num_loaded_regions-1].top();
-
-  _runtime_offset_0 = loaded_regions[0]._runtime_offset;
-  _runtime_offset_1 = loaded_regions[1]._runtime_offset;
-  _runtime_offset_2 = loaded_regions[2]._runtime_offset;
-  _runtime_offset_3 = loaded_regions[3]._runtime_offset;
-
-  assert(2 <= num_loaded_regions && num_loaded_regions <= 4, "must be");
-  if (num_loaded_regions < 4) {
-    _dumptime_base_3 = UINTPTR_MAX;
-  }
-  if (num_loaded_regions < 3) {
-    _dumptime_base_2 = UINTPTR_MAX;
-  }
-}
-
-bool HeapShared::can_load() {
-  return Universe::heap()->can_load_archived_objects();
-}
-
-template <int NUM_LOADED_REGIONS>
-class PatchLoadedRegionPointers: public BitMapClosure {
-  narrowOop* _start;
-  intx _offset_0;
-  intx _offset_1;
-  intx _offset_2;
-  intx _offset_3;
-  uintptr_t _base_0;
-  uintptr_t _base_1;
-  uintptr_t _base_2;
-  uintptr_t _base_3;
-  uintptr_t _top;
-
-  static_assert(MetaspaceShared::max_num_heap_regions == 4, "can't handle more than 4 regions");
-  static_assert(NUM_LOADED_REGIONS >= 2, "we have at least 2 loaded regions");
-  static_assert(NUM_LOADED_REGIONS <= 4, "we have at most 4 loaded regions");
-
- public:
-  PatchLoadedRegionPointers(narrowOop* start, LoadedArchiveHeapRegion* loaded_regions)
-    : _start(start),
-      _offset_0(loaded_regions[0]._runtime_offset),
-      _offset_1(loaded_regions[1]._runtime_offset),
-      _offset_2(loaded_regions[2]._runtime_offset),
-      _offset_3(loaded_regions[3]._runtime_offset),
-      _base_0(loaded_regions[0]._dumptime_base),
-      _base_1(loaded_regions[1]._dumptime_base),
-      _base_2(loaded_regions[2]._dumptime_base),
-      _base_3(loaded_regions[3]._dumptime_base) {
-    _top = loaded_regions[NUM_LOADED_REGIONS-1].top();
-  }
-
-  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");
-    uintptr_t o = cast_from_oop<uintptr_t>(HeapShared::decode_from_archive(v));
-    assert(_base_0 <= o && o < _top, "must be");
-
-
-    // We usually have only 2 regions for the default archive. Use template to avoid unnecessary comparisons.
-    if (NUM_LOADED_REGIONS > 3 && o >= _base_3) {
-      o += _offset_3;
-    } else if (NUM_LOADED_REGIONS > 2 && o >= _base_2) {
-      o += _offset_2;
-    } else if (o >= _base_1) {
-      o += _offset_1;
-    } else {
-      o += _offset_0;
-    }
-    HeapShared::assert_in_loaded_heap(o);
-    RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(o));
-    return true;
-  }
-};
-
-int HeapShared::init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
-                                    MemRegion& archive_space) {
-  size_t total_bytes = 0;
-  int num_loaded_regions = 0;
-  for (int i = MetaspaceShared::first_archive_heap_region;
-       i <= MetaspaceShared::last_archive_heap_region; i++) {
-    FileMapRegion* r = mapinfo->space_at(i);
-    r->assert_is_heap_region();
-    if (r->used() > 0) {
-      assert(is_aligned(r->used(), HeapWordSize), "must be");
-      total_bytes += r->used();
-      LoadedArchiveHeapRegion* ri = &loaded_regions[num_loaded_regions++];
-      ri->_region_index = i;
-      ri->_region_size = r->used();
-      ri->_dumptime_base = (uintptr_t)mapinfo->start_address_as_decoded_from_archive(r);
-    }
-  }
-
-  assert(is_aligned(total_bytes, HeapWordSize), "must be");
-  size_t word_size = total_bytes / HeapWordSize;
-  HeapWord* buffer = Universe::heap()->allocate_loaded_archive_space(word_size);
-  if (buffer == nullptr) {
-    return 0;
-  }
-
-  archive_space = MemRegion(buffer, word_size);
-  _loaded_heap_bottom = (uintptr_t)archive_space.start();
-  _loaded_heap_top    = _loaded_heap_bottom + total_bytes;
-
-  return num_loaded_regions;
-}
-
-void HeapShared::sort_loaded_regions(LoadedArchiveHeapRegion* loaded_regions, int num_loaded_regions,
-                                     uintptr_t buffer) {
-  // Find the relocation offset of the pointers in each region
-  qsort(loaded_regions, num_loaded_regions, sizeof(LoadedArchiveHeapRegion),
-        LoadedArchiveHeapRegion::comparator);
-
-  uintptr_t p = buffer;
-  for (int i = 0; i < num_loaded_regions; i++) {
-    // This region will be loaded at p, so all objects inside this
-    // region will be shifted by ri->offset
-    LoadedArchiveHeapRegion* ri = &loaded_regions[i];
-    ri->_runtime_offset = p - ri->_dumptime_base;
-    p += ri->_region_size;
-  }
-  assert(p == _loaded_heap_top, "must be");
-}
-
-bool HeapShared::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions,
-                              int num_loaded_regions, uintptr_t buffer) {
-  uintptr_t bitmap_base = (uintptr_t)mapinfo->map_bitmap_region();
-  if (bitmap_base == 0) {
-    _loading_failed = true;
-    return false; // OOM or CRC error
-  }
-  uintptr_t load_address = buffer;
-  for (int i = 0; i < num_loaded_regions; i++) {
-    LoadedArchiveHeapRegion* ri = &loaded_regions[i];
-    FileMapRegion* r = mapinfo->space_at(ri->_region_index);
-
-    if (!mapinfo->read_region(ri->_region_index, (char*)load_address, r->used(), /* do_commit = */ false)) {
-      // There's no easy way to free the buffer, so we will fill it with zero later
-      // in fill_failed_loaded_region(), and it will eventually be GC'ed.
-      log_warning(cds)("Loading of heap region %d has failed. Archived objects are disabled", i);
-      _loading_failed = true;
-      return false;
-    }
-    log_info(cds)("Loaded heap    region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT
-                  " size " SIZE_FORMAT_W(6) " delta " INTX_FORMAT,
-                  ri->_region_index, load_address, load_address + ri->_region_size,
-                  ri->_region_size, ri->_runtime_offset);
-
-    uintptr_t oopmap = bitmap_base + r->oopmap_offset();
-    BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
-
-    if (num_loaded_regions == 4) {
-      PatchLoadedRegionPointers<4> patcher((narrowOop*)load_address, loaded_regions);
-      bm.iterate(&patcher);
-    } else if (num_loaded_regions == 3) {
-      PatchLoadedRegionPointers<3> patcher((narrowOop*)load_address, loaded_regions);
-      bm.iterate(&patcher);
-    } else {
-      assert(num_loaded_regions == 2, "must be");
-      PatchLoadedRegionPointers<2> patcher((narrowOop*)load_address, loaded_regions);
-      bm.iterate(&patcher);
-    }
-
-    load_address += r->used();
-  }
-
-  return true;
-}
-
-bool HeapShared::load_heap_regions(FileMapInfo* mapinfo) {
-  init_narrow_oop_decoding(mapinfo->narrow_oop_base(), mapinfo->narrow_oop_shift());
-
-  LoadedArchiveHeapRegion loaded_regions[MetaspaceShared::max_num_heap_regions];
-  memset(loaded_regions, 0, sizeof(loaded_regions));
-
-  MemRegion archive_space;
-  int num_loaded_regions = init_loaded_regions(mapinfo, loaded_regions, archive_space);
-  if (num_loaded_regions <= 0) {
-    return false;
-  }
-  sort_loaded_regions(loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start());
-  if (!load_regions(mapinfo, loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start())) {
-    assert(_loading_failed, "must be");
-    return false;
-  }
-
-  init_loaded_heap_relocation(loaded_regions, num_loaded_regions);
-  _is_loaded = true;
-
-  return true;
-}
-
-class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure {
-  ResourceHashtable<uintptr_t, bool>* _table;
-
- public:
-  VerifyLoadedHeapEmbeddedPointers(ResourceHashtable<uintptr_t, bool>* table) : _table(table) {}
-
-  virtual void do_oop(narrowOop* p) {
-    // This should be called before the loaded regions are modified, so all the embedded pointers
-    // must be NULL, or must point to a valid object in the loaded regions.
-    narrowOop v = *p;
-    if (!CompressedOops::is_null(v)) {
-      oop o = CompressedOops::decode_not_null(v);
-      uintptr_t u = cast_from_oop<uintptr_t>(o);
-      HeapShared::assert_in_loaded_heap(u);
-      guarantee(_table->contains(u), "must point to beginning of object in loaded archived regions");
-    }
-  }
-  virtual void do_oop(oop* p) {
-    ShouldNotReachHere();
-  }
-};
-
-void HeapShared::finish_initialization() {
-  if (is_loaded()) {
-    HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
-    HeapWord* top    = (HeapWord*)_loaded_heap_top;
-
-    MemRegion archive_space = MemRegion(bottom, top);
-    Universe::heap()->complete_loaded_archive_space(archive_space);
-  }
-
-  if (VerifyArchivedFields <= 0 || !is_loaded()) {
-    return;
-  }
-
-  log_info(cds, heap)("Verify all oops and pointers in loaded heap");
-
-  ResourceMark rm;
-  ResourceHashtable<uintptr_t, bool> table;
-  VerifyLoadedHeapEmbeddedPointers verifier(&table);
-  HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
-  HeapWord* top    = (HeapWord*)_loaded_heap_top;
-
-  for (HeapWord* p = bottom; p < top; ) {
-    oop o = cast_to_oop(p);
-    table.put(cast_from_oop<uintptr_t>(o), true);
-    p += o->size();
-  }
-
-  for (HeapWord* p = bottom; p < top; ) {
-    oop o = cast_to_oop(p);
-    o->oop_iterate(&verifier);
-    p += o->size();
-  }
-}
-
-void HeapShared::fill_failed_loaded_region() {
-  assert(_loading_failed, "must be");
-  if (_loaded_heap_bottom != 0) {
-    assert(_loaded_heap_top != 0, "must be");
-    HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
-    HeapWord* top = (HeapWord*)_loaded_heap_top;
-    Universe::heap()->fill_with_objects(bottom, top - bottom);
-  }
-}
-
 #endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index 26da658b569..662f251d487 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -29,16 +29,13 @@
 #include "cds/metaspaceShared.hpp"
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
-#include "classfile/systemDictionary.hpp"
 #include "gc/shared/gc_globals.hpp"
 #include "memory/allocation.hpp"
+#include "memory/allStatic.hpp"
 #include "oops/compressedOops.hpp"
-#include "oops/objArrayKlass.hpp"
 #include "oops/oop.hpp"
 #include "oops/oopHandle.hpp"
 #include "oops/oopsHierarchy.hpp"
-#include "oops/typeArrayKlass.hpp"
-#include "utilities/bitMap.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/resourceHash.hpp"
 
@@ -46,6 +43,7 @@
 class DumpedInternedStrings;
 class FileMapInfo;
 class KlassSubGraphInfo;
+class ResourceBitMap;
 
 struct ArchivableStaticFieldInfo {
   const char* klass_name;
@@ -148,14 +146,6 @@ class HeapShared: AllStatic {
   friend class VerifySharedOopClosure;
 
 public:
-  // At runtime, heap regions in the CDS archive can be used in two different ways,
-  // depending on the GC type:
-  // - Mapped: (G1 only) the regions are directly mapped into the Java heap
-  // - Loaded: At VM start-up, the objects in the heap regions are copied into the
-  //           Java heap. This is easier to implement than mapping but
-  //           slightly less efficient, as the embedded pointers need to be relocated.
-  static bool can_use() { return can_map() || can_load(); }
-
   // Can this VM write heap regions into the CDS archive? Currently only G1+compressed{oops,cp}
   static bool can_write() {
     CDS_JAVA_HEAP_ONLY(
@@ -170,67 +160,19 @@ public:
   static void disable_writing() {
     CDS_JAVA_HEAP_ONLY(_disable_writing = true;)
   }
-  // Can this VM map archived heap regions? Currently only G1+compressed{oops,cp}
-  static bool can_map() {
-    CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);)
-    NOT_CDS_JAVA_HEAP(return false;)
-  }
-  static bool is_mapped() {
-    return closed_regions_mapped() && open_regions_mapped();
-  }
 
-  // Can this VM load the objects from archived heap regions into the heap at start-up?
-  static bool can_load()  NOT_CDS_JAVA_HEAP_RETURN_(false);
-  static void finish_initialization() NOT_CDS_JAVA_HEAP_RETURN;
-  static bool is_loaded() {
-    CDS_JAVA_HEAP_ONLY(return _is_loaded;)
-    NOT_CDS_JAVA_HEAP(return false;)
-  }
-
-  static bool are_archived_strings_available() {
-    return is_loaded() || closed_regions_mapped();
-  }
-  static bool are_archived_mirrors_available() {
-    return is_fully_available();
-  }
-  static bool is_fully_available() {
-    return is_loaded() || is_mapped();
-  }
   static bool is_subgraph_root_class(InstanceKlass* ik);
 private:
 #if INCLUDE_CDS_JAVA_HEAP
   static bool _disable_writing;
-  static bool _closed_regions_mapped;
-  static bool _open_regions_mapped;
-  static bool _is_loaded;
   static DumpedInternedStrings *_dumped_interned_strings;
 
-  // Support for loaded archived heap. These are cached values from
-  // LoadedArchiveHeapRegion's.
-  static uintptr_t _dumptime_base_0;
-  static uintptr_t _dumptime_base_1;
-  static uintptr_t _dumptime_base_2;
-  static uintptr_t _dumptime_base_3;
-  static uintptr_t _dumptime_top;
-  static intx _runtime_offset_0;
-  static intx _runtime_offset_1;
-  static intx _runtime_offset_2;
-  static intx _runtime_offset_3;
-  static uintptr_t _loaded_heap_bottom;
-  static uintptr_t _loaded_heap_top;
-  static bool _loading_failed;
-
 public:
   static unsigned oop_hash(oop const& p);
   static unsigned string_oop_hash(oop const& string) {
     return java_lang_String::hash_code(string);
   }
 
-  static bool load_heap_regions(FileMapInfo* mapinfo);
-  static void assert_in_loaded_heap(uintptr_t o) {
-    assert(is_in_loaded_heap(o), "must be");
-  }
-
   struct CachedOopInfo {
     KlassSubGraphInfo* _subgraph_info;
     oop _referrer;
@@ -243,9 +185,6 @@ private:
                              KlassSubGraphInfo* subgraph_info,
                              oop orig_obj,
                              bool is_closed_archive);
-  static bool is_in_loaded_heap(uintptr_t o) {
-    return (_loaded_heap_bottom <= o && o < _loaded_heap_top);
-  }
 
   typedef ResourceHashtable<oop, CachedOopInfo,
       36137, // prime number
@@ -457,20 +396,9 @@ private:
   // Run-time only
   static void clear_root(int index);
 
-  static void set_runtime_delta(ptrdiff_t delta) {
-    assert(!UseCompressedOops, "must be");
-    _runtime_delta = delta;
-  }
-
 #endif // INCLUDE_CDS_JAVA_HEAP
 
  public:
-  static ptrdiff_t runtime_delta() {
-    assert(!UseCompressedOops, "must be");
-    CDS_JAVA_HEAP_ONLY(return _runtime_delta;)
-    NOT_CDS_JAVA_HEAP_RETURN_(0L);
-  }
-
   static void run_full_gc_in_vm_thread() NOT_CDS_JAVA_HEAP_RETURN;
 
   static bool is_heap_region(int idx) {
@@ -479,41 +407,11 @@ private:
     NOT_CDS_JAVA_HEAP_RETURN_(false);
   }
 
-  static void set_closed_regions_mapped() {
-    CDS_JAVA_HEAP_ONLY(_closed_regions_mapped = true;)
-    NOT_CDS_JAVA_HEAP_RETURN;
-  }
-  static bool closed_regions_mapped() {
-    CDS_JAVA_HEAP_ONLY(return _closed_regions_mapped;)
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
-  static void set_open_regions_mapped() {
-    CDS_JAVA_HEAP_ONLY(_open_regions_mapped = true;)
-    NOT_CDS_JAVA_HEAP_RETURN;
-  }
-  static bool open_regions_mapped() {
-    CDS_JAVA_HEAP_ONLY(return _open_regions_mapped;)
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
-
-  static void fixup_regions() NOT_CDS_JAVA_HEAP_RETURN;
-
   static bool is_archived_object_during_dumptime(oop p) NOT_CDS_JAVA_HEAP_RETURN_(false);
 
   static void resolve_classes(JavaThread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
   static void initialize_from_archived_subgraph(Klass* k, JavaThread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
 
-  // NarrowOops stored in the CDS archive may use a different encoding scheme
-  // than CompressedOops::{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_from_archive(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_embedded_pointers(MemRegion region, address oopmap,
-                                      size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
-
   static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
   static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
   static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
index de1341b2a68..4b0863eb2fb 100644
--- a/src/hotspot/share/cds/metaspaceShared.cpp
+++ b/src/hotspot/share/cds/metaspaceShared.cpp
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "jvm_io.h"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/cds_globals.hpp"
 #include "cds/cdsProtectionDomain.hpp"
 #include "cds/classListWriter.hpp"
@@ -1470,7 +1471,7 @@ void MetaspaceShared::initialize_shared_spaces() {
   // Finish up archived heap initialization. These must be
   // done after ReadClosure.
   static_mapinfo->patch_heap_embedded_pointers();
-  HeapShared::finish_initialization();
+  ArchiveHeapLoader::finish_initialization();
 
   // Close the mapinfo file
   static_mapinfo->close();
@@ -1557,7 +1558,7 @@ bool MetaspaceShared::use_full_module_graph() {
   if (DumpSharedSpaces) {
     result &= HeapShared::can_write();
   } else if (UseSharedSpaces) {
-    result &= HeapShared::can_use();
+    result &= ArchiveHeapLoader::can_use();
   } else {
     result = false;
   }
diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp
index a2bd5f77deb..1815c52b37e 100644
--- a/src/hotspot/share/classfile/compactHashtable.cpp
+++ b/src/hotspot/share/classfile/compactHashtable.cpp
@@ -26,7 +26,6 @@
 #include "jvm.h"
 #include "cds/archiveBuilder.hpp"
 #include "cds/cds_globals.hpp"
-#include "cds/heapShared.inline.hpp"
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "logging/logMessage.hpp"
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
index 79ac156bf9d..481f6aa77a1 100644
--- a/src/hotspot/share/classfile/javaClasses.cpp
+++ b/src/hotspot/share/classfile/javaClasses.cpp
@@ -25,7 +25,8 @@
 #include "precompiled.hpp"
 #include "jvm.h"
 #include "cds/archiveBuilder.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/archiveHeapLoader.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/altHashing.hpp"
 #include "classfile/classLoaderData.inline.hpp"
@@ -55,6 +56,7 @@
 #include "oops/klass.hpp"
 #include "oops/klass.inline.hpp"
 #include "oops/method.inline.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oopCast.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -894,7 +896,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
   }
 
   if (k->is_shared() && k->has_archived_mirror_index()) {
-    if (HeapShared::are_archived_mirrors_available()) {
+    if (ArchiveHeapLoader::are_archived_mirrors_available()) {
       bool present = restore_archived_mirror(k, Handle(), Handle(), Handle(), CHECK);
       assert(present, "Missing archived mirror for %s", k->external_name());
       return;
@@ -1321,7 +1323,7 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
 
   // mirror is archived, restore
   log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m));
-  if (HeapShared::is_mapped()) {
+  if (ArchiveHeapLoader::is_mapped()) {
     assert(Universe::heap()->is_archived_object(m), "must be archived mirror object");
   }
   assert(as_Klass(m) == k, "must be");
diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp
index d7a7dad0a50..b9c59e38ba1 100644
--- a/src/hotspot/share/classfile/stringTable.cpp
+++ b/src/hotspot/share/classfile/stringTable.cpp
@@ -24,8 +24,9 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.inline.hpp"
 #include "cds/filemap.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/heapShared.hpp"
 #include "classfile/altHashing.hpp"
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.inline.hpp"
@@ -74,13 +75,13 @@ inline oop read_string_from_compact_hashtable(address base_address, u4 offset) {
   if (UseCompressedOops) {
     assert(sizeof(narrowOop) == sizeof(offset), "must be");
     narrowOop v = CompressedOops::narrow_oop_cast(offset);
-    return HeapShared::decode_from_archive(v);
+    return ArchiveHeapLoader::decode_from_archive(v);
   } else {
     intptr_t dumptime_oop = (uintptr_t)offset;
     assert(dumptime_oop != 0, "null strings cannot be interned");
     intptr_t runtime_oop = dumptime_oop +
                            (intptr_t)FileMapInfo::current_info()->header()->heap_begin() +
-                           (intptr_t)HeapShared::runtime_delta();
+                           (intptr_t)ArchiveHeapLoader::runtime_delta();
     return (oop)cast_to_oop(runtime_oop);
   }
 }
@@ -831,7 +832,7 @@ void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
   if (soc->writing()) {
     // Sanity. Make sure we don't use the shared table at dump time
     _shared_table.reset();
-  } else if (!HeapShared::are_archived_strings_available()) {
+  } else if (!ArchiveHeapLoader::are_archived_strings_available()) {
     _shared_table.reset();
   }
 
@@ -861,7 +862,7 @@ public:
 // _shared_table invalid. Therefore, we proactively copy all the shared
 // strings into the _local_table, which can deal with oop relocation.
 void StringTable::transfer_shared_strings_to_local_table() {
-  assert(HeapShared::is_loaded(), "must be");
+  assert(ArchiveHeapLoader::is_loaded(), "must be");
   EXCEPTION_MARK;
 
   // Reset _shared_table so that during the transfer, StringTable::intern()
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
index 086a9969333..9e80ffe7fa5 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -23,13 +23,13 @@
  */
 
 #include "precompiled.hpp"
-#include "cds/archiveUtils.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/archiveHeapLoader.hpp"
+#include "cds/archiveUtils.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
-#include "cds/heapShared.hpp"
 #include "cds/cdsProtectionDomain.hpp"
 #include "cds/dumpTimeClassInfo.inline.hpp"
 #include "cds/metaspaceShared.hpp"
@@ -60,6 +60,7 @@
 #include "memory/universe.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klass.inline.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
@@ -1599,7 +1600,7 @@ void SystemDictionaryShared::update_archived_mirror_native_pointers_for(LambdaPr
 }
 
 void SystemDictionaryShared::update_archived_mirror_native_pointers() {
-  if (!HeapShared::are_archived_mirrors_available()) {
+  if (!ArchiveHeapLoader::are_archived_mirrors_available()) {
     return;
   }
   if (MetaspaceShared::relocation_delta() == 0) {
diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp
index bfbb90d57c8..93e8b972082 100644
--- a/src/hotspot/share/classfile/vmClasses.cpp
+++ b/src/hotspot/share/classfile/vmClasses.cpp
@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
-#include "cds/heapShared.hpp"
+#include "cds/archiveHeapLoader.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/dictionary.hpp"
+#include "classfile/javaClasses.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmClasses.hpp"
 #include "classfile/vmSymbols.hpp"
@@ -135,13 +136,13 @@ void vmClasses::resolve_all(TRAPS) {
     // ConstantPool::restore_unshareable_info (restores the archived
     // resolved_references array object).
     //
-    // HeapShared::fixup_regions() fills the empty
+    // ArchiveHeapLoader::fixup_regions fills the empty
     // spaces in the archived heap regions and may use
     // vmClasses::Object_klass(), so we can do this only after
     // Object_klass is resolved. See the above resolve_through()
     // call. No mirror objects are accessed/restored in the above call.
     // Mirrors are restored after java.lang.Class is loaded.
-    HeapShared::fixup_regions();
+    ArchiveHeapLoader::fixup_regions();
 
     // Initialize the constant pool for the Object_class
     assert(Object_klass()->is_shared(), "must be");
diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
index 8a9395e28ab..636ca1826f1 100644
--- a/src/hotspot/share/memory/universe.cpp
+++ b/src/hotspot/share/memory/universe.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
@@ -451,9 +452,9 @@ void Universe::genesis(TRAPS) {
 void Universe::initialize_basic_type_mirrors(TRAPS) {
 #if INCLUDE_CDS_JAVA_HEAP
     if (UseSharedSpaces &&
-        HeapShared::are_archived_mirrors_available() &&
+        ArchiveHeapLoader::are_archived_mirrors_available() &&
         _mirrors[T_INT].resolve() != NULL) {
-      assert(HeapShared::can_use(), "Sanity");
+      assert(ArchiveHeapLoader::can_use(), "Sanity");
 
       // check that all mirrors are mapped also
       for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
@@ -806,7 +807,7 @@ jint universe_init() {
     // currently mapped regions.
     MetaspaceShared::initialize_shared_spaces();
     StringTable::create_table();
-    if (HeapShared::is_loaded()) {
+    if (ArchiveHeapLoader::is_loaded()) {
       StringTable::transfer_shared_strings_to_local_table();
     }
   } else
diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp
index c8ec68a21ae..618871c2c95 100644
--- a/src/hotspot/share/oops/constantPool.cpp
+++ b/src/hotspot/share/oops/constantPool.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jvm.h"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/javaClasses.inline.hpp"
@@ -346,7 +347,7 @@ void ConstantPool::restore_unshareable_info(TRAPS) {
   if (vmClasses::Object_klass_loaded()) {
     ClassLoaderData* loader_data = pool_holder()->class_loader_data();
 #if INCLUDE_CDS_JAVA_HEAP
-    if (HeapShared::is_fully_available() &&
+    if (ArchiveHeapLoader::is_fully_available() &&
         _cache->archived_references() != NULL) {
       oop archived = _cache->archived_references();
       // Create handle for the archived resolved reference array object
diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp
index 56b66503003..d0b74dd0e16 100644
--- a/src/hotspot/share/oops/klass.cpp
+++ b/src/hotspot/share/oops/klass.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jvm_io.h"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/classLoaderDataGraph.inline.hpp"
@@ -43,6 +44,7 @@
 #include "oops/compressedOops.inline.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klass.inline.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -605,7 +607,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec
   if (this->has_archived_mirror_index()) {
     ResourceMark rm(THREAD);
     log_debug(cds, mirror)("%s has raw archived mirror", external_name());
-    if (HeapShared::are_archived_mirrors_available()) {
+    if (ArchiveHeapLoader::are_archived_mirrors_available()) {
       bool present = java_lang_Class::restore_archived_mirror(this, loader, module_handle,
                                                               protection_domain,
                                                               CHECK);
diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp
index 2f6f1bd0374..6aaae031fa0 100644
--- a/src/hotspot/share/prims/whitebox.cpp
+++ b/src/hotspot/share/prims/whitebox.cpp
@@ -25,9 +25,10 @@
 #include "precompiled.hpp"
 #include <new>
 #include "cds.h"
+#include "cds/archiveHeapLoader.hpp"
 #include "cds/cdsConstants.hpp"
 #include "cds/filemap.hpp"
-#include "cds/heapShared.inline.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/classLoaderDataGraph.hpp"
 #include "classfile/javaClasses.inline.hpp"
@@ -1992,7 +1993,7 @@ WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz))
 WB_END
 
 WB_ENTRY(jboolean, WB_AreSharedStringsMapped(JNIEnv* env))
-  return HeapShared::closed_regions_mapped();
+  return ArchiveHeapLoader::closed_regions_mapped();
 WB_END
 
 WB_ENTRY(jobject, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass clazz))
@@ -2017,7 +2018,7 @@ WB_ENTRY(void, WB_LinkClass(JNIEnv* env, jobject wb, jclass clazz))
 WB_END
 
 WB_ENTRY(jboolean, WB_AreOpenArchiveHeapObjectsMapped(JNIEnv* env))
-  return HeapShared::open_regions_mapped();
+  return ArchiveHeapLoader::open_regions_mapped();
 WB_END
 
 WB_ENTRY(jboolean, WB_IsCDSIncluded(JNIEnv* env))