< prev index next >
src/hotspot/share/prims/jvm.cpp
Print this page
@@ -981,17 +981,185 @@
}
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,
+ 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,
+ * hidden, or weakly referenced from class loader.
+ */
+static jclass jvm_lookup_define_class(JNIEnv *env, jclass lookup, const char *name,
+ jobject loader, 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* 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_hidden = (flags & HIDDEN_CLASS) == HIDDEN_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) {
+ host_class = InstanceKlass::cast(k)->runtime_nest_host(CHECK_NULL);
+ }
+
+ 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_hidden ? "hidden" : "not hidden",
+ is_weak ? "weak" : "strong",
+ 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_weak) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "weak class is only applicable for hidden classes");
+ }
+ if (vm_annotations) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for hidden classes");
+ }
+ if (flags) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ err_msg("flag 0x%x can only be set for hidden classes", 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 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_hidden) {
+ k = SystemDictionary::resolve_from_stream(class_name,
+ class_loader,
+ protection_domain,
+ &st,
+ CHECK_NULL);
+
+ if (log_is_enabled(Debug, class, resolve) && k != NULL) {
+ trace_class_resolution(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_weak,
+ vm_annotations);
+ k = SystemDictionary::parse_stream(class_name,
+ class_loader,
+ &st,
+ cl_info,
+ CHECK_NULL);
+ if (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(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_hidden() ? "is hidden" : "is not hidden");
+ }
+ }
+
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ if (init) {
+ ik->initialize(CHECK_NULL);
+ } else {
+ ik->link_class(CHECK_NULL);
+ }
+
+ 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
+ * 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, jobject loader,
+ 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, loader, 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);
@@ -1150,10 +1318,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))) {
@@ -1417,11 +1594,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))
@@ -1863,11 +2040,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;
@@ -1885,11 +2063,11 @@
return NULL;
}
}
}
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 >