changeset 59411:fe3a9edeb7c9

8243392: Remodel CDS/Metaspace storage reservation Reviewed-by: iklam, coleenp, ngasson, aph
author stuefe
date Sun, 24 May 2020 19:25:29 +0200
parents 94e1349502da
children 438102b06fc0
files src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp src/hotspot/share/memory/dynamicArchive.cpp src/hotspot/share/memory/filemap.cpp src/hotspot/share/memory/metaspace.cpp src/hotspot/share/memory/metaspace.hpp src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp src/hotspot/share/memory/metaspaceShared.cpp src/hotspot/share/memory/metaspaceShared.hpp src/hotspot/share/oops/compressedOops.cpp src/hotspot/share/oops/compressedOops.hpp src/hotspot/share/services/virtualMemoryTracker.cpp src/hotspot/share/utilities/vmError.cpp test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java
diffstat 17 files changed, 739 insertions(+), 397 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp	Sun May 24 19:25:29 2020 +0200
@@ -56,8 +56,6 @@
 
 #define SUPPORT_RESERVED_STACK_AREA
 
-#define PREFERRED_METASPACE_ALIGNMENT
-
 #define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS true
 
 #endif // CPU_AARCH64_GLOBALDEFINITIONS_AARCH64_HPP
--- a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp	Sun May 24 19:25:29 2020 +0200
@@ -58,10 +58,6 @@
 #define INCLUDE_RTM_OPT 0
 #endif
 
-#if defined(AIX)
-#define PREFERRED_METASPACE_ALIGNMENT
-#endif
-
 #define SUPPORT_RESERVED_STACK_AREA
 
 // If UseSIGTRAP is active, we only use the poll bit and no polling page.
--- a/src/hotspot/share/memory/dynamicArchive.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/dynamicArchive.cpp	Sun May 24 19:25:29 2020 +0200
@@ -69,7 +69,7 @@
   DumpRegion* _current_dump_space;
 
   static size_t reserve_alignment() {
-    return Metaspace::reserve_alignment();
+    return os::vm_allocation_granularity();
   }
 
   static const int _total_dump_regions = 3;
@@ -724,7 +724,7 @@
 
 address DynamicArchiveBuilder::reserve_space_and_init_buffer_to_target_delta() {
   size_t total = estimate_archive_size();
-  ReservedSpace rs = MetaspaceShared::reserve_shared_space(total);
+  ReservedSpace rs(total);
   if (!rs.is_reserved()) {
     log_error(cds, dynamic)("Failed to reserve %d bytes of output buffer.", (int)total);
     vm_direct_exit(0);
--- a/src/hotspot/share/memory/filemap.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/filemap.cpp	Sun May 24 19:25:29 2020 +0200
@@ -1079,6 +1079,8 @@
                     os::strerror(errno));
     }
     return false;
+  } else {
+    log_info(cds)("Opened archive %s.", _full_path);
   }
 
   _fd = fd;
@@ -1981,11 +1983,13 @@
   size_t used = si->used();
   size_t size = align_up(used, os::vm_allocation_granularity());
 
