8208658: Make CDS archived heap regions usable even if compressed oop encoding has changed
Summary: Relocate and patch archive regions if necessary
Reviewed-by: jiangli, tschatzl
--- a/src/hotspot/share/classfile/compactHashtable.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -27,6 +27,7 @@
#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logMessage.hpp"
+#include "memory/heapShared.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "oops/compressedOops.inline.hpp"
@@ -280,8 +281,9 @@
public:
CompactHashtable_OopIterator(OopClosure *cl) : _closure(cl) {}
inline void do_value(address base_address, u4 offset) const {
- narrowOop o = (narrowOop)offset;
- _closure->do_oop(&o);
+ narrowOop v = (narrowOop)offset;
+ oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
+ _closure->do_oop(&obj);
}
};
--- a/src/hotspot/share/classfile/compactHashtable.inline.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/compactHashtable.inline.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -28,7 +28,8 @@
#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/allocation.inline.hpp"
-#include "oops/compressedOops.inline.hpp"
+#include "memory/filemap.hpp"
+#include "memory/heapShared.inline.hpp"
#include "oops/oop.hpp"
template <class T, class N>
@@ -46,8 +47,8 @@
template <class T, class N>
inline oop CompactHashtable<T, N>::decode_entry(CompactHashtable<oop, char>* const t,
u4 offset, const char* name, int len) {
- narrowOop obj = (narrowOop)offset;
- oop string = CompressedOops::decode(obj);
+ narrowOop v = (narrowOop)offset;
+ oop string = HeapShared::decode_with_archived_oop_encoding_mode(v);
if (java_lang_String::equals(string, (jchar*)name, len)) {
return string;
}
--- a/src/hotspot/share/classfile/javaClasses.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/classfile/javaClasses.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -1213,7 +1213,7 @@
bool java_lang_Class::restore_archived_mirror(Klass *k,
Handle class_loader, Handle module,
Handle protection_domain, TRAPS) {
- oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw());
+ oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
if (m == NULL) {
return false;
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -59,8 +59,8 @@
public:
StringDedupSharedClosure(StringDedupStat* stat) : _stat(stat) {}
- virtual void do_oop(oop* p) { ShouldNotReachHere(); }
- virtual void do_oop(narrowOop* p) {
+ virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+ virtual void do_oop(oop* p) {
oop java_string = RawAccess<>::oop_load(p);
StringDedupTable::deduplicate(java_string, _stat);
}
--- a/src/hotspot/share/include/cds.h Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/include/cds.h Tue Aug 14 09:59:37 2018 -0700
@@ -35,7 +35,7 @@
#define NUM_CDS_REGIONS 9
#define CDS_ARCHIVE_MAGIC 0xf00baba2
-#define CURRENT_CDS_ARCHIVE_VERSION 4
+#define CURRENT_CDS_ARCHIVE_VERSION 5
#define INVALID_CDS_ARCHIVE_VERSION -1
struct CDSFileMapRegion {
@@ -49,6 +49,8 @@
size_t _used; // for setting space top on read
int _read_only; // read only space?
int _allow_exec; // executable code in space?
+ void* _oopmap; // bitmap for relocating embedded oops
+ size_t _oopmap_size_in_bits;
};
struct CDSFileMapHeaderBase {
--- a/src/hotspot/share/memory/filemap.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/filemap.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -35,12 +35,15 @@
#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"
@@ -51,6 +54,7 @@
#include "utilities/defaultStream.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/heapRegion.hpp"
#endif
# include <sys/stat.h>
@@ -188,6 +192,9 @@
_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()) {
+ _heap_reserved = Universe::heap()->reserved_region();
+ }
// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@@ -653,13 +660,14 @@
// "_" represented unused spaced in the heap region.
//
//
-// |ah0 | ah1 | ah2| ...... | ahn |
+// |ah0 | ah1 | ah2| ...... | ahn|
// |XXXXXX|__ |XXXXX|XXXX|XXXXXXXX|XXXX|
// |<-r0->| |<- r1 ----------------->|
// ^^^
// |
// +-- gap
size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+ GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
int first_region_id, int max_num_regions) {
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
@@ -684,6 +692,10 @@
log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
i, p2i(start), p2i(start + size), size);
write_region(i, start, size, false, false);
+ if (size > 0) {
+ space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
+ space_at(i)->_oopmap_size_in_bits = oopmaps->at(arr_idx)._oopmap_size_in_bits;
+ }
}
return total_size;
}
@@ -762,7 +774,7 @@
if (!open_for_read()) {
return false;
}
- char *addr = _header->region_addr(idx);
+ char *addr = region_addr(idx);
char *base = os::remap_memory(_fd, _full_path, si->_file_offset,
addr, size, false /* !read_only */,
si->_allow_exec);
@@ -781,7 +793,7 @@
// Map the whole region at once, assumed to be allocated contiguously.
ReservedSpace FileMapInfo::reserve_shared_memory() {
- char* requested_addr = _header->region_addr(0);
+ char* requested_addr = region_addr(0);
size_t size = FileMapInfo::core_spaces_size();
// Reserve the space first, then map otherwise map will go right over some
@@ -808,7 +820,7 @@
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);
+ char *requested_addr = region_addr(i);
// If a tool agent is in use (debugging enabled), we must map the address space RW
if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) {
@@ -838,19 +850,57 @@
return base;
}
+address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
+ if (with_current_oop_encoding_mode) {
+ return (address)CompressedOops::decode_not_null(offset_of_space(spc));
+ } else {
+ return (address)HeapShared::decode_with_archived_oop_encoding_mode(offset_of_space(spc));
+ }
+}
+
static MemRegion *string_ranges = NULL;
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);
+}
+
+// Returns the address range of the archived heap regions computed using the
+// current oop encoding mode. This range may be different than the one seen at
+// dump time due to encoding mode differences. The result is used in determining
+// if/how these regions should be relocated at run time.
+MemRegion FileMapInfo::get_heap_regions_range_with_current_oop_encoding_mode() {
+ address start = (address) max_uintx;
+ address end = NULL;
+
+ for (int i = MetaspaceShared::first_string; i <= MetaspaceShared::last_valid_region; i++) {
+ CDSFileMapRegion* si = space_at(i);
+ size_t size = si->_used;
+ if (size > 0) {
+ address s = start_address_with_current_oop_encoding_mode(si);
+ address e = s + size;
+ if (start > s) {
+ start = s;
+ }
+ if (end < e) {
+ end = e;
+ }
+ }
+ }
+ assert(end != NULL, "must have at least one used heap region");
+ return MemRegion((HeapWord*)start, (HeapWord*)end);
+}
+
//
// 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
-// mapped strings contain no out-going references to any other java heap
-// regions. GC does not write into the mapped shared strings.
+// The shared strings are mapped close to the end of the java heap top in
+// closed archive regions. The mapped strings contain no out-going references
+// to any other java heap regions. GC does not write into the mapped shared strings.
//
// The open archive heap objects are mapped below the shared strings in
// the runtime java heap. The mapped open archive heap data only contain
@@ -858,54 +908,108 @@
// 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()) {
- 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());
+void FileMapInfo::map_heap_regions_impl() {
+ if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+ log_info(cds)("CDS heap data is being ignored. UseG1GC, "
+ "UseCompressedOops and UseCompressedClassPointers are required.");
+ return;
+ }
+
+ MemRegion heap_reserved = Universe::heap()->reserved_region();
+
+ log_info(cds)("CDS archive was created with max heap size = " SIZE_FORMAT "M, and the following configuration:",
+ max_heap_size()/M);
+ log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(narrow_klass_base()), narrow_klass_shift());
+ log_info(cds)(" 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)("The current max heap size = " SIZE_FORMAT "M, HeapRegion::GrainBytes = " SIZE_FORMAT,
+ heap_reserved.byte_size()/M, HeapRegion::GrainBytes);
+ log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
+ log_info(cds)(" 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());
+
+ if (narrow_klass_base() != Universe::narrow_klass_base() ||
+ narrow_klass_shift() != Universe::narrow_klass_shift()) {
+ log_info(cds)("CDS heap data cannot be used because the archive was created with an incompatible narrow klass encoding mode.");
+ return;
+ }
+
+ if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
+ narrow_oop_base() != Universe::narrow_oop_base() ||
+ narrow_oop_shift() != Universe::narrow_oop_shift()) {
+ log_info(cds)("CDS heap data need to be relocated because the archive was created with an incompatible oop encoding mode.");
+ _heap_pointers_need_patching = true;
+ } else {
+ MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode();
+ if (!heap_reserved.contains(range)) {
+ log_info(cds)("CDS heap data need to be relocated because");
+ log_info(cds)("the desired range " PTR_FORMAT " - " PTR_FORMAT, p2i(range.start()), p2i(range.end()));
+ log_info(cds)("is outside of the heap " PTR_FORMAT " - " PTR_FORMAT, p2i(heap_reserved.start()), p2i(heap_reserved.end()));
+ _heap_pointers_need_patching = true;
+ }
+ }
- // Check that all the narrow oop and klass encodings match the archive
- 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) && space_at(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);
- 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());
- }
- } else {
- // 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,
- &num_string_ranges)) {
- StringTable::set_shared_string_mapped();
+ ptrdiff_t delta = 0;
+ if (_heap_pointers_need_patching) {
+ // dumptime heap end ------------v
+ // [ |archived heap regions| ] runtime heap end ------v
+ // [ |archived heap regions| ]
+ // |<-----delta-------------------->|
+ //
+ // At dump time, the archived heap regions were near the top of the heap.
+ // At run time, they may not be inside the heap, so we move them so
+ // that they are now near the top of the runtime time. This can be done by
+ // the simple math of adding the delta as shown above.
+ address dumptime_heap_end = (address)_header->_heap_reserved.end();
+ address runtime_heap_end = (address)heap_reserved.end();
+ delta = runtime_heap_end - dumptime_heap_end;
+ }
+
+ log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta);
+ HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+
+ CDSFileMapRegion* si = space_at(MetaspaceShared::first_string);
+ address relocated_strings_bottom = start_address_with_archived_oop_encoding_mode(si);
+ if (!is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes)) {
+ // Align the bottom of the string regions at G1 region boundary. This will avoid
+ // the situation where the highest open region and the lowest string region sharing
+ // the same G1 region. Otherwise we will fail to map the open regions.
+ size_t align = size_t(relocated_strings_bottom) % HeapRegion::GrainBytes;
+ delta -= align;
+ assert(is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes), "must be");
- // Now, map open_archive heap regions, GC can write into the regions.
- if (map_heap_data(&open_archive_heap_ranges,
- MetaspaceShared::first_open_archive_heap_region,
- MetaspaceShared::max_open_archive_heap_region,
- &num_open_archive_heap_ranges,
- true /* open */)) {
- MetaspaceShared::set_open_archive_heap_region_mapped();
- }
- }
+ log_info(cds)("CDS heap data need to be relocated lower by a further " SIZE_FORMAT
+ " bytes to be aligned with HeapRegion::GrainBytes", align);
+
+ HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
+ _heap_pointers_need_patching = true;
+ }
+
+ // 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,
+ &num_string_ranges)) {
+ StringTable::set_shared_string_mapped();
+
+ // Now, map open_archive heap regions, GC can write into the regions.
+ if (map_heap_data(&open_archive_heap_ranges,
+ MetaspaceShared::first_open_archive_heap_region,
+ MetaspaceShared::max_open_archive_heap_region,
+ &num_open_archive_heap_ranges,
+ true /* open */)) {
+ MetaspaceShared::set_open_archive_heap_region_mapped();
}
- } else {
- if (log_is_enabled(Info, cds) && space_at(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()) {
@@ -926,13 +1030,13 @@
for (int i = first;
i < first + max; i++) {
si = space_at(i);
- size_t used = si->_used;
- if (used > 0) {
- size_t size = used;
- char* requested_addr = (char*)((void*)CompressedOops::decode_not_null(
- (narrowOop)si->_addr._offset));
- regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+ size_t size = si->_used;
+ if (size > 0) {
+ HeapWord* start = (HeapWord*)start_address_with_archived_oop_encoding_mode(si);
+ regions[region_num] = MemRegion(start, size / HeapWordSize);
region_num ++;
+ log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes",
+ i, p2i(start), size);
}
}
@@ -942,16 +1046,14 @@
// Check that ranges are within the java heap
if (!G1CollectedHeap::heap()->check_archive_addresses(regions, region_num)) {
- log_info(cds)("UseSharedSpaces: Unable to allocate region, "
- "range is not within java heap.");
+ log_info(cds)("UseSharedSpaces: Unable to allocate region, range is not within java heap.");
return false;
}
// allocate from java heap
if (!G1CollectedHeap::heap()->alloc_archive_regions(
regions, region_num, is_open_archive)) {
- log_info(cds)("UseSharedSpaces: Unable to allocate region, "
- "java heap range is already in use.");
+ log_info(cds)("UseSharedSpaces: Unable to allocate region, java heap range is already in use.");
return false;
}
@@ -967,7 +1069,9 @@
if (base == NULL || base != addr) {
// dealloc the regions from java heap
dealloc_archive_heap_regions(regions, region_num);
- log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap.");
+ log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
+ INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes",
+ p2i(addr), regions[i].byte_size());
return false;
}
}
@@ -995,6 +1099,31 @@
return true;
}
+void FileMapInfo::patch_archived_heap_embedded_pointers() {
+ if (!_heap_pointers_need_patching) {
+ return;
+ }
+
+ patch_archived_heap_embedded_pointers(string_ranges,
+ num_string_ranges,
+ MetaspaceShared::first_string);
+
+ patch_archived_heap_embedded_pointers(open_archive_heap_ranges,
+ num_open_archive_heap_ranges,
+ MetaspaceShared::first_open_archive_heap_region);
+}
+
+void FileMapInfo::patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
+ int first_region_idx) {
+ for (int i=0; i<num_ranges; i++) {
+ CDSFileMapRegion* si = space_at(i + first_region_idx);
+ HeapShared::patch_archived_heap_embedded_pointers(ranges[i], (address)si->_oopmap,
+ si->_oopmap_size_in_bits);
+ }
+}
+
+// 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.
@@ -1036,7 +1165,7 @@
!MetaspaceShared::open_archive_heap_region_mapped())) {
return true; // archived heap data is not mapped
}
- const char* buf = _header->region_addr(i);
+ const char* buf = region_addr(i);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
if (crc != space_at(i)->_crc) {
fail_continue("Checksum verification failed.");
@@ -1057,7 +1186,7 @@
return;
}
- char* addr = _header->region_addr(i);
+ char* addr = region_addr(i);
if (!os::unmap_memory(addr, size)) {
fail_stop("Unable to unmap shared space.");
}
@@ -1078,6 +1207,7 @@
FileMapInfo* FileMapInfo::_current_info = NULL;
+bool FileMapInfo::_heap_pointers_need_patching = false;
Array<u8>* FileMapInfo::_shared_path_table = NULL;
int FileMapInfo::_shared_path_table_size = 0;
size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
@@ -1107,12 +1237,14 @@
return true;
}
-char* FileMapHeader::region_addr(int idx) {
+char* FileMapInfo::region_addr(int idx) {
+ CDSFileMapRegion* si = space_at(idx);
if (MetaspaceShared::is_heap_region(idx)) {
- return _space[idx]._used > 0 ?
- (char*)((void*)CompressedOops::decode_not_null((narrowOop)_space[idx]._addr._offset)) : NULL;
+ assert(DumpSharedSpaces, "The following doesn't work at runtime");
+ return si->_used > 0 ?
+ (char*)start_address_with_current_oop_encoding_mode(si) : NULL;
} else {
- return _space[idx]._addr._base;
+ return si->_addr._base;
}
}
@@ -1216,34 +1348,25 @@
idx == MetaspaceShared::rw ||
idx == MetaspaceShared::mc ||
idx == MetaspaceShared::md, "invalid region index");
- char* base = _header->region_addr(idx);
+ char* base = region_addr(idx);
if (p >= base && p < base + space_at(idx)->_used) {
return true;
}
return false;
}
-void FileMapInfo::print_shared_spaces() {
- tty->print_cr("Shared Spaces:");
- for (int i = 0; i < MetaspaceShared::n_regions; i++) {
- CDSFileMapRegion* si = space_at(i);
- char *base = _header->region_addr(i);
- tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT,
- shared_region_name[i],
- p2i(base), p2i(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::num_non_heap_spaces; i++) {
- char *addr = map_info->_header->region_addr(i);
- if (addr != NULL && !MetaspaceShared::is_heap_region(i)) {
- map_info->unmap_region(i);
- map_info->space_at(i)->_addr._base = NULL;
+ if (!MetaspaceShared::is_heap_region(i)) {
+ char *addr = map_info->region_addr(i);
+ if (addr != NULL) {
+ map_info->unmap_region(i);
+ map_info->space_at(i)->_addr._base = NULL;
+ }
}
}
// Dealloc the archive heap regions only without unmapping. The regions are part
--- a/src/hotspot/share/memory/filemap.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/filemap.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -88,6 +88,11 @@
}
};
+struct ArchiveHeapOopmapInfo {
+ address _oopmap; // bitmap for relocating embedded oops
+ size_t _oopmap_size_in_bits;
+};
+
struct FileMapHeader : public CDSFileMapHeaderBase {
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
@@ -104,6 +109,7 @@
size_t _cds_i2i_entry_code_buffers_size;
size_t _core_spaces_size; // number of bytes allocated by the core spaces
// (mc, md, ro, rw and od).
+ MemRegion _heap_reserved; // reserved region for the entire heap at dump time.
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@@ -152,14 +158,16 @@
jshort max_used_path_index() { return _max_used_path_index; }
jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
- char* region_addr(int idx);
-
bool validate();
void populate(FileMapInfo* info, size_t alignment);
int compute_crc();
+
+ CDSFileMapRegion* space_at(int i) {
+ assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
+ return &_space[i];
+ }
};
-
class FileMapInfo : public CHeapObj<mtInternal> {
private:
friend class ManifestStream;
@@ -194,6 +202,7 @@
char* _paths_misc_info;
static FileMapInfo* _current_info;
+ static bool _heap_pointers_need_patching;
bool init_from_file(int fd);
void align_file_position();
@@ -253,12 +262,19 @@
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
+ GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
int first_region_id, int max_num_regions);
void write_bytes(const void* buffer, size_t count);
void write_bytes_aligned(const void* buffer, size_t count);
char* map_region(int i, char** top_ret);
+ void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
void map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
+ void patch_archived_heap_embedded_pointers() NOT_CDS_JAVA_HEAP_RETURN;
+ void patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
+ int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN;
+ bool has_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false);
+ MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
void unmap_region(int i);
bool verify_region_checksum(int i);
void close();
@@ -274,7 +290,6 @@
static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
- void print_shared_spaces() NOT_CDS_RETURN;
// Stop CDS sharing and unmap CDS regions.
static void stop_sharing_and_unmap(const char* msg);
@@ -303,6 +318,8 @@
return _shared_path_table_size;
}
+ char* region_addr(int idx);
+
private:
bool map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
@@ -310,9 +327,24 @@
void dealloc_archive_heap_regions(MemRegion* regions, int num) NOT_CDS_JAVA_HEAP_RETURN;
CDSFileMapRegion* space_at(int i) {
- assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
- return &_header->_space[i];
+ return _header->space_at(i);
+ }
+
+ narrowOop offset_of_space(CDSFileMapRegion* spc) {
+ return (narrowOop)(spc->_addr._offset);
}
+
+ // The starting address of spc, as calculated with CompressedOop::decode_non_null()
+ address start_address_with_current_oop_encoding_mode(CDSFileMapRegion* spc) {
+ return decode_start_address(spc, true);
+ }
+
+ // The starting address of spc, as calculated with HeapShared::decode_with_archived_oop_encoding_mode()
+ address start_address_with_archived_oop_encoding_mode(CDSFileMapRegion* spc) {
+ return decode_start_address(spc, false);
+ }
+
+ address decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode);
};
#endif // SHARE_VM_MEMORY_FILEMAP_HPP
--- a/src/hotspot/share/memory/heapShared.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/heapShared.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -29,7 +29,7 @@
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
-#include "memory/heapShared.hpp"
+#include "memory/heapShared.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
@@ -38,6 +38,7 @@
#include "oops/compressedOops.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
+#include "utilities/bitMap.inline.hpp"
#if INCLUDE_CDS_JAVA_HEAP
KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL;
@@ -72,6 +73,9 @@
return info;
}
+address HeapShared::_narrow_oop_base;
+int HeapShared::_narrow_oop_shift;
+
int HeapShared::num_of_subgraph_infos() {
int num = 0;
KlassSubGraphInfo* info = _subgraph_info_list;
@@ -320,7 +324,7 @@
// point. All objects in the subgraph reachable from the object are
// also 'known' by GC.
oop v = MetaspaceShared::materialize_archived_object(
- CompressedOops::decode(entry_field_records->at(i+1)));
+ entry_field_records->at(i+1));
m->obj_field_put(field_offset, v);
i += 2;
}
@@ -601,4 +605,96 @@
archive_reachable_objects_from_static_field(info->klass, info->offset, info->type, CHECK);
}
}
+
+// At dump-time, find the location of all the non-null oop pointers in an archived heap
+// region. This way we can quickly relocate all the pointers without using
+// BasicOopIterateClosure at runtime.
+class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
+ narrowOop* _start;
+ BitMap *_oopmap;
+ int _num_total_oops;
+ int _num_null_oops;
+ public:
+ FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap)
+ : _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {}
+
+ virtual bool should_verify_oops(void) {
+ return false;
+ }
+ virtual void do_oop(narrowOop* p) {
+ _num_total_oops ++;
+ narrowOop v = *p;
+ if (!CompressedOops::is_null(v)) {
+ size_t idx = p - _start;
+ _oopmap->set_bit(idx);
+ } else {
+ _num_null_oops ++;
+ }
+ }
+ virtual void do_oop(oop *p) {
+ ShouldNotReachHere();
+ }
+ int num_total_oops() const { return _num_total_oops; }
+ int num_null_oops() const { return _num_null_oops; }
+};
+
+ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
+ assert(UseCompressedOops, "must be");
+ size_t num_bits = region.byte_size() / sizeof(narrowOop);
+ ResourceBitMap oopmap(num_bits);
+
+ HeapWord* p = region.start();
+ HeapWord* end = region.end();
+ FindEmbeddedNonNullPointers finder((narrowOop*)p, &oopmap);
+
+ int num_objs = 0;
+ while (p < end) {
+ oop o = (oop)p;
+ o->oop_iterate(&finder);
+ p += o->size();
+ ++ num_objs;
+ }
+
+ log_info(cds, heap)("calculate_oopmap: objects = %6d, embedded oops = %7d, nulls = %7d",
+ num_objs, finder.num_total_oops(), finder.num_null_oops());
+ return oopmap;
+}
+
+void HeapShared::init_narrow_oop_decoding(address base, int shift) {
+ _narrow_oop_base = base;
+ _narrow_oop_shift = shift;
+}
+
+// Patch all the embedded oop pointers inside an archived heap region,
+// to be consistent with the runtime oop encoding.
+class PatchEmbeddedPointers: public BitMapClosure {
+ narrowOop* _start;
+
+ public:
+ PatchEmbeddedPointers(narrowOop* start) : _start(start) {}
+
+ bool do_bit(size_t offset) {
+ narrowOop* p = _start + offset;
+ narrowOop v = *p;
+ assert(!CompressedOops::is_null(v), "null oops should have been filtered out at dump time");
+ oop o = HeapShared::decode_with_archived_oop_encoding_mode(v);
+ RawAccess<IS_NOT_NULL>::oop_store(p, o);
+ return true;
+ }
+};
+
+void HeapShared::patch_archived_heap_embedded_pointers(MemRegion region, address oopmap,
+ size_t oopmap_size_in_bits) {
+ BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
+
+#ifndef PRODUCT
+ ResourceMark rm;
+ ResourceBitMap checkBm = calculate_oopmap(region);
+ assert(bm.is_same(checkBm), "sanity");
+#endif
+
+ PatchEmbeddedPointers patcher((narrowOop*)region.start());
+ bm.iterate(&patcher);
+}
+
#endif // INCLUDE_CDS_JAVA_HEAP
--- a/src/hotspot/share/memory/heapShared.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/heapShared.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -30,6 +30,7 @@
#include "oops/objArrayKlass.hpp"
#include "oops/oop.hpp"
#include "oops/typeArrayKlass.hpp"
+#include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp"
#if INCLUDE_CDS_JAVA_HEAP
@@ -123,13 +124,33 @@
static int num_of_subgraph_infos();
static size_t build_archived_subgraph_info_records(int num_records);
+
+ // Used by decode_with_archived_oop_encoding_mode
+ static address _narrow_oop_base;
+ static int _narrow_oop_shift;
+
#endif // INCLUDE_CDS_JAVA_HEAP
public:
static char* read_archived_subgraph_infos(char* buffer) NOT_CDS_JAVA_HEAP_RETURN_(buffer);
static void write_archived_subgraph_infos() NOT_CDS_JAVA_HEAP_RETURN;
static void initialize_from_archived_subgraph(Klass* k) NOT_CDS_JAVA_HEAP_RETURN;
+ // NarrowOops stored in the CDS archive may use a different encoding scheme
+ // than Universe::narrow_oop_{base,shift} -- see FileMapInfo::map_heap_regions_impl.
+ // To decode them, do not use CompressedOops::decode_not_null. Use this
+ // function instead.
+ inline static oop decode_with_archived_oop_encoding_mode(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+
+ static void init_narrow_oop_decoding(address base, int shift) NOT_CDS_JAVA_HEAP_RETURN;
+
+ static void patch_archived_heap_embedded_pointers(MemRegion mem, address oopmap,
+ size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
+
static void init_archivable_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
static void archive_module_graph_objects(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
+
+#if INCLUDE_CDS_JAVA_HEAP
+ static ResourceBitMap calculate_oopmap(MemRegion region);
+#endif
};
#endif // SHARE_VM_MEMORY_HEAPSHARED_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/heapShared.inline.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
+#define SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
+
+#include "oops/compressedOops.inline.hpp"
+#include "memory/heapShared.hpp"
+
+#if INCLUDE_CDS_JAVA_HEAP
+
+inline oop HeapShared::decode_with_archived_oop_encoding_mode(narrowOop v) {
+ assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
+ oop result = (oop)(void*)((uintptr_t)_narrow_oop_base + ((uintptr_t)v << _narrow_oop_shift));
+ assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
+ return result;
+}
+
+#endif
+
+#endif // SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
--- a/src/hotspot/share/memory/metaspaceShared.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -39,7 +39,7 @@
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "memory/filemap.hpp"
-#include "memory/heapShared.hpp"
+#include "memory/heapShared.inline.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
@@ -61,6 +61,7 @@
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "utilities/align.hpp"
+#include "utilities/bitMap.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/hashtable.inline.hpp"
#if INCLUDE_G1GC
@@ -227,7 +228,7 @@
// Map in spaces now also
if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
size_t cds_total = core_spaces_size();
- cds_address = (address)mapinfo->header()->region_addr(0);
+ cds_address = (address)mapinfo->region_addr(0);
#ifdef _LP64
if (Metaspace::using_class_space()) {
char* cds_end = (char*)(cds_address + cds_total);
@@ -309,10 +310,10 @@
Universe::set_narrow_klass_range(cds_total);
Metaspace::initialize_class_space(tmp_class_space);
- tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ log_info(cds)("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
- tty->print_cr("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
+ log_info(cds)("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
CompressedClassSpaceSize, p2i(tmp_class_space.base()));
#endif
@@ -424,6 +425,7 @@
soc->do_tag(--tag);
JavaClasses::serialize_offsets(soc);
+ InstanceMirrorKlass::serialize_offsets(soc);
soc->do_tag(--tag);
soc->do_tag(666);
@@ -1017,7 +1019,13 @@
GrowableArray<MemRegion> *_closed_archive_heap_regions;
GrowableArray<MemRegion> *_open_archive_heap_regions;
+ GrowableArray<ArchiveHeapOopmapInfo> *_closed_archive_heap_oopmaps;
+ GrowableArray<ArchiveHeapOopmapInfo> *_open_archive_heap_oopmaps;
+
void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
+ void dump_archive_heap_oopmaps() NOT_CDS_JAVA_HEAP_RETURN;
+ void dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
+ GrowableArray<ArchiveHeapOopmapInfo>* oopmaps);
void dump_symbols();
char* dump_read_only_tables();
void print_region_stats();
@@ -1329,6 +1337,9 @@
WriteClosure wc(&_ro_region);
MetaspaceShared::serialize(&wc);
+ // Write the bitmaps for patching the archive heap regions
+ dump_archive_heap_oopmaps();
+
char* newtop = _ro_region.top();
ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - oldtop), true);
return buckets_top;
@@ -1471,10 +1482,12 @@
_total_string_region_size = mapinfo->write_archive_heap_regions(
_closed_archive_heap_regions,
+ _closed_archive_heap_oopmaps,
MetaspaceShared::first_string,
MetaspaceShared::max_strings);
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
_open_archive_heap_regions,
+ _open_archive_heap_oopmaps,
MetaspaceShared::first_open_archive_heap_region,
MetaspaceShared::max_open_archive_heap_region);
}
@@ -1810,6 +1823,36 @@
G1HeapVerifier::verify_archive_regions();
}
+void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() {
+ if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+ _closed_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
+ dump_archive_heap_oopmaps(_closed_archive_heap_regions, _closed_archive_heap_oopmaps);
+
+ _open_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
+ dump_archive_heap_oopmaps(_open_archive_heap_regions, _open_archive_heap_oopmaps);
+ }
+}
+
+void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
+ GrowableArray<ArchiveHeapOopmapInfo>* oopmaps) {
+ for (int i=0; i<regions->length(); i++) {
+ ResourceBitMap oopmap = HeapShared::calculate_oopmap(regions->at(i));
+ size_t size_in_bits = oopmap.size();
+ size_t size_in_bytes = oopmap.size_in_bytes();
+ uintptr_t* buffer = (uintptr_t*)_ro_region.allocate(size_in_bytes, sizeof(intptr_t));
+ oopmap.write_to(buffer, size_in_bytes);
+ log_info(cds)("Oopmap = " INTPTR_FORMAT " (" SIZE_FORMAT_W(6) " bytes) for heap region "
+ INTPTR_FORMAT " (" SIZE_FORMAT_W(8) " bytes)",
+ p2i(buffer), size_in_bytes,
+ p2i(regions->at(i).start()), regions->at(i).byte_size());
+
+ ArchiveHeapOopmapInfo info;
+ info._oopmap = (address)buffer;
+ info._oopmap_size_in_bits = size_in_bits;
+ oopmaps->append(info);
+ }
+}
+
void MetaspaceShared::dump_closed_archive_heap_objects(
GrowableArray<MemRegion> * closed_archive) {
assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects");
@@ -1896,8 +1939,9 @@
return archived_oop;
}
-oop MetaspaceShared::materialize_archived_object(oop obj) {
- if (obj != NULL) {
+oop MetaspaceShared::materialize_archived_object(narrowOop v) {
+ if (!CompressedOops::is_null(v)) {
+ oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
return G1CollectedHeap::heap()->materialize_archived_object(obj);
}
return NULL;
@@ -1973,7 +2017,7 @@
"Archived heap object is not allowed");
assert(MetaspaceShared::open_archive_heap_region_mapped(),
"Open archive heap region is not mapped");
- *p = CompressedOops::decode_not_null(o);
+ *p = HeapShared::decode_with_archived_oop_encoding_mode(o);
}
}
@@ -2003,13 +2047,6 @@
return false;
}
-void MetaspaceShared::print_shared_spaces() {
- if (UseSharedSpaces) {
- FileMapInfo::current_info()->print_shared_spaces();
- }
-}
-
-
// Map shared spaces at requested addresses and return if succeeded.
bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
size_t image_alignment = mapinfo->alignment();
@@ -2120,6 +2157,8 @@
// Initialize the run-time symbol table.
SymbolTable::create_table();
+ mapinfo->patch_archived_heap_embedded_pointers();
+
// Close the mapinfo file
mapinfo->close();
--- a/src/hotspot/share/memory/metaspaceShared.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -79,6 +79,7 @@
// mapped java heap regions
first_string = od + 1, // index of first string region
max_strings = 2, // max number of string regions in string space
+ last_string = first_string + max_strings - 1,
first_open_archive_heap_region = first_string + max_strings,
max_open_archive_heap_region = 2,
@@ -111,7 +112,7 @@
}
static oop find_archived_heap_object(oop obj);
static oop archive_heap_object(oop obj, Thread* THREAD);
- static oop materialize_archived_object(oop obj);
+ static oop materialize_archived_object(narrowOop v);
static void archive_klass_objects(Thread* THREAD);
#endif
@@ -221,8 +222,6 @@
NOT_CDS(return false);
}
- static void print_shared_spaces();
-
static bool try_link_class(InstanceKlass* ik, TRAPS);
static void link_and_cleanup_shared_classes(TRAPS);
static void check_shared_class_loader_type(InstanceKlass* ik);
--- a/src/hotspot/share/memory/universe.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/memory/universe.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -517,8 +517,11 @@
// that the number of objects allocated at this point is very small.
assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded");
HandleMark hm(THREAD);
- // Cache the start of the static fields
- InstanceMirrorKlass::init_offset_of_static_fields();
+
+ if (!UseSharedSpaces) {
+ // Cache the start of the static fields
+ InstanceMirrorKlass::init_offset_of_static_fields();
+ }
GrowableArray <Klass*>* list = java_lang_Class::fixup_mirror_list();
int list_length = list->length();
--- a/src/hotspot/share/oops/cpCache.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/cpCache.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -777,7 +777,7 @@
if (CompressedOops::is_null(_archived_references)) {
return NULL;
}
- return MetaspaceShared::materialize_archived_object(CompressedOops::decode_not_null(_archived_references));
+ return MetaspaceShared::materialize_archived_object(_archived_references);
}
void ConstantPoolCache::set_archived_references(oop o) {
--- a/src/hotspot/share/oops/instanceMirrorKlass.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/instanceMirrorKlass.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -66,3 +66,9 @@
}
return 0;
}
+
+#if INCLUDE_CDS
+void InstanceMirrorKlass::serialize_offsets(SerializeClosure* f) {
+ f->do_u4((u4*)&_offset_of_static_fields);
+}
+#endif
--- a/src/hotspot/share/oops/instanceMirrorKlass.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -99,6 +99,8 @@
void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
+ static void serialize_offsets(class SerializeClosure* f) NOT_CDS_RETURN;
+
// Oop fields (and metadata) iterators
//
// The InstanceMirrorKlass iterators also visit the hidden Klass pointer.
--- a/src/hotspot/share/oops/klass.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/klass.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -571,6 +571,11 @@
return CompressedOops::decode(_archived_mirror);
}
+narrowOop Klass::archived_java_mirror_raw_narrow() {
+ assert(has_raw_archived_mirror(), "must have raw archived mirror");
+ return _archived_mirror;
+}
+
// No GC barrier
void Klass::set_archived_java_mirror_raw(oop m) {
assert(DumpSharedSpaces, "called only during runtime");
--- a/src/hotspot/share/oops/klass.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/oops/klass.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -261,6 +261,7 @@
void set_java_mirror(Handle m);
oop archived_java_mirror_raw() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // no GC barrier
+ narrowOop archived_java_mirror_raw_narrow() NOT_CDS_JAVA_HEAP_RETURN_(0); // no GC barrier
void set_archived_java_mirror_raw(oop m) NOT_CDS_JAVA_HEAP_RETURN; // no GC barrier
// Temporary mirror switch used by RedefineClasses
--- a/src/hotspot/share/runtime/arguments.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/runtime/arguments.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -1585,7 +1585,7 @@
if (RequireSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
"Class data sharing is inconsistent with other specified options.\n");
- vm_exit_during_initialization("Unable to use shared archive.", message);
+ vm_exit_during_initialization("Unable to use shared archive", message);
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}
--- a/src/hotspot/share/utilities/bitMap.cpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/utilities/bitMap.cpp Tue Aug 14 09:59:37 2018 -0700
@@ -672,6 +672,11 @@
prefix, p2i(map()), p2i((char*)map() + (size() >> LogBitsPerByte)));
}
+void BitMap::write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const {
+ assert(buffer_size_in_bytes == size_in_bytes(), "must be");
+ memcpy(buffer, _map, size_in_bytes());
+}
+
#ifndef PRODUCT
void BitMap::print_on(outputStream* st) const {
--- a/src/hotspot/share/utilities/bitMap.hpp Wed Aug 22 16:06:51 2018 +0100
+++ b/src/hotspot/share/utilities/bitMap.hpp Tue Aug 14 09:59:37 2018 -0700
@@ -288,6 +288,7 @@
bool is_full() const;
bool is_empty() const;
+ void write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const;
void print_on_error(outputStream* st, const char* prefix) const;
#ifndef PRODUCT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/DifferentHeapSizes.java Tue Aug 14 09:59:37 2018 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test automatic relocation of archive heap regions dur to heap size changes.
+ * @requires vm.cds.archived.java.heap
+ * @requires (vm.gc=="null")
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DifferentHeapSizes
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+import jdk.test.lib.cds.CDSTestUtils;
+
+public class DifferentHeapSizes {
+ static class Scenario {
+ int dumpSize; // in MB
+ int runSizes[]; // in MB
+ Scenario(int ds, int... rs) {
+ dumpSize = ds;
+ runSizes = rs;
+ }
+ }
+
+ static Scenario[] scenarios = {
+ // dump -Xmx , run -Xmx
+ new Scenario( 32, 32, 64, 512, 2048, 4097, 16374, 31000),
+ new Scenario( 128, 32, 64, 512, 2048, 4097, 16374, 31000, 40000),
+ new Scenario( 2048, 32, 512, 2600, 4097, 8500, 31000, 40000),
+ new Scenario( 17000, 32, 512, 2048, 4097, 8500, 31000, 40000),
+ new Scenario( 31000, 32, 512, 2048, 4097, 8500, 17000, 40000)
+ };
+
+ public static void main(String[] args) throws Exception {
+ String dedup = "-XX:+UseStringDeduplication"; // This increases code coverage.
+ JarBuilder.getOrCreateHelloJar();
+ String appJar = TestCommon.getTestJar("hello.jar");
+ String appClasses[] = TestCommon.list("Hello");
+
+ for (Scenario s : scenarios) {
+ String dumpXmx = "-Xmx" + s.dumpSize + "m";
+ OutputAnalyzer output = TestCommon.dump(appJar, appClasses, dumpXmx);
+
+ for (int runSize : s.runSizes) {
+ String runXmx = "-Xmx" + runSize + "m";
+ CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion",
+ "-Xlog:cds", runXmx, dedup, "Hello");
+ if (runSize < 32768) {
+ result
+ .assertNormalExit("Hello World")
+ .assertNormalExit(out -> {
+ out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
+ out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
+ });
+ } else {
+ result.assertAbnormalExit("Unable to use shared archive: UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.");
+ }
+ }
+ }
+ String flag = "HeapBaseMinAddress";
+ String xxflag = "-XX:" + flag + "=";
+ String mx = "-Xmx128m";
+ long base = WhiteBox.getWhiteBox().getSizeTVMFlag(flag).longValue();
+
+ TestCommon.dump(appJar, appClasses, mx, xxflag + base);
+ TestCommon.run("-cp", appJar, "-showversion", "-Xlog:cds", mx, xxflag + (base + 256 * 1024 * 1024), dedup, "Hello")
+ .assertNormalExit("Hello World")
+ .assertNormalExit(out -> {
+ out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
+ out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
+ });
+ }
+}
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/RangeNotWithinHeap.java Wed Aug 22 16:06:51 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/*
- * @test
- * @summary Shared classes can still be used when archived heap regions cannot be
- * mapped due to out of range, and -Xshare:on should not fail. Test on
- * linux 64-bit only since the HeapBaseMinAddress value is platform specific.
- * The value used in the test may cause different behavior on other platforms.
- * @requires vm.cds.archived.java.heap
- * @requires os.family == "linux"
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @modules java.base/jdk.internal.misc
- * @modules java.management
- * jdk.jartool/sun.tools.jar
- * @compile ../test-classes/Hello.java
- * @run main RangeNotWithinHeap
- */
-
-import jdk.test.lib.process.OutputAnalyzer;
-
-public class RangeNotWithinHeap {
- public static void main(String[] args) throws Exception {
- JarBuilder.getOrCreateHelloJar();
- String appJar = TestCommon.getTestJar("hello.jar");
- String appClasses[] = TestCommon.list("Hello");
-
- OutputAnalyzer output = TestCommon.dump(appJar, appClasses,
- "-XX:HeapBaseMinAddress=0x600000000", "-Xmx6G", "-Xlog:gc+heap=trace");
- TestCommon.checkDump(output, "oa0 space:");
-
- // Force archive region out of runtime java heap
- output = TestCommon.exec(appJar, "Hello");
- TestCommon.checkExec(output, "Hello World");
- output = TestCommon.exec(appJar,
- "-XX:HeapBaseMinAddress=0x600000000", "-Xmx2G", "-Xlog:gc+heap=trace,cds", "Hello");
- TestCommon.checkExec(output, "Hello World");
- try {
- output.shouldContain(
- "UseSharedSpaces: Unable to allocate region, range is not within java heap.");
- } catch (Exception e) {
- // In rare case the heap data is not used.
- if (output.getOutput().contains("Cached heap data from the CDS archive is being ignored")) {
- return;
- }
- // Check for common shared class data mapping failures.
- TestCommon.checkCommonExecExceptions(output, e);
- }
- }
-}
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java Wed Aug 22 16:06:51 2018 +0100
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java Tue Aug 14 09:59:37 2018 -0700
@@ -141,10 +141,10 @@
// main class param, and fails with "Could not find or load main class"
if (!extraOption.isEmpty()) {
output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
- collectorOption, extraOption, "HelloString");
+ collectorOption, "-Xlog:cds", extraOption, "HelloString");
} else {
output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
- collectorOption, "HelloString");
+ collectorOption, "-Xlog:cds", "HelloString");
}
if (expectedWarning != null)
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java Wed Aug 22 16:06:51 2018 +0100
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java Tue Aug 14 09:59:37 2018 -0700
@@ -36,6 +36,11 @@
// This class contains common test utilities for testing CDS
public class CDSTestUtils {
+ public static final String MSG_RANGE_NOT_WITHIN_HEAP =
+ "UseSharedSpaces: Unable to allocate region, range is not within java heap.";
+ public static final String MSG_RANGE_ALREADT_IN_USE =
+ "Unable to allocate region, java heap range is already in use.";
+
public interface Checker {
public void check(OutputAnalyzer output) throws Exception;
}