mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 18:14:38 +02:00
8267189: Remove duplicated unregistered classes from dynamic archive
Reviewed-by: ccheung, minqi
This commit is contained in:
parent
fa3b44d438
commit
bb24fa652a
8 changed files with 316 additions and 19 deletions
|
@ -1165,29 +1165,43 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread(
|
|||
return shared_klass;
|
||||
}
|
||||
|
||||
class LoadedUnregisteredClassesTable : public ResourceHashtable<
|
||||
Symbol*, bool,
|
||||
class UnregisteredClassesTable : public ResourceHashtable<
|
||||
Symbol*, InstanceKlass*,
|
||||
primitive_hash<Symbol*>,
|
||||
primitive_equals<Symbol*>,
|
||||
6661, // prime number
|
||||
15889, // prime number
|
||||
ResourceObj::C_HEAP> {};
|
||||
|
||||
static LoadedUnregisteredClassesTable* _loaded_unregistered_classes = NULL;
|
||||
static UnregisteredClassesTable* _unregistered_classes_table = NULL;
|
||||
|
||||
bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKlass* k) {
|
||||
// We don't allow duplicated unregistered classes of the same name.
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
Symbol* name = k->name();
|
||||
if (_loaded_unregistered_classes == NULL) {
|
||||
_loaded_unregistered_classes = new (ResourceObj::C_HEAP, mtClass)LoadedUnregisteredClassesTable();
|
||||
bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKlass* klass) {
|
||||
// We don't allow duplicated unregistered classes with the same name.
|
||||
// We only archive the first class with that name that succeeds putting
|
||||
// itself into the table.
|
||||
Arguments::assert_is_dumping_archive();
|
||||
MutexLocker ml(current, UnregisteredClassesTable_lock);
|
||||
Symbol* name = klass->name();
|
||||
if (_unregistered_classes_table == NULL) {
|
||||
_unregistered_classes_table = new (ResourceObj::C_HEAP, mtClass)UnregisteredClassesTable();
|
||||
}
|
||||
bool created = false;
|
||||
_loaded_unregistered_classes->put_if_absent(name, true, &created);
|
||||
bool created;
|
||||
InstanceKlass** v = _unregistered_classes_table->put_if_absent(name, klass, &created);
|
||||
if (created) {
|
||||
name->increment_refcount();
|
||||
}
|
||||
return (klass == *v);
|
||||
}
|
||||
|
||||
// true == class was successfully added; false == a duplicated class (with the same name) already exists.
|
||||
bool SystemDictionaryShared::add_unregistered_class_for_static_archive(Thread* current, InstanceKlass* k) {
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
if (add_unregistered_class(current, k)) {
|
||||
MutexLocker mu_r(current, Compile_lock); // add_to_hierarchy asserts this.
|
||||
SystemDictionary::add_to_hierarchy(k);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return created;
|
||||
}
|
||||
|
||||
// This function is called to lookup the super/interfaces of shared classes for
|
||||
|
@ -1295,6 +1309,21 @@ void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
|
|||
_dumptime_table->remove(k);
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::handle_class_unloading(InstanceKlass* klass) {
|
||||
remove_dumptime_info(klass);
|
||||
|
||||
if (_unregistered_classes_table != NULL) {
|
||||
// Remove the class from _unregistered_classes_table: keep the entry but
|
||||
// set it to NULL. This ensure no classes with the same name can be
|
||||
// added again.
|
||||
MutexLocker ml(Thread::current(), UnregisteredClassesTable_lock);
|
||||
InstanceKlass** v = _unregistered_classes_table->get(klass->name());
|
||||
if (v != NULL) {
|
||||
*v = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
|
||||
while (k) {
|
||||
if (k->name()->equals("jdk/internal/event/Event")) {
|
||||
|
@ -1476,6 +1505,48 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
|
|||
}
|
||||
}
|
||||
|
||||
class UnregisteredClassesDuplicationChecker : StackObj {
|
||||
GrowableArray<InstanceKlass*> _list;
|
||||
Thread* _thread;
|
||||
public:
|
||||
UnregisteredClassesDuplicationChecker() : _thread(Thread::current()) {}
|
||||
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
if (!SystemDictionaryShared::is_builtin(k)) {
|
||||
_list.append(k);
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
|
||||
static int compare_by_loader(InstanceKlass** a, InstanceKlass** b) {
|
||||
ClassLoaderData* loader_a = a[0]->class_loader_data();
|
||||
ClassLoaderData* loader_b = b[0]->class_loader_data();
|
||||
|
||||
if (loader_a != loader_b) {
|
||||
return intx(loader_a) - intx(loader_b);
|
||||
} else {
|
||||
return intx(a[0]) - intx(b[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void mark_duplicated_classes() {
|
||||
// Two loaders may load two identical or similar hierarchies of classes. If we
|
||||
// check for duplication in random order, we may end up excluding important base classes
|
||||
// in both hierarchies, causing most of the classes to be excluded.
|
||||
// We sort the classes by their loaders. This way we're likely to archive
|
||||
// all classes in the one of the two hierarchies.
|
||||
_list.sort(compare_by_loader);
|
||||
for (int i = 0; i < _list.length(); i++) {
|
||||
InstanceKlass* k = _list.at(i);
|
||||
bool i_am_first = SystemDictionaryShared::add_unregistered_class(_thread, k);
|
||||
if (!i_am_first) {
|
||||
SystemDictionaryShared::warn_excluded(k, "Duplicated unregistered class");
|
||||
SystemDictionaryShared::set_excluded_locked(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ExcludeDumpTimeSharedClasses : StackObj {
|
||||
public:
|
||||
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
||||
|
@ -1487,6 +1558,16 @@ public:
|
|||
void SystemDictionaryShared::check_excluded_classes() {
|
||||
assert(no_class_loading_should_happen(), "sanity");
|
||||
assert_lock_strong(DumpTimeTable_lock);
|
||||
|
||||
if (DynamicDumpSharedSpaces) {
|
||||
// Do this first -- if a base class is excluded due to duplication,
|
||||
// all of its subclasses will also be excluded by ExcludeDumpTimeSharedClasses
|
||||
ResourceMark rm;
|
||||
UnregisteredClassesDuplicationChecker dup_checker;
|
||||
_dumptime_table->iterate(&dup_checker);
|
||||
dup_checker.mark_duplicated_classes();
|
||||
}
|
||||
|
||||
ExcludeDumpTimeSharedClasses excl;
|
||||
_dumptime_table->iterate(&excl);
|
||||
_dumptime_table->update_counts();
|
||||
|
@ -1500,6 +1581,15 @@ bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
|
|||
return (p == NULL) ? true : p->is_excluded();
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::set_excluded_locked(InstanceKlass* k) {
|
||||
assert_lock_strong(DumpTimeTable_lock);
|
||||
Arguments::assert_is_dumping_archive();
|
||||
DumpTimeSharedClassInfo* info = find_or_allocate_info_for_locked(k);
|
||||
if (info != NULL) {
|
||||
info->set_excluded();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::set_excluded(InstanceKlass* k) {
|
||||
Arguments::assert_is_dumping_archive();
|
||||
DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue