8251330: Reorder CDS archived heap to speed up relocation
Reviewed-by: iklam, ccheung
This commit is contained in:
parent
7d8561d56b
commit
7e05a70301
@ -164,18 +164,19 @@ void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm,
|
|||||||
|
|
||||||
// Optimization: if dumptime shift is the same as runtime shift, we can perform a
|
// Optimization: if dumptime shift is the same as runtime shift, we can perform a
|
||||||
// quick conversion from "dumptime narrowOop" -> "runtime narrowOop".
|
// quick conversion from "dumptime narrowOop" -> "runtime narrowOop".
|
||||||
|
narrowOop* patching_start = (narrowOop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos();
|
||||||
if (_narrow_oop_shift == CompressedOops::shift()) {
|
if (_narrow_oop_shift == CompressedOops::shift()) {
|
||||||
uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom;
|
uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom;
|
||||||
log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta);
|
log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta);
|
||||||
if (quick_delta == 0) {
|
if (quick_delta == 0) {
|
||||||
log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0");
|
log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0");
|
||||||
} else {
|
} else {
|
||||||
PatchCompressedEmbeddedPointersQuick patcher((narrowOop*)region.start(), quick_delta);
|
PatchCompressedEmbeddedPointersQuick patcher(patching_start, quick_delta);
|
||||||
bm.iterate(&patcher);
|
bm.iterate(&patcher);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_info(cds)("CDS heap data quick relocation not possible");
|
log_info(cds)("CDS heap data quick relocation not possible");
|
||||||
PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
|
PatchCompressedEmbeddedPointers patcher(patching_start);
|
||||||
bm.iterate(&patcher);
|
bm.iterate(&patcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,17 +187,10 @@ void ArchiveHeapLoader::patch_embedded_pointers(FileMapInfo* info,
|
|||||||
MemRegion region, address oopmap,
|
MemRegion region, address oopmap,
|
||||||
size_t oopmap_size_in_bits) {
|
size_t oopmap_size_in_bits) {
|
||||||
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
|
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
ResourceMark rm;
|
|
||||||
ResourceBitMap checkBm = HeapShared::calculate_oopmap(region);
|
|
||||||
assert(bm.is_same(checkBm), "sanity");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (UseCompressedOops) {
|
if (UseCompressedOops) {
|
||||||
patch_compressed_embedded_pointers(bm, info, region);
|
patch_compressed_embedded_pointers(bm, info, region);
|
||||||
} else {
|
} else {
|
||||||
PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
|
PatchUncompressedEmbeddedPointers patcher((oop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos());
|
||||||
bm.iterate(&patcher);
|
bm.iterate(&patcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +310,7 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv
|
|||||||
uintptr_t oopmap = bitmap_base + r->oopmap_offset();
|
uintptr_t oopmap = bitmap_base + r->oopmap_offset();
|
||||||
BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
|
BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
|
||||||
|
|
||||||
PatchLoadedRegionPointers patcher((narrowOop*)load_address, loaded_region);
|
PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region);
|
||||||
bm.iterate(&patcher);
|
bm.iterate(&patcher);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -449,7 +443,7 @@ void ArchiveHeapLoader::patch_native_pointers() {
|
|||||||
if (r->mapped_base() != nullptr && r->has_ptrmap()) {
|
if (r->mapped_base() != nullptr && r->has_ptrmap()) {
|
||||||
log_info(cds, heap)("Patching native pointers in heap region");
|
log_info(cds, heap)("Patching native pointers in heap region");
|
||||||
BitMapView bm = r->ptrmap_view();
|
BitMapView bm = r->ptrmap_view();
|
||||||
PatchNativePointers patcher((Metadata**)r->mapped_base());
|
PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos());
|
||||||
bm.iterate(&patcher);
|
bm.iterate(&patcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -62,6 +62,7 @@ address ArchiveHeapWriter::_requested_top;
|
|||||||
|
|
||||||
GrowableArrayCHeap<ArchiveHeapWriter::NativePointerInfo, mtClassShared>* ArchiveHeapWriter::_native_pointers;
|
GrowableArrayCHeap<ArchiveHeapWriter::NativePointerInfo, mtClassShared>* ArchiveHeapWriter::_native_pointers;
|
||||||
GrowableArrayCHeap<oop, mtClassShared>* ArchiveHeapWriter::_source_objs;
|
GrowableArrayCHeap<oop, mtClassShared>* ArchiveHeapWriter::_source_objs;
|
||||||
|
GrowableArrayCHeap<int, mtClassShared>* ArchiveHeapWriter::_source_objs_order;
|
||||||
|
|
||||||
ArchiveHeapWriter::BufferOffsetToSourceObjectTable*
|
ArchiveHeapWriter::BufferOffsetToSourceObjectTable*
|
||||||
ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr;
|
ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr;
|
||||||
@ -72,6 +73,7 @@ typedef ResourceHashtable<address, size_t,
|
|||||||
AnyObj::C_HEAP,
|
AnyObj::C_HEAP,
|
||||||
mtClassShared> FillersTable;
|
mtClassShared> FillersTable;
|
||||||
static FillersTable* _fillers;
|
static FillersTable* _fillers;
|
||||||
|
static int _num_native_ptrs = 0;
|
||||||
|
|
||||||
void ArchiveHeapWriter::init() {
|
void ArchiveHeapWriter::init() {
|
||||||
if (HeapShared::can_write()) {
|
if (HeapShared::can_write()) {
|
||||||
@ -84,6 +86,7 @@ void ArchiveHeapWriter::init() {
|
|||||||
|
|
||||||
_native_pointers = new GrowableArrayCHeap<NativePointerInfo, mtClassShared>(2048);
|
_native_pointers = new GrowableArrayCHeap<NativePointerInfo, mtClassShared>(2048);
|
||||||
_source_objs = new GrowableArrayCHeap<oop, mtClassShared>(10000);
|
_source_objs = new GrowableArrayCHeap<oop, mtClassShared>(10000);
|
||||||
|
_source_objs_order = new GrowableArrayCHeap<int, mtClassShared>(10000);
|
||||||
|
|
||||||
guarantee(UseG1GC, "implementation limitation");
|
guarantee(UseG1GC, "implementation limitation");
|
||||||
guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be");
|
guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be");
|
||||||
@ -91,6 +94,7 @@ void ArchiveHeapWriter::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArchiveHeapWriter::add_source_obj(oop src_obj) {
|
void ArchiveHeapWriter::add_source_obj(oop src_obj) {
|
||||||
|
_source_objs_order->append(_source_objs->length());
|
||||||
_source_objs->append(src_obj);
|
_source_objs->append(src_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +230,54 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShar
|
|||||||
_buffer_used = new_used;
|
_buffer_used = new_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int oop_sorting_rank(oop o) {
|
||||||
|
bool has_o_ptr = HeapShared::has_oop_pointers(o);
|
||||||
|
bool has_n_ptr = HeapShared::has_native_pointers(o);
|
||||||
|
|
||||||
|
if (!has_o_ptr) {
|
||||||
|
if (!has_n_ptr) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (has_n_ptr) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The goal is to sort the objects in increasing order of:
|
||||||
|
// - objects that have no pointers
|
||||||
|
// - objects that have only native pointers
|
||||||
|
// - objects that have both native and oop pointers
|
||||||
|
// - objects that have only oop pointers
|
||||||
|
int ArchiveHeapWriter::compare_objs_by_oop_fields(int* a, int* b) {
|
||||||
|
oop oa = _source_objs->at(*a);
|
||||||
|
oop ob = _source_objs->at(*b);
|
||||||
|
|
||||||
|
int rank_a = oop_sorting_rank(oa);
|
||||||
|
int rank_b = oop_sorting_rank(ob);
|
||||||
|
|
||||||
|
if (rank_a != rank_b) {
|
||||||
|
return rank_a - rank_b;
|
||||||
|
} else {
|
||||||
|
// If they are the same rank, sort them by their position in the _source_objs array
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveHeapWriter::sort_source_objs() {
|
||||||
|
_source_objs_order->sort(compare_objs_by_oop_fields);
|
||||||
|
}
|
||||||
|
|
||||||
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
|
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
|
||||||
for (int i = 0; i < _source_objs->length(); i++) {
|
sort_source_objs();
|
||||||
oop src_obj = _source_objs->at(i);
|
for (int i = 0; i < _source_objs_order->length(); i++) {
|
||||||
|
int src_obj_index = _source_objs_order->at(i);
|
||||||
|
oop src_obj = _source_objs->at(src_obj_index);
|
||||||
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
|
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
|
||||||
assert(info != nullptr, "must be");
|
assert(info != nullptr, "must be");
|
||||||
size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
|
size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
|
||||||
@ -239,8 +288,8 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap<oop, mtCla
|
|||||||
|
|
||||||
copy_roots_to_buffer(roots);
|
copy_roots_to_buffer(roots);
|
||||||
|
|
||||||
log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d 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());
|
_buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ArchiveHeapWriter::filler_array_byte_size(int length) {
|
size_t ArchiveHeapWriter::filler_array_byte_size(int length) {
|
||||||
@ -512,6 +561,17 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bits) {
|
||||||
|
// The whole heap is covered by total_bits, but there are only non-zero bits within [start ... end).
|
||||||
|
size_t start = bitmap->find_first_set_bit(0);
|
||||||
|
size_t end = bitmap->size();
|
||||||
|
log_info(cds)("%s = " SIZE_FORMAT_W(7) " ... " SIZE_FORMAT_W(7) " (%3zu%% ... %3zu%% = %3zu%%)", which,
|
||||||
|
start, end,
|
||||||
|
start * 100 / total_bits,
|
||||||
|
end * 100 / total_bits,
|
||||||
|
(end - start) * 100 / total_bits);
|
||||||
|
}
|
||||||
|
|
||||||
// Update all oop fields embedded in the buffered objects
|
// Update all oop fields embedded in the buffered objects
|
||||||
void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots,
|
void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots,
|
||||||
ArchiveHeapInfo* heap_info) {
|
ArchiveHeapInfo* heap_info) {
|
||||||
@ -519,14 +579,17 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassSh
|
|||||||
size_t heap_region_byte_size = _buffer_used;
|
size_t heap_region_byte_size = _buffer_used;
|
||||||
heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit);
|
heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit);
|
||||||
|
|
||||||
auto iterator = [&] (oop src_obj, HeapShared::CachedOopInfo& info) {
|
for (int i = 0; i < _source_objs_order->length(); i++) {
|
||||||
oop requested_obj = requested_obj_from_buffer_offset(info.buffer_offset());
|
int src_obj_index = _source_objs_order->at(i);
|
||||||
|
oop src_obj = _source_objs->at(src_obj_index);
|
||||||
|
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
|
||||||
|
assert(info != nullptr, "must be");
|
||||||
|
oop requested_obj = requested_obj_from_buffer_offset(info->buffer_offset());
|
||||||
update_header_for_requested_obj(requested_obj, src_obj, src_obj->klass());
|
update_header_for_requested_obj(requested_obj, src_obj, src_obj->klass());
|
||||||
address buffered_obj = offset_to_buffered_address<address>(info.buffer_offset());
|
address buffered_obj = offset_to_buffered_address<address>(info->buffer_offset());
|
||||||
EmbeddedOopRelocator relocator(src_obj, buffered_obj, heap_info->oopmap());
|
EmbeddedOopRelocator relocator(src_obj, buffered_obj, heap_info->oopmap());
|
||||||
src_obj->oop_iterate(&relocator);
|
src_obj->oop_iterate(&relocator);
|
||||||
};
|
};
|
||||||
HeapShared::archived_object_cache()->iterate_all(iterator);
|
|
||||||
|
|
||||||
// Relocate HeapShared::roots(), which is created in copy_roots_to_buffer() and
|
// 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.
|
// doesn't have a corresponding src_obj, so we can't use EmbeddedOopRelocator on it.
|
||||||
@ -542,6 +605,10 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassSh
|
|||||||
}
|
}
|
||||||
|
|
||||||
compute_ptrmap(heap_info);
|
compute_ptrmap(heap_info);
|
||||||
|
|
||||||
|
size_t total_bytes = (size_t)_buffer->length();
|
||||||
|
log_bitmap_usage("oopmap", heap_info->oopmap(), total_bytes / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)));
|
||||||
|
log_bitmap_usage("ptrmap", heap_info->ptrmap(), total_bytes / sizeof(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
|
void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
|
||||||
@ -551,6 +618,8 @@ void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
|
|||||||
info._src_obj = src_obj;
|
info._src_obj = src_obj;
|
||||||
info._field_offset = field_offset;
|
info._field_offset = field_offset;
|
||||||
_native_pointers->append(info);
|
_native_pointers->append(info);
|
||||||
|
HeapShared::set_has_native_pointers(src_obj);
|
||||||
|
_num_native_ptrs ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,6 +634,13 @@ bool ArchiveHeapWriter::is_marked_as_native_pointer(ArchiveHeapInfo* heap_info,
|
|||||||
assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check");
|
assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check");
|
||||||
|
|
||||||
BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom;
|
BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom;
|
||||||
|
// Leading zeros have been removed so some addresses may not be in the ptrmap
|
||||||
|
size_t start_pos = FileMapInfo::current_info()->heap_ptrmap_start_pos();
|
||||||
|
if (idx < start_pos) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
idx -= start_pos;
|
||||||
|
}
|
||||||
return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true);
|
return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -140,6 +140,7 @@ private:
|
|||||||
|
|
||||||
static GrowableArrayCHeap<NativePointerInfo, mtClassShared>* _native_pointers;
|
static GrowableArrayCHeap<NativePointerInfo, mtClassShared>* _native_pointers;
|
||||||
static GrowableArrayCHeap<oop, mtClassShared>* _source_objs;
|
static GrowableArrayCHeap<oop, mtClassShared>* _source_objs;
|
||||||
|
static GrowableArrayCHeap<int, mtClassShared>* _source_objs_order;
|
||||||
|
|
||||||
typedef ResourceHashtable<size_t, oop,
|
typedef ResourceHashtable<size_t, oop,
|
||||||
36137, // prime number
|
36137, // prime number
|
||||||
@ -210,6 +211,10 @@ private:
|
|||||||
template <typename T> static void relocate_root_at(oop requested_roots, int index, 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);
|
static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass);
|
||||||
|
|
||||||
|
static int compare_objs_by_oop_fields(int* a, int* b);
|
||||||
|
static void sort_source_objs();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void init() NOT_CDS_JAVA_HEAP_RETURN;
|
static void init() NOT_CDS_JAVA_HEAP_RETURN;
|
||||||
static void add_source_obj(oop src_obj);
|
static void add_source_obj(oop src_obj);
|
||||||
|
@ -289,6 +289,8 @@ void FileMapHeader::print(outputStream* st) {
|
|||||||
st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
|
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("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
|
||||||
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
|
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
|
||||||
|
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("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
|
st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
|
||||||
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
|
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
|
||||||
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
|
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
|
||||||
@ -1565,11 +1567,37 @@ static size_t write_bitmap(const CHeapBitMap* map, char* output, size_t offset)
|
|||||||
return offset + size_in_bytes;
|
return offset + size_in_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The start of the archived heap has many primitive arrays (String
|
||||||
|
// bodies) that are not marked by the oop/ptr maps. So we must have
|
||||||
|
// lots of leading zeros.
|
||||||
|
size_t FileMapInfo::remove_bitmap_leading_zeros(CHeapBitMap* map) {
|
||||||
|
size_t old_zeros = map->find_first_set_bit(0);
|
||||||
|
size_t old_size = map->size_in_bytes();
|
||||||
|
|
||||||
|
// Slice and resize bitmap
|
||||||
|
map->truncate(old_zeros, map->size());
|
||||||
|
|
||||||
|
DEBUG_ONLY(
|
||||||
|
size_t new_zeros = map->find_first_set_bit(0);
|
||||||
|
assert(new_zeros == 0, "Should have removed leading zeros");
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(map->size_in_bytes() < old_size, "Map size should have decreased");
|
||||||
|
return old_zeros;
|
||||||
|
}
|
||||||
|
|
||||||
char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
|
char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
|
||||||
size_t &size_in_bytes) {
|
size_t &size_in_bytes) {
|
||||||
size_in_bytes = ptrmap->size_in_bytes();
|
size_in_bytes = ptrmap->size_in_bytes();
|
||||||
|
|
||||||
if (heap_info->is_used()) {
|
if (heap_info->is_used()) {
|
||||||
|
// Remove leading zeros
|
||||||
|
size_t removed_oop_zeros = remove_bitmap_leading_zeros(heap_info->oopmap());
|
||||||
|
size_t removed_ptr_zeros = remove_bitmap_leading_zeros(heap_info->ptrmap());
|
||||||
|
|
||||||
|
header()->set_heap_oopmap_start_pos(removed_oop_zeros);
|
||||||
|
header()->set_heap_ptrmap_start_pos(removed_ptr_zeros);
|
||||||
|
|
||||||
size_in_bytes += heap_info->oopmap()->size_in_bytes();
|
size_in_bytes += heap_info->oopmap()->size_in_bytes();
|
||||||
size_in_bytes += heap_info->ptrmap()->size_in_bytes();
|
size_in_bytes += heap_info->ptrmap()->size_in_bytes();
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,8 @@ private:
|
|||||||
size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap
|
size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap
|
||||||
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
|
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
|
||||||
// of the archived heap objects, in bytes.
|
// of the archived heap objects, in bytes.
|
||||||
|
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.
|
||||||
char* from_mapped_offset(size_t offset) const {
|
char* from_mapped_offset(size_t offset) const {
|
||||||
return mapped_base_address() + offset;
|
return mapped_base_address() + offset;
|
||||||
}
|
}
|
||||||
@ -269,6 +271,8 @@ public:
|
|||||||
bool compressed_oops() const { return _compressed_oops; }
|
bool compressed_oops() const { return _compressed_oops; }
|
||||||
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
|
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
|
||||||
size_t heap_roots_offset() const { return _heap_roots_offset; }
|
size_t heap_roots_offset() const { return _heap_roots_offset; }
|
||||||
|
size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos;}
|
||||||
|
size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos;}
|
||||||
// FIXME: These should really return int
|
// FIXME: These should really return int
|
||||||
jshort max_used_path_index() const { return _max_used_path_index; }
|
jshort max_used_path_index() const { return _max_used_path_index; }
|
||||||
jshort app_module_paths_start_index() const { return _app_module_paths_start_index; }
|
jshort app_module_paths_start_index() const { return _app_module_paths_start_index; }
|
||||||
@ -281,6 +285,8 @@ public:
|
|||||||
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
|
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
|
||||||
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
|
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_roots_offset(size_t n) { _heap_roots_offset = n; }
|
||||||
|
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 copy_base_archive_name(const char* name);
|
void copy_base_archive_name(const char* name);
|
||||||
|
|
||||||
void set_shared_path_table(SharedPathTable table) {
|
void set_shared_path_table(SharedPathTable table) {
|
||||||
@ -378,6 +384,8 @@ public:
|
|||||||
uintx max_heap_size() const { return header()->max_heap_size(); }
|
uintx max_heap_size() const { return header()->max_heap_size(); }
|
||||||
size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
|
size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
|
||||||
size_t core_region_alignment() const { return header()->core_region_alignment(); }
|
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(); }
|
||||||
|
|
||||||
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
|
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
|
||||||
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }
|
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }
|
||||||
@ -434,6 +442,7 @@ public:
|
|||||||
void write_header();
|
void write_header();
|
||||||
void write_region(int region, char* base, size_t size,
|
void write_region(int region, char* base, size_t size,
|
||||||
bool read_only, bool allow_exec);
|
bool read_only, bool allow_exec);
|
||||||
|
size_t remove_bitmap_leading_zeros(CHeapBitMap* map);
|
||||||
char* write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
|
char* write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
|
||||||
size_t &size_in_bytes);
|
size_t &size_in_bytes);
|
||||||
size_t write_heap_region(ArchiveHeapInfo* heap_info);
|
size_t write_heap_region(ArchiveHeapInfo* heap_info);
|
||||||
|
@ -284,7 +284,7 @@ bool HeapShared::archive_object(oop obj) {
|
|||||||
// the identity_hash in the object header will have a predictable value,
|
// the identity_hash in the object header will have a predictable value,
|
||||||
// making the archive reproducible.
|
// making the archive reproducible.
|
||||||
obj->identity_hash();
|
obj->identity_hash();
|
||||||
CachedOopInfo info = make_cached_oop_info();
|
CachedOopInfo info = make_cached_oop_info(obj);
|
||||||
archived_object_cache()->put(obj, info);
|
archived_object_cache()->put(obj, info);
|
||||||
mark_native_pointers(obj);
|
mark_native_pointers(obj);
|
||||||
|
|
||||||
@ -437,6 +437,24 @@ void HeapShared::mark_native_pointers(oop orig_obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HeapShared::has_oop_pointers(oop src_obj) {
|
||||||
|
CachedOopInfo* info = archived_object_cache()->get(src_obj);
|
||||||
|
assert(info != nullptr, "must be");
|
||||||
|
return info->has_oop_pointers();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeapShared::has_native_pointers(oop src_obj) {
|
||||||
|
CachedOopInfo* info = archived_object_cache()->get(src_obj);
|
||||||
|
assert(info != nullptr, "must be");
|
||||||
|
return info->has_native_pointers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapShared::set_has_native_pointers(oop src_obj) {
|
||||||
|
CachedOopInfo* info = archived_object_cache()->get(src_obj);
|
||||||
|
assert(info != nullptr, "must be");
|
||||||
|
info->set_has_native_pointers();
|
||||||
|
}
|
||||||
|
|
||||||
// -- Handling of Enum objects
|
// -- Handling of Enum objects
|
||||||
// Java Enum classes have synthetic <clinit> methods that look like this
|
// Java Enum classes have synthetic <clinit> methods that look like this
|
||||||
// enum MyEnum {FOO, BAR}
|
// enum MyEnum {FOO, BAR}
|
||||||
@ -1138,10 +1156,27 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure {
|
|||||||
|
|
||||||
WalkOopAndArchiveClosure* WalkOopAndArchiveClosure::_current = nullptr;
|
WalkOopAndArchiveClosure* WalkOopAndArchiveClosure::_current = nullptr;
|
||||||
|
|
||||||
HeapShared::CachedOopInfo HeapShared::make_cached_oop_info() {
|
// Checks if an oop has any non-null oop fields
|
||||||
|
class PointsToOopsChecker : public BasicOopIterateClosure {
|
||||||
|
bool _result;
|
||||||
|
|
||||||
|
template <class T> void check(T *p) {
|
||||||
|
_result |= (HeapAccess<>::oop_load(p) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PointsToOopsChecker() : _result(false) {}
|
||||||
|
void do_oop(narrowOop *p) { check(p); }
|
||||||
|
void do_oop( oop *p) { check(p); }
|
||||||
|
bool result() { return _result; }
|
||||||
|
};
|
||||||
|
|
||||||
|
HeapShared::CachedOopInfo HeapShared::make_cached_oop_info(oop obj) {
|
||||||
WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current();
|
WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current();
|
||||||
oop referrer = (walker == nullptr) ? nullptr : walker->referencing_obj();
|
oop referrer = (walker == nullptr) ? nullptr : walker->referencing_obj();
|
||||||
return CachedOopInfo(referrer);
|
PointsToOopsChecker points_to_oops_checker;
|
||||||
|
obj->oop_iterate(&points_to_oops_checker);
|
||||||
|
return CachedOopInfo(referrer, points_to_oops_checker.result());
|
||||||
}
|
}
|
||||||
|
|
||||||
// (1) If orig_obj has not been archived yet, archive it.
|
// (1) If orig_obj has not been archived yet, archive it.
|
||||||
@ -1439,12 +1474,14 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
|||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
bool is_test_class = (ArchiveHeapTestClass != nullptr) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
|
bool is_test_class = (ArchiveHeapTestClass != nullptr) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
|
||||||
|
const char* test_class_name = ArchiveHeapTestClass;
|
||||||
#else
|
#else
|
||||||
bool is_test_class = false;
|
bool is_test_class = false;
|
||||||
|
const char* test_class_name = ""; // avoid C++ printf checks warnings.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (is_test_class) {
|
if (is_test_class) {
|
||||||
log_warning(cds)("Loading ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
|
log_warning(cds)("Loading ArchiveHeapTestClass %s ...", test_class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
|
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
|
||||||
@ -1470,14 +1507,14 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
|||||||
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
|
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
|
||||||
// core-lib classes. You need to at least append to the bootclasspath.
|
// core-lib classes. You need to at least append to the bootclasspath.
|
||||||
stringStream st;
|
stringStream st;
|
||||||
st.print("ArchiveHeapTestClass %s is not in unnamed module", ArchiveHeapTestClass);
|
st.print("ArchiveHeapTestClass %s is not in unnamed module", test_class_name);
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ik->package() != nullptr) {
|
if (ik->package() != nullptr) {
|
||||||
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
|
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
|
||||||
stringStream st;
|
stringStream st;
|
||||||
st.print("ArchiveHeapTestClass %s is not in unnamed package", ArchiveHeapTestClass);
|
st.print("ArchiveHeapTestClass %s is not in unnamed package", test_class_name);
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1492,7 +1529,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_test_class) {
|
if (is_test_class) {
|
||||||
log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
|
log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", test_class_name);
|
||||||
}
|
}
|
||||||
ik->initialize(CHECK);
|
ik->initialize(CHECK);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -186,18 +186,29 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CachedOopInfo {
|
class CachedOopInfo {
|
||||||
// See "TEMP notes: What are these?" in archiveHeapWriter.hpp
|
// Used by CDSHeapVerifier.
|
||||||
oop _orig_referrer;
|
oop _orig_referrer;
|
||||||
|
|
||||||
// The location of this object inside ArchiveHeapWriter::_buffer
|
// The location of this object inside ArchiveHeapWriter::_buffer
|
||||||
size_t _buffer_offset;
|
size_t _buffer_offset;
|
||||||
|
|
||||||
|
// One or more fields in this object are pointing to non-null oops.
|
||||||
|
bool _has_oop_pointers;
|
||||||
|
|
||||||
|
// One or more fields in this object are pointing to MetaspaceObj
|
||||||
|
bool _has_native_pointers;
|
||||||
public:
|
public:
|
||||||
CachedOopInfo(oop orig_referrer)
|
CachedOopInfo(oop orig_referrer, bool has_oop_pointers)
|
||||||
: _orig_referrer(orig_referrer),
|
: _orig_referrer(orig_referrer),
|
||||||
_buffer_offset(0) {}
|
_buffer_offset(0),
|
||||||
|
_has_oop_pointers(has_oop_pointers),
|
||||||
|
_has_native_pointers(false) {}
|
||||||
oop orig_referrer() const { return _orig_referrer; }
|
oop orig_referrer() const { return _orig_referrer; }
|
||||||
void set_buffer_offset(size_t offset) { _buffer_offset = offset; }
|
void set_buffer_offset(size_t offset) { _buffer_offset = offset; }
|
||||||
size_t buffer_offset() const { return _buffer_offset; }
|
size_t buffer_offset() const { return _buffer_offset; }
|
||||||
|
bool has_oop_pointers() const { return _has_oop_pointers; }
|
||||||
|
bool has_native_pointers() const { return _has_native_pointers; }
|
||||||
|
void set_has_native_pointers() { _has_native_pointers = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -237,7 +248,7 @@ private:
|
|||||||
static DumpTimeKlassSubGraphInfoTable* _dump_time_subgraph_info_table;
|
static DumpTimeKlassSubGraphInfoTable* _dump_time_subgraph_info_table;
|
||||||
static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table;
|
static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table;
|
||||||
|
|
||||||
static CachedOopInfo make_cached_oop_info();
|
static CachedOopInfo make_cached_oop_info(oop obj);
|
||||||
static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
|
||||||
bool is_full_module_graph);
|
bool is_full_module_graph);
|
||||||
|
|
||||||
@ -368,6 +379,9 @@ private:
|
|||||||
// Scratch objects for archiving Klass::java_mirror()
|
// Scratch objects for archiving Klass::java_mirror()
|
||||||
static void set_scratch_java_mirror(Klass* k, oop mirror);
|
static void set_scratch_java_mirror(Klass* k, oop mirror);
|
||||||
static void remove_scratch_objects(Klass* k);
|
static void remove_scratch_objects(Klass* k);
|
||||||
|
static bool has_oop_pointers(oop obj);
|
||||||
|
static bool has_native_pointers(oop obj);
|
||||||
|
static void set_has_native_pointers(oop obj);
|
||||||
|
|
||||||
// We use the HeapShared::roots() array to make sure that objects stored in the
|
// We use the HeapShared::roots() array to make sure that objects stored in the
|
||||||
// archived heap region are not prematurely collected. These roots include:
|
// archived heap region are not prematurely collected. These roots include:
|
||||||
|
@ -96,6 +96,7 @@ bool MetaspaceShared::_remapped_readwrite = false;
|
|||||||
void* MetaspaceShared::_shared_metaspace_static_top = nullptr;
|
void* MetaspaceShared::_shared_metaspace_static_top = nullptr;
|
||||||
intx MetaspaceShared::_relocation_delta;
|
intx MetaspaceShared::_relocation_delta;
|
||||||
char* MetaspaceShared::_requested_base_address;
|
char* MetaspaceShared::_requested_base_address;
|
||||||
|
bool MetaspaceShared::_use_optimized_module_handling = true;
|
||||||
|
|
||||||
// The CDS archive is divided into the following regions:
|
// The CDS archive is divided into the following regions:
|
||||||
// rw - read-write metadata
|
// rw - read-write metadata
|
||||||
|
@ -52,6 +52,8 @@ class MetaspaceShared : AllStatic {
|
|||||||
static void* _shared_metaspace_static_top;
|
static void* _shared_metaspace_static_top;
|
||||||
static intx _relocation_delta;
|
static intx _relocation_delta;
|
||||||
static char* _requested_base_address;
|
static char* _requested_base_address;
|
||||||
|
static bool _use_optimized_module_handling;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
// core archive spaces
|
// core archive spaces
|
||||||
@ -158,6 +160,10 @@ public:
|
|||||||
return is_windows;
|
return is_windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can we skip some expensive operations related to modules?
|
||||||
|
static bool use_optimized_module_handling() { return NOT_CDS(false) CDS_ONLY(_use_optimized_module_handling); }
|
||||||
|
static void disable_optimized_module_handling() { _use_optimized_module_handling = false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void read_extra_data(JavaThread* current, const char* filename) NOT_CDS_RETURN;
|
static void read_extra_data(JavaThread* current, const char* filename) NOT_CDS_RETURN;
|
||||||
static FileMapInfo* open_static_archive();
|
static FileMapInfo* open_static_archive();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user