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 "*.lib" ! -name "*.jmod" ! -name "*.exe" \
! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \
! -name "*.tar.gz" ! -name "classes_nocoops.jsa" ! -name "gtestLauncher" \
! -name "*.tar.gz" ! -name "gtestLauncher" \
! -name "*.map" \
| $GREP -v "./bin/" | $SORT | $FILTER)

View File

@ -1016,24 +1016,27 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
#undef _LOG_PREFIX
// 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
// 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;
base = runtime_base;
top = runtime_base + size;
base = requested_base;
top = requested_base + size;
log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " " SIZE_FORMAT_W(9) " bytes]",
name, p2i(base), p2i(top), size);
}
#if INCLUDE_CDS_JAVA_HEAP
// open and closed archive 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++) {
address start = address(regions->at(i).start());
address end = address(regions->at(i).end());
log_region(which, start, end, start);
log_region(which, start, end, to_requested(start));
while (start < end) {
size_t byte_size;
@ -1042,34 +1045,37 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
if (original_oop != NULL) {
ResourceMark rm;
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;
} else if (archived_oop == HeapShared::roots()) {
// HeapShared::roots() is copied specially so it doesn't exist in
// HeapShared::OriginalObjectTable. See HeapShared::copy_roots().
log_info(cds, map)(PTR_FORMAT ": @@ Object HeapShared:roots (ObjArray)",
p2i(start));
log_info(cds, map)(PTR_FORMAT ": @@ Object HeapShared::roots (ObjArray)",
p2i(to_requested(start)));
byte_size = objArrayOopDesc::object_size(HeapShared::roots()->length()) * BytesPerWord;
} else {
// We have reached the end of the region
break;
}
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;
}
if (start < end) {
log_info(cds, map)(PTR_FORMAT ": @@ Unused heap space " SIZE_FORMAT " bytes",
p2i(start), size_t(end - start));
log_data(start, end, start, /*is_heap=*/true);
p2i(to_requested(start)), size_t(end - start));
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
// will be mapped to runtime_base at run-time.
static void log_data(address base, address top, address runtime_base, bool is_heap = false) {
// will be mapped to requested_base at run-time.
static void log_data(address base, address top, address requested_base, bool is_heap = false) {
assert(top >= base, "must be");
LogStreamHandle(Trace, cds, map) lsh;
@ -1080,7 +1086,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
// longs and doubles will be split into two words.
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_data((address)bitmap, bitmap_end, 0);
#if INCLUDE_CDS_JAVA_HEAP
if (closed_heap_regions != NULL) {
log_heap_regions("closed heap region", closed_heap_regions);
}
if (open_heap_regions != NULL) {
log_heap_regions("open heap region", open_heap_regions);
}
#endif
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);
} else {
assert(HeapShared::can_write(), "sanity");
_dump_region->append_intptr_t(
UseCompressedOops ? (intptr_t)CompressedOops::encode_not_null(*o) : (intptr_t)((void*)(*o)));
intptr_t p;
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_end = CompressedOops::end();
} else {
_heap_begin = (address)G1CollectedHeap::heap()->reserved().start();
_heap_end = (address)G1CollectedHeap::heap()->reserved().end();
address start = (address)G1CollectedHeap::heap()->reserved().start();
address end = (address)G1CollectedHeap::heap()->reserved().end();
_heap_begin = HeapShared::to_requested_address(start);
_heap_end = HeapShared::to_requested_address(end);
}
}
_compressed_oops = UseCompressedOops;

View File

@ -179,8 +179,9 @@ void HeapShared::fixup_regions() {
}
unsigned HeapShared::oop_hash(oop const& p) {
unsigned hash = (unsigned)p->identity_hash();
return hash;
// Do not call p->identity_hash() as that will update the
// object header.
return primitive_hash(cast_from_oop<intptr_t>(p));
}
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) {}
virtual void do_oop(narrowOop* p) {
assert(UseCompressedOops, "sanity");
_num_total_oops ++;
narrowOop v = *p;
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;
_oopmap->set_bit(idx);
} else {
@ -1587,10 +1591,15 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
}
}
virtual void do_oop(oop* p) {
assert(!UseCompressedOops, "sanity");
_num_total_oops ++;
if ((*p) != NULL) {
size_t idx = p - (oop*)_start;
_oopmap->set_bit(idx);
if (DumpSharedSpaces) {
// Make heap content deterministic.
*p = HeapShared::to_requested_address(*p);
}
} else {
_num_null_oops ++;
}
@ -1599,6 +1608,34 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
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) {
size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
ResourceBitMap oopmap(num_bits);
@ -1619,7 +1656,7 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
++ 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());
return oopmap;
}

View File

@ -36,6 +36,7 @@
#include "oops/objArrayKlass.hpp"
#include "oops/oop.hpp"
#include "oops/oopHandle.hpp"
#include "oops/oopsHierarchy.hpp"
#include "oops/typeArrayKlass.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp"
@ -517,6 +518,13 @@ private:
static void write_subgraph_info_table() 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);
// 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