8307567: Avoid relocating global roots to metaspaceObjs in CDS dump

Reviewed-by: matsaave, ccheung
This commit is contained in:
Ioi Lam 2023-05-16 01:40:07 +00:00
parent 316837226e
commit 05b51c75b9
15 changed files with 172 additions and 213 deletions

View File

@ -236,7 +236,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
ResourceMark rm; ResourceMark rm;
log_info(cds)("Gathering classes and symbols ... "); log_info(cds)("Gathering classes and symbols ... ");
GatherKlassesAndSymbols doit(this); GatherKlassesAndSymbols doit(this);
iterate_roots(&doit, /*is_relocating_pointers=*/false); iterate_roots(&doit);
#if INCLUDE_CDS_JAVA_HEAP #if INCLUDE_CDS_JAVA_HEAP
if (is_dumping_full_module_graph()) { if (is_dumping_full_module_graph()) {
ClassLoaderDataShared::iterate_symbols(&doit); ClassLoaderDataShared::iterate_symbols(&doit);
@ -390,24 +390,18 @@ address ArchiveBuilder::reserve_buffer() {
return buffer_bottom; return buffer_bottom;
} }
void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers) { void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it) {
int i; int num_symbols = _symbols->length();
for (int i = 0; i < num_symbols; i++) {
if (!is_relocating_pointers) { it->push(_symbols->adr_at(i));
// Don't relocate _symbol, so we can safely call decrement_refcount on the
// original symbols.
int num_symbols = _symbols->length();
for (i = 0; i < num_symbols; i++) {
it->push(_symbols->adr_at(i));
}
} }
int num_klasses = _klasses->length(); int num_klasses = _klasses->length();
for (i = 0; i < num_klasses; i++) { for (int i = 0; i < num_klasses; i++) {
it->push(_klasses->adr_at(i)); it->push(_klasses->adr_at(i));
} }
iterate_roots(it, is_relocating_pointers); iterate_roots(it);
} }
class GatherSortedSourceObjs : public MetaspaceClosure { class GatherSortedSourceObjs : public MetaspaceClosure {
@ -422,7 +416,7 @@ public:
virtual void do_pending_ref(Ref* ref) { virtual void do_pending_ref(Ref* ref) {
if (ref->obj() != nullptr) { if (ref->obj() != nullptr) {
_builder->remember_embedded_pointer_in_copied_obj(enclosing_ref(), ref); _builder->remember_embedded_pointer_in_gathered_obj(enclosing_ref(), ref);
} }
} }
}; };
@ -434,7 +428,7 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref,
return false; return false;
} }
ref->set_keep_after_pushing(); ref->set_keep_after_pushing();
remember_embedded_pointer_in_copied_obj(enclosing_ref, ref); remember_embedded_pointer_in_gathered_obj(enclosing_ref, ref);
FollowMode follow_mode = get_follow_mode(ref); FollowMode follow_mode = get_follow_mode(ref);
SourceObjInfo src_info(ref, read_only, follow_mode); SourceObjInfo src_info(ref, read_only, follow_mode);
@ -461,8 +455,8 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref,
} }
} }
void ArchiveBuilder::remember_embedded_pointer_in_copied_obj(MetaspaceClosure::Ref* enclosing_ref, void ArchiveBuilder::remember_embedded_pointer_in_gathered_obj(MetaspaceClosure::Ref* enclosing_ref,
MetaspaceClosure::Ref* ref) { MetaspaceClosure::Ref* ref) {
assert(ref->obj() != nullptr, "should have checked"); assert(ref->obj() != nullptr, "should have checked");
if (enclosing_ref != nullptr) { if (enclosing_ref != nullptr) {
@ -485,7 +479,7 @@ void ArchiveBuilder::gather_source_objs() {
log_info(cds)("Gathering all archivable objects ... "); log_info(cds)("Gathering all archivable objects ... ");
gather_klasses_and_symbols(); gather_klasses_and_symbols();
GatherSortedSourceObjs doit(this); GatherSortedSourceObjs doit(this);
iterate_sorted_roots(&doit, /*is_relocating_pointers=*/false); iterate_sorted_roots(&doit);
doit.finish(); doit.finish();
} }
@ -639,6 +633,19 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
_alloc_stats.record(ref->msotype(), int(newtop - oldtop), src_info->read_only()); _alloc_stats.record(ref->msotype(), int(newtop - oldtop), src_info->read_only());
} }
// This is used by code that hand-assemble data structures, such as the LambdaProxyClassKey, that are
// not handled by MetaspaceClosure.
void ArchiveBuilder::write_pointer_in_buffer(address* ptr_location, address src_addr) {
assert(is_in_buffer_space(ptr_location), "must be");
if (src_addr == nullptr) {
*ptr_location = nullptr;
ArchivePtrMarker::clear_pointer(ptr_location);
} else {
*ptr_location = get_buffered_addr(src_addr);
ArchivePtrMarker::mark_pointer(ptr_location);
}
}
address ArchiveBuilder::get_buffered_addr(address src_addr) const { address ArchiveBuilder::get_buffered_addr(address src_addr) const {
SourceObjInfo* p = _src_obj_table.get(src_addr); SourceObjInfo* p = _src_obj_table.get(src_addr);
assert(p != nullptr, "must be"); assert(p != nullptr, "must be");
@ -659,46 +666,12 @@ void ArchiveBuilder::relocate_embedded_pointers(ArchiveBuilder::SourceObjList* s
} }
} }
class RefRelocator: public MetaspaceClosure {
ArchiveBuilder* _builder;
public:
RefRelocator(ArchiveBuilder* builder) : _builder(builder) {}
virtual bool do_ref(Ref* ref, bool read_only) {
if (ref->not_null()) {
ref->update(_builder->get_buffered_addr(ref->obj()));
ArchivePtrMarker::mark_pointer(ref->addr());
}
return false; // Do not recurse.
}
};
void ArchiveBuilder::relocate_roots() {
log_info(cds)("Relocating external roots ... ");
ResourceMark rm;
RefRelocator doit(this);
iterate_sorted_roots(&doit, /*is_relocating_pointers=*/true);
doit.finish();
log_info(cds)("done");
}
void ArchiveBuilder::relocate_metaspaceobj_embedded_pointers() { void ArchiveBuilder::relocate_metaspaceobj_embedded_pointers() {
log_info(cds)("Relocating embedded pointers in core regions ... "); log_info(cds)("Relocating embedded pointers in core regions ... ");
relocate_embedded_pointers(&_rw_src_objs); relocate_embedded_pointers(&_rw_src_objs);
relocate_embedded_pointers(&_ro_src_objs); relocate_embedded_pointers(&_ro_src_objs);
} }
// We must relocate vmClasses::_klasses[] only after we have copied the
// java objects in during dump_java_heap_objects(): during the object copy, we operate on
// old objects which assert that their klass is the original klass.
void ArchiveBuilder::relocate_vm_classes() {
log_info(cds)("Relocating vmClasses::_klasses[] ... ");
ResourceMark rm;
RefRelocator doit(this);
vmClasses::metaspace_pointers_do(&doit);
}
void ArchiveBuilder::make_klasses_shareable() { void ArchiveBuilder::make_klasses_shareable() {
int num_instance_klasses = 0; int num_instance_klasses = 0;
int num_boot_klasses = 0; int num_boot_klasses = 0;
@ -715,7 +688,7 @@ void ArchiveBuilder::make_klasses_shareable() {
const char* unlinked = ""; const char* unlinked = "";
const char* hidden = ""; const char* hidden = "";
const char* generated = ""; const char* generated = "";
Klass* k = klasses()->at(i); Klass* k = get_buffered_addr(klasses()->at(i));
k->remove_java_mirror(); k->remove_java_mirror();
if (k->is_objArray_klass()) { if (k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
@ -798,6 +771,10 @@ uintx ArchiveBuilder::any_to_offset(address p) const {
assert(DynamicDumpSharedSpaces, "must be"); assert(DynamicDumpSharedSpaces, "must be");
return p - _mapped_static_archive_bottom; return p - _mapped_static_archive_bottom;
} }
if (!is_in_buffer_space(p)) {
// p must be a "source" address
p = get_buffered_addr(p);
}
return buffer_to_offset(p); return buffer_to_offset(p);
} }

View File

@ -241,7 +241,7 @@ private:
bool is_dumping_full_module_graph(); bool is_dumping_full_module_graph();
FollowMode get_follow_mode(MetaspaceClosure::Ref *ref); FollowMode get_follow_mode(MetaspaceClosure::Ref *ref);
void iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers); void iterate_sorted_roots(MetaspaceClosure* it);
void sort_symbols_and_fix_hash(); void sort_symbols_and_fix_hash();
void sort_klasses(); void sort_klasses();
static int compare_symbols_by_address(Symbol** a, Symbol** b); static int compare_symbols_by_address(Symbol** a, Symbol** b);
@ -256,7 +256,7 @@ private:
void clean_up_src_obj_table(); void clean_up_src_obj_table();
protected: protected:
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) = 0; virtual void iterate_roots(MetaspaceClosure* it) = 0;
// Conservative estimate for number of bytes needed for: // Conservative estimate for number of bytes needed for:
size_t _estimated_metaspaceobj_bytes; // all archived MetaspaceObj's. size_t _estimated_metaspaceobj_bytes; // all archived MetaspaceObj's.
@ -303,6 +303,11 @@ public:
return current()->buffer_to_requested_delta(); return current()->buffer_to_requested_delta();
} }
inline static u4 to_offset_u4(uintx offset) {
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset);
return (u4)offset;
}
public: public:
static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF; static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
@ -317,15 +322,13 @@ public:
template <typename T> template <typename T>
u4 buffer_to_offset_u4(T p) const { u4 buffer_to_offset_u4(T p) const {
uintx offset = buffer_to_offset((address)p); uintx offset = buffer_to_offset((address)p);
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset); return to_offset_u4(offset);
return (u4)offset;
} }
template <typename T> template <typename T>
u4 any_to_offset_u4(T p) const { u4 any_to_offset_u4(T p) const {
uintx offset = any_to_offset((address)p); uintx offset = any_to_offset((address)p);
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset); return to_offset_u4(offset);
return (u4)offset;
} }
static void assert_is_vm_thread() PRODUCT_RETURN; static void assert_is_vm_thread() PRODUCT_RETURN;
@ -338,7 +341,7 @@ public:
void gather_source_objs(); void gather_source_objs();
bool gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool read_only); bool gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool read_only);
bool gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref, bool read_only); bool gather_one_source_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref, bool read_only);
void remember_embedded_pointer_in_copied_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref); void remember_embedded_pointer_in_gathered_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref);
DumpRegion* rw_region() { return &_rw_region; } DumpRegion* rw_region() { return &_rw_region; }
DumpRegion* ro_region() { return &_ro_region; } DumpRegion* ro_region() { return &_ro_region; }
@ -375,15 +378,22 @@ public:
void dump_rw_metadata(); void dump_rw_metadata();
void dump_ro_metadata(); void dump_ro_metadata();
void relocate_metaspaceobj_embedded_pointers(); void relocate_metaspaceobj_embedded_pointers();
void relocate_roots();
void relocate_vm_classes();
void make_klasses_shareable(); void make_klasses_shareable();
void relocate_to_requested(); void relocate_to_requested();
void write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info); void write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info);
void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,
bool read_only, bool allow_exec); bool read_only, bool allow_exec);
void write_pointer_in_buffer(address* ptr_location, address src_addr);
template <typename T> void write_pointer_in_buffer(T* ptr_location, T src_addr) {
write_pointer_in_buffer((address*)ptr_location, (address)src_addr);
}
address get_buffered_addr(address src_addr) const; address get_buffered_addr(address src_addr) const;
template <typename T> T get_buffered_addr(T src_addr) const {
return (T)get_buffered_addr((address)src_addr);
}
address get_source_addr(address buffered_addr) const; address get_source_addr(address buffered_addr) const;
template <typename T> T get_source_addr(T buffered_addr) const { template <typename T> T get_source_addr(T buffered_addr) const {
return (T)get_source_addr((address)buffered_addr); return (T)get_source_addr((address)buffered_addr);

View File

@ -262,6 +262,21 @@ void DumpRegion::pack(DumpRegion* next) {
} }
} }
void WriteClosure::do_ptr(void** p) {
// Write ptr into the archive; ptr can be:
// (a) null -> written as 0
// (b) a "buffered" address -> written as is
// (c) a "source" address -> convert to "buffered" and write
// The common case is (c). E.g., when writing the vmClasses into the archive.
// We have (b) only when we don't have a corresponding source object. E.g.,
// the archived c++ vtable entries.
address ptr = *(address*)p;
if (ptr != nullptr && !ArchiveBuilder::current()->is_in_buffer_space(ptr)) {
ptr = ArchiveBuilder::current()->get_buffered_addr(ptr);
}
_dump_region->append_intptr_t((intptr_t)ptr, true);
}
void WriteClosure::do_oop(oop* o) { void WriteClosure::do_oop(oop* o) {
if (*o == nullptr) { if (*o == nullptr) {
_dump_region->append_intptr_t(0); _dump_region->append_intptr_t(0);
@ -282,7 +297,7 @@ void WriteClosure::do_region(u_char* start, size_t size) {
assert(size % sizeof(intptr_t) == 0, "bad size"); assert(size % sizeof(intptr_t) == 0, "bad size");
do_tag((int)size); do_tag((int)size);
while (size > 0) { while (size > 0) {
_dump_region->append_intptr_t(*(intptr_t*)start, true); do_ptr((void**)start);
start += sizeof(intptr_t); start += sizeof(intptr_t);
size -= sizeof(intptr_t); size -= sizeof(intptr_t);
} }

View File

@ -184,9 +184,7 @@ public:
_dump_region = r; _dump_region = r;
} }
void do_ptr(void** p) { void do_ptr(void** p);
_dump_region->append_intptr_t((intptr_t)*p, true);
}
void do_u4(u4* p) { void do_u4(u4* p) {
_dump_region->append_intptr_t((intptr_t)(*p)); _dump_region->append_intptr_t((intptr_t)(*p));

View File

@ -253,6 +253,7 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
case MetaspaceObj::ConstantPoolCacheType: case MetaspaceObj::ConstantPoolCacheType:
case MetaspaceObj::AnnotationsType: case MetaspaceObj::AnnotationsType:
case MetaspaceObj::MethodCountersType: case MetaspaceObj::MethodCountersType:
case MetaspaceObj::SharedClassPathEntryType:
case MetaspaceObj::RecordComponentType: case MetaspaceObj::RecordComponentType:
// These have no vtables. // These have no vtables.
break; break;
@ -268,7 +269,7 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
} }
if (kind >= _num_cloned_vtable_kinds) { if (kind >= _num_cloned_vtable_kinds) {
fatal("Cannot find C++ vtable for " INTPTR_FORMAT " -- you probably added" fatal("Cannot find C++ vtable for " INTPTR_FORMAT " -- you probably added"
" a new subtype of Klass or MetaData without updating CPP_VTABLE_TYPES_DO", " a new subtype of Klass or MetaData without updating CPP_VTABLE_TYPES_DO or the cases in this 'switch' statement",
p2i(obj)); p2i(obj));
} }
} }

View File

@ -129,7 +129,6 @@ public:
dump_rw_metadata(); dump_rw_metadata();
dump_ro_metadata(); dump_ro_metadata();
relocate_metaspaceobj_embedded_pointers(); relocate_metaspaceobj_embedded_pointers();
relocate_roots();
verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs"); verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs");
@ -175,7 +174,7 @@ public:
verify_universe("After CDS dynamic dump"); verify_universe("After CDS dynamic dump");
} }
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { virtual void iterate_roots(MetaspaceClosure* it) {
FileMapInfo::metaspace_pointers_do(it); FileMapInfo::metaspace_pointers_do(it);
SystemDictionaryShared::dumptime_classes_do(it); SystemDictionaryShared::dumptime_classes_do(it);
} }
@ -216,7 +215,7 @@ void DynamicArchiveBuilder::post_dump() {
void DynamicArchiveBuilder::sort_methods() { void DynamicArchiveBuilder::sort_methods() {
InstanceKlass::disable_method_binary_search(); InstanceKlass::disable_method_binary_search();
for (int i = 0; i < klasses()->length(); i++) { for (int i = 0; i < klasses()->length(); i++) {
Klass* k = klasses()->at(i); Klass* k = get_buffered_addr(klasses()->at(i));
if (k->is_instance_klass()) { if (k->is_instance_klass()) {
sort_methods(InstanceKlass::cast(k)); sort_methods(InstanceKlass::cast(k));
} }
@ -231,7 +230,7 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
// We have reached a supertype that's already in the base archive // We have reached a supertype that's already in the base archive
return; return;
} }
assert(is_in_buffer_space(ik), "method sorting must be done on buffered class, not original class");
if (ik->java_mirror() == nullptr) { if (ik->java_mirror() == nullptr) {
// null mirror means this class has already been visited and methods are already sorted // null mirror means this class has already been visited and methods are already sorted
return; return;
@ -315,9 +314,7 @@ void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k,
} }
void DynamicArchiveBuilder::write_archive(char* serialized_data) { void DynamicArchiveBuilder::write_archive(char* serialized_data) {
Array<u8>* table = FileMapInfo::saved_shared_path_table().table(); _header->set_shared_path_table(FileMapInfo::shared_path_table().table());
SharedPathTable runtime_table(table, FileMapInfo::shared_path_table().size());
_header->set_shared_path_table(runtime_table);
_header->set_serialized_data(serialized_data); _header->set_serialized_data(serialized_data);
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
@ -394,7 +391,6 @@ void DynamicArchive::dump_at_exit(JavaThread* current, const char* archive_name)
MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD); MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD);
if (!HAS_PENDING_EXCEPTION) { if (!HAS_PENDING_EXCEPTION) {
// copy shared path table to saved. // copy shared path table to saved.
FileMapInfo::clone_shared_path_table(current);
if (!HAS_PENDING_EXCEPTION) { if (!HAS_PENDING_EXCEPTION) {
VM_PopulateDynamicDumpSharedSpace op(archive_name); VM_PopulateDynamicDumpSharedSpace op(archive_name);
VMThread::execute(&op); VMThread::execute(&op);
@ -418,7 +414,6 @@ void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) {
assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup"); assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup");
MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK); MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK);
// copy shared path table to saved. // copy shared path table to saved.
FileMapInfo::clone_shared_path_table(CHECK);
VM_PopulateDynamicDumpSharedSpace op(archive_name); VM_PopulateDynamicDumpSharedSpace op(archive_name);
VMThread::execute(&op); VMThread::execute(&op);
} }

View File

@ -292,7 +292,6 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end)); st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
st->print_cr("- jvm_ident: %s", _jvm_ident); st->print_cr("- jvm_ident: %s", _jvm_ident);
st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset); st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset);
st->print_cr("- shared_path_table_size: %d", _shared_path_table_size);
st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index); st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index);
st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index); st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index);
st->print_cr("- num_module_paths: %d", _num_module_paths); st->print_cr("- num_module_paths: %d", _num_module_paths);
@ -453,64 +452,27 @@ bool SharedClassPathEntry::check_non_existent() const {
} }
} }
void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) { void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_name); it->push(&_name);
it->push(&_manifest); it->push(&_manifest);
} }
void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) { void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_table); it->push(&_entries);
for (int i=0; i<_size; i++) {
path_at(i)->metaspace_pointers_do(it);
}
} }
void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) { void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) {
size_t entry_size = sizeof(SharedClassPathEntry); const int num_entries =
int num_entries = 0; ClassLoader::num_boot_classpath_entries() +
num_entries += ClassLoader::num_boot_classpath_entries(); ClassLoader::num_app_classpath_entries() +
num_entries += ClassLoader::num_app_classpath_entries(); ClassLoader::num_module_path_entries() +
num_entries += ClassLoader::num_module_path_entries(); FileMapInfo::num_non_existent_class_paths();
num_entries += FileMapInfo::num_non_existent_class_paths(); _entries = MetadataFactory::new_array<SharedClassPathEntry*>(loader_data, num_entries, CHECK);
size_t bytes = entry_size * num_entries; for (int i = 0; i < num_entries; i++) {
SharedClassPathEntry* ent =
_table = MetadataFactory::new_array<u8>(loader_data, (int)bytes, CHECK); new (loader_data, SharedClassPathEntry::size(), MetaspaceObj::SharedClassPathEntryType, THREAD) SharedClassPathEntry;
_size = num_entries; _entries->at_put(i, ent);
}
// Make a copy of the _shared_path_table for use during dynamic CDS dump.
// It is needed because some Java code continues to execute after dynamic dump has finished.
// However, during dynamic dump, we have modified FileMapInfo::_shared_path_table so
// FileMapInfo::shared_path(i) returns incorrect information in ClassLoader::record_result().
void FileMapInfo::copy_shared_path_table(ClassLoaderData* loader_data, TRAPS) {
size_t entry_size = sizeof(SharedClassPathEntry);
size_t bytes = entry_size * _shared_path_table.size();
Array<u8>* array = MetadataFactory::new_array<u8>(loader_data, (int)bytes, CHECK);
_saved_shared_path_table = SharedPathTable(array, _shared_path_table.size());
for (int i = 0; i < _shared_path_table.size(); i++) {
_saved_shared_path_table.path_at(i)->copy_from(shared_path(i), loader_data, CHECK);
} }
_saved_shared_path_table_array = array;
}
void FileMapInfo::clone_shared_path_table(TRAPS) {
Arguments::assert_is_dumping_archive();
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
assert(jrt != nullptr,
"No modular java runtime image present when allocating the CDS classpath entry table");
if (_saved_shared_path_table_array != nullptr) {
MetadataFactory::free_array<u8>(loader_data, _saved_shared_path_table_array);
_saved_shared_path_table_array = nullptr;
}
copy_shared_path_table(loader_data, CHECK);
} }
void FileMapInfo::allocate_shared_path_table(TRAPS) { void FileMapInfo::allocate_shared_path_table(TRAPS) {
@ -536,7 +498,6 @@ void FileMapInfo::allocate_shared_path_table(TRAPS) {
} }
assert(i == _shared_path_table.size(), "number of shared path entry mismatch"); assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
clone_shared_path_table(CHECK);
} }
int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) { int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) {
@ -2328,20 +2289,10 @@ void FileMapInfo::assert_mark(bool check) {
} }
} }
void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it, bool use_copy) {
if (use_copy) {
_saved_shared_path_table.metaspace_pointers_do(it);
} else {
_shared_path_table.metaspace_pointers_do(it);
}
}
FileMapInfo* FileMapInfo::_current_info = nullptr; FileMapInfo* FileMapInfo::_current_info = nullptr;
FileMapInfo* FileMapInfo::_dynamic_archive_info = nullptr; FileMapInfo* FileMapInfo::_dynamic_archive_info = nullptr;
bool FileMapInfo::_heap_pointers_need_patching = false; bool FileMapInfo::_heap_pointers_need_patching = false;
SharedPathTable FileMapInfo::_shared_path_table; SharedPathTable FileMapInfo::_shared_path_table;
SharedPathTable FileMapInfo::_saved_shared_path_table;
Array<u8>* FileMapInfo::_saved_shared_path_table_array = nullptr;
bool FileMapInfo::_validating_shared_path_table = false; bool FileMapInfo::_validating_shared_path_table = false;
bool FileMapInfo::_memory_mapping_failed = false; bool FileMapInfo::_memory_mapping_failed = false;
GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = nullptr; GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = nullptr;

