8282828: CDS uncompressed oops archive is not deterministic

Reviewed-by: erikj, ihse, ccheung
This commit is contained in:
Ioi Lam 2022-05-03 04:06:56 +00:00
parent 45ca81ff5f
commit 64b5b2b0b3
6 changed files with 84 additions and 24 deletions

View File

@ -324,7 +324,7 @@ compare_general_files() {
! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ ! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \
! -name "*.lib" ! -name "*.jmod" ! -name "*.exe" \ ! -name "*.lib" ! -name "*.jmod" ! -name "*.exe" \
! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \ ! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \
! -name "*.tar.gz" ! -name "classes_nocoops.jsa" ! -name "gtestLauncher" \ ! -name "*.tar.gz" ! -name "gtestLauncher" \
! -name "*.map" \ ! -name "*.map" \
| $GREP -v "./bin/" | $SORT | $FILTER) | $GREP -v "./bin/" | $SORT | $FILTER)

View File

@ -1016,24 +1016,27 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
#undef _LOG_PREFIX #undef _LOG_PREFIX
// Log information about a region, whose address at dump time is [base .. top). At // Log information about a region, whose address at dump time is [base .. top). At
// runtime, this region will be mapped to runtime_base. runtime_base is 0 if this // runtime, this region will be mapped to requested_base. requested_base is 0 if this
// region will be mapped at os-selected addresses (such as the bitmap region), or will // region will be mapped at os-selected addresses (such as the bitmap region), or will
// be accessed with os::read (the header). // be accessed with os::read (the header).
static void log_region(const char* name, address base, address top, address runtime_base) { //
// Note: across -Xshare:dump runs, base may be different, but requested_base should
// be the same as the archive contents should be deterministic.
static void log_region(const char* name, address base, address top, address requested_base) {
size_t size = top - base; size_t size = top - base;
base = runtime_base; base = requested_base;
top = runtime_base + size; top = requested_base + size;
log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " " SIZE_FORMAT_W(9) " bytes]", log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " " SIZE_FORMAT_W(9) " bytes]",
name, p2i(base), p2i(top), size); name, p2i(base), p2i(top), size);
} }
#if INCLUDE_CDS_JAVA_HEAP
// open and closed archive regions // open and closed archive regions
static void log_heap_regions(const char* which, GrowableArray<MemRegion> *regions) { static void log_heap_regions(const char* which, GrowableArray<MemRegion> *regions) {
#if INCLUDE_CDS_JAVA_HEAP
for (int i = 0; i < regions->length(); i++) { for (int i = 0; i < regions->length(); i++) {
address start = address(regions->at(i).start()); address start = address(regions->at(i).start());
address end = address(regions->at(i).end()); address end = address(regions->at(i).end());
log_region(which, start, end, start); log_region(which, start, end, to_requested(start));
while (start < end) { while (start < end) {
size_t byte_size; size_t byte_size;
@ -1042,34 +1045,37 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
if (original_oop != NULL) { if (original_oop != NULL) {
ResourceMark rm; ResourceMark rm;
log_info(cds, map)(PTR_FORMAT ": @@ Object %s", log_info(cds, map)(PTR_FORMAT ": @@ Object %s",
p2i(start), original_oop->klass()->external_name()); p2i(to_requested(start)), original_oop->klass()->external_name());
byte_size = original_oop->size() * BytesPerWord; byte_size = original_oop->size() * BytesPerWord;
} else if (archived_oop == HeapShared::roots()) { } else if (archived_oop == HeapShared::roots()) {
// HeapShared::roots() is copied specially so it doesn't exist in // HeapShared::roots() is copied specially so it doesn't exist in
// HeapShared::OriginalObjectTable. See HeapShared::copy_roots(). // HeapShared::OriginalObjectTable. See HeapShared::copy_roots().
log_info(cds, map)(PTR_FORMAT ": @@ Object HeapShared:roots (ObjArray)", log_info(cds, map)(PTR_FORMAT ": @@ Object HeapShared::roots (ObjArray)",
p2i(start)); p2i(to_requested(start)));
byte_size = objArrayOopDesc::object_size(HeapShared::roots()->length()) * BytesPerWord; byte_size = objArrayOopDesc::object_size(HeapShared::roots()->length()) * BytesPerWord;
} else { } else {
// We have reached the end of the region // We have reached the end of the region
break; break;
} }
address oop_end = start + byte_size; address oop_end = start + byte_size;
log_data(start, oop_end, start, /*is_heap=*/true); log_data(start, oop_end, to_requested(start), /*is_heap=*/true);
start = oop_end; start = oop_end;
} }
if (start < end) { if (start < end) {
log_info(cds, map)(PTR_FORMAT ": @@ Unused heap space " SIZE_FORMAT " bytes", log_info(cds, map)(PTR_FORMAT ": @@ Unused heap space " SIZE_FORMAT " bytes",
p2i(start), size_t(end - start)); p2i(to_requested(start)), size_t(end - start));
log_data(start, end, start, /*is_heap=*/true); log_data(start, end, to_requested(start), /*is_heap=*/true);
} }
} }
#endif
} }
static address to_requested(address p) {
return HeapShared::to_requested_address(p);
}
#endif
// Log all the data [base...top). Pretend that the base address // Log all the data [base...top). Pretend that the base address
// will be mapped to runtime_base at run-time. // will be mapped to requested_base at run-time.
static void log_data(address base, address top, address runtime_base, bool is_heap = false) { static void log_data(address base, address top, address requested_base, bool is_heap = false) {
assert(top >= base, "must be"); assert(top >= base, "must be");
LogStreamHandle(Trace, cds, map) lsh; LogStreamHandle(Trace, cds, map) lsh;
@ -1080,7 +1086,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
// longs and doubles will be split into two words. // longs and doubles will be split into two words.
unitsize = sizeof(narrowOop); unitsize = sizeof(narrowOop);
} }
os::print_hex_dump(&lsh, base, top, unitsize, 32, runtime_base); os::print_hex_dump(&lsh, base, top, unitsize, 32, requested_base);
} }
} }
@ -1114,12 +1120,14 @@ public:
log_region("bitmap", address(bitmap), bitmap_end, 0); log_region("bitmap", address(bitmap), bitmap_end, 0);
log_data((address)bitmap, bitmap_end, 0); log_data((address)bitmap, bitmap_end, 0);
#if INCLUDE_CDS_JAVA_HEAP
if (closed_heap_regions != NULL) { if (closed_heap_regions != NULL) {
log_heap_regions("closed heap region", closed_heap_regions); log_heap_regions("closed heap region", closed_heap_regions);
} }
if (open_heap_regions != NULL) { if (open_heap_regions != NULL) {
log_heap_regions("open heap region", open_heap_regions); log_heap_regions("open heap region", open_heap_regions);
} }
#endif
log_info(cds, map)("[End of CDS archive map]"); log_info(cds, map)("[End of CDS archive map]");
} }

View File

@ -265,8 +265,13 @@ void WriteClosure::do_oop(oop* o) {
_dump_region->append_intptr_t(0); _dump_region->append_intptr_t(0);
} else { } else {
assert(HeapShared::can_write(), "sanity"); assert(HeapShared::can_write(), "sanity");
_dump_region->append_intptr_t( intptr_t p;
UseCompressedOops ? (intptr_t)CompressedOops::encode_not_null(*o) : (intptr_t)((void*)(*o))); if (UseCompressedOops) {
p = (intptr_t)CompressedOops::encode_not_null(*o);
} else {
p = cast_from_oop<intptr_t>(HeapShared::to_requested_address(*o));
}
_dump_region->append_intptr_t(p);
} }
} }

View File

@ -251,8 +251,10 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_heap_begin = CompressedOops::begin(); _heap_begin = CompressedOops::begin();
_heap_end = CompressedOops::end(); _heap_end = CompressedOops::end();
} else { } else {
_heap_begin = (address)G1CollectedHeap::heap()->reserved().start(); address start = (address)G1CollectedHeap::heap()->reserved().start();
_heap_end = (address)G1CollectedHeap::heap()->reserved().end(); address end = (address)G1CollectedHeap::heap()->reserved().end();
_heap_begin = HeapShared::to_requested_address(start);
_heap_end = HeapShared::to_requested_address(end);
} }
} }
_compressed_oops = UseCompressedOops; _compressed_oops = UseCompressedOops;

View File

