# HG changeset patch # User redestad # Date 1522098682 -7200 # Mon Mar 26 23:11:22 2018 +0200 # Node ID 40d80a2d7a09cd61aa0ee5149f5c89f12831ffae # Parent b39bc2eb8325eafc55b7c0d0f4dd5076b3d44561 8200238: Reduce number of exceptions created when calling MemberName$Factory::resolveOrNull Reviewed-by: lfoltan, acorn diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -2793,7 +2793,7 @@ // which MemberName resolution doesn't handle. There's special logic on JDK side to handle them // (see MethodHandles.linkMethodHandleConstant() and MethodHandles.findVirtualForMH()). } else { - MethodHandles::resolve_MemberName(mname, caller, CHECK_(empty)); + MethodHandles::resolve_MemberName(mname, caller, /*speculative_resolve*/false, CHECK_(empty)); } // After method/field resolution succeeded, it's safe to resolve MH signature as well. diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -304,7 +304,7 @@ Handle resolved_method = info.resolved_method_name(); assert(java_lang_invoke_ResolvedMethodName::vmtarget(resolved_method()) == m(), - "Should not change after link resolultion"); + "Should not change after link resolution"); oop mname_oop = mname(); java_lang_invoke_MemberName::set_flags (mname_oop, flags); @@ -680,7 +680,8 @@ // 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, Klass* caller, TRAPS) { +Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller, + bool speculative_resolve, TRAPS) { Handle empty; assert(java_lang_invoke_MemberName::is_instance(mname()), ""); @@ -779,6 +780,9 @@ assert(false, "ref_kind=%d", ref_kind); } if (HAS_PENDING_EXCEPTION) { + if (speculative_resolve) { + CLEAR_PENDING_EXCEPTION; + } return empty; } } @@ -804,6 +808,9 @@ break; // will throw after end of switch } if (HAS_PENDING_EXCEPTION) { + if (speculative_resolve) { + CLEAR_PENDING_EXCEPTION; + } return empty; } } @@ -820,6 +827,9 @@ 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 (speculative_resolve) { + CLEAR_PENDING_EXCEPTION; + } return empty; } } @@ -1185,7 +1195,8 @@ JVM_END // void resolve(MemberName self, Class caller) -JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { +JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh, + jboolean speculative_resolve)) { if (mname_jh == NULL) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); @@ -1213,7 +1224,8 @@ Klass* caller = caller_jh == NULL ? 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, speculative_resolve, + CHECK_NULL); if (resolved.is_null()) { int flags = java_lang_invoke_MemberName::flags(mname()); @@ -1221,6 +1233,10 @@ if (!MethodHandles::ref_kind_is_valid(ref_kind)) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "obsolete MemberName format"); } + if (speculative_resolve) { + assert(!HAS_PENDING_EXCEPTION, ""); + return NULL; + } if ((flags & ALL_KINDS) == IS_FIELD) { THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), "field resolution failed"); } else if ((flags & ALL_KINDS) == IS_METHOD || @@ -1512,7 +1528,7 @@ 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)}, + {CC "resolve", CC "(" MEM "" CLS "Z)" MEM, FN_PTR(MHN_resolve_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/hotspot/share/prims/methodHandles.hpp b/src/hotspot/share/prims/methodHandles.hpp --- a/src/hotspot/share/prims/methodHandles.hpp +++ b/src/hotspot/share/prims/methodHandles.hpp @@ -61,7 +61,8 @@ public: // working with member names - static Handle resolve_MemberName(Handle mname, Klass* caller, TRAPS); // compute vmtarget/vmindex from name/type + static Handle resolve_MemberName(Handle mname, Klass* caller, + bool speculative_resolve, TRAPS); // compute vmtarget/vmindex from name/type static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing static oop init_MemberName(Handle mname_h, Handle target_h, TRAPS); // compute vmtarget/vmindex from target static oop init_field_MemberName(Handle mname_h, fieldDescriptor& fd, bool is_setter = false); diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -1047,7 +1047,8 @@ * If lookup fails or access is not permitted, null is returned. * Otherwise a fresh copy of the given member is returned, with modifier bits filled in. */ - private MemberName resolve(byte refKind, MemberName ref, Class lookupClass) { + private MemberName resolve(byte refKind, MemberName ref, Class lookupClass, + boolean speculativeResolve) { MemberName m = ref.clone(); // JVM will side-effect the ref assert(refKind == m.getReferenceKind()); try { @@ -1066,7 +1067,10 @@ // // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't // participate in method selection. - m = MethodHandleNatives.resolve(m, lookupClass); + m = MethodHandleNatives.resolve(m, lookupClass, speculativeResolve); + if (m == null && speculativeResolve) { + return null; + } m.checkForTypeAlias(m.getDeclaringClass()); m.resolution = null; } catch (ClassNotFoundException | LinkageError ex) { @@ -1091,7 +1095,7 @@ MemberName resolveOrFail(byte refKind, MemberName m, Class lookupClass, Class nsmClass) throws IllegalAccessException, NoSuchMemberException { - MemberName result = resolve(refKind, m, lookupClass); + MemberName result = resolve(refKind, m, lookupClass, false); if (result.isResolved()) return result; ReflectiveOperationException ex = result.makeAccessException(); @@ -1106,8 +1110,8 @@ */ public MemberName resolveOrNull(byte refKind, MemberName m, Class lookupClass) { - MemberName result = resolve(refKind, m, lookupClass); - if (result.isResolved()) + MemberName result = resolve(refKind, m, lookupClass, true); + if (result != null && result.isResolved()) return result; return null; } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -49,7 +49,8 @@ static native void init(MemberName self, Object ref); static native void expand(MemberName self); - static native MemberName resolve(MemberName self, Class caller) throws LinkageError, ClassNotFoundException; + static native MemberName resolve(MemberName self, Class caller, + boolean speculativeResolve) throws LinkageError, ClassNotFoundException; static native int getMembers(Class defc, String matchName, String matchSig, int matchFlags, Class caller, int skip, MemberName[] results);