View File

@ -28,6 +28,7 @@
#include "cds/metaspaceShared.hpp" #include "cds/metaspaceShared.hpp"
#include "include/cds.h" #include "include/cds.h"
#include "logging/logLevel.hpp" #include "logging/logLevel.hpp"
#include "memory/allocation.hpp"
#include "oops/array.hpp" #include "oops/array.hpp"
#include "oops/compressedOops.hpp" #include "oops/compressedOops.hpp"
#include "utilities/align.hpp" #include "utilities/align.hpp"
@ -48,7 +49,7 @@ class ClassLoaderData;
class ClassPathEntry; class ClassPathEntry;
class outputStream; class outputStream;
class SharedClassPathEntry { class SharedClassPathEntry : public MetaspaceObj {
enum { enum {
modules_image_entry, modules_image_entry,
jar_entry, jar_entry,
@ -69,9 +70,17 @@ class SharedClassPathEntry {
Array<u1>* _manifest; Array<u1>* _manifest;
public: public:
SharedClassPathEntry() : _type(0), _is_module_path(false),
_from_class_path_attr(false), _timestamp(0),
_filesize(0), _name(nullptr), _manifest(nullptr) {}
static int size() {
static_assert(is_aligned(sizeof(SharedClassPathEntry), wordSize), "must be");
return (int)(sizeof(SharedClassPathEntry) / wordSize);
}
void init(bool is_modules_image, bool is_module_path, ClassPathEntry* cpe, TRAPS); void init(bool is_modules_image, bool is_module_path, ClassPathEntry* cpe, TRAPS);
void init_as_non_existent(const char* path, TRAPS); void init_as_non_existent(const char* path, TRAPS);
void metaspace_pointers_do(MetaspaceClosure* it); void metaspace_pointers_do(MetaspaceClosure* it);
MetaspaceObj::Type type() const { return SharedClassPathEntryType; }
bool validate(bool is_class_path = true) const; bool validate(bool is_class_path = true) const;
// The _timestamp only gets set for jar files. // The _timestamp only gets set for jar files.
@ -106,29 +115,22 @@ public:
}; };
class SharedPathTable { class SharedPathTable {
Array<u8>* _table; Array<SharedClassPathEntry*>* _entries;
int _size;
public: public:
SharedPathTable() : _table(nullptr), _size(0) {} SharedPathTable() : _entries(nullptr) {}
SharedPathTable(Array<u8>* table, int size) : _table(table), _size(size) {} SharedPathTable(Array<SharedClassPathEntry*>* entries) : _entries(entries) {}
void dumptime_init(ClassLoaderData* loader_data, TRAPS); void dumptime_init(ClassLoaderData* loader_data, TRAPS);
void metaspace_pointers_do(MetaspaceClosure* it); void metaspace_pointers_do(MetaspaceClosure* it);
int size() { int size() {
return _size; return _entries == nullptr ? 0 : _entries->length();
} }
SharedClassPathEntry* path_at(int index) { SharedClassPathEntry* path_at(int index) {
if (index < 0) { return _entries->at(index);
return nullptr;
}
assert(index < _size, "sanity");
char* p = (char*)_table->data();
p += sizeof(SharedClassPathEntry) * index;
return (SharedClassPathEntry*)p;
} }
Array<u8>* table() {return _table;} Array<SharedClassPathEntry*>* table() {return _entries;}
void set_table(Array<u8>* table) {_table = table;} void set_table(Array<SharedClassPathEntry*>* table) {_entries = table;}
}; };
@ -215,7 +217,6 @@ private:
// validate_shared_path_table() // validate_shared_path_table()
// validate_non_existent_class_paths() // validate_non_existent_class_paths()
size_t _shared_path_table_offset; size_t _shared_path_table_offset;
int _shared_path_table_size;
jshort _app_class_paths_start_index; // Index of first app classpath entry jshort _app_class_paths_start_index; // Index of first app classpath entry
jshort _app_module_paths_start_index; // Index of first module path entry jshort _app_module_paths_start_index; // Index of first module path entry
@ -290,7 +291,6 @@ public:
void set_shared_path_table(SharedPathTable table) { void set_shared_path_table(SharedPathTable table) {
set_as_offset((char*)table.table(), &_shared_path_table_offset); set_as_offset((char*)table.table(), &_shared_path_table_offset);
_shared_path_table_size = table.size();
} }
void set_requested_base(char* b) { void set_requested_base(char* b) {
@ -299,8 +299,8 @@ public:
} }
SharedPathTable shared_path_table() const { SharedPathTable shared_path_table() const {
return SharedPathTable((Array<u8>*)from_mapped_offset(_shared_path_table_offset), return SharedPathTable((Array<SharedClassPathEntry*>*)
_shared_path_table_size); from_mapped_offset(_shared_path_table_offset));
} }
bool validate(); bool validate();
@ -338,10 +338,7 @@ private:
const char* _base_archive_name; const char* _base_archive_name;
FileMapHeader* _header; FileMapHeader* _header;
// TODO: Probably change the following to be non-static
static SharedPathTable _shared_path_table; static SharedPathTable _shared_path_table;
static SharedPathTable _saved_shared_path_table;
static Array<u8>* _saved_shared_path_table_array; // remember the table array for cleanup
static bool _validating_shared_path_table; static bool _validating_shared_path_table;
// FileMapHeader describes the shared space data in the file to be // FileMapHeader describes the shared space data in the file to be
@ -361,13 +358,11 @@ public:
static SharedPathTable shared_path_table() { static SharedPathTable shared_path_table() {
return _shared_path_table; return _shared_path_table;
} }
static SharedPathTable saved_shared_path_table() {
assert(_saved_shared_path_table.size() >= 0, "Sanity check");
return _saved_shared_path_table;
}
bool init_from_file(int fd); bool init_from_file(int fd);
static void metaspace_pointers_do(MetaspaceClosure* it, bool use_copy = true); static void metaspace_pointers_do(MetaspaceClosure* it) {
_shared_path_table.metaspace_pointers_do(it);
}
void log_paths(const char* msg, int start_idx, int end_idx); void log_paths(const char* msg, int start_idx, int end_idx);

View File

@ -26,6 +26,7 @@
#include "cds/archiveBuilder.hpp" #include "cds/archiveBuilder.hpp"
#include "cds/lambdaProxyClassDictionary.hpp" #include "cds/lambdaProxyClassDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp" #include "classfile/systemDictionaryShared.hpp"
#include "memory/resourceArea.hpp"
// This constructor is used only by SystemDictionaryShared::clone_dumptime_tables(). // This constructor is used only by SystemDictionaryShared::clone_dumptime_tables().
// See comments there about the need for making a deep copy. // See comments there about the need for making a deep copy.
@ -46,13 +47,15 @@ DumpTimeLambdaProxyClassInfo::~DumpTimeLambdaProxyClassInfo() {
} }
} }
void LambdaProxyClassKey::mark_pointers() { void LambdaProxyClassKey::init_for_archive(LambdaProxyClassKey& dumptime_key) {
ArchivePtrMarker::mark_pointer(&_caller_ik); ArchiveBuilder* b = ArchiveBuilder::current();
ArchivePtrMarker::mark_pointer(&_instantiated_method_type);
ArchivePtrMarker::mark_pointer(&_invoked_name); b->write_pointer_in_buffer(&_caller_ik, dumptime_key._caller_ik);
ArchivePtrMarker::mark_pointer(&_invoked_type); b->write_pointer_in_buffer(&_instantiated_method_type, dumptime_key._instantiated_method_type);
ArchivePtrMarker::mark_pointer(&_member_method); b->write_pointer_in_buffer(&_invoked_name, dumptime_key._invoked_name);
ArchivePtrMarker::mark_pointer(&_method_type); b->write_pointer_in_buffer(&_invoked_type, dumptime_key._invoked_type);
b->write_pointer_in_buffer(&_member_method, dumptime_key._member_method);
b->write_pointer_in_buffer(&_method_type, dumptime_key._method_type);
} }
unsigned int LambdaProxyClassKey::hash() const { unsigned int LambdaProxyClassKey::hash() const {
@ -62,3 +65,26 @@ unsigned int LambdaProxyClassKey::hash() const {
SystemDictionaryShared::hash_for_shared_dictionary((address)_method_type) + SystemDictionaryShared::hash_for_shared_dictionary((address)_method_type) +
SystemDictionaryShared::hash_for_shared_dictionary((address)_instantiated_method_type); SystemDictionaryShared::hash_for_shared_dictionary((address)_instantiated_method_type);
} }
#ifndef PRODUCT
void LambdaProxyClassKey::print_on(outputStream* st) const {
ResourceMark rm;
st->print_cr("LambdaProxyClassKey : " INTPTR_FORMAT " hash: %0x08x", p2i(this), hash());
st->print_cr("_caller_ik : %s", _caller_ik->external_name());
st->print_cr("_instantiated_method_type : %s", _instantiated_method_type->as_C_string());
st->print_cr("_invoked_name : %s", _invoked_name->as_C_string());
st->print_cr("_invoked_type : %s", _invoked_type->as_C_string());
st->print_cr("_member_method : %s", _member_method->name()->as_C_string());
st->print_cr("_method_type : %s", _method_type->as_C_string());
}
void RunTimeLambdaProxyClassInfo::print_on(outputStream* st) const {
_key.print_on(st);
}
#endif
void RunTimeLambdaProxyClassInfo::init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
_key.init_for_archive(key);
ArchiveBuilder::current()->write_pointer_in_buffer(&_proxy_klass_head,
info._proxy_klasses->at(0));
}

