mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8360743: Enables regeneration of JLI holder classes for CDS static dump
Reviewed-by: iklam, liach
This commit is contained in:
parent
aa1911191c
commit
1dda79cfab
@ -30,6 +30,7 @@
|
||||
#include "cds/dumpTimeClassInfo.inline.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/lambdaProxyClassDictionary.hpp"
|
||||
#include "cds/regeneratedClasses.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
@ -188,7 +189,11 @@ void AOTArtifactFinder::end_scanning_for_oops() {
|
||||
|
||||
void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) {
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
assert(ik->is_initialized(), "must be");
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
precond(RegeneratedClasses::get_original_object(ik)->is_initialized());
|
||||
} else {
|
||||
precond(ik->is_initialized());
|
||||
}
|
||||
add_cached_instance_class(ik);
|
||||
|
||||
bool created;
|
||||
@ -243,6 +248,11 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) {
|
||||
add_cached_instance_class(intf);
|
||||
}
|
||||
|
||||
InstanceKlass* nest_host = ik->nest_host_or_null();
|
||||
if (nest_host != nullptr) {
|
||||
add_cached_instance_class(nest_host);
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_final_static_archive() && ik->defined_by_other_loaders()) {
|
||||
// The following are not appliable to unregistered classes
|
||||
return;
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/regeneratedClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
@ -103,6 +104,10 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
ik = RegeneratedClasses::get_original_object(ik);
|
||||
}
|
||||
|
||||
if (!ik->is_initialized() && !ik->is_being_initialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -575,6 +575,9 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref
|
||||
if (ref->msotype() == MetaspaceObj::ClassType) {
|
||||
Klass* klass = (Klass*)ref->obj();
|
||||
assert(klass->is_klass(), "must be");
|
||||
if (RegeneratedClasses::has_been_regenerated(klass)) {
|
||||
klass = RegeneratedClasses::get_regenerated_object(klass);
|
||||
}
|
||||
if (is_excluded(klass)) {
|
||||
ResourceMark rm;
|
||||
log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name());
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/filemap.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/regeneratedClasses.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
@ -543,6 +544,10 @@ template <typename T> void ArchiveHeapWriter::relocate_field_in_buffer(T* field_
|
||||
oop source_referent = load_source_oop_from_buffer<T>(field_addr_in_buffer);
|
||||
if (source_referent != nullptr) {
|
||||
if (java_lang_Class::is_instance(source_referent)) {
|
||||
Klass* k = java_lang_Class::as_Klass(source_referent);
|
||||
if (RegeneratedClasses::has_been_regenerated(k)) {
|
||||
source_referent = RegeneratedClasses::get_regenerated_object(k)->java_mirror();
|
||||
}
|
||||
// When the source object points to a "real" mirror, the buffered object should point
|
||||
// to the "scratch" mirror, which has all unarchivable fields scrubbed (to be reinstated
|
||||
// at run time).
|
||||
@ -754,6 +759,11 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
|
||||
Metadata** buffered_field_addr = requested_addr_to_buffered_addr(requested_field_addr);
|
||||
Metadata* native_ptr = *buffered_field_addr;
|
||||
guarantee(native_ptr != nullptr, "sanity");
|
||||
|
||||
if (RegeneratedClasses::has_been_regenerated(native_ptr)) {
|
||||
native_ptr = RegeneratedClasses::get_regenerated_object(native_ptr);
|
||||
}
|
||||
|
||||
guarantee(ArchiveBuilder::current()->has_been_buffered((address)native_ptr),
|
||||
"Metadata %p should have been archived", native_ptr);
|
||||
|
||||
|
||||
@ -817,9 +817,6 @@ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
|
||||
// that point to the lambda form invokers in the base archive. Such pointers will
|
||||
// be invalid if lambda form invokers are regenerated in the dynamic archive.
|
||||
return false;
|
||||
} else if (CDSConfig::is_dumping_method_handles()) {
|
||||
// Work around JDK-8310831, as some methods in lambda form holder classes may not get generated.
|
||||
return false;
|
||||
} else {
|
||||
return is_dumping_archive();
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include "cds/cdsHeapVerifier.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "cds/regeneratedClasses.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/classLoaderExt.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
@ -337,6 +338,9 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
|
||||
} else if (java_lang_invoke_ResolvedMethodName::is_instance(obj)) {
|
||||
Method* m = java_lang_invoke_ResolvedMethodName::vmtarget(obj);
|
||||
if (m != nullptr) {
|
||||
if (RegeneratedClasses::has_been_regenerated(m)) {
|
||||
m = RegeneratedClasses::get_regenerated_object(m);
|
||||
}
|
||||
InstanceKlass* method_holder = m->method_holder();
|
||||
AOTArtifactFinder::add_cached_class(method_holder);
|
||||
}
|
||||
@ -506,10 +510,17 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
|
||||
ik->set_is_runtime_setup_required();
|
||||
}
|
||||
|
||||
oop orig_mirror = ik->java_mirror();
|
||||
oop m = scratch_java_mirror(ik);
|
||||
assert(ik->is_initialized(), "must be");
|
||||
oop orig_mirror;
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
InstanceKlass* orig_ik = RegeneratedClasses::get_original_object(ik);
|
||||
precond(orig_ik->is_initialized());
|
||||
orig_mirror = orig_ik->java_mirror();
|
||||
} else {
|
||||
precond(ik->is_initialized());
|
||||
orig_mirror = ik->java_mirror();
|
||||
}
|
||||
|
||||
oop m = scratch_java_mirror(ik);
|
||||
int nfields = 0;
|
||||
for (JavaFieldStream fs(ik); !fs.done(); fs.next()) {
|
||||
if (fs.access_flags().is_static()) {
|
||||
@ -1520,6 +1531,13 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
|
||||
p2i(scratch_java_mirror(orig_obj)));
|
||||
}
|
||||
|
||||
if (java_lang_Class::is_instance(orig_obj)) {
|
||||
Klass* k = java_lang_Class::as_Klass(orig_obj);
|
||||
if (RegeneratedClasses::has_been_regenerated(k)) {
|
||||
orig_obj = RegeneratedClasses::get_regenerated_object(k)->java_mirror();
|
||||
}
|
||||
}
|
||||
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
if (java_lang_Class::is_instance(orig_obj)) {
|
||||
orig_obj = scratch_java_mirror(orig_obj);
|
||||
|
||||
@ -224,6 +224,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st,
|
||||
|
||||
result->set_is_generated_shared_class();
|
||||
if (!klass->is_shared()) {
|
||||
log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string());
|
||||
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump
|
||||
}
|
||||
log_info(aot, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,
|
||||
|
||||
@ -34,7 +34,8 @@
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
using RegeneratedObjTable = ResourceHashtable<address, address, 15889, AnyObj::C_HEAP, mtClassShared>;
|
||||
static RegeneratedObjTable* _renegerated_objs = nullptr; // InstanceKlass* and Method*
|
||||
static RegeneratedObjTable* _regenerated_objs = nullptr; // InstanceKlass* and Method* orig_obj -> regen_obj
|
||||
static RegeneratedObjTable* _original_objs = nullptr; // InstanceKlass* and Method* regen_obj -> orig_obj
|
||||
static GrowableArrayCHeap<OopHandle, mtClassShared>* _regenerated_mirrors = nullptr;
|
||||
|
||||
// The regenerated Klass is not added to any class loader, so we need
|
||||
@ -46,11 +47,15 @@ void RegeneratedClasses::add_class(InstanceKlass* orig_klass, InstanceKlass* reg
|
||||
}
|
||||
_regenerated_mirrors->append(OopHandle(Universe::vm_global(), regen_klass->java_mirror()));
|
||||
|
||||
if (_renegerated_objs == nullptr) {
|
||||
_renegerated_objs = new (mtClass)RegeneratedObjTable();
|
||||
if (_regenerated_objs == nullptr) {
|
||||
_regenerated_objs = new (mtClass)RegeneratedObjTable();
|
||||
}
|
||||
if (_original_objs == nullptr) {
|
||||
_original_objs = new (mtClass)RegeneratedObjTable();
|
||||
}
|
||||
|
||||
_renegerated_objs->put((address)orig_klass, (address)regen_klass);
|
||||
_regenerated_objs->put((address)orig_klass, (address)regen_klass);
|
||||
_original_objs->put((address)regen_klass, (address)orig_klass);
|
||||
Array<Method*>* methods = orig_klass->methods();
|
||||
for (int i = 0; i < methods->length(); i++) {
|
||||
Method* orig_m = methods->at(i);
|
||||
@ -60,26 +65,49 @@ void RegeneratedClasses::add_class(InstanceKlass* orig_klass, InstanceKlass* reg
|
||||
log_warning(aot)("Method in original class is missing from regenerated class: " INTPTR_FORMAT " %s",
|
||||
p2i(orig_m), orig_m->external_name());
|
||||
} else {
|
||||
_renegerated_objs->put((address)orig_m, (address)regen_m);
|
||||
_regenerated_objs->put((address)orig_m, (address)regen_m);
|
||||
_original_objs->put((address)regen_m, (address)orig_m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RegeneratedClasses::has_been_regenerated(address orig_obj) {
|
||||
if (_renegerated_objs == nullptr) {
|
||||
if (_regenerated_objs == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
return _renegerated_objs->get(orig_obj) != nullptr;
|
||||
return _regenerated_objs->get(orig_obj) != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
address RegeneratedClasses::get_regenerated_object(address orig_obj) {
|
||||
assert(_regenerated_objs != nullptr, "must be");
|
||||
address* p =_regenerated_objs->get(orig_obj);
|
||||
assert(p != nullptr, "must be");
|
||||
return *p;
|
||||
}
|
||||
|
||||
bool RegeneratedClasses::is_regenerated_object(address regen_obj) {
|
||||
if (_original_objs == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
return _original_objs->get(regen_obj) != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
address RegeneratedClasses::get_original_object(address regen_obj) {
|
||||
assert(_original_objs != nullptr, "must be");
|
||||
address* p =_original_objs->get(regen_obj);
|
||||
assert(p != nullptr, "must be");
|
||||
return *p;
|
||||
}
|
||||
|
||||
void RegeneratedClasses::record_regenerated_objects() {
|
||||
assert_locked_or_safepoint(DumpTimeTable_lock);
|
||||
if (_renegerated_objs != nullptr) {
|
||||
if (_regenerated_objs != nullptr) {
|
||||
auto doit = [&] (address orig_obj, address regen_obj) {
|
||||
ArchiveBuilder::current()->record_regenerated_object(orig_obj, regen_obj);
|
||||
};
|
||||
_renegerated_objs->iterate_all(doit);
|
||||
_regenerated_objs->iterate_all(doit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +120,7 @@ void RegeneratedClasses::cleanup() {
|
||||
delete _regenerated_mirrors;
|
||||
_regenerated_mirrors = nullptr;
|
||||
}
|
||||
if (_renegerated_objs != nullptr) {
|
||||
delete _renegerated_objs;
|
||||
if (_regenerated_objs != nullptr) {
|
||||
delete _regenerated_objs;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 2025, 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
|
||||
@ -43,7 +43,26 @@ class RegeneratedClasses : public AllStatic {
|
||||
static void add_class(InstanceKlass* orig_klass, InstanceKlass* regen_klass);
|
||||
static void cleanup();
|
||||
static bool has_been_regenerated(address orig_obj);
|
||||
static address get_regenerated_object(address orig_obj); // orig_obj -> regen_obj
|
||||
static void record_regenerated_objects();
|
||||
|
||||
// Handy functions to avoid type casts
|
||||
template <class T> static bool has_been_regenerated(T orig_obj) {
|
||||
return has_been_regenerated((address)orig_obj);
|
||||
}
|
||||
template <class T> static T get_regenerated_object(T orig_obj) {
|
||||
return (T)get_regenerated_object((address)orig_obj);
|
||||
}
|
||||
|
||||
static bool is_regenerated_object(address regen_obj);
|
||||
static address get_original_object(address regen_obj); // regen_obj -> orig_obj
|
||||
|
||||
template <class T> static bool is_regenerated_object(T regen_obj) {
|
||||
return is_regenerated_object((address)regen_obj);
|
||||
}
|
||||
template <class T> static T get_original_object(T regen_obj) {
|
||||
return (T)get_original_object((address)regen_obj);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_REGENERATEDCLASSES_HPP
|
||||
|
||||
@ -348,6 +348,13 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
|
||||
}
|
||||
}
|
||||
|
||||
InstanceKlass* nest_host = k->nest_host_or_null();
|
||||
if (nest_host != nullptr && nest_host != k && check_for_exclusion(nest_host, nullptr)) {
|
||||
ResourceMark rm;
|
||||
aot_log_warning(aot)("Skipping %s: nest_host class %s is excluded", k->name()->as_C_string(), nest_host->name()->as_C_string());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // false == k should NOT be excluded
|
||||
}
|
||||
|
||||
|
||||
@ -444,6 +444,9 @@ public:
|
||||
assert(_nest_host != nullptr, "must be");
|
||||
return _nest_host;
|
||||
}
|
||||
InstanceKlass* nest_host_or_null() {
|
||||
return _nest_host;
|
||||
}
|
||||
// Used to construct informative IllegalAccessError messages at a higher level,
|
||||
// if there was an issue resolving or validating the nest host.
|
||||
// Returns null if there was no error.
|
||||
|
||||
@ -82,7 +82,7 @@ public class NestHostOldInf extends DynamicArchiveTestBase {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldMatch(".class.load. OldInf source:.*oldclassapp.jar")
|
||||
.shouldMatch(".class.load. ChildOldInf source:.*oldclassapp.jar")
|
||||
.shouldContain("ChildOldInf$InnerChild source: shared objects file (top)")
|
||||
.shouldMatch(".class.load. ChildOldInf[$]InnerChild source:.*oldclassapp.jar")
|
||||
.shouldMatch(".class.load. ChildOldInf[$]InnerChild[$][$]Lambda.*/0x.*source:.ChildOldInf");
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user