8035776: Consistent Lambda construction
authorrfield
Tue, 04 Mar 2014 15:33:30 -0800
changeset 23049 c66d7e7bcded
parent 23048 cf8cda42cd52
child 23050 24d28d1eb7a9
8035776: Consistent Lambda construction Reviewed-by: ahgross, briangoetz, dlsmith
jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java
jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java
jdk/test/java/lang/invoke/lambda/LambdaReceiver.java
jdk/test/java/lang/invoke/lambda/LambdaReceiverBridge.java
jdk/test/java/lang/invoke/lambda/LambdaReceiver_anotherpkg/LambdaReceiver_A.java
jdk/test/java/lang/invoke/lambda/LambdaReturn.java
jdk/test/java/lang/invoke/lambda/MetafactoryArityTest.java
jdk/test/java/lang/invoke/lambda/MetafactoryParameterCastTest.java
jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java
--- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Tue Mar 04 13:27:55 2014 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Tue Mar 04 15:33:30 2014 -0800
@@ -200,6 +200,13 @@
                                   implIsInstanceMethod ? "instance" : "static", implInfo,
                                   instantiatedArity, samArity));
         }
+        for (MethodType bridgeMT : additionalBridges) {
+            if (bridgeMT.parameterCount() != samArity) {
+                throw new LambdaConversionException(
+                        String.format("Incorrect number of parameters for bridge signature %s; incompatible with %s",
+                                      bridgeMT, samMethodType));
+            }
+        }
 
         // If instance: first captured arg (receiver) must be subtype of class where impl method is defined
         final int capturedStart;
@@ -232,7 +239,7 @@
                throw new LambdaConversionException(
                        String.format("Invalid receiver type %s; not a subtype of implementation receiver type %s",
                                      receiverClass, implReceiverClass));
-             }
+            }
         } else {
             // no receiver
             capturedStart = 0;
@@ -274,11 +281,18 @@
                     String.format("Type mismatch for lambda return: %s is not convertible to %s",
                                   actualReturnType, expectedType));
         }
-        if (!isAdaptableToAsReturn(expectedType, samReturnType)) {
+        if (!isAdaptableToAsReturnStrict(expectedType, samReturnType)) {
             throw new LambdaConversionException(
                     String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
                                   expectedType, samReturnType));
         }
+        for (MethodType bridgeMT : additionalBridges) {
+            if (!isAdaptableToAsReturnStrict(expectedType, bridgeMT.returnType())) {
+                throw new LambdaConversionException(
+                        String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
+                                      expectedType, bridgeMT.returnType()));
+            }
+        }
      }
 
     /**
@@ -330,6 +344,10 @@
         return toType.equals(void.class)
                || !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false);
     }
+    private boolean isAdaptableToAsReturnStrict(Class<?> fromType, Class<?> toType) {
+        if (fromType.equals(void.class)) return toType.equals(void.class);
+        return isAdaptableTo(fromType, toType, true);
+    }
 
 
     /*********** Logging support -- for debugging only, uncomment as needed
--- a/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java	Tue Mar 04 13:27:55 2014 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java	Tue Mar 04 15:33:30 2014 -0800
@@ -212,7 +212,7 @@
      * @param functional
      */
     void convertType(Class<?> arg, Class<?> target, Class<?> functional) {
-        if (arg.equals(target)) {
+        if (arg.equals(target) && arg.equals(functional)) {
             return;
         }
         if (arg == Void.TYPE || target == Void.TYPE) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LambdaReceiver.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary Consistent Lambda construction
+ */
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.LambdaConversionException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.List;
+
+import LambdaReceiver_anotherpkg.LambdaReceiver_A;
+
+public class LambdaReceiver extends LambdaReceiver_A {
+
+    interface IA {
+        int m(LambdaReceiver_A x);
+    }
+
+    static MethodHandles.Lookup l;
+    static MethodHandle h;
+    private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
+    private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
+    private static void mf(List<String> errs, MethodType mts, MethodType mtf, boolean shouldWork) {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        l = MethodHandles.lookup();
+        h = l.findVirtual(LambdaReceiver_A.class, "f", mt(int.class));
+        MethodType X = mt(int.class, LambdaReceiver.class);
+        MethodType A = mt(int.class, LambdaReceiver_A.class);
+        MethodType mti = mt(IA.class);
+        CallSite cs = LambdaMetafactory.metafactory(l, "m", mti,A,h,X);
+        IA p = (IA)cs.dynamicInvoker().invoke();
+        LambdaReceiver_A lra = new LambdaReceiver_A();
+        try {
+            p.m(lra);
+        } catch (ClassCastException cce) {
+            return;
+        }
+        throw new AssertionError("CCE expected");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LambdaReceiverBridge.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary Consistent Lambda construction
+ */
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.LambdaConversionException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.List;
+
+import LambdaReceiver_anotherpkg.LambdaReceiver_A;
+
+public class LambdaReceiverBridge extends LambdaReceiver_A {
+
+    interface IA {
+        int m(LambdaReceiver_A x);
+    }
+
+    static MethodHandles.Lookup l;
+    static MethodHandle h;
+    private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
+    private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
+    private static void mf(List<String> errs, MethodType mts, MethodType mtf, boolean shouldWork) {
+    }
+
+    public static void main(String[] args) throws Throwable {
+        l = MethodHandles.lookup();
+        h = l.findVirtual(LambdaReceiver_A.class, "f", mt(int.class));
+        MethodType X = mt(int.class, LambdaReceiverBridge.class);
+        MethodType A = mt(int.class, LambdaReceiver_A.class);
+        MethodType mti = mt(IA.class);
+        CallSite cs = LambdaMetafactory.altMetafactory(l, "m", mti,X,h,X,
+                                          LambdaMetafactory.FLAG_BRIDGES, 1, A);
+        IA p = (IA)cs.dynamicInvoker().invoke();
+        LambdaReceiver_A lra = new LambdaReceiver_A();
+        try {
+            p.m(lra);
+        } catch (ClassCastException cce) {
+            return;
+        }
+        throw new AssertionError("CCE expected");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LambdaReceiver_anotherpkg/LambdaReceiver_A.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package LambdaReceiver_anotherpkg;
+
+public class LambdaReceiver_A {
+  protected final int f() { return 2; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LambdaReturn.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary Consistent Lambda construction
+ */
+
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.LambdaConversionException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.List;
+
+public class LambdaReturn {
+
+    interface I {
+        void m();
+    }
+
+    static void hereV() {}
+    static String hereS() { return "hi"; }
+    static MethodHandles.Lookup l;
+    private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
+    private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
+    private static void amf(List<String> errs, MethodHandle h, MethodType mts, MethodType mtf, MethodType mtb, boolean shouldWork) {
+        MethodType mti = mt(I.class);
+        try {
+            LambdaMetafactory.altMetafactory(l, "m", mti, mts,h,mtf,
+                                          LambdaMetafactory.FLAG_BRIDGES, 1, mtb);
+        } catch(LambdaConversionException e) {
+            if (shouldWork)  errs.add("Error: Should work h=" + h + " s=" + mts + " -- f=" + mtf + " / b=" + mtb + " got: " + e);
+            return;
+        }
+        if (!shouldWork)  errs.add("Error: Should fail h=" + h + " s=" + mts + " -- f=" + mtf + " / b=" + mtb);
+    }
+
+    public static void main(String[] args) throws Throwable {
+        l = MethodHandles.lookup();
+        MethodHandle hV = l.findStatic(LambdaReturn.class, "hereV", mt(void.class));
+        MethodHandle hS = l.findStatic(LambdaReturn.class, "hereS", mt(String.class));
+        List<String> errs = new ArrayList<>();
+        MethodType V = mt(void.class);
+        MethodType S = mt(String.class);
+        MethodType O = mt(Object.class);
+        MethodType I = mt(int.class);
+        amf(errs, hS, S, S, O, true);
+        amf(errs, hS, S, S, V, false);
+        amf(errs, hS, S, S, I, false);
+        amf(errs, hS, O, S, S, true);
+        amf(errs, hS, V, S, S, false);
+        amf(errs, hS, I, S, S, false);
+        amf(errs, hS, O, O, S, false);
+        amf(errs, hS, S, O, O, false);
+        amf(errs, hV, V, V, O, false);
+        amf(errs, hV, V, V, I, false);
+        amf(errs, hV, V, V, S, false);
+        amf(errs, hV, O, V, V, false);
+        amf(errs, hV, I, V, V, false);
+        amf(errs, hV, S, V, V, false);
+
+        if (errs.size() > 0) {
+            for (String err : errs) {
+                System.err.println(err);
+            }
+            throw new AssertionError("Errors: " + errs.size());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/MetafactoryArityTest.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary metafactory should fail if arities are mismatched
+ */
+import java.lang.invoke.*;
+import java.util.Arrays;
+import static java.lang.invoke.MethodType.methodType;
+
+public class MetafactoryArityTest {
+
+    public interface I {}
+    public static class C { public static String m(int arg) { return ""; } }
+
+    static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+    static final Class<?>[] capInt = { int.class };
+    static final MethodHandle C_m;
+    static {
+        try { C_m = lookup.findStatic(C.class, "m", methodType(String.class, int.class)); }
+        catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(e); }
+    }
+
+    public static void main(String... args) {
+        MethodType unary = methodType(String.class, int.class);
+        MethodType nullary = methodType(String.class);
+        MethodType binary = methodType(String.class, int.class, int.class);
+        MethodType unaryCS = methodType(CharSequence.class, int.class);
+        MethodType nullaryCS = methodType(CharSequence.class);
+        MethodType binaryCS = methodType(CharSequence.class, int.class, int.class);
+        MethodType unaryObj = methodType(Object.class, int.class);
+        MethodType nullaryObj = methodType(Object.class);
+        MethodType binaryObj = methodType(Object.class, int.class, int.class);
+
+        test(true, C_m, unary, unary);
+        test(false, C_m, unary, nullary);
+        test(false, C_m, nullary, unary);
+        test(false, C_m, unary, binary);
+        test(false, C_m, binary, unary);
+
+        testBridge(true, C_m, unary, unary, unaryCS);
+        testBridge(false, C_m, unary, unary, nullaryCS);
+        testBridge(false, C_m, unary, unary, binaryCS);
+
+        testBridge(true, C_m, unary, unary, unaryCS, unaryObj);
+        testBridge(false, C_m, unary, unary, unaryCS, nullaryObj);
+        testBridge(false, C_m, unary, unary, unaryCS, binaryObj);
+
+        testCapture(true, C_m, capInt, nullary, nullary);
+        testCapture(false, C_m, capInt, binary, binary);
+        testCapture(false, C_m, capInt, nullary, unary);
+        testCapture(false, C_m, capInt, nullary, binary);
+        testCapture(false, C_m, capInt, unary, nullary);
+        testCapture(false, C_m, capInt, unary, binary);
+
+        testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS);
+        testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS);
+        testCaptureBridge(false, C_m, capInt, nullary, nullary, unaryCS);
+        testCaptureBridge(false, C_m, capInt, nullary, nullary, binaryCS);
+
+        testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS, nullaryObj);
+        testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS, unaryObj);
+        testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, unaryObj);
+        testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, binaryObj);
+    }
+
+    static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
+        tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
+        tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
+    }
+
+    static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
+        tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs);
+    }
+
+    static void testCapture(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT) {
+        tryMetafactory(correct, mh, captured, instMT, samMT);
+        tryAltMetafactory(correct, mh, captured, instMT, samMT);
+    }
+
+    static void testCaptureBridge(boolean correct, MethodHandle mh, Class<?>[] captured,
+                                  MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
+        tryAltMetafactory(correct, mh, captured, instMT, samMT, bridgeMTs);
+    }
+
+    static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
+                               MethodType instMT, MethodType samMT) {
+        try {
+            LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured),
+                                          samMT, mh, instMT);
+            if (!correct) {
+                throw new AssertionError("Uncaught linkage error:" +
+                                         " impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT);
+            }
+        }
+        catch (LambdaConversionException e) {
+            if (correct) {
+                throw new AssertionError("Unexpected linkage error:" +
+                                         " e=" + e +
+                                         ", impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT);
+            }
+        }
+    }
+
+    static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
+                                  MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
+        boolean bridge = bridgeMTs.length > 0;
+        Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
+        args[0] = samMT;
+        args[1] = mh;
+        args[2] = instMT;
+        args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
+        if (bridge) {
+            args[4] = bridgeMTs.length;
+            for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
+        }
+        try {
+            LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args);
+            if (!correct) {
+                throw new AssertionError("Uncaught linkage error:" +
+                                         " impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT +
+                                         ", bridges=" + Arrays.toString(bridgeMTs));
+            }
+        }
+        catch (LambdaConversionException e) {
+            if (correct) {
+                throw new AssertionError("Unexpected linkage error:" +
+                                         " e=" + e +
+                                         ", impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT +
+                                         ", bridges=" + Arrays.toString(bridgeMTs));
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/MetafactoryParameterCastTest.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary Ensure that invocation parameters are always cast to the instantiatedMethodType
+ */
+import java.lang.invoke.*;
+import java.util.Arrays;
+import static java.lang.invoke.MethodType.methodType;
+
+public class MetafactoryParameterCastTest {
+
+    static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+    public static class A {
+    }
+
+    public static class B extends A {
+        void instance0() {}
+        void instance1(B arg) {}
+        static void static1(B arg) {}
+        static void static2(B arg1, B arg2) {}
+    }
+
+    public static class C extends B {}
+    public static class NotC extends B {}
+
+    public interface ASink { void take(A arg); }
+    public interface BSink { void take(B arg); }
+
+    public static void main(String... args) throws Throwable {
+        new MetafactoryParameterCastTest().test();
+    }
+
+    void test() throws Throwable {
+        MethodType takeA = methodType(void.class, A.class);
+        MethodType takeB = methodType(void.class, B.class);
+        MethodType takeC = methodType(void.class, C.class);
+
+        Class<?>[] noCapture = {};
+        Class<?>[] captureB = { B.class };
+
+        MethodHandle[] oneBParam = { lookup.findVirtual(B.class, "instance0", methodType(void.class)),
+                                     lookup.findStatic(B.class, "static1", methodType(void.class, B.class)) };
+        MethodHandle[] twoBParams = { lookup.findVirtual(B.class, "instance1", methodType(void.class, B.class)),
+                                      lookup.findStatic(B.class, "static2", methodType(void.class, B.class, B.class)) };
+
+        for (MethodHandle mh : oneBParam) {
+            // sam
+            tryASink(invokeMetafactory(mh, ASink.class, "take", noCapture, takeC, takeA));
+            tryBSink(invokeMetafactory(mh, BSink.class, "take", noCapture, takeC, takeB));
+            tryASink(invokeAltMetafactory(mh, ASink.class, "take", noCapture, takeC, takeA));
+            tryBSink(invokeAltMetafactory(mh, BSink.class, "take", noCapture, takeC, takeB));
+
+            // bridge
+            tryASink(invokeAltMetafactory(mh, ASink.class, "take", noCapture, takeC, takeC, takeA));
+            tryBSink(invokeAltMetafactory(mh, BSink.class, "take", noCapture, takeC, takeC, takeB));
+        }
+
+        for (MethodHandle mh : twoBParams) {
+            // sam
+            tryCapASink(invokeMetafactory(mh, ASink.class, "take", captureB, takeC, takeA));
+            tryCapBSink(invokeMetafactory(mh, BSink.class, "take", captureB, takeC, takeB));
+            tryCapASink(invokeAltMetafactory(mh, ASink.class, "take", captureB, takeC, takeA));
+            tryCapBSink(invokeAltMetafactory(mh, BSink.class, "take", captureB, takeC, takeB));
+
+            // bridge
+            tryCapASink(invokeAltMetafactory(mh, ASink.class, "take", captureB, takeC, takeC, takeA));
+            tryCapBSink(invokeAltMetafactory(mh, BSink.class, "take", captureB, takeC, takeC, takeB));
+        }
+    }
+
+    void tryASink(CallSite cs) throws Throwable {
+        ASink sink = (ASink) cs.dynamicInvoker().invoke();
+        tryASink(sink);
+    }
+
+    void tryCapASink(CallSite cs) throws Throwable {
+        ASink sink = (ASink) cs.dynamicInvoker().invoke(new B());
+        tryASink(sink);
+    }
+
+    void tryBSink(CallSite cs) throws Throwable {
+        BSink sink = (BSink) cs.dynamicInvoker().invoke();
+        tryBSink(sink);
+    }
+
+    void tryCapBSink(CallSite cs) throws Throwable {
+        BSink sink = (BSink) cs.dynamicInvoker().invoke(new B());
+        tryBSink(sink);
+    }
+
+    void tryASink(ASink sink) {
+        try { sink.take(new C()); }
+        catch (ClassCastException e) {
+            throw new AssertionError("Unexpected cast failure: " + e + " " + lastMFParams());
+        }
+
+        try {
+            sink.take(new B());
+            throw new AssertionError("Missing cast from A to C: " + lastMFParams());
+        }
+        catch (ClassCastException e) { /* expected */ }
+
+        try {
+            sink.take(new NotC());
+            throw new AssertionError("Missing cast from A to C: " + lastMFParams());
+        }
+        catch (ClassCastException e) { /* expected */ }
+    }
+
+    void tryBSink(BSink sink) {
+        try { sink.take(new C()); }
+        catch (ClassCastException e) {
+            throw new AssertionError("Unexpected cast failure: " + e + " " + lastMFParams());
+        }
+
+        try {
+            sink.take(new B());
+            throw new AssertionError("Missing cast from B to C: " + lastMFParams());
+        }
+        catch (ClassCastException e) { /* expected */ }
+
+        try {
+            sink.take(new NotC());
+            throw new AssertionError("Missing cast from B to C: " + lastMFParams());
+        }
+        catch (ClassCastException e) { /* expected */ }
+    }
+
+    MethodHandle lastMH;
+    Class<?>[] lastCaptured;
+    MethodType lastInstMT;
+    MethodType lastSamMT;
+    MethodType[] lastBridgeMTs;
+
+    String lastMFParams() {
+        return "mh=" + lastMH +
+               ", captured=" + Arrays.toString(lastCaptured) +
+               ", instMT=" + lastInstMT +
+               ", samMT=" + lastSamMT +
+               ", bridgeMTs=" + Arrays.toString(lastBridgeMTs);
+    }
+
+    CallSite invokeMetafactory(MethodHandle mh, Class<?> sam, String methodName,
+                               Class<?>[] captured, MethodType instMT, MethodType samMT) {
+        lastMH = mh;
+        lastCaptured = captured;
+        lastInstMT = instMT;
+        lastSamMT = samMT;
+        lastBridgeMTs = new MethodType[]{};
+        try {
+            return LambdaMetafactory.metafactory(lookup, methodName, methodType(sam, captured),
+                                                 samMT, mh, instMT);
+        }
+        catch (LambdaConversionException e) {
+            // unexpected linkage error
+            throw new RuntimeException(e);
+        }
+    }
+
+    CallSite invokeAltMetafactory(MethodHandle mh, Class<?> sam, String methodName,
+                                  Class<?>[] captured, MethodType instMT,
+                                  MethodType samMT, MethodType... bridgeMTs) {
+        lastMH = mh;
+        lastCaptured = captured;
+        lastInstMT = instMT;
+        lastSamMT = samMT;
+        lastBridgeMTs = bridgeMTs;
+        try {
+            boolean bridge = bridgeMTs.length > 0;
+            Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
+            args[0] = samMT;
+            args[1] = mh;
+            args[2] = instMT;
+            args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
+            if (bridge) {
+                args[4] = bridgeMTs.length;
+                for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
+            }
+            return LambdaMetafactory.altMetafactory(lookup, methodName, methodType(sam, captured), args);
+        }
+        catch (LambdaConversionException e) {
+            // unexpected linkage error
+            throw new RuntimeException(e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java	Tue Mar 04 15:33:30 2014 -0800
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8035776
+ * @summary metafactory should fail if impl return does not match sam/bridge returns
+ */
+import java.lang.invoke.*;
+import java.util.Arrays;
+import static java.lang.invoke.MethodType.methodType;
+
+public class MetafactorySamReturnTest {
+
+    static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+    public interface I {}
+
+    public static class C {
+        public static void m_void(String arg) {}
+        public static boolean m_boolean(String arg) { return true; }
+        public static char m_char(String arg) { return 'x'; }
+        public static byte m_byte(String arg) { return 12; }
+        public static short m_short(String arg) { return 12; }
+        public static int m_int(String arg) { return 12; }
+        public static long m_long(String arg) { return 12; }
+        public static float m_float(String arg) { return 12; }
+        public static double m_double(String arg) { return 12; }
+        public static String m_String(String arg) { return ""; }
+        public static Integer m_Integer(String arg) { return 23; }
+        public static Object m_Object(String arg) { return new Object(); }
+
+        public static MethodHandle getMH(Class<?> c) {
+            try {
+                return lookup.findStatic(C.class, "m_" + c.getSimpleName(), methodType(c, String.class));
+            }
+            catch (NoSuchMethodException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static void main(String... args) {
+        Class<?>[] t = { void.class, boolean.class, char.class,
+                         byte.class, short.class, int.class, long.class, float.class, double.class,
+                         String.class, Integer.class, Object.class };
+
+        for (int i = 0; i < t.length; i++) {
+            MethodHandle mh = C.getMH(t[i]);
+            for (int j = 0; j < t.length; j++) {
+                // TEMPORARY EXCEPTIONS
+                if (t[j] == void.class) continue;
+                if (t[i].isPrimitive() && t[j] == Object.class) continue;
+                if (t[i] == char.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
+                if (t[i] == byte.class && (t[j] == short.class || t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
+                if (t[i] == short.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
+                if (t[i] == int.class && (t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
+                if (t[i] == long.class && (t[j] == float.class || t[j] == double.class)) continue;
+                if (t[i] == float.class && t[j] == double.class) continue;
+                if (t[i] == int.class && t[j] == Integer.class) continue;
+                if (t[i] == Integer.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue;
+                // END TEMPORARY EXCEPTIONS
+                boolean correct = (t[i].isPrimitive() || t[j].isPrimitive())
+                                  ? t[i] == t[j]
+                                  : t[j].isAssignableFrom(t[i]);
+                MethodType mti = methodType(t[i], String.class);
+                MethodType mtiCS = methodType(t[i], CharSequence.class);
+                MethodType mtj = methodType(t[j], String.class);
+                MethodType mtjObj = methodType(t[j], Object.class);
+                test(correct, mh, mti, mtj);
+                testBridge(correct, mh, mti, mti, mtjObj);
+                testBridge(correct, mh, mti, mti, mtiCS, mtjObj);
+            }
+        }
+    }
+
+    static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
+        tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
+        tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
+    }
+
+    static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
+        tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs);
+    }
+
+    static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
+                               MethodType instMT, MethodType samMT) {
+        try {
+            LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured),
+                                          samMT, mh, instMT);
+            if (!correct) {
+                throw new AssertionError("Uncaught linkage error:" +
+                                         " impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT);
+            }
+        }
+        catch (LambdaConversionException e) {
+            if (correct) {
+                throw new AssertionError("Unexpected linkage error:" +
+                                         " e=" + e +
+                                         ", impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT);
+            }
+        }
+    }
+
+    static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
+                                  MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
+        boolean bridge = bridgeMTs.length > 0;
+        Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
+        args[0] = samMT;
+        args[1] = mh;
+        args[2] = instMT;
+        args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
+        if (bridge) {
+            args[4] = bridgeMTs.length;
+            for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
+        }
+        try {
+            LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args);
+            if (!correct) {
+                throw new AssertionError("Uncaught linkage error:" +
+                                         " impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT +
+                                         ", bridges=" + Arrays.toString(bridgeMTs));
+            }
+        }
+        catch (LambdaConversionException e) {
+            if (correct) {
+                throw new AssertionError("Unexpected linkage error:" +
+                                         " e=" + e +
+                                         ", impl=" + mh +
+                                         ", captured=" + Arrays.toString(captured) +
+                                         ", inst=" + instMT +
+                                         ", sam=" + samMT +
+                                         ", bridges=" + Arrays.toString(bridgeMTs));
+            }
+        }
+    }
+
+}