Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8028739

javac generates incorrect descriptor for MethodHandle::invoke

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 8
    • 8
    • tools
    • b119
    • Verified

      Invocations of signature polymorphic methods (MethodHandle.invoke, MethodHandle.invokeExact) derive the bytecode descriptor of the method call from the call site rather than the method's declared signature ("([Ljava/lang/Object;)Ljava/lang/Object;"). See JLS 15.12.3.

      A method handle like MethodHandle::invoke or mh::invoke should do the same. But currently, the descriptor generated by javac always seems to be "([Ljava/lang/Object;)Ljava/lang/Object;".

      Test case:

      ---
      import java.lang.invoke.*;

      public class MHInvoke {

        interface TriFunction {
            Object apply(String a, char b, char c) throws Throwable;
        }

        public static void main(String... args) throws Throwable {
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            MethodType mt = MethodType.methodType(String.class, char.class, char.class);
            MethodHandle ms = lookup.findVirtual(String.class, "replace", mt);

            System.out.println("result 1: " + ms.invoke("some string to search", 's', 'o'));
            
            TriFunction f1 = (a, b, c) -> ms.invoke(a,b,c);
            System.out.println("result 2: " + f1.apply("some string to search", 's', 'o'));
            
            TriFunction f2 = ms::invoke;
            System.out.println("result 3: " + f2.apply("some string to search", 's', 'o'));
        }
      }

      ---

      Expected: Run successfully
      Actual: BootstrapMethodError

      ---

      Looking at the bytecode, here's the 'invoke' call from the lambda body:

               4: invokevirtual #15 // Method java/lang/invoke/MethodHandle.invoke:(Ljava/lang/String;CC)Ljava/lang/Object;

      And here's the 'invoke' call for the method reference (passed as an argument to 'metafactory' in the form of a MethodHandle):

              #74 invokevirtual java/lang/invoke/MethodHandle.invoke:([Ljava/lang/Object;)Ljava/lang/Object;

      This should look like the following instead:

              #74 invokevirtual java/lang/invoke/MethodHandle.invoke:(Ljava/lang/String;CC)Ljava/lang/Object;

            rfield Robert Field (Inactive)
            dlsmith Dan Smith
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: