From 33d0b6260118f3a27299355013f1edf8faa5404a Mon Sep 17 00:00:00 2001 From: twisti Date: Mon, 6 May 2013 13:53:13 -0700 Subject: [PATCH] 7196277: JSR 292: Two jck/runtime tests crash on java.lang.invoke.MethodHandle.invokeExact Reviewed-by: jrose, kvn --- src/share/vm/oops/method.cpp | 4 +- src/share/vm/prims/methodHandles.cpp | 58 ++++++++++++++++++++++---- src/share/vm/prims/nativeLookup.cpp | 5 +-- src/share/vm/runtime/sharedRuntime.cpp | 28 +++++++------ 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/share/vm/oops/method.cpp b/src/share/vm/oops/method.cpp index 74364c3bd..68a55ef09 100644 --- a/src/share/vm/oops/method.cpp +++ b/src/share/vm/oops/method.cpp @@ -832,7 +832,9 @@ void Method::link_method(methodHandle h_method, TRAPS) { assert(entry != NULL, "interpreter entry must be non-null"); // Sets both _i2i_entry and _from_interpreted_entry set_interpreter_entry(entry); - if (is_native() && !is_method_handle_intrinsic()) { + + // Don't overwrite already registered native entries. + if (is_native() && !has_native_function()) { set_native_function( SharedRuntime::native_method_throw_unsatisfied_link_error_entry(), !native_bind_event_is_interesting); diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp index 341049852..2ef36f914 100644 --- a/src/share/vm/prims/methodHandles.cpp +++ b/src/share/vm/prims/methodHandles.cpp @@ -1298,6 +1298,28 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec } JVM_END +/** + * Throws a java/lang/UnsupportedOperationException unconditionally. + * This is required by the specification of MethodHandle.invoke if + * invoked directly. + */ +JVM_ENTRY(jobject, MH_invoke_UOE(JNIEnv* env, jobject mh, jobjectArray args)) { + THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invoke cannot be invoked reflectively"); + return NULL; +} +JVM_END + +/** + * Throws a java/lang/UnsupportedOperationException unconditionally. + * This is required by the specification of MethodHandle.invokeExact if + * invoked directly. + */ +JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args)) { + THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invokeExact cannot be invoked reflectively"); + return NULL; +} +JVM_END + /// JVM_RegisterMethodHandleMethods #undef CS // Solaris builds complain @@ -1317,7 +1339,7 @@ JVM_END #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) // These are the native methods on java.lang.invoke.MethodHandleNatives. -static JNINativeMethod required_methods_JDK8[] = { +static JNINativeMethod MHN_methods[] = { {CC"init", CC"("MEM""OBJ")V", FN_PTR(MHN_init_Mem)}, {CC"expand", CC"("MEM")V", FN_PTR(MHN_expand_Mem)}, {CC"resolve", CC"("MEM""CLS")"MEM, FN_PTR(MHN_resolve_Mem)}, @@ -1335,8 +1357,28 @@ static JNINativeMethod required_methods_JDK8[] = { {CC"getMemberVMInfo", CC"("MEM")"OBJ, FN_PTR(MHN_getMemberVMInfo)} }; -// This one function is exported, used by NativeLookup. +static JNINativeMethod MH_methods[] = { + // UnsupportedOperationException throwers + {CC"invoke", CC"(["OBJ")"OBJ, FN_PTR(MH_invoke_UOE)}, + {CC"invokeExact", CC"(["OBJ")"OBJ, FN_PTR(MH_invokeExact_UOE)} +}; + +/** + * Helper method to register native methods. + */ +static bool register_natives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) { + int status = env->RegisterNatives(clazz, methods, nMethods); + if (status != JNI_OK || env->ExceptionOccurred()) { + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); + env->ExceptionClear(); + return false; + } + return true; +} +/** + * This one function is exported, used by NativeLookup. + */ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { if (!EnableInvokeDynamic) { warning("JSR 292 is disabled in this JVM. Use -XX:+UnlockDiagnosticVMOptions -XX:+EnableInvokeDynamic to enable."); @@ -1354,16 +1396,14 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) MH_class = (jclass) JNIHandles::make_local(env, mirror); } - int status; - if (enable_MH) { ThreadToNativeFromVM ttnfv(thread); - status = env->RegisterNatives(MHN_class, required_methods_JDK8, sizeof(required_methods_JDK8)/sizeof(JNINativeMethod)); - if (status != JNI_OK || env->ExceptionOccurred()) { - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - enable_MH = false; - env->ExceptionClear(); + if (enable_MH) { + enable_MH = register_natives(env, MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod)); + } + if (enable_MH) { + enable_MH = register_natives(env, MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); } } diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp index 6162ae850..990600eea 100644 --- a/src/share/vm/prims/nativeLookup.cpp +++ b/src/share/vm/prims/nativeLookup.cpp @@ -383,10 +383,7 @@ address NativeLookup::lookup_base(methodHandle method, bool& in_base_library, TR address NativeLookup::lookup(methodHandle method, bool& in_base_library, TRAPS) { if (!method->has_native_function()) { - address entry = - method->intrinsic_id() == vmIntrinsics::_invokeGeneric ? - SharedRuntime::native_method_throw_unsupported_operation_exception_entry() : - lookup_base(method, in_base_library, CHECK_NULL); + address entry = lookup_base(method, in_base_library, CHECK_NULL); method->set_native_function(entry, Method::native_bind_event_is_interesting); // -verbose:jni printing diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp index 57af1f3bd..114f27d20 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp @@ -883,15 +883,23 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, } -JNI_ENTRY(void, throw_unsatisfied_link_error(JNIEnv* env, ...)) -{ - THROW(vmSymbols::java_lang_UnsatisfiedLinkError()); -} -JNI_END - -JNI_ENTRY(void, throw_unsupported_operation_exception(JNIEnv* env, ...)) +/** + * Throws an java/lang/UnsatisfiedLinkError. The address of this method is + * installed in the native function entry of all native Java methods before + * they get linked to their actual native methods. + * + * \note + * This method actually never gets called! The reason is because + * the interpreter's native entries call NativeLookup::lookup() which + * throws the exception when the lookup fails. The exception is then + * caught and forwarded on the return from NativeLookup::lookup() call + * before the call to the native function. This might change in the future. + */ +JNI_ENTRY(void*, throw_unsatisfied_link_error(JNIEnv* env, ...)) { - THROW(vmSymbols::java_lang_UnsupportedOperationException()); + // We return a bad value here to make sure that the exception is + // forwarded before we look at the return value. + THROW_(vmSymbols::java_lang_UnsatisfiedLinkError(), (void*)badJNIHandle); } JNI_END @@ -899,10 +907,6 @@ address SharedRuntime::native_method_throw_unsatisfied_link_error_entry() { return CAST_FROM_FN_PTR(address, &throw_unsatisfied_link_error); } -address SharedRuntime::native_method_throw_unsupported_operation_exception_entry() { - return CAST_FROM_FN_PTR(address, &throw_unsupported_operation_exception); -} - #ifndef PRODUCT JRT_ENTRY(intptr_t, SharedRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2)) -- GitLab