# HG changeset patch # User redestad # Date 1468856116 -7200 # Mon Jul 18 17:35:16 2016 +0200 # Node ID 49140edb00eefa3fe6fbf154ffe9b1fa77acb6cc # Parent 22bf6db9767b1b3a1994cbf32eb3331f31ae2093 8161588: MemberName::resolveOrNull cause and hide NoSuchMethodErrors Reviewed-by: mhaupt diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp +++ b/src/share/vm/prims/methodHandles.cpp @@ -639,7 +639,7 @@ // An unresolved member name is a mere symbolic reference. // Resolving it plants a vmtarget/vmindex in it, // which refers directly to JVM internals. -Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS) { +Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, bool clear_pending, TRAPS) { Handle empty; assert(java_lang_invoke_MemberName::is_instance(mname()), ""); @@ -738,6 +738,7 @@ assert(false, "ref_kind=%d", ref_kind); } if (HAS_PENDING_EXCEPTION) { + if (clear_pending) CLEAR_PENDING_EXCEPTION; return empty; } } @@ -762,6 +763,7 @@ break; // will throw after end of switch } if (HAS_PENDING_EXCEPTION) { + if (clear_pending) CLEAR_PENDING_EXCEPTION; return empty; } } @@ -777,6 +779,7 @@ LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check); LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { + if (clear_pending) CLEAR_PENDING_EXCEPTION; return empty; } } @@ -1213,13 +1216,9 @@ } JVM_END -// void resolve(MemberName self, Class caller) -JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { - if (mname_jh == NULL) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); } - Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); - - // The trusted Java code that calls this method should already have performed - // access checks on behalf of the given caller. But, we can verify this. +// The trusted Java code that calls this method should already have performed +// access checks on behalf of the given caller. But, we can verify this. +static void verify_method_handle(Handle mname, jclass caller_jh, TRAPS) { if (VerifyMethodHandles && caller_jh != NULL && java_lang_invoke_MemberName::clazz(mname()) != NULL) { Klass* reference_klass = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(mname())); @@ -1234,15 +1233,23 @@ if (Reflection::verify_class_access(caller, reference_klass, true) != Reflection::ACCESS_OK) { - THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), reference_klass->external_name()); + THROW_MSG(vmSymbols::java_lang_InternalError(), reference_klass->external_name()); } } } +} + +// void resolve(MemberName self, Class caller) +JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { + if (mname_jh == NULL) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); } + Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); + + verify_method_handle(mname, caller_jh, CHECK_NULL); KlassHandle caller(THREAD, caller_jh == NULL ? (Klass*) NULL : java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh))); - Handle resolved = MethodHandles::resolve_MemberName(mname, caller, CHECK_NULL); + Handle resolved = MethodHandles::resolve_MemberName(mname, caller, /* !clear_pending */false, CHECK_NULL); if (resolved.is_null()) { int flags = java_lang_invoke_MemberName::flags(mname()); @@ -1264,6 +1271,22 @@ } JVM_END +// void resolveOrNull(MemberName self, Class caller) +JVM_ENTRY(jobject, MHN_resolve_or_null_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { + if (mname_jh == NULL) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); } + Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); + + verify_method_handle(mname, caller_jh, CHECK_NULL); + + KlassHandle caller(THREAD, + caller_jh == NULL ? (Klass*) NULL : + java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh))); + Handle resolved = MethodHandles::resolve_MemberName(mname, caller, /* clear_pending */true, CHECK_NULL); + + return JNIHandles::make_local(THREAD, resolved()); +} +JVM_END + static jlong find_member_field_offset(oop mname, bool must_be_static, TRAPS) { if (mname == NULL || java_lang_invoke_MemberName::vmtarget(mname) == NULL) { @@ -1461,6 +1484,7 @@ {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)}, + {CC "resolveOrNull", CC "(" MEM "" CLS ")" MEM, FN_PTR(MHN_resolve_or_null_Mem)}, // static native int getNamedCon(int which, Object[] name) {CC "getNamedCon", CC "(I[" OBJ ")I", FN_PTR(MHN_getNamedCon)}, // static native int getMembers(Class defc, String matchName, String matchSig, diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp +++ b/src/share/vm/prims/methodHandles.hpp @@ -61,7 +61,7 @@ public: // working with member names - static Handle resolve_MemberName(Handle mname, KlassHandle caller, TRAPS); // compute vmtarget/vmindex from name/type + static Handle resolve_MemberName(Handle mname, KlassHandle caller, bool clear_pending, TRAPS); // compute vmtarget/vmindex from name/type static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing static Handle new_MemberName(TRAPS); // must be followed by init_MemberName static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target