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

Lambda metafactory: incorrect type conversion of constructor method handle

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 8
    • None
    • core-libs
    • b98
    • generic
    • generic
    • Verified

      a minimal test case to reproduce the issue is this:

      interface IntFunction<X> {
          int m(X x);
      }

      class Test {
          public static void main(String[] args) {
             IntFunction<String> s = Integer::new;
          }
      }


      Looking at the javap output, in particular at the indy call details, we
      find this:

      BootstrapMethods:
           0: #15 invokestatic
      java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
             Method arguments:
               #16 invokeinterface IntFunction.m:(Ljava/lang/Object;)I
               #17 newinvokespecial
      java/lang/Integer."<init>":(Ljava/lang/String;)V
               #18 (Ljava/lang/String;)I


      This seems correct; however, judging from the runtime error, it seems
      like the metafactory is not unboxing the Integer instance back to int
      (which is the expected return value of the implemented method). Hence
      the 292 link failure.

      ----

      A REF_newInvokeSpecial method handle constant refers to a void-returning method named <init>, but its bytecode behavior returns a reference to the constructed object.

      This may require special checks, such as with 'actualReturnType' in AbstractValidatingLambdaMetafactory.java.

      There is a missing check in InnerClassLambdaMetafactory.java. Here is a suggested fix (which I have not tested).

      — John

      diff --git a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
      --- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
      +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
      @@ -112,7 +112,10 @@
               implMethodDesc = implMethodType.toMethodDescriptorString();
               Type implMethodAsmType = Type.getMethodType(implMethodDesc);
               implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
      - implMethodReturnType = implMethodAsmType.getReturnType();
      + if (implKind == MethodHandleInfo.REF_newInvokeSpecial)
      + implMethodReturnType = Type.getType(implMethodClassName);
      + else
      + implMethodReturnType = implMethodAsmType.getReturnType();
               constructorType = invokedType.changeReturnType(Void.TYPE);
               constructorDesc = constructorType.toMethodDescriptorString();
               lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();

      ----

      I tried playing around with that fix. It pushes the error further along to somewhere else.

      I don't know the exact terms here... but:

        implMethodReturnType = Type.getType(implMethodClassName)

      creates a type whose description is "java/lang/Integer" rather than "Ljava/lang/Integer" i.e. the input is not a type descriptor is just a class name with '.' replaced with '/'. (Perhaps that could be a bug in ASM not throwing an exception on an illegal description?)

      If i do the following then it works:

              if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
                  implMethodReturnType = Type.getObjectType(implMethodClassName);
              } else {
                  implMethodReturnType = implMethodAsmType.getReturnType();
              }

      Plus it does not cause additional failures in the lambda lang/invoke tests (same number of tests fail before and after the fix, but i dunno if they are exactly the same tests that fail ).

            rfield Robert Field (Inactive)
            rfield Robert Field (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: