8238358: Implementation of JEP 371: Hidden Classes

Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
This commit is contained in:
Mandy Chung 2020-04-21 06:55:38 -07:00
parent 642041adbc
commit 7cc1371059
198 changed files with 9526 additions and 1575 deletions

View file

@ -111,6 +111,46 @@ oop SystemDictionary::_java_platform_loader = NULL;
const int defaultProtectionDomainCacheSize = 1009;
ClassLoadInfo::ClassLoadInfo() {
_protection_domain = Handle();
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle();
_is_hidden = false;
_is_strong_hidden = false;
_can_access_vm_annotations = false;
}
ClassLoadInfo::ClassLoadInfo(Handle protection_domain) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle();
_is_hidden = false;
_is_strong_hidden = false;
_can_access_vm_annotations = false;
}
ClassLoadInfo::ClassLoadInfo(Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
InstanceKlass* dynamic_nest_host,
Handle class_data,
bool is_hidden,
bool is_strong_hidden,
bool can_access_vm_annotations) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = unsafe_anonymous_host;
_cp_patches = cp_patches;
_class_hidden_info._dynamic_nest_host = dynamic_nest_host;
_class_hidden_info._class_data = class_data;
_is_hidden = is_hidden;
_is_strong_hidden = is_strong_hidden;
_can_access_vm_annotations = can_access_vm_annotations;
}
// ----------------------------------------------------------------------------
// Java-level SystemLoader and PlatformLoader
@ -822,7 +862,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// class loaders holding the ObjectLock shouldn't find the class here
InstanceKlass* check = find_class(d_hash, name, dictionary);
if (check != NULL) {
// Klass is already loaded, so return it after checking/adding protection domain
// Klass is already loaded, so return it after checking/adding protection domain
k = check;
class_has_been_loaded = true;
}
@ -982,24 +1022,36 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
// Note: this method is much like resolve_from_stream, but
// does not publish the classes via the SystemDictionary.
// Handles unsafe_DefineAnonymousClass and redefineclasses
// RedefinedClasses do not add to the class hierarchy
// Handles Lookup.defineClass hidden, unsafe_DefineAnonymousClass
// and redefineclasses. RedefinedClasses do not add to the class hierarchy.
InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo& cl_info,
TRAPS) {
EventClassLoad class_load_start_event;
ClassLoaderData* loader_data;
if (unsafe_anonymous_host != NULL) {
// Create a new CLD for an unsafe anonymous class, that uses the same class loader
// as the unsafe_anonymous_host
guarantee(unsafe_anonymous_host->class_loader() == class_loader(), "should be the same");
loader_data = ClassLoaderData::unsafe_anonymous_class_loader_data(class_loader);
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL;
if (is_unsafe_anon_class) {
// - for unsafe anonymous class: create a new CLD whith a class holder that uses
// the same class loader as the unsafe_anonymous_host.
guarantee(cl_info.unsafe_anonymous_host()->class_loader() == class_loader(),
"should be the same");
loader_data = ClassLoaderData::has_class_mirror_holder_cld(class_loader);
} else if (cl_info.is_hidden()) {
// - for hidden classes that are not strong: create a new CLD that has a class holder and
// whose loader is the Lookup class' loader.
// - for hidden class: add the class to the Lookup class' loader's CLD.
if (!cl_info.is_strong_hidden()) {
loader_data = ClassLoaderData::has_class_mirror_holder_cld(class_loader);
} else {
// This hidden class goes into the regular CLD pool for this loader.
loader_data = register_loader(class_loader);
}
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
@ -1015,15 +1067,16 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
InstanceKlass* k = KlassFactory::create_from_stream(st,
class_name,
loader_data,
protection_domain,
unsafe_anonymous_host,
cp_patches,
cl_info,
CHECK_NULL);
if (unsafe_anonymous_host != NULL && k != NULL) {
// Unsafe anonymous classes must update ClassLoaderData holder (was unsafe_anonymous_host loader)
// so that they can be unloaded when the mirror is no longer referenced.
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
if ((cl_info.is_hidden() || is_unsafe_anon_class) && k != NULL) {
// Hidden classes that are not strong and unsafe anonymous classes must update
// ClassLoaderData holder so that they can be unloaded when the mirror is no
// longer referenced.
if (!cl_info.is_strong_hidden() || is_unsafe_anon_class) {
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
}
{
MutexLocker mu_r(THREAD, Compile_lock);
@ -1036,12 +1089,14 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL);
if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches);
if (cl_info.cp_patches() != NULL) {
k->constants()->patch_resolved_references(cl_info.cp_patches());
}
// If it's anonymous, initialize it now, since nobody else will.
k->eager_initialize(CHECK_NULL);
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}
// notify jvmti
if (JvmtiExport::should_post_class_load()) {
@ -1052,7 +1107,7 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
post_class_load_event(&class_load_start_event, k, loader_data);
}
}
assert(unsafe_anonymous_host != NULL || NULL == cp_patches,
assert(is_unsafe_anon_class || NULL == cl_info.cp_patches(),
"cp_patches only found with unsafe_anonymous_host");
return k;
@ -1107,13 +1162,8 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
if (st->buffer() == NULL) {
return NULL;
}
k = KlassFactory::create_from_stream(st,
class_name,
loader_data,
protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
CHECK_NULL);
ClassLoadInfo cl_info(protection_domain);
k = KlassFactory::create_from_stream(st, class_name, loader_data, cl_info, CHECK_NULL);
}
assert(k != NULL, "no klass created");
@ -2327,6 +2377,42 @@ Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool,
}
}
// Add an entry to resolution error table to record an error in resolving or
// validating a nest host. This is used to construct informative error
// messages when IllegalAccessError's occur. If an entry already exists it will
// be updated with the nest host error message.
void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool,
int which,
const char* message) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
if (entry != NULL) {
assert(entry->nest_host_error() == NULL, "Nest host error message already set!");
entry->set_nest_host_error(message);
} else {
resolution_errors()->add_entry(index, hash, pool, which, message);
}
}
}
// Lookup any nest host error
const char* SystemDictionary::find_nest_host_error(const constantPoolHandle& pool, int which) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
if (entry != NULL) {
return entry->nest_host_error();
} else {
return NULL;
}
}
}
// Signature constraints ensure that callers and callees agree about
// the meaning of type names in their signatures. This routine is the