# HG changeset patch # User vlivanov # Date 1516921095 28800 # Thu Jan 25 14:58:15 2018 -0800 # Node ID 321108949ed5e1c5cc148a846fae7f0075159e0f # Parent 4162f740b7bd4764af88cbd92de5068972b10ca8 [mq]: 8196022 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 @@ -2784,7 +2784,11 @@ // 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)); + Handle resolved = MethodHandles::resolve_MemberName(mname, caller, CHECK_(empty)); + if (resolved.is_null()) { + // Resolution failure should already trigger an exception. + THROW_MSG_(vmSymbols::java_lang_InternalError(), "empty", 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 @@ -135,6 +135,10 @@ return flags; } +int MethodHandles::flags_to_ref_kind(int flags) { + return (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK; +} + Handle MethodHandles::resolve_MemberName_type(Handle mname, Klass* caller, TRAPS) { Handle empty; Handle type(THREAD, java_lang_invoke_MemberName::type(mname())); @@ -680,6 +684,35 @@ // which refers directly to JVM internals. Handle MethodHandles::resolve_MemberName(Handle mname, Klass* caller, TRAPS) { Handle empty; + Handle resolved = MethodHandles::resolve_MemberName_helper(mname, caller, THREAD); + if (HAS_PENDING_EXCEPTION) { + if (PENDING_EXCEPTION->is_a(SystemDictionary::ClassNotFoundException_klass())) { + // Convert CNFE to NCDFE and don't worry about it on JDK side. + Handle e(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + THROW_CAUSE_(vmSymbols::java_lang_NoClassDefFoundError(), e, empty); + } + return empty; + } + if (resolved.is_null()) { + int flags = java_lang_invoke_MemberName::flags(mname()); + int ref_kind = flags_to_ref_kind(flags); + if (!MethodHandles::ref_kind_is_valid(ref_kind)) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "obsolete MemberName format", empty); + } else if ((flags & ALL_KINDS) == IS_FIELD) { + THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), "field resolution failed", empty); + } else if ((flags & ALL_KINDS) == IS_METHOD || + (flags & ALL_KINDS) == IS_CONSTRUCTOR) { + THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), "method resolution failed", empty); + } else { + THROW_MSG_(vmSymbols::java_lang_LinkageError(), "resolution failed", empty); + } + } + return resolved; +} + +Handle MethodHandles::resolve_MemberName_helper(Handle mname, Klass* caller, TRAPS) { + Handle empty; assert(java_lang_invoke_MemberName::is_instance(mname()), ""); if (java_lang_invoke_MemberName::vmtarget(mname()) != NULL) { @@ -693,7 +726,7 @@ Handle name_str(THREAD, java_lang_invoke_MemberName::name( mname())); Handle type_str(THREAD, java_lang_invoke_MemberName::type( mname())); int flags = java_lang_invoke_MemberName::flags(mname()); - int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK; + int ref_kind = flags_to_ref_kind(flags); if (!ref_kind_is_valid(ref_kind)) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "obsolete MemberName format", empty); } @@ -1212,23 +1245,10 @@ 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); - if (resolved.is_null()) { - int flags = java_lang_invoke_MemberName::flags(mname()); - int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK; - if (!MethodHandles::ref_kind_is_valid(ref_kind)) { - THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "obsolete MemberName format"); - } - if ((flags & ALL_KINDS) == IS_FIELD) { - THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), "field resolution failed"); - } else if ((flags & ALL_KINDS) == IS_METHOD || - (flags & ALL_KINDS) == IS_CONSTRUCTOR) { - THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), "method resolution failed"); - } else { - THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "resolution failed"); - } + // Resolution failure should already trigger an exception. + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "empty"); } - return JNIHandles::make_local(THREAD, resolved()); } JVM_END 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 @@ -59,6 +59,8 @@ static oop field_name_or_null(Symbol* s); static oop field_signature_type_or_null(Symbol* s); + static Handle resolve_MemberName_helper(Handle mname, Klass* caller, TRAPS); // compute vmtarget/vmindex from name/type + public: // working with member names static Handle resolve_MemberName(Handle mname, Klass* caller, TRAPS); // compute vmtarget/vmindex from name/type @@ -194,6 +196,7 @@ } static int ref_kind_to_flags(int ref_kind); + static int flags_to_ref_kind(int flags); #include CPU_HEADER(methodHandles) diff --git a/src/hotspot/share/utilities/exceptions.hpp b/src/hotspot/share/utilities/exceptions.hpp --- a/src/hotspot/share/utilities/exceptions.hpp +++ b/src/hotspot/share/utilities/exceptions.hpp @@ -266,6 +266,9 @@ #define THROW_MSG_(name, message, result) \ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message); return result; } +#define THROW_CAUSE_(name, cause, result) \ + { Exceptions::_throw_cause(THREAD_AND_LOCATION, name, cause); return result; } + #define THROW_MSG_LOADER_(name, message, loader, protection_domain, result) \ { Exceptions::_throw_msg(THREAD_AND_LOCATION, name, message, loader, protection_domain); return result; } 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 @@ -955,14 +955,18 @@ String message = message() + ": "+ toString(); ReflectiveOperationException ex; if (isResolved() || !(resolution instanceof NoSuchMethodError || - resolution instanceof NoSuchFieldError)) + resolution instanceof NoSuchFieldError || + resolution instanceof NoClassDefFoundError)) { ex = new IllegalAccessException(message); - else if (isConstructor()) + } else if (resolution instanceof NoClassDefFoundError) { + ex = new ClassNotFoundException(message); + } else if (isConstructor()) { ex = new NoSuchMethodException(message); - else if (isMethod()) + } else if (isMethod()) { ex = new NoSuchMethodException(message); - else + } else { ex = new NoSuchFieldException(message); + } if (resolution instanceof Throwable) ex.initCause((Throwable) resolution); return ex; @@ -1069,7 +1073,7 @@ m = MethodHandleNatives.resolve(m, lookupClass); m.checkForTypeAlias(m.getDeclaringClass()); m.resolution = null; - } catch (ClassNotFoundException | LinkageError ex) { + } catch (LinkageError ex) { // JVM reports that the "bytecode behavior" would get an error assert(!m.isResolved()); m.resolution = ex; 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,7 @@ 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) throws LinkageError; static native int getMembers(Class defc, String matchName, String matchSig, int matchFlags, Class caller, int skip, MemberName[] results); @@ -507,9 +507,11 @@ assert(refKindIsValid(refKind)); return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type); } catch (IllegalAccessException ex) { + // MemberName.makeAccessException() wraps most of LinkageErrors reported by Factory.resolve() in IAE + // when resolution fails. Try to recover original error and rethrow it. Throwable cause = ex.getCause(); - if (cause instanceof AbstractMethodError) { - throw (AbstractMethodError) cause; + if (cause instanceof LinkageError) { + throw (LinkageError) cause; } else { Error err = new IllegalAccessError(ex.getMessage()); throw initCauseFrom(err, ex); @@ -520,6 +522,9 @@ } catch (NoSuchFieldException ex) { Error err = new NoSuchFieldError(ex.getMessage()); throw initCauseFrom(err, ex); + } catch (ClassNotFoundException ex) { + Error err = new NoClassDefFoundError(ex.getMessage()); + throw initCauseFrom(err, ex); } catch (ReflectiveOperationException ex) { Error err = new IncompatibleClassChangeError(); throw initCauseFrom(err, ex);