--- old/src/hotspot/share/memory/filemap.cpp 2018-08-01 22:33:59.611835276 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2018-08-01 22:33:58.719801351 -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" @@ -188,6 +191,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,7 +531,7 @@ } size_t len = lseek(fd, 0, SEEK_END); - struct FileMapInfo::FileMapHeader::space_info* si = + FileMapHeader::space_info* si = &_header->_space[MetaspaceShared::last_valid_region]; // The last space might be empty if (si->_file_offset > len || len - si->_file_offset < si->_used) { @@ -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 = &_header->_space[region]; if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); @@ -760,7 +766,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 = &_header->_space[idx]; if (!si->_read_only) { // the space is already readwrite so we are done return true; @@ -812,7 +818,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 = &_header->_space[i]; size_t used = si->_used; size_t alignment = os::vm_allocation_granularity(); size_t size = align_up(used, alignment); @@ -852,6 +858,10 @@ static int num_open_archive_heap_ranges = 0; #if INCLUDE_CDS_JAVA_HEAP +bool FileMapInfo::has_heap_regions() { + return (_header->_space[MetaspaceShared::first_string]._used > 0); +} + // // Map the shared string objects and open archive heap objects to the runtime // java heap. @@ -866,55 +876,79 @@ // 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(); - } - } - } - } else { - if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) { - log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, " - "UseCompressedOops and UseCompressedClassPointers are required."); +void FileMapInfo::map_heap_regions_impl() { + if (!MetaspaceShared::is_heap_object_archiving_allowed()) { + log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, " + "UseCompressedOops and UseCompressedClassPointers are required."); + return; + } + + if (narrow_klass_base() != Universe::narrow_klass_base() || + narrow_klass_shift() != Universe::narrow_klass_shift()) { + log_info(cds)("Cached heap data from the CDS archive need to be relocated because"); + log_info(cds)("the CDS archive was created with an incompatible heap size: " UINTX_FORMAT "M.", max_heap_size()/M); + log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", + p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift()); + return; + } + + log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift()); + log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", + p2i(narrow_klass_base()), narrow_klass_shift()); + + ptrdiff_t delta = 0; + + if (narrow_oop_mode() != Universe::narrow_oop_mode() || + narrow_oop_base() != Universe::narrow_oop_base() || + narrow_oop_shift() != Universe::narrow_oop_shift()) { + log_info(cds)("Cached heap data from the CDS archive need to be relocated because"); + log_info(cds)("the CDS archive was created with an incompatible heap size: " UINTX_FORMAT "M.", max_heap_size()/M); + log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()), + Universe::narrow_oop_shift()); + + _heap_pointers_need_relocation = true; + + // dumptime heap end ------------v + // [ |archived heap regions| ] runtime heap end ------v + // [ |archived heap regions| ] + // |<-----delta-------------------->| + // + // At dump time, the archived heap region were near the top of the heap. + // At run time, that region may not be inside the heap, so we move it so + // that it's now near the top of teh runtime time. This can be done by + // the simple math of adding the delta as shown above. + address dumptime_heap_end = (address)_header->_g1_reserved.end(); + address runtime_heap_end = (address)G1CollectedHeap::heap()->g1_reserved().end(); + delta = runtime_heap_end - dumptime_heap_end; + } + + HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift()); + + // First, map string regions as closed archive heap regions. + // GC does not write into the regions. + if (map_heap_data(&string_ranges, + MetaspaceShared::first_string, + MetaspaceShared::max_strings, + &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,16 +962,15 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first, int max, int* num, bool is_open_archive) { MemRegion * regions = new MemRegion[max]; - struct FileMapInfo::FileMapHeader::space_info* si; + FileMapHeader::space_info* si; int region_num = 0; for (int i = first; i < first + max; i++) { si = &_header->_space[i]; - size_t used = si->_used; - if (used > 0) { - size_t size = used; - char* requested_addr = (char*)((void*)CompressedOops::decode_not_null( + size_t size = si->_used; + if (size > 0) { + char* requested_addr = (char*)((void*)HeapShared::decode_not_null( (narrowOop)si->_addr._offset)); regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize); region_num ++; @@ -1003,6 +1036,51 @@ return true; } +void FileMapInfo::relocate_archived_heap_embedded_pointers() { + if (!_heap_pointers_need_relocation) { + return; + } + + relocate_archived_heap_embedded_pointers_impl(string_ranges, + num_string_ranges); + + relocate_archived_heap_embedded_pointers_impl(open_archive_heap_ranges, + num_open_archive_heap_ranges); +} + +class RelocateInternalPointers: public BasicOopIterateClosure { + public: + virtual bool should_verify_oops(void) { + return false; + } + virtual void do_oop(narrowOop *p) { + narrowOop v = *p; + if (!CompressedOops::is_null(v)) { + oop o = HeapShared::decode_not_null(v); + RawAccess::oop_store(p, o); + } + } + virtual void do_oop(oop *p) { + ShouldNotReachHere(); + } +}; + +void FileMapInfo::relocate_archived_heap_embedded_pointers_impl(MemRegion *heap_mem, int num) { + RelocateInternalPointers relocator; + + for (int i=0; ioop_iterate(&relocator); + p += o->size(); + } + } +} + +// This internally allocates objects using SystemDictionary::Object_klass(), so it +// must be called after the well-known classes are resolved. void FileMapInfo::fixup_mapped_heap_regions() { // If any string regions were found, call the fill routine to make them parseable. // Note that string_ranges may be non-NULL even if no ranges were found. @@ -1057,7 +1135,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 = &_header->_space[i]; size_t used = si->_used; size_t size = align_up(used, os::vm_allocation_granularity()); @@ -1086,6 +1164,7 @@ FileMapInfo* FileMapInfo::_current_info = NULL; +bool FileMapInfo::_heap_pointers_need_relocation = false; Array* FileMapInfo::_shared_path_table = NULL; int FileMapInfo::_shared_path_table_size = 0; size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;