8293291: Simplify relocation of native pointers in archive heap

Reviewed-by: ccheung, coleenp
This commit is contained in:
Ioi Lam 2022-10-19 04:57:56 +00:00
parent 1553551d82
commit 3f4964f83d
17 changed files with 275 additions and 235 deletions

View File

@ -1166,8 +1166,8 @@ void ArchiveBuilder::clean_up_src_obj_table() {
void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
GrowableArray<MemRegion>* closed_heap_regions,
GrowableArray<MemRegion>* open_heap_regions,
GrowableArray<ArchiveHeapOopmapInfo>* closed_heap_oopmaps,
GrowableArray<ArchiveHeapOopmapInfo>* open_heap_oopmaps) {
GrowableArray<ArchiveHeapBitmapInfo>* closed_heap_bitmaps,
GrowableArray<ArchiveHeapBitmapInfo>* open_heap_bitmaps) {
// Make sure NUM_CDS_REGIONS (exported in cds.h) agrees with
// MetaspaceShared::n_regions (internal to hotspot).
assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity");
@ -1176,18 +1176,18 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
size_t bitmap_size_in_bytes;
char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap(), closed_heap_oopmaps, open_heap_oopmaps,
char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap(), closed_heap_bitmaps, open_heap_bitmaps,
bitmap_size_in_bytes);
if (closed_heap_regions != NULL) {
_total_closed_heap_region_size = mapinfo->write_heap_regions(
closed_heap_regions,
closed_heap_oopmaps,
closed_heap_bitmaps,
MetaspaceShared::first_closed_heap_region,
MetaspaceShared::max_num_closed_heap_regions);
_total_open_heap_region_size = mapinfo->write_heap_regions(
open_heap_regions,
open_heap_oopmaps,
open_heap_bitmaps,
MetaspaceShared::first_open_heap_region,
MetaspaceShared::max_num_open_heap_regions);
}

View File

@ -36,7 +36,7 @@
#include "utilities/resizeableResourceHash.hpp"
#include "utilities/resourceHash.hpp"
struct ArchiveHeapOopmapInfo;
struct ArchiveHeapBitmapInfo;
class CHeapBitMap;
class FileMapInfo;
class Klass;
@ -406,8 +406,8 @@ public:
void write_archive(FileMapInfo* mapinfo,
GrowableArray<MemRegion>* closed_heap_regions,
GrowableArray<MemRegion>* open_heap_regions,
GrowableArray<ArchiveHeapOopmapInfo>* closed_heap_oopmaps,
GrowableArray<ArchiveHeapOopmapInfo>* open_heap_oopmaps);
GrowableArray<ArchiveHeapBitmapInfo>* closed_heap_oopmaps,
GrowableArray<ArchiveHeapBitmapInfo>* open_heap_oopmaps);
void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,
bool read_only, bool allow_exec);

View File

