< prev index next >

src/hotspot/share/prims/jvm.cpp

Print this page

        

@@ -951,26 +951,183 @@
   Handle protection_domain (THREAD, JNIHandles::resolve(pd));
   Klass* k = SystemDictionary::resolve_from_stream(class_name,
                                                    class_loader,
                                                    protection_domain,
                                                    &st,
+                                                   NULL,  // dynamic_nest_host
                                                    CHECK_NULL);
 
   if (log_is_enabled(Debug, class, resolve) && k != NULL) {
     trace_class_resolution(k);
   }
 
   return (jclass) JNIHandles::make_local(env, k->java_mirror());
 }
 
+enum {
+  NESTMATE              = java_lang_invoke_MemberName::MN_NESTMATE_CLASS,
+  NONFINDABLE_CLASS     = java_lang_invoke_MemberName::MN_NONFINDABLE_CLASS,
+  WEAK_CLASS            = java_lang_invoke_MemberName::MN_WEAK_CLASS,
+  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,
+ * not findable, or weakly reachable from class loader.
+ *
+ * Same class may be defined by multiple threads at the same time.
+ * Should the VM keep the classData (the one successfully defined the class)
+ * as if a private static field is declared in the class?
+ */
+static jclass jvm_lookup_define_class(JNIEnv *env, jclass lookup, const char *name,
+                                      jobject loader, const jbyte *buf, jsize len, jobject pd,
+                                      int flags, jobject classData, TRAPS) {
+  assert(THREAD->is_Java_thread(), "must be a JavaThread");
+  JavaThread* jt = (JavaThread*) THREAD;
+  ResourceMark rm(THREAD);
+
+  Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup));
+  // Lookup class must be a non-null instance
+  if (k == NULL) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
+  }
+  assert(k->is_instance_klass(), "Lookup class must be an instance klass");
+
+  jboolean is_nestmate = (flags & NESTMATE) == NESTMATE;
+  jboolean is_nonfindable = (flags & NONFINDABLE_CLASS) == NONFINDABLE_CLASS;
+  jboolean is_weak = (flags & WEAK_CLASS) == WEAK_CLASS;
+  jboolean vm_annotations = (flags & ACCESS_VM_ANNOTATIONS) == ACCESS_VM_ANNOTATIONS;
+
+  InstanceKlass* host_class = NULL;
+  if (is_nestmate) {
+    // we need to find the true nest-host of the lookup class,
+    // so any exceptions in nest validation must be thrown
+    Symbol* icce = vmSymbols::java_lang_IncompatibleClassChangeError();
+    host_class = InstanceKlass::cast(k)->nest_host(icce, CHECK_NULL);
+  }
+
+  // classData (constant pool patching replacement) is only applicable for nonfindable classes
+  if (classData != NULL && !is_nonfindable) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "classData is only applicable for nonfindable classes");
+  }
+
+  // vm_annotations only allowed for nonfindable classes
+  if (vm_annotations && !is_nonfindable) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for weak nonfindable classes");
+  }
+
+  if (log_is_enabled(Info, class, nestmates)) {
+    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_nonfindable ? "non-findable" : "findable",
+                               is_weak ? "weak" : "strong",
+                               vm_annotations ? "with vm annotations" : "without vm annotation");
+  }
+
+  // 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, CHECK_NULL);
+  }
+
+  Handle class_loader (THREAD, JNIHandles::resolve(loader));
+  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);
+
+  if (!is_nonfindable) {
+    k = SystemDictionary::resolve_from_stream(class_name,
+                                              class_loader,
+                                              protection_domain,
+                                              &st,
+                                              host_class,
+                                              CHECK_NULL);
+
+    if (log_is_enabled(Debug, class, resolve) && k != NULL) {
+      trace_class_resolution(k);
+    }
+  } else { //nonfindable
+    Handle classData_h(THREAD, JNIHandles::resolve(classData));
+    k = SystemDictionary::parse_stream(class_name,
+                                       class_loader,
+                                       protection_domain,
+                                       &st,
+                                       NULL, // unsafe_anonymous_host
+                                       NULL, // cp_patches
+                                       is_nonfindable,
+                                       is_weak,
+                                       vm_annotations,
+                                       host_class,
+                                       classData_h,
+                                       CHECK_NULL);
+    if (k == NULL) {
+      THROW_MSG_0(vmSymbols::java_lang_Error(), "Failure to define a nonfindable class");
+    }
+
+    // The nonfindable 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(k)->class_loader_data()->dec_keep_alive();
+  }
+
+  if (is_nestmate && log_is_enabled(Debug, class, nestmates)) {
+    InstanceKlass* ik = InstanceKlass::cast(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_nonfindable() ? "is non-findable" : "is findable");
+  }
+
+  return (jclass) JNIHandles::make_local(env, 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
+ *  flags:   properties of the class
+ *  classData: private static pre-initialized field
+ */
+JVM_ENTRY(jclass, JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char *name, jobject loader,
+                      const jbyte *buf, jsize len, jobject pd, 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, loader, buf, len, pd, 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);

@@ -1388,11 +1545,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 nonfindable 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))

@@ -1833,11 +1990,12 @@
              // 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",
+                                "%s.getNestMembers: Nest member %s in %s declares a different nest host of %s",
+                                c->external_name(),
                                 k->external_name(),
                                 host->external_name(),
                                 nest_host_k->external_name()
                            );
              return NULL;
< prev index next >