# HG changeset patch # User mchung # Date 1585265017 25200 # Thu Mar 26 16:23:37 2020 -0700 # Node ID d764d4d34e41fcc001e313e87e575edd4f8a16e4 # Parent e886b0d7ff87fc85663321b7eb79cf189b1ab4d5 8238358: Implementation of JEP 371: Hidden Classes Reviewed-by: duke Contributed-by: mandy.chung@oracle.com, lois.foltan@oracle.com, david.holmes@oracle.com, harold.seigel@oracle.com, serguei.spitsyn@oracle.com, alex.buckley@oracle.com, jamsheed.c.m@oracle.com diff --git a/make/hotspot/symbols/symbols-unix b/make/hotspot/symbols/symbols-unix --- a/make/hotspot/symbols/symbols-unix +++ b/make/hotspot/symbols/symbols-unix @@ -142,6 +142,7 @@ JVM_InvokeMethod JVM_IsArrayClass JVM_IsConstructorIx +JVM_IsHiddenClass JVM_IsInterface JVM_IsPrimitiveClass JVM_IsRecord @@ -151,6 +152,7 @@ JVM_IsVMGeneratedMethodIx JVM_LatestUserDefinedLoader JVM_LoadLibrary +JVM_LookupDefineClass JVM_MaxMemory JVM_MaxObjectInspectionAge JVM_MonitorNotify diff --git a/src/hotspot/share/aot/aotCodeHeap.cpp b/src/hotspot/share/aot/aotCodeHeap.cpp --- a/src/hotspot/share/aot/aotCodeHeap.cpp +++ b/src/hotspot/share/aot/aotCodeHeap.cpp @@ -1050,7 +1050,7 @@ InstanceKlass* dyno = InstanceKlass::cast(dyno_klass); - if (!dyno->is_unsafe_anonymous()) { + if (!dyno->is_hidden() && !dyno->is_unsafe_anonymous()) { if (_klasses_got[dyno_data->_got_index] != dyno) { // compile-time class different from runtime class, fail and deoptimize sweep_dependent_methods(holder_data); diff --git a/src/hotspot/share/aot/aotLoader.cpp b/src/hotspot/share/aot/aotLoader.cpp --- a/src/hotspot/share/aot/aotLoader.cpp +++ b/src/hotspot/share/aot/aotLoader.cpp @@ -43,7 +43,7 @@ #define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator lib = libraries()->begin(); lib != libraries()->end(); ++lib) void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) { - if (ik->is_unsafe_anonymous()) { + if (ik->is_hidden() || ik->is_unsafe_anonymous()) { // don't even bother return; } @@ -58,7 +58,7 @@ uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) { assert(UseAOT, "called only when AOT is enabled"); - if (ik->is_unsafe_anonymous()) { + if (ik->is_hidden() || ik->is_unsafe_anonymous()) { // don't even bother return 0; } diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -223,9 +223,10 @@ holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("jdk/incubator/foreign") || holder->is_in_package("java/lang")) return true; - // Trust VM unsafe anonymous classes. They are private API (jdk.internal.misc.Unsafe) - // and can't be serialized, so there is no hacking of finals going on with them. - if (holder->is_unsafe_anonymous()) + // Trust VM hidden and unsafe anonymous classes. They are created via Lookup.defineClass or + // the private API (jdk.internal.misc.Unsafe) and can't be serialized, so there is no hacking + // of finals going on with them. + if (holder->is_hidden() || holder->is_unsafe_anonymous()) return true; // Trust final fields in all boxed classes if (holder->is_box_klass()) diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -63,6 +63,7 @@ _has_nonstatic_fields = ik->has_nonstatic_fields(); _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods(); _is_unsafe_anonymous = ik->is_unsafe_anonymous(); + _is_hidden = ik->is_hidden(); _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: _has_injected_fields = -1; _implementor = NULL; // we will fill these lazily @@ -73,13 +74,13 @@ // InstanceKlass are created for both weak and strong metadata. Ensuring this metadata // alive covers the cases where there are weak roots without performance cost. oop holder = ik->klass_holder(); - if (ik->is_unsafe_anonymous()) { + if (ik->class_loader_data()->has_class_mirror_holder()) { // Though ciInstanceKlass records class loader oop, it's not enough to keep - // VM unsafe anonymous classes alive (loader == NULL). Klass holder should + // VM weak hidden and unsafe anonymous classes alive (loader == NULL). Klass holder should // be used instead. It is enough to record a ciObject, since cached elements are never removed // during ciObjectFactory lifetime. ciObjectFactory itself is created for // every compilation and lives for the whole duration of the compilation. - assert(holder != NULL, "holder of unsafe anonymous class is the mirror which is never null"); + assert(holder != NULL, "holder of hidden or unsafe anonymous class is the mirror which is never null"); (void)CURRENT_ENV->get_object(holder); } @@ -123,6 +124,7 @@ _nonstatic_fields = NULL; _has_injected_fields = -1; _is_unsafe_anonymous = false; + _is_hidden = false; _loader = loader; _protection_domain = protection_domain; _is_shared = false; diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -56,6 +56,7 @@ bool _has_nonstatic_fields; bool _has_nonstatic_concrete_methods; bool _is_unsafe_anonymous; + bool _is_hidden; ciFlags _flags; jint _nonstatic_field_size; @@ -195,6 +196,10 @@ return _is_unsafe_anonymous; } + bool is_hidden() { + return _is_hidden; + } + ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1092,7 +1092,7 @@ assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, ""); } // If this annotation name has an ID, report it (or _none). - ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name); + ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name, const bool can_access_vm_annotations); // Set the annotation name: void set_annotation(ID id) { assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob"); @@ -1225,6 +1225,7 @@ const u1* buffer, int limit, AnnotationCollector* coll, ClassLoaderData* loader_data, + const bool can_access_vm_annotations, TRAPS) { assert(cp != NULL, "invariant"); @@ -1270,7 +1271,7 @@ } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); + AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations); if (AnnotationCollector::_unknown == id) continue; coll->set_annotation(id); @@ -1396,6 +1397,7 @@ runtime_visible_annotations_length, parsed_annotations, _loader_data, + _can_access_vm_annotations, CHECK); cfs->skip_u1_fast(runtime_visible_annotations_length); } else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2059,12 +2061,13 @@ AnnotationCollector::ID AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, - const Symbol* name) { + const Symbol* name, + const bool can_access_vm_annotations) { const vmSymbols::SID sid = vmSymbols::find_sid(name); // Privileged code can use all annotations. Other code silently drops some. - const bool privileged = loader_data->is_the_null_class_loader_data() || + const bool privileged = loader_data->is_boot_class_loader_data() || loader_data->is_platform_class_loader_data() || - loader_data->is_unsafe_anonymous(); + can_access_vm_annotations; switch (sid) { case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): { if (_location != _in_method) break; // only allow for methods @@ -2671,6 +2674,7 @@ runtime_visible_annotations_length, &parsed_annotations, _loader_data, + _can_access_vm_annotations, CHECK_NULL); cfs->skip_u1_fast(runtime_visible_annotations_length); } else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2865,6 +2869,10 @@ if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(methodHandle(THREAD, m)); + if (is_hidden()) { // Mark methods in hidden classes as 'hidden'. + m->set_hidden(true); + } + // Copy annotations copy_method_annotations(m->constMethod(), runtime_visible_annotations, @@ -3596,6 +3604,7 @@ runtime_visible_annotations_length, parsed_annotations, _loader_data, + _can_access_vm_annotations, CHECK); cfs->skip_u1_fast(runtime_visible_annotations_length); } else if (tag == vmSymbols::tag_runtime_invisible_annotations()) { @@ -5592,7 +5601,9 @@ } } -InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) { +InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, + const ClassInstanceInfo& cl_inst_info, + TRAPS) { if (_klass != NULL) { return _klass; } @@ -5600,7 +5611,11 @@ InstanceKlass* const ik = InstanceKlass::allocate_instance_klass(*this, CHECK_NULL); - fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL); + if (is_hidden()) { + mangle_hidden_class_name(ik); + } + + fill_instance_klass(ik, changed_by_loadhook, cl_inst_info, CHECK_NULL); assert(_klass == ik, "invariant"); @@ -5626,7 +5641,10 @@ return ik; } -void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) { +void ClassFileParser::fill_instance_klass(InstanceKlass* ik, + bool changed_by_loadhook, + const ClassInstanceInfo& cl_inst_info, + TRAPS) { assert(ik != NULL, "invariant"); // Set name and CLD before adding to CLD @@ -5662,6 +5680,11 @@ // the parser onto the InstanceKlass* apply_parsed_class_metadata(ik, _java_fields_count, CHECK); + // can only set dynamic nest-host after static nest information is set + if (cl_inst_info.dynamic_nest_host() != NULL) { + ik->set_nest_host(cl_inst_info.dynamic_nest_host(), THREAD); + } + // note that is not safe to use the fields in the parser from this point on assert(NULL == _cp, "invariant"); assert(NULL == _fields, "invariant"); @@ -5686,11 +5709,11 @@ ik->set_this_class_index(_this_class_index); - if (is_unsafe_anonymous()) { + if (_is_hidden || is_unsafe_anonymous()) { // _this_class_index is a CONSTANT_Class entry that refers to this - // anonymous class itself. If this class needs to refer to its own methods or - // fields, it would use a CONSTANT_MethodRef, etc, which would reference - // _this_class_index. However, because this class is anonymous (it's + // hidden or anonymous class itself. If this class needs to refer to its own + // methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference + // _this_class_index. However, because this class is hidden or anonymous (it's // not stored in SystemDictionary), _this_class_index cannot be resolved // with ConstantPool::klass_at_impl, which does a SystemDictionary lookup. // Therefore, we must eagerly resolve _this_class_index now. @@ -5706,6 +5729,9 @@ assert (ik->is_unsafe_anonymous(), "should be the same"); ik->set_unsafe_anonymous_host(_unsafe_anonymous_host); } + if (_is_hidden) { + ik->set_is_hidden(); + } // Set PackageEntry for this_klass oop cl = ik->class_loader(); @@ -5785,6 +5811,7 @@ Handle(THREAD, _loader_data->class_loader()), module_handle, _protection_domain, + cl_inst_info.class_data(), CHECK); assert(_all_mirandas != NULL, "invariant"); @@ -5869,7 +5896,6 @@ _class_name->increment_refcount(); } - // For an unsafe anonymous class that is in the unnamed package, move it to its host class's // package by prepending its host class's package name to its class name and setting // its _class_name field. @@ -5922,8 +5948,8 @@ } static bool relax_format_check_for(ClassLoaderData* loader_data) { - bool trusted = (loader_data->is_the_null_class_loader_data() || - SystemDictionary::is_platform_class_loader(loader_data->class_loader())); + bool trusted = loader_data->is_boot_class_loader_data() || + loader_data->is_platform_class_loader_data(); bool need_verify = // verifyAll (BytecodeVerificationLocal && BytecodeVerificationRemote) || @@ -5935,17 +5961,16 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, Symbol* name, ClassLoaderData* loader_data, - Handle protection_domain, - const InstanceKlass* unsafe_anonymous_host, - GrowableArray* cp_patches, + const ClassLoadInfo* cl_info, Publicity pub_level, TRAPS) : _stream(stream), - _requested_name(name), _class_name(NULL), _loader_data(loader_data), - _unsafe_anonymous_host(unsafe_anonymous_host), - _cp_patches(cp_patches), + _unsafe_anonymous_host(cl_info->unsafe_anonymous_host()), + _cp_patches(cl_info->cp_patches()), + _is_hidden(cl_info->is_hidden()), + _can_access_vm_annotations(cl_info->can_access_vm_annotations()), _num_patched_klasses(0), _max_num_patched_klasses(0), _orig_cp_size(0), @@ -5976,7 +6001,7 @@ _itable_size(0), _num_miranda_methods(0), _rt(REF_NONE), - _protection_domain(protection_domain), + _protection_domain(cl_info->protection_domain()), _access_flags(), _pub_level(pub_level), _bad_constant_seen(0), @@ -6179,10 +6204,15 @@ cp_size, CHECK); _orig_cp_size = cp_size; - if (int(cp_size) + _max_num_patched_klasses > 0xffff) { - THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes"); - } - cp_size += _max_num_patched_klasses; + if (is_hidden()) { // Add a slot for hidden class name. + assert(_max_num_patched_klasses == 0, "Sanity check"); + cp_size++; + } else { + if (int(cp_size) + _max_num_patched_klasses > 0xffff) { + THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes"); + } + cp_size += _max_num_patched_klasses; + } _cp = ConstantPool::allocate(_loader_data, cp_size, @@ -6233,36 +6263,67 @@ Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index); assert(class_name_in_cp != NULL, "class_name can't be null"); - // Update _class_name to reflect the name in the constant pool - update_class_name(class_name_in_cp); - // Don't need to check whether this class name is legal or not. // It has been checked when constant pool is parsed. // However, make sure it is not an array type. if (_need_verify) { - guarantee_property(_class_name->char_at(0) != JVM_SIGNATURE_ARRAY, + guarantee_property(class_name_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY, "Bad class name in class file %s", CHECK); } - // Checks if name in class file matches requested name - if (_requested_name != NULL && _requested_name != _class_name) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_NoClassDefFoundError(), - "%s (wrong name: %s)", - _class_name->as_C_string(), - _requested_name != NULL ? _requested_name->as_C_string() : "NoName" - ); - return; - } - - // if this is an anonymous class fix up its name if it's in the unnamed +#ifdef ASSERT + // Basic sanity checks + assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants"); + + if (_unsafe_anonymous_host != NULL) { + assert(_class_name == vmSymbols::unknown_class_name(), "A named anonymous class???"); + } + if (_is_hidden) { + assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name"); + } +#endif + + // Update the _class_name as needed depending on whether this is a named, + // un-named, hidden or unsafe-anonymous class. + + if (_is_hidden) { + assert(_class_name != NULL, "Unexpected null _class_name"); +#ifdef ASSERT + if (_need_verify) { + verify_legal_class_name(_class_name, CHECK); + } +#endif + + // NOTE: !_is_hidden does not imply "findable" as it could be an old-style + // "hidden" unsafe-anonymous class + + // If this is an anonymous class fix up its name if it is in the unnamed // package. Otherwise, throw IAE if it is in a different package than // its host class. - if (_unsafe_anonymous_host != NULL) { + } else if (_unsafe_anonymous_host != NULL) { + update_class_name(class_name_in_cp); fix_unsafe_anonymous_class_name(CHECK); + + } else { + // Check if name in class file matches given name + if (_class_name != class_name_in_cp) { + if (_class_name != vmSymbols::unknown_class_name()) { + ResourceMark rm(THREAD); + Exceptions::fthrow(THREAD_AND_LOCATION, + vmSymbols::java_lang_NoClassDefFoundError(), + "%s (wrong name: %s)", + class_name_in_cp->as_C_string(), + _class_name->as_C_string() + ); + return; + } else { + // The class name was not known by the caller so we set it from + // the value in the CP. + update_class_name(class_name_in_cp); + } + // else nothing to do: the expected class name matches what is in the CP + } } // Verification prevents us from creating names with dots in them, this @@ -6287,9 +6348,10 @@ warning("DumpLoadedClassList and CDS are not supported in exploded build"); DumpLoadedClassList = NULL; } else if (SystemDictionaryShared::is_sharing_possible(_loader_data) && + !_is_hidden && _unsafe_anonymous_host == NULL) { // Only dump the classes that can be stored into CDS archive. - // Unsafe anonymous classes such as generated LambdaForm classes are also not included. + // Hidden and unsafe anonymous classes such as generated LambdaForm classes are also not included. oop class_loader = _loader_data->class_loader(); ResourceMark rm(THREAD); bool skip = false; @@ -6384,6 +6446,35 @@ // all bytes in stream read and parsed } +void ClassFileParser::mangle_hidden_class_name(InstanceKlass* const ik) { + ResourceMark rm; + // Construct hidden name from _class_name, "+", and &ik. Note that we can't + // use a '/' because that confuses finding the class's package. Also, can't + // use an illegal char such as ';' because that causes serialization issues + // and issues with hidden classes that create their own hidden classes. + char addr_buf[20]; + jio_snprintf(addr_buf, 20, INTPTR_FORMAT, p2i(ik)); + size_t new_name_len = _class_name->utf8_length() + 2 + strlen(addr_buf); + char* new_name = NEW_RESOURCE_ARRAY(char, new_name_len); + jio_snprintf(new_name, new_name_len, "%s+%s", + _class_name->as_C_string(), addr_buf); + update_class_name(SymbolTable::new_symbol(new_name)); + + // Add a Utf8 entry containing the hidden name. + assert(_class_name != NULL, "Unexpected null _class_name"); + int hidden_index = _orig_cp_size; // this is an extra slot we added + _cp->symbol_at_put(hidden_index, _class_name); + + // Update this_class_index's slot in the constant pool with the new Utf8 entry. + // We have to update the resolved_klass_index and the name_index together + // so extract the existing resolved_klass_index first. + CPKlassSlot cp_klass_slot = _cp->klass_slot_at(_this_class_index); + int resolved_klass_index = cp_klass_slot.resolved_klass_index(); + _cp->unresolved_klass_at_put(_this_class_index, hidden_index, resolved_klass_index); + assert(_cp->klass_slot_at(_this_class_index).name_index() == _orig_cp_size, + "Bad name_index"); +} + void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const stream, ConstantPool* cp, TRAPS) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -37,6 +37,8 @@ class Array; class ClassFileStream; class ClassLoaderData; +class ClassLoadInfo; +class ClassInstanceInfo; class CompressedLineNumberWriteStream; class ConstMethod; class FieldInfo; @@ -109,11 +111,12 @@ typedef void unsafe_u2; const ClassFileStream* _stream; // Actual input stream - const Symbol* _requested_name; Symbol* _class_name; mutable ClassLoaderData* _loader_data; const InstanceKlass* _unsafe_anonymous_host; GrowableArray* _cp_patches; // overrides for CP entries + const bool _is_hidden; + const bool _can_access_vm_annotations; int _num_patched_klasses; int _max_num_patched_klasses; int _orig_cp_size; @@ -201,6 +204,8 @@ void parse_stream(const ClassFileStream* const stream, TRAPS); + void mangle_hidden_class_name(InstanceKlass* const ik); + void post_process_parsed_stream(const ClassFileStream* const stream, ConstantPool* cp, TRAPS); @@ -208,7 +213,9 @@ void prepend_host_package_name(const InstanceKlass* unsafe_anonymous_host, TRAPS); void fix_unsafe_anonymous_class_name(TRAPS); - void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS); + void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, + const ClassInstanceInfo& cl_inst_info, TRAPS); + void set_klass(InstanceKlass* instance); void set_class_bad_constant_seen(short bad_constant); @@ -527,21 +534,19 @@ FieldLayoutInfo* info, TRAPS); - void update_class_name(Symbol* new_name); + void update_class_name(Symbol* new_name); public: ClassFileParser(ClassFileStream* stream, Symbol* name, ClassLoaderData* loader_data, - Handle protection_domain, - const InstanceKlass* unsafe_anonymous_host, - GrowableArray* cp_patches, + const ClassLoadInfo* cl_info, Publicity pub_level, TRAPS); ~ClassFileParser(); - InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, TRAPS); + InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, const ClassInstanceInfo& cl_inst_info, TRAPS); const ClassFileStream* clone_stream() const; @@ -557,6 +562,7 @@ u2 this_class_index() const { return _this_class_index; } bool is_unsafe_anonymous() const { return _unsafe_anonymous_host != NULL; } + bool is_hidden() const { return _is_hidden; } bool is_interface() const { return _access_flags.is_interface(); } const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; } diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -1283,13 +1283,12 @@ ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); Handle protection_domain; + ClassLoadInfo cl_info(protection_domain); InstanceKlass* result = KlassFactory::create_from_stream(stream, name, loader_data, - protection_domain, - NULL, // unsafe_anonymous_host - NULL, // cp_patches + cl_info, THREAD); if (HAS_PENDING_EXCEPTION) { if (DumpSharedSpaces) { @@ -1331,8 +1330,8 @@ Arguments::assert_is_dumping_archive(); assert(stream != NULL, "sanity"); - if (ik->is_unsafe_anonymous()) { - // We do not archive unsafe anonymous classes. + if (ik->is_hidden() || ik->is_unsafe_anonymous()) { + // We do not archive hidden or unsafe anonymous classes. return; } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -126,16 +126,16 @@ _name_and_id = SymbolTable::new_symbol(cl_instance_name_and_id); } -ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous) : +ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder) : _metaspace(NULL), _metaspace_lock(new Mutex(Mutex::leaf+1, "Metaspace allocation lock", true, Mutex::_safepoint_check_never)), - _unloading(false), _is_unsafe_anonymous(is_unsafe_anonymous), + _unloading(false), _has_class_mirror_holder(has_class_mirror_holder), _modified_oops(true), _accumulated_modified_oops(false), // An unsafe anonymous class loader data doesn't have anything to keep // it from being unloaded during parsing of the unsafe anonymous class. // The null-class-loader should always be kept alive. - _keep_alive((is_unsafe_anonymous || h_class_loader.is_null()) ? 1 : 0), + _keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0), _claim(0), _handles(), _klasses(NULL), _packages(NULL), _modules(NULL), _unnamed_module(NULL), _dictionary(NULL), @@ -150,13 +150,13 @@ initialize_name(h_class_loader); } - if (!is_unsafe_anonymous) { - // The holder is initialized later for unsafe anonymous classes, and before calling anything - // that call class_loader(). + if (!has_class_mirror_holder) { + // The holder is initialized later for weak hidden and unsafe anonymous classes, + // and before calling anything that call class_loader(). initialize_holder(h_class_loader); - // A ClassLoaderData created solely for an unsafe anonymous class should never have a - // ModuleEntryTable or PackageEntryTable created for it. The defining package + // A ClassLoaderData created solely for an weak hidden or unsafe anonymous class should + // never have a ModuleEntryTable or PackageEntryTable created for it. The defining package // and module for an unsafe anonymous class will be found in its host class. _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); if (h_class_loader.is_null()) { @@ -291,20 +291,20 @@ } } -// Unsafe anonymous classes have their own ClassLoaderData that is marked to keep alive +// Weak hidden and unsafe anonymous classes have their own ClassLoaderData that is marked to keep alive // while the class is being parsed, and if the class appears on the module fixup list. -// Due to the uniqueness that no other class shares the unsafe anonymous class' name or -// ClassLoaderData, no other non-GC thread has knowledge of the unsafe anonymous class while +// Due to the uniqueness that no other class shares the hidden or unsafe anonymous class' name or +// ClassLoaderData, no other non-GC thread has knowledge of the hidden or unsafe anonymous class while // it is being defined, therefore _keep_alive is not volatile or atomic. void ClassLoaderData::inc_keep_alive() { - if (is_unsafe_anonymous()) { + if (has_class_mirror_holder()) { assert(_keep_alive > 0, "Invalid keep alive increment count"); _keep_alive++; } } void ClassLoaderData::dec_keep_alive() { - if (is_unsafe_anonymous()) { + if (has_class_mirror_holder()) { assert(_keep_alive > 0, "Invalid keep alive decrement count"); _keep_alive--; } @@ -410,21 +410,21 @@ // Do not need to record dependency if the dependency is to a class whose // class loader data is never freed. (i.e. the dependency's class loader - // is one of the three builtin class loaders and the dependency is not - // unsafe anonymous.) + // is one of the three builtin class loaders and the dependency's class + // loader data has a ClassLoader holder, not a Class holder.) if (to_cld->is_permanent_class_loader_data()) { return; } oop to; - if (to_cld->is_unsafe_anonymous()) { - // Just return if an unsafe anonymous class is attempting to record a dependency - // to itself. (Note that every unsafe anonymous class has its own unique class + if (to_cld->has_class_mirror_holder()) { + // Just return if a weak hidden or unsafe anonymous class is attempting to record a dependency + // to itself. (Note that every weak hidden or unsafe anonymous class has its own unique class // loader data.) if (to_cld == from_cld) { return; } - // Unsafe anonymous class dependencies are through the mirror. + // Hidden and unsafe anonymous class dependencies are through the mirror. to = k->java_mirror(); } else { to = to_cld->class_loader(); @@ -572,7 +572,7 @@ const int _default_loader_dictionary_size = 107; Dictionary* ClassLoaderData::create_dictionary() { - assert(!is_unsafe_anonymous(), "unsafe anonymous class loader data do not have a dictionary"); + assert(!has_class_mirror_holder(), "class mirror holder cld does not have a dictionary"); int size; bool resizable = false; if (_the_null_class_loader_data == NULL) { @@ -618,7 +618,7 @@ // Unloading support bool ClassLoaderData::is_alive() const { - bool alive = keep_alive() // null class loader and incomplete unsafe anonymous klasses. + bool alive = keep_alive() // null class loader and incomplete weak hidden or unsafe anonymous klasses. || (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing. return alive; @@ -716,13 +716,13 @@ // Returns true if this class loader data is for the app class loader // or a user defined system class loader. (Note that the class loader -// data may be unsafe anonymous.) +// data may have a Class holder.) bool ClassLoaderData::is_system_class_loader_data() const { return SystemDictionary::is_system_class_loader(class_loader()); } // Returns true if this class loader data is for the platform class loader. -// (Note that the class loader data may be unsafe anonymous.) +// (Note that the class loader data may have a Class holder.) bool ClassLoaderData::is_platform_class_loader_data() const { return SystemDictionary::is_platform_class_loader(class_loader()); } @@ -730,8 +730,8 @@ // Returns true if the class loader for this class loader data is one of // the 3 builtin (boot application/system or platform) class loaders, // including a user-defined system class loader. Note that if the class -// loader data is for an unsafe anonymous class then it may get freed by a GC -// even if its class loader is one of these loaders. +// loader data is for a weak hidden or unsafe anonymous class then it may +// get freed by a GC even if its class loader is one of these loaders. bool ClassLoaderData::is_builtin_class_loader_data() const { return (is_boot_class_loader_data() || SystemDictionary::is_system_class_loader(class_loader()) || @@ -740,9 +740,9 @@ // Returns true if this class loader data is a class loader data // that is not ever freed by a GC. It must be the CLD for one of the builtin -// class loaders and not the CLD for an unsafe anonymous class. +// class loaders and not the CLD for a weak hidden or unsafe anonymous class. bool ClassLoaderData::is_permanent_class_loader_data() const { - return is_builtin_class_loader_data() && !is_unsafe_anonymous(); + return is_builtin_class_loader_data() && !has_class_mirror_holder(); } ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() { @@ -759,8 +759,8 @@ if (this == the_null_class_loader_data()) { assert (class_loader() == NULL, "Must be"); metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType); - } else if (is_unsafe_anonymous()) { - metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::UnsafeAnonymousMetaspaceType); + } else if (has_class_mirror_holder()) { + metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ClassMirrorHolderMetaspaceType); } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) { metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType); } else { @@ -877,8 +877,8 @@ } } -// These CLDs are to contain unsafe anonymous classes used for JSR292 -ClassLoaderData* ClassLoaderData::unsafe_anonymous_class_loader_data(Handle loader) { +// These CLDs are to contain weak hidden or unsafe anonymous classes used for JSR292 +ClassLoaderData* ClassLoaderData::has_class_mirror_holder_cld(Handle loader) { // Add a new class loader data to the graph. return ClassLoaderDataGraph::add(loader, true); } @@ -920,8 +920,8 @@ // loader data: 0xsomeaddr of 'bootstrap' out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name_and_id()); } - if (is_unsafe_anonymous()) { - out->print(" unsafe anonymous"); + if (_has_class_mirror_holder) { + out->print(" has a class holder"); } } @@ -931,7 +931,7 @@ void ClassLoaderData::print_on(outputStream* out) const { out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {", p2i(this), p2i(_class_loader.ptr_raw()), loader_name_and_id()); - if (is_unsafe_anonymous()) out->print(" unsafe anonymous"); + if (has_class_mirror_holder()) out->print(" has a class holder"); if (claimed()) out->print(" claimed"); if (is_unloading()) out->print(" unloading"); out->print(" metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null())); @@ -951,8 +951,8 @@ assert_locked_or_safepoint(_metaspace_lock); oop cl = class_loader(); - guarantee(this == class_loader_data(cl) || is_unsafe_anonymous(), "Must be the same"); - guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_unsafe_anonymous(), "must be"); + guarantee(this == class_loader_data(cl) || has_class_mirror_holder(), "Must be the same"); + guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || has_class_mirror_holder(), "must be"); // Verify the integrity of the allocated space. if (metaspace_or_null() != NULL) { diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -117,17 +117,19 @@ // classes in the class loader are allocated. Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup. bool _unloading; // true if this class loader goes away - bool _is_unsafe_anonymous; // CLD is dedicated to one class and that class determines the CLDs lifecycle. - // For example, an unsafe anonymous class. + bool _has_class_mirror_holder; // If true, CLD is dedicated to one class and that class determines + // the CLDs lifecycle. For example, a non-strong hidden class or an + // unsafe anonymous class. Arrays of these classes are also assigned + // to these class loader datas. // Remembered sets support for the oops in the class loader data. bool _modified_oops; // Card Table Equivalent (YC/CMS support) bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support) int _keep_alive; // if this CLD is kept alive. - // Used for unsafe anonymous classes and the boot class - // loader. _keep_alive does not need to be volatile or - // atomic since there is one unique CLD per unsafe anonymous class. + // Used for weak hidden classes, unsafe anonymous classes and the + // boot class loader. _keep_alive does not need to be volatile or + // atomic since there is one unique CLD per weak hidden or unsafe anonymous class. volatile int _claim; // non-zero if claimed, for example during GC traces. // To avoid applying oop closure more than once. @@ -162,7 +164,7 @@ void set_next(ClassLoaderData* next) { _next = next; } ClassLoaderData* next() const { return Atomic::load(&_next); } - ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous); + ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder); ~ClassLoaderData(); // The CLD are not placed in the Heap, so the Card Table or @@ -231,7 +233,7 @@ Mutex* metaspace_lock() const { return _metaspace_lock; } - bool is_unsafe_anonymous() const { return _is_unsafe_anonymous; } + bool has_class_mirror_holder() const { return _has_class_mirror_holder; } static void init_null_class_loader_data(); @@ -240,15 +242,15 @@ } // Returns true if this class loader data is for the system class loader. - // (Note that the class loader data may be unsafe anonymous.) + // (Note that the class loader data may be for an weak hidden or unsafe anonymous class) bool is_system_class_loader_data() const; // Returns true if this class loader data is for the platform class loader. - // (Note that the class loader data may be unsafe anonymous.) + // (Note that the class loader data may be for an weak hidden or unsafe anonymous class) bool is_platform_class_loader_data() const; // Returns true if this class loader data is for the boot class loader. - // (Note that the class loader data may be unsafe anonymous.) + // (Note that the class loader data may be for an weak hidden unsafe anonymous class) inline bool is_boot_class_loader_data() const; bool is_builtin_class_loader_data() const; @@ -269,7 +271,7 @@ return _unloading; } - // Used to refcount an unsafe anonymous class's CLD in order to + // Used to refcount an weak hidden or unsafe anonymous class's CLD in order to // indicate their aliveness. void inc_keep_alive(); void dec_keep_alive(); @@ -313,7 +315,7 @@ static ClassLoaderData* class_loader_data(oop loader); static ClassLoaderData* class_loader_data_or_null(oop loader); - static ClassLoaderData* unsafe_anonymous_class_loader_data(Handle loader); + static ClassLoaderData* has_class_mirror_holder_cld(Handle loader); // Returns Klass* of associated class loader, or NULL if associated loader is 'bootstrap'. // Also works if unloading. diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -192,7 +192,7 @@ // Add a new class loader data node to the list. Assign the newly created // ClassLoaderData into the java/lang/ClassLoader object as a hidden field -ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) { +ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool has_class_mirror_holder) { assert_lock_strong(ClassLoaderDataGraph_lock); @@ -200,7 +200,7 @@ // First check if another thread beat us to creating the CLD and installing // it into the loader while we were waiting for the lock. - if (!is_unsafe_anonymous && loader.not_null()) { + if (!has_class_mirror_holder && loader.not_null()) { cld = java_lang_ClassLoader::loader_data_acquire(loader()); if (cld != NULL) { return cld; @@ -212,14 +212,14 @@ // loader oop in all collections, particularly young collections. NoSafepointVerifier no_safepoints; - cld = new ClassLoaderData(loader, is_unsafe_anonymous); + cld = new ClassLoaderData(loader, has_class_mirror_holder); // First install the new CLD to the Graph. cld->set_next(_head); Atomic::release_store(&_head, cld); // Next associate with the class_loader. - if (!is_unsafe_anonymous) { + if (!has_class_mirror_holder) { // Use OrderAccess, since readers need to get the loader_data only after // it's added to the Graph java_lang_ClassLoader::release_set_loader_data(loader(), cld); @@ -237,9 +237,9 @@ return cld; } -ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) { +ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool has_class_mirror_holder) { MutexLocker ml(ClassLoaderDataGraph_lock); - ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous); + ClassLoaderData* loader_data = add_to_graph(loader, has_class_mirror_holder); return loader_data; } diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -56,8 +56,8 @@ static volatile size_t _num_instance_classes; static volatile size_t _num_array_classes; - static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous); - static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous); + static ClassLoaderData* add_to_graph(Handle class_loader, bool has_class_mirror_holder); + static ClassLoaderData* add(Handle class_loader, bool has_class_mirror_holder); public: static ClassLoaderData* find_or_create(Handle class_loader); @@ -76,7 +76,7 @@ // Walking classes through the ClassLoaderDataGraph include array classes. It also includes // classes that are allocated but not loaded, classes that have errors, and scratch classes // for redefinition. These classes are removed during the next class unloading. - // Walking the ClassLoaderDataGraph also includes unsafe anonymous classes. + // Walking the ClassLoaderDataGraph also includes hidden and unsafe anonymous classes. static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); static void methods_do(void f(Method*)); diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -284,13 +284,12 @@ ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); Handle protection_domain; + ClassLoadInfo cl_info(protection_domain); InstanceKlass* result = KlassFactory::create_from_stream(stream, name, loader_data, - protection_domain, - NULL, // unsafe_anonymous_host - NULL, // cp_patches + cl_info, THREAD); if (HAS_PENDING_EXCEPTION) { diff --git a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp --- a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp +++ b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -129,7 +129,7 @@ class LoaderTreeNode : public ResourceObj { - // We walk the CLDG and, for each CLD which is non-unsafe_anonymous, add + // We walk the CLDG and, for each CLD which is findable, add // a tree node. // To add a node we need its parent node; if the parent node does not yet // exist - because we have not yet encountered the CLD for the parent loader - @@ -149,6 +149,9 @@ LoadedClassInfo* _anon_classes; int _num_anon_classes; + LoadedClassInfo* _hidden_weak_classes; + int _num_hidden_weak_classes; + // In default view, similar tree nodes (same loader class, same name or no name) // are folded into each other to make the output more readable. // _num_folded contains the number of nodes which have been folded into this @@ -177,6 +180,7 @@ if (_cld->is_the_null_class_loader_data()) { st->print(" "); } else { + assert(!_cld->has_class_mirror_holder(), "_cld must be the primary cld"); if (loader_name != NULL) { st->print(" \"%s\",", loader_name->as_C_string()); } @@ -220,7 +224,7 @@ if (print_classes) { if (_classes != NULL) { for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) { - // Non-unsafe anonymous classes should live in the primary CLD of its loader + // Weak-hidden and unsafe anonymous classes should not live in the primary CLD of their loaders. assert(lci->_cld == _cld, "must be"); branchtracker.print(st); @@ -258,7 +262,8 @@ st->print("%*s ", indentation, ""); } st->print("%s", lci->_klass->external_name()); - // For unsafe anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD. + // For unsafe anonymous classes, also print CLD if verbose. Should + // be a different one than the primary CLD. assert(lci->_cld != _cld, "must be"); if (verbose) { st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld)); @@ -267,7 +272,35 @@ } branchtracker.print(st); st->print("%*s ", indentation, ""); - st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es"); + st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes, + (_num_anon_classes == 1) ? "" : "es"); + + // Empty line + branchtracker.print(st); + st->cr(); + } + + if (_hidden_weak_classes != NULL) { + for (LoadedClassInfo* lci = _hidden_weak_classes; lci; lci = lci->_next) { + branchtracker.print(st); + if (lci == _hidden_weak_classes) { // first iteration + st->print("%*s ", indentation, "Weak Hidden Classes:"); + } else { + st->print("%*s ", indentation, ""); + } + st->print("%s", lci->_klass->external_name()); + // For weak hidden classes, also print CLD if verbose. Should be a + // different one than the primary CLD. + assert(lci->_cld != _cld, "must be"); + if (verbose) { + st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld)); + } + st->cr(); + } + branchtracker.print(st); + st->print("%*s ", indentation, ""); + st->print_cr("(%u weak hidden class%s)", _num_hidden_weak_classes, + (_num_hidden_weak_classes == 1) ? "" : "es"); // Empty line branchtracker.print(st); @@ -301,6 +334,7 @@ LoaderTreeNode(const oop loader_oop) : _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL), _classes(NULL), _num_classes(0), _anon_classes(NULL), _num_anon_classes(0), + _hidden_weak_classes(NULL), _num_hidden_weak_classes(0), _num_folded(0) {} @@ -319,15 +353,25 @@ _next = info; } - void add_classes(LoadedClassInfo* first_class, int num_classes, bool is_unsafe_anonymous) { - LoadedClassInfo** p_list_to_add_to = is_unsafe_anonymous ? &_anon_classes : &_classes; + void add_classes(LoadedClassInfo* first_class, int num_classes, bool has_class_mirror_holder) { + LoadedClassInfo** p_list_to_add_to; + bool is_hidden = first_class->_klass->is_hidden(); + if (has_class_mirror_holder) { + p_list_to_add_to = is_hidden ? &_hidden_weak_classes : &_anon_classes; + } else { + p_list_to_add_to = &_classes; + } // Search tail. while ((*p_list_to_add_to) != NULL) { p_list_to_add_to = &(*p_list_to_add_to)->_next; } *p_list_to_add_to = first_class; - if (is_unsafe_anonymous) { - _num_anon_classes += num_classes; + if (has_class_mirror_holder) { + if (is_hidden) { + _num_hidden_weak_classes += num_classes; + } else { + _num_anon_classes += num_classes; + } } else { _num_classes += num_classes; } @@ -421,7 +465,7 @@ LoadedClassCollectClosure lccc(cld); const_cast(cld)->classes_do(&lccc); if (lccc._num_classes > 0) { - info->add_classes(lccc._list, lccc._num_classes, cld->is_unsafe_anonymous()); + info->add_classes(lccc._list, lccc._num_classes, cld->has_class_mirror_holder()); } } @@ -481,7 +525,7 @@ assert(info != NULL, "must be"); // Update CLD in node, but only if this is the primary CLD for this loader. - if (cld->is_unsafe_anonymous() == false) { + if (cld->has_class_mirror_holder() == false) { assert(info->cld() == NULL, "there should be only one primary CLD per loader"); info->set_cld(cld); } diff --git a/src/hotspot/share/classfile/classLoaderStats.cpp b/src/hotspot/share/classfile/classLoaderStats.cpp --- a/src/hotspot/share/classfile/classLoaderStats.cpp +++ b/src/hotspot/share/classfile/classLoaderStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,6 +26,7 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderStats.hpp" +#include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" @@ -59,7 +60,7 @@ cls = *cls_ptr; } - if (!cld->is_unsafe_anonymous()) { + if (!cld->has_class_mirror_holder()) { cls->_cld = cld; } @@ -71,8 +72,20 @@ ClassStatsClosure csc; cld->classes_do(&csc); - if(cld->is_unsafe_anonymous()) { - cls->_anon_classes_count += csc._num_classes; + bool is_hidden = false; + if(cld->has_class_mirror_holder()) { + // if cld has a class holder then it must be either hidden or unsafe anonymous. + Klass* k = cld->klasses(); + // if it's an array class then need to see if bottom class is hidden. + if (k->is_array_klass()) { + k = ObjArrayKlass::cast(k)->bottom_klass(); + } + is_hidden = k->is_hidden(); + if (is_hidden) { + cls->_hidden_classes_count += csc._num_classes; + } else { + cls->_anon_classes_count += csc._num_classes; + } } else { cls->_classes_count = csc._num_classes; } @@ -80,9 +93,14 @@ ClassLoaderMetaspace* ms = cld->metaspace_or_null(); if (ms != NULL) { - if(cld->is_unsafe_anonymous()) { - cls->_anon_chunk_sz += ms->allocated_chunks_bytes(); - cls->_anon_block_sz += ms->allocated_blocks_bytes(); + if(cld->has_class_mirror_holder()) { + if (is_hidden) { + cls->_hidden_chunk_sz += ms->allocated_chunks_bytes(); + cls->_hidden_block_sz += ms->allocated_blocks_bytes(); + } else { + cls->_anon_chunk_sz += ms->allocated_chunks_bytes(); + cls->_anon_block_sz += ms->allocated_blocks_bytes(); + } } else { cls->_chunk_sz = ms->allocated_chunks_bytes(); cls->_block_sz = ms->allocated_blocks_bytes(); @@ -121,6 +139,12 @@ cls->_anon_classes_count, cls->_anon_chunk_sz, cls->_anon_block_sz); } + if (cls->_hidden_classes_count > 0) { + _out->print_cr(SPACE SPACE SPACE " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " + hidden classes", + "", "", "", + cls->_hidden_classes_count, + cls->_hidden_chunk_sz, cls->_hidden_block_sz); + } return true; } diff --git a/src/hotspot/share/classfile/classLoaderStats.hpp b/src/hotspot/share/classfile/classLoaderStats.hpp --- a/src/hotspot/share/classfile/classLoaderStats.hpp +++ b/src/hotspot/share/classfile/classLoaderStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -81,6 +81,10 @@ size_t _anon_block_sz; uintx _anon_classes_count; + size_t _hidden_chunk_sz; + size_t _hidden_block_sz; + uintx _hidden_classes_count; + ClassLoaderStats() : _cld(0), _class_loader(0), @@ -90,7 +94,10 @@ _classes_count(0), _anon_chunk_sz(0), _anon_block_sz(0), - _anon_classes_count(0) { + _anon_classes_count(0), + _hidden_chunk_sz(0), + _hidden_block_sz(0), + _hidden_classes_count(0) { } }; diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -918,7 +918,7 @@ ConstantPool* cp = bpool->create_constant_pool(CHECK); if (cp != klass->constants()) { // Copy resolved anonymous class into new constant pool. - if (klass->is_unsafe_anonymous()) { + if (klass->is_unsafe_anonymous() || klass->is_hidden()) { cp->klass_at_put(klass->this_class_index(), klass); } klass->class_loader_data()->add_to_deallocate_list(klass->constants()); diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp --- a/src/hotspot/share/classfile/dictionary.cpp +++ b/src/hotspot/share/classfile/dictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -354,6 +354,7 @@ // since been unreferenced, so this entry should be cleared. void Dictionary::clean_cached_protection_domains() { assert_locked_or_safepoint(SystemDictionary_lock); + assert(!loader_data()->has_class_mirror_holder(), "cld should have a ClassLoader holder not a Class holder"); if (loader_data()->is_the_null_class_loader_data()) { // Classes in the boot loader are not loaded with protection domains @@ -482,6 +483,7 @@ ResourceMark rm; assert(loader_data() != NULL, "loader data should not be null"); + assert(!loader_data()->has_class_mirror_holder(), "cld should have a ClassLoader holder not a Class holder"); st->print_cr("Java dictionary (table_size=%d, classes=%d, resizable=%s)", table_size(), number_of_entries(), BOOL_TO_STR(_resizable)); st->print_cr("^ indicates that initiating loader is different from defining loader"); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -852,12 +852,13 @@ k->clear_has_raw_archived_mirror(); } } - create_mirror(k, Handle(), Handle(), Handle(), CHECK); + create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK); } void java_lang_Class::initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, + Handle classData, TRAPS) { // Allocate a simple java object for a lock. // This needs to be a java object because during class initialization @@ -870,6 +871,9 @@ // Initialize static fields InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK); + + // Set classData + set_class_data(mirror(), classData()); } // Set the java.lang.Module module field in the java_lang_Class mirror @@ -923,7 +927,8 @@ } void java_lang_Class::create_mirror(Klass* k, Handle class_loader, - Handle module, Handle protection_domain, TRAPS) { + Handle module, Handle protection_domain, + Handle classData, TRAPS) { assert(k != NULL, "Use create_basic_type_mirror for primitive types"); assert(k->java_mirror() == NULL, "should only assign mirror once"); @@ -970,7 +975,7 @@ } else { assert(k->is_instance_klass(), "Must be"); - initialize_mirror_fields(k, mirror, protection_domain, THREAD); + initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field // from the mirror so GC doesn't follow it after the klass has been deallocated. @@ -1397,6 +1402,14 @@ java_class->obj_field_put(_signers_offset, (oop)signers); } +oop java_lang_Class::class_data(oop java_class) { + assert(_classData_offset != 0, "must be set"); + return java_class->obj_field(_classData_offset); +} +void java_lang_Class::set_class_data(oop java_class, oop class_data) { + assert(_classData_offset != 0, "must be set"); + java_class->obj_field_put(_classData_offset, class_data); +} void java_lang_Class::set_class_loader(oop java_class, oop loader) { assert(_class_loader_offset != 0, "offsets should have been initialized"); @@ -1600,6 +1613,7 @@ macro(_component_mirror_offset, k, "componentType", class_signature, false); \ macro(_module_offset, k, "module", module_signature, false); \ macro(_name_offset, k, "name", string_signature, false); \ + macro(_classData_offset, k, "classData", object_signature, false); \ void java_lang_Class::compute_offsets() { if (offsets_computed) { @@ -4268,6 +4282,7 @@ int java_lang_Class::_signers_offset; int java_lang_Class::_name_offset; int java_lang_Class::_source_file_offset; +int java_lang_Class::_classData_offset; GrowableArray* java_lang_Class::_fixup_mirror_list = NULL; GrowableArray* java_lang_Class::_fixup_module_field_list = NULL; int java_lang_Throwable::backtrace_offset; diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -240,7 +240,7 @@ macro(java_lang_Class, static_oop_field_count, int_signature, false) \ macro(java_lang_Class, protection_domain, object_signature, false) \ macro(java_lang_Class, signers, object_signature, false) \ - macro(java_lang_Class, source_file, object_signature, false) \ + macro(java_lang_Class, source_file, object_signature, false) class java_lang_Class : AllStatic { friend class VMStructs; @@ -263,6 +263,7 @@ static int _component_mirror_offset; static int _name_offset; static int _source_file_offset; + static int _classData_offset; static bool offsets_computed; static int classRedefinedCount_offset; @@ -274,7 +275,8 @@ static void set_protection_domain(oop java_class, oop protection_domain); static void set_class_loader(oop java_class, oop class_loader); static void set_component_mirror(oop java_class, oop comp_mirror); - static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, TRAPS); + static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, + Handle classData, TRAPS); static void set_mirror_module_field(Klass* K, Handle mirror, Handle module, TRAPS); public: static void allocate_fixup_lists(); @@ -282,7 +284,7 @@ // Instance creation static void create_mirror(Klass* k, Handle class_loader, Handle module, - Handle protection_domain, TRAPS); + Handle protection_domain, Handle classData, TRAPS); static void fixup_mirror(Klass* k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); static void update_archived_primitive_mirror_native_pointers(oop archived_mirror) NOT_CDS_JAVA_HEAP_RETURN; @@ -330,6 +332,8 @@ static oop component_mirror(oop java_class); static objArrayOop signers(oop java_class); static void set_signers(oop java_class, objArrayOop signers); + static oop class_data(oop java_class); + static void set_class_data(oop java_class, oop classData); static oop class_loader(oop java_class); static void set_module(oop java_class, oop module); @@ -1142,16 +1146,20 @@ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants): enum { - MN_IS_METHOD = 0x00010000, // method (not constructor) - MN_IS_CONSTRUCTOR = 0x00020000, // constructor - MN_IS_FIELD = 0x00040000, // field - MN_IS_TYPE = 0x00080000, // nested type - MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected - MN_REFERENCE_KIND_SHIFT = 24, // refKind - MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, + MN_IS_METHOD = 0x00010000, // method (not constructor) + MN_IS_CONSTRUCTOR = 0x00020000, // constructor + MN_IS_FIELD = 0x00040000, // field + MN_IS_TYPE = 0x00080000, // nested type + MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected + MN_REFERENCE_KIND_SHIFT = 24, // refKind + MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: - MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes - MN_SEARCH_INTERFACES = 0x00200000 // walk implemented interfaces + MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes + MN_SEARCH_INTERFACES = 0x00200000, // walk implemented interfaces + MN_NESTMATE_CLASS = 0x00000001, + MN_HIDDEN_CLASS = 0x00000002, + MN_STRONG_LOADER_LINK = 0x00000004, + MN_ACCESS_VM_ANNOTATIONS = 0x00000008 }; // Accessors for code generation: diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -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 @@ -79,16 +79,18 @@ end_ptr - ptr, cfs->source(), ClassFileStream::verify); + ClassLoadInfo cl_info(protection_domain); ClassFileParser parser(stream, class_name, loader_data, - protection_domain, - NULL, - NULL, + &cl_info, ClassFileParser::BROADCAST, // publicity level CHECK_NULL); - InstanceKlass* new_ik = parser.create_instance_klass(true /* changed_by_loadhook */, + const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr(); + InstanceKlass* new_ik = parser.create_instance_klass(true, // changed_by_loadhook + *cl_inst_info, // dynamic_nest_host and classData CHECK_NULL); + if (cached_class_file != NULL) { new_ik->set_cached_class_file(cached_class_file); } @@ -165,9 +167,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, Symbol* name, ClassLoaderData* loader_data, - Handle protection_domain, - const InstanceKlass* unsafe_anonymous_host, - GrowableArray* cp_patches, + const ClassLoadInfo& cl_info, TRAPS) { assert(stream != NULL, "invariant"); assert(loader_data != NULL, "invariant"); @@ -183,12 +183,15 @@ // increment counter THREAD->statistical_info().incr_define_class_count(); - // Skip this processing for VM anonymous classes - if (unsafe_anonymous_host == NULL) { + assert(!(cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() != NULL)), + "hidden class has an anonymous host"); + + // Skip this processing for VM hidden or anonymous classes + if (!cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() == NULL)) { stream = check_class_file_load_hook(stream, name, loader_data, - protection_domain, + cl_info.protection_domain(), &cached_class_file, CHECK_NULL); } @@ -196,14 +199,12 @@ ClassFileParser parser(stream, name, loader_data, - protection_domain, - unsafe_anonymous_host, - cp_patches, + &cl_info, ClassFileParser::BROADCAST, // publicity level CHECK_NULL); - InstanceKlass* result = parser.create_instance_klass(old_stream != stream, CHECK_NULL); - assert(result == parser.create_instance_klass(old_stream != stream, THREAD), "invariant"); + const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr(); + InstanceKlass* result = parser.create_instance_klass(old_stream != stream, *cl_inst_info, CHECK_NULL); if (result == NULL) { return NULL; diff --git a/src/hotspot/share/classfile/klassFactory.hpp b/src/hotspot/share/classfile/klassFactory.hpp --- a/src/hotspot/share/classfile/klassFactory.hpp +++ b/src/hotspot/share/classfile/klassFactory.hpp @@ -30,6 +30,7 @@ class ClassFileStream; class ClassLoaderData; +class ClassLoadInfo; template class GrowableArray; class Klass; @@ -71,9 +72,7 @@ static InstanceKlass* create_from_stream(ClassFileStream* stream, Symbol* name, ClassLoaderData* loader_data, - Handle protection_domain, - const InstanceKlass* unsafe_anonymous_host, - GrowableArray* cp_patches, + const ClassLoadInfo& cl_info, TRAPS); public: static InstanceKlass* check_shared_class_file_load_hook( diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -75,6 +75,7 @@ const char* loc = location()->as_C_string(); ClassLoaderData* cld = loader_data(); + assert(!cld->has_class_mirror_holder(), "module's cld should have a ClassLoader holder not a Class holder"); if ((cld->is_the_null_class_loader_data() || cld->is_platform_class_loader_data()) && (strncmp(loc, "jrt:/java.", 10) == 0)) { return false; @@ -135,6 +136,7 @@ // injecting dependencies that require the default read edges for resolution. if (this->has_default_read_edges() && !m->is_named()) { ClassLoaderData* cld = m->loader_data(); + assert(!cld->has_class_mirror_holder(), "module's cld should have a ClassLoader holder not a Class holder"); if (cld->is_the_null_class_loader_data() || cld->is_system_class_loader_data()) { return true; // default read edge } diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -110,7 +110,7 @@ ClassLoaderData* loader_data() const { return _loader_data; } void set_loader_data(ClassLoaderData* cld) { - assert(!cld->is_unsafe_anonymous(), "Unexpected unsafe anonymous class loader data"); + assert(!cld->has_class_mirror_holder(), "Unexpected has_class_mirror_holder cld"); _loader_data = cld; } diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/resolutionErrors.hpp" +#include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" @@ -42,6 +43,18 @@ add_entry(index, entry); } +// add new entry to the table +void ResolutionErrorTable::add_entry(int index, unsigned int hash, + const constantPoolHandle& pool, int cp_index, + const char* message) +{ + assert_locked_or_safepoint(SystemDictionary_lock); + assert(!pool.is_null() && message != NULL, "adding NULL obj"); + + ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, message); + add_entry(index, entry); +} + // find entry in the table ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int hash, const constantPoolHandle& pool, int cp_index) @@ -59,9 +72,10 @@ } void ResolutionErrorEntry::set_error(Symbol* e) { - assert(e != NULL, "must set a value"); _error = e; - _error->increment_refcount(); + if (_error != NULL) { + _error->increment_refcount(); + } } void ResolutionErrorEntry::set_message(Symbol* c) { @@ -71,6 +85,10 @@ } } +void ResolutionErrorEntry::set_nest_host_error(const char* message) { + _nest_host_error = message; +} + // create new error entry ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool, int cp_index, Symbol* error, @@ -80,17 +98,35 @@ entry->set_cp_index(cp_index); entry->set_error(error); entry->set_message(message); + entry->set_nest_host_error(NULL); + + return entry; +} + +// create new nest host error entry +ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool, + int cp_index, const char* message) +{ + ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable::new_entry(hash, pool); + entry->set_cp_index(cp_index); + entry->set_nest_host_error(message); + entry->set_error(NULL); + entry->set_message(NULL); return entry; } void ResolutionErrorTable::free_entry(ResolutionErrorEntry *entry) { // decrement error refcount - assert(entry->error() != NULL, "error should be set"); - entry->error()->decrement_refcount(); + if (entry->error() != NULL) { + entry->error()->decrement_refcount(); + } if (entry->message() != NULL) { entry->message()->decrement_refcount(); } + if (entry->nest_host_error() != NULL) { + FREE_C_HEAP_ARRAY(char, entry->nest_host_error()); + } Hashtable::free_entry(entry); } diff --git a/src/hotspot/share/classfile/resolutionErrors.hpp b/src/hotspot/share/classfile/resolutionErrors.hpp --- a/src/hotspot/share/classfile/resolutionErrors.hpp +++ b/src/hotspot/share/classfile/resolutionErrors.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -46,6 +46,8 @@ ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index, Symbol* error, Symbol* message); + ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index, + const char* message); void free_entry(ResolutionErrorEntry *entry); ResolutionErrorEntry* bucket(int i) { @@ -64,6 +66,8 @@ void add_entry(int index, unsigned int hash, const constantPoolHandle& pool, int which, Symbol* error, Symbol* message); + void add_entry(int index, unsigned int hash, + const constantPoolHandle& pool, int which, const char* message); // find error given the constant pool and constant pool index ResolutionErrorEntry* find_entry(int index, unsigned int hash, @@ -95,6 +99,7 @@ int _cp_index; Symbol* _error; Symbol* _message; + const char* _nest_host_error; public: ConstantPool* pool() const { return literal(); } @@ -108,6 +113,9 @@ Symbol* message() const { return _message; } void set_message(Symbol* c); + const char* nest_host_error() const { return _nest_host_error; } + void set_nest_host_error(const char* message); + ResolutionErrorEntry* next() const { return (ResolutionErrorEntry*)HashtableEntry::next(); } diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -459,6 +459,8 @@ void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp, int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues) { + // Note that c_heap will be true for unsafe anonymous and weak hidden classes + // even if their loader is the boot loader because they will have a different cld. bool c_heap = !loader_data->is_the_null_class_loader_data(); for (int i = 0; i < names_count; i++) { const char *name = names[i]; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -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 diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -34,6 +34,53 @@ #include "runtime/signature.hpp" #include "utilities/hashtable.hpp" +class ClassInstanceInfo : public StackObj { + private: + InstanceKlass* _dynamic_nest_host; + Handle _class_data; + + public: + ClassInstanceInfo() { + _dynamic_nest_host = NULL; + _class_data = Handle(); + } + ClassInstanceInfo(InstanceKlass* dynamic_nest_host, Handle class_data) { + _dynamic_nest_host = dynamic_nest_host; + _class_data = class_data; + } + + InstanceKlass* dynamic_nest_host() const { return _dynamic_nest_host; } + Handle class_data() const { return _class_data; } + friend class ClassLoadInfo; +}; + +class ClassLoadInfo : public StackObj { + private: + Handle _protection_domain; + const InstanceKlass* _unsafe_anonymous_host; + GrowableArray* _cp_patches; + ClassInstanceInfo _class_hidden_info; + bool _is_hidden; + bool _is_strong_hidden; + bool _can_access_vm_annotations; + + public: + ClassLoadInfo(); + ClassLoadInfo(Handle protection_domain); + 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); + + Handle protection_domain() const { return _protection_domain; } + const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; } + GrowableArray* cp_patches() const { return _cp_patches; } + const ClassInstanceInfo* class_hidden_info_ptr() const { return &_class_hidden_info; } + bool is_hidden() const { return _is_hidden; } + bool is_strong_hidden() const { return _is_strong_hidden; } + bool can_access_vm_annotations() const { return _can_access_vm_annotations; } +}; + // The dictionary in each ClassLoaderData stores all loaded classes, either // initiatied by its class loader or defined by its class loader: // @@ -271,28 +318,13 @@ bool is_superclass, TRAPS); - // Parse new stream. This won't update the dictionary or - // class hierarchy, simply parse the stream. Used by JVMTI RedefineClasses. - // Also used by Unsafe_DefineAnonymousClass + // Parse new stream. This won't update the dictionary or class + // hierarchy, simply parse the stream. Used by JVMTI RedefineClasses + // and by Unsafe_DefineAnonymousClass and jvm_lookup_define_class. static InstanceKlass* parse_stream(Symbol* class_name, Handle class_loader, - Handle protection_domain, ClassFileStream* st, - TRAPS) { - return parse_stream(class_name, - class_loader, - protection_domain, - st, - NULL, // unsafe_anonymous_host - NULL, // cp_patches - THREAD); - } - static InstanceKlass* 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); // Resolve from stream (called by jni_DefineClass and JVM_DefineClass) @@ -530,6 +562,11 @@ Symbol** message); + // Record a nest host resolution/validation error + static void add_nest_host_error(const constantPoolHandle& pool, int which, + const char* message); + static const char* find_nest_host_error(const constantPoolHandle& pool, int which); + static ProtectionDomainCacheEntry* cache_get(Handle protection_domain); protected: diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -909,7 +909,7 @@ if (!UseSharedSpaces) { return NULL; } - if (class_name == NULL) { // don't do this for anonymous classes + if (class_name == NULL) { // don't do this for hidden and unsafe anonymous classes return NULL; } if (class_loader.is_null() || @@ -1088,9 +1088,9 @@ } bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) { - if (k->class_loader_data()->is_unsafe_anonymous()) { - warn_excluded(k, "Unsafe anonymous class"); - return true; // unsafe anonymous classes are not archived, skip + if (k->is_hidden() || k->is_unsafe_anonymous()) { + warn_excluded(k, "Hidden or Unsafe anonymous class"); + return true; // hidden and unsafe anonymous classes are not archived, skip } if (k->is_in_error_state()) { warn_excluded(k, "In error state"); diff --git a/src/hotspot/share/classfile/verificationType.cpp b/src/hotspot/share/classfile/verificationType.cpp --- a/src/hotspot/share/classfile/verificationType.cpp +++ b/src/hotspot/share/classfile/verificationType.cpp @@ -48,11 +48,16 @@ bool VerificationType::resolve_and_check_assignability(InstanceKlass* klass, Symbol* name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, TRAPS) { HandleMark hm(THREAD); - Klass* this_class = SystemDictionary::resolve_or_fail( + Klass* this_class; + if (klass->is_hidden() && klass->name() == name) { + this_class = klass; + } else { + this_class = SystemDictionary::resolve_or_fail( name, Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (log_is_enabled(Debug, class, resolve)) { - Verifier::trace_class_resolution(this_class, klass); + if (log_is_enabled(Debug, class, resolve)) { + Verifier::trace_class_resolution(this_class, klass); + } } if (this_class->is_interface() && (!from_field_is_protected || @@ -65,11 +70,16 @@ this_class == SystemDictionary::Cloneable_klass() || this_class == SystemDictionary::Serializable_klass(); } else if (from_is_object) { - Klass* from_class = SystemDictionary::resolve_or_fail( + Klass* from_class; + if (klass->is_hidden() && klass->name() == from_name) { + from_class = klass; + } else { + from_class = SystemDictionary::resolve_or_fail( from_name, Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (log_is_enabled(Debug, class, resolve)) { - Verifier::trace_class_resolution(from_class, klass); + if (log_is_enabled(Debug, class, resolve)) { + Verifier::trace_class_resolution(from_class, klass); + } } return from_class->is_subclass_of(this_class); } diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2081,6 +2081,8 @@ oop loader = current_class()->class_loader(); oop protection_domain = current_class()->protection_domain(); + assert(name_in_supers(name, current_class()), "name should be a super class"); + Klass* kls = SystemDictionary::resolve_or_fail( name, Handle(THREAD, loader), Handle(THREAD, protection_domain), true, THREAD); diff --git a/src/hotspot/share/classfile/vmSymbols.cpp b/src/hotspot/share/classfile/vmSymbols.cpp --- a/src/hotspot/share/classfile/vmSymbols.cpp +++ b/src/hotspot/share/classfile/vmSymbols.cpp @@ -546,6 +546,7 @@ case vmIntrinsics::_isInterface: case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: + case vmIntrinsics::_isHiddenClass: case vmIntrinsics::_getSuperclass: case vmIntrinsics::_Class_cast: case vmIntrinsics::_getLength: diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -884,6 +884,8 @@ do_name( isArray_name, "isArray") \ do_intrinsic(_isPrimitive, java_lang_Class, isPrimitive_name, void_boolean_signature, F_RN) \ do_name( isPrimitive_name, "isPrimitive") \ + do_intrinsic(_isHiddenClass, java_lang_Class, isHiddenClass_name, void_boolean_signature, F_RN) \ + do_name( isHiddenClass_name, "isHiddenClass") \ do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \ do_name( getSuperclass_name, "getSuperclass") \ do_intrinsic(_Class_cast, java_lang_Class, Class_cast_name, object_object_signature, F_R) \ diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -389,6 +389,22 @@ const char *source); /* + * Define a class with the specified lookup class. + * lookup: Lookup class + * name: the name of the class + * loader: defining class loader + * buf: class bytes + * len: length of class bytes + * pd: protection domain + * init: initialize the class + * flags: properties of the class + * classData: private static pre-initialized field; may be null + */ +JNIEXPORT jclass JNICALL +JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char *name, const jbyte *buf, + jsize len, jobject pd, jboolean init, int flags, jobject classData); + +/* * Module support funcions */ @@ -474,6 +490,9 @@ JNIEXPORT jboolean JNICALL JVM_IsPrimitiveClass(JNIEnv *env, jclass cls); +JNIEXPORT jboolean JNICALL +JVM_IsHiddenClass(JNIEnv *env, jclass cls); + JNIEXPORT jint JNICALL JVM_GetClassModifiers(JNIEnv *env, jclass cls); diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -547,6 +547,21 @@ return NULL; } +static void print_nest_host_error_on(stringStream* ss, Klass* ref_klass, Klass* sel_klass, TRAPS) { + assert(ref_klass->is_instance_klass(), "must be"); + assert(sel_klass->is_instance_klass(), "must be"); + InstanceKlass* ref_ik = InstanceKlass::cast(ref_klass); + InstanceKlass* sel_ik = InstanceKlass::cast(sel_klass); + const char* nest_host_error_1 = ref_ik->nest_host_error(THREAD); + const char* nest_host_error_2 = sel_ik->nest_host_error(THREAD); + if (nest_host_error_1 != NULL || nest_host_error_2 != NULL) { + ss->print(", (%s%s%s)", + (nest_host_error_1 != NULL) ? nest_host_error_1 : "", + (nest_host_error_1 != NULL && nest_host_error_2 != NULL) ? ", " : "", + (nest_host_error_2 != NULL) ? nest_host_error_2 : ""); + } +} + void LinkResolver::check_method_accessability(Klass* ref_klass, Klass* resolved_klass, Klass* sel_klass, @@ -579,24 +594,34 @@ sel_klass, flags, true, false, CHECK); - // Any existing exceptions that may have been thrown, for example LinkageErrors - // from nest-host resolution, have been allowed to propagate. + // Any existing exceptions that may have been thrown + // have been allowed to propagate. if (!can_access) { ResourceMark rm(THREAD); + stringStream ss; bool same_module = (sel_klass->module() == ref_klass->module()); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s tried to access %s%s%smethod '%s' (%s%s%s)", - ref_klass->external_name(), - sel_method->is_abstract() ? "abstract " : "", - sel_method->is_protected() ? "protected " : "", - sel_method->is_private() ? "private " : "", - sel_method->external_name(), - (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), - (same_module) ? "" : "; ", - (same_module) ? "" : sel_klass->class_in_module_of_loader() - ); + ss.print("class %s tried to access %s%s%smethod '%s' (%s%s%s)", + ref_klass->external_name(), + sel_method->is_abstract() ? "abstract " : "", + sel_method->is_protected() ? "protected " : "", + sel_method->is_private() ? "private " : "", + sel_method->external_name(), + (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), + (same_module) ? "" : "; ", + (same_module) ? "" : sel_klass->class_in_module_of_loader() + ); + + // For private access check if there was a problem with nest host + // resolution, and if so report that as part of the message. + if (sel_method->is_private()) { + print_nest_host_error_on(&ss, ref_klass, sel_klass, THREAD); + } + + Exceptions::fthrow(THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "%s", + ss.as_string() + ); return; } } @@ -915,19 +940,27 @@ if (!can_access) { bool same_module = (sel_klass->module() == ref_klass->module()); ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s tried to access %s%sfield %s.%s (%s%s%s)", - ref_klass->external_name(), - fd.is_protected() ? "protected " : "", - fd.is_private() ? "private " : "", - sel_klass->external_name(), - fd.name()->as_C_string(), - (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), - (same_module) ? "" : "; ", - (same_module) ? "" : sel_klass->class_in_module_of_loader() - ); + stringStream ss; + ss.print("class %s tried to access %s%sfield %s.%s (%s%s%s)", + ref_klass->external_name(), + fd.is_protected() ? "protected " : "", + fd.is_private() ? "private " : "", + sel_klass->external_name(), + fd.name()->as_C_string(), + (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), + (same_module) ? "" : "; ", + (same_module) ? "" : sel_klass->class_in_module_of_loader() + ); + // For private access check if there was a problem with nest host + // resolution, and if so report that as part of the message. + if (fd.is_private()) { + print_nest_host_error_on(&ss, ref_klass, sel_klass, THREAD); + } + Exceptions::fthrow(THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "%s", + ss.as_string() + ); return; } } diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -1460,12 +1460,11 @@ Handle pd(THREAD, ik->protection_domain()); Symbol* const class_name = ik->name(); const char* const klass_name = class_name != NULL ? class_name->as_C_string() : ""; + ClassLoadInfo cl_info(pd); ClassFileParser new_parser(stream, class_name, cld, - pd, - NULL, // host klass - NULL, // cp_patches + &cl_info, ClassFileParser::INTERNAL, // internal visibility THREAD); if (HAS_PENDING_EXCEPTION) { @@ -1473,7 +1472,8 @@ CLEAR_PENDING_EXCEPTION; return NULL; } - InstanceKlass* const new_ik = new_parser.create_instance_klass(false, THREAD); + const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr(); + InstanceKlass* const new_ik = new_parser.create_instance_klass(false, *cl_inst_info, THREAD); if (HAS_PENDING_EXCEPTION) { log_pending_exception(PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -162,10 +162,9 @@ if (k->is_instance_klass()) { const InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->is_unsafe_anonymous()) { + if (ik->is_unsafe_anonymous() || ik->is_hidden()) { return; } - assert(!ik->is_unsafe_anonymous(), "invariant"); const Symbol* name = ik->name(); if (name != NULL) { write_text("Class Name: "); diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -219,6 +219,7 @@ stackTrace="true"> + @@ -227,6 +228,7 @@ + @@ -724,6 +726,11 @@ description="Total size of all allocated metaspace chunks for unsafe anonymous classes (each chunk has several blocks)" /> + + + @@ -1093,6 +1100,7 @@ + diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -483,6 +483,9 @@ event.set_unsafeAnonymousClassCount(cls->_anon_classes_count); event.set_unsafeAnonymousChunkSize(cls->_anon_chunk_sz); event.set_unsafeAnonymousBlockSize(cls->_anon_block_sz); + event.set_hiddenClassCount(cls->_hidden_classes_count); + event.set_hiddenChunkSize(cls->_hidden_chunk_sz); + event.set_hiddenBlockSize(cls->_hidden_block_sz); event.commit(); return true; } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -137,7 +137,6 @@ static traceid cld_id(CldPtr cld, bool leakp) { assert(cld != NULL, "invariant"); - assert(!cld->is_unsafe_anonymous(), "invariant"); if (leakp) { SET_LEAKP(cld); } else { @@ -163,6 +162,7 @@ if (klass->is_objArray_klass()) { klass = ObjArrayKlass::cast(klass)->bottom_klass(); } + if (klass->is_hidden_weak()) return NULL; return is_unsafe_anonymous(klass) ? InstanceKlass::cast(klass)->unsafe_anonymous_host()->class_loader_data() : klass->class_loader_data(); } @@ -188,10 +188,12 @@ assert(_artifacts != NULL, "invariant"); assert(klass != NULL, "invariant"); writer->write(artifact_id(klass)); - writer->write(cld_id(get_cld(klass), leakp)); + ClassLoaderData* cld = get_cld(klass); + writer->write(cld != NULL ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); writer->write(get_flags(klass)); + writer->write(klass->is_hidden()); return 1; } @@ -546,7 +548,6 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { assert(cld != NULL, "invariant"); - assert(!cld->is_unsafe_anonymous(), "invariant"); // class loader type const Klass* class_loader_klass = cld->class_loader_klass(); if (class_loader_klass == NULL) { @@ -604,7 +605,7 @@ CLDCallback() {} void do_cld(ClassLoaderData* cld) { assert(cld != NULL, "invariant"); - if (cld->is_unsafe_anonymous()) { + if (cld->has_class_mirror_holder()) { return; } do_class_loader_data(cld); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -189,52 +189,54 @@ * caller needs ResourceMark */ -uintptr_t JfrSymbolId::unsafe_anonymous_klass_name_hash(const InstanceKlass* ik) { +uintptr_t JfrSymbolId::hidden_or_anon_klass_name_hash(const InstanceKlass* ik) { assert(ik != NULL, "invariant"); - assert(ik->is_unsafe_anonymous(), "invariant"); + assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); const oop mirror = ik->java_mirror_no_keepalive(); assert(mirror != NULL, "invariant"); return (uintptr_t)mirror->identity_hash(); } -static const char* create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { +static const char* create_hidden_or_anon_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { assert(ik != NULL, "invariant"); - assert(ik->is_unsafe_anonymous(), "invariant"); + assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); assert(hash != 0, "invariant"); - char* anonymous_symbol = NULL; + char* hidden_or_anon_symbol = NULL; const oop mirror = ik->java_mirror_no_keepalive(); assert(mirror != NULL, "invariant"); char hash_buf[40]; sprintf(hash_buf, "/" UINTX_FORMAT, hash); const size_t hash_len = strlen(hash_buf); const size_t result_len = ik->name()->utf8_length(); - anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); - ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1); - assert(strlen(anonymous_symbol) == result_len, "invariant"); - strcpy(anonymous_symbol + result_len, hash_buf); - assert(strlen(anonymous_symbol) == result_len + hash_len, "invariant"); - return anonymous_symbol; + hidden_or_anon_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); + ik->name()->as_klass_external_name(hidden_or_anon_symbol, (int)result_len + 1); + assert(strlen(hidden_or_anon_symbol) == result_len, "invariant"); + strcpy(hidden_or_anon_symbol + result_len, hash_buf); + assert(strlen(hidden_or_anon_symbol) == result_len + hash_len, "invariant"); + return hidden_or_anon_symbol; } -bool JfrSymbolId::is_unsafe_anonymous_klass(const Klass* k) { +bool JfrSymbolId::is_hidden_or_anon_klass(const Klass* k) { assert(k != NULL, "invariant"); - return k->is_instance_klass() && ((const InstanceKlass*)k)->is_unsafe_anonymous(); + return k->is_instance_klass() && + (((const InstanceKlass*)k)->is_unsafe_anonymous() || + ((const InstanceKlass*)k)->is_hidden()); } -traceid JfrSymbolId::mark_unsafe_anonymous_klass_name(const InstanceKlass* ik, bool leakp) { +traceid JfrSymbolId::mark_hidden_or_anon_klass_name(const InstanceKlass* ik, bool leakp) { assert(ik != NULL, "invariant"); - assert(ik->is_unsafe_anonymous(), "invariant"); - const uintptr_t hash = unsafe_anonymous_klass_name_hash(ik); - const char* const anonymous_klass_symbol = create_unsafe_anonymous_klass_symbol(ik, hash); - return mark(hash, anonymous_klass_symbol, leakp); + assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); + const uintptr_t hash = hidden_or_anon_klass_name_hash(ik); + const char* const hidden_or_anon_symbol = create_hidden_or_anon_klass_symbol(ik, hash); + return mark(hash, hidden_or_anon_symbol, leakp); } traceid JfrSymbolId::mark(const Klass* k, bool leakp) { assert(k != NULL, "invariant"); traceid symbol_id = 0; - if (is_unsafe_anonymous_klass(k)) { + if (is_hidden_or_anon_klass(k)) { assert(k->is_instance_klass(), "invariant"); - symbol_id = mark_unsafe_anonymous_klass_name((const InstanceKlass*)k, leakp); + symbol_id = mark_hidden_or_anon_klass_name((const InstanceKlass*)k, leakp); } if (0 == symbol_id) { Symbol* const sym = k->name(); @@ -276,9 +278,9 @@ return _symbol_id->bootstrap_name(leakp); } -traceid JfrArtifactSet::mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp) { +traceid JfrArtifactSet::mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp) { assert(klass->is_instance_klass(), "invariant"); - return _symbol_id->mark_unsafe_anonymous_klass_name((const InstanceKlass*)klass, leakp); + return _symbol_id->mark_hidden_or_anon_klass_name((const InstanceKlass*)klass, leakp); } traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -241,9 +241,9 @@ } } - traceid mark_unsafe_anonymous_klass_name(const InstanceKlass* k, bool leakp); - bool is_unsafe_anonymous_klass(const Klass* k); - uintptr_t unsafe_anonymous_klass_name_hash(const InstanceKlass* ik); + traceid mark_hidden_or_anon_klass_name(const InstanceKlass* k, bool leakp); + bool is_hidden_or_anon_klass(const Klass* k); + uintptr_t hidden_or_anon_klass_name_hash(const InstanceKlass* ik); public: JfrSymbolId(); @@ -304,7 +304,7 @@ traceid mark(const Klass* klass, bool leakp); traceid mark(const Symbol* symbol, bool leakp); traceid mark(uintptr_t hash, const char* const str, bool leakp); - traceid mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp); + traceid mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp); traceid bootstrap_name(bool leakp); const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -140,7 +140,7 @@ void JfrTraceId::assign(const ClassLoaderData* cld) { assert(cld != NULL, "invariant"); - if (cld->is_unsafe_anonymous()) { + if (cld->has_class_mirror_holder()) { cld->set_trace_id(0); return; } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp @@ -114,7 +114,7 @@ inline traceid JfrTraceId::use(const ClassLoaderData* cld) { assert(cld != NULL, "invariant"); - return cld->is_unsafe_anonymous() ? 0 : set_used_and_get(cld); + return cld->has_class_mirror_holder() ? 0 : set_used_and_get(cld); } inline void JfrTraceId::set_leakp(const Klass* klass, const Method* method) { diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -64,7 +64,7 @@ switch (t) { case Metaspace::StandardMetaspaceType: s = "Standard"; break; case Metaspace::BootMetaspaceType: s = "Boot"; break; - case Metaspace::UnsafeAnonymousMetaspaceType: s = "UnsafeAnonymous"; break; + case Metaspace::ClassMirrorHolderMetaspaceType: s = "ClassMirrorHolder"; break; case Metaspace::ReflectionMetaspaceType: s = "Reflection"; break; default: ShouldNotReachHere(); } diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -104,8 +104,8 @@ ZeroMetaspaceType = 0, StandardMetaspaceType = ZeroMetaspaceType, BootMetaspaceType = StandardMetaspaceType + 1, - UnsafeAnonymousMetaspaceType = BootMetaspaceType + 1, - ReflectionMetaspaceType = UnsafeAnonymousMetaspaceType + 1, + ClassMirrorHolderMetaspaceType = BootMetaspaceType + 1, + ReflectionMetaspaceType = ClassMirrorHolderMetaspaceType + 1, MetaspaceTypeCount }; @@ -254,7 +254,7 @@ // Initialize the first chunk for a Metaspace. Used for // special cases such as the boot class loader, reflection - // class loader and anonymous class loader. + // class loader and hidden class loader. void initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype); metaspace::Metachunk* get_initialization_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype); @@ -399,7 +399,7 @@ rf_show_loaders = (1 << 0), // Breaks report down by chunk type (small, medium, ...). rf_break_down_by_chunktype = (1 << 1), - // Breaks report down by space type (anonymous, reflection, ...). + // Breaks report down by space type (hidden, reflection, ...). rf_break_down_by_spacetype = (1 << 2), // Print details about the underlying virtual spaces. rf_show_vslist = (1 << 3), diff --git a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp --- a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp +++ b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -104,7 +104,7 @@ _out->print(UINTX_FORMAT_W(4) ": ", _num_loaders); // Print "CLD for [,] instance of " - // or "CLD for , loaded by [,] instance of " + // or "CLD for