8338912: CDS: Segmented roots array
Reviewed-by: ccheung, iklam
This commit is contained in:
parent
74add0e2e0
commit
dc00eb87bc
@ -1104,6 +1104,17 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
|
||||
LogStreamHandle(Info, cds, map) st;
|
||||
|
||||
HeapRootSegments segments = heap_info->heap_root_segments();
|
||||
assert(segments.base_offset() == 0, "Sanity");
|
||||
|
||||
for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
|
||||
address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start);
|
||||
st.print_cr(PTR_FORMAT ": Heap roots segment [%d]",
|
||||
p2i(requested_start), segments.size_in_elems(seg_idx));
|
||||
start += segments.size_in_bytes(seg_idx);
|
||||
}
|
||||
log_heap_roots();
|
||||
|
||||
while (start < end) {
|
||||
size_t byte_size;
|
||||
oop source_oop = ArchiveHeapWriter::buffered_addr_to_source_obj(start);
|
||||
@ -1114,12 +1125,6 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
// This is a regular oop that got archived.
|
||||
print_oop_with_requested_addr_cr(&st, source_oop, false);
|
||||
byte_size = source_oop->size() * BytesPerWord;
|
||||
} else if (start == ArchiveHeapWriter::buffered_heap_roots_addr()) {
|
||||
// HeapShared::roots() is copied specially, so it doesn't exist in
|
||||
// ArchiveHeapWriter::BufferOffsetToSourceObjectTable.
|
||||
// See ArchiveHeapWriter::copy_roots_to_buffer().
|
||||
st.print_cr("HeapShared::roots[%d]", HeapShared::pending_roots()->length());
|
||||
byte_size = ArchiveHeapWriter::heap_roots_word_size() * BytesPerWord;
|
||||
} else if ((byte_size = ArchiveHeapWriter::get_filler_size_at(start)) > 0) {
|
||||
// We have a filler oop, which also does not exist in BufferOffsetToSourceObjectTable.
|
||||
st.print_cr("filler " SIZE_FORMAT " bytes", byte_size);
|
||||
@ -1132,8 +1137,6 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
|
||||
if (source_oop != nullptr) {
|
||||
log_oop_details(heap_info, source_oop, /*buffered_addr=*/start);
|
||||
} else if (start == ArchiveHeapWriter::buffered_heap_roots_addr()) {
|
||||
log_heap_roots();
|
||||
}
|
||||
start = oop_end;
|
||||
}
|
||||
|
@ -374,8 +374,18 @@ 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));
|
||||
|
||||
// The heap roots are stored in one or more segments that are laid out consecutively.
|
||||
// The byte size of each segment (except for the last one) is max_size.
|
||||
HeapRootSegments segments = FileMapInfo::current_info()->heap_root_segments();
|
||||
int max_size = segments.max_size_in_bytes();
|
||||
HeapShared::init_root_segment_sizes(max_size);
|
||||
intptr_t first_segment_addr = bottom + segments.base_offset();
|
||||
for (size_t c = 0; c < segments.count(); c++) {
|
||||
oop segment_oop = cast_to_oop(first_segment_addr + (c * max_size));
|
||||
assert(segment_oop->is_objArray(), "Must be");
|
||||
HeapShared::add_root_segment((objArrayOop)segment_oop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,9 @@ GrowableArrayCHeap<u1, mtClassShared>* ArchiveHeapWriter::_buffer = nullptr;
|
||||
|
||||
// The following are offsets from buffer_bottom()
|
||||
size_t ArchiveHeapWriter::_buffer_used;
|
||||
size_t ArchiveHeapWriter::_heap_roots_offset;
|
||||
|
||||
size_t ArchiveHeapWriter::_heap_roots_word_size;
|
||||
// Heap root segments
|
||||
HeapRootSegments ArchiveHeapWriter::_heap_root_segments;
|
||||
|
||||
address ArchiveHeapWriter::_requested_bottom;
|
||||
address ArchiveHeapWriter::_requested_top;
|
||||
@ -164,10 +164,6 @@ address ArchiveHeapWriter::buffered_addr_to_requested_addr(address buffered_addr
|
||||
return _requested_bottom + buffered_address_to_offset(buffered_addr);
|
||||
}
|
||||
|
||||
oop ArchiveHeapWriter::heap_roots_requested_address() {
|
||||
return cast_to_oop(_requested_bottom + _heap_roots_offset);
|
||||
}
|
||||
|
||||
address ArchiveHeapWriter::requested_address() {
|
||||
assert(_buffer != nullptr, "must be initialized");
|
||||
return _requested_bottom;
|
||||
@ -186,47 +182,71 @@ void ArchiveHeapWriter::ensure_buffer_space(size_t min_bytes) {
|
||||
_buffer->at_grow(to_array_index(min_bytes));
|
||||
}
|
||||
|
||||
objArrayOop ArchiveHeapWriter::allocate_root_segment(size_t offset, int element_count) {
|
||||
HeapWord* mem = offset_to_buffered_address<HeapWord *>(offset);
|
||||
memset(mem, 0, objArrayOopDesc::object_size(element_count));
|
||||
|
||||
// The initialization code is copied from MemAllocator::finish and ObjArrayAllocator::initialize.
|
||||
oopDesc::set_mark(mem, markWord::prototype());
|
||||
oopDesc::release_set_klass(mem, Universe::objectArrayKlass());
|
||||
arrayOopDesc::set_length(mem, element_count);
|
||||
return objArrayOop(cast_to_oop(mem));
|
||||
}
|
||||
|
||||
void ArchiveHeapWriter::root_segment_at_put(objArrayOop segment, int index, oop root) {
|
||||
// Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside the real heap!
|
||||
if (UseCompressedOops) {
|
||||
*segment->obj_at_addr<narrowOop>(index) = CompressedOops::encode(root);
|
||||
} else {
|
||||
*segment->obj_at_addr<oop>(index) = root;
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
|
||||
Klass* k = Universe::objectArrayKlass(); // already relocated to point to archived klass
|
||||
int length = roots->length();
|
||||
_heap_roots_word_size = objArrayOopDesc::object_size(length);
|
||||
size_t byte_size = _heap_roots_word_size * HeapWordSize;
|
||||
if (byte_size >= MIN_GC_REGION_ALIGNMENT) {
|
||||
log_error(cds, heap)("roots array is too large. Please reduce the number of classes");
|
||||
vm_exit(1);
|
||||
}
|
||||
// Depending on the number of classes we are archiving, a single roots array may be
|
||||
// larger than MIN_GC_REGION_ALIGNMENT. Roots are allocated first in the buffer, which
|
||||
// allows us to chop the large array into a series of "segments". Current layout
|
||||
// starts with zero or more segments exactly fitting MIN_GC_REGION_ALIGNMENT, and end
|
||||
// with a single segment that may be smaller than MIN_GC_REGION_ALIGNMENT.
|
||||
// This is simple and efficient. We do not need filler objects anywhere between the segments,
|
||||
// or immediately after the last segment. This allows starting the object dump immediately
|
||||
// after the roots.
|
||||
|
||||
maybe_fill_gc_region_gap(byte_size);
|
||||
assert((_buffer_used % MIN_GC_REGION_ALIGNMENT) == 0,
|
||||
"Pre-condition: Roots start at aligned boundary: " SIZE_FORMAT, _buffer_used);
|
||||
|
||||
size_t new_used = _buffer_used + byte_size;
|
||||
ensure_buffer_space(new_used);
|
||||
int max_elem_count = ((MIN_GC_REGION_ALIGNMENT - arrayOopDesc::header_size_in_bytes()) / heapOopSize);
|
||||
assert(objArrayOopDesc::object_size(max_elem_count)*HeapWordSize == MIN_GC_REGION_ALIGNMENT,
|
||||
"Should match exactly");
|
||||
|
||||
HeapWord* mem = offset_to_buffered_address<HeapWord*>(_buffer_used);
|
||||
memset(mem, 0, byte_size);
|
||||
{
|
||||
// This is copied from MemAllocator::finish
|
||||
oopDesc::set_mark(mem, markWord::prototype());
|
||||
oopDesc::release_set_klass(mem, k);
|
||||
}
|
||||
{
|
||||
// This is copied from ObjArrayAllocator::initialize
|
||||
arrayOopDesc::set_length(mem, length);
|
||||
}
|
||||
HeapRootSegments segments(_buffer_used,
|
||||
roots->length(),
|
||||
MIN_GC_REGION_ALIGNMENT,
|
||||
max_elem_count);
|
||||
|
||||
objArrayOop arrayOop = objArrayOop(cast_to_oop(mem));
|
||||
for (int i = 0; i < length; i++) {
|
||||
// Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside of the real heap!
|
||||
oop o = roots->at(i);
|
||||
if (UseCompressedOops) {
|
||||
* arrayOop->obj_at_addr<narrowOop>(i) = CompressedOops::encode(o);
|
||||
} else {
|
||||
* arrayOop->obj_at_addr<oop>(i) = o;
|
||||
for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
|
||||
int size_elems = segments.size_in_elems(seg_idx);
|
||||
size_t size_bytes = segments.size_in_bytes(seg_idx);
|
||||
|
||||
size_t oop_offset = _buffer_used;
|
||||
_buffer_used = oop_offset + size_bytes;
|
||||
ensure_buffer_space(_buffer_used);
|
||||
|
||||
assert((oop_offset % MIN_GC_REGION_ALIGNMENT) == 0,
|
||||
"Roots segment " SIZE_FORMAT " start is not aligned: " SIZE_FORMAT,
|
||||
segments.count(), oop_offset);
|
||||
|
||||
int root_index = 0;
|
||||
objArrayOop seg_oop = allocate_root_segment(oop_offset, size_elems);
|
||||
for (int i = 0; i < size_elems; i++) {
|
||||
root_segment_at_put(seg_oop, i, roots->at(root_index++));
|
||||
}
|
||||
}
|
||||
log_info(cds, heap)("archived obj roots[%d] = " SIZE_FORMAT " bytes, klass = %p, obj = %p", length, byte_size, k, mem);
|
||||
|
||||
_heap_roots_offset = _buffer_used;
|
||||
_buffer_used = new_used;
|
||||
log_info(cds, heap)("archived obj root segment [%d] = " SIZE_FORMAT " bytes, obj = " PTR_FORMAT,
|
||||
size_elems, size_bytes, p2i(seg_oop));
|
||||
}
|
||||
|
||||
_heap_root_segments = segments;
|
||||
}
|
||||
|
||||
static int oop_sorting_rank(oop o) {
|
||||
@ -282,6 +302,10 @@ void ArchiveHeapWriter::sort_source_objs() {
|
||||
}
|
||||
|
||||
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
|
||||
// There could be multiple root segments, which we want to be aligned by region.
|
||||
// Putting them ahead of objects makes sure we waste no space.
|
||||
copy_roots_to_buffer(roots);
|
||||
|
||||
sort_source_objs();
|
||||
for (int i = 0; i < _source_objs_order->length(); i++) {
|
||||
int src_obj_index = _source_objs_order->at(i)._index;
|
||||
@ -295,8 +319,6 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtCla
|
||||
_buffer_offset_to_source_obj_table->maybe_grow();
|
||||
}
|
||||
|
||||
copy_roots_to_buffer(roots);
|
||||
|
||||
log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d roots, %d native ptrs",
|
||||
_buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
|
||||
}
|
||||
@ -455,7 +477,7 @@ void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) {
|
||||
|
||||
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);
|
||||
info->set_heap_root_segments(_heap_root_segments);
|
||||
}
|
||||
|
||||
// Oop relocation
|
||||
@ -543,12 +565,6 @@ void ArchiveHeapWriter::update_header_for_requested_obj(oop requested_obj, oop s
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate an element in the buffered copy of HeapShared::roots()
|
||||
template <typename T> void ArchiveHeapWriter::relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap) {
|
||||
size_t offset = (size_t)((objArrayOop)requested_roots)->obj_at_offset<T>(index);
|
||||
relocate_field_in_buffer<T>((T*)(buffered_heap_roots_addr() + offset), oopmap);
|
||||
}
|
||||
|
||||
class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
|
||||
oop _src_obj;
|
||||
address _buffered_obj;
|
||||
@ -600,14 +616,24 @@ 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_offset);
|
||||
update_header_for_requested_obj(requested_roots, nullptr, Universe::objectArrayKlass());
|
||||
int length = roots != nullptr ? roots->length() : 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (size_t seg_idx = 0; seg_idx < _heap_root_segments.count(); seg_idx++) {
|
||||
size_t seg_offset = _heap_root_segments.segment_offset(seg_idx);
|
||||
|
||||
objArrayOop requested_obj = (objArrayOop)requested_obj_from_buffer_offset(seg_offset);
|
||||
update_header_for_requested_obj(requested_obj, nullptr, Universe::objectArrayKlass());
|
||||
address buffered_obj = offset_to_buffered_address<address>(seg_offset);
|
||||
int length = _heap_root_segments.size_in_elems(seg_idx);
|
||||
|
||||
if (UseCompressedOops) {
|
||||
relocate_root_at<narrowOop>(requested_roots, i, heap_info->oopmap());
|
||||
for (int i = 0; i < length; i++) {
|
||||
narrowOop* addr = (narrowOop*)(buffered_obj + objArrayOopDesc::obj_at_offset<narrowOop>(i));
|
||||
relocate_field_in_buffer<narrowOop>(addr, heap_info->oopmap());
|
||||
}
|
||||
} else {
|
||||
relocate_root_at<oop>(requested_roots, i, heap_info->oopmap());
|
||||
for (int i = 0; i < length; i++) {
|
||||
oop* addr = (oop*)(buffered_obj + objArrayOopDesc::obj_at_offset<oop>(i));
|
||||
relocate_field_in_buffer<oop>(addr, heap_info->oopmap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@ class ArchiveHeapInfo {
|
||||
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.
|
||||
HeapRootSegments _heap_root_segments;
|
||||
|
||||
public:
|
||||
ArchiveHeapInfo() : _buffer_region(), _oopmap(128, mtClassShared), _ptrmap(128, mtClassShared) {}
|
||||
@ -57,8 +56,8 @@ public:
|
||||
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; }
|
||||
void set_heap_root_segments(HeapRootSegments segments) { _heap_root_segments = segments; };
|
||||
HeapRootSegments heap_root_segments() { return _heap_root_segments; }
|
||||
};
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
@ -130,9 +129,8 @@ private:
|
||||
// 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_offset;
|
||||
static size_t _heap_roots_word_size;
|
||||
// The heap root segments information.
|
||||
static HeapRootSegments _heap_root_segments;
|
||||
|
||||
// The address range of the requested location of the archived heap objects.
|
||||
static address _requested_bottom;
|
||||
@ -193,6 +191,8 @@ private:
|
||||
return buffered_addr - buffer_bottom();
|
||||
}
|
||||
|
||||
static void root_segment_at_put(objArrayOop segment, int index, oop root);
|
||||
static objArrayOop allocate_root_segment(size_t offset, int element_count);
|
||||
static void copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots);
|
||||
static void copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots);
|
||||
static size_t copy_one_source_obj_to_buffer(oop src_obj);
|
||||
@ -219,7 +219,6 @@ private:
|
||||
template <typename T> static T* requested_addr_to_buffered_addr(T* p);
|
||||
template <typename T> static void relocate_field_in_buffer(T* field_addr_in_buffer, CHeapBitMap* oopmap);
|
||||
template <typename T> static void mark_oop_pointer(T* buffered_addr, CHeapBitMap* oopmap);
|
||||
template <typename T> static void relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap);
|
||||
|
||||
static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass);
|
||||
|
||||
@ -234,13 +233,6 @@ public:
|
||||
static bool is_string_too_large_to_archive(oop string);
|
||||
static void write(GrowableArrayCHeap<oop, mtClassShared>*, ArchiveHeapInfo* heap_info);
|
||||
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_offset);
|
||||
}
|
||||
static size_t heap_roots_word_size() {
|
||||
return _heap_roots_word_size;
|
||||
}
|
||||
static size_t get_filler_size_at(address buffered_addr);
|
||||
|
||||
static void mark_native_pointer(oop src_obj, int offset);
|
||||
|
@ -369,3 +369,24 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t HeapRootSegments::size_in_bytes(size_t seg_idx) {
|
||||
assert(seg_idx < _count, "In range");
|
||||
return objArrayOopDesc::object_size(size_in_elems(seg_idx)) * HeapWordSize;
|
||||
}
|
||||
|
||||
int HeapRootSegments::size_in_elems(size_t seg_idx) {
|
||||
assert(seg_idx < _count, "In range");
|
||||
if (seg_idx != _count - 1) {
|
||||
return _max_size_in_elems;
|
||||
} else {
|
||||
// Last slice, leftover
|
||||
return _roots_count % _max_size_in_elems;
|
||||
}
|
||||
}
|
||||
|
||||
size_t HeapRootSegments::segment_offset(size_t seg_idx) {
|
||||
assert(seg_idx < _count, "In range");
|
||||
return _base_offset + seg_idx * _max_size_in_bytes;
|
||||
}
|
||||
|
||||
|
@ -250,4 +250,45 @@ public:
|
||||
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
|
||||
};
|
||||
|
||||
class HeapRootSegments {
|
||||
private:
|
||||
size_t _base_offset;
|
||||
size_t _count;
|
||||
int _roots_count;
|
||||
int _max_size_in_bytes;
|
||||
int _max_size_in_elems;
|
||||
|
||||
public:
|
||||
size_t base_offset() { return _base_offset; }
|
||||
size_t count() { return _count; }
|
||||
int roots_count() { return _roots_count; }
|
||||
int max_size_in_bytes() { return _max_size_in_bytes; }
|
||||
int max_size_in_elems() { return _max_size_in_elems; }
|
||||
|
||||
size_t size_in_bytes(size_t seg_idx);
|
||||
int size_in_elems(size_t seg_idx);
|
||||
size_t segment_offset(size_t seg_idx);
|
||||
|
||||
// Trivial copy assignments are allowed to copy the entire object representation.
|
||||
// We also inline this class into archive header. Therefore, it is important to make
|
||||
// sure any gaps in object representation are initialized to zeroes. This is why
|
||||
// constructors memset before doing field assignments.
|
||||
HeapRootSegments() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
HeapRootSegments(size_t base_offset, int roots_count, int max_size_in_bytes, int max_size_in_elems) {
|
||||
assert(is_power_of_2(max_size_in_bytes), "must be");
|
||||
memset(this, 0, sizeof(*this));
|
||||
_base_offset = base_offset;
|
||||
_count = (roots_count + max_size_in_elems - 1) / max_size_in_elems;
|
||||
_roots_count = roots_count;
|
||||
_max_size_in_bytes = max_size_in_bytes;
|
||||
_max_size_in_elems = max_size_in_elems;
|
||||
}
|
||||
|
||||
// This class is trivially copyable and assignable.
|
||||
HeapRootSegments(const HeapRootSegments&) = default;
|
||||
HeapRootSegments& operator=(const HeapRootSegments&) = default;
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_ARCHIVEUTILS_HPP
|
||||
|
@ -289,7 +289,11 @@ void FileMapHeader::print(outputStream* st) {
|
||||
st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath);
|
||||
st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
|
||||
st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
|
||||
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
|
||||
st->print_cr("- heap_root_segments.roots_count: %d" , _heap_root_segments.roots_count());
|
||||
st->print_cr("- heap_root_segments.base_offset: " SIZE_FORMAT_X, _heap_root_segments.base_offset());
|
||||
st->print_cr("- heap_root_segments.count: " SIZE_FORMAT, _heap_root_segments.count());
|
||||
st->print_cr("- heap_root_segments.max_size_elems: %d", _heap_root_segments.max_size_in_elems());
|
||||
st->print_cr("- heap_root_segments.max_size_bytes: %d", _heap_root_segments.max_size_in_bytes());
|
||||
st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
|
||||
st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_ptrmap_start_pos);
|
||||
st->print_cr("- _rw_ptrmap_start_pos: " SIZE_FORMAT, _rw_ptrmap_start_pos);
|
||||
@ -1647,7 +1651,7 @@ size_t FileMapInfo::write_heap_region(ArchiveHeapInfo* heap_info) {
|
||||
char* buffer_start = heap_info->buffer_start();
|
||||
size_t buffer_size = heap_info->buffer_byte_size();
|
||||
write_region(MetaspaceShared::hp, buffer_start, buffer_size, false, false);
|
||||
header()->set_heap_roots_offset(heap_info->heap_roots_offset());
|
||||
header()->set_heap_root_segments(heap_info->heap_root_segments());
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_CDS_FILEMAP_HPP
|
||||
#define SHARE_CDS_FILEMAP_HPP
|
||||
|
||||
#include "cds/archiveUtils.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "include/cds.h"
|
||||
#include "logging/logLevel.hpp"
|
||||
@ -225,8 +226,7 @@ private:
|
||||
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
|
||||
// some expensive operations.
|
||||
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
|
||||
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
|
||||
// of the archived heap objects, in bytes.
|
||||
HeapRootSegments _heap_root_segments; // Heap root segments info
|
||||
size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
|
||||
size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
|
||||
size_t _rw_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the rw region
|
||||
@ -270,7 +270,7 @@ public:
|
||||
bool has_non_jar_in_classpath() const { return _has_non_jar_in_classpath; }
|
||||
bool compressed_oops() const { return _compressed_oops; }
|
||||
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
|
||||
size_t heap_roots_offset() const { return _heap_roots_offset; }
|
||||
HeapRootSegments heap_root_segments() const { return _heap_root_segments; }
|
||||
size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos; }
|
||||
size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; }
|
||||
size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; }
|
||||
@ -285,7 +285,7 @@ public:
|
||||
void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); }
|
||||
void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); }
|
||||
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
|
||||
void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
|
||||
void set_heap_root_segments(HeapRootSegments segments) { _heap_root_segments = segments; }
|
||||
void set_heap_oopmap_start_pos(size_t n) { _heap_oopmap_start_pos = n; }
|
||||
void set_heap_ptrmap_start_pos(size_t n) { _heap_ptrmap_start_pos = n; }
|
||||
void set_rw_ptrmap_start_pos(size_t n) { _rw_ptrmap_start_pos = n; }
|
||||
@ -385,7 +385,7 @@ public:
|
||||
address narrow_oop_base() const { return header()->narrow_oop_base(); }
|
||||
int narrow_oop_shift() const { return header()->narrow_oop_shift(); }
|
||||
uintx max_heap_size() const { return header()->max_heap_size(); }
|
||||
size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
|
||||
HeapRootSegments heap_root_segments() const { return header()->heap_root_segments(); }
|
||||
size_t core_region_alignment() const { return header()->core_region_alignment(); }
|
||||
size_t heap_oopmap_start_pos() const { return header()->heap_oopmap_start_pos(); }
|
||||
size_t heap_ptrmap_start_pos() const { return header()->heap_ptrmap_start_pos(); }
|
||||
|
@ -133,7 +133,9 @@ static ArchivableStaticFieldInfo fmg_archive_subgraph_entry_fields[] = {
|
||||
|
||||
KlassSubGraphInfo* HeapShared::_default_subgraph_info;
|
||||
GrowableArrayCHeap<oop, mtClassShared>* HeapShared::_pending_roots = nullptr;
|
||||
OopHandle HeapShared::_roots;
|
||||
GrowableArrayCHeap<OopHandle, mtClassShared>* HeapShared::_root_segments;
|
||||
int HeapShared::_root_segment_max_size_shift;
|
||||
int HeapShared::_root_segment_max_size_mask;
|
||||
OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1];
|
||||
MetaspaceObjToOopHandleTable* HeapShared::_scratch_java_mirror_table = nullptr;
|
||||
MetaspaceObjToOopHandleTable* HeapShared::_scratch_references_table = nullptr;
|
||||
@ -225,7 +227,7 @@ int HeapShared::append_root(oop obj) {
|
||||
return _pending_roots->append(obj);
|
||||
}
|
||||
|
||||
objArrayOop HeapShared::roots() {
|
||||
objArrayOop HeapShared::root_segment(int segment_idx) {
|
||||
if (CDSConfig::is_dumping_heap()) {
|
||||
assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
|
||||
if (!HeapShared::can_write()) {
|
||||
@ -235,17 +237,21 @@ objArrayOop HeapShared::roots() {
|
||||
assert(CDSConfig::is_using_archive(), "must be");
|
||||
}
|
||||
|
||||
objArrayOop roots = (objArrayOop)_roots.resolve();
|
||||
assert(roots != nullptr, "should have been initialized");
|
||||
return roots;
|
||||
objArrayOop segment = (objArrayOop)_root_segments->at(segment_idx).resolve();
|
||||
assert(segment != nullptr, "should have been initialized");
|
||||
return segment;
|
||||
}
|
||||
|
||||
// Returns an objArray that contains all the roots of the archived objects
|
||||
oop HeapShared::get_root(int index, bool clear) {
|
||||
assert(_root_segment_max_size_shift > 0, "sanity");
|
||||
assert(_root_segment_max_size_mask > 0, "sanity");
|
||||
assert(index >= 0, "sanity");
|
||||
assert(!CDSConfig::is_dumping_heap() && CDSConfig::is_using_archive(), "runtime only");
|
||||
assert(!_roots.is_empty(), "must have loaded shared heap");
|
||||
oop result = roots()->obj_at(index);
|
||||
assert(!_root_segments->is_empty(), "must have loaded shared heap");
|
||||
int seg_idx = index >> _root_segment_max_size_shift;
|
||||
int int_idx = index & _root_segment_max_size_mask;
|
||||
oop result = root_segment(seg_idx)->obj_at(int_idx);
|
||||
if (clear) {
|
||||
clear_root(index);
|
||||
}
|
||||
@ -256,11 +262,15 @@ void HeapShared::clear_root(int index) {
|
||||
assert(index >= 0, "sanity");
|
||||
assert(CDSConfig::is_using_archive(), "must be");
|
||||
if (ArchiveHeapLoader::is_in_use()) {
|
||||
assert(_root_segment_max_size_shift > 0, "sanity");
|
||||
assert(_root_segment_max_size_mask > 0, "sanity");
|
||||
int seg_idx = index >> _root_segment_max_size_shift;
|
||||
int int_idx = index & _root_segment_max_size_mask;
|
||||
if (log_is_enabled(Debug, cds, heap)) {
|
||||
oop old = roots()->obj_at(index);
|
||||
oop old = root_segment(seg_idx)->obj_at(int_idx);
|
||||
log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old));
|
||||
}
|
||||
roots()->obj_at_put(index, nullptr);
|
||||
root_segment(seg_idx)->obj_at_put(int_idx, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,11 +774,19 @@ void HeapShared::write_subgraph_info_table() {
|
||||
}
|
||||
}
|
||||
|
||||
void HeapShared::init_roots(oop roots_oop) {
|
||||
if (roots_oop != nullptr) {
|
||||
assert(ArchiveHeapLoader::is_in_use(), "must be");
|
||||
_roots = OopHandle(Universe::vm_global(), roots_oop);
|
||||
void HeapShared::add_root_segment(objArrayOop segment_oop) {
|
||||
assert(segment_oop != nullptr, "must be");
|
||||
assert(ArchiveHeapLoader::is_in_use(), "must be");
|
||||
if (_root_segments == nullptr) {
|
||||
_root_segments = new GrowableArrayCHeap<OopHandle, mtClassShared>(10);
|
||||
}
|
||||
_root_segments->push(OopHandle(Universe::vm_global(), segment_oop));
|
||||
}
|
||||
|
||||
void HeapShared::init_root_segment_sizes(int max_size) {
|
||||
assert(is_power_of_2(max_size), "must be");
|
||||
_root_segment_max_size_shift = log2i_exact(max_size);
|
||||
_root_segment_max_size_mask = max_size - 1;
|
||||
}
|
||||
|
||||
void HeapShared::serialize_tables(SerializeClosure* soc) {
|
||||
|
@ -290,7 +290,9 @@ private:
|
||||
static KlassSubGraphInfo* _default_subgraph_info;
|
||||
|
||||
static GrowableArrayCHeap<oop, mtClassShared>* _pending_roots;
|
||||
static OopHandle _roots;
|
||||
static GrowableArrayCHeap<OopHandle, mtClassShared>* _root_segments;
|
||||
static int _root_segment_max_size_shift;
|
||||
static int _root_segment_max_size_mask;
|
||||
static OopHandle _scratch_basic_type_mirrors[T_VOID+1];
|
||||
static MetaspaceObjToOopHandleTable* _scratch_java_mirror_table;
|
||||
static MetaspaceObjToOopHandleTable* _scratch_references_table;
|
||||
@ -399,7 +401,7 @@ private:
|
||||
static GrowableArrayCHeap<oop, mtClassShared>* pending_roots() { return _pending_roots; }
|
||||
|
||||
// Dump-time and runtime
|
||||
static objArrayOop roots();
|
||||
static objArrayOop root_segment(int segment_idx);
|
||||
static oop get_root(int index, bool clear=false);
|
||||
|
||||
// Run-time only
|
||||
@ -422,7 +424,8 @@ private:
|
||||
|
||||
static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void init_roots(oop roots_oop) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void add_root_segment(objArrayOop segment_oop) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void init_root_segment_sizes(int max_size) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
Loading…
Reference in New Issue
Block a user