8307567: Avoid relocating global roots to metaspaceObjs in CDS dump
Reviewed-by: matsaave, ccheung
This commit is contained in:
parent
316837226e
commit
05b51c75b9
@ -236,7 +236,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
|
||||
ResourceMark rm;
|
||||
log_info(cds)("Gathering classes and symbols ... ");
|
||||
GatherKlassesAndSymbols doit(this);
|
||||
iterate_roots(&doit, /*is_relocating_pointers=*/false);
|
||||
iterate_roots(&doit);
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
if (is_dumping_full_module_graph()) {
|
||||
ClassLoaderDataShared::iterate_symbols(&doit);
|
||||
@ -390,24 +390,18 @@ address ArchiveBuilder::reserve_buffer() {
|
||||
return buffer_bottom;
|
||||
}
|
||||
|
||||
void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers) {
|
||||
int i;
|
||||
|
||||
if (!is_relocating_pointers) {
|
||||
// Don't relocate _symbol, so we can safely call decrement_refcount on the
|
||||
// original symbols.
|
||||
void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it) {
|
||||
int num_symbols = _symbols->length();
|
||||
for (i = 0; i < num_symbols; i++) {
|
||||
for (int i = 0; i < num_symbols; i++) {
|
||||
it->push(_symbols->adr_at(i));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
iterate_roots(it, is_relocating_pointers);
|
||||
iterate_roots(it);
|
||||
}
|
||||
|
||||
class GatherSortedSourceObjs : public MetaspaceClosure {
|
||||
@ -422,7 +416,7 @@ public:
|
||||
|
||||
virtual void do_pending_ref(Ref* ref) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
SourceObjInfo src_info(ref, read_only, follow_mode);
|
||||
@ -461,7 +455,7 @@ 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) {
|
||||
assert(ref->obj() != nullptr, "should have checked");
|
||||
|
||||
@ -485,7 +479,7 @@ void ArchiveBuilder::gather_source_objs() {
|
||||
log_info(cds)("Gathering all archivable objects ... ");
|
||||
gather_klasses_and_symbols();
|
||||
GatherSortedSourceObjs doit(this);
|
||||
iterate_sorted_roots(&doit, /*is_relocating_pointers=*/false);
|
||||
iterate_sorted_roots(&doit);
|
||||
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());
|
||||
}
|
||||
|
||||
// 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 {
|
||||
SourceObjInfo* p = _src_obj_table.get(src_addr);
|
||||
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() {
|
||||
log_info(cds)("Relocating embedded pointers in core regions ... ");
|
||||
relocate_embedded_pointers(&_rw_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() {
|
||||
int num_instance_klasses = 0;
|
||||
int num_boot_klasses = 0;
|
||||
@ -715,7 +688,7 @@ void ArchiveBuilder::make_klasses_shareable() {
|
||||
const char* unlinked = "";
|
||||
const char* hidden = "";
|
||||
const char* generated = "";
|
||||
Klass* k = klasses()->at(i);
|
||||
Klass* k = get_buffered_addr(klasses()->at(i));
|
||||
k->remove_java_mirror();
|
||||
if (k->is_objArray_klass()) {
|
||||
// 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");
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ private:
|
||||
bool is_dumping_full_module_graph();
|
||||
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_klasses();
|
||||
static int compare_symbols_by_address(Symbol** a, Symbol** b);
|
||||
@ -256,7 +256,7 @@ private:
|
||||
void clean_up_src_obj_table();
|
||||
|
||||
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:
|
||||
size_t _estimated_metaspaceobj_bytes; // all archived MetaspaceObj's.
|
||||
@ -303,6 +303,11 @@ public:
|
||||
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:
|
||||
static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
|
||||
|
||||
@ -317,15 +322,13 @@ public:
|
||||
template <typename T>
|
||||
u4 buffer_to_offset_u4(T p) const {
|
||||
uintx offset = buffer_to_offset((address)p);
|
||||
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset);
|
||||
return (u4)offset;
|
||||
return to_offset_u4(offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
u4 any_to_offset_u4(T p) const {
|
||||
uintx offset = any_to_offset((address)p);
|
||||
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset);
|
||||
return (u4)offset;
|
||||
return to_offset_u4(offset);
|
||||
}
|
||||
|
||||
static void assert_is_vm_thread() PRODUCT_RETURN;
|
||||
@ -338,7 +341,7 @@ public:
|
||||
void gather_source_objs();
|
||||
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);
|
||||
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* ro_region() { return &_ro_region; }
|
||||
@ -375,15 +378,22 @@ public:
|
||||
void dump_rw_metadata();
|
||||
void dump_ro_metadata();
|
||||
void relocate_metaspaceobj_embedded_pointers();
|
||||
void relocate_roots();
|
||||
void relocate_vm_classes();
|
||||
void make_klasses_shareable();
|
||||
void relocate_to_requested();
|
||||
void write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info);
|
||||
void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,
|
||||
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;
|
||||
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;
|
||||
template <typename T> T get_source_addr(T buffered_addr) const {
|
||||
return (T)get_source_addr((address)buffered_addr);
|
||||
|
@ -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) {
|
||||
if (*o == nullptr) {
|
||||
_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");
|
||||
do_tag((int)size);
|
||||
while (size > 0) {
|
||||
_dump_region->append_intptr_t(*(intptr_t*)start, true);
|
||||
do_ptr((void**)start);
|
||||
start += sizeof(intptr_t);
|
||||
size -= sizeof(intptr_t);
|
||||
}
|
||||
|
@ -184,9 +184,7 @@ public:
|
||||
_dump_region = r;
|
||||
}
|
||||
|
||||
void do_ptr(void** p) {
|
||||
_dump_region->append_intptr_t((intptr_t)*p, true);
|
||||
}
|
||||
void do_ptr(void** p);
|
||||
|
||||
void do_u4(u4* p) {
|
||||
_dump_region->append_intptr_t((intptr_t)(*p));
|
||||
|
@ -253,6 +253,7 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
|
||||
case MetaspaceObj::ConstantPoolCacheType:
|
||||
case MetaspaceObj::AnnotationsType:
|
||||
case MetaspaceObj::MethodCountersType:
|
||||
case MetaspaceObj::SharedClassPathEntryType:
|
||||
case MetaspaceObj::RecordComponentType:
|
||||
// These have no vtables.
|
||||
break;
|
||||
@ -268,7 +269,7 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
|
||||
}
|
||||
if (kind >= _num_cloned_vtable_kinds) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,6 @@ public:
|
||||
dump_rw_metadata();
|
||||
dump_ro_metadata();
|
||||
relocate_metaspaceobj_embedded_pointers();
|
||||
relocate_roots();
|
||||
|
||||
verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs");
|
||||
|
||||
@ -175,7 +174,7 @@ public:
|
||||
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);
|
||||
SystemDictionaryShared::dumptime_classes_do(it);
|
||||
}
|
||||
@ -216,7 +215,7 @@ void DynamicArchiveBuilder::post_dump() {
|
||||
void DynamicArchiveBuilder::sort_methods() {
|
||||
InstanceKlass::disable_method_binary_search();
|
||||
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()) {
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
||||
assert(is_in_buffer_space(ik), "method sorting must be done on buffered class, not original class");
|
||||
if (ik->java_mirror() == nullptr) {
|
||||
// null mirror means this class has already been visited and methods are already sorted
|
||||
return;
|
||||
@ -315,9 +314,7 @@ void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k,
|
||||
}
|
||||
|
||||
void DynamicArchiveBuilder::write_archive(char* serialized_data) {
|
||||
Array<u8>* table = FileMapInfo::saved_shared_path_table().table();
|
||||
SharedPathTable runtime_table(table, FileMapInfo::shared_path_table().size());
|
||||
_header->set_shared_path_table(runtime_table);
|
||||
_header->set_shared_path_table(FileMapInfo::shared_path_table().table());
|
||||
_header->set_serialized_data(serialized_data);
|
||||
|
||||
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);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
// copy shared path table to saved.
|
||||
FileMapInfo::clone_shared_path_table(current);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
VM_PopulateDynamicDumpSharedSpace op(archive_name);
|
||||
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");
|
||||
MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK);
|
||||
// copy shared path table to saved.
|
||||
FileMapInfo::clone_shared_path_table(CHECK);
|
||||
VM_PopulateDynamicDumpSharedSpace op(archive_name);
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
|
@ -292,7 +292,6 @@ void FileMapHeader::print(outputStream* st) {
|
||||
st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
|
||||
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_size: %d", _shared_path_table_size);
|
||||
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("- num_module_paths: %d", _num_module_paths);
|
||||
@ -453,64 +452,27 @@ bool SharedClassPathEntry::check_non_existent() const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_name);
|
||||
it->push(&_manifest);
|
||||
}
|
||||
|
||||
void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_table);
|
||||
for (int i=0; i<_size; i++) {
|
||||
path_at(i)->metaspace_pointers_do(it);
|
||||
}
|
||||
it->push(&_entries);
|
||||
}
|
||||
|
||||
void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) {
|
||||
size_t entry_size = sizeof(SharedClassPathEntry);
|
||||
int num_entries = 0;
|
||||
num_entries += ClassLoader::num_boot_classpath_entries();
|
||||
num_entries += ClassLoader::num_app_classpath_entries();
|
||||
num_entries += ClassLoader::num_module_path_entries();
|
||||
num_entries += FileMapInfo::num_non_existent_class_paths();
|
||||
size_t bytes = entry_size * num_entries;
|
||||
|
||||
_table = MetadataFactory::new_array<u8>(loader_data, (int)bytes, CHECK);
|
||||
_size = num_entries;
|
||||
const int num_entries =
|
||||
ClassLoader::num_boot_classpath_entries() +
|
||||
ClassLoader::num_app_classpath_entries() +
|
||||
ClassLoader::num_module_path_entries() +
|
||||
FileMapInfo::num_non_existent_class_paths();
|
||||
_entries = MetadataFactory::new_array<SharedClassPathEntry*>(loader_data, num_entries, CHECK);
|
||||
for (int i = 0; i < num_entries; i++) {
|
||||
SharedClassPathEntry* ent =
|
||||
new (loader_data, SharedClassPathEntry::size(), MetaspaceObj::SharedClassPathEntryType, THREAD) SharedClassPathEntry;
|
||||
_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) {
|
||||
@ -536,7 +498,6 @@ void FileMapInfo::allocate_shared_path_table(TRAPS) {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -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::_dynamic_archive_info = nullptr;
|
||||
bool FileMapInfo::_heap_pointers_need_patching = false;
|
||||
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::_memory_mapping_failed = false;
|
||||
GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = nullptr;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "include/cds.h"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/array.hpp"
|
||||
#include "oops/compressedOops.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
@ -48,7 +49,7 @@ class ClassLoaderData;
|
||||
class ClassPathEntry;
|
||||
class outputStream;
|
||||
|
||||
class SharedClassPathEntry {
|
||||
class SharedClassPathEntry : public MetaspaceObj {
|
||||
enum {
|
||||
modules_image_entry,
|
||||
jar_entry,
|
||||
@ -69,9 +70,17 @@ class SharedClassPathEntry {
|
||||
Array<u1>* _manifest;
|
||||
|
||||
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_as_non_existent(const char* path, TRAPS);
|
||||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
MetaspaceObj::Type type() const { return SharedClassPathEntryType; }
|
||||
bool validate(bool is_class_path = true) const;
|
||||
|
||||
// The _timestamp only gets set for jar files.
|
||||
@ -106,29 +115,22 @@ public:
|
||||
};
|
||||
|
||||
class SharedPathTable {
|
||||
Array<u8>* _table;
|
||||
int _size;
|
||||
Array<SharedClassPathEntry*>* _entries;
|
||||
public:
|
||||
SharedPathTable() : _table(nullptr), _size(0) {}
|
||||
SharedPathTable(Array<u8>* table, int size) : _table(table), _size(size) {}
|
||||
SharedPathTable() : _entries(nullptr) {}
|
||||
SharedPathTable(Array<SharedClassPathEntry*>* entries) : _entries(entries) {}
|
||||
|
||||
void dumptime_init(ClassLoaderData* loader_data, TRAPS);
|
||||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
|
||||
int size() {
|
||||
return _size;
|
||||
return _entries == nullptr ? 0 : _entries->length();
|
||||
}
|
||||
SharedClassPathEntry* path_at(int index) {
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
return _entries->at(index);
|
||||
}
|
||||
assert(index < _size, "sanity");
|
||||
char* p = (char*)_table->data();
|
||||
p += sizeof(SharedClassPathEntry) * index;
|
||||
return (SharedClassPathEntry*)p;
|
||||
}
|
||||
Array<u8>* table() {return _table;}
|
||||
void set_table(Array<u8>* table) {_table = table;}
|
||||
Array<SharedClassPathEntry*>* table() {return _entries;}
|
||||
void set_table(Array<SharedClassPathEntry*>* table) {_entries = table;}
|
||||
};
|
||||
|
||||
|
||||
@ -215,7 +217,6 @@ private:
|
||||
// validate_shared_path_table()
|
||||
// validate_non_existent_class_paths()
|
||||
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_module_paths_start_index; // Index of first module path entry
|
||||
@ -290,7 +291,6 @@ public:
|
||||
|
||||
void set_shared_path_table(SharedPathTable table) {
|
||||
set_as_offset((char*)table.table(), &_shared_path_table_offset);
|
||||
_shared_path_table_size = table.size();
|
||||
}
|
||||
|
||||
void set_requested_base(char* b) {
|
||||
@ -299,8 +299,8 @@ public:
|
||||
}
|
||||
|
||||
SharedPathTable shared_path_table() const {
|
||||
return SharedPathTable((Array<u8>*)from_mapped_offset(_shared_path_table_offset),
|
||||
_shared_path_table_size);
|
||||
return SharedPathTable((Array<SharedClassPathEntry*>*)
|
||||
from_mapped_offset(_shared_path_table_offset));
|
||||
}
|
||||
|
||||
bool validate();
|
||||
@ -338,10 +338,7 @@ private:
|
||||
const char* _base_archive_name;
|
||||
FileMapHeader* _header;
|
||||
|
||||
// TODO: Probably change the following to be non-static
|
||||
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;
|
||||
|
||||
// FileMapHeader describes the shared space data in the file to be
|
||||
@ -361,13 +358,11 @@ public:
|
||||
static SharedPathTable 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);
|
||||
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);
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/lambdaProxyClassDictionary.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
|
||||
// This constructor is used only by SystemDictionaryShared::clone_dumptime_tables().
|
||||
// See comments there about the need for making a deep copy.
|
||||
@ -46,13 +47,15 @@ DumpTimeLambdaProxyClassInfo::~DumpTimeLambdaProxyClassInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
void LambdaProxyClassKey::mark_pointers() {
|
||||
ArchivePtrMarker::mark_pointer(&_caller_ik);
|
||||
ArchivePtrMarker::mark_pointer(&_instantiated_method_type);
|
||||
ArchivePtrMarker::mark_pointer(&_invoked_name);
|
||||
ArchivePtrMarker::mark_pointer(&_invoked_type);
|
||||
ArchivePtrMarker::mark_pointer(&_member_method);
|
||||
ArchivePtrMarker::mark_pointer(&_method_type);
|
||||
void LambdaProxyClassKey::init_for_archive(LambdaProxyClassKey& dumptime_key) {
|
||||
ArchiveBuilder* b = ArchiveBuilder::current();
|
||||
|
||||
b->write_pointer_in_buffer(&_caller_ik, dumptime_key._caller_ik);
|
||||
b->write_pointer_in_buffer(&_instantiated_method_type, dumptime_key._instantiated_method_type);
|
||||
b->write_pointer_in_buffer(&_invoked_name, dumptime_key._invoked_name);
|
||||
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 {
|
||||
@ -62,3 +65,26 @@ unsigned int LambdaProxyClassKey::hash() const {
|
||||
SystemDictionaryShared::hash_for_shared_dictionary((address)_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));
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
class InstanceKlass;
|
||||
class Method;
|
||||
class Symbol;
|
||||
class outputStream;
|
||||
|
||||
class LambdaProxyClassKey {
|
||||
InstanceKlass* _caller_ik;
|
||||
@ -73,7 +74,6 @@ public:
|
||||
_instantiated_method_type == other._instantiated_method_type;
|
||||
}
|
||||
|
||||
void mark_pointers();
|
||||
unsigned int hash() const;
|
||||
|
||||
static unsigned int dumptime_hash(Symbol* sym) {
|
||||
@ -102,6 +102,12 @@ public:
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -141,12 +147,7 @@ public:
|
||||
const RunTimeLambdaProxyClassInfo* value, LambdaProxyClassKey* key, int len_unused) {
|
||||
return (value->_key.equals(*key));
|
||||
}
|
||||
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);
|
||||
}
|
||||
void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info);
|
||||
|
||||
unsigned int hash() const {
|
||||
return _key.hash();
|
||||
@ -154,6 +155,9 @@ public:
|
||||
LambdaProxyClassKey key() const {
|
||||
return _key;
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
void print_on(outputStream* st) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
class DumpTimeLambdaProxyClassDictionary
|
||||
|
@ -451,8 +451,8 @@ class StaticArchiveBuilder : public ArchiveBuilder {
|
||||
public:
|
||||
StaticArchiveBuilder() : ArchiveBuilder() {}
|
||||
|
||||
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) {
|
||||
FileMapInfo::metaspace_pointers_do(it, false);
|
||||
virtual void iterate_roots(MetaspaceClosure* it) {
|
||||
FileMapInfo::metaspace_pointers_do(it);
|
||||
SystemDictionaryShared::dumptime_classes_do(it);
|
||||
Universe::metaspace_pointers_do(it);
|
||||
vmSymbols::metaspace_pointers_do(it);
|
||||
@ -507,14 +507,9 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
builder.dump_ro_metadata();
|
||||
builder.relocate_metaspaceobj_embedded_pointers();
|
||||
|
||||
// Dump supported java heap objects
|
||||
dump_java_heap_objects(builder.klasses());
|
||||
|
||||
builder.relocate_roots();
|
||||
dump_shared_symbol_table(builder.symbols());
|
||||
|
||||
builder.relocate_vm_classes();
|
||||
|
||||
log_info(cds)("Make classes 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.
|
||||
//
|
||||
// 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
|
||||
// loader during DumpSharedSpaces).
|
||||
// tolerate this.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,8 +30,8 @@
|
||||
|
||||
void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
ArchiveBuilder* builder = ArchiveBuilder::current();
|
||||
assert(builder->is_in_buffer_space(info._klass), "must be");
|
||||
_klass = info._klass;
|
||||
builder->write_pointer_in_buffer(&_klass, info._klass);
|
||||
|
||||
if (!SystemDictionaryShared::is_builtin(_klass)) {
|
||||
CrcInfo* c = crc();
|
||||
c->_clsfile_size = info._clsfile_size;
|
||||
@ -62,8 +62,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
}
|
||||
|
||||
if (_klass->is_hidden()) {
|
||||
InstanceKlass* n_h = info.nest_host();
|
||||
set_nest_host(n_h);
|
||||
builder->write_pointer_in_buffer(nest_host_addr(), info.nest_host());
|
||||
}
|
||||
if (_klass->has_archived_enum_objs()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
ArchivePtrMarker::mark_pointer(&_klass);
|
||||
}
|
||||
|
||||
size_t RunTimeClassInfo::crc_size(InstanceKlass* klass) {
|
||||
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -180,10 +180,6 @@ public:
|
||||
InstanceKlass* nest_host() {
|
||||
return *nest_host_addr();
|
||||
}
|
||||
void set_nest_host(InstanceKlass* k) {
|
||||
*nest_host_addr() = k;
|
||||
ArchivePtrMarker::mark_pointer((address*)nest_host_addr());
|
||||
}
|
||||
|
||||
RTLoaderConstraint* loader_constraints() {
|
||||
assert(_num_loader_constraints > 0, "sanity");
|
||||
|
@ -1166,22 +1166,19 @@ public:
|
||||
AdjustLambdaProxyClassInfo() {}
|
||||
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
|
||||
int len = info._proxy_klasses->length();
|
||||
if (len > 1) {
|
||||
for (int i = 0; i < len-1; i++) {
|
||||
InstanceKlass* ok0 = info._proxy_klasses->at(i+0); // this is original klass
|
||||
InstanceKlass* ok1 = info._proxy_klasses->at(i+1); // this is original klass
|
||||
assert(ArchiveBuilder::current()->is_in_buffer_space(ok0), "must be");
|
||||
assert(ArchiveBuilder::current()->is_in_buffer_space(ok1), "must be");
|
||||
InstanceKlass* bk0 = ok0;
|
||||
InstanceKlass* bk1 = ok1;
|
||||
assert(bk0->next_link() == 0, "must be called after Klass::remove_unshareable_info()");
|
||||
assert(bk1->next_link() == 0, "must be called after Klass::remove_unshareable_info()");
|
||||
bk0->set_next_link(bk1);
|
||||
bk1->set_lambda_proxy_is_available();
|
||||
ArchivePtrMarker::mark_pointer(bk0->next_link_addr());
|
||||
InstanceKlass* last_buff_k = nullptr;
|
||||
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
InstanceKlass* orig_k = info._proxy_klasses->at(i);
|
||||
InstanceKlass* buff_k = ArchiveBuilder::current()->get_buffered_addr(orig_k);
|
||||
assert(ArchiveBuilder::current()->is_in_buffer_space(buff_k), "must be");
|
||||
buff_k->set_lambda_proxy_is_available();
|
||||
buff_k->set_next_link(last_buff_k);
|
||||
if (last_buff_k != nullptr) {
|
||||
ArchivePtrMarker::mark_pointer(buff_k->next_link_addr());
|
||||
}
|
||||
last_buff_k = buff_k;
|
||||
}
|
||||
info._proxy_klasses->at(0)->set_lambda_proxy_is_available();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1205,6 +1202,7 @@ public:
|
||||
|
||||
unsigned int hash;
|
||||
Symbol* name = info._klass->name();
|
||||
name = ArchiveBuilder::current()->get_buffered_addr(name);
|
||||
hash = SystemDictionaryShared::hash_for_shared_dictionary((address)name);
|
||||
u4 delta = _builder->buffer_to_offset_u4((address)record);
|
||||
if (_is_builtin && info._klass->is_hidden()) {
|
||||
@ -1218,7 +1216,8 @@ public:
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -370,6 +370,7 @@ class MetaspaceObj {
|
||||
f(ConstantPoolCache) \
|
||||
f(Annotations) \
|
||||
f(MethodCounters) \
|
||||
f(SharedClassPathEntry) \
|
||||
f(RecordComponent)
|
||||
|
||||
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
|
||||
|
Loading…
x
Reference in New Issue
Block a user