1 /*
2  * Copyright (c) 2017, 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 8173587
27  * @summary metafactory should fail if instantiatedMethodType does not match sam/bridge descriptors
28  */
29 import java.lang.invoke.*;
30 import java.util.*;
31 
32 public class MetafactoryDescriptorTest {
33 
34     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
35 
mt(Class<?> ret, Class<?>... params)36     static MethodType mt(Class<?> ret, Class<?>... params) {
37         return MethodType.methodType(ret, params);
38     }
39 
40     public interface I {}
41 
42     public static class C {
m_void(String arg)43         public static void m_void(String arg) {}
m_boolean(String arg)44         public static boolean m_boolean(String arg) { return true; }
m_char(String arg)45         public static char m_char(String arg) { return 'x'; }
m_byte(String arg)46         public static byte m_byte(String arg) { return 12; }
m_short(String arg)47         public static short m_short(String arg) { return 12; }
m_int(String arg)48         public static int m_int(String arg) { return 12; }
m_long(String arg)49         public static long m_long(String arg) { return 12; }
m_float(String arg)50         public static float m_float(String arg) { return 12; }
m_double(String arg)51         public static double m_double(String arg) { return 12; }
m_String(String arg)52         public static String m_String(String arg) { return ""; }
m_Integer(String arg)53         public static Integer m_Integer(String arg) { return 23; }
m_Object(String arg)54         public static Object m_Object(String arg) { return new Object(); }
55 
n_boolean(boolean arg)56         public static String n_boolean(boolean arg) { return ""; }
n_char(char arg)57         public static String n_char(char arg) { return ""; }
n_byte(byte arg)58         public static String n_byte(byte arg) { return ""; }
n_short(short arg)59         public static String n_short(short arg) { return ""; }
n_int(int arg)60         public static String n_int(int arg) { return ""; }
n_long(long arg)61         public static String n_long(long arg) { return ""; }
n_float(float arg)62         public static String n_float(float arg) { return ""; }
n_double(double arg)63         public static String n_double(double arg) { return ""; }
n_String(String arg)64         public static String n_String(String arg) { return ""; }
n_Integer(Integer arg)65         public static String n_Integer(Integer arg) { return ""; }
n_Object(Object arg)66         public static String n_Object(Object arg) { return ""; }
67 
getM(Class<?> c)68         public static MethodHandle getM(Class<?> c) {
69             try {
70                 return lookup.findStatic(C.class, "m_" + c.getSimpleName(), mt(c, String.class));
71             }
72             catch (NoSuchMethodException | IllegalAccessException e) {
73                 throw new RuntimeException(e);
74             }
75         }
76 
getN(Class<?> c)77         public static MethodHandle getN(Class<?> c) {
78             if (c == void.class) return null;
79             try {
80                 return lookup.findStatic(C.class, "n_" + c.getSimpleName(), mt(String.class, c));
81             }
82             catch (NoSuchMethodException | IllegalAccessException e) {
83                 throw new RuntimeException(e);
84             }
85         }
86 
87     }
88 
main(String... args)89     public static void main(String... args) {
90         Class<?>[] t = { void.class, boolean.class, char.class,
91                          byte.class, short.class, int.class, long.class, float.class, double.class,
92                          String.class, Integer.class, Object.class };
93 
94         for (int i = 0; i < t.length; i++) {
95             MethodHandle m = C.getM(t[i]);
96             MethodHandle n = C.getN(t[i]); // null for void.class
97             for (int j = 0; j < t.length; j++) {
98                 boolean correctRet = t[j].isAssignableFrom(t[i]) || conversions.contains(t[i], t[j]);
99                 test(correctRet, m, mt(t[i], String.class), mt(t[j], String.class));
100                 testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
101                            mt(t[j], Object.class));
102                 testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
103                            mt(t[i], CharSequence.class), mt(t[j], Object.class));
104 
105                 if (t[i] != void.class && t[j] != void.class) {
106                     boolean correctParam = t[j].isAssignableFrom(t[i]);
107                     test(correctParam, n, mt(String.class, t[i]), mt(String.class, t[j]));
108                     testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
109                             mt(Object.class, t[j]));
110                     testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
111                             mt(CharSequence.class, t[i]), mt(Object.class, t[j]));
112                 }
113 
114             }
115         }
116     }
117 
test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT)118     static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
119         tryMetafactory(correct, mh, instMT, samMT);
120         tryAltMetafactory(correct, mh, instMT, samMT);
121     }
122 
testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)123     static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
124         tryAltMetafactory(correct, mh, instMT, samMT, bridgeMTs);
125     }
126 
tryMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT)127     static void tryMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
128         try {
129             LambdaMetafactory.metafactory(lookup, "run", mt(I.class),
130                                           samMT, mh, instMT);
131             if (!correct) {
132                 throw new AssertionError("Unexpected linkage without error:" +
133                                          " impl=" + mh +
134                                          ", inst=" + instMT +
135                                          ", sam=" + samMT);
136             }
137         }
138         catch (LambdaConversionException e) {
139             if (correct) {
140                 throw new AssertionError("Unexpected linkage error:" +
141                                          " e=" + e +
142                                          ", impl=" + mh +
143                                          ", inst=" + instMT +
144                                          ", sam=" + samMT);
145             }
146         }
147     }
148 
tryAltMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs)149     static void tryAltMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT,
150                                   MethodType... bridgeMTs) {
151         boolean bridge = bridgeMTs.length > 0;
152         Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
153         args[0] = samMT;
154         args[1] = mh;
155         args[2] = instMT;
156         args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
157         if (bridge) {
158             args[4] = bridgeMTs.length;
159             for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
160         }
161         try {
162             LambdaMetafactory.altMetafactory(lookup, "run", mt(I.class), args);
163             if (!correct) {
164                 throw new AssertionError("Unexpected linkage without error:" +
165                                          " impl=" + mh +
166                                          ", inst=" + instMT +
167                                          ", sam=" + samMT +
168                                          ", bridges=" + Arrays.toString(bridgeMTs));
169             }
170         }
171         catch (LambdaConversionException e) {
172             if (correct) {
173                 throw new AssertionError("Unexpected linkage error:" +
174                                          " e=" + e +
175                                          ", impl=" + mh +
176                                          ", inst=" + instMT +
177                                          ", sam=" + samMT +
178                                          ", bridges=" + Arrays.toString(bridgeMTs));
179             }
180         }
181     }
182 
183     private static class ConversionTable {
184         private final Map<Class<?>, Set<Class<?>>> pairs = new HashMap<>();
185 
put(Class<?> from, Class<?> to)186         public void put(Class<?> from, Class<?> to) {
187             Set<Class<?>> set = pairs.computeIfAbsent(from, f -> new HashSet<>());
188             set.add(to);
189         }
190 
contains(Class<?> from, Class<?> to)191         public boolean contains(Class<?> from, Class<?> to) {
192             return pairs.containsKey(from) && pairs.get(from).contains(to);
193         }
194     }
195 
196     private static ConversionTable conversions = new ConversionTable();
197     static {
conversions.put(char.class, int.class)198         conversions.put(char.class, int.class);
conversions.put(char.class, long.class)199         conversions.put(char.class, long.class);
conversions.put(char.class, float.class)200         conversions.put(char.class, float.class);
conversions.put(char.class, double.class)201         conversions.put(char.class, double.class);
conversions.put(char.class, Character.class)202         conversions.put(char.class, Character.class);
conversions.put(char.class, Object.class)203         conversions.put(char.class, Object.class);
conversions.put(Character.class, char.class)204         conversions.put(Character.class, char.class);
conversions.put(Character.class, int.class)205         conversions.put(Character.class, int.class);
conversions.put(Character.class, long.class)206         conversions.put(Character.class, long.class);
conversions.put(Character.class, float.class)207         conversions.put(Character.class, float.class);
conversions.put(Character.class, double.class)208         conversions.put(Character.class, double.class);
209 
conversions.put(byte.class, short.class)210         conversions.put(byte.class, short.class);
conversions.put(byte.class, int.class)211         conversions.put(byte.class, int.class);
conversions.put(byte.class, long.class)212         conversions.put(byte.class, long.class);
conversions.put(byte.class, float.class)213         conversions.put(byte.class, float.class);
conversions.put(byte.class, double.class)214         conversions.put(byte.class, double.class);
conversions.put(byte.class, Byte.class)215         conversions.put(byte.class, Byte.class);
conversions.put(byte.class, Object.class)216         conversions.put(byte.class, Object.class);
conversions.put(Byte.class, byte.class)217         conversions.put(Byte.class, byte.class);
conversions.put(Byte.class, short.class)218         conversions.put(Byte.class, short.class);
conversions.put(Byte.class, int.class)219         conversions.put(Byte.class, int.class);
conversions.put(Byte.class, long.class)220         conversions.put(Byte.class, long.class);
conversions.put(Byte.class, float.class)221         conversions.put(Byte.class, float.class);
conversions.put(Byte.class, double.class)222         conversions.put(Byte.class, double.class);
223 
conversions.put(short.class, int.class)224         conversions.put(short.class, int.class);
conversions.put(short.class, long.class)225         conversions.put(short.class, long.class);
conversions.put(short.class, float.class)226         conversions.put(short.class, float.class);
conversions.put(short.class, double.class)227         conversions.put(short.class, double.class);
conversions.put(short.class, Short.class)228         conversions.put(short.class, Short.class);
conversions.put(short.class, Object.class)229         conversions.put(short.class, Object.class);
conversions.put(Short.class, short.class)230         conversions.put(Short.class, short.class);
conversions.put(Short.class, int.class)231         conversions.put(Short.class, int.class);
conversions.put(Short.class, long.class)232         conversions.put(Short.class, long.class);
conversions.put(Short.class, float.class)233         conversions.put(Short.class, float.class);
conversions.put(Short.class, double.class)234         conversions.put(Short.class, double.class);
235 
conversions.put(int.class, long.class)236         conversions.put(int.class, long.class);
conversions.put(int.class, float.class)237         conversions.put(int.class, float.class);
conversions.put(int.class, double.class)238         conversions.put(int.class, double.class);
conversions.put(int.class, Integer.class)239         conversions.put(int.class, Integer.class);
conversions.put(int.class, Object.class)240         conversions.put(int.class, Object.class);
conversions.put(Integer.class, int.class)241         conversions.put(Integer.class, int.class);
conversions.put(Integer.class, long.class)242         conversions.put(Integer.class, long.class);
conversions.put(Integer.class, float.class)243         conversions.put(Integer.class, float.class);
conversions.put(Integer.class, double.class)244         conversions.put(Integer.class, double.class);
245 
conversions.put(long.class, float.class)246         conversions.put(long.class, float.class);
conversions.put(long.class, double.class)247         conversions.put(long.class, double.class);
conversions.put(long.class, Long.class)248         conversions.put(long.class, Long.class);
conversions.put(long.class, Object.class)249         conversions.put(long.class, Object.class);
conversions.put(Long.class, long.class)250         conversions.put(Long.class, long.class);
conversions.put(Long.class, float.class)251         conversions.put(Long.class, float.class);
conversions.put(Long.class, double.class)252         conversions.put(Long.class, double.class);
253 
conversions.put(float.class, double.class)254         conversions.put(float.class, double.class);
conversions.put(float.class, Float.class)255         conversions.put(float.class, Float.class);
conversions.put(float.class, Object.class)256         conversions.put(float.class, Object.class);
conversions.put(Float.class, float.class)257         conversions.put(Float.class, float.class);
conversions.put(Float.class, double.class)258         conversions.put(Float.class, double.class);
259 
conversions.put(double.class, Double.class)260         conversions.put(double.class, Double.class);
conversions.put(double.class, Object.class)261         conversions.put(double.class, Object.class);
conversions.put(Double.class, double.class)262         conversions.put(Double.class, double.class);
263 
conversions.put(boolean.class, Boolean.class)264         conversions.put(boolean.class, Boolean.class);
conversions.put(boolean.class, Object.class)265         conversions.put(boolean.class, Object.class);
conversions.put(Boolean.class, boolean.class)266         conversions.put(Boolean.class, boolean.class);
267     }
268 
269 }
270