< prev index next >

src/hotspot/share/memory/filemap.cpp

Print this page

@@ -33,16 +33,19 @@
 #include "classfile/altHashing.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "logging/logMessage.hpp"
 #include "memory/filemap.hpp"
+#include "memory/heapShared.inline.hpp"
+#include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceClosure.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/objArrayOop.hpp"
+#include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/java.hpp"
 #include "runtime/os.hpp"
 #include "runtime/vm_version.hpp"

@@ -186,10 +189,13 @@
   _narrow_klass_base = Universe::narrow_klass_base();
   _narrow_klass_shift = Universe::narrow_klass_shift();
   _shared_path_table_size = mapinfo->_shared_path_table_size;
   _shared_path_table = mapinfo->_shared_path_table;
   _shared_path_entry_size = mapinfo->_shared_path_entry_size;
+  if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+    _g1_reserved = G1CollectedHeap::heap()->g1_reserved();
+  }
 
   // The following fields are for sanity checks for whether this archive
   // will function correctly with this JVM and the bootclasspath it's
   // invoked with.
 

@@ -523,11 +529,11 @@
     _paths_misc_info = NULL;
     return false;
   }
 
   size_t len = lseek(fd, 0, SEEK_END);
-  struct FileMapInfo::FileMapHeader::space_info* si =
+  FileMapHeader::space_info* si =
     &_header->_space[MetaspaceShared::last_valid_region];
   // The last space might be empty
   if (si->_file_offset > len || len - si->_file_offset < si->_used) {
     fail_continue("The shared archive file has been truncated.");
     return false;

@@ -605,11 +611,11 @@
 
 // Dump region to file.
 
 void FileMapInfo::write_region(int region, char* base, size_t size,
                                bool read_only, bool allow_exec) {
-  struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[region];
+  FileMapHeader::space_info* si = &_header->_space[region];
 
   if (_file_open) {
     guarantee(si->_file_offset == _file_offset, "file offset mismatch.");
     log_info(cds)("Shared file region %d: " SIZE_FORMAT_HEX_W(08)
                   " bytes, addr " INTPTR_FORMAT " file offset " SIZE_FORMAT_HEX_W(08),

@@ -758,11 +764,11 @@
 
 // JVM/TI RedefineClasses() support:
 // Remap the shared readonly space to shared readwrite, private.
 bool FileMapInfo::remap_shared_readonly_as_readwrite() {
   int idx = MetaspaceShared::ro;
-  struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[idx];
+  FileMapHeader::space_info* si = &_header->_space[idx];
   if (!si->_read_only) {
     // the space is already readwrite so we are done
     return true;
   }
   size_t used = si->_used;

@@ -810,11 +816,11 @@
 static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
                                             "String1", "String2", "OpenArchive1", "OpenArchive2" };
 
 char* FileMapInfo::map_region(int i, char** top_ret) {
   assert(!MetaspaceShared::is_heap_region(i), "sanity");
-  struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+  FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t alignment = os::vm_allocation_granularity();
   size_t size = align_up(used, alignment);
   char *requested_addr = _header->region_addr(i);
 

@@ -850,10 +856,14 @@
 static MemRegion *open_archive_heap_ranges = NULL;
 static int num_string_ranges = 0;
 static int num_open_archive_heap_ranges = 0;
 
 #if INCLUDE_CDS_JAVA_HEAP
+bool FileMapInfo::has_heap_regions() {
+  return (_header->_space[MetaspaceShared::first_string]._used > 0);
+}
+
 //
 // Map the shared string objects and open archive heap objects to the runtime
 // java heap.
 //
 // The shared strings are mapped near the runtime java heap top. The

@@ -864,35 +874,60 @@
 // the runtime java heap. The mapped open archive heap data only contain
 // references to the shared strings and open archive objects initially.
 // During runtime execution, out-going references to any other java heap
 // regions may be added. GC may mark and update references in the mapped
 // open archive objects.
-void FileMapInfo::map_heap_regions() {
-  if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+void FileMapInfo::map_heap_regions_impl() {
+  if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+    log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, "
+                  "UseCompressedOops and UseCompressedClassPointers are required.");
+    return;
+  }
+
+  if (narrow_klass_base() != Universe::narrow_klass_base() ||
+      narrow_klass_shift() != Universe::narrow_klass_shift()) {
+    log_info(cds)("Cached heap data from the CDS archive need to be relocated because");
+    log_info(cds)("the CDS archive was created with an incompatible heap size: " UINTX_FORMAT "M.", max_heap_size()/M);
+    log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+                  p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
+    return;
+  }
+
       log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
                     narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
       log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
                     p2i(narrow_klass_base()), narrow_klass_shift());
 
-    // Check that all the narrow oop and klass encodings match the archive
+  ptrdiff_t delta = 0;
+
     if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
         narrow_oop_base() != Universe::narrow_oop_base() ||
-        narrow_oop_shift() != Universe::narrow_oop_shift() ||
-        narrow_klass_base() != Universe::narrow_klass_base() ||
-        narrow_klass_shift() != Universe::narrow_klass_shift()) {
-      if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
-        log_info(cds)("Cached heap data from the CDS archive is being ignored. "
-                      "The current CompressedOops/CompressedClassPointers encoding differs from "
-                      "that archived due to heap size change. The archive was dumped using max heap "
-                      "size " UINTX_FORMAT "M.", max_heap_size()/M);
+      narrow_oop_shift() != Universe::narrow_oop_shift()) {
+    log_info(cds)("Cached heap data from the CDS archive need to be relocated because");
+    log_info(cds)("the CDS archive was created with an incompatible heap size: " UINTX_FORMAT "M.", max_heap_size()/M);
         log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
                       Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()),
                       Universe::narrow_oop_shift());
-        log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
-                      p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
+
+    _heap_pointers_need_relocation = true;
+
+    //   dumptime heap end  ------------v
+    //   [      |archived heap regions| ]         runtime heap end ------v
+    //                                       [   |archived heap regions| ] 
+    //                                  |<-----delta-------------------->|
+    //
+    // At dump time, the archived heap region were near the top of the heap.
+    // At run time, that region may not be inside the heap, so we move it so
+    // that it's now near the top of teh runtime time. This can be done by
+    // the simple math of adding the delta as shown above.
+    address dumptime_heap_end = (address)_header->_g1_reserved.end();
+    address runtime_heap_end = (address)G1CollectedHeap::heap()->g1_reserved().end();
+    delta = runtime_heap_end - dumptime_heap_end;
       }
-    } else {
+
+  HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+
       // First, map string regions as closed archive heap regions.
       // GC does not write into the regions.
       if (map_heap_data(&string_ranges,
                          MetaspaceShared::first_string,
                          MetaspaceShared::max_strings,

@@ -906,16 +941,15 @@
                           &num_open_archive_heap_ranges,
                           true /* open */)) {
           MetaspaceShared::set_open_archive_heap_region_mapped();
         }
       }
