--- old/src/hotspot/share/classfile/systemDictionary.cpp 2020-03-26 15:58:06.000000000 -0700 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2020-03-26 15:58:05.000000000 -0700 @@ -111,6 +111,46 @@ 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* 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 @@ // 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 @@ // 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* 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* 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 @@ // 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 @@ 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 @@ 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"); @@ -2325,6 +2375,42 @@ } } +// 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