Skip to content
Permalink
Browse files
8240244: Avoid calling resolve_super_or_fail in SystemDictionary::loa…
…d_shared_class

Reviewed-by: redestad, lfoltan, minqi
  • Loading branch information
iklam committed Mar 5, 2020
1 parent 6cb2e02 commit 7ba18fc015d8f03ae64d62fd981c50224591582e
@@ -318,7 +318,7 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS

// This tells JVM_FindLoadedClass to not find this class.
k->set_shared_classpath_index(UNREGISTERED_INDEX);
k->clear_class_loader_type();
k->clear_shared_class_loader_type();
}

return k;
@@ -1361,7 +1361,7 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
if (loader == NULL) {
// JFR classes
ik->set_shared_classpath_index(0);
ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
ik->set_shared_class_loader_type(ClassLoader::BOOT_LOADER);
}
return;
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@@ -245,7 +245,7 @@ void ClassLoaderExt::record_result(const s2 classpath_index,
ClassLoaderExt::set_max_used_path_index(classpath_index);
}
result->set_shared_classpath_index(classpath_index);
result->set_class_loader_type(classloader_type);
result->set_shared_class_loader_type(classloader_type);
}

// Load the class of the given name from the location given by path. The path is specified by
@@ -1255,56 +1255,86 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
}
}

InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
Handle class_loader,
Handle protection_domain,
const ClassFileStream *cfs,
TRAPS) {
assert(ik != NULL, "sanity");
assert(!ik->is_unshareable_info_restored(), "shared class can be loaded only once");
Symbol* class_name = ik->name();
bool SystemDictionary::check_shared_class_super_type(InstanceKlass* child, InstanceKlass* super_type,
Handle class_loader, Handle protection_domain,
bool is_superclass, TRAPS) {
assert(super_type->is_shared(), "must be");

// Quick check if the super type has been already loaded.
// + Don't do it for unregistered classes -- they can be unloaded so
// super_type->class_loader_data() could be stale.
// + Don't take the lock if loader data is NULL.
if (!super_type->is_shared_unregistered_class() && super_type->class_loader_data() != NULL) {
MutexLocker mu1(THREAD, SystemDictionary_lock);
// Read loader_data again inside the lock for thread safety
ClassLoaderData* loader_data = super_type->class_loader_data();
if (loader_data != NULL) {
Symbol* name = super_type->name();
Dictionary* dictionary = loader_data->dictionary();
unsigned int d_hash = dictionary->compute_hash(name);
if (SystemDictionary::find_class(d_hash, name, dictionary) != super_type) {
return true;
}
}
}

bool visible = is_shared_class_visible(
class_name, ik, class_loader, CHECK_NULL);
if (!visible) {
return NULL;
// Not sure if super type is loaded. Do it the slow way.
Klass *found = resolve_super_or_fail(child->name(), super_type->name(),
class_loader, protection_domain, is_superclass, CHECK_0);
if (found == super_type) {
return true;
} else {
// The dynamically resolved super type is not the same as the one we used during dump time,
// so we cannot use the child class.
return false;
}
}

// Resolve the superclass and interfaces. They must be the same
bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle class_loader,
Handle protection_domain, TRAPS) {
// Check the superclass and interfaces. They must be the same
// as in dump time, because the layout of <ik> depends on
// the specific layout of ik->super() and ik->local_interfaces().
//
// If unexpected superclass or interfaces are found, we cannot
// load <ik> from the shared archive.

if (ik->super() != NULL) {
Symbol* cn = ik->super()->name();
Klass *s = resolve_super_or_fail(class_name, cn,
class_loader, protection_domain, true, CHECK_NULL);
if (s != ik->super()) {
// The dynamically resolved super class is not the same as the one we used during dump time,
// so we cannot use ik.
return NULL;
} else {
assert(s->is_shared(), "must be");
}
if (ik->super() != NULL &&
!check_shared_class_super_type(ik, InstanceKlass::cast(ik->super()),
class_loader, protection_domain, true, THREAD)) {
return false;
}

Array<InstanceKlass*>* interfaces = ik->local_interfaces();
int num_interfaces = interfaces->length();
for (int index = 0; index < num_interfaces; index++) {
InstanceKlass* k = interfaces->at(index);
Symbol* name = k->name();
Klass* i = resolve_super_or_fail(class_name, name, class_loader, protection_domain, false, CHECK_NULL);
if (k != i) {
// The dynamically resolved interface class is not the same as the one we used during dump time,
// so we cannot use ik.
return NULL;
} else {
assert(i->is_shared(), "must be");
if (!check_shared_class_super_type(ik, interfaces->at(index), class_loader, protection_domain, false, THREAD)) {
return false;
}
}

return true;
}

InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
Handle class_loader,
Handle protection_domain,
const ClassFileStream *cfs,
TRAPS) {
assert(ik != NULL, "sanity");
assert(!ik->is_unshareable_info_restored(), "shared class can be loaded only once");
Symbol* class_name = ik->name();

bool visible = is_shared_class_visible(
class_name, ik, class_loader, CHECK_NULL);
if (!visible) {
return NULL;
}

if (!check_shared_class_super_types(ik, class_loader, protection_domain, THREAD)) {
return NULL;
}

InstanceKlass* new_ik = KlassFactory::check_shared_class_file_load_hook(
ik, class_name, class_loader, protection_domain, cfs, CHECK_NULL);
if (new_ik != NULL) {
@@ -594,6 +594,11 @@ class SystemDictionary : AllStatic {
InstanceKlass* k, TRAPS);
static bool is_shared_class_visible(Symbol* class_name, InstanceKlass* ik,
Handle class_loader, TRAPS);
static bool check_shared_class_super_type(InstanceKlass* child, InstanceKlass* super,
Handle class_loader, Handle protection_domain,
bool is_superclass, TRAPS);
static bool check_shared_class_super_types(InstanceKlass* ik, Handle class_loader,
Handle protection_domain, TRAPS);
static InstanceKlass* load_shared_class(InstanceKlass* ik,
Handle class_loader,
Handle protection_domain,
@@ -1171,10 +1171,10 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
if (is_builtin(k)) {
guarantee(k->loader_type() != 0,
guarantee(!k->is_shared_unregistered_class(),
"Class loader type must be set for BUILTIN class %s", name);
} else {
guarantee(k->loader_type() == 0,
guarantee(k->is_shared_unregistered_class(),
"Class loader type must not be set for UNREGISTERED class %s", name);
}
}
@@ -841,13 +841,13 @@ void DynamicArchiveBuilder::make_klasses_shareable() {
InstanceKlass* ik = _klasses->at(i);
ClassLoaderData *cld = ik->class_loader_data();
if (cld->is_boot_class_loader_data()) {
ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
ik->set_shared_class_loader_type(ClassLoader::BOOT_LOADER);
}
else if (cld->is_platform_class_loader_data()) {
ik->set_class_loader_type(ClassLoader::PLATFORM_LOADER);
ik->set_shared_class_loader_type(ClassLoader::PLATFORM_LOADER);
}
else if (cld->is_system_class_loader_data()) {
ik->set_class_loader_type(ClassLoader::APP_LOADER);
ik->set_shared_class_loader_type(ClassLoader::APP_LOADER);
}

MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
@@ -1852,7 +1852,7 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
if (ik->init_state() < InstanceKlass::linked &&
!SystemDictionaryShared::has_class_failed_verification(ik)) {
bool saved = BytecodeVerificationLocal;
if (ik->loader_type() == 0 && ik->class_loader() == NULL) {
if (ik->is_shared_unregistered_class() && ik->class_loader() == NULL) {
// The verification decision is based on BytecodeVerificationRemote
// for non-system classes. Since we are using the NULL classloader
// to load non-system classes for customized class loaders during dumping,
@@ -2471,7 +2471,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
}
}

void InstanceKlass::set_class_loader_type(s2 loader_type) {
void InstanceKlass::set_shared_class_loader_type(s2 loader_type) {
switch (loader_type) {
case ClassLoader::BOOT_LOADER:
_misc_flags |= _misc_is_shared_boot_class;
@@ -262,7 +262,7 @@ class InstanceKlass: public Klass {
_misc_is_being_redefined = 1 << 16, // used for locking redefinition
_misc_has_contended_annotations = 1 << 17 // has @Contended annotation
};
u2 loader_type_bits() {
u2 shared_loader_type_bits() const {
return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
}
u4 _misc_flags;
@@ -353,10 +353,7 @@ class InstanceKlass: public Klass {
static bool _disable_method_binary_search;

public:
u2 loader_type() {
return _misc_flags & loader_type_bits();
}

// The three BUILTIN class loader types
bool is_shared_boot_class() const {
return (_misc_flags & _misc_is_shared_boot_class) != 0;
}
@@ -366,12 +363,16 @@ class InstanceKlass: public Klass {
bool is_shared_app_class() const {
return (_misc_flags & _misc_is_shared_app_class) != 0;
}
// The UNREGISTERED class loader type
bool is_shared_unregistered_class() const {
return (_misc_flags & shared_loader_type_bits()) == 0;
}

void clear_class_loader_type() {
_misc_flags &= ~loader_type_bits();
void clear_shared_class_loader_type() {
_misc_flags &= ~shared_loader_type_bits();
}

void set_class_loader_type(s2 loader_type);
void set_shared_class_loader_type(s2 loader_type);

bool has_nonstatic_fields() const {
return (_misc_flags & _misc_has_nonstatic_fields) != 0;

0 comments on commit 7ba18fc

Please sign in to comment.