8035776: Consistent Lambda construction
Reviewed-by: ahgross, briangoetz, dlsmith
This commit is contained in:
parent
15411a6579
commit
2e148fb065
jdk
src/share/classes/java/lang/invoke
test/java/lang/invoke/lambda
@ -200,6 +200,13 @@ import static sun.invoke.util.Wrapper.isWrapperType;
|
||||
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 @@ import static sun.invoke.util.Wrapper.isWrapperType;
|
||||
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 @@ import static sun.invoke.util.Wrapper.isWrapperType;
|
||||
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 @@ import static sun.invoke.util.Wrapper.isWrapperType;
|
||||
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
|
||||
|
@ -212,7 +212,7 @@ class TypeConvertingMethodAdapter extends MethodVisitor {
|
||||
* @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) {
|
||||
|
70
jdk/test/java/lang/invoke/lambda/LambdaReceiver.java
Normal file
70
jdk/test/java/lang/invoke/lambda/LambdaReceiver.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
71
jdk/test/java/lang/invoke/lambda/LambdaReceiverBridge.java
Normal file
71
jdk/test/java/lang/invoke/lambda/LambdaReceiverBridge.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
92
jdk/test/java/lang/invoke/lambda/LambdaReturn.java
Normal file
92
jdk/test/java/lang/invoke/lambda/LambdaReturn.java
Normal file
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
169
jdk/test/java/lang/invoke/lambda/MetafactoryArityTest.java
Normal file
169
jdk/test/java/lang/invoke/lambda/MetafactoryArityTest.java
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
167
jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java
Normal file
167
jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user