-  if (mapped_base != NULL && size > 0 && si->mapped_from_file()) {
-    log_info(cds)("Unmapping region #%d at base " INTPTR_FORMAT " (%s)", i, p2i(mapped_base),
-                  shared_region_name[i]);
-    if (!os::unmap_memory(mapped_base, size)) {
-      fatal("os::unmap_memory failed");
+  if (mapped_base != NULL) {
+    if (size > 0 && si->mapped_from_file()) {
+      log_info(cds)("Unmapping region #%d at base " INTPTR_FORMAT " (%s)", i, p2i(mapped_base),
+                    shared_region_name[i]);
+      if (!os::unmap_memory(mapped_base, size)) {
+        fatal("os::unmap_memory failed");
+      }
     }
     si->set_mapped_base(NULL);
   }
--- a/src/hotspot/share/memory/metaspace.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/metaspace.cpp	Sun May 24 19:25:29 2020 +0200
@@ -973,201 +973,95 @@
 #define VIRTUALSPACEMULTIPLIER 2
 
 #ifdef _LP64
-static const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
 
-void Metaspace::set_narrow_klass_base_and_shift(ReservedSpace metaspace_rs, address cds_base) {
-  assert(!DumpSharedSpaces, "narrow_klass is set by MetaspaceShared class.");
-  // Figure out the narrow_klass_base and the narrow_klass_shift.  The
-  // narrow_klass_base is the lower of the metaspace base and the cds base
-  // (if cds is enabled).  The narrow_klass_shift depends on the distance
-  // between the lower base and higher address.
-  address lower_base = (address)metaspace_rs.base();
-  address higher_address = (address)metaspace_rs.end();
-  if (cds_base != NULL) {
-    assert(UseSharedSpaces, "must be");
-    lower_base = MIN2(lower_base, cds_base);
-  } else {
-    uint64_t klass_encoding_max = UnscaledClassSpaceMax << LogKlassAlignmentInBytes;
-    // If compressed class space fits in lower 32G, we don't need a base.
-    if (higher_address <= (address)klass_encoding_max) {
-      lower_base = 0; // Effectively lower base is zero.
-    }
-  }
-
-  CompressedKlassPointers::set_base(lower_base);
-
-  // CDS uses LogKlassAlignmentInBytes for narrow_klass_shift. See
-  // MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() for
-  // how dump time narrow_klass_shift is set. Although, CDS can work
-  // with zero-shift mode also, to be consistent with AOT it uses
-  // LogKlassAlignmentInBytes for klass shift so archived java heap objects
-  // can be used at same time as AOT code.
-  if (!UseSharedSpaces
-      && (uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
-    CompressedKlassPointers::set_shift(0);
-  } else {
-    CompressedKlassPointers::set_shift(LogKlassAlignmentInBytes);
-  }
-  AOTLoader::set_narrow_klass_shift();
-}
-
-// Try to allocate the metaspace at the requested addr.
-void Metaspace::allocate_metaspace_compressed_klass_ptrs(ReservedSpace metaspace_rs, char* requested_addr, address cds_base) {
-  assert(!DumpSharedSpaces, "compress klass space is allocated by MetaspaceShared class.");
-  assert(using_class_space(), "called improperly");
-  assert(UseCompressedClassPointers, "Only use with CompressedKlassPtrs");
-  assert(compressed_class_space_size() < KlassEncodingMetaspaceMax,
-         "Metaspace size is too big");
-  assert_is_aligned(requested_addr, _reserve_alignment);
-  assert_is_aligned(cds_base, _reserve_alignment);
-  assert_is_aligned(compressed_class_space_size(), _reserve_alignment);
-
-  if (metaspace_rs.is_reserved()) {
-    // CDS should have already reserved the space.
-    assert(requested_addr == NULL, "not used");
-    assert(cds_base != NULL, "CDS should have already reserved the memory space");
-  } else {
-    assert(cds_base == NULL, "must be");
-    metaspace_rs = reserve_space(compressed_class_space_size(),
-                                 _reserve_alignment, requested_addr,
-                                 false /* use_requested_addr */);
-  }
-
-  if (!metaspace_rs.is_reserved()) {
-    assert(cds_base == NULL, "CDS should have already reserved the memory space");
-    // If no successful allocation then try to allocate the space anywhere.  If
-    // that fails then OOM doom.  At this point we cannot try allocating the
-    // metaspace as if UseCompressedClassPointers is off because too much
-    // initialization has happened that depends on UseCompressedClassPointers.
-    // So, UseCompressedClassPointers cannot be turned off at this point.
-    metaspace_rs = reserve_space(compressed_class_space_size(),
-                                 _reserve_alignment, NULL, false);
-    if (!metaspace_rs.is_reserved()) {
-      vm_exit_during_initialization(err_msg("Could not allocate metaspace: " SIZE_FORMAT " bytes",
-                                            compressed_class_space_size()));
-    }
-  }
-
-  if (cds_base == NULL) {
-    // If we got here then the metaspace got allocated.
-    MemTracker::record_virtual_memory_type((address)metaspace_rs.base(), mtClass);
-  }
-
-  set_narrow_klass_base_and_shift(metaspace_rs, cds_base);
-
-  initialize_class_space(metaspace_rs);
-
-  LogTarget(Trace, gc, metaspace) lt;
-  if (lt.is_enabled()) {
-    ResourceMark rm;
-    LogStream ls(lt);
-    print_compressed_class_space(&ls, requested_addr);
-  }
-}
-
-void Metaspace::print_compressed_class_space(outputStream* st, const char* requested_addr) {
-  st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d",
-               p2i(CompressedKlassPointers::base()), CompressedKlassPointers::shift());
+void Metaspace::print_compressed_class_space(outputStream* st) {
   if (_class_space_list != NULL) {
     address base = (address)_class_space_list->current_virtual_space()->bottom();
-    st->print("Compressed class space size: " SIZE_FORMAT " Address: " PTR_FORMAT,
-                 compressed_class_space_size(), p2i(base));
-    if (requested_addr != 0) {
-      st->print(" Req Addr: " PTR_FORMAT, p2i(requested_addr));
-    }
+    address top = base + compressed_class_space_size();
+    st->print("Compressed class space mapped at: " PTR_FORMAT "-" PTR_FORMAT ", size: " SIZE_FORMAT,
+               p2i(base), p2i(top), top - base);
     st->cr();
   }
 }
 
-// For UseCompressedClassPointers the class space is reserved above the top of
-// the Java heap.  The argument passed in is at the base of the compressed space.
+// Given a prereserved space, use that to set up the compressed class space list.
 void Metaspace::initialize_class_space(ReservedSpace rs) {
-  // The reserved space size may be bigger because of alignment, esp with UseLargePages
-  assert(rs.size() >= CompressedClassSpaceSize,
-         SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize);
   assert(using_class_space(), "Must be using class space");
+  assert(_class_space_list == NULL && _chunk_manager_class == NULL, "Only call once");
+
+  assert(rs.size() == CompressedClassSpaceSize, SIZE_FORMAT " != " SIZE_FORMAT,
+         rs.size(), CompressedClassSpaceSize);
+  assert(is_aligned(rs.base(), Metaspace::reserve_alignment()) &&
+         is_aligned(rs.size(), Metaspace::reserve_alignment()),
+         "wrong alignment");
+
   _class_space_list = new VirtualSpaceList(rs);
   _chunk_manager_class = new ChunkManager(true/*is_class*/);
 
+  // This does currently not work because rs may be the result of a split
+  // operation and NMT seems not to be able to handle splits.
+  // Will be fixed with JDK-8243535.
+  // MemTracker::record_virtual_memory_type((address)rs.base(), mtClass);
+
   if (!_class_space_list->initialization_succeeded()) {
     vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
   }
+
+}
+
+// Reserve a range of memory at an address suitable for en/decoding narrow
+// Klass pointers (see: CompressedClassPointers::is_valid_base()).
+// The returned address shall both be suitable as a compressed class pointers
+//  base, and aligned to Metaspace::reserve_alignment (which is equal to or a
+//  multiple of allocation granularity).
+// On error, returns an unreserved space.
+ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t size) {
+
+#ifdef AARCH64
+  const size_t alignment = Metaspace::reserve_alignment();
+
+  // AArch64: Try to align metaspace so that we can decode a compressed
+  // klass with a single MOVK instruction. We can do this iff the
+  // compressed class base is a multiple of 4G.
+  // Additionally, above 32G, ensure the lower LogKlassAlignmentInBytes bits
+  // of the upper 32-bits of the address are zero so we can handle a shift
+  // when decoding.
+
+  static const struct {
+    address from;
+    address to;
+    size_t increment;
+  } search_ranges[] = {
+    {  (address)(4*G),   (address)(32*G),   4*G, },
+    {  (address)(32*G),  (address)(1024*G), (4 << LogKlassAlignmentInBytes) * G },
+    {  NULL, NULL, 0 }
+  };
+
+  for (int i = 0; search_ranges[i].from != NULL; i ++) {
+    address a = search_ranges[i].from;
+    assert(CompressedKlassPointers::is_valid_base(a), "Sanity");
+    while (a < search_ranges[i].to) {
+      ReservedSpace rs(size, Metaspace::reserve_alignment(),
+                       false /*large_pages*/, (char*)a);
+      if (rs.is_reserved()) {
+        assert(a == (address)rs.base(), "Sanity");
+        return rs;
+      }
+      a +=  search_ranges[i].increment;
+    }
+  }
+
+  // Note: on AARCH64, if the code above does not find any good placement, we
+  // have no recourse. We return an empty space and the VM will exit.
+  return ReservedSpace();
+#else
+  // Default implementation: Just reserve anywhere.
+  return ReservedSpace(size, Metaspace::reserve_alignment(), false, (char*)NULL);
+#endif // AARCH64
 }
 
 #endif // _LP64
 
-#ifdef PREFERRED_METASPACE_ALIGNMENT
-ReservedSpace Metaspace::reserve_preferred_space(size_t size, size_t alignment,
-                                                 bool large_pages, char *requested_addr,
-                                                 bool use_requested_addr) {
-  // Our compressed klass pointers may fit nicely into the lower 32 bits.
-  if (requested_addr != NULL && (uint64_t)requested_addr + size < 4*G) {
-    ReservedSpace rs(size, alignment, large_pages, requested_addr);
-    if (rs.is_reserved() || use_requested_addr) {
-      return rs;
-    }
-  }
-
-  struct SearchParams { uintptr_t limit; size_t increment; };
-
-  // AArch64: Try to align metaspace so that we can decode a compressed
-  // klass with a single MOVK instruction. We can do this iff the
-  // compressed class base is a multiple of 4G.
-  // Aix: Search for a place where we can find memory. If we need to load
-  // the base, 4G alignment is helpful, too.
-
-  // Go faster above 32G as it is no longer possible to use a zero base.
-  // AArch64: Additionally, ensure the lower LogKlassAlignmentInBytes
-  // bits of the upper 32-bits of the address are zero so we can handle
-  // a shift when decoding.
-
-  static const SearchParams search_params[] = {
-    // Limit    Increment
-    {  32*G,    AARCH64_ONLY(4*)G,                               },
-    {  1024*G,  (4 AARCH64_ONLY(<< LogKlassAlignmentInBytes))*G  },
-  };
-
-  // Null requested_addr means allocate anywhere so ensure the search
-  // begins from a non-null address.
-  char *a = MAX2(requested_addr, (char *)search_params[0].increment);
-
-  for (const SearchParams *p = search_params;
-       p < search_params + ARRAY_SIZE(search_params);
-       ++p) {
-    a = align_up(a, p->increment);
-    if (use_requested_addr && a != requested_addr)
-      return ReservedSpace();
-
-    for (; a < (char *)p->limit; a += p->increment) {
-      ReservedSpace rs(size, alignment, large_pages, a);
-      if (rs.is_reserved() || use_requested_addr) {
-        return rs;
-      }
-    }
-  }
-
-  return ReservedSpace();
-}
-#endif // PREFERRED_METASPACE_ALIGNMENT
-
-// Try to reserve a region for the metaspace at the requested address. Some
-// platforms have particular alignment requirements to allow efficient decode of
-// compressed class pointers in which case requested_addr is treated as hint for
-// where to start looking unless use_requested_addr is true.
-ReservedSpace Metaspace::reserve_space(size_t size, size_t alignment,
-                                       char* requested_addr, bool use_requested_addr) {
-  bool large_pages = false; // Don't use large pages for the class space.
-  assert(is_aligned(requested_addr, alignment), "must be");
-  assert(requested_addr != NULL || !use_requested_addr,
-         "cannot set use_requested_addr with NULL address");
-
-#ifdef PREFERRED_METASPACE_ALIGNMENT
-  return reserve_preferred_space(size, alignment, large_pages,
-                                 requested_addr, use_requested_addr);
-#else
-  return ReservedSpace(size, alignment, large_pages, requested_addr);
-#endif
-}
 
 void Metaspace::ergo_initialize() {
   if (DumpSharedSpaces) {
@@ -1229,16 +1123,23 @@
 void Metaspace::global_initialize() {
   MetaspaceGC::initialize();
 
-  bool class_space_inited = false;
+  // If UseCompressedClassPointers=1, we have two cases:
+  // a) if CDS is active (either dump time or runtime), it will create the ccs
+  //    for us, initialize it and set up CompressedKlassPointers encoding.
+  //    Class space will be reserved above the mapped archives.
+  // b) if CDS is not active, we will create the ccs on our own. It will be
+  //    placed above the java heap, since we assume it has been placed in low
+  //    address regions. We may rethink this (see JDK-8244943). Failing that,
+  //    it will be placed anywhere.
+
 #if INCLUDE_CDS
+  // case (a)
   if (DumpSharedSpaces) {
     MetaspaceShared::initialize_dumptime_shared_and_meta_spaces();
-    class_space_inited = true;
   } else if (UseSharedSpaces) {
     // If any of the archived space fails to map, UseSharedSpaces
     // is reset to false.
     MetaspaceShared::initialize_runtime_shared_and_meta_spaces();
-    class_space_inited = UseSharedSpaces;
   }
 
   if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
@@ -1247,16 +1148,49 @@
 #endif // INCLUDE_CDS
 
 #ifdef _LP64
-  if (using_class_space() && !class_space_inited) {
-    char* base;
-    if (UseCompressedOops) {
-      base = (char*)align_up(CompressedOops::end(), _reserve_alignment);
-    } else {
-      base = (char*)HeapBaseMinAddress;
+
+  if (using_class_space() && !class_space_is_initialized()) {
+    assert(!UseSharedSpaces && !DumpSharedSpaces, "CDS should be off at this point");
+
+    // case (b)
+    ReservedSpace rs;
+
+    // If UseCompressedOops=1, java heap may have been placed in coops-friendly
+    //  territory already (lower address regions), so we attempt to place ccs
+    //  right above the java heap.
+    // If UseCompressedOops=0, the heap has been placed anywhere - probably in
+    //  high memory regions. In that case, try to place ccs at the lowest allowed
+    //  mapping address.
+    address base = UseCompressedOops ? CompressedOops::end() : (address)HeapBaseMinAddress;
+    base = align_up(base, Metaspace::reserve_alignment());
+
+    const size_t size = align_up(CompressedClassSpaceSize, Metaspace::reserve_alignment());
+    if (base != NULL) {
+      if (CompressedKlassPointers::is_valid_base(base)) {
+        rs = ReservedSpace(size, Metaspace::reserve_alignment(),
+                           false /* large */, (char*)base);
+      }
     }
-    ReservedSpace dummy;
-    allocate_metaspace_compressed_klass_ptrs(dummy, base, 0);
+
+    // ...failing that, reserve anywhere, but let platform do optimized placement:
+    if (!rs.is_reserved()) {
+      rs = Metaspace::reserve_address_space_for_compressed_classes(size);
+    }
+
+    // ...failing that, give up.
+    if (!rs.is_reserved()) {
+      vm_exit_during_initialization(
+          err_msg("Could not allocate compressed class space: " SIZE_FORMAT " bytes",
+                   compressed_class_space_size()));
+    }
+
+    // Initialize space
+    Metaspace::initialize_class_space(rs);
+
+    // Set up compressed class pointer encoding.
+    CompressedKlassPointers::initialize((address)rs.base(), rs.size());
   }
+
 #endif
 
   // Initialize these before initializing the VirtualSpaceList
@@ -1285,6 +1219,20 @@
 
   _initialized = true;
 
+#ifdef _LP64
+  if (UseCompressedClassPointers) {
+    // Note: "cds" would be a better fit but keep this for backward compatibility.
+    LogTarget(Info, gc, metaspace) lt;
+    if (lt.is_enabled()) {
+      ResourceMark rm;
+      LogStream ls(lt);
+      CDS_ONLY(MetaspaceShared::print_on(&ls);)
+      Metaspace::print_compressed_class_space(&ls);
+      CompressedKlassPointers::print_mode(&ls);
+    }
+  }
+#endif
+
 }
 
 void Metaspace::post_initialize() {
--- a/src/hotspot/share/memory/metaspace.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/metaspace.hpp	Sun May 24 19:25:29 2020 +0200
@@ -171,25 +171,25 @@
   static void assert_not_frozen() {
     assert(!_frozen, "sanity");
   }
-#ifdef _LP64
-  static void allocate_metaspace_compressed_klass_ptrs(ReservedSpace metaspace_rs, char* requested_addr, address cds_base);
-#endif
 
  private:
 
 #ifdef _LP64
-  static void set_narrow_klass_base_and_shift(ReservedSpace metaspace_rs, address cds_base);
 
+  // Reserve a range of memory at an address suitable for en/decoding narrow
+  // Klass pointers (see: CompressedClassPointers::is_valid_base()).
+  // The returned address shall both be suitable as a compressed class pointers
+  //  base, and aligned to Metaspace::reserve_alignment (which is equal to or a
+  //  multiple of allocation granularity).
+  // On error, returns an unreserved space.
+  static ReservedSpace reserve_address_space_for_compressed_classes(size_t size);
+
+  // Given a prereserved space, use that to set up the compressed class space list.
   static void initialize_class_space(ReservedSpace rs);
-#endif
 
-  static ReservedSpace reserve_space(size_t size, size_t alignment,
-                                     char* requested_addr, bool use_requested_addr);
+  // Returns true if class space has been setup (initialize_class_space).
+  static bool class_space_is_initialized() { return _class_space_list != NULL; }
 
-#ifdef PREFERRED_METASPACE_ALIGNMENT
-  static ReservedSpace reserve_preferred_space(size_t size, size_t alignment,
-                                               bool large_pages, char *requested_addr,
-                                               bool use_requested_addr);
 #endif
 
  public:
@@ -223,7 +223,7 @@
 
   static const char* metadata_type_name(Metaspace::MetadataType mdtype);
 
-  static void print_compressed_class_space(outputStream* st, const char* requested_addr = 0) NOT_LP64({});
+  static void print_compressed_class_space(outputStream* st) NOT_LP64({});
 
   // Return TRUE only if UseCompressedClassPointers is True.
   static bool using_class_space() {
--- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp	Sun May 24 19:25:29 2020 +0200
@@ -84,7 +84,7 @@
     _next(NULL), _is_class(is_class), _rs(rs), _top(NULL), _container_count(0), _occupancy_map(NULL) {}
   ~VirtualSpaceNode();
 
-  // Convenience functions for logical bottom and end
+  // Convenience functions for logical bottom and (committed) end
   MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); }
   MetaWord* end() const { return (MetaWord*) _virtual_space.high(); }
 
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Sun May 24 19:25:29 2020 +0200
@@ -69,6 +69,7 @@
 #include "runtime/vmOperations.hpp"
 #include "utilities/align.hpp"
 #include "utilities/bitMap.inline.hpp"
+#include "utilities/ostream.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/hashtable.inline.hpp"
 #if INCLUDE_G1GC
@@ -191,7 +192,7 @@
 
 void DumpRegion::pack(DumpRegion* next) {
   assert(!is_packed(), "sanity");
-  _end = (char*)align_up(_top, Metaspace::reserve_alignment());
+  _end = (char*)align_up(_top, MetaspaceShared::reserved_space_alignment());
   _is_packed = true;
   if (next != NULL) {
     next->_rs = _rs;
@@ -237,52 +238,51 @@
   return _ro_region.allocate(num_bytes);
 }
 
-// When reserving an address range using ReservedSpace, we need an alignment that satisfies both:
-// os::vm_allocation_granularity() -- so that we can sub-divide this range into multiple mmap regions,
-//                                    while keeping the first range at offset 0 of this range.
-// Metaspace::reserve_alignment()  -- so we can pass the region to
-//                                    Metaspace::allocate_metaspace_compressed_klass_ptrs.
-size_t MetaspaceShared::reserved_space_alignment() {
-  size_t os_align = os::vm_allocation_granularity();
-  size_t ms_align = Metaspace::reserve_alignment();
-  if (os_align >= ms_align) {
-    assert(os_align % ms_align == 0, "must be a multiple");
-    return os_align;
-  } else {
-    assert(ms_align % os_align == 0, "must be a multiple");
-    return ms_align;
+size_t MetaspaceShared::reserved_space_alignment() { return os::vm_allocation_granularity(); }
+
+#ifdef _LP64
+// Check SharedBaseAddress for validity. At this point, os::init() must
+//  have been ran.
+static void check_SharedBaseAddress() {
+  SharedBaseAddress = align_up(SharedBaseAddress,
+                               MetaspaceShared::reserved_space_alignment());
+  if (!CompressedKlassPointers::is_valid_base((address)SharedBaseAddress)) {
+    log_warning(cds)("SharedBaseAddress=" PTR_FORMAT " is invalid for this "
+                     "platform, option will be ignored.",
+                     p2i((address)SharedBaseAddress));
+    SharedBaseAddress = Arguments::default_SharedBaseAddress();
   }
 }
-
-ReservedSpace MetaspaceShared::reserve_shared_space(size_t size, char* requested_address) {
-  return Metaspace::reserve_space(size, reserved_space_alignment(),
-                                  requested_address, requested_address != NULL);
-}
+#endif
 
 void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
   assert(DumpSharedSpaces, "should be called for dump time only");
-  const size_t reserve_alignment = reserved_space_alignment();
+
+  check_SharedBaseAddress();
+
+  const size_t reserve_alignment = MetaspaceShared::reserved_space_alignment();
   char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment);
 
 #ifdef _LP64
-  // On 64-bit VM, the heap and class space layout will be the same as if
-  // you're running in -Xshare:on mode:
-  //
-  //                              +-- SharedBaseAddress (default = 0x800000000)
-  //                              v
-  // +-..---------+---------+ ... +----+----+----+--------------------+
-  // |    Heap    | Archive |     | MC | RW | RO |    class space     |
-  // +-..---------+---------+ ... +----+----+----+--------------------+
-  // |<--   MaxHeapSize  -->|     |<-- UnscaledClassSpaceMax = 4GB -->|
-  //
+  assert(CompressedKlassPointers::is_valid_base((address)shared_base), "Sanity");
+  // On 64-bit VM we reserve a 4G range and, if UseCompressedClassPointers=1,
+  //  will use that to house both the archives and the ccs. See below for
+  //  details.
   const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
   const size_t cds_total = align_down(UnscaledClassSpaceMax, reserve_alignment);
 #else
-  // We don't support archives larger than 256MB on 32-bit due to limited virtual address space.
+  // We don't support archives larger than 256MB on 32-bit due to limited
+  //  virtual address space.
   size_t cds_total = align_down(256*M, reserve_alignment);
 #endif
 
+  // Whether to use SharedBaseAddress as attach address.
   bool use_requested_base = true;
+
+  if (shared_base == NULL) {
+    use_requested_base = false;
+  }
+
   if (ArchiveRelocationMode == 1) {
     log_info(cds)("ArchiveRelocationMode == 1: always allocate class space at an alternative address");
     use_requested_base = false;
@@ -291,47 +291,104 @@
   // First try to reserve the space at the specified SharedBaseAddress.
   assert(!_shared_rs.is_reserved(), "must be");
   if (use_requested_base) {
-    _shared_rs = reserve_shared_space(cds_total, shared_base);
+    _shared_rs = ReservedSpace(cds_total, reserve_alignment,
+                               false /* large */, (char*)shared_base);
+    if (_shared_rs.is_reserved()) {
+      assert(_shared_rs.base() == shared_base, "should match");
+    } else {
+      log_info(cds)("dumptime space reservation: failed to map at "
+                    "SharedBaseAddress " PTR_FORMAT, p2i(shared_base));
+    }
   }
-  if (_shared_rs.is_reserved()) {
-    assert(shared_base == 0 || _shared_rs.base() == shared_base, "should match");
-  } else {
-    // Get a mmap region anywhere if the SharedBaseAddress fails.
-    _shared_rs = reserve_shared_space(cds_total);
+  if (!_shared_rs.is_reserved()) {
+    // Get a reserved space anywhere if attaching at the SharedBaseAddress
+    //  fails:
+    if (UseCompressedClassPointers) {
+      // If we need to reserve class space as well, let the platform handle
+      //  the reservation.
+      LP64_ONLY(_shared_rs =
+                Metaspace::reserve_address_space_for_compressed_classes(cds_total);)
+      NOT_LP64(ShouldNotReachHere();)
+    } else {
+      // anywhere is fine.
+      _shared_rs = ReservedSpace(cds_total, reserve_alignment,
+                                 false /* large */, (char*)NULL);
+    }
   }
+
   if (!_shared_rs.is_reserved()) {
     vm_exit_during_initialization("Unable to reserve memory for shared space",
                                   err_msg(SIZE_FORMAT " bytes.", cds_total));
   }
 
 #ifdef _LP64
-  // During dump time, we allocate 4GB (UnscaledClassSpaceMax) of space and split it up:
-  // + The upper 1 GB is used as the "temporary compressed class space" -- preload_classes()
-  //   will store Klasses into this space.
-  // + The lower 3 GB is used for the archive -- when preload_classes() is done,
-  //   ArchiveCompactor will copy the class metadata into this space, first the RW parts,
-  //   then the RO parts.
-
-  size_t max_archive_size = align_down(cds_total * 3 / 4, reserve_alignment);
-  ReservedSpace tmp_class_space = _shared_rs.last_part(max_archive_size);
-  CompressedClassSpaceSize = align_down(tmp_class_space.size(), reserve_alignment);
-  _shared_rs = _shared_rs.first_part(max_archive_size);
 
   if (UseCompressedClassPointers) {
-    // Set up compress class pointers.
-    CompressedKlassPointers::set_base((address)_shared_rs.base());
-    // Set narrow_klass_shift to be LogKlassAlignmentInBytes. This is consistent
-    // with AOT.
-    CompressedKlassPointers::set_shift(LogKlassAlignmentInBytes);
-    // Set the range of klass addresses to 4GB.
-    CompressedKlassPointers::set_range(cds_total);
+
+    assert(CompressedKlassPointers::is_valid_base((address)_shared_rs.base()), "Sanity");
+
+    // On 64-bit VM, if UseCompressedClassPointers=1, the compressed class space
+    //  must be allocated near the cds such as that the compressed Klass pointer
+    //  encoding can be used to en/decode pointers from both cds and ccs. Since
+    //  Metaspace cannot do this (it knows nothing about cds), we do it for
+    //  Metaspace here and pass it the space to use for ccs.
+    //
+    // We do this by reserving space for the ccs behind the archives. Note
+    //  however that ccs follows a different alignment
+    //  (Metaspace::reserve_alignment), so there may be a gap between ccs and
+    //  cds.
+    // We use a similar layout at runtime, see reserve_address_space_for_archives().
+    //
+    //                              +-- SharedBaseAddress (default = 0x800000000)
+    //                              v
+    // +-..---------+---------+ ... +----+----+----+--------+-----------------+
+    // |    Heap    | Archive |     | MC | RW | RO | [gap]  |    class space  |
+    // +-..---------+---------+ ... +----+----+----+--------+-----------------+
+    // |<--   MaxHeapSize  -->|     |<-- UnscaledClassSpaceMax = 4GB -->|
+    //
+    // Note: ccs must follow the archives, and the archives must start at the
+    //  encoding base. However, the exact placement of ccs does not matter as
+    //  long as it it resides in the encoding range of CompressedKlassPointers
+    //  and comes after the archive.
+    //
+    // We do this by splitting up the allocated 4G into 3G of archive space,
+    //  followed by 1G for the ccs:
+    // + The upper 1 GB is used as the "temporary compressed class space"
+    //   -- preload_classes() will store Klasses into this space.
+    // + The lower 3 GB is used for the archive -- when preload_classes()
+    //   is done, ArchiveCompactor will copy the class metadata into this
+    //   space, first the RW parts, then the RO parts.
+
+    // Starting address of ccs must be aligned to Metaspace::reserve_alignment()...
+    size_t class_space_size = align_down(_shared_rs.size() / 4, Metaspace::reserve_alignment());
+    address class_space_start = (address)align_down(_shared_rs.end() - class_space_size, Metaspace::reserve_alignment());
+    size_t archive_size = class_space_start - (address)_shared_rs.base();
+
+    ReservedSpace tmp_class_space = _shared_rs.last_part(archive_size);
+    _shared_rs = _shared_rs.first_part(archive_size);
+
+    // ... as does the size of ccs.
+    tmp_class_space = tmp_class_space.first_part(class_space_size);
+    CompressedClassSpaceSize = class_space_size;
+
+    // Let Metaspace initialize ccs
     Metaspace::initialize_class_space(tmp_class_space);
+
+    // and set up CompressedKlassPointers encoding.
+    CompressedKlassPointers::initialize((address)_shared_rs.base(), cds_total);
+
+    log_info(cds)("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+                  p2i(CompressedKlassPointers::base()), CompressedKlassPointers::shift());
+
+    log_info(cds)("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
+                  CompressedClassSpaceSize, p2i(tmp_class_space.base()));
+
+    assert(_shared_rs.end() == tmp_class_space.base() &&
+           is_aligned(_shared_rs.base(), MetaspaceShared::reserved_space_alignment()) &&
+           is_aligned(tmp_class_space.base(), Metaspace::reserve_alignment()) &&
+           is_aligned(tmp_class_space.size(), Metaspace::reserve_alignment()), "Sanity");
   }
-  log_info(cds)("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
-                p2i(CompressedKlassPointers::base()), CompressedKlassPointers::shift());
 
-  log_info(cds)("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
-                CompressedClassSpaceSize, p2i(tmp_class_space.base()));
 #endif
 
   init_shared_dump_space(&_mc_region);
@@ -2073,6 +2130,7 @@
 void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
   assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
   MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
+
   FileMapInfo* static_mapinfo = open_static_archive();
   FileMapInfo* dynamic_mapinfo = NULL;
 
@@ -2149,7 +2207,8 @@
                                                bool use_requested_addr) {
   PRODUCT_ONLY(if (ArchiveRelocationMode == 1 && use_requested_addr) {
       // For product build only -- this is for benchmarking the cost of doing relocation.
-      // For debug builds, the check is done in FileMapInfo::map_regions for better test coverage.
+      // For debug builds, the check is done below, after reserving the space, for better test coverage
+      // (see comment below).
       log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address");
       return MAP_ARCHIVE_MMAP_FAILURE;
     });
@@ -2165,26 +2224,71 @@
     assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap");
   }
 
-  ReservedSpace main_rs, archive_space_rs, class_space_rs;
+  ReservedSpace archive_space_rs, class_space_rs;
   MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
   char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo,
-                                                                 use_requested_addr, main_rs, archive_space_rs,
+                                                                 use_requested_addr, archive_space_rs,
                                                                  class_space_rs);
   if (mapped_base_address == NULL) {
     result = MAP_ARCHIVE_MMAP_FAILURE;
   } else {
+
+#ifdef ASSERT
+    // Some sanity checks after reserving address spaces for archives
+    //  and class space.
+    assert(archive_space_rs.is_reserved(), "Sanity");
+    if (Metaspace::using_class_space()) {
+      // Class space must closely follow the archive space. Both spaces
+      //  must be aligned correctly.
+      assert(class_space_rs.is_reserved(),
+             "A class space should have been reserved");
+      assert(class_space_rs.base() >= archive_space_rs.end(),
+             "class space should follow the cds archive space");
+      assert(is_aligned(archive_space_rs.base(),
+                        MetaspaceShared::reserved_space_alignment()),
+             "Archive space misaligned");
+      assert(is_aligned(class_space_rs.base(),
+                        Metaspace::reserve_alignment()),
+             "class space misaligned");
+    }
+#endif // ASSERT
+
     log_debug(cds)("Reserved archive_space_rs     [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
                    p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size());
     log_debug(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
                    p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size());
+
+    if (MetaspaceShared::use_windows_memory_mapping()) {
+      // We have now reserved address space for the archives, and will map in
+      //  the archive files into this space.
+      //
+      // Special handling for Windows: on Windows we cannot map a file view
+      //  into an existing memory mapping. So, we unmap the address range we
+      //  just reserved again, which will make it available for mapping the
+      //  archives.
+      // Reserving this range has not been for naught however since it makes
+      //  us reasonably sure the address range is available.
+      //
+      // But still it may fail, since between unmapping the range and mapping
+      //  in the archive someone else may grab the address space. Therefore
+      //  there is a fallback in FileMap::map_region() where we just read in
+      //  the archive files sequentially instead of mapping it in. We couple
+      //  this with use_requested_addr, since we're going to patch all the
+      //  pointers anyway so there's no benefit to mmap.
+      if (use_requested_addr) {
+        log_info(cds)("Windows mmap workaround: releasing archive space.");
+        archive_space_rs.release();
+      }
+    }
     MapArchiveResult static_result = map_archive(static_mapinfo, mapped_base_address, archive_space_rs);
     MapArchiveResult dynamic_result = (static_result == MAP_ARCHIVE_SUCCESS) ?
                                      map_archive(dynamic_mapinfo, mapped_base_address, archive_space_rs) : MAP_ARCHIVE_OTHER_FAILURE;
 
     DEBUG_ONLY(if (ArchiveRelocationMode == 1 && use_requested_addr) {
-      // This is for simulating mmap failures at the requested address. In debug builds, we do it
-      // here (after all archives have possibly been mapped), so we can thoroughly test the code for
-      // failure handling (releasing all allocated resource, etc).
+      // This is for simulating mmap failures at the requested address. In
+      //  debug builds, we do it here (after all archives have possibly been
+      //  mapped), so we can thoroughly test the code for failure handling
+      //  (releasing all allocated resource, etc).
       log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address");
       if (static_result == MAP_ARCHIVE_SUCCESS) {
         static_result = MAP_ARCHIVE_MMAP_FAILURE;
@@ -2217,121 +2321,203 @@
   }
 
   if (result == MAP_ARCHIVE_SUCCESS) {
-    if (!main_rs.is_reserved() && class_space_rs.is_reserved()) {
-      MemTracker::record_virtual_memory_type((address)class_space_rs.base(), mtClass);
-    }
     SharedBaseAddress = (size_t)mapped_base_address;
     LP64_ONLY({
         if (Metaspace::using_class_space()) {
-          assert(class_space_rs.is_reserved(), "must be");
-          char* cds_base = static_mapinfo->mapped_base();
-          Metaspace::allocate_metaspace_compressed_klass_ptrs(class_space_rs, NULL, (address)cds_base);
+          // Set up ccs in metaspace.
+          Metaspace::initialize_class_space(class_space_rs);
+
+          // Set up compressed Klass pointer encoding: the encoding range must
+          //  cover both archive and class space.
+          address cds_base = (address)static_mapinfo->mapped_base();
+          address ccs_end = (address)class_space_rs.end();
+          CompressedKlassPointers::initialize(cds_base, ccs_end - cds_base);
+
           // map_heap_regions() compares the current narrow oop and klass encodings
           // with the archived ones, so it must be done after all encodings are determined.
           static_mapinfo->map_heap_regions();
-          CompressedKlassPointers::set_range(CompressedClassSpaceSize);
         }
       });
   } else {
     unmap_archive(static_mapinfo);
     unmap_archive(dynamic_mapinfo);
-    release_reserved_spaces(main_rs, archive_space_rs, class_space_rs);
+    release_reserved_spaces(archive_space_rs, class_space_rs);
   }
 
   return result;
 }
 
+
+// This will reserve two address spaces suitable to house Klass structures, one
+//  for the cds archives (static archive and optionally dynamic archive) and
+//  optionally one move for ccs.
+//
+// Since both spaces must fall within the compressed class pointer encoding
+//  range, they are allocated close to each other.
+//
+// Space for archives will be reserved first, followed by a potential gap,
+//  followed by the space for ccs:
+//
+// +-- Base address             A        B                     End
+// |                            |        |                      |
+// v                            v        v                      v
+// +-------------+--------------+        +----------------------+
+// | static arc  | [dyn. arch]  | [gap]  | compr. class space   |
+// +-------------+--------------+        +----------------------+
+//
+// (The gap may result from different alignment requirements between metaspace
+//  and CDS)
+//
+// If UseCompressedClassPointers is disabled, only one address space will be
+//  reserved:
+//
+// +-- Base address             End
+// |                            |
+// v                            v
+// +-------------+--------------+
+// | static arc  | [dyn. arch]  |
+// +-------------+--------------+
+//
+// Base address: If use_archive_base_addr address is true, the Base address is
+//  determined by the address stored in the static archive. If
+//  use_archive_base_addr address is false, this base address is determined
+//  by the platform.
+//
+// If UseCompressedClassPointers=1, the range encompassing both spaces will be
+//  suitable to en/decode narrow Klass pointers: the base will be valid for
+//  encoding, the range [Base, End) not surpass KlassEncodingMetaspaceMax.
+//
+// Return:
+//
+// - On success:
+//    - archive_space_rs will be reserved and large enough to host static and
+//      if needed dynamic archive: [Base, A).
+//      archive_space_rs.base and size will be aligned to CDS reserve
+//      granularity.
+//    - class_space_rs: If UseCompressedClassPointers=1, class_space_rs will
+//      be reserved. Its start address will be aligned to metaspace reserve
+//      alignment, which may differ from CDS alignment. It will follow the cds
+//      archive space, close enough such that narrow class pointer encoding
+//      covers both spaces.
+//      If UseCompressedClassPointers=0, class_space_rs remains unreserved.
+// - On error: NULL is returned and the spaces remain unreserved.
 char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
                                                           FileMapInfo* dynamic_mapinfo,
-                                                          bool use_requested_addr,
-                                                          ReservedSpace& main_rs,
+                                                          bool use_archive_base_addr,
                                                           ReservedSpace& archive_space_rs,
                                                           ReservedSpace& class_space_rs) {
-  const bool use_klass_space = NOT_LP64(false) LP64_ONLY(Metaspace::using_class_space());
-  const size_t class_space_size = NOT_LP64(0) LP64_ONLY(Metaspace::compressed_class_space_size());
 
-  if (use_klass_space) {
-    assert(class_space_size > 0, "CompressedClassSpaceSize must have been validated");
+  address const base_address = (address) (use_archive_base_addr ? static_mapinfo->requested_base_address() : NULL);
+  const size_t archive_space_alignment = MetaspaceShared::reserved_space_alignment();
+
+  // Size and requested location of the archive_space_rs (for both static and dynamic archives)
+  assert(static_mapinfo->mapping_base_offset() == 0, "Must be");
+  size_t archive_end_offset  = (dynamic_mapinfo == NULL) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset();
+  size_t archive_space_size = align_up(archive_end_offset, archive_space_alignment);
+
+  // If a base address is given, it must have valid alignment and be suitable as encoding base.
+  if (base_address != NULL) {
+    assert(is_aligned(base_address, archive_space_alignment),
+           "Archive base address invalid: " PTR_FORMAT ".", p2i(base_address));
+    if (Metaspace::using_class_space()) {
+      assert(CompressedKlassPointers::is_valid_base(base_address),
+             "Archive base address invalid: " PTR_FORMAT ".", p2i(base_address));
+    }
   }
-  if (use_requested_addr && !is_aligned(static_mapinfo->requested_base_address(), reserved_space_alignment())) {
+
+  if (!Metaspace::using_class_space()) {
+    // Get the simple case out of the way first:
+    // no compressed class space, simple allocation.
+    archive_space_rs = ReservedSpace(archive_space_size, archive_space_alignment,
+                                     false /* bool large */, (char*)base_address);
+    if (archive_space_rs.is_reserved()) {
+      assert(base_address == NULL ||
+             (address)archive_space_rs.base() == base_address, "Sanity");
+      return archive_space_rs.base();
+    }
     return NULL;
   }
 
-  // Size and requested location of the archive_space_rs (for both static and dynamic archives)
-  size_t base_offset = static_mapinfo->mapping_base_offset();
-  size_t end_offset  = (dynamic_mapinfo == NULL) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset();
-  assert(base_offset == 0, "must be");
-  assert(is_aligned(end_offset,  os::vm_allocation_granularity()), "must be");
-  assert(is_aligned(base_offset, os::vm_allocation_granularity()), "must be");
+#ifdef _LP64
 
-  // In case reserved_space_alignment() != os::vm_allocation_granularity()
-  assert((size_t)os::vm_allocation_granularity() <= reserved_space_alignment(), "must be");
-  end_offset = align_up(end_offset, reserved_space_alignment());
+  // Complex case: two spaces adjacent to each other, both to be addressable
+  //  with narrow class pointers.
+  // We reserve the whole range spanning both spaces, then split that range up.
 
-  size_t archive_space_size = end_offset - base_offset;
+  const size_t class_space_alignment = Metaspace::reserve_alignment();
 
-  // Special handling for Windows because it cannot mmap into a reserved space:
-  //    use_requested_addr: We just map each region individually, and give up if any one of them fails.
-  //   !use_requested_addr: We reserve the space first, and then os::read in all the regions (instead of mmap).
-  //                        We're going to patch all the pointers anyway so there's no benefit for mmap.
+  // To simplify matters, lets assume that metaspace alignment will always be
+  //  equal or a multiple of archive alignment.
+  assert(is_power_of_2(class_space_alignment) &&
+                       is_power_of_2(archive_space_alignment) &&
+                       class_space_alignment >= archive_space_alignment,
+                       "Sanity");
 
-  if (use_requested_addr) {
-    char* archive_space_base = static_mapinfo->requested_base_address() + base_offset;
-    char* archive_space_end  = archive_space_base + archive_space_size;
-    if (!MetaspaceShared::use_windows_memory_mapping()) {
-      archive_space_rs = reserve_shared_space(archive_space_size, archive_space_base);
-      if (!archive_space_rs.is_reserved()) {
-        return NULL;
-      }
-    }
-    if (use_klass_space) {
-      // Make sure we can map the klass space immediately following the archive_space space
-      // Don't call reserve_shared_space here as that may try to enforce platform-specific
-      // alignment rules which only apply to the archive base address
-      char* class_space_base = archive_space_end;
-      class_space_rs = ReservedSpace(class_space_size, reserved_space_alignment(),
-                                     false /* large_pages */, class_space_base);
-      if (!class_space_rs.is_reserved()) {
-        return NULL;
-      }
-    }
-    return static_mapinfo->requested_base_address();
+  const size_t class_space_size = CompressedClassSpaceSize;
+  assert(CompressedClassSpaceSize > 0 &&
+         is_aligned(CompressedClassSpaceSize, class_space_alignment),
+         "CompressedClassSpaceSize malformed: "
+         SIZE_FORMAT, CompressedClassSpaceSize);
+
+  const size_t ccs_begin_offset = align_up(archive_space_size,
+                                           class_space_alignment);
+  const size_t gap_size = ccs_begin_offset - archive_space_size;
+
+  const size_t total_range_size =
+      align_up(archive_space_size + gap_size + class_space_size,
+               os::vm_allocation_granularity());
+
+  ReservedSpace total_rs;
+  if (base_address != NULL) {
+    // Reserve at the given archive base address, or not at all.
+    total_rs = ReservedSpace(total_range_size, archive_space_alignment,
+                             false /* bool large */, (char*) base_address);
   } else {
-    if (use_klass_space) {
-      main_rs = reserve_shared_space(archive_space_size + class_space_size);
-      if (main_rs.is_reserved()) {
-        archive_space_rs = main_rs.first_part(archive_space_size, reserved_space_alignment(), /*split=*/true);
-        class_space_rs = main_rs.last_part(archive_space_size);
-      }
-    } else {
-      main_rs = reserve_shared_space(archive_space_size);
-      archive_space_rs = main_rs;
-    }
-    if (archive_space_rs.is_reserved()) {
-      return archive_space_rs.base();
-    } else {
-      return NULL;
-    }
+    // Reserve at any address, but leave it up to the platform to choose a good one.
+    total_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size);
   }
+
+  if (!total_rs.is_reserved()) {
+    return NULL;
+  }
+
+  // Paranoid checks:
+  assert(base_address == NULL || (address)total_rs.base() == base_address,
+         "Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_rs.base()));
+  assert(is_aligned(total_rs.base(), archive_space_alignment), "Sanity");
+  assert(total_rs.size() == total_range_size, "Sanity");
+  assert(CompressedKlassPointers::is_valid_base((address)total_rs.base()), "Sanity");
+
+  // Now split up the space into ccs and cds archive. For simplicity, just leave
+  //  the gap reserved at the end of the archive space.
+  archive_space_rs = total_rs.first_part(ccs_begin_offset,
+                                         (size_t)os::vm_allocation_granularity(),
+                                         /*split=*/true);
+  class_space_rs = total_rs.last_part(ccs_begin_offset);
+
+  assert(is_aligned(archive_space_rs.base(), archive_space_alignment), "Sanity");
+  assert(is_aligned(archive_space_rs.size(), archive_space_alignment), "Sanity");
+  assert(is_aligned(class_space_rs.base(), class_space_alignment), "Sanity");
+  assert(is_aligned(class_space_rs.size(), class_space_alignment), "Sanity");
+
+  return archive_space_rs.base();
+
+#else
+  ShouldNotReachHere();
+  return NULL;
+#endif
+
 }
 
-void MetaspaceShared::release_reserved_spaces(ReservedSpace& main_rs,
-                                              ReservedSpace& archive_space_rs,
+void MetaspaceShared::release_reserved_spaces(ReservedSpace& archive_space_rs,
                                               ReservedSpace& class_space_rs) {
-  if (main_rs.is_reserved()) {
-    assert(main_rs.contains(archive_space_rs.base()), "must be");
-    assert(main_rs.contains(class_space_rs.base()), "must be");
-    log_debug(cds)("Released shared space (archive+classes) " INTPTR_FORMAT, p2i(main_rs.base()));
-    main_rs.release();
-  } else {
-    if (archive_space_rs.is_reserved()) {
-      log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
-      archive_space_rs.release();
-    }
-    if (class_space_rs.is_reserved()) {
-      log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
-      class_space_rs.release();
-    }
+  if (archive_space_rs.is_reserved()) {
+    log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
+    archive_space_rs.release();
+  }
+  if (class_space_rs.is_reserved()) {
+    log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
+    class_space_rs.release();
   }
 }
 
@@ -2476,3 +2662,31 @@
   return intx(Arguments::default_SharedBaseAddress())  // We want the archive to be mapped to here at runtime
        - intx(SharedBaseAddress);                      // .. but the archive is mapped at here at dump time
 }
+
+void MetaspaceShared::print_on(outputStream* st) {
+  if (UseSharedSpaces || DumpSharedSpaces) {
+    st->print("CDS archive(s) mapped at: ");
+    address base;
+    address top;
+    if (UseSharedSpaces) { // Runtime
+      base = (address)MetaspaceObj::shared_metaspace_base();
+      address static_top = (address)_shared_metaspace_static_top;
+      top = (address)MetaspaceObj::shared_metaspace_top();
+      st->print("[" PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "), ", p2i(base), p2i(static_top), p2i(top));
+    } else if (DumpSharedSpaces) { // Dump Time
+      base = (address)_shared_rs.base();
+      top = (address)_shared_rs.end();
+      st->print("[" PTR_FORMAT "-" PTR_FORMAT "), ", p2i(base), p2i(top));
+    }
+    st->print("size " SIZE_FORMAT ", ", top - base);
+    st->print("SharedBaseAddress: " PTR_FORMAT ", ArchiveRelocationMode: %d.", SharedBaseAddress, (int)ArchiveRelocationMode);
+  } else {
+    st->print("CDS disabled.");
+  }
+  st->cr();
+}
+
+
+
+
+
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Sun May 24 19:25:29 2020 +0200
@@ -36,6 +36,7 @@
 
 #define MAX_SHARED_DELTA                (0x7FFFFFFF)
 
+class outputStream;
 class FileMapInfo;
 class CHeapBitMap;
 struct ArchiveHeapOopmapInfo;
@@ -166,6 +167,8 @@
 class MetaspaceShared : AllStatic {
 
   // CDS support
+
+  // Note: _shared_rs and _symbol_rs are only used at dump time.
   static ReservedSpace _shared_rs;
   static VirtualSpace _shared_vs;
   static ReservedSpace _symbol_rs;
@@ -227,6 +230,8 @@
   static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN;
   static void post_initialize(TRAPS) NOT_CDS_RETURN;
 
+  static void print_on(outputStream* st);
+
   // Delta of this object from SharedBaseAddress
   static uintx object_delta_uintx(void* obj);
 
@@ -296,7 +301,6 @@
   static void link_and_cleanup_shared_classes(TRAPS) NOT_CDS_RETURN;
 
 #if INCLUDE_CDS
-  static ReservedSpace reserve_shared_space(size_t size, char* requested_address = NULL);
   static size_t reserved_space_alignment();
   static void init_shared_dump_space(DumpRegion* first_space);
   static DumpRegion* misc_code_dump_space();
@@ -369,16 +373,15 @@
   static void read_extra_data(const char* filename, TRAPS) NOT_CDS_RETURN;
   static FileMapInfo* open_static_archive();
   static FileMapInfo* open_dynamic_archive();
+  // use_requested_addr: If true (default), attempt to map at the address the
   static MapArchiveResult map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo,
                                        bool use_requested_addr);
   static char* reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
                                                   FileMapInfo* dynamic_mapinfo,
-                                                  bool use_requested_addr,
-                                                  ReservedSpace& main_rs,
+                                                  bool use_archive_base_addr,
                                                   ReservedSpace& archive_space_rs,
                                                   ReservedSpace& class_space_rs);
-  static void release_reserved_spaces(ReservedSpace& main_rs,
-                                      ReservedSpace& archive_space_rs,
+  static void release_reserved_spaces(ReservedSpace& archive_space_rs,
                                       ReservedSpace& class_space_rs);
   static MapArchiveResult map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs);
   static void unmap_archive(FileMapInfo* mapinfo);
--- a/src/hotspot/share/oops/compressedOops.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/oops/compressedOops.cpp	Sun May 24 19:25:29 2020 +0200
@@ -182,7 +182,103 @@
 NarrowPtrStruct CompressedKlassPointers::_narrow_klass = { NULL, 0, true };
 
 // CompressedClassSpaceSize set to 1GB, but appear 3GB away from _narrow_ptrs_base during CDS dump.
-uint64_t CompressedKlassPointers::_narrow_klass_range = (uint64_t(max_juint)+1);;
+// (Todo: we should #ifdef out CompressedKlassPointers for 32bit completely and fix all call sites which
+//  are compiled for 32bit to LP64_ONLY).
+size_t CompressedKlassPointers::_range = 0;
+
+
+// Given an address range [addr, addr+len) which the encoding is supposed to
+//  cover, choose base, shift and range.
+//  The address range is the expected range of uncompressed Klass pointers we
+//  will encounter (and the implicit promise that there will be no Klass
+//  structures outside this range).
+void CompressedKlassPointers::initialize(address addr, size_t len) {
+#ifdef _LP64
+  assert(is_valid_base(addr), "Address must be a valid encoding base");
+  address const end = addr + len;
+
+  address base;
+  int shift;
+  size_t range;
+
+  if (UseSharedSpaces || DumpSharedSpaces) {
+
+    // Special requirements if CDS is active:
+    // Encoding base and shift must be the same between dump and run time.
+    //   CDS takes care that the SharedBaseAddress and CompressedClassSpaceSize
+    //   are the same. Archive size will be probably different at runtime, but
+    //   it can only be smaller than at, never larger, since archives get
+    //   shrunk at the end of the dump process.
+    //   From that it follows that the range [addr, len) we are handed in at
+    //   runtime will start at the same address then at dumptime, and its len
+    //   may be smaller at runtime then it was at dump time.
+    //
+    // To be very careful here, we avoid any optimizations and just keep using
+    //  the same address and shift value. Specifically we avoid using zero-based
+    //  encoding. We also set the expected value range to 4G (encoding range
+    //  cannot be larger than that).
+
+    base = addr;
+    shift = LogKlassAlignmentInBytes;
+
+    // This must be true since at dumptime cds+ccs is 4G, at runtime it can
+    //  only be smaller, see comment above.
+    assert(len <= 4 * G, "Encoding range cannot be larger than 4G");
+    range = 4 * G;
+
+  } else {
+
+    // Otherwise we attempt to use a zero base if the range fits in lower 32G.
+    if (end <= (address)KlassEncodingMetaspaceMax) {
+      base = 0;
+    } else {
+      base = addr;
+    }
+
+    // Highest offset a Klass* can ever have in relation to base.
+    range = end - base;
+
+    // We may not even need a shift if the range fits into 32bit:
+    const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
+    if (range < UnscaledClassSpaceMax) {
+      shift = 0;
+    } else {
+      shift = LogKlassAlignmentInBytes;
+    }
+
+  }
+
+  set_base(base);
+  set_shift(shift);
+  set_range(range);
+
+  // Note: this may modify our shift.
+  AOTLoader::set_narrow_klass_shift();
+#else
+  fatal("64bit only.");
+#endif
+}
+
+// Given an address p, return true if p can be used as an encoding base.
+//  (Some platforms have restrictions of what constitutes a valid base address).
+bool CompressedKlassPointers::is_valid_base(address p) {
+#ifdef AARCH64
+  // Below 32G, base must be aligned to 4G.
+  // Above that point, base must be aligned to 32G
+  if (p < (address)(32 * G)) {
+    return is_aligned(p, 4 * G);
+  }
+  return is_aligned(p, (4 << LogKlassAlignmentInBytes) * G);
+#else
+  return true;
+#endif
+}
+
+void CompressedKlassPointers::print_mode(outputStream* st) {
+  st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d, "
+               "Narrow klass range: " SIZE_FORMAT_HEX, p2i(base()), shift(),
+               range());
+}
 
 void CompressedKlassPointers::set_base(address base) {
   assert(UseCompressedClassPointers, "no compressed klass ptrs?");
@@ -194,7 +290,7 @@
   _narrow_klass._shift   = shift;
 }
 
-void CompressedKlassPointers::set_range(uint64_t range) {
+void CompressedKlassPointers::set_range(size_t range) {
   assert(UseCompressedClassPointers, "no compressed klass ptrs?");
-  _narrow_klass_range = range;
+  _range = range;
 }
--- a/src/hotspot/share/oops/compressedOops.hpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/oops/compressedOops.hpp	Sun May 24 19:25:29 2020 +0200
@@ -133,16 +133,37 @@
 
   static NarrowPtrStruct _narrow_klass;
 
-  // CompressedClassSpaceSize set to 1GB, but appear 3GB away from _narrow_ptrs_base during CDS dump.
-  static uint64_t _narrow_klass_range;
+  // Together with base, this defines the address range within which Klass
+  //  structures will be located: [base, base+range). While the maximal
+  //  possible encoding range is 4|32G for shift 0|3, if we know beforehand
+  //  the expected range of Klass* pointers will be smaller, a platform
+  //  could use this info to optimize encoding.
+  static size_t _range;
+
+  static void set_base(address base);
+  static void set_range(size_t range);
 
 public:
-  static void set_base(address base);
+
   static void set_shift(int shift);
-  static void set_range(uint64_t range);
+
+
+  // Given an address p, return true if p can be used as an encoding base.
+  //  (Some platforms have restrictions of what constitutes a valid base
+  //   address).
+  static bool is_valid_base(address p);
+
+  // Given an address range [addr, addr+len) which the encoding is supposed to
+  //  cover, choose base, shift and range.
+  //  The address range is the expected range of uncompressed Klass pointers we
+  //  will encounter (and the implicit promise that there will be no Klass
+  //  structures outside this range).
+  static void initialize(address addr, size_t len);
+
+  static void     print_mode(outputStream* st);
 
   static address  base()               { return  _narrow_klass._base; }
-  static uint64_t range()              { return  _narrow_klass_range; }
+  static size_t   range()              { return  _range; }
   static int      shift()              { return  _narrow_klass._shift; }
 
   static bool is_null(Klass* v)      { return v == NULL; }
@@ -153,6 +174,7 @@
   static inline Klass* decode(narrowKlass v);
   static inline narrowKlass encode_not_null(Klass* v);
   static inline narrowKlass encode(Klass* v);
+
 };
 
 #endif // SHARE_OOPS_COMPRESSEDOOPS_HPP
--- a/src/hotspot/share/services/virtualMemoryTracker.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/services/virtualMemoryTracker.cpp	Sun May 24 19:25:29 2020 +0200
@@ -403,7 +403,8 @@
   if (reserved_rgn != NULL) {
     assert(reserved_rgn->contain_address(addr), "Containment");
     if (reserved_rgn->flag() != flag) {
-      assert(reserved_rgn->flag() == mtNone, "Overwrite memory type");
+      assert(reserved_rgn->flag() == mtNone, "Overwrite memory type (should be mtNone, is: \"%s\")",
+             NMTUtil::flag_to_name(reserved_rgn->flag()));
       reserved_rgn->set_flag(flag);
     }
   }
--- a/src/hotspot/share/utilities/vmError.cpp	Sat May 23 10:39:07 2020 +0000
+++ b/src/hotspot/share/utilities/vmError.cpp	Sun May 24 19:25:29 2020 +0200
@@ -29,6 +29,8 @@
 #include "compiler/disassembler.hpp"
 #include "gc/shared/gcConfig.hpp"
 #include "logging/logConfiguration.hpp"
+#include "memory/metaspace.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/compressedOops.hpp"
@@ -907,15 +909,19 @@
        st->cr();
      }
 
+#ifdef _LP64
   STEP("printing compressed oops mode")
 
      if (_verbose && UseCompressedOops) {
        CompressedOops::print_mode(st);
        if (UseCompressedClassPointers) {
+         CDS_ONLY(MetaspaceShared::print_on(st);)
          Metaspace::print_compressed_class_space(st);
+         CompressedKlassPointers::print_mode(st);
        }
        st->cr();
      }
+#endif
 
   STEP("printing heap information")
 
@@ -1108,15 +1114,18 @@
     st->cr();
   }
 
+#ifdef _LP64
   // STEP("printing compressed oops mode")
-
   if (UseCompressedOops) {
     CompressedOops::print_mode(st);
     if (UseCompressedClassPointers) {
+      CDS_ONLY(MetaspaceShared::print_on(st);)
       Metaspace::print_compressed_class_space(st);
+      CompressedKlassPointers::print_mode(st);
     }
     st->cr();
   }
+#endif
 
   // STEP("printing heap information")
 
--- a/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java	Sat May 23 10:39:07 2020 +0000
+++ b/test/hotspot/jtreg/gc/logging/TestMetaSpaceLog.java	Sun May 24 19:25:29 2020 +0200
@@ -56,6 +56,8 @@
 
   static {
     // Do this once here.
+    // Scan for Metaspace update notices as part of the GC log, e.g. in this form:
+    // [gc,metaspace   ] GC(0) Metaspace: 11895K(14208K)->11895K(14208K) NonClass: 10552K(12544K)->10552K(12544K) Class: 1343K(1664K)->1343K(1664K)
     metaSpaceRegexp = Pattern.compile(".*Metaspace: ([0-9]+).*->([0-9]+).*");
   }
 
@@ -73,10 +75,13 @@
 
   private static boolean check(String line) {
     Matcher m = metaSpaceRegexp.matcher(line);
-    Asserts.assertTrue(m.matches(), "Unexpected line for metaspace logging: " + line);
-    long before = Long.parseLong(m.group(1));
-    long after  = Long.parseLong(m.group(2));
-    return before > after;
+    if (m.matches()) {
+      // Numbers for Metaspace occupation should grow.
+      long before = Long.parseLong(m.group(1));
+      long after = Long.parseLong(m.group(2));
+      return before > after;
+    }
+    return false;
   }
 
   private static void testMetaSpaceUpdate() throws Exception {
--- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java	Sat May 23 10:39:07 2020 +0000
+++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java	Sun May 24 19:25:29 2020 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8024927
  * @summary Testing address of compressed class pointer space as best as possible.
- * @requires vm.bits == 64 & os.family != "windows" & !vm.graal.enabled
+ * @requires vm.bits == 64 & !vm.graal.enabled
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  *          java.management
@@ -39,59 +39,101 @@
 
 public class CompressedClassPointers {
 
+    static final String logging_option = "-Xlog:gc+metaspace=trace,cds=trace";
+
+    // Returns true if we are to test the narrow klass base; we only do this on
+    // platforms where we can be reasonably shure that we get reproducable placement).
+    static boolean testNarrowKlassBase() {
+        if (Platform.isWindows() || Platform.isPPC()) {
+            return false;
+        }
+        return true;
+
+    }
+
+    // CDS off, small heap, ccs size default (1G)
+    // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.
     public static void smallHeapTest() throws Exception {
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
             "-XX:+UnlockDiagnosticVMOptions",
             "-XX:SharedBaseAddress=8g",
             "-Xmx128m",
-            "-Xlog:gc+metaspace=trace",
+            logging_option,
             "-Xshare:off",
-            "-Xlog:cds=trace",
             "-XX:+VerifyBeforeGC", "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Narrow klass base: 0x0000000000000000");
+        if (testNarrowKlassBase()) {
+            output.shouldContain("Narrow klass base: 0x0000000000000000");
+        }
         output.shouldHaveExitValue(0);
     }
 
+    // CDS off, small heap, ccs size explicitely set to 1G
+    // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.
     public static void smallHeapTestWith1G() throws Exception {
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
             "-XX:+UnlockDiagnosticVMOptions",
             "-XX:CompressedClassSpaceSize=1g",
             "-Xmx128m",
-            "-Xlog:gc+metaspace=trace",
+            logging_option,
             "-Xshare:off",
-            "-Xlog:cds=trace",
             "-XX:+VerifyBeforeGC", "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3");
+        if (testNarrowKlassBase()) {
+            output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3");
+        }
         output.shouldHaveExitValue(0);
     }
 
+    // CDS off, a very large heap, ccs size left to 1G default.
+    // We expect the ccs to be mapped somewhere far beyond the heap, such that it is not possible
+    // to use zero based encoding.
     public static void largeHeapTest() throws Exception {
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
             "-XX:+UnlockDiagnosticVMOptions",
             "-XX:+UnlockExperimentalVMOptions",
             "-Xmx30g",
             "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
-            "-Xlog:gc+metaspace=trace",
+            logging_option,
             "-Xshare:off",
-            "-Xlog:cds=trace",
             "-XX:+VerifyBeforeGC", "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
-        output.shouldNotContain("Narrow klass base: 0x0000000000000000");
-        output.shouldContain("Narrow klass shift: 0");
+        if (testNarrowKlassBase()) {
+            output.shouldNotContain("Narrow klass base: 0x0000000000000000");
+            output.shouldContain("Narrow klass shift: 0");
+        }
         output.shouldHaveExitValue(0);
     }
 
-    public static void largePagesTest() throws Exception {
+    // Using large paged heap, metaspace uses small pages.
+    public static void largePagesForHeapTest() throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-Xmx128m",
+                "-XX:+UseLargePages",
+                logging_option,
+                "-XX:+VerifyBeforeGC", "-version");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        if (testNarrowKlassBase()) {
+            output.shouldContain("Narrow klass base:");
+        }
+        output.shouldHaveExitValue(0);
+    }
+
+    // Using large pages for heap and metaspace.
+    // Note that this is still unexciting since the compressed class space always uses small pages;
+    // UseLargePagesInMetaspace only affects non-class metaspace.
+    public static void largePagesForHeapAndMetaspaceTest() throws Exception {
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
             "-XX:+UnlockDiagnosticVMOptions",
             "-Xmx128m",
-            "-XX:+UseLargePages",
-            "-Xlog:gc+metaspace=trace",
+            "-XX:+UseLargePages", "-XX:+UseLargePagesInMetaspace",
+            logging_option,
             "-XX:+VerifyBeforeGC", "-version");
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Narrow klass base:");
+        if (testNarrowKlassBase()) {
+            output.shouldContain("Narrow klass base:");
+        }
         output.shouldHaveExitValue(0);
     }
 
@@ -262,7 +304,8 @@
         smallHeapTest();
         smallHeapTestWith1G();
         largeHeapTest();
-        largePagesTest();
+        largePagesForHeapTest();
+        largePagesForHeapAndMetaspaceTest();
         heapBaseMinAddressTest();
         sharingTest();
 
--- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java	Sat May 23 10:39:07 2020 +0000
+++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java	Sun May 24 19:25:29 2020 +0200
@@ -69,7 +69,7 @@
                                                    "-Xlog:gc+metaspace=trace",
                                                    "-version");
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Compressed class space size: 1048576")
+        output.shouldMatch("Compressed class space.*1048576")
               .shouldHaveExitValue(0);
 
 
@@ -79,7 +79,7 @@
                                                    "-Xlog:gc+metaspace=trace",
                                                    "-version");
         output = new OutputAnalyzer(pb.start());
-        output.shouldContain("Compressed class space size: 3221225472")
+        output.shouldMatch("Compressed class space.*3221225472")
               .shouldHaveExitValue(0);
 
 
--- a/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java	Sat May 23 10:39:07 2020 +0000
+++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java	Sun May 24 19:25:29 2020 +0200
@@ -50,6 +50,9 @@
         for (String testEntry : testTable) {
             System.out.println("sharedBaseAddress = " + testEntry);
 
+            // Note: some platforms may restrict valid values for SharedBaseAddress; the VM should print
+            // a warning and use the default value instead. Similar, ASLR may prevent the given address
+            // from being used; this too should handled gracefully by using the default base address.
             OutputAnalyzer dumpOutput = TestCommon.dump(
                 appJar, new String[] {"Hello"}, "-XX:SharedBaseAddress=" + testEntry);
             TestCommon.checkDump(dumpOutput, "Loading classes to share");