< prev index next >

src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java

Print this page

        

@@ -56,10 +56,11 @@
     private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
         super(mtype, form);
         if (!member.isResolved())  throw new InternalError();
 
         if (member.getDeclaringClass().isInterface() &&
+            member.getReferenceKind() == REF_invokeInterface &&
                 member.isMethod() && !member.isAbstract()) {
             // Check for corner case: invokeinterface of Object method
             MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
             m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
             if (m != null && m.isPublic()) {

@@ -78,26 +79,32 @@
             if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor())
                 throw new InternalError(member.toString());
             mtype = mtype.insertParameterTypes(0, refc);
         }
         if (!member.isField()) {
+            // refKind reflects the original type of lookup via findSpecial or
+            // findVirtual etc.
             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);
+                    // for interfaces we always need the receiver typecheck,
+                    // so we always pass 'true' to ensure we adapt if needed
+                    // to include the REF_invokeSpecial case
+                    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);
                 }
             }
         } else {
             LambdaForm lform = preparedFieldLambdaForm(member);

@@ -163,15 +170,20 @@
     /**
      * Create a LF which can invoke the given method.
      * 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 represents the JVM optimized form of the call
+        // as distinct from the "kind" passed to DMH.make which represents the original
+        // bytecode-equivalent request. Specifically private/final methods that use a direct
+        // call have getReferenceKind 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;
         case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
         case REF_invokeInterface:  which = LF_INVINTERFACE;  break;

@@ -181,11 +193,11 @@
         if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
             // precompute the barrier-free version:
             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);
         maybeCompile(lform, m);
         assert(lform.methodType().dropParameterTypes(0, 1)

@@ -193,11 +205,11 @@
                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
         return lform;
     }
 
     private static LambdaForm preparedLambdaForm(MemberName m) {
-        return preparedLambdaForm(m, null);
+        return preparedLambdaForm(m, false);
     }
 
     private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
         LambdaForm lform = mtype.form().cachedLambdaForm(which);
         if (lform != null)  return lform;
< prev index next >