8255495: Support CDS Archived Heap for uncompressed oops

Reviewed-by: iklam, tschatzl
This commit is contained in:
Calvin Cheung 2022-02-01 19:33:36 +00:00
parent bde2b3783e
commit d95de5c7fe
14 changed files with 367 additions and 62 deletions

View File

@ -266,7 +266,7 @@ void WriteClosure::do_oop(oop* o) {
} else { } else {
assert(HeapShared::can_write(), "sanity"); assert(HeapShared::can_write(), "sanity");
_dump_region->append_intptr_t( _dump_region->append_intptr_t(
(intptr_t)CompressedOops::encode_not_null(*o)); UseCompressedOops ? (intptr_t)CompressedOops::encode_not_null(*o) : (intptr_t)((void*)(*o)));
} }
} }
@ -308,6 +308,7 @@ void ReadClosure::do_tag(int tag) {
} }
void ReadClosure::do_oop(oop *p) { void ReadClosure::do_oop(oop *p) {
if (UseCompressedOops) {
narrowOop o = CompressedOops::narrow_oop_cast(nextPtr()); narrowOop o = CompressedOops::narrow_oop_cast(nextPtr());
if (CompressedOops::is_null(o) || !HeapShared::is_fully_available()) { if (CompressedOops::is_null(o) || !HeapShared::is_fully_available()) {
*p = NULL; *p = NULL;
@ -316,6 +317,15 @@ void ReadClosure::do_oop(oop *p) {
assert(HeapShared::is_fully_available(), "must be"); assert(HeapShared::is_fully_available(), "must be");
*p = HeapShared::decode_from_archive(o); *p = HeapShared::decode_from_archive(o);
} }
} else {
intptr_t dumptime_oop = nextPtr();
if (dumptime_oop == 0 || !HeapShared::is_fully_available()) {
*p = NULL;
} else {
intptr_t runtime_oop = dumptime_oop + HeapShared::runtime_delta();
*p = cast_to_oop(runtime_oop);
}
}
} }
void ReadClosure::do_region(u_char* start, size_t size) { void ReadClosure::do_region(u_char* start, size_t size) {

View File

@ -245,8 +245,13 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_narrow_oop_mode = CompressedOops::mode(); _narrow_oop_mode = CompressedOops::mode();
_narrow_oop_base = CompressedOops::base(); _narrow_oop_base = CompressedOops::base();
_narrow_oop_shift = CompressedOops::shift(); _narrow_oop_shift = CompressedOops::shift();
if (UseCompressedOops) {
_heap_begin = CompressedOops::begin(); _heap_begin = CompressedOops::begin();
_heap_end = CompressedOops::end(); _heap_end = CompressedOops::end();
} else {
_heap_begin = (address)G1CollectedHeap::heap()->reserved().start();
_heap_end = (address)G1CollectedHeap::heap()->reserved().end();
}
} }
_compressed_oops = UseCompressedOops; _compressed_oops = UseCompressedOops;
_compressed_class_ptrs = UseCompressedClassPointers; _compressed_class_ptrs = UseCompressedClassPointers;
@ -316,6 +321,7 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs); st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs);
st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset); st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset);
st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset); st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset);
st->print_cr("- heap_begin: " INTPTR_FORMAT, p2i(_heap_begin));
st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end)); st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
st->print_cr("- jvm_ident: %s", _jvm_ident); st->print_cr("- jvm_ident: %s", _jvm_ident);
st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_HEX, _shared_path_table_offset); st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_HEX, _shared_path_table_offset);
@ -1491,7 +1497,11 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
} else if (HeapShared::is_heap_region(region)) { } else if (HeapShared::is_heap_region(region)) {
assert(!DynamicDumpSharedSpaces, "must be"); assert(!DynamicDumpSharedSpaces, "must be");
requested_base = base; requested_base = base;
if (UseCompressedOops) {
mapping_offset = (size_t)CompressedOops::encode_not_null(cast_to_oop(base)); mapping_offset = (size_t)CompressedOops::encode_not_null(cast_to_oop(base));
} else {
mapping_offset = requested_base - (char*)G1CollectedHeap::heap()->reserved().start();
}
assert(mapping_offset == (size_t)(uint32_t)mapping_offset, "must be 32-bit only"); assert(mapping_offset == (size_t)(uint32_t)mapping_offset, "must be 32-bit only");
} else { } else {
char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address(); char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address();
@ -2013,7 +2023,10 @@ bool FileMapInfo::can_use_heap_regions() {
log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
CompressedOops::mode(), p2i(CompressedOops::base()), CompressedOops::shift()); CompressedOops::mode(), p2i(CompressedOops::base()), CompressedOops::shift());
log_info(cds)(" heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", log_info(cds)(" heap range = [" PTR_FORMAT " - " PTR_FORMAT "]",
p2i(CompressedOops::begin()), p2i(CompressedOops::end())); UseCompressedOops ? p2i(CompressedOops::begin()) :
UseG1GC ? p2i((address)G1CollectedHeap::heap()->reserved().start()) : 0L,
UseCompressedOops ? p2i(CompressedOops::end()) :
UseG1GC ? p2i((address)G1CollectedHeap::heap()->reserved().end()) : 0L);
if (narrow_klass_base() != CompressedKlassPointers::base() || if (narrow_klass_base() != CompressedKlassPointers::base() ||
narrow_klass_shift() != CompressedKlassPointers::shift()) { narrow_klass_shift() != CompressedKlassPointers::shift()) {
@ -2023,6 +2036,26 @@ bool FileMapInfo::can_use_heap_regions() {
return true; return true;
} }
// The address where the bottom of this shared heap region should be mapped
// at runtime
address FileMapInfo::heap_region_runtime_start_address(FileMapRegion* spc) {
assert(UseSharedSpaces, "runtime only");
spc->assert_is_heap_region();
if (UseCompressedOops) {
return start_address_as_decoded_from_archive(spc);
} else {
assert(is_aligned(spc->mapping_offset(), sizeof(HeapWord)), "must be");
return header()->heap_begin() + spc->mapping_offset() + HeapShared::runtime_delta();
}
}
void FileMapInfo::set_shared_heap_runtime_delta(ptrdiff_t delta) {
if (UseCompressedOops) {
HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
} else {
HeapShared::set_runtime_delta(delta);
}
}
// //
// Map the closed and open archive heap objects to the runtime java heap. // Map the closed and open archive heap objects to the runtime java heap.
@ -2045,6 +2078,7 @@ void FileMapInfo::map_heap_regions_impl() {
log_info(cds)("CDS heap data needs to be relocated because the archive was created with an incompatible oop encoding mode."); log_info(cds)("CDS heap data needs to be relocated because the archive was created with an incompatible oop encoding mode.");
_heap_pointers_need_patching = true; _heap_pointers_need_patching = true;
} else { } else {
if (UseCompressedOops) {
MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode(); MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode();
if (!CompressedOops::is_in(range)) { if (!CompressedOops::is_in(range)) {
log_info(cds)("CDS heap data needs to be relocated because"); log_info(cds)("CDS heap data needs to be relocated because");
@ -2055,29 +2089,55 @@ void FileMapInfo::map_heap_regions_impl() {
log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation"); log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation");
_heap_pointers_need_patching = true; _heap_pointers_need_patching = true;
} }
} else {
MemRegion range((HeapWord*)header()->heap_begin(), (HeapWord*)header()->heap_end());
if (!G1CollectedHeap::heap()->reserved().contains(range)) {
log_info(cds)("CDS heap data needs 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((address)G1CollectedHeap::heap()->reserved().start()), p2i((address)G1CollectedHeap::heap()->reserved().end()));
_heap_pointers_need_patching = true;
} else if (header()->heap_end() != (address)G1CollectedHeap::heap()->reserved().end()) {
log_info(cds)("CDS heap data needs to be relocated to the end of the runtime heap to reduce fragmentation");
_heap_pointers_need_patching = true;
}
}
} }
ptrdiff_t delta = 0; ptrdiff_t delta = 0;
if (_heap_pointers_need_patching) { if (_heap_pointers_need_patching) {
// dumptime heap end ------------v // dumptime heap end ------------v
// [ |archived heap regions| ] runtime heap end ------v // [ |archived heap regions| ] run time heap end -----v
// [ |archived heap regions| ] // [ |archived heap regions| ]
// ^
// D ^
// R
// |<-----delta-------------------->| // |<-----delta-------------------->|
// //
// At dump time, the archived heap regions were near the top of the heap. // 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 // At run time, if the heap ends at a different address, we need to
// that they are now near the top of the runtime time. This can be done by // move them near to top of the run time heap. This can be done by
// the simple math of adding the delta as shown above. // the simple math of adding the delta as shown above.
//
// Also: D = bottom of a heap region at dump time
// R = bottom of a heap region at run time
//
// FileMapRegion* spc = ...;
// address D = header()->heap_begin() + spc->mapping_offset();
// address R = D + delta;
address dumptime_heap_end = header()->heap_end(); address dumptime_heap_end = header()->heap_end();
address runtime_heap_end = CompressedOops::end(); address runtime_heap_end = UseCompressedOops ? CompressedOops::end() :
(address)G1CollectedHeap::heap()->reserved().end();
delta = runtime_heap_end - dumptime_heap_end; delta = runtime_heap_end - dumptime_heap_end;
} }
log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta); log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta);
HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
set_shared_heap_runtime_delta(delta);
FileMapRegion* si = space_at(MetaspaceShared::first_closed_heap_region); FileMapRegion* si = space_at(MetaspaceShared::first_closed_heap_region);
address relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si); address relocated_closed_heap_region_bottom = heap_region_runtime_start_address(si);
if (!is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes)) { if (!is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes)) {
// Align the bottom of the closed archive heap regions at G1 region boundary. // Align the bottom of the closed archive heap regions at G1 region boundary.
// This will avoid the situation where the highest open region and the lowest // This will avoid the situation where the highest open region and the lowest
@ -2088,9 +2148,9 @@ void FileMapInfo::map_heap_regions_impl() {
log_info(cds)("CDS heap data needs to be relocated lower by a further " SIZE_FORMAT log_info(cds)("CDS heap data needs to be relocated lower by a further " SIZE_FORMAT
" bytes to " INTX_FORMAT " to be aligned with HeapRegion::GrainBytes", " bytes to " INTX_FORMAT " to be aligned with HeapRegion::GrainBytes",
align, delta); align, delta);
HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift()); set_shared_heap_runtime_delta(delta);
relocated_closed_heap_region_bottom = heap_region_runtime_start_address(si);
_heap_pointers_need_patching = true; _heap_pointers_need_patching = true;
relocated_closed_heap_region_bottom = start_address_as_decoded_from_archive(si);
} }
assert(is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes), assert(is_aligned(relocated_closed_heap_region_bottom, HeapRegion::GrainBytes),
"must be"); "must be");
@ -2148,7 +2208,7 @@ bool FileMapInfo::map_heap_regions(int first, int max, bool is_open_archive,
si = space_at(i); si = space_at(i);
size_t size = si->used(); size_t size = si->used();
if (size > 0) { if (size > 0) {
HeapWord* start = (HeapWord*)start_address_as_decoded_from_archive(si); HeapWord* start = (HeapWord*)heap_region_runtime_start_address(si);
regions[num_regions] = MemRegion(start, size / HeapWordSize); regions[num_regions] = MemRegion(start, size / HeapWordSize);
num_regions ++; num_regions ++;
log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes", log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes",

View File

@ -351,9 +351,8 @@ private:
static bool _memory_mapping_failed; static bool _memory_mapping_failed;
static GrowableArray<const char*>* _non_existent_class_paths; static GrowableArray<const char*>* _non_existent_class_paths;
FileMapHeader *header() const { return _header; }
public: public:
FileMapHeader *header() const { return _header; }
static bool get_base_archive_name_from_header(const char* archive_name, static bool get_base_archive_name_from_header(const char* archive_name,
char** base_archive_name); char** base_archive_name);
static SharedPathTable shared_path_table() { static SharedPathTable shared_path_table() {
@ -568,6 +567,8 @@ public:
bool can_use_heap_regions(); bool can_use_heap_regions();
bool load_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false); bool load_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false);
bool map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false); bool map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false);
address heap_region_runtime_start_address(FileMapRegion* spc) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
void set_shared_heap_runtime_delta(ptrdiff_t delta) NOT_CDS_JAVA_HEAP_RETURN;
void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN; void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
MapArchiveResult map_region(int i, intx addr_delta, char* mapped_base_address, ReservedSpace rs); MapArchiveResult map_region(int i, intx addr_delta, char* mapped_base_address, ReservedSpace rs);
bool relocate_pointers_in_core_regions(intx addr_delta); bool relocate_pointers_in_core_regions(intx addr_delta);

View File

@ -76,6 +76,7 @@ address HeapShared::_narrow_oop_base;
int HeapShared::_narrow_oop_shift; int HeapShared::_narrow_oop_shift;
DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL; DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
// Support for loaded heap.
uintptr_t HeapShared::_loaded_heap_bottom = 0; uintptr_t HeapShared::_loaded_heap_bottom = 0;
uintptr_t HeapShared::_loaded_heap_top = 0; uintptr_t HeapShared::_loaded_heap_top = 0;
uintptr_t HeapShared::_dumptime_base_0 = UINTPTR_MAX; uintptr_t HeapShared::_dumptime_base_0 = UINTPTR_MAX;
@ -88,6 +89,10 @@ intx HeapShared::_runtime_offset_1 = 0;
intx HeapShared::_runtime_offset_2 = 0; intx HeapShared::_runtime_offset_2 = 0;
intx HeapShared::_runtime_offset_3 = 0; intx HeapShared::_runtime_offset_3 = 0;
bool HeapShared::_loading_failed = false; bool HeapShared::_loading_failed = false;
// Suport for mapped heap (!UseCompressedOops only)
ptrdiff_t HeapShared::_runtime_delta = 0;
// //
// If you add new entries to the following tables, you should know what you're doing! // If you add new entries to the following tables, you should know what you're doing!
// //
@ -362,7 +367,10 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions,
create_archived_object_cache(); create_archived_object_cache();
log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]",
p2i(CompressedOops::begin()), p2i(CompressedOops::end())); UseCompressedOops ? p2i(CompressedOops::begin()) :
p2i((address)G1CollectedHeap::heap()->reserved().start()),
UseCompressedOops ? p2i(CompressedOops::end()) :
p2i((address)G1CollectedHeap::heap()->reserved().end()));
log_info(cds)("Dumping objects to closed archive heap region ..."); log_info(cds)("Dumping objects to closed archive heap region ...");
copy_closed_objects(closed_regions); copy_closed_objects(closed_regions);
@ -658,7 +666,6 @@ void HeapShared::write_subgraph_info_table() {
CompactHashtableWriter writer(d_table->_count, &stats); CompactHashtableWriter writer(d_table->_count, &stats);
CopyKlassSubGraphInfoToArchive copy(&writer); CopyKlassSubGraphInfoToArchive copy(&writer);
d_table->iterate(&copy); d_table->iterate(&copy);
writer.dump(&_run_time_subgraph_info_table, "subgraphs"); writer.dump(&_run_time_subgraph_info_table, "subgraphs");
} }
@ -1400,39 +1407,44 @@ void HeapShared::add_to_dumped_interned_strings(oop string) {
// region. This way we can quickly relocate all the pointers without using // region. This way we can quickly relocate all the pointers without using
// BasicOopIterateClosure at runtime. // BasicOopIterateClosure at runtime.
class FindEmbeddedNonNullPointers: public BasicOopIterateClosure { class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
narrowOop* _start; void* _start;
BitMap *_oopmap; BitMap *_oopmap;
int _num_total_oops; int _num_total_oops;
int _num_null_oops; int _num_null_oops;
public: public:
FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap) FindEmbeddedNonNullPointers(void* start, BitMap* oopmap)
: _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {} : _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {}
virtual void do_oop(narrowOop* p) { virtual void do_oop(narrowOop* p) {
_num_total_oops ++; _num_total_oops ++;
narrowOop v = *p; narrowOop v = *p;
if (!CompressedOops::is_null(v)) { if (!CompressedOops::is_null(v)) {
size_t idx = p - _start; size_t idx = p - (narrowOop*)_start;
_oopmap->set_bit(idx); _oopmap->set_bit(idx);
} else { } else {
_num_null_oops ++; _num_null_oops ++;
} }
} }
virtual void do_oop(oop* p) { virtual void do_oop(oop* p) {
ShouldNotReachHere(); _num_total_oops ++;
if ((*p) != NULL) {
size_t idx = p - (oop*)_start;
_oopmap->set_bit(idx);
} else {
_num_null_oops ++;
}
} }
int num_total_oops() const { return _num_total_oops; } int num_total_oops() const { return _num_total_oops; }
int num_null_oops() const { return _num_null_oops; } int num_null_oops() const { return _num_null_oops; }
}; };
ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) { ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
assert(UseCompressedOops, "must be"); size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
size_t num_bits = region.byte_size() / sizeof(narrowOop);
ResourceBitMap oopmap(num_bits); ResourceBitMap oopmap(num_bits);
HeapWord* p = region.start(); HeapWord* p = region.start();
HeapWord* end = region.end(); HeapWord* end = region.end();
FindEmbeddedNonNullPointers finder((narrowOop*)p, &oopmap); FindEmbeddedNonNullPointers finder((void*)p, &oopmap);
ArchiveBuilder* builder = DumpSharedSpaces ? ArchiveBuilder::current() : NULL; ArchiveBuilder* builder = DumpSharedSpaces ? ArchiveBuilder::current() : NULL;
int num_objs = 0; int num_objs = 0;
@ -1453,11 +1465,11 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
// Patch all the embedded oop pointers inside an archived heap region, // Patch all the embedded oop pointers inside an archived heap region,
// to be consistent with the runtime oop encoding. // to be consistent with the runtime oop encoding.
class PatchEmbeddedPointers: public BitMapClosure { class PatchCompressedEmbeddedPointers: public BitMapClosure {
narrowOop* _start; narrowOop* _start;
public: public:
PatchEmbeddedPointers(narrowOop* start) : _start(start) {} PatchCompressedEmbeddedPointers(narrowOop* start) : _start(start) {}
bool do_bit(size_t offset) { bool do_bit(size_t offset) {
narrowOop* p = _start + offset; narrowOop* p = _start + offset;
@ -1469,6 +1481,22 @@ class PatchEmbeddedPointers: public BitMapClosure {
} }
}; };
class PatchUncompressedEmbeddedPointers: public BitMapClosure {
oop* _start;
public:
PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {}
bool do_bit(size_t offset) {
oop* p = _start + offset;
intptr_t dumptime_oop = (intptr_t)((void*)*p);
assert(dumptime_oop != 0, "null oops should have been filtered out at dump time");
intptr_t runtime_oop = dumptime_oop + HeapShared::runtime_delta();
RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(runtime_oop));
return true;
}
};
// Patch all the non-null pointers that are embedded in the archived heap objects // Patch all the non-null pointers that are embedded in the archived heap objects
// in this region // in this region
void HeapShared::patch_embedded_pointers(MemRegion region, address oopmap, void HeapShared::patch_embedded_pointers(MemRegion region, address oopmap,
@ -1481,8 +1509,13 @@ void HeapShared::patch_embedded_pointers(MemRegion region, address oopmap,
assert(bm.is_same(checkBm), "sanity"); assert(bm.is_same(checkBm), "sanity");
#endif #endif
PatchEmbeddedPointers patcher((narrowOop*)region.start()); if (UseCompressedOops) {
PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
bm.iterate(&patcher); bm.iterate(&patcher);
} else {
PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
bm.iterate(&patcher);
}
} }
// The CDS archive remembers each heap object by its address at dump time, but // The CDS archive remembers each heap object by its address at dump time, but

View File

@ -159,7 +159,7 @@ public:
if (_disable_writing) { if (_disable_writing) {
return false; return false;
} }
return (UseG1GC && UseCompressedOops && UseCompressedClassPointers); return (UseG1GC && UseCompressedClassPointers);
) )
NOT_CDS_JAVA_HEAP(return false;) NOT_CDS_JAVA_HEAP(return false;)
} }
@ -169,7 +169,7 @@ public:
} }
// Can this VM map archived heap regions? Currently only G1+compressed{oops,cp} // Can this VM map archived heap regions? Currently only G1+compressed{oops,cp}
static bool can_map() { static bool can_map() {
CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);) CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);)
NOT_CDS_JAVA_HEAP(return false;) NOT_CDS_JAVA_HEAP(return false;)
} }
static bool is_mapped() { static bool is_mapped() {
@ -297,10 +297,13 @@ private:
static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
int num, TRAPS); int num, TRAPS);
// Used by decode_from_archive // UseCompressedOops only: Used by decode_from_archive
static address _narrow_oop_base; static address _narrow_oop_base;
static int _narrow_oop_shift; static int _narrow_oop_shift;
// !UseCompressedOops only: used to relocate pointers to the archived objects
static ptrdiff_t _runtime_delta;
typedef ResourceHashtable<oop, bool, typedef ResourceHashtable<oop, bool,
15889, // prime number 15889, // prime number
ResourceObj::C_HEAP, ResourceObj::C_HEAP,
@ -418,9 +421,21 @@ private:
// Run-time only // Run-time only
static void clear_root(int index); static void clear_root(int index);
static void set_runtime_delta(ptrdiff_t delta) {
assert(!UseCompressedOops, "must be");
_runtime_delta = delta;
}
#endif // INCLUDE_CDS_JAVA_HEAP #endif // INCLUDE_CDS_JAVA_HEAP
public: public:
static ptrdiff_t runtime_delta() {
assert(!UseCompressedOops, "must be");
CDS_JAVA_HEAP_ONLY(return _runtime_delta;)
NOT_CDS_JAVA_HEAP_RETURN_(0L);
}
static void run_full_gc_in_vm_thread() NOT_CDS_JAVA_HEAP_RETURN; static void run_full_gc_in_vm_thread() NOT_CDS_JAVA_HEAP_RETURN;
static bool is_heap_region(int idx) { static bool is_heap_region(int idx) {

View File

@ -65,6 +65,7 @@
#include "oops/oopHandle.hpp" #include "oops/oopHandle.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "runtime/safepointVerifiers.hpp" #include "runtime/safepointVerifiers.hpp"
@ -709,6 +710,30 @@ void MetaspaceShared::preload_and_dump() {
} }
} }
#if INCLUDE_CDS_JAVA_HEAP && defined(_LP64)
void MetaspaceShared::adjust_heap_sizes_for_dumping() {
if (!DumpSharedSpaces || UseCompressedOops) {
return;
}
// CDS heap dumping requires all string oops to have an offset
// from the heap bottom that can be encoded in 32-bit.
julong max_heap_size = (julong)(4 * G);
if (MinHeapSize > max_heap_size) {
log_debug(cds)("Setting MinHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", MinHeapSize/M);
FLAG_SET_ERGO(MinHeapSize, max_heap_size);
}
if (InitialHeapSize > max_heap_size) {
log_debug(cds)("Setting InitialHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", InitialHeapSize/M);
FLAG_SET_ERGO(InitialHeapSize, max_heap_size);
}
if (MaxHeapSize > max_heap_size) {
log_debug(cds)("Setting MaxHeapSize to 4G for CDS dumping, original size = " SIZE_FORMAT "M", MaxHeapSize/M);
FLAG_SET_ERGO(MaxHeapSize, max_heap_size);
}
}
#endif // INCLUDE_CDS_JAVA_HEAP && _LP64
void MetaspaceShared::preload_classes(TRAPS) { void MetaspaceShared::preload_classes(TRAPS) {
char default_classlist[JVM_MAXPATHLEN]; char default_classlist[JVM_MAXPATHLEN];
const char* classlist_path; const char* classlist_path;
@ -834,11 +859,10 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) {
void VM_PopulateDumpSharedSpace::dump_java_heap_objects(GrowableArray<Klass*>* klasses) { void VM_PopulateDumpSharedSpace::dump_java_heap_objects(GrowableArray<Klass*>* klasses) {
if(!HeapShared::can_write()) { if(!HeapShared::can_write()) {
log_info(cds)( log_info(cds)(
"Archived java heap is not supported as UseG1GC, " "Archived java heap is not supported as UseG1GC "
"UseCompressedOops and UseCompressedClassPointers are required." "and UseCompressedClassPointers are required."
"Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.", "Current settings: UseG1GC=%s, UseCompressedClassPointers=%s.",
BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops), BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedClassPointers));
BOOL_TO_STR(UseCompressedClassPointers));
return; return;
} }
// Find all the interned strings that should be dumped. // Find all the interned strings that should be dumped.

View File

@ -82,6 +82,9 @@ class MetaspaceShared : AllStatic {
static void prepare_for_dumping() NOT_CDS_RETURN; static void prepare_for_dumping() NOT_CDS_RETURN;
static void preload_and_dump() NOT_CDS_RETURN; static void preload_and_dump() NOT_CDS_RETURN;
#ifdef _LP64
static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN;
#endif
private: private:
static void preload_and_dump_impl(TRAPS) NOT_CDS_RETURN; static void preload_and_dump_impl(TRAPS) NOT_CDS_RETURN;

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "cds/archiveBuilder.hpp" #include "cds/archiveBuilder.hpp"
#include "cds/filemap.hpp"
#include "cds/heapShared.inline.hpp" #include "cds/heapShared.inline.hpp"
#include "classfile/altHashing.hpp" #include "classfile/altHashing.hpp"
#include "classfile/compactHashtable.hpp" #include "classfile/compactHashtable.hpp"
@ -55,6 +56,9 @@
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/resizeableResourceHash.hpp" #include "utilities/resizeableResourceHash.hpp"
#include "utilities/utf8.hpp" #include "utilities/utf8.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
#endif
// We prefer short chains of avg 2 // We prefer short chains of avg 2
const double PREF_AVG_LIST_LEN = 2.0; const double PREF_AVG_LIST_LEN = 2.0;
@ -67,9 +71,18 @@ const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5;
#if INCLUDE_CDS_JAVA_HEAP #if INCLUDE_CDS_JAVA_HEAP
inline oop read_string_from_compact_hashtable(address base_address, u4 offset) { inline oop read_string_from_compact_hashtable(address base_address, u4 offset) {
if (UseCompressedOops) {
assert(sizeof(narrowOop) == sizeof(offset), "must be"); assert(sizeof(narrowOop) == sizeof(offset), "must be");
narrowOop v = CompressedOops::narrow_oop_cast(offset); narrowOop v = CompressedOops::narrow_oop_cast(offset);
return HeapShared::decode_from_archive(v); return HeapShared::decode_from_archive(v);
} else {
intptr_t dumptime_oop = (uintptr_t)offset;
assert(dumptime_oop != 0, "null strings cannot be interned");
intptr_t runtime_oop = dumptime_oop +
(intptr_t)FileMapInfo::current_info()->header()->heap_begin() +
(intptr_t)HeapShared::runtime_delta();
return (oop)cast_to_oop(runtime_oop);
}
} }
typedef CompactHashtable< typedef CompactHashtable<
@ -746,6 +759,16 @@ oop StringTable::create_archived_string(oop s) {
class CopyToArchive : StackObj { class CopyToArchive : StackObj {
CompactHashtableWriter* _writer; CompactHashtableWriter* _writer;
private:
u4 compute_delta(oop s) {
HeapWord* start = G1CollectedHeap::heap()->reserved().start();
intx offset = ((address)(void*)s) - ((address)(void*)start);
assert(offset >= 0, "must be");
if (offset > 0xffffffff) {
fatal("too large");
}
return (u4)offset;
}
public: public:
CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {} CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {}
bool do_entry(oop s, bool value_ignored) { bool do_entry(oop s, bool value_ignored) {
@ -757,7 +780,11 @@ public:
} }
// add to the compact table // add to the compact table
if (UseCompressedOops) {
_writer->add(hash, CompressedOops::narrow_oop_value(new_s)); _writer->add(hash, CompressedOops::narrow_oop_value(new_s));
} else {
_writer->add(hash, compute_delta(new_s));
}
return true; return true;
} }
}; };
@ -771,7 +798,6 @@ void StringTable::write_to_archive(const DumpedInternedStrings* dumped_interned_
// Copy the interned strings into the "string space" within the java heap // Copy the interned strings into the "string space" within the java heap
CopyToArchive copier(&writer); CopyToArchive copier(&writer);
dumped_interned_strings->iterate(&copier); dumped_interned_strings->iterate(&copier);
writer.dump(&_shared_table, "string"); writer.dump(&_shared_table, "string");
} }

View File

@ -132,7 +132,7 @@ public:
bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); }
// Support for loading objects from CDS archive into the heap // Support for loading objects from CDS archive into the heap
virtual bool can_load_archived_objects() const { return true; } virtual bool can_load_archived_objects() const { return UseCompressedOops; }
virtual HeapWord* allocate_loaded_archive_space(size_t size); virtual HeapWord* allocate_loaded_archive_space(size_t size);
virtual void print_on(outputStream* st) const; virtual void print_on(outputStream* st) const;

