< prev index next >

src/share/vm/memory/filemap.cpp

Print this page

        

@@ -26,10 +26,13 @@
 #include "classfile/classLoader.hpp"
 #include "classfile/sharedClassUtil.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/altHashing.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.hpp"
+#endif
 #include "memory/filemap.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/oopFactory.hpp"
 #include "oops/objArrayOop.hpp"
 #include "runtime/arguments.hpp"

@@ -163,10 +166,13 @@
 void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
   _magic = 0xf00baba2;
   _version = _current_version;
   _alignment = alignment;
   _obj_alignment = ObjectAlignmentInBytes;
+  _narrow_oop_mode = Universe::narrow_oop_mode();
+  _narrow_oop_shift = Universe::narrow_oop_shift();
+  _max_heap_size = MaxHeapSize;
   _classpath_entry_table_size = mapinfo->_classpath_entry_table_size;
   _classpath_entry_table = mapinfo->_classpath_entry_table;
   _classpath_entry_size = mapinfo->_classpath_entry_size;
 
   // The following fields are for sanity checks for whether this archive

@@ -438,19 +444,60 @@
                     " file offset 0x%6x", region, size, base, _file_offset);
     }
   } else {
     si->_file_offset = _file_offset;
   }
-  si->_base = base;
+  if (MetaspaceShared::is_string_region(region)) {
+    assert((base - (char*)Universe::narrow_oop_base()) % HeapWordSize == 0, "Sanity");
+    if (base != NULL) {
+      si->_addr._offset = (intx)oopDesc::encode_heap_oop_not_null((oop)base);
+    } else {
+      si->_addr._offset = 0;
+    }
+  } else {
+    si->_addr._base = base;
+  }
   si->_used = size;
   si->_capacity = capacity;
   si->_read_only = read_only;
   si->_allow_exec = allow_exec;
   si->_crc = ClassLoader::crc32(0, base, (jint)size);
   write_bytes_aligned(base, (int)size);
 }
 