@ -179,8 +179,9 @@ void HeapShared::fixup_regions() {
} }
unsigned HeapShared::oop_hash(oop const& p) { unsigned HeapShared::oop_hash(oop const& p) {
unsigned hash = (unsigned)p->identity_hash(); // Do not call p->identity_hash() as that will update the
return hash; // object header.
return primitive_hash(cast_from_oop<intptr_t>(p));
} }
static void reset_states(oop obj, TRAPS) { static void reset_states(oop obj, TRAPS) {
@ -1577,9 +1578,12 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
: _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) {
assert(UseCompressedOops, "sanity");
_num_total_oops ++; _num_total_oops ++;
narrowOop v = *p; narrowOop v = *p;
if (!CompressedOops::is_null(v)) { if (!CompressedOops::is_null(v)) {
// Note: HeapShared::to_requested_address() is not necessary because
// the heap always starts at a deterministic address with UseCompressedOops==true.
size_t idx = p - (narrowOop*)_start; size_t idx = p - (narrowOop*)_start;
_oopmap->set_bit(idx); _oopmap->set_bit(idx);
} else { } else {
@ -1587,10 +1591,15 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
} }
} }
virtual void do_oop(oop* p) { virtual void do_oop(oop* p) {
assert(!UseCompressedOops, "sanity");
_num_total_oops ++; _num_total_oops ++;
if ((*p) != NULL) { if ((*p) != NULL) {
size_t idx = p - (oop*)_start; size_t idx = p - (oop*)_start;
_oopmap->set_bit(idx); _oopmap->set_bit(idx);
if (DumpSharedSpaces) {
// Make heap content deterministic.
*p = HeapShared::to_requested_address(*p);
}
} else { } else {
_num_null_oops ++; _num_null_oops ++;
} }
@ -1599,6 +1608,34 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
int num_null_oops() const { return _num_null_oops; } int num_null_oops() const { return _num_null_oops; }
}; };
address HeapShared::to_requested_address(address dumptime_addr) {
assert(DumpSharedSpaces, "static dump time only");
if (dumptime_addr == NULL || UseCompressedOops) {
return dumptime_addr;
}
// With UseCompressedOops==false, actual_base is selected by the OS so
// it's different across -Xshare:dump runs.
address actual_base = (address)G1CollectedHeap::heap()->reserved().start();
address actual_end = (address)G1CollectedHeap::heap()->reserved().end();
assert(actual_base <= dumptime_addr && dumptime_addr <= actual_end, "must be an address in the heap");
// We always write the objects as if the heap started at this address. This
// makes the heap content deterministic.
//
// Note that at runtime, the heap address is also selected by the OS, so
// the archive heap will not be mapped at 0x10000000. Instead, we will call
// HeapShared::patch_embedded_pointers() to relocate the heap contents
// accordingly.
const address REQUESTED_BASE = (address)0x10000000;
intx delta = REQUESTED_BASE - actual_base;
address requested_addr = dumptime_addr + delta;
assert(REQUESTED_BASE != 0 && requested_addr != NULL, "sanity");
return requested_addr;
}
ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) { ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)); size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
ResourceBitMap oopmap(num_bits); ResourceBitMap oopmap(num_bits);
@ -1619,7 +1656,7 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
++ num_objs; ++ num_objs;
} }
log_info(cds, heap)("calculate_oopmap: objects = %6d, embedded oops = %7d, nulls = %7d", log_info(cds, heap)("calculate_oopmap: objects = %6d, oop fields = %7d (nulls = %7d)",
num_objs, finder.num_total_oops(), finder.num_null_oops()); num_objs, finder.num_total_oops(), finder.num_null_oops());
return oopmap; return oopmap;
} }

View File

@ -36,6 +36,7 @@
#include "oops/objArrayKlass.hpp" #include "oops/objArrayKlass.hpp"
#include "oops/oop.hpp" #include "oops/oop.hpp"
#include "oops/oopHandle.hpp" #include "oops/oopHandle.hpp"
#include "oops/oopsHierarchy.hpp"
#include "oops/typeArrayKlass.hpp" #include "oops/typeArrayKlass.hpp"
#include "utilities/bitMap.hpp" #include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
@ -517,6 +518,13 @@ private:
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN; static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static bool initialize_enum_klass(InstanceKlass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false); static bool initialize_enum_klass(InstanceKlass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false);
// Returns the address of a heap object when it's mapped at the
// runtime requested address. See comments in archiveBuilder.hpp.
static address to_requested_address(address dumptime_addr) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static oop to_requested_address(oop dumptime_oop) {
return cast_to_oop(to_requested_address(cast_from_oop<address>(dumptime_oop)));
}
}; };
#if INCLUDE_CDS_JAVA_HEAP #if INCLUDE_CDS_JAVA_HEAP