-    }
-  } else {
-    if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
-      log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, "
-                    "UseCompressedOops and UseCompressedClassPointers are required.");
-    }
+}
+
+void FileMapInfo::map_heap_regions() {
+  if (has_heap_regions()) {
+    map_heap_regions_impl();
   }
 
   if (!StringTable::shared_string_mapped()) {
     assert(string_ranges == NULL && num_string_ranges == 0, "sanity");
   }

@@ -926,20 +960,19 @@
 }
 
 bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
                                 int max, int* num, bool is_open_archive) {
   MemRegion * regions = new MemRegion[max];
-  struct FileMapInfo::FileMapHeader::space_info* si;
+  FileMapHeader::space_info* si;
   int region_num = 0;
 
   for (int i = first;
            i < first + max; i++) {
     si = &_header->_space[i];
-    size_t used = si->_used;
-    if (used > 0) {
-      size_t size = used;
-      char* requested_addr = (char*)((void*)CompressedOops::decode_not_null(
+    size_t size = si->_used;
+    if (size > 0) {
+      char* requested_addr = (char*)((void*)HeapShared::decode_not_null(
                                             (narrowOop)si->_addr._offset));
       regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
       region_num ++;
     }
   }

@@ -1001,10 +1034,55 @@
     }
   }
   return true;
 }
 
+void FileMapInfo::relocate_archived_heap_embedded_pointers() {
+  if (!_heap_pointers_need_relocation) {
+    return;
+  }
+
+  relocate_archived_heap_embedded_pointers_impl(string_ranges,
+                                                num_string_ranges);
+
+  relocate_archived_heap_embedded_pointers_impl(open_archive_heap_ranges,
+                                                num_open_archive_heap_ranges);
+}
+
+class RelocateInternalPointers: public BasicOopIterateClosure {
+ public:
+  virtual bool should_verify_oops(void) {
+    return false;
+  }
+  virtual void do_oop(narrowOop *p) {
+    narrowOop v = *p;
+    if (!CompressedOops::is_null(v)) {
+      oop o = HeapShared::decode_not_null(v);
+      RawAccess<IS_NOT_NULL>::oop_store(p, o);
+    }
+  }
+  virtual void do_oop(oop *p) {
+    ShouldNotReachHere();
+  }
+};
+
+void FileMapInfo::relocate_archived_heap_embedded_pointers_impl(MemRegion *heap_mem, int num) {
+  RelocateInternalPointers relocator;
+
+  for (int i=0; i<num; i++) {
+    HeapWord* p   = heap_mem[i].start();
+    HeapWord* end = heap_mem[i].end();
+    while (p < end) {
+      oop o = (oop)p;
+      o->oop_iterate(&relocator);
+      p += o->size();
+    }
+  }
+}
+
+// This internally allocates objects using SystemDictionary::Object_klass(), so it
+// must be called after the well-known classes are resolved.
 void FileMapInfo::fixup_mapped_heap_regions() {
   // If any string regions were found, call the fill routine to make them parseable.
   // Note that string_ranges may be non-NULL even if no ranges were found.
   if (num_string_ranges != 0) {
     assert(string_ranges != NULL, "Null string_ranges array with non-zero count");

@@ -1055,11 +1133,11 @@
 
 // Unmap a memory region in the address space.
 
 void FileMapInfo::unmap_region(int i) {
   assert(!MetaspaceShared::is_heap_region(i), "sanity");
-  struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+  FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t size = align_up(used, os::vm_allocation_granularity());
 
   if (used == 0) {
     return;

@@ -1084,10 +1162,11 @@
   }
 }
 
 
 FileMapInfo* FileMapInfo::_current_info = NULL;
+bool FileMapInfo::_heap_pointers_need_relocation = false;
 Array<u8>* FileMapInfo::_shared_path_table = NULL;
 int FileMapInfo::_shared_path_table_size = 0;
 size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
 bool FileMapInfo::_validating_shared_path_table = false;
 
< prev index next >