+// Write the string space. The string space contains one or multiple GC(G1) regions.
+// When the total string space size is smaller than one GC region of the dump time,
+// only one string region is used for shared strings.
+//
+// If the total string space size is bigger than one GC region, there would be more
+// than one GC regions allocated for shared strings. The first/bottom GC region might
+// be a partial GC region with the empty portion at the higher address within that region.
+// The non-empty portion of the first region is written into the archive as one string
+// region. The rest are consecutive full GC regions if they exist, which can be written
+// out in one chunk as another string region.
+void FileMapInfo::write_string_regions(GrowableArray<MemRegion> *regions) {
+  for (int i = MetaspaceShared::first_string;
+           i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+    char* start = NULL;
+    size_t size = 0;
+    if (regions->is_nonempty()) {
+      if (i == MetaspaceShared::first_string) {
+        MemRegion first = regions->first();
+        start = (char*)first.start();
+        size = first.byte_size();
+      } else {
+        int len = regions->length();
+        if (len > 1) {
+          start = (char*)regions->at(1).start();
+          size = (char*)regions->at(len - 1).end() - start;
+        }
+      }
+    }
+    write_region(i, start, size, size, false, false);
+  }
+}
+
 
 // Dump bytes to file -- at the current file position.
 
 void FileMapInfo::write_bytes(const void* buffer, int nbytes) {
   if (_file_open) {

@@ -511,40 +558,42 @@
 
 
 // JVM/TI RedefineClasses() support:
 // Remap the shared readonly space to shared readwrite, private.
 bool FileMapInfo::remap_shared_readonly_as_readwrite() {
-  struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0];
+  int idx = 0;
+  struct FileMapInfo::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;
   size_t size = align_size_up(used, os::vm_allocation_granularity());
   if (!open_for_read()) {
     return false;
   }
+  char *addr = _header->region_addr(idx);
   char *base = os::remap_memory(_fd, _full_path, si->_file_offset,
-                                si->_base, size, false /* !read_only */,
+                                addr, size, false /* !read_only */,
                                 si->_allow_exec);
   close();
   if (base == NULL) {
     fail_continue("Unable to remap shared readonly space (errno=%d).", errno);
     return false;
   }
-  if (base != si->_base) {
+  if (base != addr) {
     fail_continue("Unable to remap shared readonly space at required address.");
     return false;
   }
   si->_read_only = false;
   return true;
 }
 
 // Map the whole region at once, assumed to be allocated contiguously.
 ReservedSpace FileMapInfo::reserve_shared_memory() {
   struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0];
-  char* requested_addr = si->_base;
+  char* requested_addr = _header->region_addr(0);
 
   size_t size = FileMapInfo::shared_spaces_size();
 
   // Reserve the space first, then map otherwise map will go right over some
   // other reserved memory (like the code cache).

@@ -558,41 +607,144 @@
 
   return rs;
 }
 
 // Memory map a region in the address space.
-static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode"};
+static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
+                                            "String1", "String2"};
 
 char* FileMapInfo::map_region(int i) {
+  assert(!MetaspaceShared::is_string_region(i), "sanity");
   struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t alignment = os::vm_allocation_granularity();
   size_t size = align_size_up(used, alignment);
-  char *requested_addr = si->_base;
+  char *requested_addr = _header->region_addr(i); 
 
   // map the contents of the CDS archive in this memory
   char *base = os::map_memory(_fd, _full_path, si->_file_offset,
                               requested_addr, size, si->_read_only,
                               si->_allow_exec);
-  if (base == NULL || base != si->_base) {
+  if (base == NULL || base != requested_addr) {
     fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
     return NULL;
   }
 #ifdef _WINDOWS
   // This call is Windows-only because the memory_type gets recorded for the other platforms
   // in method FileMapInfo::reserve_shared_memory(), which is not called on Windows.
   MemTracker::record_virtual_memory_type((address)base, mtClassShared);
 #endif
+
   return base;
 }
 
+MemRegion *string_ranges = NULL;
+int num_ranges = 0;
+bool FileMapInfo::map_string_regions() {
+#if INCLUDE_ALL_GCS
+  if (UseG1GC && UseCompressedOops && UseCompressedClassPointers) {
+    if (narrow_oop_mode() == Universe::narrow_oop_mode() &&
+        narrow_oop_shift() == Universe::narrow_oop_shift()) {
+      string_ranges = new MemRegion[MetaspaceShared::max_strings];
+      struct FileMapInfo::FileMapHeader::space_info* si;
+
+      for (int i = MetaspaceShared::first_string;
+               i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+        si = &_header->_space[i];
+        size_t used = si->_used;
+        if (used > 0) {
+          size_t size = used;
+          char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
+                                                 (narrowOop)si->_addr._offset));
+          string_ranges[num_ranges] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+          num_ranges ++;
+        }
+      }
+
+      // Check that ranges are within the java heap
+      if (!G1CollectedHeap::heap()->check_archive_addresses(string_ranges, num_ranges)) {
+        fail_continue("Unable to allocate shared string space: range is not "
+                      "within java heap.");
+        return false;
+      }
+
+      // allocate from java heap
+      if (!G1CollectedHeap::heap()->alloc_archive_regions(string_ranges, num_ranges)) {
+        fail_continue("Unable to allocate shared string space: range is "
+                      "already in use.");
+        return false;
+      }
+
+      // Map the string data. No need to call MemTracker::record_virtual_memory_type()
+      // for mapped string regions as they are part of the reserved java heap, which
+      // is already recorded.
+      for (int i = 0; i < num_ranges; i++) {
+        si = &_header->_space[MetaspaceShared::first_string + i];
+        char* addr = (char*)string_ranges[i].start();
+        char* base = os::map_memory(_fd, _full_path, si->_file_offset,
+                                    addr, string_ranges[i].byte_size(), si->_read_only,
+                                    si->_allow_exec);
+        if (base == NULL || base != addr) {
+          fail_continue("Unable to map shared string space at required address.");
+          return false;
+        }
+      }
+      return true; // the shared string data is mapped successfuly
+    } else {
+      //  narrow oop encoding differ, the shared string data are not used
+      if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) {
+        tty->print_cr("Shared string data from the CDS archive is being ignored. "
+                     "The current CompressedOops encoding differs from that archived "
+                     "due to heap size change. The archive was dumped using max heap "
+                     "size %dM.", max_heap_size() >> 20);
+      }
+    }
+  } else {
+    if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) {
+      tty->print_cr("Shared string data from the CDS archive is being ignored. UseG1GC, "
+                    "UseCompressedOops and UseCompressedClassPointers are required.");
+    }
+  }
+
+  // if we get here, the shared string data is not mapped
+  assert(string_ranges == NULL && num_ranges == 0, "sanity");
+  StringTable::ignore_shared_strings(true);
+#endif
+  return true;
+}
+
+bool FileMapInfo::verify_string_regions() {
+  for (int i = MetaspaceShared::first_string;
+           i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+    if (!verify_region_checksum(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void FileMapInfo::fixup_string_regions() {
+  if (string_ranges != NULL) {
+    G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_ranges);
+  }
+}
+
 bool FileMapInfo::verify_region_checksum(int i) {
   if (!VerifySharedSpaces) {
     return true;
   }
-  const char* buf = _header->_space[i]._base;
+
+  const char* buf;
   size_t sz = _header->_space[i]._used;
+
+  if (sz == 0) {
+    return true; // no data
+  }
+  if (MetaspaceShared::is_string_region(i) && StringTable::shared_string_ignored()) {
+    return true; // shared string data are not mapped
+  }
+  buf = _header->region_addr(i);
   int crc = ClassLoader::crc32(0, buf, (jint)sz);
   if (crc != _header->_space[i]._crc) {
     fail_continue("Checksum verification failed.");
     return false;
   }

@@ -600,18 +752,41 @@
 }
 
 // Unmap a memory region in the address space.
 
 void FileMapInfo::unmap_region(int i) {
+  assert(!MetaspaceShared::is_string_region(i), "sanity");
   struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
   size_t used = si->_used;
   size_t size = align_size_up(used, os::vm_allocation_granularity());
-  if (!os::unmap_memory(si->_base, size)) {
+  char* addr;
+
+  if (used == 0) {
+    return;
+  }
+
+  addr = _header->region_addr(i);
+  if (!os::unmap_memory(addr, size)) {
     fail_stop("Unable to unmap shared space.");
   }
 }
 
+void FileMapInfo::unmap_string_regions() {
+  for (int i = MetaspaceShared::first_string;
+           i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+    struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+    size_t used = si->_used;
+    if (used > 0) {
+      size_t size = align_size_up(used, os::vm_allocation_granularity());
+      char* addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
+                                             (narrowOop)si->_addr._offset));
+      if (!os::unmap_memory(addr, size)) {
+        fail_stop("Unable to unmap shared space.");
+      }
+    }
+  }
+}
 
 void FileMapInfo::assert_mark(bool check) {
   if (!check) {
     fail_stop("Mark mismatch while restoring from shared file.");
   }

@@ -656,10 +831,19 @@
   SharedMiscDataSize =  _header->_space[2]._capacity;
   SharedMiscCodeSize =  _header->_space[3]._capacity;
   return true;
 }
 
+char* FileMapInfo::FileMapHeader::region_addr(int idx) {
+  if (MetaspaceShared::is_string_region(idx)) {
+    return (char*)((void*)oopDesc::decode_heap_oop_not_null(
+              (narrowOop)_space[idx]._addr._offset));
+  } else {
+    return _space[idx]._addr._base;
+  }
+}
+
 int FileMapInfo::FileMapHeader::compute_crc() {
   char* header = data();
   // start computing from the field after _crc
   char* buf = (char*)&_crc + sizeof(int);
   size_t sz = data_size() - (buf - header);

@@ -727,12 +911,16 @@
 // p, The given pointer
 // Return:
 // True if the p is within the mapped shared space, otherwise, false.
 bool FileMapInfo::is_in_shared_space(const void* p) {
   for (int i = 0; i < MetaspaceShared::n_regions; i++) {
-    if (p >= _header->_space[i]._base &&
-        p < _header->_space[i]._base + _header->_space[i]._used) {
+    char *base;
+    if (MetaspaceShared::is_string_region(i) && _header->_space[i]._used == 0) {
+      continue;
+    }
+    base = _header->region_addr(i);
+    if (p >= base && p < base + _header->_space[i]._used) {
       return true;
     }
   }
 
   return false;

@@ -740,26 +928,29 @@
 
 void FileMapInfo::print_shared_spaces() {
   gclog_or_tty->print_cr("Shared Spaces:");
   for (int i = 0; i < MetaspaceShared::n_regions; i++) {
     struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+    char *base = _header->region_addr(i);
     gclog_or_tty->print("  %s " INTPTR_FORMAT "-" INTPTR_FORMAT,
                         shared_region_name[i],
-                        si->_base, si->_base + si->_used);
+                        base, base + si->_used);
   }
 }
 
 // Unmap mapped regions of shared space.
 void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
   FileMapInfo *map_info = FileMapInfo::current_info();
   if (map_info) {
     map_info->fail_continue("%s", msg);
-    for (int i = 0; i < MetaspaceShared::n_regions; i++) {
-      if (map_info->_header->_space[i]._base != NULL) {
+    for (int i = 0; i < MetaspaceShared::num_non_strings; i++) {
+      char *addr = map_info->_header->region_addr(i);
+      if (addr != NULL && !MetaspaceShared::is_string_region(i)) {
         map_info->unmap_region(i);
-        map_info->_header->_space[i]._base = NULL;
+        map_info->_header->_space[i]._addr._base = NULL;
       }
     }
+    map_info->unmap_string_regions();
   } else if (DumpSharedSpaces) {
     fail_stop("%s", msg);
   }
 }
< prev index next >