View File

@ -32,6 +32,7 @@
class InstanceKlass; class InstanceKlass;
class Method; class Method;
class Symbol; class Symbol;
class outputStream;
class LambdaProxyClassKey { class LambdaProxyClassKey {
InstanceKlass* _caller_ik; InstanceKlass* _caller_ik;
@ -73,7 +74,6 @@ public:
_instantiated_method_type == other._instantiated_method_type; _instantiated_method_type == other._instantiated_method_type;
} }
void mark_pointers();
unsigned int hash() const; unsigned int hash() const;
static unsigned int dumptime_hash(Symbol* sym) { static unsigned int dumptime_hash(Symbol* sym) {
@ -102,6 +102,12 @@ public:
} }
InstanceKlass* caller_ik() const { return _caller_ik; } InstanceKlass* caller_ik() const { return _caller_ik; }
void init_for_archive(LambdaProxyClassKey& dumptime_key);
#ifndef PRODUCT
void print_on(outputStream* st) const;
#endif
}; };
class DumpTimeLambdaProxyClassInfo { class DumpTimeLambdaProxyClassInfo {
@ -141,12 +147,7 @@ public:
const RunTimeLambdaProxyClassInfo* value, LambdaProxyClassKey* key, int len_unused) { const RunTimeLambdaProxyClassInfo* value, LambdaProxyClassKey* key, int len_unused) {
return (value->_key.equals(*key)); return (value->_key.equals(*key));
} }
void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) { void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info);
_key = key;
_key.mark_pointers();
_proxy_klass_head = info._proxy_klasses->at(0);
ArchivePtrMarker::mark_pointer(&_proxy_klass_head);
}
unsigned int hash() const { unsigned int hash() const {
return _key.hash(); return _key.hash();
@ -154,6 +155,9 @@ public:
LambdaProxyClassKey key() const { LambdaProxyClassKey key() const {
return _key; return _key;
} }
#ifndef PRODUCT
void print_on(outputStream* st) const;
#endif
}; };
class DumpTimeLambdaProxyClassDictionary class DumpTimeLambdaProxyClassDictionary

