1 /* |
|
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * @test |
|
26 * @bug 8035776 |
|
27 * @summary metafactory should fail if impl return does not match sam/bridge returns |
|
28 */ |
|
29 import java.lang.invoke.*; |
|
30 import java.util.Arrays; |
|
31 import static java.lang.invoke.MethodType.methodType; |
|
32 |
|
33 public class MetafactorySamReturnTest { |
|
34 |
|
35 static final MethodHandles.Lookup lookup = MethodHandles.lookup(); |
|
36 |
|
37 public interface I {} |
|
38 |
|
39 public static class C { |
|
40 public static void m_void(String arg) {} |
|
41 public static boolean m_boolean(String arg) { return true; } |
|
42 public static char m_char(String arg) { return 'x'; } |
|
43 public static byte m_byte(String arg) { return 12; } |
|
44 public static short m_short(String arg) { return 12; } |
|
45 public static int m_int(String arg) { return 12; } |
|
46 public static long m_long(String arg) { return 12; } |
|
47 public static float m_float(String arg) { return 12; } |
|
48 public static double m_double(String arg) { return 12; } |
|
49 public static String m_String(String arg) { return ""; } |
|
50 public static Integer m_Integer(String arg) { return 23; } |
|
51 public static Object m_Object(String arg) { return new Object(); } |
|
52 |
|
53 public static MethodHandle getMH(Class<?> c) { |
|
54 try { |
|
55 return lookup.findStatic(C.class, "m_" + c.getSimpleName(), methodType(c, String.class)); |
|
56 } |
|
57 catch (NoSuchMethodException | IllegalAccessException e) { |
|
58 throw new RuntimeException(e); |
|
59 } |
|
60 } |
|
61 } |
|
62 |
|
63 public static void main(String... args) { |
|
64 Class<?>[] t = { void.class, boolean.class, char.class, |
|
65 byte.class, short.class, int.class, long.class, float.class, double.class, |
|
66 String.class, Integer.class, Object.class }; |
|
67 |
|
68 for (int i = 0; i < t.length; i++) { |
|
69 MethodHandle mh = C.getMH(t[i]); |
|
70 for (int j = 0; j < t.length; j++) { |
|
71 // TEMPORARY EXCEPTIONS |
|
72 if (t[j] == void.class) continue; |
|
73 if (t[i].isPrimitive() && t[j] == Object.class) continue; |
|
74 if (t[i] == char.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; |
|
75 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; |
|
76 if (t[i] == short.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; |
|
77 if (t[i] == int.class && (t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; |
|
78 if (t[i] == long.class && (t[j] == float.class || t[j] == double.class)) continue; |
|
79 if (t[i] == float.class && t[j] == double.class) continue; |
|
80 if (t[i] == int.class && t[j] == Integer.class) continue; |
|
81 if (t[i] == Integer.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; |
|
82 // END TEMPORARY EXCEPTIONS |
|
83 boolean correct = (t[i].isPrimitive() || t[j].isPrimitive()) |
|
84 ? t[i] == t[j] |
|
85 : t[j].isAssignableFrom(t[i]); |
|
86 MethodType mti = methodType(t[i], String.class); |
|
87 MethodType mtiCS = methodType(t[i], CharSequence.class); |
|
88 MethodType mtj = methodType(t[j], String.class); |
|
89 MethodType mtjObj = methodType(t[j], Object.class); |
|
90 test(correct, mh, mti, mtj); |
|
91 testBridge(correct, mh, mti, mti, mtjObj); |
|
92 testBridge(correct, mh, mti, mti, mtiCS, mtjObj); |
|
93 } |
|
94 } |
|
95 } |
|
96 |
|
97 static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) { |
|
98 tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT); |
|
99 tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT); |
|
100 } |
|
101 |
|
102 static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) { |
|
103 tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs); |
|
104 } |
|
105 |
|
106 static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, |
|
107 MethodType instMT, MethodType samMT) { |
|
108 try { |
|
109 LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured), |
|
110 samMT, mh, instMT); |
|
111 if (!correct) { |
|
112 throw new AssertionError("Uncaught linkage error:" + |
|
113 " impl=" + mh + |
|
114 ", captured=" + Arrays.toString(captured) + |
|
115 ", inst=" + instMT + |
|
116 ", sam=" + samMT); |
|
117 } |
|
118 } |
|
119 catch (LambdaConversionException e) { |
|
120 if (correct) { |
|
121 throw new AssertionError("Unexpected linkage error:" + |
|
122 " e=" + e + |
|
123 ", impl=" + mh + |
|
124 ", captured=" + Arrays.toString(captured) + |
|
125 ", inst=" + instMT + |
|
126 ", sam=" + samMT); |
|
127 } |
|
128 } |
|
129 } |
|
130 |
|
131 static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured, |
|
132 MethodType instMT, MethodType samMT, MethodType... bridgeMTs) { |
|
133 boolean bridge = bridgeMTs.length > 0; |
|
134 Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4]; |
|
135 args[0] = samMT; |
|
136 args[1] = mh; |
|
137 args[2] = instMT; |
|
138 args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0; |
|
139 if (bridge) { |
|
140 args[4] = bridgeMTs.length; |
|
141 for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i]; |
|
142 } |
|
143 try { |
|
144 LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args); |
|
145 if (!correct) { |
|
146 throw new AssertionError("Uncaught linkage error:" + |
|
147 " impl=" + mh + |
|
148 ", captured=" + Arrays.toString(captured) + |
|
149 ", inst=" + instMT + |
|
150 ", sam=" + samMT + |
|
151 ", bridges=" + Arrays.toString(bridgeMTs)); |
|
152 } |
|
153 } |
|
154 catch (LambdaConversionException e) { |
|
155 if (correct) { |
|
156 throw new AssertionError("Unexpected linkage error:" + |
|
157 " e=" + e + |
|
158 ", impl=" + mh + |
|
159 ", captured=" + Arrays.toString(captured) + |
|
160 ", inst=" + instMT + |
|
161 ", sam=" + samMT + |
|
162 ", bridges=" + Arrays.toString(bridgeMTs)); |
|
163 } |
|
164 } |
|
165 } |
|
166 |
|
167 } |
|