< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page

        

@@ -153,10 +153,11 @@
   return false;
 }
 
 // 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);
       log_trace(class, nestmates)("Checked nest membership of %s in non-nest-host class %s",
                                   k->external_name(), this->external_name());

@@ -210,10 +211,28 @@
   }
   log_trace(class, nestmates)("- class is NOT a nest member!");
   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
 // causes the access check to return false. Such code will retry the access
 // from a more suitable environment later.

@@ -243,12 +262,17 @@
       }
 
       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;
           jio_snprintf(buf, sizeof(buf),
                        "Unable to load nest-host class (%s) of %s",

@@ -329,10 +353,46 @@
     }
   }
   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
 bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
 

@@ -366,16 +426,17 @@
 
   return access;
 }
 
 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");
   ClassLoaderData* loader_data = parser.loader_data();
   assert(loader_data != NULL, "invariant");

@@ -444,10 +505,11 @@
   _reference_type(parser.reference_type())
 {
   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));
 
   assert(NULL == _methods, "underlying memory not zeroed?");

@@ -2246,23 +2308,23 @@
   }
 
   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) {
     // (1) We are running AOT to generate a shared library.
     return true;
   }
   if (Arguments::is_dumping_archive()) {
     // (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
 
   // In all other cases we might set the _misc_has_passed_fingerprint_check bit,

@@ -2583,10 +2645,11 @@
   }
 #endif
 
   // 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();
   FREE_C_HEAP_ARRAY(char, _source_debug_extension);
 }

@@ -2669,10 +2732,29 @@
   if (is_unsafe_anonymous()) {
     assert(unsafe_anonymous_host() != NULL, "unsafe anonymous class must have a host class");
     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();
   }
 

@@ -2880,11 +2962,11 @@
       Klass* ok = i_cp->klass_at(ooff, CHECK_NULL);
       outer_klass = InstanceKlass::cast(ok);
       *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);
         outer_klass = InstanceKlass::cast(ok);
         *inner_is_member = false;
< prev index next >