--- old/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java 2018-05-04 04:04:38.061753778 -0400 +++ new/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java 2018-05-04 04:04:36.413658718 -0400 @@ -84,19 +84,21 @@ switch (refKind) { case REF_invokeSpecial: { member = member.asSpecial(); - LambdaForm lform = preparedLambdaForm(member, callerClass); - Class checkClass = refc; // Class to use for receiver type check - if (callerClass != null) { - checkClass = callerClass; // potentially strengthen to caller class + // if caller is an interface we need to adapt to get the + // receiver check inserted + if (callerClass == null) { + throw new InternalError("callerClass must not be null for REF_invokeSpecial"); } - return new Special(mtype, lform, member, checkClass); + LambdaForm lform = preparedLambdaForm(member, callerClass.isInterface()); + return new Special(mtype, lform, member, callerClass); } case REF_invokeInterface: { - LambdaForm lform = preparedLambdaForm(member, callerClass); + // we always adapt 'special' when dealing with interfaces + LambdaForm lform = preparedLambdaForm(member, true); return new Interface(mtype, lform, member, refc); } default: { - LambdaForm lform = preparedLambdaForm(member, callerClass); + LambdaForm lform = preparedLambdaForm(member); return new DirectMethodHandle(mtype, lform, member); } } @@ -166,11 +168,15 @@ * Cache and share this structure among all methods with * the same basicType and refKind. */ - private static LambdaForm preparedLambdaForm(MemberName m, Class callerClass) { + private static LambdaForm preparedLambdaForm(MemberName m, boolean adaptToSpecialIfc) { assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead MethodType mtype = m.getInvocationType().basicType(); assert(!m.isMethodHandleInvoke()) : m; int which; + // MemberName.getReferenceKind may be different from the 'kind' passed to + // DMH.make. Specifically private/final methods that use a direct call + // have been adapted to REF_invokeSpecial, even though the actual + // invocation mode may be invokevirtual or invokeinterface. switch (m.getReferenceKind()) { case REF_invokeVirtual: which = LF_INVVIRTUAL; break; case REF_invokeStatic: which = LF_INVSTATIC; break; @@ -184,7 +190,7 @@ preparedLambdaForm(mtype, which); which = LF_INVSTATIC_INIT; } - if (which == LF_INVSPECIAL && callerClass != null && callerClass.isInterface()) { + if (which == LF_INVSPECIAL && adaptToSpecialIfc) { which = LF_INVSPECIAL_IFC; } LambdaForm lform = preparedLambdaForm(mtype, which); @@ -196,7 +202,7 @@ } private static LambdaForm preparedLambdaForm(MemberName m) { - return preparedLambdaForm(m, null); + return preparedLambdaForm(m, false); } private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {