--- old/src/hotspot/share/classfile/compactHashtable.cpp 2018-08-14 19:22:51.377220639 -0700 +++ new/src/hotspot/share/classfile/compactHashtable.cpp 2018-08-14 19:22:51.049208104 -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); } }; --- old/src/hotspot/share/classfile/compactHashtable.inline.hpp 2018-08-14 19:22:52.341257482 -0700 +++ new/src/hotspot/share/classfile/compactHashtable.inline.hpp 2018-08-14 19:22:52.021245252 -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 @@ -46,8 +47,8 @@ template inline oop CompactHashtable::decode_entry(CompactHashtable* 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; } --- old/src/hotspot/share/classfile/javaClasses.cpp 2018-08-14 19:22:53.309294477 -0700 +++ new/src/hotspot/share/classfile/javaClasses.cpp 2018-08-14 19:22:52.985282094 -0700 @@ -1212,7 +1212,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; --- old/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp 2018-08-14 19:22:54.369334990 -0700 +++ new/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.cpp 2018-08-14 19:22:54.037322301 -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); } --- old/src/hotspot/share/memory/filemap.cpp 2018-08-14 19:22:55.329371680 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2018-08-14 19:22:54.997358992 -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 @@ -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()) { + _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 @@ -525,8 +532,7 @@ } size_t len = lseek(fd, 0, SEEK_END); - struct FileMapInfo::FileMapHeader::space_info* si = - &_header->_space[MetaspaceShared::last_valid_region]; + FileMapHeader::space_info* si = space_at(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."); @@ -607,7 +613,7 @@ 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 = space_at(region); if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); @@ -661,13 +667,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 *heap_mem, + GrowableArray *oopmaps, int first_region_id, int max_num_regions) { assert(max_num_regions <= 2, "Only support maximum 2 memory regions"); @@ -692,6 +699,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; } @@ -760,7 +771,7 @@ // 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 = space_at(idx); if (!si->_read_only) { // the space is already readwrite so we are done return true; @@ -812,7 +823,7 @@ 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 = space_at(i); size_t used = si->_used; size_t alignment = os::vm_allocation_granularity(); size_t size = align_up(used, alignment); @@ -846,12 +857,49 @@ return base; } + +address FileMapInfo::FileMapHeader::space_info::decode_start_address(bool with_current_oop_encoding_mode) { + if (with_current_oop_encoding_mode) { + return (address)CompressedOops::decode_not_null(offset()); + } else { + return (address)HeapShared::decode_with_archived_oop_encoding_mode(offset()); + } +} + 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 where the heap regions would occupy using the +// current oop encoding mode. +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++) { + FileMapHeader::space_info* si = space_at(i); + size_t size = si->_used; + if (size > 0) { + address s = si->start_address_with_current_oop_encoding_mode(); + 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. @@ -866,56 +914,110 @@ // 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()); - - // 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) && _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); - 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(); - - // 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(); - } - } - } +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 g1_reserved = G1CollectedHeap::heap()->g1_reserved(); + + log_info(cds)("CDS archive was created with max heap size = " UINTX_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 = " UINTX_FORMAT "M, HeapRegion::GrainBytes = " UINTX_FORMAT, + g1_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 heap size."); + 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 heap size."); + _heap_pointers_need_patching = true; } 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."); + MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode(); + if (!g1_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(g1_reserved.start()), p2i(g1_reserved.end())); + _heap_pointers_need_patching = true; } } + 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->_g1_reserved.end(); + address runtime_heap_end = (address)g1_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()); + + FileMapHeader::space_info* si = space_at(MetaspaceShared::first_string); + address relocated_strings_bottom = si->start_address_with_archived_oop_encoding_mode(); + 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"); + + log_info(cds)("CDS heap data need to be relocated lower by a further " UINTX_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(); + } + } +} + +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"); } @@ -928,19 +1030,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( - (narrowOop)si->_addr._offset)); - regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize); + si = space_at(i); + size_t size = si->_used; + if (size > 0) { + HeapWord* start = (HeapWord*)si->start_address_with_archived_oop_encoding_mode(); + regions[region_num] = MemRegion(start, size / HeapWordSize); region_num ++; + log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = %8d bytes", + i, p2i(start), int(size)); } } @@ -950,16 +1052,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 +1067,7 @@ // for mapped regions as they are part of the reserved java heap, which is // already recorded. for (int i = 0; i < region_num; i++) { - si = &_header->_space[first + i]; + si = space_at(first + i); char* addr = (char*)regions[i].start(); char* base = os::map_memory(_fd, _full_path, si->_file_offset, addr, regions[i].byte_size(), si->_read_only, @@ -975,7 +1075,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 = " UINTX_FORMAT " bytes", + p2i(addr), regions[i].byte_size()); return false; } } @@ -1003,6 +1105,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_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. @@ -1057,7 +1184,7 @@ 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 = space_at(i); size_t used = si->_used; size_t size = align_up(used, os::vm_allocation_granularity()); @@ -1086,6 +1213,7 @@ FileMapInfo* FileMapInfo::_current_info = NULL; +bool FileMapInfo::_heap_pointers_need_patching = false; Array* FileMapInfo::_shared_path_table = NULL; int FileMapInfo::_shared_path_table_size = 0; size_t FileMapInfo::_shared_path_entry_size = 0x1234baad; @@ -1117,8 +1245,9 @@ char* FileMapInfo::FileMapHeader::region_addr(int idx) { if (MetaspaceShared::is_heap_region(idx)) { + assert(DumpSharedSpaces, "The following doesn't work at runtime"); return _space[idx]._used > 0 ? - (char*)((void*)CompressedOops::decode_not_null((narrowOop)_space[idx]._addr._offset)) : NULL; + (char*)_space[idx].start_address_with_current_oop_encoding_mode() : NULL; } else { return _space[idx]._addr._base; } @@ -1231,27 +1360,18 @@ return false; } -void FileMapInfo::print_shared_spaces() { - 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); - 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->_header->_space[i]._addr._base = NULL; + if (!MetaspaceShared::is_heap_region(i)) { + char *addr = map_info->_header->region_addr(i); + if (addr != NULL) { + map_info->unmap_region(i); + map_info->_header->_space[i]._addr._base = NULL; + } } } // Dealloc the archive heap regions only without unmapping. The regions are part --- old/src/hotspot/share/memory/filemap.hpp 2018-08-14 19:22:56.337410206 -0700 +++ new/src/hotspot/share/memory/filemap.hpp 2018-08-14 19:22:56.009397670 -0700 @@ -87,13 +87,18 @@ } }; +struct ArchiveHeapOopmapInfo { + address _oopmap; // bitmap for relocating embedded oops + size_t _oopmap_size_in_bits; +}; + class FileMapInfo : public CHeapObj { private: friend class ManifestStream; friend class VMStructs; enum { _invalid_version = -1, - _current_version = 3 + _current_version = 4 }; bool _file_open; @@ -116,6 +121,7 @@ // methods, we would get sizeof(FileMapHeaderBase) == 1 with gcc. intx _dummy; }; + struct FileMapHeader : FileMapHeaderBase { // Use data() and data_size() to memcopy to/from the FileMapHeader. We need to // avoid read/writing the C++ vtable pointer. @@ -125,7 +131,9 @@ char* data() { return ((char*)this) + sizeof(FileMapHeaderBase); } - + FileMapHeader() { + memset(data(), 0, data_size()); + } int _magic; // identify file type. int _crc; // header crc checksum. int _version; // (from enum, above.) @@ -144,6 +152,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 _g1_reserved; // reserved region at dump time. struct space_info { int _crc; // crc checksum of the current space size_t _file_offset; // sizeof(this) rounded to vm page size @@ -155,6 +164,23 @@ size_t _used; // for setting space top on read bool _read_only; // read only space? bool _allow_exec; // executable code in space? + address _oopmap; // bitmap for relocating embedded oops + size_t _oopmap_size_in_bits; + narrowOop offset() { + return (narrowOop)_addr._offset; + } + + // The starting address, as calculated with CompressedOop::decode_non_null() + address start_address_with_current_oop_encoding_mode() { + return decode_start_address(true); + } + + // The starting address, as calculated with HeapShared::decode_with_archived_oop_encoding_mode() + address start_address_with_archived_oop_encoding_mode() { + return decode_start_address(false); + } + private: + address decode_start_address(bool with_current_oop_encoding_mode); } _space[MetaspaceShared::n_regions]; // The following fields are all sanity checks for whether this archive @@ -214,6 +240,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(); @@ -274,12 +301,19 @@ void write_region(int region, char* base, size_t size, bool read_only, bool allow_exec); size_t write_archive_heap_regions(GrowableArray *heap_mem, + GrowableArray *oopmaps, int first_region_id, int max_num_regions); void write_bytes(const void* buffer, int count); void write_bytes_aligned(const void* buffer, int 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; + MemRegion get_heap_regions_range_with_current_oop_encoding_mode(); void unmap_region(int i); bool verify_region_checksum(int i); void close(); @@ -295,7 +329,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); @@ -329,6 +362,11 @@ bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false); bool verify_mapped_heap_regions(int first, int num) NOT_CDS_JAVA_HEAP_RETURN_(false); void dealloc_archive_heap_regions(MemRegion* regions, int num) NOT_CDS_JAVA_HEAP_RETURN; + + FileMapHeader::space_info* space_at(int i) { + assert(i >= 0 && i <= MetaspaceShared::last_valid_region, "invalid region"); + return &_header->_space[i]; + } }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP --- old/src/hotspot/share/memory/heapShared.cpp 2018-08-14 19:22:57.333448274 -0700 +++ new/src/hotspot/share/memory/heapShared.cpp 2018-08-14 19:22:57.009435890 -0700 @@ -28,7 +28,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" @@ -36,6 +36,7 @@ #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" +#include "utilities/bitMap.inline.hpp" #if INCLUDE_CDS_JAVA_HEAP KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL; @@ -70,6 +71,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; @@ -318,7 +322,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; } @@ -516,4 +520,80 @@ void HeapShared::archive_module_graph_objects(Thread* THREAD) { do_module_object_graph(archive_reachable_objects_from_static_field); } + +class FindEmbeddedPointers: public BasicOopIterateClosure { + narrowOop* _start; + BitMap *_oopmap; + public: + FindEmbeddedPointers(narrowOop* start, BitMap* oopmap) : _start(start), _oopmap(oopmap) {} + virtual bool should_verify_oops(void) { + return false; + } + virtual void do_oop(narrowOop* p) { + size_t idx = p - _start; + _oopmap->set_bit(idx); + } + virtual void do_oop(oop *p) { + ShouldNotReachHere(); + } +}; + +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(); + FindEmbeddedPointers relocator((narrowOop*)p, &oopmap); + + while (p < end) { + oop o = (oop)p; + o->oop_iterate(&relocator); + p += o->size(); + } + + return oopmap; +} + +void HeapShared::init_narrow_oop_decoding(address base, int shift) { + _narrow_oop_base = base; + _narrow_oop_shift = shift; +} + +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; + if (!CompressedOops::is_null(v)) { + oop o = HeapShared::decode_with_archived_oop_encoding_mode(v); + RawAccess::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(checkBm.size() == bm.size(), "sanity"); + for (size_t ci = 0; ci < bm.size(); ci++) { + assert(checkBm.at(ci) == bm.at(ci), "sanity"); + } +#endif + + PatchEmbeddedPointers patcher((narrowOop*)region.start()); + bm.iterate(&patcher); +} + #endif // INCLUDE_CDS_JAVA_HEAP --- old/src/hotspot/share/memory/heapShared.hpp 2018-08-14 19:22:58.277484355 -0700 +++ new/src/hotspot/share/memory/heapShared.hpp 2018-08-14 19:22:57.953471971 -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,11 +124,28 @@ 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; + static ResourceBitMap calculate_oopmap(MemRegion region) NOT_CDS_JAVA_HEAP_RETURN_(NULL); + + // 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 archive_module_graph_objects(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN; }; --- old/src/hotspot/share/memory/metaspaceShared.cpp 2018-08-14 19:22:59.269522270 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2018-08-14 19:22:58.941509733 -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 @@ -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 @@ -466,6 +467,7 @@ java_util_ImmutableCollections_MapN::serialize(soc); java_util_ImmutableCollections_SetN::serialize(soc); jdk_internal_module_ArchivedModuleGraph::serialize(soc); + InstanceMirrorKlass::serialize(soc); } address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) { @@ -1057,7 +1059,13 @@ GrowableArray *_closed_archive_heap_regions; GrowableArray *_open_archive_heap_regions; + GrowableArray *_closed_archive_heap_oopmaps; + GrowableArray *_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* regions, + GrowableArray* oopmaps); void dump_symbols(); char* dump_read_only_tables(); void print_region_stats(); @@ -1369,6 +1377,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; @@ -1511,10 +1522,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); } @@ -1849,6 +1862,35 @@ G1HeapVerifier::verify_archive_regions(); } +void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() { + if (MetaspaceShared::is_heap_object_archiving_allowed()) { + _closed_archive_heap_oopmaps = new GrowableArray(2); + dump_archive_heap_oopmaps(_closed_archive_heap_regions, _closed_archive_heap_oopmaps); + + _open_archive_heap_oopmaps = new GrowableArray(2); + dump_archive_heap_oopmaps(_open_archive_heap_regions, _open_archive_heap_oopmaps); + } +} + +void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps(GrowableArray* regions, + GrowableArray* oopmaps) { + for (int i=0; ilength(); 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 " (%6d bytes) for heap region " INTPTR_FORMAT " (%8d bytes)", + p2i(buffer), (int)(size_in_bytes), + p2i(regions->at(i).start()), (int)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 * closed_archive) { assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects"); @@ -1928,8 +1970,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; @@ -2005,7 +2048,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); } } @@ -2035,13 +2078,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(); @@ -2152,6 +2188,8 @@ // Initialize the run-time symbol table. SymbolTable::create_table(); + mapinfo->patch_archived_heap_embedded_pointers(); + // Close the mapinfo file mapinfo->close(); --- old/src/hotspot/share/memory/metaspaceShared.hpp 2018-08-14 19:23:00.277560798 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.hpp 2018-08-14 19:22:59.961548720 -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 @@ -222,8 +223,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); --- old/src/hotspot/share/memory/universe.cpp 2018-08-14 19:23:01.221596879 -0700 +++ new/src/hotspot/share/memory/universe.cpp 2018-08-14 19:23:00.901584648 -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 * list = java_lang_Class::fixup_mirror_list(); int list_length = list->length(); --- old/src/hotspot/share/oops/cpCache.cpp 2018-08-14 19:23:02.213634796 -0700 +++ new/src/hotspot/share/oops/cpCache.cpp 2018-08-14 19:23:01.889622412 -0700 @@ -778,7 +778,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) { --- old/src/hotspot/share/oops/instanceMirrorKlass.cpp 2018-08-14 19:23:03.205672714 -0700 +++ new/src/hotspot/share/oops/instanceMirrorKlass.cpp 2018-08-14 19:23:02.881660329 -0700 @@ -66,3 +66,9 @@ } return 0; } + +#if INCLUDE_CDS +void InstanceMirrorKlass::serialize(SerializeClosure* f) { + f->do_u4((u4*)&_offset_of_static_fields); +} +#endif --- old/src/hotspot/share/oops/instanceMirrorKlass.hpp 2018-08-14 19:23:04.173709714 -0700 +++ new/src/hotspot/share/oops/instanceMirrorKlass.hpp 2018-08-14 19:23:03.853697483 -0700 @@ -99,6 +99,8 @@ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm); #endif + static void serialize(class SerializeClosure* f) NOT_CDS_RETURN; + // Oop fields (and metadata) iterators // // The InstanceMirrorKlass iterators also visit the hidden Klass pointer. --- old/src/hotspot/share/oops/klass.cpp 2018-08-14 19:23:05.145746868 -0700 +++ new/src/hotspot/share/oops/klass.cpp 2018-08-14 19:23:04.821734484 -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"); --- old/src/hotspot/share/oops/klass.hpp 2018-08-14 19:23:06.109783716 -0700 +++ new/src/hotspot/share/oops/klass.hpp 2018-08-14 19:23:05.797771790 -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_(NULL); // 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 --- old/src/hotspot/share/runtime/arguments.cpp 2018-08-14 19:23:07.093821330 -0700 +++ new/src/hotspot/share/runtime/arguments.cpp 2018-08-14 19:23:06.781809403 -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); } --- old/src/hotspot/share/utilities/bitMap.cpp 2018-08-14 19:23:08.133861084 -0700 +++ new/src/hotspot/share/utilities/bitMap.cpp 2018-08-14 19:23:07.813848851 -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 { --- old/src/hotspot/share/utilities/bitMap.hpp 2018-08-14 19:23:09.117898698 -0700 +++ new/src/hotspot/share/utilities/bitMap.hpp 2018-08-14 19:23:08.793886313 -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 --- old/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-08-14 19:23:10.109936619 -0700 +++ new/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-08-14 19:23:09.789924386 -0700 @@ -215,7 +215,7 @@ #define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 3 +#define CURRENT_ARCHIVE_VERSION 4 typedef unsigned char* address; typedef uintptr_t uintx; @@ -240,7 +240,10 @@ 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). - + struct MemRegion { + address _start; + size_t _word_size; + } _g1_reserved; // reserved region at dump time. struct space_info { int _crc; // crc checksum of the current space @@ -257,6 +260,8 @@ // may need to adjust the type of these fields. char _read_only; // read only space? char _allow_exec; // executable code in space? + address _oopmap; // bitmap for relocating embedded oops + size_t _oopmap_size_in_bits; } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. --- old/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-08-14 19:23:11.093974233 -0700 +++ new/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-08-14 19:23:10.773962001 -0700 @@ -216,7 +216,7 @@ #define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 3 +#define CURRENT_ARCHIVE_VERSION 4 typedef unsigned char* address; typedef uintptr_t uintx; @@ -242,7 +242,10 @@ 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). - + struct MemRegion { + address _start; + size_t _word_size; + } _g1_reserved; // reserved region at dump time. struct space_info { int _crc; // crc checksum of the current space @@ -259,6 +262,8 @@ // may need to adjust the type of these fields. char _read_only; // read only space? char _allow_exec; // executable code in space? + address _oopmap; // bitmap for relocating embedded oops + size_t _oopmap_size_in_bits; } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. --- old/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-08-14 19:23:12.094012461 -0700 +++ new/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-08-14 19:23:11.770000075 -0700 @@ -499,7 +499,7 @@ const int NUM_SHARED_MAPS = 9; // Refer to FileMapInfo::_current_version in filemap.hpp -const int CURRENT_ARCHIVE_VERSION = 3; +const int CURRENT_ARCHIVE_VERSION = 4; typedef unsigned char* address; typedef uintptr_t uintx; @@ -524,7 +524,10 @@ 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). - + struct MemRegion { + address _start; + size_t _word_size; + } _g1_reserved; // reserved region at dump time. struct space_info { int _crc; // crc checksum of the current space @@ -541,6 +544,8 @@ // may need to adjust the type of these fields. char _read_only; // read only space? char _allow_exec; // executable code in space? + address _oopmap; // bitmap for relocating embedded oops + size_t _oopmap_size_in_bits; } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. --- old/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java 2018-08-14 19:23:13.098050842 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java 2018-08-14 19:23:12.774038456 -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) --- old/test/lib/jdk/test/lib/cds/CDSTestUtils.java 2018-08-14 19:23:14.098089069 -0700 +++ new/test/lib/jdk/test/lib/cds/CDSTestUtils.java 2018-08-14 19:23:13.770076531 -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; } --- /dev/null 2018-08-14 18:25:04.628316445 -0700 +++ new/src/hotspot/share/memory/heapShared.inline.hpp 2018-08-14 19:23:14.758114300 -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 --- /dev/null 2018-08-14 18:25:04.628316445 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/cacheObject/DifferentHeapSizes.java 2018-08-14 19:23:15.898157881 -0700 @@ -0,0 +1,99 @@ +/* + * 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( 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); + }); + } +} --- old/test/hotspot/jtreg/runtime/appcds/cacheObject/RangeNotWithinHeap.java 2018-08-14 19:23:17.378214460 -0700 +++ /dev/null 2018-08-14 18:25:04.628316445 -0700 @@ -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); - } - } -}