@ -72,7 +72,7 @@ void ArchiveHeapLoader::fixup_regions() {
if (is_mapped()) {
mapinfo->fixup_mapped_heap_regions();
} else if (_loading_failed) {
fill_failed_loaded_region();
fill_failed_loaded_heap();
}
if (is_fully_available()) {
if (!MetaspaceShared::use_full_module_graph()) {
@ -80,7 +80,6 @@ void ArchiveHeapLoader::fixup_regions() {
ClassLoaderDataShared::clear_archived_oops();
}
}
SystemDictionaryShared::update_archived_mirror_native_pointers();
}
// ------------------ Support for Region MAPPING -----------------------------------------
@ -171,7 +170,7 @@ struct LoadedArchiveHeapRegion {
};
void ArchiveHeapLoader::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loaded_regions,
int num_loaded_regions) {
int num_loaded_regions) {
_dumptime_base_0 = loaded_regions[0]._dumptime_base;
_dumptime_base_1 = loaded_regions[1]._dumptime_base;
_dumptime_base_2 = loaded_regions[2]._dumptime_base;
@ -314,7 +313,7 @@ bool ArchiveHeapLoader::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegi
if (!mapinfo->read_region(ri->_region_index, (char*)load_address, r->used(), /* do_commit = */ false)) {
// There's no easy way to free the buffer, so we will fill it with zero later
// in fill_failed_loaded_region(), and it will eventually be GC'ed.
// in fill_failed_loaded_heap(), and it will eventually be GC'ed.
log_warning(cds)("Loading of heap region %d has failed. Archived objects are disabled", i);
_loading_failed = true;
return false;
@ -339,6 +338,7 @@ bool ArchiveHeapLoader::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegi
bm.iterate(&patcher);
}
r->set_mapped_base((char*)load_address);
load_address += r->used();
}
@ -392,17 +392,24 @@ class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure {
void ArchiveHeapLoader::finish_initialization() {
if (is_loaded()) {
HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
HeapWord* top = (HeapWord*)_loaded_heap_top;
MemRegion archive_space = MemRegion(bottom, top);
Universe::heap()->complete_loaded_archive_space(archive_space);
// These operations are needed only when the heap is loaded (not mapped).
finish_loaded_heap();
if (VerifyArchivedFields > 0) {
verify_loaded_heap();
}
}
patch_native_pointers();
}
if (VerifyArchivedFields <= 0 || !is_loaded()) {
return;
}
void ArchiveHeapLoader::finish_loaded_heap() {
HeapWord* bottom = (HeapWord*)_loaded_heap_bottom;
HeapWord* top = (HeapWord*)_loaded_heap_top;
MemRegion archive_space = MemRegion(bottom, top);
Universe::heap()->complete_loaded_archive_space(archive_space);
}
void ArchiveHeapLoader::verify_loaded_heap() {
log_info(cds, heap)("Verify all oops and pointers in loaded heap");
ResourceMark rm;
@ -424,7 +431,7 @@ void ArchiveHeapLoader::finish_initialization() {
}
}
void ArchiveHeapLoader::fill_failed_loaded_region() {
void ArchiveHeapLoader::fill_failed_loaded_heap() {
assert(_loading_failed, "must be");
if (_loaded_heap_bottom != 0) {
assert(_loaded_heap_top != 0, "must be");
@ -434,4 +441,37 @@ void ArchiveHeapLoader::fill_failed_loaded_region() {
}
}
class PatchNativePointers: public BitMapClosure {
Metadata** _start;
public:
PatchNativePointers(Metadata** start) : _start(start) {}
bool do_bit(size_t offset) {
Metadata** p = _start + offset;
*p = (Metadata*)(address(*p) + MetaspaceShared::relocation_delta());
// Currently we have only Klass pointers in heap objects.
// This needs to be relaxed when we support other types of native
// pointers such as Method.
assert(((Klass*)(*p))->is_klass(), "must be");
return true;
}
};
void ArchiveHeapLoader::patch_native_pointers() {
if (MetaspaceShared::relocation_delta() == 0) {
return;
}
for (int i = MetaspaceShared::first_archive_heap_region;
i <= MetaspaceShared::last_archive_heap_region; i++) {
FileMapRegion* r = FileMapInfo::current_info()->space_at(i);
if (r->mapped_base() != NULL && r->has_ptrmap()) {
log_info(cds, heap)("Patching native pointers in heap region %d", i);
BitMapView bm = r->ptrmap_view();
PatchNativePointers patcher((Metadata**)r->mapped_base());
bm.iterate(&patcher);
}
}
}
#endif // INCLUDE_CDS_JAVA_HEAP

View File

@ -146,7 +146,10 @@ private:
int num_loaded_regions, uintptr_t buffer);
static void init_loaded_heap_relocation(LoadedArchiveHeapRegion* reloc_info,
int num_loaded_regions);
static void fill_failed_loaded_region();
static void patch_native_pointers();
static void finish_loaded_heap();
static void verify_loaded_heap();
static void fill_failed_loaded_heap();
static bool is_in_loaded_heap(uintptr_t o) {
return (_loaded_heap_bottom <= o && o < _loaded_heap_top);

View File

@ -1492,6 +1492,29 @@ void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, b
_mapped_base = NULL;
}
void FileMapRegion::init_bitmaps(ArchiveHeapBitmapInfo oopmap, ArchiveHeapBitmapInfo ptrmap) {
_oopmap_offset = oopmap._bm_region_offset;
_oopmap_size_in_bits = oopmap._size_in_bits;
_ptrmap_offset = ptrmap._bm_region_offset;
_ptrmap_size_in_bits = ptrmap._size_in_bits;
}
BitMapView FileMapRegion::bitmap_view(bool is_oopmap) {
char* bitmap_base = FileMapInfo::current_info()->map_bitmap_region();
bitmap_base += is_oopmap ? _oopmap_offset : _ptrmap_offset;
size_t size_in_bits = is_oopmap ? _oopmap_size_in_bits : _ptrmap_size_in_bits;
return BitMapView((BitMap::bm_word_t*)(bitmap_base), size_in_bits);
}
BitMapView FileMapRegion::oopmap_view() {
return bitmap_view(true);
}
BitMapView FileMapRegion::ptrmap_view() {
assert(has_ptrmap(), "must be");
return bitmap_view(false);
}
static const char* region_name(int region_index) {
static const char* names[] = {
@ -1566,41 +1589,41 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
}
}
size_t FileMapInfo::set_oopmaps_offset(GrowableArray<ArchiveHeapOopmapInfo>* oopmaps, size_t curr_size) {
for (int i = 0; i < oopmaps->length(); i++) {
oopmaps->at(i)._offset = curr_size;
curr_size += oopmaps->at(i)._oopmap_size_in_bytes;
size_t FileMapInfo::set_bitmaps_offset(GrowableArray<ArchiveHeapBitmapInfo>* bitmaps, size_t curr_size) {
for (int i = 0; i < bitmaps->length(); i++) {
bitmaps->at(i)._bm_region_offset = curr_size;
curr_size += bitmaps->at(i)._size_in_bytes;
}
return curr_size;
}
size_t FileMapInfo::write_oopmaps(GrowableArray<ArchiveHeapOopmapInfo>* oopmaps, size_t curr_offset, char* buffer) {
for (int i = 0; i < oopmaps->length(); i++) {
memcpy(buffer + curr_offset, oopmaps->at(i)._oopmap, oopmaps->at(i)._oopmap_size_in_bytes);
curr_offset += oopmaps->at(i)._oopmap_size_in_bytes;
size_t FileMapInfo::write_bitmaps(GrowableArray<ArchiveHeapBitmapInfo>* bitmaps, size_t curr_offset, char* buffer) {
for (int i = 0; i < bitmaps->length(); i++) {
memcpy(buffer + curr_offset, bitmaps->at(i)._map, bitmaps->at(i)._size_in_bytes);
curr_offset += bitmaps->at(i)._size_in_bytes;
}
return curr_offset;
}
char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap,
GrowableArray<ArchiveHeapOopmapInfo>* closed_oopmaps,
GrowableArray<ArchiveHeapOopmapInfo>* open_oopmaps,
GrowableArray<ArchiveHeapBitmapInfo>* closed_bitmaps,
GrowableArray<ArchiveHeapBitmapInfo>* open_bitmaps,
size_t &size_in_bytes) {
size_t size_in_bits = ptrmap->size();
size_in_bytes = ptrmap->size_in_bytes();
if (closed_oopmaps != NULL && open_oopmaps != NULL) {
size_in_bytes = set_oopmaps_offset(closed_oopmaps, size_in_bytes);
size_in_bytes = set_oopmaps_offset(open_oopmaps, size_in_bytes);
if (closed_bitmaps != NULL && open_bitmaps != NULL) {
size_in_bytes = set_bitmaps_offset(closed_bitmaps, size_in_bytes);
size_in_bytes = set_bitmaps_offset(open_bitmaps, size_in_bytes);
}
char* buffer = NEW_C_HEAP_ARRAY(char, size_in_bytes, mtClassShared);
ptrmap->write_to((BitMap::bm_word_t*)buffer, ptrmap->size_in_bytes());
header()->set_ptrmap_size_in_bits(size_in_bits);
if (closed_oopmaps != NULL && open_oopmaps != NULL) {
size_t curr_offset = write_oopmaps(closed_oopmaps, ptrmap->size_in_bytes(), buffer);
write_oopmaps(open_oopmaps, curr_offset, buffer);
if (closed_bitmaps != NULL && open_bitmaps != NULL) {
size_t curr_offset = write_bitmaps(closed_bitmaps, ptrmap->size_in_bytes(), buffer);
write_bitmaps(open_bitmaps, curr_offset, buffer);
}
write_region(MetaspaceShared::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false);
@ -1639,7 +1662,7 @@ char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap,
// |
// +-- gap
size_t FileMapInfo::write_heap_regions(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps,
GrowableArray<ArchiveHeapBitmapInfo>* bitmaps,
int first_region_id, int max_num_regions) {
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
@ -1665,8 +1688,10 @@ size_t FileMapInfo::write_heap_regions(GrowableArray<MemRegion>* regions,
int region_idx = i + first_region_id;
write_region(region_idx, start, size, false, false);
if (size > 0) {
space_at(region_idx)->init_oopmap(oopmaps->at(i)._offset,
oopmaps->at(i)._oopmap_size_in_bits);
int oopmap_idx = i * 2;
int ptrmap_idx = i * 2 + 1;
space_at(region_idx)->init_bitmaps(bitmaps->at(oopmap_idx),
bitmaps->at(ptrmap_idx));
}
}
return total_size;
@ -2307,6 +2332,8 @@ bool FileMapInfo::map_heap_regions(int first, int max, bool is_open_archive,
log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
return false;
}
si->set_mapped_base(base);
}
cleanup._aborted = false;

View File

@ -39,6 +39,7 @@
static const int JVM_IDENT_MAX = 256;
class BitMapView;
class CHeapBitMap;
class ClassFileStream;
class ClassLoaderData;
@ -102,11 +103,11 @@ public:
}
};
struct ArchiveHeapOopmapInfo {
address _oopmap; // bitmap for relocating embedded oops
size_t _offset; // this oopmap is stored at this offset from the bottom of the BM region
size_t _oopmap_size_in_bits;
size_t _oopmap_size_in_bytes;
struct ArchiveHeapBitmapInfo {
address _map; // bitmap for relocating embedded oops
size_t _bm_region_offset; // this bitmap is stored at this offset from the bottom of the BM region
size_t _size_in_bits;
size_t _size_in_bytes;
};
class SharedPathTable {
@ -137,6 +138,7 @@ public:
class FileMapRegion: private CDSFileMapRegion {
BitMapView bitmap_view(bool is_oopmap);
public:
void assert_is_heap_region() const {
assert(_is_heap_region, "must be heap region");
@ -156,7 +158,7 @@ public:
size_t mapping_end_offset() const { return _mapping_offset + used_aligned(); }
size_t used() const { return _used; }
size_t used_aligned() const; // aligned up to MetaspaceShared::core_region_alignment()
char* mapped_base() const { assert_is_not_heap_region(); return _mapped_base; }
char* mapped_base() const { return _mapped_base; }
char* mapped_end() const { return mapped_base() + used_aligned(); }
bool read_only() const { return _read_only != 0; }
bool allow_exec() const { return _allow_exec != 0; }
@ -170,11 +172,10 @@ public:
void set_mapped_from_file(bool v) { _mapped_from_file = v; }
void init(int region_index, size_t mapping_offset, size_t size, bool read_only,
bool allow_exec, int crc);
void init_oopmap(size_t oopmap_offset, size_t size_in_bits) {
_oopmap_offset = oopmap_offset;
_oopmap_size_in_bits = size_in_bits;
}
void init_bitmaps(ArchiveHeapBitmapInfo oopmap, ArchiveHeapBitmapInfo ptrmap);
BitMapView oopmap_view();
BitMapView ptrmap_view();
bool has_ptrmap() { return _ptrmap_size_in_bits != 0; }
void print(outputStream* st, int region_index);
};
@ -444,11 +445,11 @@ public:
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
char* write_bitmap_region(const CHeapBitMap* ptrmap,
GrowableArray<ArchiveHeapOopmapInfo>* closed_oopmaps,
GrowableArray<ArchiveHeapOopmapInfo>* open_oopmaps,
GrowableArray<ArchiveHeapBitmapInfo>* closed_bitmaps,
GrowableArray<ArchiveHeapBitmapInfo>* open_bitmaps,
size_t &size_in_bytes);
size_t write_heap_regions(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps,
GrowableArray<ArchiveHeapBitmapInfo>* bitmaps,
int first_region_id, int max_num_regions);
void write_bytes(const void* buffer, size_t count);
void write_bytes_aligned(const void* buffer, size_t count);
@ -573,8 +574,8 @@ public:
void map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
MapArchiveResult map_region(int i, intx addr_delta, char* mapped_base_address, ReservedSpace rs);
bool relocate_pointers_in_core_regions(intx addr_delta);
static size_t set_oopmaps_offset(GrowableArray<ArchiveHeapOopmapInfo> *oopmaps, size_t curr_size);
static size_t write_oopmaps(GrowableArray<ArchiveHeapOopmapInfo> *oopmaps, size_t curr_offset, char* buffer);
static size_t set_bitmaps_offset(GrowableArray<ArchiveHeapBitmapInfo> *bitmaps, size_t curr_size);
static size_t write_bitmaps(GrowableArray<ArchiveHeapBitmapInfo> *bitmaps, size_t curr_offset, char* buffer);
address decode_start_address(FileMapRegion* spc, bool with_current_oop_encoding_mode);

View File

@ -82,6 +82,7 @@ struct ArchivableStaticFieldInfo {
bool HeapShared::_disable_writing = false;
DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
GrowableArrayCHeap<Metadata**, mtClassShared>* HeapShared::_native_pointers = NULL;
#ifndef PRODUCT
#define ARCHIVE_TEST_FIELD_NAME "archivedObjects"
@ -320,6 +321,7 @@ oop HeapShared::archive_object(oop obj) {
if (_original_object_table != NULL) {
_original_object_table->put(archived_oop, obj);
}
mark_native_pointers(obj, archived_oop);
if (log_is_enabled(Debug, cds, heap)) {
ResourceMark rm;
log_debug(cds, heap)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT " : %s",
@ -353,6 +355,32 @@ void HeapShared::archive_klass_objects() {
}
}
void HeapShared::mark_native_pointers(oop orig_obj, oop archived_obj) {
if (java_lang_Class::is_instance(orig_obj)) {
mark_one_native_pointer(archived_obj, java_lang_Class::klass_offset());
mark_one_native_pointer(archived_obj, java_lang_Class::array_klass_offset());
}
}
void HeapShared::mark_one_native_pointer(oop archived_obj, int offset) {
Metadata* ptr = archived_obj->metadata_field_acquire(offset);
if (ptr != NULL) {
// Set the native pointer to the requested address (at runtime, if the metadata
// is mapped at the default location, it will be at this address).
address buffer_addr = ArchiveBuilder::current()->get_buffered_addr((address)ptr);
address requested_addr = ArchiveBuilder::current()->to_requested(buffer_addr);
archived_obj->metadata_field_put(offset, (Metadata*)requested_addr);
// Remember this pointer. At runtime, if the metadata is mapped at a non-default
// location, the pointer needs to be patched (see ArchiveHeapLoader::patch_native_pointers()).
_native_pointers->append(archived_obj->field_addr<Metadata*>(offset));
log_debug(cds, heap, mirror)(
"Marked metadata field at %d: " PTR_FORMAT " ==> " PTR_FORMAT,
offset, p2i(ptr), p2i(requested_addr));
}
}
// -- Handling of Enum objects
// Java Enum classes have synthetic <clinit> methods that look like this
// enum MyEnum {FOO, BAR}
@ -1632,6 +1660,7 @@ void HeapShared::init_for_dumping(TRAPS) {
if (HeapShared::can_write()) {
setup_test_class(ArchiveHeapTestClass);
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
_native_pointers = new GrowableArrayCHeap<Metadata**, mtClassShared>(2048);
init_subgraph_entry_fields(CHECK);
}
}
@ -1797,4 +1826,33 @@ ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
return oopmap;
}
ResourceBitMap HeapShared::calculate_ptrmap(MemRegion region) {
size_t num_bits = region.byte_size() / sizeof(Metadata*);
ResourceBitMap oopmap(num_bits);
Metadata** start = (Metadata**)region.start();
Metadata** end = (Metadata**)region.end();
int num_non_null_ptrs = 0;
int len = _native_pointers->length();
for (int i = 0; i < len; i++) {
Metadata** p = _native_pointers->at(i);
if (start <= p && p < end) {
assert(*p != NULL, "must be non-null");
num_non_null_ptrs ++;
size_t idx = p - start;
oopmap.set_bit(idx);
}
}
log_info(cds, heap)("calculate_ptrmap: marked %d non-null native pointers out of "
SIZE_FORMAT " possible locations", num_non_null_ptrs, num_bits);
if (num_non_null_ptrs > 0) {
return oopmap;
} else {
return ResourceBitMap(0);
}
}
#endif // INCLUDE_CDS_JAVA_HEAP

View File

@ -160,6 +160,7 @@ private:
#if INCLUDE_CDS_JAVA_HEAP
static bool _disable_writing;
static DumpedInternedStrings *_dumped_interned_strings;
static GrowableArrayCHeap<Metadata**, mtClassShared>* _native_pointers;
public:
static unsigned oop_hash(oop const& p);
@ -311,6 +312,8 @@ private:
static void init_loaded_heap_relocation(LoadedArchiveHeapRegion* reloc_info,
int num_loaded_regions);
static void fill_failed_loaded_region();
static void mark_native_pointers(oop orig_obj, oop archived_obj);
static void mark_one_native_pointer(oop archived_obj, int offset);
public:
static void reset_archived_object_states(TRAPS);
static void create_archived_object_cache(bool create_orig_table) {
@ -359,7 +362,8 @@ private:
oop orig_obj,
bool is_closed_archive);
static ResourceBitMap calculate_oopmap(MemRegion region);
static ResourceBitMap calculate_oopmap(MemRegion region); // marks all the oop pointers
static ResourceBitMap calculate_ptrmap(MemRegion region); // marks all the native pointers
static void add_to_dumped_interned_strings(oop string);
// We use the HeapShared::roots() array to make sure that objects stored in the

View File

@ -438,13 +438,15 @@ private:
GrowableArray<MemRegion> *_closed_heap_regions;
GrowableArray<MemRegion> *_open_heap_regions;
GrowableArray<ArchiveHeapOopmapInfo> *_closed_heap_oopmaps;
GrowableArray<ArchiveHeapOopmapInfo> *_open_heap_oopmaps;
GrowableArray<ArchiveHeapBitmapInfo> *_closed_heap_bitmaps;
GrowableArray<ArchiveHeapBitmapInfo> *_open_heap_bitmaps;
void dump_java_heap_objects(GrowableArray<Klass*>* klasses) NOT_CDS_JAVA_HEAP_RETURN;
void dump_heap_oopmaps() NOT_CDS_JAVA_HEAP_RETURN;
void dump_heap_oopmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps);
void dump_heap_bitmaps() NOT_CDS_JAVA_HEAP_RETURN;
void dump_heap_bitmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapBitmapInfo>* bitmaps);
void dump_one_heap_bitmap(MemRegion region, GrowableArray<ArchiveHeapBitmapInfo>* bitmaps,
ResourceBitMap bitmap, bool is_oopmap);
void dump_shared_symbol_table(GrowableArray<Symbol*>* symbols) {
log_info(cds)("Dumping symbol table ...");
SymbolTable::write_to_archive(symbols);
@ -457,8 +459,8 @@ public:
VM_GC_Operation(0 /* total collections, ignored */, GCCause::_archive_time_gc),
_closed_heap_regions(NULL),
_open_heap_regions(NULL),
_closed_heap_oopmaps(NULL),
_open_heap_oopmaps(NULL) {}
_closed_heap_bitmaps(NULL),
_open_heap_bitmaps(NULL) {}
bool skip_operation() const { return false; }
@ -504,7 +506,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
MetaspaceShared::serialize(&wc);
// Write the bitmaps for patching the archive heap regions
dump_heap_oopmaps();
dump_heap_bitmaps();
return start;
}
@ -566,8 +568,8 @@ void VM_PopulateDumpSharedSpace::doit() {
builder.write_archive(mapinfo,
_closed_heap_regions,
_open_heap_regions,
_closed_heap_oopmaps,
_open_heap_oopmaps);
_closed_heap_bitmaps,
_open_heap_bitmaps);
if (PrintSystemDictionaryAtExit) {
SystemDictionary::print();
@ -899,36 +901,55 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects(GrowableArray<Klass*>* k
HeapShared::write_subgraph_info_table();
}
void VM_PopulateDumpSharedSpace::dump_heap_oopmaps() {
void VM_PopulateDumpSharedSpace::dump_heap_bitmaps() {
if (HeapShared::can_write()) {
_closed_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
dump_heap_oopmaps(_closed_heap_regions, _closed_heap_oopmaps);
_closed_heap_bitmaps = new GrowableArray<ArchiveHeapBitmapInfo>(2);
dump_heap_bitmaps(_closed_heap_regions, _closed_heap_bitmaps);
_open_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
dump_heap_oopmaps(_open_heap_regions, _open_heap_oopmaps);
_open_heap_bitmaps = new GrowableArray<ArchiveHeapBitmapInfo>(2);
dump_heap_bitmaps(_open_heap_regions, _open_heap_bitmaps);
}
}
void VM_PopulateDumpSharedSpace::dump_heap_oopmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps) {
for (int i=0; i<regions->length(); i++) {
ResourceBitMap oopmap = HeapShared::calculate_oopmap(regions->at(i));
size_t size_in_bits = oopmap.size();
size_t size_in_bytes = oopmap.size_in_bytes();
uintptr_t* buffer = (uintptr_t*)NEW_C_HEAP_ARRAY(char, size_in_bytes, mtInternal);
oopmap.write_to(buffer, size_in_bytes);
log_info(cds, heap)("Oopmap = " INTPTR_FORMAT " (" SIZE_FORMAT_W(6) " bytes) for heap region "
INTPTR_FORMAT " (" SIZE_FORMAT_W(8) " bytes)",
p2i(buffer), size_in_bytes,
p2i(regions->at(i).start()), regions->at(i).byte_size());
ArchiveHeapOopmapInfo info;
info._oopmap = (address)buffer;
info._oopmap_size_in_bits = size_in_bits;
info._oopmap_size_in_bytes = size_in_bytes;
oopmaps->append(info);
void VM_PopulateDumpSharedSpace::dump_heap_bitmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapBitmapInfo>* bitmaps) {
for (int i = 0; i < regions->length(); i++) {
MemRegion region = regions->at(i);
ResourceBitMap oopmap = HeapShared::calculate_oopmap(region);
ResourceBitMap ptrmap = HeapShared::calculate_ptrmap(region);
dump_one_heap_bitmap(region, bitmaps, oopmap, true);
dump_one_heap_bitmap(region, bitmaps, ptrmap, false);
}
}
void VM_PopulateDumpSharedSpace::dump_one_heap_bitmap(MemRegion region,
GrowableArray<ArchiveHeapBitmapInfo>* bitmaps,
ResourceBitMap bitmap, bool is_oopmap) {
size_t size_in_bits = bitmap.size();
size_t size_in_bytes;
uintptr_t* buffer;
if (size_in_bits > 0) {
size_in_bytes = bitmap.size_in_bytes();
buffer = (uintptr_t*)NEW_C_HEAP_ARRAY(char, size_in_bytes, mtInternal);
bitmap.write_to(buffer, size_in_bytes);
} else {
size_in_bytes = 0;
buffer = NULL;
}
log_info(cds, heap)("%s = " INTPTR_FORMAT " (" SIZE_FORMAT_W(6) " bytes) for heap region "
INTPTR_FORMAT " (" SIZE_FORMAT_W(8) " bytes)",
is_oopmap ? "Oopmap" : "Ptrmap",
p2i(buffer), size_in_bytes,
p2i(region.start()), region.byte_size());
ArchiveHeapBitmapInfo info;
info._map = (address)buffer;
info._size_in_bits = size_in_bits;
info._size_in_bytes = size_in_bytes;
bitmaps->append(info);
}
#endif // INCLUDE_CDS_JAVA_HEAP
void MetaspaceShared::set_shared_metaspace_range(void* base, void *static_top, void* top) {

View File

@ -1117,21 +1117,6 @@ class ResetMirrorField: public FieldClosure {
}
};
static void set_klass_field_in_archived_mirror(oop mirror_obj, int offset, Klass* k) {
assert(java_lang_Class::is_instance(mirror_obj), "must be");
// this is the copy of k in the output buffer
Klass* copy = ArchiveBuilder::get_buffered_klass(k);
// This is the address of k, if the archive is loaded at the requested location
Klass* def = ArchiveBuilder::current()->to_requested(copy);
log_debug(cds, heap, mirror)(
"Relocate mirror metadata field at %d from " PTR_FORMAT " ==> " PTR_FORMAT,
offset, p2i(k), p2i(def));
mirror_obj->metadata_field_put(offset, def);
}
void java_lang_Class::archive_basic_type_mirrors() {
assert(HeapShared::can_write(), "must be");
@ -1142,11 +1127,6 @@ void java_lang_Class::archive_basic_type_mirrors() {
// Update the field at _array_klass_offset to point to the relocated array klass.
oop archived_m = HeapShared::archive_object(m);
assert(archived_m != NULL, "sanity");
Klass *ak = (Klass*)(archived_m->metadata_field(_array_klass_offset));
assert(ak != NULL || t == T_VOID, "should not be NULL");
if (ak != NULL) {
set_klass_field_in_archived_mirror(archived_m, _array_klass_offset, ak);
}
// Clear the fields. Just to be safe
Klass *k = m->klass();
@ -1260,47 +1240,9 @@ oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
set_class_loader(archived_mirror, NULL);
set_module(archived_mirror, NULL);
// The archived mirror's field at _klass_offset is still pointing to the original
// klass. Updated the field in the archived mirror to point to the relocated
// klass in the archive.
set_klass_field_in_archived_mirror(archived_mirror, _klass_offset, as_Klass(mirror));
// The field at _array_klass_offset is pointing to the original one dimension
// higher array klass if exists. Relocate the pointer.
Klass *arr = array_klass_acquire(mirror);
if (arr != NULL) {
set_klass_field_in_archived_mirror(archived_mirror, _array_klass_offset, arr);
}
return archived_mirror;
}
void java_lang_Class::update_archived_primitive_mirror_native_pointers(oop archived_mirror) {
if (MetaspaceShared::relocation_delta() != 0) {
assert(archived_mirror->metadata_field(_klass_offset) == NULL, "must be for primitive class");
Klass* ak = ((Klass*)archived_mirror->metadata_field(_array_klass_offset));
if (ak != NULL) {
archived_mirror->metadata_field_put(_array_klass_offset,
(Klass*)(address(ak) + MetaspaceShared::relocation_delta()));
}
}
}
void java_lang_Class::update_archived_mirror_native_pointers(oop archived_mirror) {
assert(MetaspaceShared::relocation_delta() != 0, "must be");
Klass* k = ((Klass*)archived_mirror->metadata_field(_klass_offset));
archived_mirror->metadata_field_put(_klass_offset,
(Klass*)(address(k) + MetaspaceShared::relocation_delta()));
Klass* ak = ((Klass*)archived_mirror->metadata_field(_array_klass_offset));
if (ak != NULL) {
archived_mirror->metadata_field_put(_array_klass_offset,
(Klass*)(address(ak) + MetaspaceShared::relocation_delta()));
}
}
// Returns true if the mirror is updated, false if no archived mirror
// data is present. After the archived mirror object is restored, the
// shared klass' _has_raw_archived_mirror flag is cleared.

View File

@ -253,8 +253,6 @@ class java_lang_Class : AllStatic {
Handle protection_domain, Handle classData, TRAPS);
static void fixup_mirror(Klass* k, TRAPS);
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
static void update_archived_primitive_mirror_native_pointers(oop archived_mirror) NOT_CDS_JAVA_HEAP_RETURN;
static void update_archived_mirror_native_pointers(oop archived_mirror) NOT_CDS_JAVA_HEAP_RETURN;
// Archiving
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;

View File

@ -1550,73 +1550,3 @@ void SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary() {
CleanupDumpTimeLambdaProxyClassTable cleanup_proxy_classes;
_dumptime_lambda_proxy_class_dictionary->unlink(&cleanup_proxy_classes);
}
#if INCLUDE_CDS_JAVA_HEAP
class ArchivedMirrorPatcher {
protected:
static void update(Klass* k) {
if (k->has_archived_mirror_index()) {
oop m = k->archived_java_mirror();
if (m != NULL) {
java_lang_Class::update_archived_mirror_native_pointers(m);
}
}
}
public:
static void update_array_klasses(Klass* ak) {
while (ak != NULL) {
update(ak);
ak = ArrayKlass::cast(ak)->higher_dimension();
}
}
void do_value(const RunTimeClassInfo* info) {
InstanceKlass* ik = info->_klass;
update(ik);
update_array_klasses(ik->array_klasses());
}
};
class ArchivedLambdaMirrorPatcher : public ArchivedMirrorPatcher {
public:
void do_value(const RunTimeLambdaProxyClassInfo* info) {
InstanceKlass* ik = info->proxy_klass_head();
while (ik != NULL) {
update(ik);
Klass* k = ik->next_link();
ik = (k != NULL) ? InstanceKlass::cast(k) : NULL;
}
}
};
void SystemDictionaryShared::update_archived_mirror_native_pointers_for(RunTimeSharedDictionary* dict) {
ArchivedMirrorPatcher patcher;
dict->iterate(&patcher);
}
void SystemDictionaryShared::update_archived_mirror_native_pointers_for(LambdaProxyClassDictionary* dict) {
ArchivedLambdaMirrorPatcher patcher;
dict->iterate(&patcher);
}
void SystemDictionaryShared::update_archived_mirror_native_pointers() {
if (!ArchiveHeapLoader::are_archived_mirrors_available()) {
return;
}
if (MetaspaceShared::relocation_delta() == 0) {
return;
}
// mirrors are not archived for the classes in the dynamic archive
update_archived_mirror_native_pointers_for(&_static_archive._builtin_dictionary);
update_archived_mirror_native_pointers_for(&_static_archive._unregistered_dictionary);
update_archived_mirror_native_pointers_for(&_static_archive._lambda_proxy_class_dictionary);
for (int t = T_BOOLEAN; t <= T_LONG; t++) {
Klass* k = Universe::typeArrayKlassObj((BasicType)t);
ArchivedMirrorPatcher::update_array_klasses(k);
}
ArchivedMirrorPatcher::update_array_klasses(Universe::fillerArrayKlassObj());
}
#endif

View File

@ -346,14 +346,6 @@ public:
}
static unsigned int hash_for_shared_dictionary(address ptr);
#if INCLUDE_CDS_JAVA_HEAP
private:
static void update_archived_mirror_native_pointers_for(RunTimeSharedDictionary* dict);
static void update_archived_mirror_native_pointers_for(LambdaProxyClassDictionary* dict);
public:
static void update_archived_mirror_native_pointers() NOT_CDS_RETURN;
#endif
};
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP

View File

@ -39,7 +39,7 @@
#define CDS_ARCHIVE_MAGIC 0xf00baba2
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13
#define CURRENT_CDS_ARCHIVE_VERSION 14
#define CURRENT_CDS_ARCHIVE_VERSION 15
typedef struct CDSFileMapRegion {
int _crc; // CRC checksum of this region.
@ -55,8 +55,12 @@ typedef struct CDSFileMapRegion {
// - for heap regions, the base address is the compressed oop encoding base
size_t _used; // Number of bytes actually used by this region (excluding padding bytes added
// for alignment purposed.
size_t _oopmap_offset; // Bitmap for relocating embedded oops (offset from SharedBaseAddress).
size_t _oopmap_offset; // Bitmap for relocating oop fields in archived heap objects.
// (The base address is the bottom of the BM region)
size_t _oopmap_size_in_bits;
size_t _ptrmap_offset; // Bitmap for relocating native pointer fields in archived heap objects.
// (The base address is the bottom of the BM region).
size_t _ptrmap_size_in_bits;
char* _mapped_base; // Actually mapped address (NULL if this region is not mapped).
} CDSFileMapRegion;

View File

@ -258,9 +258,6 @@ void Universe::serialize(SerializeClosure* f) {
}
f->do_oop(&mirror_oop); // write to archive
}
if (mirror_oop != NULL) { // may be null if archived heap is disabled
java_lang_Class::update_archived_primitive_mirror_native_pointers(mirror_oop);
}
}
}
#endif

View File

@ -63,7 +63,7 @@ public class ArchiveRelocationTest {
String mainClass = "Hello";
String forceRelocation = "-XX:ArchiveRelocationMode=1";
String runRelocArg = run_reloc ? forceRelocation : "-showversion";
String logArg = "-Xlog:cds=debug,cds+reloc=debug";
String logArg = "-Xlog:cds=debug,cds+reloc=debug,cds+heap";
String unlockArg = "-XX:+UnlockDiagnosticVMOptions";
String nmtArg = "-XX:NativeMemoryTracking=detail";
@ -76,6 +76,12 @@ public class ArchiveRelocationTest {
.assertNormalExit(output -> {
if (run_reloc) {
output.shouldContain("Try to map archive(s) at an alternative address");
if (output.getOutput().contains("Trying to map heap") || output.getOutput().contains("Loaded heap")) {
// The native data in the RO/RW regions have been relocated. If the CDS heap is
// mapped/loaded, we must patch all the native pointers. (CDS heap is
// not supported on all platforms)
output.shouldContain("Patching native pointers in heap region");
}
}
});
}

View File

@ -91,6 +91,23 @@ public class TestSerialGCWithCDS {
out.shouldContain(HELLO);
out.shouldHaveExitValue(0);
System.out.println("2. Exec with " + execGC + " and test ArchiveRelocationMode");
out = TestCommon.exec(helloJar,
execGC,
small1,
small2,
"-Xlog:cds,cds+heap",
"-XX:ArchiveRelocationMode=1", // always relocate shared metadata
"Hello");
out.shouldContain(HELLO);
if (out.getOutput().contains("Trying to map heap") || out.getOutput().contains("Loaded heap")) {
// The native data in the RO/RW regions have been relocated. If the CDS heap is
// mapped/loaded, we must patch all the native pointers. (CDS heap is
// not supported on all platforms)
out.shouldContain("Patching native pointers in heap region");
}
out.shouldHaveExitValue(0);
int n = 2;
if (dumpWithSerial == false && execWithSerial == true) {
// We dumped with G1, so we have an archived heap. At exec time, try to load them into