View File

@ -451,8 +451,8 @@ class StaticArchiveBuilder : public ArchiveBuilder {
public: public:
StaticArchiveBuilder() : ArchiveBuilder() {} StaticArchiveBuilder() : ArchiveBuilder() {}
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { virtual void iterate_roots(MetaspaceClosure* it) {
FileMapInfo::metaspace_pointers_do(it, false); FileMapInfo::metaspace_pointers_do(it);
SystemDictionaryShared::dumptime_classes_do(it); SystemDictionaryShared::dumptime_classes_do(it);
Universe::metaspace_pointers_do(it); Universe::metaspace_pointers_do(it);
vmSymbols::metaspace_pointers_do(it); vmSymbols::metaspace_pointers_do(it);
@ -507,14 +507,9 @@ void VM_PopulateDumpSharedSpace::doit() {
builder.dump_ro_metadata(); builder.dump_ro_metadata();
builder.relocate_metaspaceobj_embedded_pointers(); builder.relocate_metaspaceobj_embedded_pointers();
// Dump supported java heap objects
dump_java_heap_objects(builder.klasses()); dump_java_heap_objects(builder.klasses());
builder.relocate_roots();
dump_shared_symbol_table(builder.symbols()); dump_shared_symbol_table(builder.symbols());
builder.relocate_vm_classes();
log_info(cds)("Make classes shareable"); log_info(cds)("Make classes shareable");
builder.make_klasses_shareable(); builder.make_klasses_shareable();
@ -588,8 +583,7 @@ bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) {
// that may not be expected by custom class loaders. // that may not be expected by custom class loaders.
// //
// It's OK to do this for the built-in loaders as we know they can // It's OK to do this for the built-in loaders as we know they can
// tolerate this. (Note that unregistered classes are loaded by the null // tolerate this.
// loader during DumpSharedSpaces).
return false; return false;
} }
return true; return true;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2023, 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
@ -30,8 +30,8 @@
void RunTimeClassInfo::init(DumpTimeClassInfo& info) { void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
ArchiveBuilder* builder = ArchiveBuilder::current(); ArchiveBuilder* builder = ArchiveBuilder::current();
assert(builder->is_in_buffer_space(info._klass), "must be"); builder->write_pointer_in_buffer(&_klass, info._klass);
_klass = info._klass;
if (!SystemDictionaryShared::is_builtin(_klass)) { if (!SystemDictionaryShared::is_builtin(_klass)) {
CrcInfo* c = crc(); CrcInfo* c = crc();
c->_clsfile_size = info._clsfile_size; c->_clsfile_size = info._clsfile_size;
@ -62,8 +62,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
} }
if (_klass->is_hidden()) { if (_klass->is_hidden()) {
InstanceKlass* n_h = info.nest_host(); builder->write_pointer_in_buffer(nest_host_addr(), info.nest_host());
set_nest_host(n_h);
} }
if (_klass->has_archived_enum_objs()) { if (_klass->has_archived_enum_objs()) {
int num = info.num_enum_klass_static_fields(); int num = info.num_enum_klass_static_fields();
@ -73,8 +72,6 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
set_enum_klass_static_field_root_index_at(i, root_index); set_enum_klass_static_field_root_index_at(i, root_index);
} }
} }
ArchivePtrMarker::mark_pointer(&_klass);
} }
size_t RunTimeClassInfo::crc_size(InstanceKlass* klass) { size_t RunTimeClassInfo::crc_size(InstanceKlass* klass) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2023, 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
@ -180,10 +180,6 @@ public:
InstanceKlass* nest_host() { InstanceKlass* nest_host() {
return *nest_host_addr(); return *nest_host_addr();
} }
void set_nest_host(InstanceKlass* k) {
*nest_host_addr() = k;
ArchivePtrMarker::mark_pointer((address*)nest_host_addr());
}
RTLoaderConstraint* loader_constraints() { RTLoaderConstraint* loader_constraints() {
assert(_num_loader_constraints > 0, "sanity"); assert(_num_loader_constraints > 0, "sanity");

View File

@ -1166,22 +1166,19 @@ public:
AdjustLambdaProxyClassInfo() {} AdjustLambdaProxyClassInfo() {}
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) { bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
int len = info._proxy_klasses->length(); int len = info._proxy_klasses->length();
if (len > 1) { InstanceKlass* last_buff_k = nullptr;
for (int i = 0; i < len-1; i++) {
InstanceKlass* ok0 = info._proxy_klasses->at(i+0); // this is original klass for (int i = len - 1; i >= 0; i--) {
InstanceKlass* ok1 = info._proxy_klasses->at(i+1); // this is original klass InstanceKlass* orig_k = info._proxy_klasses->at(i);
assert(ArchiveBuilder::current()->is_in_buffer_space(ok0), "must be"); InstanceKlass* buff_k = ArchiveBuilder::current()->get_buffered_addr(orig_k);
assert(ArchiveBuilder::current()->is_in_buffer_space(ok1), "must be"); assert(ArchiveBuilder::current()->is_in_buffer_space(buff_k), "must be");
InstanceKlass* bk0 = ok0; buff_k->set_lambda_proxy_is_available();
InstanceKlass* bk1 = ok1; buff_k->set_next_link(last_buff_k);
assert(bk0->next_link() == 0, "must be called after Klass::remove_unshareable_info()"); if (last_buff_k != nullptr) {
assert(bk1->next_link() == 0, "must be called after Klass::remove_unshareable_info()"); ArchivePtrMarker::mark_pointer(buff_k->next_link_addr());
bk0->set_next_link(bk1);
bk1->set_lambda_proxy_is_available();
ArchivePtrMarker::mark_pointer(bk0->next_link_addr());
} }
last_buff_k = buff_k;
} }
info._proxy_klasses->at(0)->set_lambda_proxy_is_available();
return true; return true;
} }
@ -1205,6 +1202,7 @@ public:
unsigned int hash; unsigned int hash;
Symbol* name = info._klass->name(); Symbol* name = info._klass->name();
name = ArchiveBuilder::current()->get_buffered_addr(name);
hash = SystemDictionaryShared::hash_for_shared_dictionary((address)name); hash = SystemDictionaryShared::hash_for_shared_dictionary((address)name);
u4 delta = _builder->buffer_to_offset_u4((address)record); u4 delta = _builder->buffer_to_offset_u4((address)record);
if (_is_builtin && info._klass->is_hidden()) { if (_is_builtin && info._klass->is_hidden()) {
@ -1218,7 +1216,8 @@ public:
} }
// Save this for quick runtime lookup of InstanceKlass* -> RunTimeClassInfo* // Save this for quick runtime lookup of InstanceKlass* -> RunTimeClassInfo*
RunTimeClassInfo::set_for(info._klass, record); InstanceKlass* buffered_klass = ArchiveBuilder::current()->get_buffered_addr(info._klass);
RunTimeClassInfo::set_for(buffered_klass, record);
} }
} }
}; };

View File

@ -370,6 +370,7 @@ class MetaspaceObj {
f(ConstantPoolCache) \ f(ConstantPoolCache) \
f(Annotations) \ f(Annotations) \
f(MethodCounters) \ f(MethodCounters) \
f(SharedClassPathEntry) \
f(RecordComponent) f(RecordComponent)
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,