< prev index next >

src/hotspot/share/prims/jvm.cpp

Print this page

        

@@ -987,17 +987,188 @@
   }
 
   return (jclass) JNIHandles::make_local(env, k->java_mirror());
 }
 
+enum {
+  NESTMATE              = java_lang_invoke_MemberName::MN_NESTMATE_CLASS,
+  HIDDEN_CLASS          = java_lang_invoke_MemberName::MN_HIDDEN_CLASS,
+  STRONG_LOADER_LINK    = java_lang_invoke_MemberName::MN_STRONG_LOADER_LINK,
+  ACCESS_VM_ANNOTATIONS = java_lang_invoke_MemberName::MN_ACCESS_VM_ANNOTATIONS
+};
+
+/*
+ * Define a class with the specified flags that indicates if it's a nestmate,
+ * hidden, or strongly referenced from class loader.
+ */
+static jclass jvm_lookup_define_class(JNIEnv *env, jclass lookup, const char *name,
+                                      const jbyte *buf, jsize len, jobject pd,
+                                      jboolean init, int flags, jobject classData, TRAPS) {
+  assert(THREAD->is_Java_thread(), "must be a JavaThread");
+  JavaThread* jt = (JavaThread*) THREAD;
+  ResourceMark rm(THREAD);
+
+  Klass* lookup_k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup));
+  // Lookup class must be a non-null instance
+  if (lookup_k == NULL) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
+  }
+  assert(lookup_k->is_instance_klass(), "Lookup class must be an instance klass");
+
+  oop loader = lookup_k->class_loader();
+  Handle class_loader (THREAD, loader);
+
+  jboolean is_nestmate = (flags & NESTMATE) == NESTMATE;
+  jboolean is_hidden = (flags & HIDDEN_CLASS) == HIDDEN_CLASS;
+  jboolean is_strong = (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK;
+  jboolean vm_annotations = (flags & ACCESS_VM_ANNOTATIONS) == ACCESS_VM_ANNOTATIONS;
+
+  InstanceKlass* host_class = NULL;
+  if (is_nestmate) {
+    host_class = InstanceKlass::cast(lookup_k)->nest_host(CHECK_NULL);
+  }
+
+  log_info(class, nestmates)("LookupDefineClass: %s - %s%s, %s, %s, %s",
+                             name,
+                             is_nestmate ? "with dynamic nest-host " : "non-nestmate",
+                             is_nestmate ? host_class->external_name() : "",
+                             is_hidden ? "hidden" : "not hidden",
+                             is_strong ? "strong" : "weak",
+                             vm_annotations ? "with vm annotations" : "without vm annotation");
+
+  if (!is_hidden) {
+    // classData is only applicable for hidden classes
+    if (classData != NULL) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "classData is only applicable for hidden classes");
+    }
+    if (is_nestmate) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "dynamic nestmate is only applicable for hidden classes");
+    }
+    if (!is_strong) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "an ordinary class must be strongly referenced by its defining loader");
+    }
+    if (vm_annotations) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for hidden classes");
+    }
+    if (flags != STRONG_LOADER_LINK) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+                  err_msg("invalid flag 0x%x", flags));
+    }
+  }
+
+
+  // Since exceptions can be thrown, class initialization can take place
+  // if name is NULL no check for class name in .class stream has to be made.
+  TempNewSymbol class_name = NULL;
+  if (name != NULL) {
+    const int str_len = (int)strlen(name);
+    if (str_len > Symbol::max_length()) {
+      // It's impossible to create this class;  the name cannot fit
+      // into the constant pool.
+      Exceptions::fthrow(THREAD_AND_LOCATION,
+                         vmSymbols::java_lang_NoClassDefFoundError(),
+                         "Class name exceeds maximum length of %d: %s",
+                         Symbol::max_length(),
+                         name);
+      return 0;
+    }
+    class_name = SymbolTable::new_symbol(name, str_len);
+  }
+
+  Handle protection_domain (THREAD, JNIHandles::resolve(pd));
+  const char* source = is_nestmate ? host_class->external_name() : "__JVM_LookupDefineClass__";
+  ClassFileStream st((u1*)buf, len, source, ClassFileStream::verify);
+
+  Klass* defined_k;
+  if (!is_hidden) {
+    defined_k = SystemDictionary::resolve_from_stream(class_name,
+                                                      class_loader,
+                                                      protection_domain,
+                                                      &st,
+                                                      CHECK_NULL);
+
+    if (log_is_enabled(Debug, class, resolve) && defined_k != NULL) {
+      trace_class_resolution(defined_k);
+    }
+  } else { // hidden
+    Handle classData_h(THREAD, JNIHandles::resolve(classData));
+    ClassLoadInfo cl_info(protection_domain,
+                          NULL, // unsafe_anonymous_host
+                          NULL, // cp_patches
+                          host_class,
+                          classData_h,
+                          is_hidden,
+                          is_strong,
+                          vm_annotations);
+    defined_k = SystemDictionary::parse_stream(class_name,
+                                               class_loader,
+                                               &st,
+                                               cl_info,
+                                               CHECK_NULL);
+    if (defined_k == NULL) {
+      THROW_MSG_0(vmSymbols::java_lang_Error(), "Failure to define a hidden class");
+    }
+
+    // The hidden class loader data has been artificially been kept alive to
+    // this point. The mirror and any instances of this class have to keep
+    // it alive afterwards.
+    InstanceKlass::cast(defined_k)->class_loader_data()->dec_keep_alive();
+
+    if (is_nestmate && log_is_enabled(Debug, class, nestmates)) {
+      InstanceKlass* ik = InstanceKlass::cast(defined_k);
+      ModuleEntry* module = ik->module();
+      const char * module_name = module->is_named() ? module->name()->as_C_string() : UNNAMED_MODULE;
+      log_debug(class, nestmates)("Dynamic nestmate: %s/%s, nest_host %s, %s",
+                                  module_name,
+                                  ik->external_name(),
+                                  host_class->external_name(),
+                                  ik->is_hidden() ? "is hidden" : "is not hidden");
+    }
+  }
+  assert(Reflection::is_same_class_package(lookup_k, defined_k),
+         "lookup class and defined class are in different packages");
+
+  InstanceKlass* ik = InstanceKlass::cast(defined_k);
+  if (init) {
+    ik->initialize(CHECK_NULL);
+  } else {
+    ik->link_class(CHECK_NULL);
+  }
+
+  return (jclass) JNIHandles::make_local(env, defined_k->java_mirror());
+}
 
 JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd))
   JVMWrapper("JVM_DefineClass");
 
   return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD);
 JVM_END
 
+/*
+ * 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
+ */
+JVM_ENTRY(jclass, JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char *name, const jbyte *buf,
+          jsize len, jobject pd, jboolean initialize, int flags, jobject classData))
+  JVMWrapper("JVM_LookupDefineClass");
+
+  if (lookup == NULL) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
+  }
+
+  assert(buf != NULL, "buf must not be NULL");
+
+  return jvm_lookup_define_class(env, lookup, name, buf, len, pd, initialize, flags, classData, THREAD);
+JVM_END
 
 JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source))
   JVMWrapper("JVM_DefineClassWithSource");
 
   return jvm_define_class_common(env, name, loader, buf, len, pd, source, THREAD);

@@ -1156,10 +1327,19 @@
   // The compiler intrinsic for isInterface tests the
   // Klass::_access_flags bits in the same way.
   return result;
 JVM_END
 
+JVM_ENTRY(jboolean, JVM_IsHiddenClass(JNIEnv *env, jclass cls))
+  JVMWrapper("JVM_IsHiddenClass");
+  oop mirror = JNIHandles::resolve_non_null(cls);
+  if (java_lang_Class::is_primitive(mirror)) {
+    return JNI_FALSE;
+  }
+  Klass* k = java_lang_Class::as_Klass(mirror);
+  return k->is_hidden();
+JVM_END
 
 JVM_ENTRY(jobjectArray, JVM_GetClassSigners(JNIEnv *env, jclass cls))
   JVMWrapper("JVM_GetClassSigners");
   JvmtiVMObjectAllocEventCollector oam;
   if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) {

@@ -1423,11 +1603,11 @@
   bool inner_is_member = false;
   Klass* outer_klass
     = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))
                           )->compute_enclosing_class(&inner_is_member, CHECK_NULL);
   if (outer_klass == NULL)  return NULL;  // already a top-level class
-  if (!inner_is_member)  return NULL;     // an anonymous class (inside a method)
+  if (!inner_is_member)  return NULL;     // a hidden or unsafe anonymous class (inside a method)
   return (jclass) JNIHandles::make_local(env, outer_klass->java_mirror());
 }
 JVM_END
 
 JVM_ENTRY(jstring, JVM_GetSimpleBinaryName(JNIEnv *env, jclass cls))

@@ -1873,77 +2053,91 @@
   // current is not a primitive or array class
   JVMWrapper("JVM_GetNestHost");
   Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
   assert(c->is_instance_klass(), "must be");
   InstanceKlass* ck = InstanceKlass::cast(c);
-  // Don't post exceptions if validation fails
-  InstanceKlass* host = ck->nest_host(NULL, THREAD);
+  InstanceKlass* host = ck->nest_host(THREAD);
   return (jclass) (host == NULL ? NULL :
                    JNIHandles::make_local(THREAD, host->java_mirror()));
 }
 JVM_END
 
 JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current))
 {
   // current is not a primitive or array class
   JVMWrapper("JVM_GetNestMembers");
+  ResourceMark rm(THREAD);
   Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
   assert(c->is_instance_klass(), "must be");
   InstanceKlass* ck = InstanceKlass::cast(c);
-  // Get the nest host for this nest - throw ICCE if validation fails
-  Symbol* icce = vmSymbols::java_lang_IncompatibleClassChangeError();
-  InstanceKlass* host = ck->nest_host(icce, CHECK_NULL);
+  InstanceKlass* host = ck->nest_host(THREAD);
 
+  log_trace(class, nestmates)("Calling GetNestMembers for type %s with nest-host %s",
+                              ck->external_name(), host->external_name());
   {
     JvmtiVMObjectAllocEventCollector oam;
     Array<u2>* members = host->nest_members();
     int length = members == NULL ? 0 : members->length();
+
+    log_trace(class, nestmates)(" - host has %d listed nest members", length);
+
     // nest host is first in the array so make it one bigger
     objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(),
                                              length + 1, CHECK_NULL);
-    objArrayHandle result (THREAD, r);
+    objArrayHandle result(THREAD, r);
     result->obj_at_put(0, host->java_mirror());
     if (length != 0) {
-      int i;
-      for (i = 0; i < length; i++) {
+      int count = 0;
+      for (int i = 0; i < length; i++) {
          int cp_index = members->at(i);
-         Klass* k = host->constants()->klass_at(cp_index, CHECK_NULL);
+        Klass* k = host->constants()->klass_at(cp_index, THREAD);
+        if (HAS_PENDING_EXCEPTION) {
+          if (PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass())) {
+            return NULL; // propagate VMEs
+          }
+          if (log_is_enabled(Trace, class, nestmates)) {
+            stringStream ss;
+            char* target_member_class = host->constants()->klass_name_at(cp_index)->as_C_string();
+            ss.print(" - resolution of nest member %s failed: ", target_member_class);
+            java_lang_Throwable::print(PENDING_EXCEPTION, &ss);
+            log_trace(class, nestmates)("%s", ss.as_string());
+          }
+          CLEAR_PENDING_EXCEPTION;
+          continue;
+        }
          if (k->is_instance_klass()) {
-           InstanceKlass* nest_host_k =
-             InstanceKlass::cast(k)->nest_host(icce, CHECK_NULL);
+          InstanceKlass* ik = InstanceKlass::cast(k);
+          InstanceKlass* nest_host_k = ik->nest_host(CHECK_NULL);
            if (nest_host_k == host) {
-             result->obj_at_put(i+1, k->java_mirror());
+            result->obj_at_put(count+1, k->java_mirror());
+            count++;
+            log_trace(class, nestmates)(" - [%d] = %s", count, ik->external_name());
+          } else {
+            log_trace(class, nestmates)(" - skipping member %s with different host %s",
+                                        ik->external_name(), nest_host_k->external_name());
            }
-           else {
-             // k's nest host is legal but it isn't our host so
-             // throw ICCE
-             ResourceMark rm(THREAD);
-             Exceptions::fthrow(THREAD_AND_LOCATION,
-                                icce,
-                                "Nest member %s in %s declares a different nest host of %s",
-                                k->external_name(),
-                                host->external_name(),
-                                nest_host_k->external_name()
-                           );
-             return NULL;
+        } else {
+          log_trace(class, nestmates)(" - skipping member %s that is not an instance class",
+                                      k->external_name());
            }
          }
-         else {
-           // we have a bad nest member entry - throw ICCE
-           ResourceMark rm(THREAD);
-           Exceptions::fthrow(THREAD_AND_LOCATION,
-                              icce,
-                              "Class %s can not be a nest member of %s",
-                              k->external_name(),
-                              host->external_name()
-                              );
-           return NULL;
+      if (count < length) {
+        // we had invalid entries so we need to compact the array
+        log_trace(class, nestmates)(" - compacting array from length %d to %d",
+                                    length + 1, count + 1);
+
+        objArrayOop r2 = oopFactory::new_objArray(SystemDictionary::Class_klass(),
+                                                  count + 1, CHECK_NULL);
+        objArrayHandle result2(THREAD, r2);
+        for (int i = 0; i < count + 1; i++) {
+          result2->obj_at_put(i, result->obj_at(i));
          }
+        return (jobjectArray)JNIHandles::make_local(THREAD, result2());
       }
     }
     else {
-      assert(host == ck, "must be singleton nest");
+      assert(host == ck || ck->is_hidden(), "must be singleton nest or dynamic nestmate");
     }
     return (jobjectArray)JNIHandles::make_local(THREAD, result());
   }
 }
 JVM_END
< prev index next >