--- old/src/hotspot/share/oops/instanceKlass.cpp 2019-12-03 19:37:02.000000000 -0800 +++ new/src/hotspot/share/oops/instanceKlass.cpp 2019-12-03 19:37:02.000000000 -0800 @@ -155,6 +155,7 @@ // called to verify that k is a member of this nest bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const { + assert(!is_hidden(), "unexpected hidden class"); if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) { if (log_is_enabled(Trace, class, nestmates)) { ResourceMark rm(THREAD); @@ -212,6 +213,24 @@ return false; } +InstanceKlass* InstanceKlass::runtime_nest_host(TRAPS) { + // TODO: nest_host returns NULL if validation fails. Need to follow up + // the specification when to evaluate the runtime nest host. Right now + // it's only determined when a dynamic nestmate is added. + InstanceKlass* nest_host_k = nest_host(NULL, CHECK_NULL); + if (nest_host_k == NULL) { + assert(_nest_host == NULL, "should fail to validate NestNost"); + // drop the static nest information; set dynamic nest to this class + if (log_is_enabled(Trace, class, nestmates)) { + ResourceMark rm(THREAD); + log_trace(class, nestmates)("Fail to validate static nest host of %s: setting nest-host to self", + this->external_name()); + } + _nest_host = nest_host_k = this; + } + return nest_host_k; +} + // Return nest-host class, resolving, validating and saving it if needed. // In cases where this is called from a thread that can not do classloading // (such as a native JIT thread) then we simply return NULL, which in turn @@ -245,8 +264,13 @@ Klass* k = _constants->klass_at(_nest_host_index, THREAD); if (HAS_PENDING_EXCEPTION) { Handle exc_h = Handle(THREAD, PENDING_EXCEPTION); - if (exc_h->is_a(SystemDictionary::NoClassDefFoundError_klass())) { - // throw a new CDNFE with the original as its cause, and a clear msg + if (validationException == NULL && exc_h->is_a(SystemDictionary::LinkageError_klass())) { + // clear exception if fails to resolve the nest host class + CLEAR_PENDING_EXCEPTION; + } + // throw a new NCDFE with the original as its cause, and a clear msg + if (exc_h->is_a(SystemDictionary::NoClassDefFoundError_klass()) && validationException != NULL) { + // throw a new NCDFE with the original as its cause, and a clear msg ResourceMark rm(THREAD); char buf[200]; CLEAR_PENDING_EXCEPTION; @@ -331,6 +355,42 @@ return nest_host_k; } + +// Dynamic nest member support: set this class's nest host to the given class. +// This occurs as part of the class definition, as soon as the instanceKlass +// has been created and doesn't require further resolution. The code: +// lookup().defineHiddenClass(bytes_for_X, NESTMATE); +// results in: +// class_of_X.set_nest_host(lookup().lookupClass().getNestHost()) +// If it has an explicit _nest_host_index or _nest_members, these will be ignored. +// We also know the "host" is a valid nest-host in the same package so we can +// assert some of those facts. +void InstanceKlass::set_nest_host(InstanceKlass* host, TRAPS) { + assert(is_hidden(), "must be a hidden class"); + assert(host != NULL, "NULL nest host specified"); + assert(_nest_host == NULL, "current class has resolved nest-host"); + assert((host->_nest_host == NULL && host->_nest_host_index == 0) || + (host->_nest_host == host), "proposed host is not a valid nest-host"); + // Can't assert this as package is not set yet: + // assert(is_same_class_package(host), "proposed host is in wrong package"); + + if (log_is_enabled(Trace, class, nestmates)) { + ResourceMark rm(THREAD); + // a hidden class does not expect a statically defined nest-host + if (_nest_host_index > 0) { + log_trace(class, nestmates)("Type %s is a dynamic nest member of %s: the NestHost attribute in the current class is ignored", + this->external_name(), + host->external_name()); + } else if (_nest_members != NULL && _nest_members != Universe::the_empty_short_array()) { + log_trace(class, nestmates)("Type %s is a dynamic nest member of %s: the NestMembers attribute in the current class is ignored", + this->external_name(), + host->external_name()); + } + } + // set dynamic nest host + _nest_host = host; +} + // check if 'this' and k are nestmates (same nest_host), or k is our nest_host, // or we are k's nest_host - all of which is covered by comparing the two // resolved_nest_hosts @@ -368,12 +428,13 @@ } InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) { + bool is_hidden_or_anonymous = parser.is_hidden() || parser.is_unsafe_anonymous(); const int size = InstanceKlass::size(parser.vtable_size(), parser.itable_size(), nonstatic_oop_map_size(parser.total_oop_map_count()), parser.is_interface(), - parser.is_unsafe_anonymous(), - should_store_fingerprint(parser.is_unsafe_anonymous())); + is_hidden_or_anonymous, + should_store_fingerprint(is_hidden_or_anonymous)); const Symbol* const class_name = parser.class_name(); assert(class_name != NULL, "invariant"); @@ -446,6 +507,7 @@ set_vtable_length(parser.vtable_size()); set_kind(kind); set_access_flags(parser.access_flags()); + if (parser.is_hidden()) set_is_hidden(); set_is_unsafe_anonymous(parser.is_unsafe_anonymous()); set_layout_helper(Klass::instance_layout_helper(parser.layout_size(), false)); @@ -2248,7 +2310,7 @@ return true; } -bool InstanceKlass::should_store_fingerprint(bool is_unsafe_anonymous) { +bool InstanceKlass::should_store_fingerprint(bool is_hidden_or_anonymous) { #if INCLUDE_AOT // We store the fingerprint into the InstanceKlass only in the following 2 cases: if (CalculateClassFingerprint) { @@ -2259,8 +2321,8 @@ // (2) We are running -Xshare:dump or -XX:ArchiveClassesAtExit to create a shared archive return true; } - if (UseAOT && is_unsafe_anonymous) { - // (3) We are using AOT code from a shared library and see an unsafe anonymous class + if (UseAOT && is_hidden_or_anonymous) { + // (3) We are using AOT code from a shared library and see a hidden or unsafe anonymous class return true; } #endif @@ -2585,6 +2647,7 @@ // Decrement symbol reference counts associated with the unloaded class. if (_name != NULL) _name->decrement_refcount(); + // unreference array name derived from this class name (arrays of an unloaded // class can't be referenced anymore). if (_array_name != NULL) _array_name->decrement_refcount(); @@ -2671,6 +2734,25 @@ return unsafe_anonymous_host()->module(); } + if (is_hidden() && + in_unnamed_package() && + class_loader_data()->is_shortlived()) { + // For a weak hidden class defined to an unnamed package, + // the short-lived CLD will not have an unnamed module created for it. + // Two choices to find the correct ModuleEntry: + // 1. If hidden class is within a nest, use nest host's module + // 2. Find the unnamed module off from the class loader + // For now option #2 is used since a nest host is not set until + // after the instance class is created in jvm_lookup_define_class(). + if (class_loader_data()->is_boot_class_loader_data()) { + return ClassLoaderData::the_null_class_loader_data()->unnamed_module(); + } else { + oop module = java_lang_ClassLoader::unnamedModule(class_loader_data()->class_loader()); + assert(java_lang_Module::is_instance(module), "Not an instance of java.lang.Module"); + return java_lang_Module::module_entry(module); + } + } + // Class is in a named package if (!in_unnamed_package()) { return _package_entry->module(); @@ -2882,7 +2964,7 @@ *inner_is_member = true; } if (NULL == outer_klass) { - // It may be unsafe anonymous; try for that. + // It may be a local or anonymous class; try for that. int encl_method_class_idx = enclosing_method_class_index(); if (encl_method_class_idx != 0) { Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);