View File

@ -105,7 +105,7 @@ public:
virtual void safepoint_synchronize_end(); virtual void safepoint_synchronize_end();
// Support for loading objects from CDS archive into the heap // Support for loading objects from CDS archive into the heap
bool can_load_archived_objects() const { return true; } bool can_load_archived_objects() const { return UseCompressedOops; }
HeapWord* allocate_loaded_archive_space(size_t size); HeapWord* allocate_loaded_archive_space(size_t size);
void complete_loaded_archive_space(MemRegion archive_space); void complete_loaded_archive_space(MemRegion archive_space);
}; };

View File

@ -748,6 +748,10 @@ jint universe_init() {
GCLogPrecious::initialize(); GCLogPrecious::initialize();
#ifdef _LP64
MetaspaceShared::adjust_heap_sizes_for_dumping();
#endif // _LP64
GCConfig::arguments()->initialize_heap_sizes(); GCConfig::arguments()->initialize_heap_sizes();
jint status = Universe::initialize_heap(); jint status = Universe::initialize_heap();

View File

@ -46,6 +46,10 @@ hotspot_gc = \
hotspot_runtime = \ hotspot_runtime = \
runtime runtime
hotspot_runtime_no_cds = \
runtime \
-runtime/cds
hotspot_handshake = \ hotspot_handshake = \
runtime/handshake runtime/handshake
@ -384,6 +388,8 @@ hotspot_cds = \
runtime/cds/ \ runtime/cds/ \
runtime/CompressedOops/ runtime/CompressedOops/
hotspot_cds_only = \
runtime/cds/
hotspot_appcds_dynamic = \ hotspot_appcds_dynamic = \
runtime/cds/appcds/ \ runtime/cds/appcds/ \
@ -405,6 +411,7 @@ hotspot_appcds_dynamic = \
-runtime/cds/appcds/BadBSM.java \ -runtime/cds/appcds/BadBSM.java \
-runtime/cds/appcds/DumpClassList.java \ -runtime/cds/appcds/DumpClassList.java \
-runtime/cds/appcds/DumpClassListWithLF.java \ -runtime/cds/appcds/DumpClassListWithLF.java \
-runtime/cds/appcds/DumpingWithNoCoops.java \
-runtime/cds/appcds/ExtraSymbols.java \ -runtime/cds/appcds/ExtraSymbols.java \
-runtime/cds/appcds/LambdaContainsOldInf.java \ -runtime/cds/appcds/LambdaContainsOldInf.java \
-runtime/cds/appcds/LambdaEagerInit.java \ -runtime/cds/appcds/LambdaEagerInit.java \

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2022, 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
* @bug 8255495
* @summary Test CDS with UseCompressedOops disable with various heap sizes.
* @requires vm.cds.write.archived.java.heap
* @requires vm.gc.G1
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile test-classes/Hello.java
* @run driver DumpingWithNoCoops
*/
import java.util.ArrayList;
import java.util.List;
import jdk.test.lib.process.OutputAnalyzer;
public class DumpingWithNoCoops {
static class HeapArgs {
int initialSize, minSize, maxSize;
HeapArgs(int initial, int min, int max) {
initialSize = initial;
minSize = min;
maxSize = max;
}
String heapArgsString(HeapArgs ha) {
String heapArgs = "";
if (ha.initialSize > 0) {
heapArgs += "-XX:InitialHeapSize=" + ha.initialSize + "g";
}
if (ha.minSize > 0) {
if (heapArgs.length() > 0) {
heapArgs += " ";
}
heapArgs += "-XX:MinHeapSize=" + ha.minSize + "g";
}
if (ha.maxSize > 0) {
if (heapArgs.length() > 0) {
heapArgs += " ";
}
heapArgs += "-XX:MaxHeapSize=" + ha.maxSize + "g";
}
return heapArgs;
}
}
static HeapArgs[] heapArgsCases = {
// InitialHeapSize, MinHeapSize, MaxHeapSize
// all sizes are in the unit of GB
// size of 0 means don't set the heap size
new HeapArgs( 0, 0, 0),
new HeapArgs( 8, 0, 0),
new HeapArgs( 0, 8, 0),
new HeapArgs( 0, 0, 8),
new HeapArgs( 8, 8, 0),
new HeapArgs( 0, 8, 8),
new HeapArgs( 8, 0, 8),
new HeapArgs( 8, 8, 8),
new HeapArgs( 2, 1, 33),
};
public static void main(String[] args) throws Exception {
final String noCoops = "-XX:-UseCompressedOops";
final String logArg = "-Xlog:gc+heap=trace,cds=debug";
JarBuilder.getOrCreateHelloJar();
String appJar = TestCommon.getTestJar("hello.jar");
String appClasses[] = TestCommon.list("Hello");
for (HeapArgs ha : heapArgsCases) {
String heapArg = ha.heapArgsString(ha);
List<String> dumptimeArgs = new ArrayList<String>();
// UseCompressedOops is ergonomically disabled for MaxHeapSize > 32g.
if (ha.maxSize < 32) {
dumptimeArgs.add(noCoops);
}
dumptimeArgs.add(logArg);
OutputAnalyzer output;
if (heapArg.length() == 0) {
System.out.println("\n Test without heap args\n");
output = TestCommon.dump(appJar, appClasses, dumptimeArgs.toArray(new String[0]));
} else {
System.out.println("\n Test with heap args: " + heapArg + "\n");
String[] heapSizes = heapArg.split(" ");
for (String heapSize : heapSizes) {
dumptimeArgs.add(heapSize);
}
output = TestCommon.dump(appJar, appClasses, dumptimeArgs.toArray(new String[0]));
output.shouldContain("Setting MaxHeapSize to 4G for CDS dumping");
}
TestCommon.checkDump(output);
TestCommon.run("-cp", appJar,
logArg, "-Xlog:class+load", noCoops, "Hello")
.assertNormalExit("Hello source: shared objects file");
}
}
}

View File

@ -62,6 +62,8 @@ public class DifferentHeapSizes {
JarBuilder.getOrCreateHelloJar(); JarBuilder.getOrCreateHelloJar();
String appJar = TestCommon.getTestJar("hello.jar"); String appJar = TestCommon.getTestJar("hello.jar");
String appClasses[] = TestCommon.list("Hello"); String appClasses[] = TestCommon.list("Hello");
WhiteBox wb = WhiteBox.getWhiteBox();
boolean useCompressedOops = wb.getBooleanVMFlag("UseCompressedOops");
for (Scenario s : scenarios) { for (Scenario s : scenarios) {
String dumpXmx = "-Xmx" + s.dumpSize + "m"; String dumpXmx = "-Xmx" + s.dumpSize + "m";
@ -71,7 +73,7 @@ public class DifferentHeapSizes {
String runXmx = "-Xmx" + runSize + "m"; String runXmx = "-Xmx" + runSize + "m";
CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion", CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion",
"-Xlog:cds", runXmx, DEDUP, "Hello"); "-Xlog:cds", runXmx, DEDUP, "Hello");
if (runSize < 32768) { if (runSize < 32768 || !useCompressedOops) {
result result
.assertNormalExit("Hello World") .assertNormalExit("Hello World")
.assertNormalExit(out -> { .assertNormalExit(out -> {
@ -88,7 +90,7 @@ public class DifferentHeapSizes {
// Test various settings of -XX:HeapBaseMinAddress that would trigger // Test various settings of -XX:HeapBaseMinAddress that would trigger
// "CDS heap data need to be relocated because the desired range ... is outside of the heap" // "CDS heap data need to be relocated because the desired range ... is outside of the heap"
long default_base = WhiteBox.getWhiteBox().getSizeTVMFlag("HeapBaseMinAddress").longValue(); long default_base = wb.getSizeTVMFlag("HeapBaseMinAddress").longValue();
long M = 1024 * 1024; long M = 1024 * 1024;
long bases[] = new long[] { long bases[] = new long[] {
/* dump xmx */ /* run xmx */ /* dump base */ /* run base */ /* dump xmx */ /* run xmx */ /* dump base */ /* run base */