Skip to content

8311604: Simplify NOCOOPS requested addresses for archived heap objects #14792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/hotspot/share/cds/archiveBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {

#if INCLUDE_CDS_JAVA_HEAP
static void log_heap_region(ArchiveHeapInfo* heap_info) {
MemRegion r = heap_info->memregion();
MemRegion r = heap_info->buffer_region();
address start = address(r.start());
address end = address(r.end());
log_region("heap", start, end, to_requested(start));
Expand Down Expand Up @@ -1204,8 +1204,8 @@ void ArchiveBuilder::print_bitmap_region_stats(size_t size, size_t total_size) {
}

void ArchiveBuilder::print_heap_region_stats(ArchiveHeapInfo *info, size_t total_size) {
char* start = info->start();
size_t size = info->byte_size();
char* start = info->buffer_start();
size_t size = info->buffer_byte_size();
char* top = start + size;
log_debug(cds)("hp space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100.0%% used] at " INTPTR_FORMAT,
size, size/double(total_size)*100.0, size, p2i(start));
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/cds/archiveHeapLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,20 @@ intx ArchiveHeapLoader::_runtime_offset = 0;
bool ArchiveHeapLoader::_loading_failed = false;

// Support for mapped heap.
uintptr_t ArchiveHeapLoader::_mapped_heap_bottom = 0;
bool ArchiveHeapLoader::_mapped_heap_relocation_initialized = false;
ptrdiff_t ArchiveHeapLoader::_mapped_heap_delta = 0;

// Every mapped region is offset by _mapped_heap_delta from its requested address.
// See FileMapInfo::heap_region_requested_address().
void ArchiveHeapLoader::init_mapped_heap_relocation(ptrdiff_t delta, int dumptime_oop_shift) {
void ArchiveHeapLoader::init_mapped_heap_info(address mapped_heap_bottom, ptrdiff_t delta, int dumptime_oop_shift) {
assert(!_mapped_heap_relocation_initialized, "only once");
if (!UseCompressedOops) {
assert(dumptime_oop_shift == 0, "sanity");
}
assert(can_map(), "sanity");
init_narrow_oop_decoding(CompressedOops::base() + delta, dumptime_oop_shift);
_mapped_heap_bottom = (intptr_t)mapped_heap_bottom;
_mapped_heap_delta = delta;
_mapped_heap_relocation_initialized = true;
}
Expand Down Expand Up @@ -374,6 +376,9 @@ void ArchiveHeapLoader::finish_initialization() {
}
if (is_in_use()) {
patch_native_pointers();
intptr_t bottom = is_loaded() ? _loaded_heap_bottom : _mapped_heap_bottom;
intptr_t roots_oop = bottom + FileMapInfo::current_info()->heap_roots_offset();
HeapShared::init_roots(cast_to_oop(roots_oop));
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/cds/archiveHeapLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class ArchiveHeapLoader : AllStatic {
static void fixup_region() NOT_CDS_JAVA_HEAP_RETURN;

#if INCLUDE_CDS_JAVA_HEAP
static void init_mapped_heap_relocation(ptrdiff_t delta, int dumptime_oop_shift);
static void init_mapped_heap_info(address mapped_heap_bottom, ptrdiff_t delta, int dumptime_oop_shift);
private:
static bool _is_mapped;
static bool _is_loaded;
Expand All @@ -124,6 +124,7 @@ class ArchiveHeapLoader : AllStatic {

// is_mapped() only: the mapped address of each region is offset by this amount from
// their requested address.
static uintptr_t _mapped_heap_bottom;
static ptrdiff_t _mapped_heap_delta;
static bool _mapped_heap_relocation_initialized;

Expand Down
37 changes: 23 additions & 14 deletions src/hotspot/share/cds/archiveHeapWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@

#if INCLUDE_CDS_JAVA_HEAP

GrowableArrayCHeap<u1, mtClassShared>* ArchiveHeapWriter::_buffer;
GrowableArrayCHeap<u1, mtClassShared>* ArchiveHeapWriter::_buffer = nullptr;

// The following are offsets from buffer_bottom()
size_t ArchiveHeapWriter::_buffer_used;
size_t ArchiveHeapWriter::_heap_roots_bottom_offset;
size_t ArchiveHeapWriter::_heap_roots_offset;

size_t ArchiveHeapWriter::_heap_roots_word_size;

Expand Down Expand Up @@ -153,7 +153,7 @@ address ArchiveHeapWriter::buffered_addr_to_requested_addr(address buffered_addr
}

oop ArchiveHeapWriter::heap_roots_requested_address() {
return cast_to_oop(_requested_bottom + _heap_roots_bottom_offset);
return cast_to_oop(_requested_bottom + _heap_roots_offset);
}

address ArchiveHeapWriter::requested_address() {
Expand Down Expand Up @@ -213,7 +213,7 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShar
}
log_info(cds, heap)("archived obj roots[%d] = " SIZE_FORMAT " bytes, klass = %p, obj = %p", length, byte_size, k, mem);

_heap_roots_bottom_offset = _buffer_used;
_heap_roots_offset = _buffer_used;
_buffer_used = new_used;
}

Expand Down Expand Up @@ -339,13 +339,25 @@ void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) {
size_t heap_region_byte_size = _buffer_used;
assert(heap_region_byte_size > 0, "must archived at least one object!");

_requested_bottom = align_down(heap_end - heap_region_byte_size, HeapRegion::GrainBytes);

if (UseCompressedOops) {
_requested_bottom = align_down(heap_end - heap_region_byte_size, HeapRegion::GrainBytes);
} else {
// We always write the objects as if the heap started at this address. This
// makes the contents of the archive heap deterministic.
//
// Note that at runtime, the heap address is selected by the OS, so the archive
// heap will not be mapped at 0x10000000, and the contents need to be patched.
_requested_bottom = (address)NOCOOPS_REQUESTED_BASE;
}

assert(is_aligned(_requested_bottom, HeapRegion::GrainBytes), "sanity");

_requested_top = _requested_bottom + _buffer_used;

info->set_memregion(MemRegion(offset_to_buffered_address<HeapWord*>(0),
offset_to_buffered_address<HeapWord*>(_buffer_used)));
info->set_buffer_region(MemRegion(offset_to_buffered_address<HeapWord*>(0),
offset_to_buffered_address<HeapWord*>(_buffer_used)));
info->set_heap_roots_offset(_heap_roots_offset);
}

// Oop relocation
Expand All @@ -371,14 +383,11 @@ template <typename T> void ArchiveHeapWriter::store_requested_oop_in_buffer(T* b
store_oop_in_buffer(buffered_addr, request_oop);
}

void ArchiveHeapWriter::store_oop_in_buffer(oop* buffered_addr, oop requested_obj) {
// Make heap content deterministic. See comments inside HeapShared::to_requested_address.
*buffered_addr = HeapShared::to_requested_address(requested_obj);
inline void ArchiveHeapWriter::store_oop_in_buffer(oop* buffered_addr, oop requested_obj) {
*buffered_addr = requested_obj;
}

void ArchiveHeapWriter::store_oop_in_buffer(narrowOop* buffered_addr, oop requested_obj) {
// Note: HeapShared::to_requested_address() is not necessary because
// the heap always starts at a deterministic address with UseCompressedOops==true.
inline void ArchiveHeapWriter::store_oop_in_buffer(narrowOop* buffered_addr, oop requested_obj) {
narrowOop val = CompressedOops::encode_not_null(requested_obj);
*buffered_addr = val;
}
Expand Down Expand Up @@ -481,7 +490,7 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassSh

// Relocate HeapShared::roots(), which is created in copy_roots_to_buffer() and
// doesn't have a corresponding src_obj, so we can't use EmbeddedOopRelocator on it.
oop requested_roots = requested_obj_from_buffer_offset(_heap_roots_bottom_offset);
oop requested_roots = requested_obj_from_buffer_offset(_heap_roots_offset);
update_header_for_requested_obj(requested_roots, nullptr, Universe::objectArrayKlassObj());
int length = roots != nullptr ? roots->length() : 0;
for (int i = 0; i < length; i++) {
Expand Down
94 changes: 66 additions & 28 deletions src/hotspot/share/cds/archiveHeapWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,81 @@
class MemRegion;

class ArchiveHeapInfo {
MemRegion _memregion;
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
CHeapBitMap _oopmap;
CHeapBitMap _ptrmap;
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
// of the archived heap objects, in bytes.

public:
ArchiveHeapInfo() : _memregion(), _oopmap(128, mtClassShared), _ptrmap(128, mtClassShared) {}
bool is_used() { return !_memregion.is_empty(); }
ArchiveHeapInfo() : _buffer_region(), _oopmap(128, mtClassShared), _ptrmap(128, mtClassShared) {}
bool is_used() { return !_buffer_region.is_empty(); }

MemRegion memregion() { return _memregion; }
void set_memregion(MemRegion r) { _memregion = r; }
MemRegion buffer_region() { return _buffer_region; }
void set_buffer_region(MemRegion r) { _buffer_region = r; }

char* start() { return (char*)_memregion.start(); }
size_t byte_size() { return _memregion.byte_size(); }
char* buffer_start() { return (char*)_buffer_region.start(); }
size_t buffer_byte_size() { return _buffer_region.byte_size(); }

CHeapBitMap* oopmap() { return &_oopmap; }
CHeapBitMap* ptrmap() { return &_ptrmap; }

void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
size_t heap_roots_offset() const { return _heap_roots_offset; }
};

#if INCLUDE_CDS_JAVA_HEAP
class ArchiveHeapWriter : AllStatic {
// ArchiveHeapWriter manipulates three types of addresses:
//
// "source" vs "buffered" vs "requested"
//
// (Note: the design and convention is the same as for the archiving of Metaspace objects.
// See archiveBuilder.hpp.)
//
// - "source objects" are regular Java objects allocated during the execution
// of "java -Xshare:dump". They can be used as regular oops.
//
// HeapShared::archive_objects() recursively searches for the oops that need to be
// stored into the CDS archive. These are entered into HeapShared::archived_object_cache().
//
// - "buffered objects" are copies of the "source objects", and are stored in into
// ArchiveHeapWriter::_buffer, which is a GrowableArray that sits outside of
// the valid heap range. Therefore we avoid using the addresses of these copies
// as oops. They are usually called "buffered_addr" in the code (of the type "address").
//
// The buffered objects are stored contiguously, possibly with interleaving fillers
// to make sure no objects span across boundaries of MIN_GC_REGION_ALIGNMENT.
//
// - Each archived object has a "requested address" -- at run time, if the object
// can be mapped at this address, we can avoid relocation.
//
// The requested address is implemented differently depending on UseCompressedOops:
//
// UseCompressedOops == true:
// The archived objects are stored assuming that the runtime COOPS compression
// scheme is exactly the same as in dump time (or else a more expensive runtime relocation
// would be needed.)
//
// At dump time, we assume that the runtime heap range is exactly the same as
// in dump time. The requested addresses of the archived objects are chosen such that
// they would occupy the top end of a G1 heap (TBD when dumping is supported by other
// collectors. See JDK-8298614).
//
// UseCompressedOops == false:
// At runtime, the heap range is usually picked (randomly) by the OS, so we will almost always
// need to perform relocation. Hence, the goal of the "requested address" is to ensure that
// the contents of the archived objects are deterministic. I.e., the oop fields of archived
// objects will always point to deterministic addresses.
//
// For G1, the archived heap is written such that the lowest archived object is placed
// at NOCOOPS_REQUESTED_BASE. (TBD after JDK-8298614).
// ----------------------------------------------------------------------

public:
static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000;

private:
class EmbeddedOopRelocator;
struct NativePointerInfo {
oop _src_obj;
Expand All @@ -70,30 +125,13 @@ class ArchiveHeapWriter : AllStatic {
// (TODO: Perhaps change to 256K to be compatible with Shenandoah)
static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M;

// "source" vs "buffered" vs "requested"
//
// [1] HeapShared::archive_objects() identifies all of the oops that need to be stored
// into the CDS archive. These are entered into HeapShared::archived_object_cache().
// These are called "source objects"
//
// [2] ArchiveHeapWriter::write() copies all source objects into ArchiveHeapWriter::_buffer,
// which is a GrowableArray that sites outside of the valid heap range. Therefore
// we avoid using the addresses of these copies as oops. They are usually
// called "buffered_addr" in the code (of the type "address").
//
// [3] Each archived object has a "requested address" -- at run time, if the object
// can be mapped at this address, we can avoid relocation.
//
// Note: the design and convention is the same as for the archiving of Metaspace objects.
// See archiveBuilder.hpp.

static GrowableArrayCHeap<u1, mtClassShared>* _buffer;

// The number of bytes that have written into _buffer (may be smaller than _buffer->length()).
static size_t _buffer_used;

// The bottom of the copy of Heap::roots() inside this->_buffer.
static size_t _heap_roots_bottom_offset;
static size_t _heap_roots_offset;
static size_t _heap_roots_word_size;

// The address range of the requested location of the archived heap objects.
Expand Down Expand Up @@ -160,8 +198,8 @@ class ArchiveHeapWriter : AllStatic {

static oop load_oop_from_buffer(oop* buffered_addr);
static oop load_oop_from_buffer(narrowOop* buffered_addr);
static void store_oop_in_buffer(oop* buffered_addr, oop requested_obj);
static void store_oop_in_buffer(narrowOop* buffered_addr, oop requested_obj);
inline static void store_oop_in_buffer(oop* buffered_addr, oop requested_obj);
inline static void store_oop_in_buffer(narrowOop* buffered_addr, oop requested_obj);

template <typename T> static oop load_source_oop_from_buffer(T* buffered_addr);
template <typename T> static void store_requested_oop_in_buffer(T* buffered_addr, oop request_oop);
Expand All @@ -182,7 +220,7 @@ class ArchiveHeapWriter : AllStatic {
static address requested_address(); // requested address of the lowest achived heap object
static oop heap_roots_requested_address(); // requested address of HeapShared::roots()
static address buffered_heap_roots_addr() {
return offset_to_buffered_address<address>(_heap_roots_bottom_offset);
return offset_to_buffered_address<address>(_heap_roots_offset);
}
static size_t heap_roots_word_size() {
return _heap_roots_word_size;
Expand Down
37 changes: 0 additions & 37 deletions src/hotspot/share/cds/archiveUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,21 +277,6 @@ void WriteClosure::do_ptr(void** p) {
_dump_region->append_intptr_t((intptr_t)ptr, true);
}

void WriteClosure::do_oop(oop* o) {
if (*o == nullptr) {
_dump_region->append_intptr_t(0);
} else {
assert(HeapShared::can_write(), "sanity");
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);
}
}

void WriteClosure::do_region(u_char* start, size_t size) {
assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
assert(size % sizeof(intptr_t) == 0, "bad size");
Expand Down Expand Up @@ -334,28 +319,6 @@ void ReadClosure::do_tag(int tag) {
FileMapInfo::assert_mark(tag == old_tag);
}

void ReadClosure::do_oop(oop *p) {
if (UseCompressedOops) {
narrowOop o = CompressedOops::narrow_oop_cast(nextPtr());
if (CompressedOops::is_null(o) || !ArchiveHeapLoader::is_in_use()) {
*p = nullptr;
} else {
assert(ArchiveHeapLoader::can_use(), "sanity");
assert(ArchiveHeapLoader::is_in_use(), "must be");
*p = ArchiveHeapLoader::decode_from_archive(o);
}
} else {
intptr_t dumptime_oop = nextPtr();
if (dumptime_oop == 0 || !ArchiveHeapLoader::is_in_use()) {
*p = nullptr;
} else {
assert(!ArchiveHeapLoader::is_loaded(), "ArchiveHeapLoader::can_load() is not supported for uncompessed oops");
intptr_t runtime_oop = dumptime_oop + ArchiveHeapLoader::mapped_heap_delta();
*p = cast_to_oop(runtime_oop);
}
}
}

void ReadClosure::do_region(u_char* start, size_t size) {
assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
assert(size % sizeof(intptr_t) == 0, "bad size");
Expand Down
4 changes: 1 addition & 3 deletions src/hotspot/share/cds/archiveUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
#ifndef SHARE_CDS_ARCHIVEUTILS_HPP
#define SHARE_CDS_ARCHIVEUTILS_HPP

#include "cds/serializeClosure.hpp"
#include "logging/log.hpp"
#include "memory/iterator.hpp"
#include "memory/virtualspace.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/exceptions.hpp"
Expand Down Expand Up @@ -202,7 +202,6 @@ class WriteClosure : public SerializeClosure {
_dump_region->append_intptr_t((intptr_t)tag);
}

void do_oop(oop* o);
void do_region(u_char* start, size_t size);
bool reading() const { return false; }
};
Expand All @@ -226,7 +225,6 @@ class ReadClosure : public SerializeClosure {
void do_int(int* p);
void do_bool(bool *p);
void do_tag(int tag);
void do_oop(oop *p);
void do_region(u_char* start, size_t size);
bool reading() const { return true; }
};
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/cds/cdsHeapVerifier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
*
*/

#ifndef SHARED_CDS_CDSHEAPVERIFIER_HPP
#define SHARED_CDS_CDSHEAPVERIFIER_HPP
#ifndef SHARE_CDS_CDSHEAPVERIFIER_HPP
#define SHARE_CDS_CDSHEAPVERIFIER_HPP

#include "cds/heapShared.hpp"
#include "memory/iterator.hpp"
Expand Down Expand Up @@ -88,4 +88,4 @@ class CDSHeapVerifier : public KlassClosure {
};

#endif // INCLUDE_CDS_JAVA_HEAP
#endif // SHARED_CDS_CDSHEAPVERIFIER_HPP
#endif // SHARE_CDS_CDSHEAPVERIFIER_HPP
Loading