< 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 >