blob: 21485726ce32c0324e594d0507da80cd73bc2ec2 [file] [log] [blame]
jrose55220c32009-10-21 23:19:48 -07001/*
jrosef108fc02011-02-11 01:26:24 -08002 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
jrose55220c32009-10-21 23:19:48 -07003 * 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
ohair2283b9d2010-05-25 15:58:33 -07007 * published by the Free Software Foundation. Oracle designates this
jrose55220c32009-10-21 23:19:48 -07008 * particular file as subject to the "Classpath" exception as provided
ohair2283b9d2010-05-25 15:58:33 -07009 * by Oracle in the LICENSE file that accompanied this code.
jrose55220c32009-10-21 23:19:48 -070010 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
ohair2283b9d2010-05-25 15:58:33 -070021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
jrose55220c32009-10-21 23:19:48 -070024 */
25
26/* @test
jroseada69fa2011-03-23 23:02:31 -070027 * @summary unit tests for java.lang.invoke.MethodHandles
twisti10d37ec2012-07-24 10:47:44 -070028 * @compile MethodHandlesTest.java remote/RemoteExample.java
jrose9633f5f2011-04-07 22:07:06 -070029 * @run junit/othervm test.java.lang.invoke.MethodHandlesTest
jrose55220c32009-10-21 23:19:48 -070030 */
31
jroseada69fa2011-03-23 23:02:31 -070032package test.java.lang.invoke;
jrose55220c32009-10-21 23:19:48 -070033
twisti10d37ec2012-07-24 10:47:44 -070034import test.java.lang.invoke.remote.RemoteExample;
jroseada69fa2011-03-23 23:02:31 -070035import java.lang.invoke.*;
36import java.lang.invoke.MethodHandles.Lookup;
jrose55220c32009-10-21 23:19:48 -070037import java.lang.reflect.*;
38import java.util.*;
39import org.junit.*;
40import static org.junit.Assert.*;
jrose55220c32009-10-21 23:19:48 -070041
42
43/**
44 *
45 * @author jrose
46 */
47public class MethodHandlesTest {
jroseb4be0262011-07-16 15:44:33 -070048 static final Class<?> THIS_CLASS = MethodHandlesTest.class;
jrose55220c32009-10-21 23:19:48 -070049 // How much output?
jrose2cc9c832010-04-30 23:48:23 -070050 static int verbosity = 0;
jrosecf98d422010-06-08 23:08:56 -070051 static {
jroseb4be0262011-07-16 15:44:33 -070052 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
53 if (vstr == null)
54 vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
jrosecf98d422010-06-08 23:08:56 -070055 if (vstr != null) verbosity = Integer.parseInt(vstr);
56 }
jrose55220c32009-10-21 23:19:48 -070057
58 // Set this true during development if you want to fast-forward to
59 // a particular new, non-working test. Tests which are known to
60 // work (or have recently worked) test this flag and return on true.
twisti10d37ec2012-07-24 10:47:44 -070061 static final boolean CAN_SKIP_WORKING;
62 static {
63 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING");
64 if (vstr == null)
65 vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING");
66 CAN_SKIP_WORKING = Boolean.parseBoolean(vstr);
67 }
jrose55220c32009-10-21 23:19:48 -070068
jroseb4be0262011-07-16 15:44:33 -070069 // Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest.
70 // This might be useful with -Xcomp stress tests that compile all method handles.
71 static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY");
jrose55220c32009-10-21 23:19:48 -070072
jrose55220c32009-10-21 23:19:48 -070073 @Test
74 public void testFirst() throws Throwable {
75 verbosity += 9; try {
76 // left blank for debugging
jrose2cc9c832010-04-30 23:48:23 -070077 } finally { printCounts(); verbosity -= 9; }
jrose55220c32009-10-21 23:19:48 -070078 }
79
80 static final int MAX_ARG_INCREASE = 3;
81
82 public MethodHandlesTest() {
83 }
84
jrose55220c32009-10-21 23:19:48 -070085 String testName;
jrosecf98d422010-06-08 23:08:56 -070086 static int allPosTests, allNegTests;
jrose55220c32009-10-21 23:19:48 -070087 int posTests, negTests;
88 @After
89 public void printCounts() {
jrose2cc9c832010-04-30 23:48:23 -070090 if (verbosity >= 2 && (posTests | negTests) != 0) {
jrose55220c32009-10-21 23:19:48 -070091 System.out.println();
92 if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
93 if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
jrosecf98d422010-06-08 23:08:56 -070094 allPosTests += posTests;
95 allNegTests += negTests;
jrose2cc9c832010-04-30 23:48:23 -070096 posTests = negTests = 0;
jrose55220c32009-10-21 23:19:48 -070097 }
98 }
99 void countTest(boolean positive) {
100 if (positive) ++posTests;
101 else ++negTests;
102 }
103 void countTest() { countTest(true); }
104 void startTest(String name) {
105 if (testName != null) printCounts();
jrose2cc9c832010-04-30 23:48:23 -0700106 if (verbosity >= 1)
jrose55220c32009-10-21 23:19:48 -0700107 System.out.println(name);
108 posTests = negTests = 0;
109 testName = name;
110 }
111
112 @BeforeClass
113 public static void setUpClass() throws Exception {
114 calledLog.clear();
115 calledLog.add(null);
jrose2cc9c832010-04-30 23:48:23 -0700116 nextArgVal = INITIAL_ARG_VAL;
jrose55220c32009-10-21 23:19:48 -0700117 }
118
119 @AfterClass
120 public static void tearDownClass() throws Exception {
jrosecf98d422010-06-08 23:08:56 -0700121 int posTests = allPosTests, negTests = allNegTests;
jroseb4be0262011-07-16 15:44:33 -0700122 if (verbosity >= 0 && (posTests | negTests) != 0) {
jrosecf98d422010-06-08 23:08:56 -0700123 System.out.println();
124 if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
125 if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
126 }
jrose55220c32009-10-21 23:19:48 -0700127 }
128
jrose49494522012-01-18 17:34:29 -0800129 static List<Object> calledLog = new ArrayList<>();
jrose55220c32009-10-21 23:19:48 -0700130 static Object logEntry(String name, Object... args) {
131 return Arrays.asList(name, Arrays.asList(args));
132 }
twisti10d37ec2012-07-24 10:47:44 -0700133 public static Object called(String name, Object... args) {
jrose55220c32009-10-21 23:19:48 -0700134 Object entry = logEntry(name, args);
135 calledLog.add(entry);
136 return entry;
137 }
138 static void assertCalled(String name, Object... args) {
139 Object expected = logEntry(name, args);
140 Object actual = calledLog.get(calledLog.size() - 1);
jrose2cc9c832010-04-30 23:48:23 -0700141 if (expected.equals(actual) && verbosity < 9) return;
jrose55220c32009-10-21 23:19:48 -0700142 System.out.println("assertCalled "+name+":");
143 System.out.println("expected: "+expected);
144 System.out.println("actual: "+actual);
145 System.out.println("ex. types: "+getClasses(expected));
146 System.out.println("act. types: "+getClasses(actual));
jrose55220c32009-10-21 23:19:48 -0700147 assertEquals("previous method call", expected, actual);
148 }
149 static void printCalled(MethodHandle target, String name, Object... args) {
jrose2cc9c832010-04-30 23:48:23 -0700150 if (verbosity >= 3)
151 System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
jrose55220c32009-10-21 23:19:48 -0700152 }
153
154 static Object castToWrapper(Object value, Class<?> dst) {
155 Object wrap = null;
156 if (value instanceof Number)
157 wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
158 if (value instanceof Character)
159 wrap = castToWrapperOrNull((char)(Character)value, dst);
160 if (wrap != null) return wrap;
161 return dst.cast(value);
162 }
163
jrose49494522012-01-18 17:34:29 -0800164 @SuppressWarnings("cast") // primitive cast to (long) is part of the pattern
jrose55220c32009-10-21 23:19:48 -0700165 static Object castToWrapperOrNull(long value, Class<?> dst) {
166 if (dst == int.class || dst == Integer.class)
167 return (int)(value);
168 if (dst == long.class || dst == Long.class)
169 return (long)(value);
170 if (dst == char.class || dst == Character.class)
171 return (char)(value);
172 if (dst == short.class || dst == Short.class)
173 return (short)(value);
174 if (dst == float.class || dst == Float.class)
175 return (float)(value);
176 if (dst == double.class || dst == Double.class)
177 return (double)(value);
jrose10f3b682010-01-07 16:16:45 -0800178 if (dst == byte.class || dst == Byte.class)
179 return (byte)(value);
180 if (dst == boolean.class || dst == boolean.class)
181 return ((value % 29) & 1) == 0;
jrose55220c32009-10-21 23:19:48 -0700182 return null;
183 }
184
jrose2cc9c832010-04-30 23:48:23 -0700185 static final int ONE_MILLION = (1000*1000), // first int value
186 TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits
187 INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;
188 static long nextArgVal;
189 static long nextArg(boolean moreBits) {
190 long val = nextArgVal++;
191 long sign = -(val & 1); // alternate signs
192 val >>= 1;
193 if (moreBits)
194 // Guarantee some bits in the high word.
195 // In any case keep the decimal representation simple-looking,
196 // with lots of zeroes, so as not to make the printed decimal
197 // strings unnecessarily noisy.
198 val += (val % ONE_MILLION) * TEN_BILLION;
199 return val ^ sign;
200 }
201 static int nextArg() {
202 // Produce a 32-bit result something like ONE_MILLION+(smallint).
203 // Example: 1_000_042.
204 return (int) nextArg(false);
205 }
206 static long nextArg(Class<?> kind) {
207 if (kind == long.class || kind == Long.class ||
208 kind == double.class || kind == Double.class)
209 // produce a 64-bit result something like
210 // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
211 // Example: 10_000_420_001_000_042.
212 return nextArg(true);
213 return (long) nextArg();
214 }
215
jrose55220c32009-10-21 23:19:48 -0700216 static Object randomArg(Class<?> param) {
jrose2cc9c832010-04-30 23:48:23 -0700217 Object wrap = castToWrapperOrNull(nextArg(param), param);
jrose55220c32009-10-21 23:19:48 -0700218 if (wrap != null) {
jrose55220c32009-10-21 23:19:48 -0700219 return wrap;
220 }
jroseada69fa2011-03-23 23:02:31 -0700221// import sun.invoke.util.Wrapper;
jrose55220c32009-10-21 23:19:48 -0700222// Wrapper wrap = Wrapper.forBasicType(dst);
223// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
224// wrap = Wrapper.forWrapperType(dst);
225// if (wrap != Wrapper.OBJECT)
226// return wrap.wrap(nextArg++);
jrosebe2db602010-09-08 18:40:34 -0700227 if (param.isInterface()) {
228 for (Class<?> c : param.getClasses()) {
229 if (param.isAssignableFrom(c) && !c.isInterface())
230 { param = c; break; }
231 }
232 }
jrose485df122012-07-12 00:11:35 -0700233 if (param.isInterface() && param.isAssignableFrom(List.class))
234 return Arrays.asList("#"+nextArg());
jrose55220c32009-10-21 23:19:48 -0700235 if (param.isInterface() || param.isAssignableFrom(String.class))
jrose2cc9c832010-04-30 23:48:23 -0700236 return "#"+nextArg();
jrose55220c32009-10-21 23:19:48 -0700237 else
238 try {
239 return param.newInstance();
jrose49494522012-01-18 17:34:29 -0800240 } catch (InstantiationException | IllegalAccessException ex) {
jrose55220c32009-10-21 23:19:48 -0700241 }
242 return null; // random class not Object, String, Integer, etc.
243 }
244 static Object[] randomArgs(Class<?>... params) {
245 Object[] args = new Object[params.length];
246 for (int i = 0; i < args.length; i++)
247 args[i] = randomArg(params[i]);
248 return args;
249 }
250 static Object[] randomArgs(int nargs, Class<?> param) {
251 Object[] args = new Object[nargs];
252 for (int i = 0; i < args.length; i++)
253 args[i] = randomArg(param);
254 return args;
255 }
256
jrose49494522012-01-18 17:34:29 -0800257 @SafeVarargs @SuppressWarnings("varargs")
jrose55220c32009-10-21 23:19:48 -0700258 static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
259 return Arrays.copyOf(a, a.length, atype);
260 }
jrose49494522012-01-18 17:34:29 -0800261 @SafeVarargs @SuppressWarnings("varargs")
jrose55220c32009-10-21 23:19:48 -0700262 static <T> T[] cat(T[] a, T... b) {
263 int alen = a.length, blen = b.length;
264 if (blen == 0) return a;
265 T[] c = Arrays.copyOf(a, alen + blen);
266 System.arraycopy(b, 0, c, alen, blen);
267 return c;
268 }
269 static Integer[] boxAll(int... vx) {
270 Integer[] res = new Integer[vx.length];
271 for (int i = 0; i < res.length; i++) {
272 res[i] = vx[i];
273 }
274 return res;
275 }
276 static Object getClasses(Object x) {
277 if (x == null) return x;
278 if (x instanceof String) return x; // keep the name
279 if (x instanceof List) {
280 // recursively report classes of the list elements
281 Object[] xa = ((List)x).toArray();
282 for (int i = 0; i < xa.length; i++)
283 xa[i] = getClasses(xa[i]);
284 return Arrays.asList(xa);
285 }
286 return x.getClass().getSimpleName();
287 }
288
jroseadc650a2011-02-11 01:26:28 -0800289 /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */
290 static MethodHandle varargsList(int arity) {
291 return ValueConversions.varargsList(arity);
292 }
293 /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */
294 static MethodHandle varargsArray(int arity) {
295 return ValueConversions.varargsArray(arity);
296 }
jrose320b7692011-05-12 19:27:49 -0700297 static MethodHandle varargsArray(Class<?> arrayType, int arity) {
298 return ValueConversions.varargsArray(arrayType, arity);
299 }
jroseadc650a2011-02-11 01:26:28 -0800300 /** Variation of varargsList, but with the given rtype. */
301 static MethodHandle varargsList(int arity, Class<?> rtype) {
302 MethodHandle list = varargsList(arity);
303 MethodType listType = list.type().changeReturnType(rtype);
304 if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) {
305 // OK
306 } else if (rtype.isAssignableFrom(String.class)) {
307 if (LIST_TO_STRING == null)
308 try {
309 LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",
310 MethodType.methodType(String.class, List.class));
jrose49494522012-01-18 17:34:29 -0800311 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseadc650a2011-02-11 01:26:28 -0800312 list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);
313 } else if (rtype.isPrimitive()) {
314 if (LIST_TO_INT == null)
315 try {
316 LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",
317 MethodType.methodType(int.class, List.class));
jrose49494522012-01-18 17:34:29 -0800318 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseadc650a2011-02-11 01:26:28 -0800319 list = MethodHandles.filterReturnValue(list, LIST_TO_INT);
320 list = MethodHandles.explicitCastArguments(list, listType);
321 } else {
322 throw new RuntimeException("varargsList: "+rtype);
323 }
324 return list.asType(listType);
325 }
326 private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
jrose49494522012-01-18 17:34:29 -0800327 private static String listToString(List<?> x) { return x.toString(); }
328 private static int listToInt(List<?> x) { return x.toString().hashCode(); }
jroseadc650a2011-02-11 01:26:28 -0800329
jrose55220c32009-10-21 23:19:48 -0700330 static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
331 return changeArgTypes(target, 0, 999, argType);
332 }
333 static MethodHandle changeArgTypes(MethodHandle target,
334 int beg, int end, Class<?> argType) {
335 MethodType targetType = target.type();
336 end = Math.min(end, targetType.parameterCount());
jrose49494522012-01-18 17:34:29 -0800337 ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
jrose55220c32009-10-21 23:19:48 -0700338 Collections.fill(argTypes.subList(beg, end), argType);
jrose10f3b682010-01-07 16:16:45 -0800339 MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
jrose9b82ad62011-05-26 17:37:36 -0700340 return target.asType(ttype2);
jrose55220c32009-10-21 23:19:48 -0700341 }
jroseb4be0262011-07-16 15:44:33 -0700342 static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {
343 int targetLen = target.type().parameterCount();
344 int extra = (nargs - targetLen);
345 if (extra <= 0) return target;
346 List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);
347 return MethodHandles.dropArguments(target, targetLen, fakeArgs);
348 }
jrose55220c32009-10-21 23:19:48 -0700349
350 // This lookup is good for all members in and under MethodHandlesTest.
351 static final Lookup PRIVATE = MethodHandles.lookup();
352 // This lookup is good for package-private members but not private ones.
353 static final Lookup PACKAGE = PackageSibling.lookup();
twisti10d37ec2012-07-24 10:47:44 -0700354 // This lookup is good for public members and protected members of PubExample
355 static final Lookup SUBCLASS = RemoteExample.lookup();
jrose55220c32009-10-21 23:19:48 -0700356 // This lookup is good only for public members.
jrose10f3b682010-01-07 16:16:45 -0800357 static final Lookup PUBLIC = MethodHandles.publicLookup();
jrose55220c32009-10-21 23:19:48 -0700358
359 // Subject methods...
360 static class Example implements IntExample {
361 final String name;
jrose2cc9c832010-04-30 23:48:23 -0700362 public Example() { name = "Example#"+nextArg(); }
jrose55220c32009-10-21 23:19:48 -0700363 protected Example(String name) { this.name = name; }
jrose49494522012-01-18 17:34:29 -0800364 @SuppressWarnings("LeakingThisInConstructor")
jrose55220c32009-10-21 23:19:48 -0700365 protected Example(int x) { this(); called("protected <init>", this, x); }
366 @Override public String toString() { return name; }
367
368 public void v0() { called("v0", this); }
twisti10d37ec2012-07-24 10:47:44 -0700369 protected void pro_v0() { called("pro_v0", this); }
jrose55220c32009-10-21 23:19:48 -0700370 void pkg_v0() { called("pkg_v0", this); }
371 private void pri_v0() { called("pri_v0", this); }
372 public static void s0() { called("s0"); }
twisti10d37ec2012-07-24 10:47:44 -0700373 protected static void pro_s0() { called("pro_s0"); }
jrose55220c32009-10-21 23:19:48 -0700374 static void pkg_s0() { called("pkg_s0"); }
375 private static void pri_s0() { called("pri_s0"); }
376
377 public Object v1(Object x) { return called("v1", this, x); }
378 public Object v2(Object x, Object y) { return called("v2", this, x, y); }
379 public Object v2(Object x, int y) { return called("v2", this, x, y); }
380 public Object v2(int x, Object y) { return called("v2", this, x, y); }
381 public Object v2(int x, int y) { return called("v2", this, x, y); }
382 public static Object s1(Object x) { return called("s1", x); }
383 public static Object s2(int x) { return called("s2", x); }
384 public static Object s3(long x) { return called("s3", x); }
385 public static Object s4(int x, int y) { return called("s4", x, y); }
386 public static Object s5(long x, int y) { return called("s5", x, y); }
387 public static Object s6(int x, long y) { return called("s6", x, y); }
388 public static Object s7(float x, double y) { return called("s7", x, y); }
jrose2cc9c832010-04-30 23:48:23 -0700389
jroseb4be0262011-07-16 15:44:33 -0700390 // for testing findConstructor:
391 public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }
392 public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }
twisti10d37ec2012-07-24 10:47:44 -0700393 public Example(int x, int y) { this.name = x+""+y; called("Example.<init>", x, y); }
394 public Example(int x, long y) { this.name = x+""+y; called("Example.<init>", x, y); }
395 public Example(int x, float y) { this.name = x+""+y; called("Example.<init>", x, y); }
396 public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); }
397 public Example(int x, int y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); }
398 public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }
jroseb4be0262011-07-16 15:44:33 -0700399
jrose2cc9c832010-04-30 23:48:23 -0700400 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
jrose55220c32009-10-21 23:19:48 -0700401 }
jrose2cc9c832010-04-30 23:48:23 -0700402 static final Lookup EXAMPLE = Example.EXAMPLE;
jrose55220c32009-10-21 23:19:48 -0700403 public static class PubExample extends Example {
twisti10d37ec2012-07-24 10:47:44 -0700404 public PubExample() { this("PubExample"); }
405 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
406 protected void pro_v0() { called("Pub/pro_v0", this); }
407 protected static void pro_s0() { called("Pub/pro_s0"); }
jrose55220c32009-10-21 23:19:48 -0700408 }
409 static class SubExample extends Example {
410 @Override public void v0() { called("Sub/v0", this); }
411 @Override void pkg_v0() { called("Sub/pkg_v0", this); }
jrose49494522012-01-18 17:34:29 -0800412 @SuppressWarnings("LeakingThisInConstructor")
jrose55220c32009-10-21 23:19:48 -0700413 private SubExample(int x) { called("<init>", this, x); }
jrose2cc9c832010-04-30 23:48:23 -0700414 public SubExample() { super("SubExample#"+nextArg()); }
jrose55220c32009-10-21 23:19:48 -0700415 }
416 public static interface IntExample {
417 public void v0();
jrosebe2db602010-09-08 18:40:34 -0700418 public static class Impl implements IntExample {
jrose55220c32009-10-21 23:19:48 -0700419 public void v0() { called("Int/v0", this); }
420 final String name;
jrose2cc9c832010-04-30 23:48:23 -0700421 public Impl() { name = "Impl#"+nextArg(); }
422 @Override public String toString() { return name; }
jrose55220c32009-10-21 23:19:48 -0700423 }
424 }
jrose485df122012-07-12 00:11:35 -0700425 static interface SubIntExample extends IntExample { }
jrose55220c32009-10-21 23:19:48 -0700426
427 static final Object[][][] ACCESS_CASES = {
twisti10d37ec2012-07-24 10:47:44 -0700428 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
429 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
430 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
431 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK
432 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true
jrose55220c32009-10-21 23:19:48 -0700433 };
434
jrose2cc9c832010-04-30 23:48:23 -0700435 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
436 Object[][] cases;
437 if (name.contains("pri_") || isSpecial) {
438 cases = ACCESS_CASES[1]; // PRIVATE only
439 } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {
440 cases = ACCESS_CASES[2]; // not PUBLIC
twisti10d37ec2012-07-24 10:47:44 -0700441 } else if (name.contains("pro_")) {
442 cases = ACCESS_CASES[3]; // PUBLIC class, protected member
jrose10f3b682010-01-07 16:16:45 -0800443 } else {
twisti10d37ec2012-07-24 10:47:44 -0700444 assertTrue(name.indexOf('_') < 0 || name.contains("fin_"));
jrose10f3b682010-01-07 16:16:45 -0800445 boolean pubc = Modifier.isPublic(defc.getModifiers());
446 if (pubc)
twisti10d37ec2012-07-24 10:47:44 -0700447 cases = ACCESS_CASES[4]; // all access levels
jrose2cc9c832010-04-30 23:48:23 -0700448 else
449 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC
jrose10f3b682010-01-07 16:16:45 -0800450 }
jrose2cc9c832010-04-30 23:48:23 -0700451 if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)
452 cases = Arrays.copyOfRange(cases, 0, cases.length-1);
453 return cases;
454 }
455 static Object[][] accessCases(Class<?> defc, String name) {
456 return accessCases(defc, name, false);
jrose55220c32009-10-21 23:19:48 -0700457 }
458
twisti10d37ec2012-07-24 10:47:44 -0700459 static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) {
460 if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE)
461 // external views stay external
462 return lookup;
463 return lookup.in(defc);
464 }
465
jrose55220c32009-10-21 23:19:48 -0700466 @Test
467 public void testFindStatic() throws Throwable {
468 if (CAN_SKIP_WORKING) return;
469 startTest("findStatic");
470 testFindStatic(PubExample.class, void.class, "s0");
471 testFindStatic(Example.class, void.class, "s0");
472 testFindStatic(Example.class, void.class, "pkg_s0");
473 testFindStatic(Example.class, void.class, "pri_s0");
twisti10d37ec2012-07-24 10:47:44 -0700474 testFindStatic(Example.class, void.class, "pro_s0");
475 testFindStatic(PubExample.class, void.class, "Pub/pro_s0");
jrose55220c32009-10-21 23:19:48 -0700476
477 testFindStatic(Example.class, Object.class, "s1", Object.class);
478 testFindStatic(Example.class, Object.class, "s2", int.class);
479 testFindStatic(Example.class, Object.class, "s3", long.class);
480 testFindStatic(Example.class, Object.class, "s4", int.class, int.class);
481 testFindStatic(Example.class, Object.class, "s5", long.class, int.class);
482 testFindStatic(Example.class, Object.class, "s6", int.class, long.class);
483 testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
484
485 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
twisti10d37ec2012-07-24 10:47:44 -0700486 testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
jrose55220c32009-10-21 23:19:48 -0700487 }
488
489 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
490 for (Object[] ac : accessCases(defc, name)) {
491 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
492 }
493 }
494 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
495 testFindStatic(true, lookup, defc, ret, name, params);
496 }
497 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
498 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700499 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800500 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700501 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700502 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700503 try {
jrose2cc9c832010-04-30 23:48:23 -0700504 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700505 target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800506 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700507 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -0700508 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -0800509 if (name.contains("bogus"))
510 assertTrue(noAccess instanceof NoSuchMethodException);
511 else
512 assertTrue(noAccess instanceof IllegalAccessException);
jrose55220c32009-10-21 23:19:48 -0700513 }
jrose2cc9c832010-04-30 23:48:23 -0700514 if (verbosity >= 3)
515 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
jrose55220c32009-10-21 23:19:48 -0700516 +(noAccess == null ? "" : " !! "+noAccess));
517 if (positive && noAccess != null) throw noAccess;
518 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
519 if (!positive) return; // negative test failed as expected
520 assertEquals(type, target.type());
twisti10d37ec2012-07-24 10:47:44 -0700521 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700522 Object[] args = randomArgs(params);
523 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700524 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700525 assertCalled(name, args);
jrose2cc9c832010-04-30 23:48:23 -0700526 if (verbosity >= 1)
527 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700528 }
529
jrose73016262011-05-17 19:48:19 -0700530 static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
531
jrose900bafd2010-10-30 21:08:23 -0700532 // rough check of name string
jrose73016262011-05-17 19:48:19 -0700533 static void assertNameStringContains(MethodHandle x, String s) {
534 if (!DEBUG_METHOD_HANDLE_NAMES) {
535 // ignore s
536 assertEquals("MethodHandle"+x.type(), x.toString());
537 return;
538 }
jrose900bafd2010-10-30 21:08:23 -0700539 if (x.toString().contains(s)) return;
540 assertEquals(s, x);
541 }
542
jrose55220c32009-10-21 23:19:48 -0700543 @Test
544 public void testFindVirtual() throws Throwable {
545 if (CAN_SKIP_WORKING) return;
546 startTest("findVirtual");
547 testFindVirtual(Example.class, void.class, "v0");
548 testFindVirtual(Example.class, void.class, "pkg_v0");
549 testFindVirtual(Example.class, void.class, "pri_v0");
550 testFindVirtual(Example.class, Object.class, "v1", Object.class);
551 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class);
552 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class);
553 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class);
554 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700555 testFindVirtual(Example.class, void.class, "pro_v0");
556 testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");
557
jrose55220c32009-10-21 23:19:48 -0700558 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
twisti10d37ec2012-07-24 10:47:44 -0700559 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
560
jrose55220c32009-10-21 23:19:48 -0700561 // test dispatch
562 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0");
563 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0");
564 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0");
565 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0");
566 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0");
567 testFindVirtual(Example.class, IntExample.class, void.class, "v0");
568 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
569 }
570
571 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
572 Class<?> rcvc = defc;
573 testFindVirtual(rcvc, defc, ret, name, params);
574 }
575 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
576 for (Object[] ac : accessCases(defc, name)) {
577 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params);
578 }
579 }
580 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
581 testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
582 }
583 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
584 countTest(positive);
585 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800586 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700587 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700588 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700589 try {
jrose2cc9c832010-04-30 23:48:23 -0700590 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700591 target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800592 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700593 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -0700594 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -0800595 if (name.contains("bogus"))
596 assertTrue(noAccess instanceof NoSuchMethodException);
597 else
598 assertTrue(noAccess instanceof IllegalAccessException);
jrose55220c32009-10-21 23:19:48 -0700599 }
jrose2cc9c832010-04-30 23:48:23 -0700600 if (verbosity >= 3)
601 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
jrose55220c32009-10-21 23:19:48 -0700602 +(noAccess == null ? "" : " !! "+noAccess));
603 if (positive && noAccess != null) throw noAccess;
604 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
605 if (!positive) return; // negative test failed as expected
twisti10d37ec2012-07-24 10:47:44 -0700606 Class<?> selfc = defc;
607 // predict receiver type narrowing:
608 if (lookup == SUBCLASS &&
609 name.contains("pro_") &&
610 selfc.isAssignableFrom(lookup.lookupClass())) {
611 selfc = lookup.lookupClass();
612 if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4);
613 }
614 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params);
jrose10f3b682010-01-07 16:16:45 -0800615 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700616 assertEquals(typeWithSelf, target.type());
jrose900bafd2010-10-30 21:08:23 -0700617 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700618 Object[] argsWithSelf = randomArgs(paramsWithSelf);
twisti10d37ec2012-07-24 10:47:44 -0700619 if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc);
jrose55220c32009-10-21 23:19:48 -0700620 printCalled(target, name, argsWithSelf);
jrose900bafd2010-10-30 21:08:23 -0700621 target.invokeWithArguments(argsWithSelf);
jrose55220c32009-10-21 23:19:48 -0700622 assertCalled(name, argsWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700623 if (verbosity >= 1)
624 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700625 }
626
627 @Test
628 public void testFindSpecial() throws Throwable {
629 if (CAN_SKIP_WORKING) return;
630 startTest("findSpecial");
jrose2cc9c832010-04-30 23:48:23 -0700631 testFindSpecial(SubExample.class, Example.class, void.class, "v0");
632 testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
twisti10d37ec2012-07-24 10:47:44 -0700633 testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
jrose2cc9c832010-04-30 23:48:23 -0700634 // Do some negative testing:
jrosef15905c2011-02-11 01:26:32 -0800635 testFindSpecial(false, EXAMPLE, SubExample.class, Example.class, void.class, "bogus");
636 testFindSpecial(false, PRIVATE, SubExample.class, Example.class, void.class, "bogus");
jrose2cc9c832010-04-30 23:48:23 -0700637 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
638 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
639 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
640 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
jrose2cc9c832010-04-30 23:48:23 -0700641 }
jrose55220c32009-10-21 23:19:48 -0700642 }
643
jrose2cc9c832010-04-30 23:48:23 -0700644 void testFindSpecial(Class<?> specialCaller,
645 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -0700646 if (specialCaller == RemoteExample.class) {
647 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
648 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
649 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
650 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params);
651 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
652 return;
653 }
654 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
655 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
656 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
657 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
658 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
jrose55220c32009-10-21 23:19:48 -0700659 }
jrose2cc9c832010-04-30 23:48:23 -0700660 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
661 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -0700662 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700663 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800664 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700665 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700666 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700667 try {
jrose2cc9c832010-04-30 23:48:23 -0700668 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700669 if (verbosity >= 5) System.out.println(" lookup => "+maybeMoveIn(lookup, specialCaller));
670 target = maybeMoveIn(lookup, specialCaller).findSpecial(defc, methodName, type, specialCaller);
jrosef15905c2011-02-11 01:26:32 -0800671 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700672 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -0700673 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -0800674 if (name.contains("bogus"))
675 assertTrue(noAccess instanceof NoSuchMethodException);
676 else
677 assertTrue(noAccess instanceof IllegalAccessException);
jrose55220c32009-10-21 23:19:48 -0700678 }
jrose2cc9c832010-04-30 23:48:23 -0700679 if (verbosity >= 3)
680 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
681 +(target == null ? "" : target.type())
682 +(noAccess == null ? "" : " !! "+noAccess));
jrose55220c32009-10-21 23:19:48 -0700683 if (positive && noAccess != null) throw noAccess;
684 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
685 if (!positive) return; // negative test failed as expected
jrose2cc9c832010-04-30 23:48:23 -0700686 assertEquals(specialCaller, target.type().parameterType(0));
687 assertEquals(type, target.type().dropParameterTypes(0,1));
688 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
jrose10f3b682010-01-07 16:16:45 -0800689 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
twisti10d37ec2012-07-24 10:47:44 -0700690 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700691 Object[] args = randomArgs(paramsWithSelf);
692 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700693 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700694 assertCalled(name, args);
jrose55220c32009-10-21 23:19:48 -0700695 }
696
697 @Test
jroseb4be0262011-07-16 15:44:33 -0700698 public void testFindConstructor() throws Throwable {
699 if (CAN_SKIP_WORKING) return;
700 startTest("findConstructor");
701 testFindConstructor(true, EXAMPLE, Example.class);
702 testFindConstructor(true, EXAMPLE, Example.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700703 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class);
704 testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class);
705 testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class);
706 testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class);
jroseb4be0262011-07-16 15:44:33 -0700707 testFindConstructor(true, EXAMPLE, Example.class, String.class);
twisti10d37ec2012-07-24 10:47:44 -0700708 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class);
709 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class);
jroseb4be0262011-07-16 15:44:33 -0700710 }
711 void testFindConstructor(boolean positive, Lookup lookup,
712 Class<?> defc, Class<?>... params) throws Throwable {
713 countTest(positive);
714 MethodType type = MethodType.methodType(void.class, params);
715 MethodHandle target = null;
716 Exception noAccess = null;
717 try {
718 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type);
719 target = lookup.findConstructor(defc, type);
720 } catch (ReflectiveOperationException ex) {
721 noAccess = ex;
722 assertTrue(noAccess instanceof IllegalAccessException);
723 }
724 if (verbosity >= 3)
725 System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
726 +(target == null ? "" : target.type())
727 +(noAccess == null ? "" : " !! "+noAccess));
728 if (positive && noAccess != null) throw noAccess;
729 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
730 if (!positive) return; // negative test failed as expected
731 assertEquals(type.changeReturnType(defc), target.type());
732 Object[] args = randomArgs(params);
733 printCalled(target, defc.getSimpleName(), args);
734 Object obj = target.invokeWithArguments(args);
735 if (!(defc == Example.class && params.length < 2))
736 assertCalled(defc.getSimpleName()+".<init>", args);
737 assertTrue("instance of "+defc.getName(), defc.isInstance(obj));
738 }
739
740 @Test
jrose55220c32009-10-21 23:19:48 -0700741 public void testBind() throws Throwable {
742 if (CAN_SKIP_WORKING) return;
743 startTest("bind");
744 testBind(Example.class, void.class, "v0");
745 testBind(Example.class, void.class, "pkg_v0");
746 testBind(Example.class, void.class, "pri_v0");
747 testBind(Example.class, Object.class, "v1", Object.class);
748 testBind(Example.class, Object.class, "v2", Object.class, Object.class);
749 testBind(Example.class, Object.class, "v2", Object.class, int.class);
750 testBind(Example.class, Object.class, "v2", int.class, Object.class);
751 testBind(Example.class, Object.class, "v2", int.class, int.class);
752 testBind(false, PRIVATE, Example.class, void.class, "bogus");
753 testBind(SubExample.class, void.class, "Sub/v0");
754 testBind(SubExample.class, void.class, "Sub/pkg_v0");
755 testBind(IntExample.Impl.class, void.class, "Int/v0");
756 }
757
758 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
759 for (Object[] ac : accessCases(defc, name)) {
760 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
761 }
762 }
763
764 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
765 countTest(positive);
766 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800767 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700768 Object receiver = randomArg(defc);
769 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700770 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700771 try {
jrose2cc9c832010-04-30 23:48:23 -0700772 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700773 target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800774 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700775 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -0700776 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -0800777 if (name.contains("bogus"))
778 assertTrue(noAccess instanceof NoSuchMethodException);
779 else
780 assertTrue(noAccess instanceof IllegalAccessException);
jrose55220c32009-10-21 23:19:48 -0700781 }
jrose2cc9c832010-04-30 23:48:23 -0700782 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -0700783 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
784 +(noAccess == null ? "" : " !! "+noAccess));
785 if (positive && noAccess != null) throw noAccess;
786 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
787 if (!positive) return; // negative test failed as expected
788 assertEquals(type, target.type());
789 Object[] args = randomArgs(params);
790 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700791 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700792 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
793 assertCalled(name, argsWithReceiver);
jrose2cc9c832010-04-30 23:48:23 -0700794 if (verbosity >= 1)
795 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700796 }
797
798 @Test
799 public void testUnreflect() throws Throwable {
800 if (CAN_SKIP_WORKING) return;
801 startTest("unreflect");
802 testUnreflect(Example.class, true, void.class, "s0");
twisti10d37ec2012-07-24 10:47:44 -0700803 testUnreflect(Example.class, true, void.class, "pro_s0");
jrose55220c32009-10-21 23:19:48 -0700804 testUnreflect(Example.class, true, void.class, "pkg_s0");
805 testUnreflect(Example.class, true, void.class, "pri_s0");
806
807 testUnreflect(Example.class, true, Object.class, "s1", Object.class);
808 testUnreflect(Example.class, true, Object.class, "s2", int.class);
jrose2cc9c832010-04-30 23:48:23 -0700809 testUnreflect(Example.class, true, Object.class, "s3", long.class);
810 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
811 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
812 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
jrose55220c32009-10-21 23:19:48 -0700813
814 testUnreflect(Example.class, false, void.class, "v0");
815 testUnreflect(Example.class, false, void.class, "pkg_v0");
816 testUnreflect(Example.class, false, void.class, "pri_v0");
817 testUnreflect(Example.class, false, Object.class, "v1", Object.class);
818 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class);
819 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class);
820 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class);
821 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700822
823 // Test a public final member in another package:
824 testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0");
jrose55220c32009-10-21 23:19:48 -0700825 }
826
827 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
828 for (Object[] ac : accessCases(defc, name)) {
jrose2cc9c832010-04-30 23:48:23 -0700829 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params);
jrose55220c32009-10-21 23:19:48 -0700830 }
831 }
jrose2cc9c832010-04-30 23:48:23 -0700832 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
833 for (Object[] ac : accessCases(defc, name)) {
834 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
835 }
836 }
837 void testUnreflectMaybeSpecial(Class<?> specialCaller,
838 boolean positive, Lookup lookup,
839 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -0700840 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700841 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800842 MethodType type = MethodType.methodType(ret, params);
twisti10d37ec2012-07-24 10:47:44 -0700843 Method rmethod = defc.getDeclaredMethod(methodName, params);
jrose55220c32009-10-21 23:19:48 -0700844 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700845 Exception noAccess = null;
jrose2cc9c832010-04-30 23:48:23 -0700846 boolean isStatic = (rcvc == null);
847 boolean isSpecial = (specialCaller != null);
jrose55220c32009-10-21 23:19:48 -0700848 try {
jrose2cc9c832010-04-30 23:48:23 -0700849 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
850 if (isSpecial)
twisti10d37ec2012-07-24 10:47:44 -0700851 target = maybeMoveIn(lookup, specialCaller).unreflectSpecial(rmethod, specialCaller);
jrose2cc9c832010-04-30 23:48:23 -0700852 else
twisti10d37ec2012-07-24 10:47:44 -0700853 target = maybeMoveIn(lookup, defc).unreflect(rmethod);
jrosef15905c2011-02-11 01:26:32 -0800854 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700855 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -0700856 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -0800857 if (name.contains("bogus"))
858 assertTrue(noAccess instanceof NoSuchMethodException);
859 else
860 assertTrue(noAccess instanceof IllegalAccessException);
jrose55220c32009-10-21 23:19:48 -0700861 }
jrose2cc9c832010-04-30 23:48:23 -0700862 if (verbosity >= 3)
863 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
864 +(!isSpecial ? "" : " specialCaller="+specialCaller)
865 +( isStatic ? "" : " receiver="+rcvc)
866 +" => "+target
867 +(noAccess == null ? "" : " !! "+noAccess));
jrose55220c32009-10-21 23:19:48 -0700868 if (positive && noAccess != null) throw noAccess;
869 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
870 if (!positive) return; // negative test failed as expected
jrose2cc9c832010-04-30 23:48:23 -0700871 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
jrose55220c32009-10-21 23:19:48 -0700872 Class<?>[] paramsMaybeWithSelf = params;
873 if (!isStatic) {
jrose2cc9c832010-04-30 23:48:23 -0700874 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params);
jrose55220c32009-10-21 23:19:48 -0700875 }
jrose10f3b682010-01-07 16:16:45 -0800876 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700877 if (isStatic) {
878 assertEquals(typeMaybeWithSelf, target.type());
879 } else {
jrose2cc9c832010-04-30 23:48:23 -0700880 if (isSpecial)
881 assertEquals(specialCaller, target.type().parameterType(0));
882 else
883 assertEquals(defc, target.type().parameterType(0));
884 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc));
885 }
jrose55220c32009-10-21 23:19:48 -0700886 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
887 printCalled(target, name, argsMaybeWithSelf);
jrose900bafd2010-10-30 21:08:23 -0700888 target.invokeWithArguments(argsMaybeWithSelf);
jrose55220c32009-10-21 23:19:48 -0700889 assertCalled(name, argsMaybeWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700890 if (verbosity >= 1)
891 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700892 }
893
jrose2cc9c832010-04-30 23:48:23 -0700894 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
895 for (Object[] ac : accessCases(defc, name, true)) {
896 Class<?> specialCaller = rcvc;
897 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
898 }
899 }
900
901 @Test
jrose55220c32009-10-21 23:19:48 -0700902 public void testUnreflectSpecial() throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -0700903 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -0700904 startTest("unreflectSpecial");
jrose2cc9c832010-04-30 23:48:23 -0700905 testUnreflectSpecial(Example.class, Example.class, void.class, "v0");
906 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0");
907 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0");
908 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0");
909 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class);
910 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class);
911 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0");
jrose55220c32009-10-21 23:19:48 -0700912 }
913
jrose10f3b682010-01-07 16:16:45 -0800914 public static class HasFields {
915 boolean fZ = false;
916 byte fB = (byte)'B';
917 short fS = (short)'S';
918 char fC = 'C';
919 int fI = 'I';
920 long fJ = 'J';
921 float fF = 'F';
922 double fD = 'D';
923 static boolean sZ = true;
924 static byte sB = 1+(byte)'B';
925 static short sS = 1+(short)'S';
926 static char sC = 1+'C';
927 static int sI = 1+'I';
928 static long sJ = 1+'J';
929 static float sF = 1+'F';
930 static double sD = 1+'D';
931
932 Object fL = 'L';
933 String fR = "R";
934 static Object sL = 'M';
935 static String sR = "S";
936
937 static final Object[][] CASES;
938 static {
jrose49494522012-01-18 17:34:29 -0800939 ArrayList<Object[]> cases = new ArrayList<>();
jrose10f3b682010-01-07 16:16:45 -0800940 Object types[][] = {
941 {'L',Object.class}, {'R',String.class},
942 {'I',int.class}, {'J',long.class},
943 {'F',float.class}, {'D',double.class},
944 {'Z',boolean.class}, {'B',byte.class},
945 {'S',short.class}, {'C',char.class},
946 };
947 HasFields fields = new HasFields();
948 for (Object[] t : types) {
949 for (int kind = 0; kind <= 1; kind++) {
950 boolean isStatic = (kind != 0);
951 char btc = (Character)t[0];
952 String name = (isStatic ? "s" : "f") + btc;
953 Class<?> type = (Class<?>) t[1];
954 Object value;
955 Field field;
jrose320b7692011-05-12 19:27:49 -0700956 try {
jrose10f3b682010-01-07 16:16:45 -0800957 field = HasFields.class.getDeclaredField(name);
jrose49494522012-01-18 17:34:29 -0800958 } catch (NoSuchFieldException | SecurityException ex) {
jrose10f3b682010-01-07 16:16:45 -0800959 throw new InternalError("no field HasFields."+name);
960 }
961 try {
962 value = field.get(fields);
jrose49494522012-01-18 17:34:29 -0800963 } catch (IllegalArgumentException | IllegalAccessException ex) {
jrose10f3b682010-01-07 16:16:45 -0800964 throw new InternalError("cannot fetch field HasFields."+name);
965 }
966 if (type == float.class) {
967 float v = 'F';
968 if (isStatic) v++;
jrosef15905c2011-02-11 01:26:32 -0800969 assertTrue(value.equals(v));
jrose10f3b682010-01-07 16:16:45 -0800970 }
jrosef15905c2011-02-11 01:26:32 -0800971 assertTrue(name.equals(field.getName()));
972 assertTrue(type.equals(field.getType()));
973 assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));
jrose10f3b682010-01-07 16:16:45 -0800974 cases.add(new Object[]{ field, value });
975 }
976 }
jrosef15905c2011-02-11 01:26:32 -0800977 cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class });
978 cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class });
jrose10f3b682010-01-07 16:16:45 -0800979 CASES = cases.toArray(new Object[0][]);
980 }
981 }
982
twisti10d37ec2012-07-24 10:47:44 -0700983 static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40;
jrosecf98d422010-06-08 23:08:56 -0700984 static boolean testModeMatches(int testMode, boolean isStatic) {
985 switch (testMode) {
jrosef15905c2011-02-11 01:26:32 -0800986 case TEST_FIND_STATIC: return isStatic;
jrosecf98d422010-06-08 23:08:56 -0700987 case TEST_FIND_FIELD: return !isStatic;
jrosef15905c2011-02-11 01:26:32 -0800988 case TEST_UNREFLECT: return true; // unreflect matches both
jrosecf98d422010-06-08 23:08:56 -0700989 }
jrosef15905c2011-02-11 01:26:32 -0800990 throw new InternalError("testMode="+testMode);
jrosecf98d422010-06-08 23:08:56 -0700991 }
992
jrose10f3b682010-01-07 16:16:45 -0800993 @Test
jrose55220c32009-10-21 23:19:48 -0700994 public void testUnreflectGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -0700995 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -0700996 startTest("unreflectGetter");
jrosecf98d422010-06-08 23:08:56 -0700997 testGetter(TEST_UNREFLECT);
998 }
999 @Test
1000 public void testFindGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001001 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001002 startTest("findGetter");
1003 testGetter(TEST_FIND_FIELD);
twisti10d37ec2012-07-24 10:47:44 -07001004 testGetter(TEST_FIND_FIELD | TEST_BOUND);
jrosecf98d422010-06-08 23:08:56 -07001005 }
1006 @Test
1007 public void testFindStaticGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001008 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001009 startTest("findStaticGetter");
jrosef15905c2011-02-11 01:26:32 -08001010 testGetter(TEST_FIND_STATIC);
jrosecf98d422010-06-08 23:08:56 -07001011 }
1012 public void testGetter(int testMode) throws Throwable {
1013 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
jrose10f3b682010-01-07 16:16:45 -08001014 for (Object[] c : HasFields.CASES) {
jrosef15905c2011-02-11 01:26:32 -08001015 boolean positive = (c[1] != Error.class);
1016 testGetter(positive, lookup, c[0], c[1], testMode);
jrose485df122012-07-12 00:11:35 -07001017 if (positive)
1018 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
jrosef15905c2011-02-11 01:26:32 -08001019 }
1020 testGetter(true, lookup,
1021 new Object[]{ true, System.class, "out", java.io.PrintStream.class },
1022 System.out, testMode);
1023 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1024 testGetter(false, lookup,
1025 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1026 null, testMode);
jrose10f3b682010-01-07 16:16:45 -08001027 }
1028 }
jrosef15905c2011-02-11 01:26:32 -08001029 public void testGetter(boolean positive, MethodHandles.Lookup lookup,
1030 Object fieldRef, Object value, int testMode) throws Throwable {
1031 testAccessor(positive, lookup, fieldRef, value, testMode);
1032 }
1033
jrose485df122012-07-12 00:11:35 -07001034 public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,
jrosef15905c2011-02-11 01:26:32 -08001035 Object fieldRef, Object value, int testMode0) throws Throwable {
jroseb4be0262011-07-16 15:44:33 -07001036 if (verbosity >= 4)
jrose485df122012-07-12 00:11:35 -07001037 System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));
jrosef15905c2011-02-11 01:26:32 -08001038 boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
twisti10d37ec2012-07-24 10:47:44 -07001039 boolean doBound = ((testMode0 & TEST_BOUND) != 0);
jrose485df122012-07-12 00:11:35 -07001040 boolean testNPE = ((testMode0 & TEST_NPE) != 0);
twisti10d37ec2012-07-24 10:47:44 -07001041 int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE);
jrose485df122012-07-12 00:11:35 -07001042 boolean positive = positive0 && !testNPE;
jrosef15905c2011-02-11 01:26:32 -08001043 boolean isStatic;
1044 Class<?> fclass;
1045 String fname;
1046 Class<?> ftype;
1047 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null);
1048 if (f != null) {
1049 isStatic = Modifier.isStatic(f.getModifiers());
1050 fclass = f.getDeclaringClass();
1051 fname = f.getName();
1052 ftype = f.getType();
1053 } else {
1054 Object[] scnt = (Object[]) fieldRef;
1055 isStatic = (Boolean) scnt[0];
1056 fclass = (Class<?>) scnt[1];
1057 fname = (String) scnt[2];
1058 ftype = (Class<?>) scnt[3];
1059 try {
1060 f = fclass.getDeclaredField(fname);
1061 } catch (ReflectiveOperationException ex) {
1062 f = null;
1063 }
1064 }
jrosecf98d422010-06-08 23:08:56 -07001065 if (!testModeMatches(testMode, isStatic)) return;
jrosef15905c2011-02-11 01:26:32 -08001066 if (f == null && testMode == TEST_UNREFLECT) return;
jrose485df122012-07-12 00:11:35 -07001067 if (testNPE && isStatic) return;
jrosef15905c2011-02-11 01:26:32 -08001068 countTest(positive);
1069 MethodType expType;
1070 if (isGetter)
1071 expType = MethodType.methodType(ftype, HasFields.class);
1072 else
1073 expType = MethodType.methodType(void.class, HasFields.class, ftype);
jrose10f3b682010-01-07 16:16:45 -08001074 if (isStatic) expType = expType.dropParameterTypes(0, 1);
jrosef15905c2011-02-11 01:26:32 -08001075 Exception noAccess = null;
1076 MethodHandle mh;
1077 try {
twisti10d37ec2012-07-24 10:47:44 -07001078 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) {
jrosef15905c2011-02-11 01:26:32 -08001079 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break;
1080 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break;
1081 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break;
1082 case TEST_SETTER|
1083 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break;
1084 case TEST_SETTER|
1085 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break;
1086 case TEST_SETTER|
1087 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break;
1088 default:
1089 throw new InternalError("testMode="+testMode);
1090 }
1091 } catch (ReflectiveOperationException ex) {
1092 mh = null;
1093 noAccess = ex;
twisti10d37ec2012-07-24 10:47:44 -07001094 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -08001095 if (fname.contains("bogus"))
1096 assertTrue(noAccess instanceof NoSuchFieldException);
1097 else
1098 assertTrue(noAccess instanceof IllegalAccessException);
1099 }
1100 if (verbosity >= 3)
1101 System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
1102 +" => "+mh
1103 +(noAccess == null ? "" : " !! "+noAccess));
jrose485df122012-07-12 00:11:35 -07001104 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess);
1105 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
1106 if (!positive && !testNPE) return; // negative access test failed as expected
jrosef15905c2011-02-11 01:26:32 -08001107 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
1108
1109
jrose10f3b682010-01-07 16:16:45 -08001110 assertSame(mh.type(), expType);
twisti10d37ec2012-07-24 10:47:44 -07001111 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs
jrose10f3b682010-01-07 16:16:45 -08001112 HasFields fields = new HasFields();
jrose485df122012-07-12 00:11:35 -07001113 HasFields fieldsForMH = fields;
1114 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error
twisti10d37ec2012-07-24 10:47:44 -07001115 if (doBound)
1116 mh = mh.bindTo(fieldsForMH);
jrose10f3b682010-01-07 16:16:45 -08001117 Object sawValue;
jrosef15905c2011-02-11 01:26:32 -08001118 Class<?> vtype = ftype;
1119 if (ftype != int.class) vtype = Object.class;
1120 if (isGetter) {
jrose9b82ad62011-05-26 17:37:36 -07001121 mh = mh.asType(mh.type().generic()
1122 .changeReturnType(vtype));
jrosef15905c2011-02-11 01:26:32 -08001123 } else {
1124 int last = mh.type().parameterCount() - 1;
jrose9b82ad62011-05-26 17:37:36 -07001125 mh = mh.asType(mh.type().generic()
1126 .changeReturnType(void.class)
1127 .changeParameterType(last, vtype));
jrose10f3b682010-01-07 16:16:45 -08001128 }
jrosef15905c2011-02-11 01:26:32 -08001129 if (f != null && f.getDeclaringClass() == HasFields.class) {
1130 assertEquals(f.get(fields), value); // clean to start with
1131 }
jrose485df122012-07-12 00:11:35 -07001132 Throwable caughtEx = null;
jrosef15905c2011-02-11 01:26:32 -08001133 if (isGetter) {
1134 Object expValue = value;
1135 for (int i = 0; i <= 1; i++) {
twisti10d37ec2012-07-24 10:47:44 -07001136 sawValue = null; // make DA rules happy under try/catch
1137 try {
1138 if (isStatic || doBound) {
1139 if (ftype == int.class)
1140 sawValue = (int) mh.invokeExact(); // do these exactly
1141 else
1142 sawValue = mh.invokeExact();
1143 } else {
jrose485df122012-07-12 00:11:35 -07001144 if (ftype == int.class)
1145 sawValue = (int) mh.invokeExact((Object) fieldsForMH);
1146 else
1147 sawValue = mh.invokeExact((Object) fieldsForMH);
twisti10d37ec2012-07-24 10:47:44 -07001148 }
1149 } catch (RuntimeException ex) {
1150 if (ex instanceof NullPointerException && testNPE) {
1151 caughtEx = ex;
1152 break;
jrose485df122012-07-12 00:11:35 -07001153 }
jrosef15905c2011-02-11 01:26:32 -08001154 }
1155 assertEquals(sawValue, expValue);
1156 if (f != null && f.getDeclaringClass() == HasFields.class
1157 && !Modifier.isFinal(f.getModifiers())) {
1158 Object random = randomArg(ftype);
1159 f.set(fields, random);
1160 expValue = random;
1161 } else {
1162 break;
1163 }
1164 }
1165 } else {
1166 for (int i = 0; i <= 1; i++) {
1167 Object putValue = randomArg(ftype);
twisti10d37ec2012-07-24 10:47:44 -07001168 try {
1169 if (isStatic || doBound) {
1170 if (ftype == int.class)
1171 mh.invokeExact((int)putValue); // do these exactly
1172 else
1173 mh.invokeExact(putValue);
1174 } else {
jrose485df122012-07-12 00:11:35 -07001175 if (ftype == int.class)
1176 mh.invokeExact((Object) fieldsForMH, (int)putValue);
1177 else
1178 mh.invokeExact((Object) fieldsForMH, putValue);
twisti10d37ec2012-07-24 10:47:44 -07001179 }
1180 } catch (RuntimeException ex) {
1181 if (ex instanceof NullPointerException && testNPE) {
1182 caughtEx = ex;
1183 break;
jrose485df122012-07-12 00:11:35 -07001184 }
jrosef15905c2011-02-11 01:26:32 -08001185 }
1186 if (f != null && f.getDeclaringClass() == HasFields.class) {
1187 assertEquals(f.get(fields), putValue);
1188 }
1189 }
1190 }
1191 if (f != null && f.getDeclaringClass() == HasFields.class) {
1192 f.set(fields, value); // put it back
1193 }
jrose485df122012-07-12 00:11:35 -07001194 if (testNPE) {
1195 if (caughtEx == null || !(caughtEx instanceof NullPointerException))
1196 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);
1197 caughtEx = null; // nullify expected exception
1198 }
1199 if (caughtEx != null) {
1200 throw new RuntimeException("unexpected exception", caughtEx);
1201 }
jrose55220c32009-10-21 23:19:48 -07001202 }
1203
jrose10f3b682010-01-07 16:16:45 -08001204
1205 @Test
jrose55220c32009-10-21 23:19:48 -07001206 public void testUnreflectSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001207 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001208 startTest("unreflectSetter");
1209 testSetter(TEST_UNREFLECT);
1210 }
1211 @Test
1212 public void testFindSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001213 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001214 startTest("findSetter");
1215 testSetter(TEST_FIND_FIELD);
twisti10d37ec2012-07-24 10:47:44 -07001216 testSetter(TEST_FIND_FIELD | TEST_BOUND);
jrosecf98d422010-06-08 23:08:56 -07001217 }
1218 @Test
1219 public void testFindStaticSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001220 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001221 startTest("findStaticSetter");
jrosef15905c2011-02-11 01:26:32 -08001222 testSetter(TEST_FIND_STATIC);
jrosecf98d422010-06-08 23:08:56 -07001223 }
1224 public void testSetter(int testMode) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001225 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
1226 startTest("unreflectSetter");
jrose10f3b682010-01-07 16:16:45 -08001227 for (Object[] c : HasFields.CASES) {
jrosef15905c2011-02-11 01:26:32 -08001228 boolean positive = (c[1] != Error.class);
1229 testSetter(positive, lookup, c[0], c[1], testMode);
jrose485df122012-07-12 00:11:35 -07001230 if (positive)
1231 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
jrosef15905c2011-02-11 01:26:32 -08001232 }
1233 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1234 testSetter(false, lookup,
1235 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1236 null, testMode);
jrose10f3b682010-01-07 16:16:45 -08001237 }
1238 }
jrosef15905c2011-02-11 01:26:32 -08001239 public void testSetter(boolean positive, MethodHandles.Lookup lookup,
1240 Object fieldRef, Object value, int testMode) throws Throwable {
1241 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER);
jrose55220c32009-10-21 23:19:48 -07001242 }
1243
jrose10f3b682010-01-07 16:16:45 -08001244 @Test
jrose55220c32009-10-21 23:19:48 -07001245 public void testArrayElementGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001246 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -07001247 startTest("arrayElementGetter");
jrose2cc9c832010-04-30 23:48:23 -07001248 testArrayElementGetterSetter(false);
jrose55220c32009-10-21 23:19:48 -07001249 }
1250
jrose10f3b682010-01-07 16:16:45 -08001251 @Test
jrose55220c32009-10-21 23:19:48 -07001252 public void testArrayElementSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001253 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -07001254 startTest("arrayElementSetter");
jrose2cc9c832010-04-30 23:48:23 -07001255 testArrayElementGetterSetter(true);
1256 }
1257
jrose485df122012-07-12 00:11:35 -07001258 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;
1259
jrose2cc9c832010-04-30 23:48:23 -07001260 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
jrose485df122012-07-12 00:11:35 -07001261 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);
jrose10f3b682010-01-07 16:16:45 -08001262 }
1263
jrose485df122012-07-12 00:11:35 -07001264 @Test
1265 public void testArrayElementErrors() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001266 if (CAN_SKIP_WORKING) return;
jrose485df122012-07-12 00:11:35 -07001267 startTest("arrayElementErrors");
1268 testArrayElementGetterSetter(false, TEST_ARRAY_NPE);
1269 testArrayElementGetterSetter(true, TEST_ARRAY_NPE);
1270 testArrayElementGetterSetter(false, TEST_ARRAY_OOB);
1271 testArrayElementGetterSetter(true, TEST_ARRAY_OOB);
1272 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);
1273 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);
1274 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);
1275 }
1276
1277 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {
1278 testArrayElementGetterSetter(new String[10], testSetter, negTest);
1279 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);
1280 testArrayElementGetterSetter(new Example[10], testSetter, negTest);
1281 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);
1282 testArrayElementGetterSetter(new Object[10], testSetter, negTest);
1283 testArrayElementGetterSetter(new boolean[10], testSetter, negTest);
1284 testArrayElementGetterSetter(new byte[10], testSetter, negTest);
1285 testArrayElementGetterSetter(new char[10], testSetter, negTest);
1286 testArrayElementGetterSetter(new short[10], testSetter, negTest);
1287 testArrayElementGetterSetter(new int[10], testSetter, negTest);
1288 testArrayElementGetterSetter(new float[10], testSetter, negTest);
1289 testArrayElementGetterSetter(new long[10], testSetter, negTest);
1290 testArrayElementGetterSetter(new double[10], testSetter, negTest);
1291 }
1292
1293 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {
1294 boolean positive = (negTest == TEST_ARRAY_NONE);
1295 int length = java.lang.reflect.Array.getLength(array);
jrose10f3b682010-01-07 16:16:45 -08001296 Class<?> arrayType = array.getClass();
1297 Class<?> elemType = arrayType.getComponentType();
jrose485df122012-07-12 00:11:35 -07001298 Object arrayToMH = array;
1299 // this stanza allows negative tests to make argument perturbations:
1300 switch (negTest) {
1301 case TEST_ARRAY_NPE:
1302 arrayToMH = null;
1303 break;
1304 case TEST_ARRAY_OOB:
1305 assert(length > 0);
1306 arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);
1307 break;
1308 case TEST_ARRAY_ASE:
1309 assert(testSetter && !elemType.isPrimitive());
1310 if (elemType == Object.class)
1311 arrayToMH = new StringBuffer[length]; // very random subclass of Object!
1312 else if (elemType == Example.class)
1313 arrayToMH = new SubExample[length];
1314 else if (elemType == IntExample.class)
1315 arrayToMH = new SubIntExample[length];
1316 else
1317 return; // can't make an ArrayStoreException test
1318 assert(arrayType.isInstance(arrayToMH))
1319 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);
1320 break;
1321 }
1322 countTest(positive);
1323 if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH})));
jrose10f3b682010-01-07 16:16:45 -08001324 MethodType expType = !testSetter
1325 ? MethodType.methodType(elemType, arrayType, int.class)
1326 : MethodType.methodType(void.class, arrayType, int.class, elemType);
1327 MethodHandle mh = !testSetter
1328 ? MethodHandles.arrayElementGetter(arrayType)
1329 : MethodHandles.arrayElementSetter(arrayType);
1330 assertSame(mh.type(), expType);
jrose2cc9c832010-04-30 23:48:23 -07001331 if (elemType != int.class && elemType != boolean.class) {
jrose485df122012-07-12 00:11:35 -07001332 MethodType gtype = mh.type().generic().changeParameterType(1, int.class);
jrose320b7692011-05-12 19:27:49 -07001333 if (testSetter) gtype = gtype.changeReturnType(void.class);
jrose9b82ad62011-05-26 17:37:36 -07001334 mh = mh.asType(gtype);
jrose2cc9c832010-04-30 23:48:23 -07001335 }
jrose10f3b682010-01-07 16:16:45 -08001336 Object sawValue, expValue;
1337 List<Object> model = array2list(array);
jrose485df122012-07-12 00:11:35 -07001338 Throwable caughtEx = null;
jrose10f3b682010-01-07 16:16:45 -08001339 for (int i = 0; i < length; i++) {
1340 // update array element
1341 Object random = randomArg(elemType);
1342 model.set(i, random);
1343 if (testSetter) {
jrose485df122012-07-12 00:11:35 -07001344 try {
1345 if (elemType == int.class)
1346 mh.invokeExact((int[]) arrayToMH, i, (int)random);
1347 else if (elemType == boolean.class)
1348 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);
1349 else
1350 mh.invokeExact(arrayToMH, i, random);
1351 } catch (RuntimeException ex) {
1352 caughtEx = ex;
1353 break;
1354 }
jrose10f3b682010-01-07 16:16:45 -08001355 assertEquals(model, array2list(array));
1356 } else {
1357 Array.set(array, i, random);
jrose2cc9c832010-04-30 23:48:23 -07001358 }
1359 if (verbosity >= 5) {
1360 List<Object> array2list = array2list(array);
1361 System.out.println("a["+i+"]="+random+" => "+array2list);
1362 if (!array2list.equals(model))
1363 System.out.println("*** != "+model);
jrose10f3b682010-01-07 16:16:45 -08001364 }
1365 // observe array element
1366 sawValue = Array.get(array, i);
1367 if (!testSetter) {
1368 expValue = sawValue;
jrose485df122012-07-12 00:11:35 -07001369 try {
1370 if (elemType == int.class)
1371 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);
1372 else if (elemType == boolean.class)
1373 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);
1374 else
1375 sawValue = mh.invokeExact(arrayToMH, i);
1376 } catch (RuntimeException ex) {
1377 caughtEx = ex;
1378 break;
1379 }
jrose10f3b682010-01-07 16:16:45 -08001380 assertEquals(sawValue, expValue);
1381 assertEquals(model, array2list(array));
1382 }
1383 }
jrose485df122012-07-12 00:11:35 -07001384 if (!positive) {
1385 if (caughtEx == null)
1386 throw new RuntimeException("failed to catch exception for negTest="+negTest);
1387 // test the kind of exception
1388 Class<?> reqType = null;
1389 switch (negTest) {
1390 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break;
1391 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break;
1392 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break;
1393 default: assert(false);
1394 }
1395 if (reqType.isInstance(caughtEx)) {
1396 caughtEx = null; // nullify expected exception
1397 }
1398 }
1399 if (caughtEx != null) {
1400 throw new RuntimeException("unexpected exception", caughtEx);
1401 }
jrose10f3b682010-01-07 16:16:45 -08001402 }
1403
1404 List<Object> array2list(Object array) {
1405 int length = Array.getLength(array);
jrose49494522012-01-18 17:34:29 -08001406 ArrayList<Object> model = new ArrayList<>(length);
jrose10f3b682010-01-07 16:16:45 -08001407 for (int i = 0; i < length; i++)
1408 model.add(Array.get(array, i));
1409 return model;
jrose55220c32009-10-21 23:19:48 -07001410 }
1411
1412 static class Callee {
1413 static Object id() { return called("id"); }
1414 static Object id(Object x) { return called("id", x); }
1415 static Object id(Object x, Object y) { return called("id", x, y); }
1416 static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }
1417 static Object id(Object... vx) { return called("id", vx); }
1418 static MethodHandle ofType(int n) {
1419 return ofType(Object.class, n);
1420 }
1421 static MethodHandle ofType(Class<?> rtype, int n) {
1422 if (n == -1)
jrose10f3b682010-01-07 16:16:45 -08001423 return ofType(MethodType.methodType(rtype, Object[].class));
1424 return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));
jrose55220c32009-10-21 23:19:48 -07001425 }
1426 static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {
jrose10f3b682010-01-07 16:16:45 -08001427 return ofType(MethodType.methodType(rtype, ptypes));
jrose55220c32009-10-21 23:19:48 -07001428 }
1429 static MethodHandle ofType(MethodType type) {
1430 Class<?> rtype = type.returnType();
1431 String pfx = "";
1432 if (rtype != Object.class)
1433 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
1434 String name = pfx+"id";
jrosea1ebbe62010-09-08 18:40:23 -07001435 try {
1436 return PRIVATE.findStatic(Callee.class, name, type);
jrose49494522012-01-18 17:34:29 -08001437 } catch (NoSuchMethodException | IllegalAccessException ex) {
jrosea1ebbe62010-09-08 18:40:23 -07001438 throw new RuntimeException(ex);
1439 }
jrose55220c32009-10-21 23:19:48 -07001440 }
1441 }
1442
1443 @Test
1444 public void testConvertArguments() throws Throwable {
1445 if (CAN_SKIP_WORKING) return;
1446 startTest("convertArguments");
1447 testConvert(Callee.ofType(1), null, "id", int.class);
1448 testConvert(Callee.ofType(1), null, "id", String.class);
1449 testConvert(Callee.ofType(1), null, "id", Integer.class);
1450 testConvert(Callee.ofType(1), null, "id", short.class);
jrose2cc9c832010-04-30 23:48:23 -07001451 testConvert(Callee.ofType(1), null, "id", char.class);
1452 testConvert(Callee.ofType(1), null, "id", byte.class);
jrose55220c32009-10-21 23:19:48 -07001453 }
1454
1455 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
jrose9b82ad62011-05-26 17:37:36 -07001456 testConvert(true, id, rtype, name, params);
jrose55220c32009-10-21 23:19:48 -07001457 }
1458
jrose9b82ad62011-05-26 17:37:36 -07001459 void testConvert(boolean positive,
jrose900bafd2010-10-30 21:08:23 -07001460 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001461 countTest(positive);
1462 MethodType idType = id.type();
1463 if (rtype == null) rtype = idType.returnType();
1464 for (int i = 0; i < params.length; i++) {
1465 if (params[i] == null) params[i] = idType.parameterType(i);
1466 }
1467 // simulate the pairwise conversion
jrose10f3b682010-01-07 16:16:45 -08001468 MethodType newType = MethodType.methodType(rtype, params);
jrose55220c32009-10-21 23:19:48 -07001469 Object[] args = randomArgs(newType.parameterArray());
1470 Object[] convArgs = args.clone();
1471 for (int i = 0; i < args.length; i++) {
1472 Class<?> src = newType.parameterType(i);
1473 Class<?> dst = idType.parameterType(i);
1474 if (src != dst)
1475 convArgs[i] = castToWrapper(convArgs[i], dst);
1476 }
jrose900bafd2010-10-30 21:08:23 -07001477 Object convResult = id.invokeWithArguments(convArgs);
jrose55220c32009-10-21 23:19:48 -07001478 {
1479 Class<?> dst = newType.returnType();
1480 Class<?> src = idType.returnType();
1481 if (src != dst)
1482 convResult = castToWrapper(convResult, dst);
1483 }
1484 MethodHandle target = null;
1485 RuntimeException error = null;
1486 try {
jrose9b82ad62011-05-26 17:37:36 -07001487 target = id.asType(newType);
jrose55220c32009-10-21 23:19:48 -07001488 } catch (RuntimeException ex) {
1489 error = ex;
1490 }
jrose2cc9c832010-04-30 23:48:23 -07001491 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -07001492 System.out.println("convert "+id+ " to "+newType+" => "+target
1493 +(error == null ? "" : " !! "+error));
1494 if (positive && error != null) throw error;
1495 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
1496 if (!positive) return; // negative test failed as expected
1497 assertEquals(newType, target.type());
1498 printCalled(target, id.toString(), args);
jrose900bafd2010-10-30 21:08:23 -07001499 Object result = target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -07001500 assertCalled(name, convArgs);
1501 assertEquals(convResult, result);
jrose2cc9c832010-04-30 23:48:23 -07001502 if (verbosity >= 1)
1503 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -07001504 }
1505
1506 @Test
jrosef108fc02011-02-11 01:26:24 -08001507 public void testVarargsCollector() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001508 if (CAN_SKIP_WORKING) return;
1509 startTest("varargsCollector");
jrosef108fc02011-02-11 01:26:24 -08001510 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called",
1511 MethodType.methodType(Object.class, String.class, Object[].class));
1512 vac0 = vac0.bindTo("vac");
1513 MethodHandle vac = vac0.asVarargsCollector(Object[].class);
jrose9b82ad62011-05-26 17:37:36 -07001514 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
1515 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
jrose49494522012-01-18 17:34:29 -08001516 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) {
jrose9b82ad62011-05-26 17:37:36 -07001517 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
1518 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
jrosef108fc02011-02-11 01:26:24 -08001519 }
1520 }
1521
twisti10d37ec2012-07-24 10:47:44 -07001522 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001523 public void testPermuteArguments() throws Throwable {
1524 if (CAN_SKIP_WORKING) return;
1525 startTest("permuteArguments");
jroseb4be0262011-07-16 15:44:33 -07001526 testPermuteArguments(4, Integer.class, 2, long.class, 6);
1527 if (CAN_TEST_LIGHTLY) return;
jrose10f3b682010-01-07 16:16:45 -08001528 testPermuteArguments(4, Integer.class, 2, String.class, 0);
jrose9b82ad62011-05-26 17:37:36 -07001529 testPermuteArguments(6, Integer.class, 0, null, 30);
jrose10f3b682010-01-07 16:16:45 -08001530 }
1531 public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -07001532 if (verbosity >= 2)
jrose10f3b682010-01-07 16:16:45 -08001533 System.out.println("permuteArguments "+max+"*"+type1.getName()
1534 +(t2c==0?"":"/"+t2c+"*"+type2.getName())
1535 +(dilution > 0 ? " with dilution "+dilution : ""));
1536 int t2pos = t2c == 0 ? 0 : 1;
1537 for (int inargs = t2pos+1; inargs <= max; inargs++) {
1538 Class<?>[] types = new Class<?>[inargs];
1539 Arrays.fill(types, type1);
1540 if (t2c != 0) {
1541 // Fill in a middle range with type2:
1542 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);
1543 }
1544 Object[] args = randomArgs(types);
1545 int numcases = 1;
1546 for (int outargs = 0; outargs <= max; outargs++) {
1547 if (outargs - inargs >= MAX_ARG_INCREASE) continue;
jrose10f3b682010-01-07 16:16:45 -08001548 int casStep = dilution + 1;
1549 // Avoid some common factors:
1550 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||
1551 (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))
1552 casStep++;
jrose320b7692011-05-12 19:27:49 -07001553 testPermuteArguments(args, types, outargs, numcases, casStep);
jrose10f3b682010-01-07 16:16:45 -08001554 numcases *= inargs;
jroseb4be0262011-07-16 15:44:33 -07001555 if (CAN_TEST_LIGHTLY && outargs < max-2) continue;
jrose10f3b682010-01-07 16:16:45 -08001556 if (dilution > 10 && outargs >= 4) {
jroseb4be0262011-07-16 15:44:33 -07001557 if (CAN_TEST_LIGHTLY) continue;
jrose320b7692011-05-12 19:27:49 -07001558 int[] reorder = new int[outargs];
jrose10f3b682010-01-07 16:16:45 -08001559 // Do some special patterns, which we probably missed.
1560 // Replication of a single argument or argument pair.
1561 for (int i = 0; i < inargs; i++) {
1562 Arrays.fill(reorder, i);
1563 testPermuteArguments(args, types, reorder);
1564 for (int d = 1; d <= 2; d++) {
1565 if (i + d >= inargs) continue;
1566 for (int j = 1; j < outargs; j += 2)
1567 reorder[j] += 1;
1568 testPermuteArguments(args, types, reorder);
1569 testPermuteArguments(args, types, reverse(reorder));
1570 }
1571 }
1572 // Repetition of a sequence of 3 or more arguments.
1573 for (int i = 1; i < inargs; i++) {
1574 for (int len = 3; len <= inargs; len++) {
1575 for (int j = 0; j < outargs; j++)
1576 reorder[j] = (i + (j % len)) % inargs;
1577 testPermuteArguments(args, types, reorder);
1578 testPermuteArguments(args, types, reverse(reorder));
1579 }
1580 }
1581 }
1582 }
1583 }
1584 }
1585
jrose320b7692011-05-12 19:27:49 -07001586 public void testPermuteArguments(Object[] args, Class<?>[] types,
1587 int outargs, int numcases, int casStep) throws Throwable {
1588 int inargs = args.length;
1589 int[] reorder = new int[outargs];
1590 for (int cas = 0; cas < numcases; cas += casStep) {
1591 for (int i = 0, c = cas; i < outargs; i++) {
1592 reorder[i] = c % inargs;
1593 c /= inargs;
1594 }
jroseb4be0262011-07-16 15:44:33 -07001595 if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2])) continue;
jrose320b7692011-05-12 19:27:49 -07001596 testPermuteArguments(args, types, reorder);
1597 }
1598 }
1599
jrose10f3b682010-01-07 16:16:45 -08001600 static int[] reverse(int[] reorder) {
1601 reorder = reorder.clone();
1602 for (int i = 0, imax = reorder.length / 2; i < imax; i++) {
1603 int j = reorder.length - 1 - i;
1604 int tem = reorder[i];
1605 reorder[i] = reorder[j];
1606 reorder[j] = tem;
1607 }
1608 return reorder;
1609 }
1610
1611 void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {
1612 countTest();
1613 if (args == null && types == null) {
1614 int max = 0;
1615 for (int j : reorder) {
1616 if (max < j) max = j;
1617 }
1618 args = randomArgs(max+1, Integer.class);
1619 }
1620 if (args == null) {
1621 args = randomArgs(types);
1622 }
1623 if (types == null) {
1624 types = new Class<?>[args.length];
1625 for (int i = 0; i < args.length; i++)
1626 types[i] = args[i].getClass();
1627 }
1628 int inargs = args.length, outargs = reorder.length;
jrosef15905c2011-02-11 01:26:32 -08001629 assertTrue(inargs == types.length);
jrose2cc9c832010-04-30 23:48:23 -07001630 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001631 System.out.println("permuteArguments "+Arrays.toString(reorder));
1632 Object[] permArgs = new Object[outargs];
1633 Class<?>[] permTypes = new Class<?>[outargs];
1634 for (int i = 0; i < outargs; i++) {
1635 permArgs[i] = args[reorder[i]];
1636 permTypes[i] = types[reorder[i]];
1637 }
jrose2cc9c832010-04-30 23:48:23 -07001638 if (verbosity >= 4) {
jrose10f3b682010-01-07 16:16:45 -08001639 System.out.println("in args: "+Arrays.asList(args));
1640 System.out.println("out args: "+Arrays.asList(permArgs));
1641 System.out.println("in types: "+Arrays.asList(types));
1642 System.out.println("out types: "+Arrays.asList(permTypes));
1643 }
1644 MethodType inType = MethodType.methodType(Object.class, types);
1645 MethodType outType = MethodType.methodType(Object.class, permTypes);
jrose9b82ad62011-05-26 17:37:36 -07001646 MethodHandle target = varargsList(outargs).asType(outType);
jrose10f3b682010-01-07 16:16:45 -08001647 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
jrose9b82ad62011-05-26 17:37:36 -07001648 if (verbosity >= 5) System.out.println("newTarget = "+newTarget);
jrose900bafd2010-10-30 21:08:23 -07001649 Object result = newTarget.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001650 Object expected = Arrays.asList(permArgs);
jrose320b7692011-05-12 19:27:49 -07001651 if (!expected.equals(result)) {
1652 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));
1653 System.out.println("in args: "+Arrays.asList(args));
1654 System.out.println("out args: "+expected);
1655 System.out.println("bad args: "+result);
1656 }
jrose10f3b682010-01-07 16:16:45 -08001657 assertEquals(expected, result);
1658 }
1659
1660
twisti10d37ec2012-07-24 10:47:44 -07001661 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001662 public void testSpreadArguments() throws Throwable {
1663 if (CAN_SKIP_WORKING) return;
1664 startTest("spreadArguments");
jrose49494522012-01-18 17:34:29 -08001665 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose2cc9c832010-04-30 23:48:23 -07001666 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001667 System.out.println("spreadArguments "+argType);
jroseb4be0262011-07-16 15:44:33 -07001668 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001669 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001670 for (int pos = 0; pos <= nargs; pos++) {
1671 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1672 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1673 continue;
1674 testSpreadArguments(argType, pos, nargs);
jrose10f3b682010-01-07 16:16:45 -08001675 }
1676 }
1677 }
1678 }
1679 public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
1680 countTest();
jrose320b7692011-05-12 19:27:49 -07001681 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1682 MethodHandle target2 = varargsArray(arrayType, nargs);
1683 MethodHandle target = target2.asType(target2.type().generic());
jrose2cc9c832010-04-30 23:48:23 -07001684 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001685 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
1686 Object[] args = randomArgs(target2.type().parameterArray());
1687 // make sure the target does what we think it does:
jrose320b7692011-05-12 19:27:49 -07001688 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
jrose49494522012-01-18 17:34:29 -08001689 Object[] check = (Object[]) target.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001690 assertArrayEquals(args, check);
1691 switch (nargs) {
1692 case 0:
jrose320b7692011-05-12 19:27:49 -07001693 check = (Object[]) (Object) target.invokeExact();
jrose10f3b682010-01-07 16:16:45 -08001694 assertArrayEquals(args, check);
1695 break;
1696 case 1:
jrose320b7692011-05-12 19:27:49 -07001697 check = (Object[]) (Object) target.invokeExact(args[0]);
jrose10f3b682010-01-07 16:16:45 -08001698 assertArrayEquals(args, check);
1699 break;
1700 case 2:
jrose320b7692011-05-12 19:27:49 -07001701 check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
jrose10f3b682010-01-07 16:16:45 -08001702 assertArrayEquals(args, check);
1703 break;
1704 }
1705 }
jrose49494522012-01-18 17:34:29 -08001706 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
jrose10f3b682010-01-07 16:16:45 -08001707 { // modify newParams in place
1708 List<Class<?>> spreadParams = newParams.subList(pos, nargs);
jrose320b7692011-05-12 19:27:49 -07001709 spreadParams.clear(); spreadParams.add(arrayType);
jrose10f3b682010-01-07 16:16:45 -08001710 }
jrose320b7692011-05-12 19:27:49 -07001711 MethodType newType = MethodType.methodType(arrayType, newParams);
1712 MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
1713 assert(result.type() == newType) : Arrays.asList(result, newType);
1714 result = result.asType(newType.generic());
1715 Object returnValue;
jrose10f3b682010-01-07 16:16:45 -08001716 if (pos == 0) {
jrose320b7692011-05-12 19:27:49 -07001717 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1718 returnValue = result.invokeExact(args2);
jrose10f3b682010-01-07 16:16:45 -08001719 } else {
1720 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
jrose320b7692011-05-12 19:27:49 -07001721 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1722 returnValue = result.invokeWithArguments(args1);
jrose10f3b682010-01-07 16:16:45 -08001723 }
jrose320b7692011-05-12 19:27:49 -07001724 String argstr = Arrays.toString(args);
1725 if (!argType.isPrimitive()) {
1726 Object[] rv = (Object[]) returnValue;
1727 String rvs = Arrays.toString(rv);
1728 if (!Arrays.equals(args, rv)) {
1729 System.out.println("method: "+result);
1730 System.out.println("expected: "+argstr);
1731 System.out.println("returned: "+rvs);
1732 assertArrayEquals(args, rv);
1733 }
1734 } else if (argType == int.class) {
1735 String rvs = Arrays.toString((int[]) returnValue);
1736 if (!argstr.equals(rvs)) {
1737 System.out.println("method: "+result);
1738 System.out.println("expected: "+argstr);
1739 System.out.println("returned: "+rvs);
1740 assertEquals(argstr, rvs);
1741 }
1742 } else if (argType == long.class) {
1743 String rvs = Arrays.toString((long[]) returnValue);
1744 if (!argstr.equals(rvs)) {
1745 System.out.println("method: "+result);
1746 System.out.println("expected: "+argstr);
1747 System.out.println("returned: "+rvs);
1748 assertEquals(argstr, rvs);
1749 }
1750 } else {
1751 // cannot test...
1752 }
jrose10f3b682010-01-07 16:16:45 -08001753 }
1754
twisti10d37ec2012-07-24 10:47:44 -07001755 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001756 public void testCollectArguments() throws Throwable {
1757 if (CAN_SKIP_WORKING) return;
1758 startTest("collectArguments");
jrose49494522012-01-18 17:34:29 -08001759 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose2cc9c832010-04-30 23:48:23 -07001760 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001761 System.out.println("collectArguments "+argType);
jroseb4be0262011-07-16 15:44:33 -07001762 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001763 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001764 for (int pos = 0; pos <= nargs; pos++) {
1765 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1766 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1767 continue;
jrose10f3b682010-01-07 16:16:45 -08001768 testCollectArguments(argType, pos, nargs);
1769 }
1770 }
1771 }
1772 }
1773 public void testCollectArguments(Class<?> argType, int pos, int nargs) throws Throwable {
1774 countTest();
1775 // fake up a MH with the same type as the desired adapter:
jroseadc650a2011-02-11 01:26:28 -08001776 MethodHandle fake = varargsArray(nargs);
jrose10f3b682010-01-07 16:16:45 -08001777 fake = changeArgTypes(fake, argType);
1778 MethodType newType = fake.type();
1779 Object[] args = randomArgs(newType.parameterArray());
1780 // here is what should happen:
1781 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
1782 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
1783 // here is the MH which will witness the collected argument tail:
jroseadc650a2011-02-11 01:26:28 -08001784 MethodHandle target = varargsArray(pos+1);
jrose10f3b682010-01-07 16:16:45 -08001785 target = changeArgTypes(target, 0, pos, argType);
1786 target = changeArgTypes(target, pos, pos+1, Object[].class);
jrose2cc9c832010-04-30 23:48:23 -07001787 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001788 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
jroseadc650a2011-02-11 01:26:28 -08001789 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
jrose900bafd2010-10-30 21:08:23 -07001790 Object[] returnValue = (Object[]) result.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001791// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
1792// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
1793// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
1794 assertArrayEquals(collectedArgs, returnValue);
1795 }
1796
twisti10d37ec2012-07-24 10:47:44 -07001797 @Test // SLOW
jrose55220c32009-10-21 23:19:48 -07001798 public void testInsertArguments() throws Throwable {
1799 if (CAN_SKIP_WORKING) return;
1800 startTest("insertArguments");
jroseb4be0262011-07-16 15:44:33 -07001801 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001802 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001803 for (int ins = 0; ins <= nargs; ins++) {
1804 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
1805 continue;
jrose55220c32009-10-21 23:19:48 -07001806 for (int pos = 0; pos <= nargs; pos++) {
jroseb4be0262011-07-16 15:44:33 -07001807 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1808 continue;
1809 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
jrose55220c32009-10-21 23:19:48 -07001810 testInsertArguments(nargs, pos, ins);
1811 }
1812 }
1813 }
1814 }
1815
1816 void testInsertArguments(int nargs, int pos, int ins) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001817 countTest();
jroseadc650a2011-02-11 01:26:28 -08001818 MethodHandle target = varargsArray(nargs + ins);
jrose55220c32009-10-21 23:19:48 -07001819 Object[] args = randomArgs(target.type().parameterArray());
1820 List<Object> resList = Arrays.asList(args);
jrose49494522012-01-18 17:34:29 -08001821 List<Object> argsToPass = new ArrayList<>(resList);
jrose55220c32009-10-21 23:19:48 -07001822 List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
jrose2cc9c832010-04-30 23:48:23 -07001823 if (verbosity >= 3)
twisti10d37ec2012-07-24 10:47:44 -07001824 System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
jrose49494522012-01-18 17:34:29 -08001825 @SuppressWarnings("cast") // cast to spread Object... is helpful
jrose10f3b682010-01-07 16:16:45 -08001826 MethodHandle target2 = MethodHandles.insertArguments(target, pos,
jrose49494522012-01-18 17:34:29 -08001827 (Object[]/*...*/) argsToInsert.toArray());
jrose55220c32009-10-21 23:19:48 -07001828 argsToInsert.clear(); // remove from argsToInsert
jrose900bafd2010-10-30 21:08:23 -07001829 Object res2 = target2.invokeWithArguments(argsToPass);
jrose55220c32009-10-21 23:19:48 -07001830 Object res2List = Arrays.asList((Object[])res2);
jrose2cc9c832010-04-30 23:48:23 -07001831 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -07001832 System.out.println("result: "+res2List);
1833 //if (!resList.equals(res2List))
1834 // System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
1835 assertEquals(resList, res2List);
1836 }
1837
jrose10f3b682010-01-07 16:16:45 -08001838 @Test
jroseadc650a2011-02-11 01:26:28 -08001839 public void testFilterReturnValue() throws Throwable {
1840 if (CAN_SKIP_WORKING) return;
1841 startTest("filterReturnValue");
1842 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass();
1843 assertTrue(List.class.isAssignableFrom(classOfVCList));
1844 for (int nargs = 0; nargs <= 3; nargs++) {
jrose49494522012-01-18 17:34:29 -08001845 for (Class<?> rtype : new Class<?>[] { Object.class,
jroseadc650a2011-02-11 01:26:28 -08001846 List.class,
1847 int.class,
jroseb4be0262011-07-16 15:44:33 -07001848 byte.class,
1849 long.class,
jroseadc650a2011-02-11 01:26:28 -08001850 CharSequence.class,
1851 String.class }) {
1852 testFilterReturnValue(nargs, rtype);
1853 }
1854 }
1855 }
1856
1857 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable {
1858 countTest();
1859 MethodHandle target = varargsList(nargs, rtype);
1860 MethodHandle filter;
1861 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class))
1862 filter = varargsList(1); // add another layer of list-ness
1863 else
1864 filter = MethodHandles.identity(rtype);
1865 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype));
1866 Object[] argsToPass = randomArgs(nargs, Object.class);
1867 if (verbosity >= 3)
1868 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter);
1869 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter);
1870 if (verbosity >= 4)
1871 System.out.println("filtered target: "+target2);
1872 // Simulate expected effect of filter on return value:
1873 Object unfiltered = target.invokeWithArguments(argsToPass);
1874 Object expected = filter.invokeWithArguments(unfiltered);
1875 if (verbosity >= 4)
1876 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName());
1877 if (verbosity >= 4)
1878 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName());
1879 Object result = target2.invokeWithArguments(argsToPass);
1880 if (verbosity >= 3)
1881 System.out.println("result: "+result+" : "+result.getClass().getSimpleName());
1882 if (!expected.equals(result))
1883 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
1884 assertEquals(expected, result);
1885 }
1886
1887 @Test
jrose10f3b682010-01-07 16:16:45 -08001888 public void testFilterArguments() throws Throwable {
1889 if (CAN_SKIP_WORKING) return;
1890 startTest("filterArguments");
1891 for (int nargs = 1; nargs <= 6; nargs++) {
1892 for (int pos = 0; pos < nargs; pos++) {
1893 testFilterArguments(nargs, pos);
1894 }
1895 }
1896 }
1897
1898 void testFilterArguments(int nargs, int pos) throws Throwable {
1899 countTest();
jroseadc650a2011-02-11 01:26:28 -08001900 MethodHandle target = varargsList(nargs);
1901 MethodHandle filter = varargsList(1);
jrose9b82ad62011-05-26 17:37:36 -07001902 filter = filter.asType(filter.type().generic());
jrose10f3b682010-01-07 16:16:45 -08001903 Object[] argsToPass = randomArgs(nargs, Object.class);
jrose2cc9c832010-04-30 23:48:23 -07001904 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001905 System.out.println("filter "+target+" at "+pos+" with "+filter);
jrose900bafd2010-10-30 21:08:23 -07001906 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);
jrose10f3b682010-01-07 16:16:45 -08001907 // Simulate expected effect of filter on arglist:
1908 Object[] filteredArgs = argsToPass.clone();
jrose2cc9c832010-04-30 23:48:23 -07001909 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
jrose10f3b682010-01-07 16:16:45 -08001910 List<Object> expected = Arrays.asList(filteredArgs);
jrose900bafd2010-10-30 21:08:23 -07001911 Object result = target2.invokeWithArguments(argsToPass);
jrose2cc9c832010-04-30 23:48:23 -07001912 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001913 System.out.println("result: "+result);
1914 if (!expected.equals(result))
jroseadc650a2011-02-11 01:26:28 -08001915 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
jrose10f3b682010-01-07 16:16:45 -08001916 assertEquals(expected, result);
1917 }
1918
1919 @Test
1920 public void testFoldArguments() throws Throwable {
1921 if (CAN_SKIP_WORKING) return;
1922 startTest("foldArguments");
1923 for (int nargs = 0; nargs <= 4; nargs++) {
1924 for (int fold = 0; fold <= nargs; fold++) {
1925 for (int pos = 0; pos <= nargs; pos++) {
1926 testFoldArguments(nargs, pos, fold);
1927 }
1928 }
1929 }
1930 }
1931
1932 void testFoldArguments(int nargs, int pos, int fold) throws Throwable {
1933 if (pos != 0) return; // can fold only at pos=0 for now
1934 countTest();
jroseadc650a2011-02-11 01:26:28 -08001935 MethodHandle target = varargsList(1 + nargs);
1936 MethodHandle combine = varargsList(fold).asType(MethodType.genericMethodType(fold));
jrose10f3b682010-01-07 16:16:45 -08001937 List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
jrose2cc9c832010-04-30 23:48:23 -07001938 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001939 System.out.println("fold "+target+" with "+combine);
1940 MethodHandle target2 = MethodHandles.foldArguments(target, combine);
1941 // Simulate expected effect of combiner on arglist:
jrose49494522012-01-18 17:34:29 -08001942 List<Object> expected = new ArrayList<>(argsToPass);
jrose10f3b682010-01-07 16:16:45 -08001943 List<Object> argsToFold = expected.subList(pos, pos + fold);
jrose2cc9c832010-04-30 23:48:23 -07001944 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001945 System.out.println("fold: "+argsToFold+" into "+target2);
jrose900bafd2010-10-30 21:08:23 -07001946 Object foldedArgs = combine.invokeWithArguments(argsToFold);
jrose10f3b682010-01-07 16:16:45 -08001947 argsToFold.add(0, foldedArgs);
jrose900bafd2010-10-30 21:08:23 -07001948 Object result = target2.invokeWithArguments(argsToPass);
jrose2cc9c832010-04-30 23:48:23 -07001949 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001950 System.out.println("result: "+result);
1951 if (!expected.equals(result))
jroseadc650a2011-02-11 01:26:28 -08001952 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
jrose10f3b682010-01-07 16:16:45 -08001953 assertEquals(expected, result);
1954 }
1955
1956 @Test
1957 public void testDropArguments() throws Throwable {
1958 if (CAN_SKIP_WORKING) return;
1959 startTest("dropArguments");
1960 for (int nargs = 0; nargs <= 4; nargs++) {
1961 for (int drop = 1; drop <= 4; drop++) {
1962 for (int pos = 0; pos <= nargs; pos++) {
1963 testDropArguments(nargs, pos, drop);
1964 }
1965 }
1966 }
1967 }
1968
1969 void testDropArguments(int nargs, int pos, int drop) throws Throwable {
1970 countTest();
jroseadc650a2011-02-11 01:26:28 -08001971 MethodHandle target = varargsArray(nargs);
jrose10f3b682010-01-07 16:16:45 -08001972 Object[] args = randomArgs(target.type().parameterArray());
1973 MethodHandle target2 = MethodHandles.dropArguments(target, pos,
jrose49494522012-01-18 17:34:29 -08001974 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0]));
jrose10f3b682010-01-07 16:16:45 -08001975 List<Object> resList = Arrays.asList(args);
jrose49494522012-01-18 17:34:29 -08001976 List<Object> argsToDrop = new ArrayList<>(resList);
jrose10f3b682010-01-07 16:16:45 -08001977 for (int i = drop; i > 0; i--) {
1978 argsToDrop.add(pos, "blort#"+i);
1979 }
jrose900bafd2010-10-30 21:08:23 -07001980 Object res2 = target2.invokeWithArguments(argsToDrop);
jrose10f3b682010-01-07 16:16:45 -08001981 Object res2List = Arrays.asList((Object[])res2);
1982 //if (!resList.equals(res2List))
1983 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
1984 assertEquals(resList, res2List);
1985 }
1986
twisti10d37ec2012-07-24 10:47:44 -07001987 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001988 public void testInvokers() throws Throwable {
1989 if (CAN_SKIP_WORKING) return;
1990 startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
1991 // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
jrose49494522012-01-18 17:34:29 -08001992 Set<MethodType> done = new HashSet<>();
jrose10f3b682010-01-07 16:16:45 -08001993 for (int i = 0; i <= 6; i++) {
jroseb4be0262011-07-16 15:44:33 -07001994 if (CAN_TEST_LIGHTLY && i > 3) break;
jrose10f3b682010-01-07 16:16:45 -08001995 MethodType gtype = MethodType.genericMethodType(i);
jrose49494522012-01-18 17:34:29 -08001996 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose10f3b682010-01-07 16:16:45 -08001997 for (int j = -1; j < i; j++) {
1998 MethodType type = gtype;
1999 if (j < 0)
2000 type = type.changeReturnType(argType);
2001 else if (argType == void.class)
2002 continue;
2003 else
2004 type = type.changeParameterType(j, argType);
jrose10f3b682010-01-07 16:16:45 -08002005 if (done.add(type))
2006 testInvokers(type);
2007 MethodType vtype = type.changeReturnType(void.class);
2008 if (done.add(vtype))
2009 testInvokers(vtype);
2010 }
2011 }
2012 }
2013 }
2014
2015 public void testInvokers(MethodType type) throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -07002016 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002017 System.out.println("test invokers for "+type);
2018 int nargs = type.parameterCount();
2019 boolean testRetCode = type.returnType() != void.class;
2020 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",
2021 MethodType.genericMethodType(0, true));
jroseadc650a2011-02-11 01:26:28 -08002022 assertTrue(target.isVarargsCollector());
2023 target = target.asType(type);
jrose10f3b682010-01-07 16:16:45 -08002024 Object[] args = randomArgs(type.parameterArray());
jrose49494522012-01-18 17:34:29 -08002025 List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args));
jrose10f3b682010-01-07 16:16:45 -08002026 targetPlusArgs.add(0, target);
2027 int code = (Integer) invokee(args);
2028 Object log = logEntry("invokee", args);
2029 assertEquals(log.hashCode(), code);
2030 assertCalled("invokee", args);
2031 MethodHandle inv;
2032 Object result;
2033 // exact invoker
2034 countTest();
2035 calledLog.clear();
2036 inv = MethodHandles.exactInvoker(type);
jrose900bafd2010-10-30 21:08:23 -07002037 result = inv.invokeWithArguments(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002038 if (testRetCode) assertEquals(code, result);
2039 assertCalled("invokee", args);
2040 // generic invoker
2041 countTest();
jrose79e0a6c2011-05-12 19:27:33 -07002042 inv = MethodHandles.invoker(type);
jrose9b82ad62011-05-26 17:37:36 -07002043 if (nargs <= 3 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002044 calledLog.clear();
2045 switch (nargs) {
2046 case 0:
jrose2cc9c832010-04-30 23:48:23 -07002047 result = inv.invokeExact(target);
jrose10f3b682010-01-07 16:16:45 -08002048 break;
2049 case 1:
jrose2cc9c832010-04-30 23:48:23 -07002050 result = inv.invokeExact(target, args[0]);
jrose10f3b682010-01-07 16:16:45 -08002051 break;
2052 case 2:
jrose2cc9c832010-04-30 23:48:23 -07002053 result = inv.invokeExact(target, args[0], args[1]);
jrose10f3b682010-01-07 16:16:45 -08002054 break;
2055 case 3:
jrose2cc9c832010-04-30 23:48:23 -07002056 result = inv.invokeExact(target, args[0], args[1], args[2]);
jrose10f3b682010-01-07 16:16:45 -08002057 break;
2058 }
2059 if (testRetCode) assertEquals(code, result);
2060 assertCalled("invokee", args);
2061 }
2062 calledLog.clear();
jrose900bafd2010-10-30 21:08:23 -07002063 result = inv.invokeWithArguments(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002064 if (testRetCode) assertEquals(code, result);
2065 assertCalled("invokee", args);
2066 // varargs invoker #0
2067 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002068 inv = MethodHandles.spreadInvoker(type, 0);
jrose9b82ad62011-05-26 17:37:36 -07002069 if (type.returnType() == Object.class) {
2070 result = inv.invokeExact(target, args);
2071 } else if (type.returnType() == void.class) {
2072 result = null; inv.invokeExact(target, args);
2073 } else {
2074 result = inv.invokeWithArguments(target, (Object) args);
2075 }
jrose10f3b682010-01-07 16:16:45 -08002076 if (testRetCode) assertEquals(code, result);
2077 assertCalled("invokee", args);
jrose9b82ad62011-05-26 17:37:36 -07002078 if (nargs >= 1 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002079 // varargs invoker #1
2080 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002081 inv = MethodHandles.spreadInvoker(type, 1);
jrose2cc9c832010-04-30 23:48:23 -07002082 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs));
jrose10f3b682010-01-07 16:16:45 -08002083 if (testRetCode) assertEquals(code, result);
2084 assertCalled("invokee", args);
2085 }
jrose9b82ad62011-05-26 17:37:36 -07002086 if (nargs >= 2 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002087 // varargs invoker #2
2088 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002089 inv = MethodHandles.spreadInvoker(type, 2);
jrose2cc9c832010-04-30 23:48:23 -07002090 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
jrose10f3b682010-01-07 16:16:45 -08002091 if (testRetCode) assertEquals(code, result);
2092 assertCalled("invokee", args);
2093 }
jrose9b82ad62011-05-26 17:37:36 -07002094 if (nargs >= 3 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002095 // varargs invoker #3
2096 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002097 inv = MethodHandles.spreadInvoker(type, 3);
jrose2cc9c832010-04-30 23:48:23 -07002098 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
jrose10f3b682010-01-07 16:16:45 -08002099 if (testRetCode) assertEquals(code, result);
2100 assertCalled("invokee", args);
2101 }
2102 for (int k = 0; k <= nargs; k++) {
2103 // varargs invoker #0..N
jroseb4be0262011-07-16 15:44:33 -07002104 if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue;
jrose10f3b682010-01-07 16:16:45 -08002105 countTest();
2106 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002107 inv = MethodHandles.spreadInvoker(type, k);
jrose9b82ad62011-05-26 17:37:36 -07002108 MethodType expType = (type.dropParameterTypes(k, nargs)
2109 .appendParameterTypes(Object[].class)
2110 .insertParameterTypes(0, MethodHandle.class));
2111 assertEquals(expType, inv.type());
jrose49494522012-01-18 17:34:29 -08002112 List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002113 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
2114 Object[] tail = tailList.toArray();
2115 tailList.clear(); tailList.add(tail);
jrose900bafd2010-10-30 21:08:23 -07002116 result = inv.invokeWithArguments(targetPlusVarArgs);
jrose10f3b682010-01-07 16:16:45 -08002117 if (testRetCode) assertEquals(code, result);
2118 assertCalled("invokee", args);
2119 }
jrose900bafd2010-10-30 21:08:23 -07002120
jrose10f3b682010-01-07 16:16:45 -08002121 // dynamic invoker
2122 countTest();
jroseb90d2e72010-12-16 15:59:27 -08002123 CallSite site = new MutableCallSite(type);
2124 inv = site.dynamicInvoker();
jrose900bafd2010-10-30 21:08:23 -07002125
2126 // see if we get the result of the original target:
2127 try {
2128 result = inv.invokeWithArguments(args);
2129 assertTrue("should not reach here", false);
2130 } catch (IllegalStateException ex) {
2131 String msg = ex.getMessage();
2132 assertTrue(msg, msg.contains("site"));
2133 }
2134
2135 // set new target after invoker is created, to make sure we track target
jrose10f3b682010-01-07 16:16:45 -08002136 site.setTarget(target);
2137 calledLog.clear();
jrose900bafd2010-10-30 21:08:23 -07002138 result = inv.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08002139 if (testRetCode) assertEquals(code, result);
2140 assertCalled("invokee", args);
2141 }
2142
2143 static Object invokee(Object... args) {
2144 return called("invokee", args).hashCode();
2145 }
2146
jrose55220c32009-10-21 23:19:48 -07002147 private static final String MISSING_ARG = "missingArg";
jroseb4be0262011-07-16 15:44:33 -07002148 private static final String MISSING_ARG_2 = "missingArg#2";
jrose55220c32009-10-21 23:19:48 -07002149 static Object targetIfEquals() {
2150 return called("targetIfEquals");
2151 }
2152 static Object fallbackIfNotEquals() {
2153 return called("fallbackIfNotEquals");
2154 }
2155 static Object targetIfEquals(Object x) {
2156 assertEquals(x, MISSING_ARG);
2157 return called("targetIfEquals", x);
2158 }
2159 static Object fallbackIfNotEquals(Object x) {
2160 assertFalse(x.toString(), x.equals(MISSING_ARG));
2161 return called("fallbackIfNotEquals", x);
2162 }
2163 static Object targetIfEquals(Object x, Object y) {
2164 assertEquals(x, y);
2165 return called("targetIfEquals", x, y);
2166 }
2167 static Object fallbackIfNotEquals(Object x, Object y) {
2168 assertFalse(x.toString(), x.equals(y));
2169 return called("fallbackIfNotEquals", x, y);
2170 }
2171 static Object targetIfEquals(Object x, Object y, Object z) {
2172 assertEquals(x, y);
2173 return called("targetIfEquals", x, y, z);
2174 }
2175 static Object fallbackIfNotEquals(Object x, Object y, Object z) {
2176 assertFalse(x.toString(), x.equals(y));
2177 return called("fallbackIfNotEquals", x, y, z);
2178 }
2179
jrose10f3b682010-01-07 16:16:45 -08002180 @Test
2181 public void testGuardWithTest() throws Throwable {
2182 if (CAN_SKIP_WORKING) return;
2183 startTest("guardWithTest");
jroseb4be0262011-07-16 15:44:33 -07002184 for (int nargs = 0; nargs <= 50; nargs++) {
2185 if (CAN_TEST_LIGHTLY && nargs > 7) break;
jrose10f3b682010-01-07 16:16:45 -08002186 testGuardWithTest(nargs, Object.class);
2187 testGuardWithTest(nargs, String.class);
2188 }
2189 }
2190 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {
jroseb4be0262011-07-16 15:44:33 -07002191 testGuardWithTest(nargs, 0, argClass);
2192 if (nargs <= 5 || nargs % 10 == 3) {
2193 for (int testDrops = 1; testDrops <= nargs; testDrops++)
2194 testGuardWithTest(nargs, testDrops, argClass);
2195 }
2196 }
2197 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08002198 countTest();
jroseb4be0262011-07-16 15:44:33 -07002199 int nargs1 = Math.min(3, nargs);
jrose10f3b682010-01-07 16:16:45 -08002200 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
jroseb4be0262011-07-16 15:44:33 -07002201 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1));
2202 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1));
jrose10f3b682010-01-07 16:16:45 -08002203 while (test.type().parameterCount() > nargs)
jroseb4be0262011-07-16 15:44:33 -07002204 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG))
2205 // 1: test = lambda (_) MISSING_ARG.equals(_)
jrose10f3b682010-01-07 16:16:45 -08002206 test = MethodHandles.insertArguments(test, 0, MISSING_ARG);
2207 if (argClass != Object.class) {
2208 test = changeArgTypes(test, argClass);
2209 target = changeArgTypes(target, argClass);
2210 fallback = changeArgTypes(fallback, argClass);
2211 }
jroseb4be0262011-07-16 15:44:33 -07002212 int testArgs = nargs - testDrops;
2213 assert(testArgs >= 0);
2214 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass);
2215 target = addTrailingArgs(target, nargs, argClass);
2216 fallback = addTrailingArgs(fallback, nargs, argClass);
jrose10f3b682010-01-07 16:16:45 -08002217 Object[][] argLists = {
2218 { },
2219 { "foo" }, { MISSING_ARG },
2220 { "foo", "foo" }, { "foo", "bar" },
2221 { "foo", "foo", "baz" }, { "foo", "bar", "baz" }
2222 };
2223 for (Object[] argList : argLists) {
jroseb4be0262011-07-16 15:44:33 -07002224 Object[] argList1 = argList;
2225 if (argList.length != nargs) {
2226 if (argList.length != nargs1) continue;
2227 argList1 = Arrays.copyOf(argList, nargs);
2228 Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2);
2229 }
2230 MethodHandle test1 = test;
2231 if (test1.type().parameterCount() > testArgs) {
2232 int pc = test1.type().parameterCount();
2233 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
2234 }
2235 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
2236 assertEquals(target.type(), mh.type());
jrose10f3b682010-01-07 16:16:45 -08002237 boolean equals;
2238 switch (nargs) {
2239 case 0: equals = true; break;
2240 case 1: equals = MISSING_ARG.equals(argList[0]); break;
2241 default: equals = argList[0].equals(argList[1]); break;
2242 }
2243 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
jrose2cc9c832010-04-30 23:48:23 -07002244 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002245 System.out.println(logEntry(willCall, argList));
jroseb4be0262011-07-16 15:44:33 -07002246 Object result = mh.invokeWithArguments(argList1);
jrose10f3b682010-01-07 16:16:45 -08002247 assertCalled(willCall, argList);
2248 }
2249 }
2250
2251 @Test
2252 public void testCatchException() throws Throwable {
2253 if (CAN_SKIP_WORKING) return;
2254 startTest("catchException");
jroseb4be0262011-07-16 15:44:33 -07002255 for (int nargs = 0; nargs < 40; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07002256 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07002257 for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) {
2258 testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs);
2259 if (CAN_TEST_LIGHTLY && nargs > 3) continue;
2260 testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs);
2261 testCatchException(String.class, new LinkageError("testing"), throwMode, nargs);
jrose10f3b682010-01-07 16:16:45 -08002262 }
2263 }
2264 }
2265
jroseb4be0262011-07-16 15:44:33 -07002266 static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4;
2267
2268 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable {
2269 testCatchException(returnType, thrown, throwMode, nargs, 0);
2270 if (nargs <= 5 || nargs % 10 == 3) {
2271 for (int catchDrops = 1; catchDrops <= nargs; catchDrops++)
2272 testCatchException(returnType, thrown, throwMode, nargs, catchDrops);
2273 }
2274 }
2275
jrose10f3b682010-01-07 16:16:45 -08002276 private static <T extends Throwable>
2277 Object throwOrReturn(Object normal, T exception) throws T {
jroseb4be0262011-07-16 15:44:33 -07002278 if (exception != null) {
2279 called("throwOrReturn/throw", normal, exception);
2280 throw exception;
2281 }
2282 called("throwOrReturn/normal", normal, exception);
jrose10f3b682010-01-07 16:16:45 -08002283 return normal;
2284 }
jroseb4be0262011-07-16 15:44:33 -07002285 private int fakeIdentityCount;
2286 private Object fakeIdentity(Object x) {
2287 System.out.println("should throw through this!");
2288 fakeIdentityCount++;
2289 return x;
2290 }
jrose10f3b682010-01-07 16:16:45 -08002291
jroseb4be0262011-07-16 15:44:33 -07002292 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08002293 countTest();
jrose2cc9c832010-04-30 23:48:23 -07002294 if (verbosity >= 3)
jroseb4be0262011-07-16 15:44:33 -07002295 System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops);
jrose10f3b682010-01-07 16:16:45 -08002296 Class<? extends Throwable> exType = thrown.getClass();
jroseb4be0262011-07-16 15:44:33 -07002297 if (throwMode > THROW_CAUGHT) thrown = new UnsupportedOperationException("do not catch this");
jrose10f3b682010-01-07 16:16:45 -08002298 MethodHandle throwOrReturn
2299 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
2300 MethodType.methodType(Object.class, Object.class, Throwable.class));
jroseb4be0262011-07-16 15:44:33 -07002301 if (throwMode == THROW_THROUGH_ADAPTER) {
2302 MethodHandle fakeIdentity
2303 = PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity",
2304 MethodType.methodType(Object.class, Object.class)).bindTo(this);
2305 for (int i = 0; i < 10; i++)
2306 throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity);
2307 }
2308 int nargs1 = Math.max(2, nargs);
jroseb90d2e72010-12-16 15:59:27 -08002309 MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
jroseb4be0262011-07-16 15:44:33 -07002310 thrower = addTrailingArgs(thrower, nargs, Object.class);
2311 int catchArgc = 1 + nargs - catchDrops;
2312 MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc));
jrose10f3b682010-01-07 16:16:45 -08002313 Object[] args = randomArgs(nargs, Object.class);
jroseb4be0262011-07-16 15:44:33 -07002314 Object arg0 = MISSING_ARG;
2315 Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown;
2316 if (nargs > 0) arg0 = args[0];
2317 if (nargs > 1) args[1] = arg1;
2318 assertEquals(nargs1, thrower.type().parameterCount());
2319 if (nargs < nargs1) {
2320 Object[] appendArgs = { arg0, arg1 };
2321 appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1);
2322 thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs);
2323 }
2324 assertEquals(nargs, thrower.type().parameterCount());
2325 MethodHandle target = MethodHandles.catchException(thrower, exType, catcher);
2326 assertEquals(thrower.type(), target.type());
2327 assertEquals(nargs, target.type().parameterCount());
2328 //System.out.println("catching with "+target+" : "+throwOrReturn);
2329 Object returned;
2330 try {
2331 returned = target.invokeWithArguments(args);
2332 } catch (Throwable ex) {
2333 assertSame("must get the out-of-band exception", thrown, ex);
2334 if (throwMode <= THROW_CAUGHT)
2335 assertEquals(THROW_UNCAUGHT, throwMode);
2336 returned = ex;
2337 }
2338 assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1);
jrose10f3b682010-01-07 16:16:45 -08002339 //System.out.println("return from "+target+" : "+returned);
jroseb4be0262011-07-16 15:44:33 -07002340 if (throwMode == THROW_NOTHING) {
2341 assertSame(arg0, returned);
2342 } else if (throwMode == THROW_CAUGHT) {
jrose49494522012-01-18 17:34:29 -08002343 List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
jroseb4be0262011-07-16 15:44:33 -07002344 // catcher receives an initial subsequence of target arguments:
2345 catchArgs.subList(nargs - catchDrops, nargs).clear();
2346 // catcher also receives the exception, prepended:
jrose10f3b682010-01-07 16:16:45 -08002347 catchArgs.add(0, thrown);
2348 assertEquals(catchArgs, returned);
2349 }
jroseb4be0262011-07-16 15:44:33 -07002350 assertEquals(0, fakeIdentityCount);
jrose10f3b682010-01-07 16:16:45 -08002351 }
2352
2353 @Test
2354 public void testThrowException() throws Throwable {
2355 if (CAN_SKIP_WORKING) return;
2356 startTest("throwException");
2357 testThrowException(int.class, new ClassCastException("testing"));
2358 testThrowException(void.class, new java.io.IOException("testing"));
2359 testThrowException(String.class, new LinkageError("testing"));
2360 }
2361
2362 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
2363 countTest();
2364 Class<? extends Throwable> exType = thrown.getClass();
2365 MethodHandle target = MethodHandles.throwException(returnType, exType);
2366 //System.out.println("throwing with "+target+" : "+thrown);
2367 MethodType expectedType = MethodType.methodType(returnType, exType);
2368 assertEquals(expectedType, target.type());
jrose9b82ad62011-05-26 17:37:36 -07002369 target = target.asType(target.type().generic());
jrose10f3b682010-01-07 16:16:45 -08002370 Throwable caught = null;
2371 try {
jrose2cc9c832010-04-30 23:48:23 -07002372 Object res = target.invokeExact((Object) thrown);
jrose10f3b682010-01-07 16:16:45 -08002373 fail("got "+res+" instead of throwing "+thrown);
2374 } catch (Throwable ex) {
2375 if (ex != thrown) {
2376 if (ex instanceof Error) throw (Error)ex;
2377 if (ex instanceof RuntimeException) throw (RuntimeException)ex;
2378 }
2379 caught = ex;
2380 }
2381 assertSame(thrown, caught);
2382 }
2383
twisti10d37ec2012-07-24 10:47:44 -07002384 //@Test
jroseb4be0262011-07-16 15:44:33 -07002385 public void testInterfaceCast() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07002386 //if (CAN_SKIP_WORKING) return;
2387 startTest("interfaceCast");
jroseb4be0262011-07-16 15:44:33 -07002388 for (Class<?> ctype : new Class<?>[]{ Object.class, String.class, CharSequence.class, Number.class, Iterable.class}) {
2389 testInterfaceCast(ctype, false, false);
2390 testInterfaceCast(ctype, true, false);
2391 testInterfaceCast(ctype, false, true);
2392 testInterfaceCast(ctype, true, true);
2393 }
2394 }
2395 public void testInterfaceCast(Class<?> ctype, boolean doret, boolean docast) throws Throwable {
2396 String str = "normal return value";
2397 MethodHandle mh = MethodHandles.identity(String.class);
2398 MethodType mt = mh.type();
2399 if (doret) mt = mt.changeReturnType(ctype);
2400 else mt = mt.changeParameterType(0, ctype);
2401 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt);
2402 else mh = mh.asType(mt);
2403 // this bit is needed to make the interface types disappear for invokeWithArguments:
2404 mh = MethodHandles.explicitCastArguments(mh, mt.generic());
2405 boolean expectFail = !ctype.isInstance(str);
2406 if (ctype.isInterface()) {
2407 // special rules: interfaces slide by more frequently
2408 if (docast || !doret) expectFail = false;
2409 }
2410 Object res;
2411 try {
2412 res = mh.invokeWithArguments(str);
2413 } catch (Exception ex) {
2414 res = ex;
2415 }
2416 boolean sawFail = !(res instanceof String);
2417 if (sawFail != expectFail) {
2418 System.out.println("*** testInterfaceCast: "+mh+" was "+mt+" => "+res+(docast ? " (explicitCastArguments)" : ""));
2419 }
2420 if (!sawFail) {
2421 assertFalse(res.toString(), expectFail);
2422 assertEquals(str, res);
2423 } else {
2424 assertTrue(res.toString(), expectFail);
2425 }
2426 }
2427
twisti10d37ec2012-07-24 10:47:44 -07002428 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08002429 public void testCastFailure() throws Throwable {
2430 if (CAN_SKIP_WORKING) return;
2431 startTest("testCastFailure");
2432 testCastFailure("cast/argument", 11000);
twisti10d37ec2012-07-24 10:47:44 -07002433 if (CAN_TEST_LIGHTLY) return;
jrose10f3b682010-01-07 16:16:45 -08002434 testCastFailure("unbox/argument", 11000);
2435 testCastFailure("cast/return", 11000);
2436 testCastFailure("unbox/return", 11000);
2437 }
2438
jrose900bafd2010-10-30 21:08:23 -07002439 static class Surprise {
jrosea1ebbe62010-09-08 18:40:23 -07002440 public MethodHandle asMethodHandle() {
2441 return VALUE.bindTo(this);
2442 }
jrose10f3b682010-01-07 16:16:45 -08002443 Object value(Object x) {
2444 trace("value", x);
2445 if (boo != null) return boo;
2446 return x;
2447 }
2448 Object boo;
2449 void boo(Object x) { boo = x; }
2450
2451 static void trace(String x, Object y) {
2452 if (verbosity > 8) System.out.println(x+"="+y);
2453 }
2454 static Object refIdentity(Object x) { trace("ref.x", x); return x; }
2455 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }
2456 static int intIdentity(int x) { trace("int.x", x); return x; }
jrosea1ebbe62010-09-08 18:40:23 -07002457 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY;
2458 static {
2459 try {
2460 VALUE = PRIVATE.findVirtual(
2461 Surprise.class, "value",
2462 MethodType.methodType(Object.class, Object.class));
2463 REF_IDENTITY = PRIVATE.findStatic(
2464 Surprise.class, "refIdentity",
2465 MethodType.methodType(Object.class, Object.class));
2466 BOX_IDENTITY = PRIVATE.findStatic(
2467 Surprise.class, "boxIdentity",
2468 MethodType.methodType(Integer.class, Integer.class));
2469 INT_IDENTITY = PRIVATE.findStatic(
2470 Surprise.class, "intIdentity",
2471 MethodType.methodType(int.class, int.class));
jrose49494522012-01-18 17:34:29 -08002472 } catch (NoSuchMethodException | IllegalAccessException ex) {
jrosea1ebbe62010-09-08 18:40:23 -07002473 throw new RuntimeException(ex);
2474 }
2475 }
jrose10f3b682010-01-07 16:16:45 -08002476 }
2477
jrose49494522012-01-18 17:34:29 -08002478 @SuppressWarnings("ConvertToStringSwitch")
jrose10f3b682010-01-07 16:16:45 -08002479 void testCastFailure(String mode, int okCount) throws Throwable {
2480 countTest(false);
jrose2cc9c832010-04-30 23:48:23 -07002481 if (verbosity > 2) System.out.println("mode="+mode);
jrose10f3b682010-01-07 16:16:45 -08002482 Surprise boo = new Surprise();
jrosea1ebbe62010-09-08 18:40:23 -07002483 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0;
jrose10f3b682010-01-07 16:16:45 -08002484 if (mode.endsWith("/return")) {
2485 if (mode.equals("unbox/return")) {
2486 // fail on return to ((Integer)surprise).intValue
jrose9b82ad62011-05-26 17:37:36 -07002487 surprise = surprise.asType(MethodType.methodType(int.class, Object.class));
2488 identity = identity.asType(MethodType.methodType(int.class, Object.class));
jrose10f3b682010-01-07 16:16:45 -08002489 } else if (mode.equals("cast/return")) {
2490 // fail on return to (Integer)surprise
jrose9b82ad62011-05-26 17:37:36 -07002491 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));
2492 identity = identity.asType(MethodType.methodType(Integer.class, Object.class));
jrose10f3b682010-01-07 16:16:45 -08002493 }
2494 } else if (mode.endsWith("/argument")) {
2495 MethodHandle callee = null;
2496 if (mode.equals("unbox/argument")) {
2497 // fail on handing surprise to int argument
2498 callee = Surprise.INT_IDENTITY;
2499 } else if (mode.equals("cast/argument")) {
2500 // fail on handing surprise to Integer argument
2501 callee = Surprise.BOX_IDENTITY;
2502 }
2503 if (callee != null) {
jrose9b82ad62011-05-26 17:37:36 -07002504 callee = callee.asType(MethodType.genericMethodType(1));
jrose900bafd2010-10-30 21:08:23 -07002505 surprise = MethodHandles.filterArguments(callee, 0, surprise);
2506 identity = MethodHandles.filterArguments(callee, 0, identity);
jrose10f3b682010-01-07 16:16:45 -08002507 }
2508 }
jrosea1ebbe62010-09-08 18:40:23 -07002509 assertNotSame(mode, surprise, surprise0);
jrose9b82ad62011-05-26 17:37:36 -07002510 identity = identity.asType(MethodType.genericMethodType(1));
2511 surprise = surprise.asType(MethodType.genericMethodType(1));
jrose10f3b682010-01-07 16:16:45 -08002512 Object x = 42;
2513 for (int i = 0; i < okCount; i++) {
jrose2cc9c832010-04-30 23:48:23 -07002514 Object y = identity.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002515 assertEquals(x, y);
jrose2cc9c832010-04-30 23:48:23 -07002516 Object z = surprise.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002517 assertEquals(x, z);
2518 }
2519 boo.boo("Boo!");
jrose2cc9c832010-04-30 23:48:23 -07002520 Object y = identity.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002521 assertEquals(x, y);
2522 try {
jrose2cc9c832010-04-30 23:48:23 -07002523 Object z = surprise.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002524 System.out.println("Failed to throw; got z="+z);
2525 assertTrue(false);
jrose320b7692011-05-12 19:27:49 -07002526 } catch (ClassCastException ex) {
jrose10f3b682010-01-07 16:16:45 -08002527 if (verbosity > 2)
jrose2cc9c832010-04-30 23:48:23 -07002528 System.out.println("caught "+ex);
2529 if (verbosity > 3)
twisti10d37ec2012-07-24 10:47:44 -07002530 ex.printStackTrace(System.out);
jrose320b7692011-05-12 19:27:49 -07002531 assertTrue(true); // all is well
jrose10f3b682010-01-07 16:16:45 -08002532 }
2533 }
2534
jrose45b7a332010-05-03 23:32:47 -07002535 static Example userMethod(Object o, String s, int i) {
2536 called("userMethod", o, s, i);
2537 return null;
2538 }
2539
2540 @Test
2541 public void testUserClassInSignature() throws Throwable {
2542 if (CAN_SKIP_WORKING) return;
2543 startTest("testUserClassInSignature");
2544 Lookup lookup = MethodHandles.lookup();
2545 String name; MethodType mt; MethodHandle mh;
2546 Object[] args;
2547
2548 // Try a static method.
2549 name = "userMethod";
2550 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class);
2551 mh = lookup.findStatic(lookup.lookupClass(), name, mt);
2552 assertEquals(mt, mh.type());
2553 assertEquals(Example.class, mh.type().returnType());
2554 args = randomArgs(mh.type().parameterArray());
jrose900bafd2010-10-30 21:08:23 -07002555 mh.invokeWithArguments(args);
jrose45b7a332010-05-03 23:32:47 -07002556 assertCalled(name, args);
2557
2558 // Try a virtual method.
2559 name = "v2";
2560 mt = MethodType.methodType(Object.class, Object.class, int.class);
2561 mh = lookup.findVirtual(Example.class, name, mt);
2562 assertEquals(mt, mh.type().dropParameterTypes(0,1));
2563 assertTrue(mh.type().parameterList().contains(Example.class));
2564 args = randomArgs(mh.type().parameterArray());
jrose900bafd2010-10-30 21:08:23 -07002565 mh.invokeWithArguments(args);
jrose45b7a332010-05-03 23:32:47 -07002566 assertCalled(name, args);
2567 }
jrosebe2db602010-09-08 18:40:34 -07002568
2569 static void runForRunnable() {
2570 called("runForRunnable");
2571 }
jroseaf751942011-06-14 22:47:12 -07002572 public interface Fooable {
jroseb4be0262011-07-16 15:44:33 -07002573 // overloads:
jrose49494522012-01-18 17:34:29 -08002574 Object foo(Object x, String y);
2575 List<?> foo(String x, int y);
2576 Object foo(String x);
jrosebe2db602010-09-08 18:40:34 -07002577 }
jroseb4be0262011-07-16 15:44:33 -07002578 static Object fooForFooable(String x, Object... y) {
2579 return called("fooForFooable/"+x, y);
jrosebe2db602010-09-08 18:40:34 -07002580 }
jrose49494522012-01-18 17:34:29 -08002581 @SuppressWarnings("serial") // not really a public API, just a test case
jroseaf751942011-06-14 22:47:12 -07002582 public static class MyCheckedException extends Exception {
jrosebe2db602010-09-08 18:40:34 -07002583 }
jroseaf751942011-06-14 22:47:12 -07002584 public interface WillThrow {
jrosebe2db602010-09-08 18:40:34 -07002585 void willThrow() throws MyCheckedException;
2586 }
jroseb4be0262011-07-16 15:44:33 -07002587 /*non-public*/ interface PrivateRunnable {
2588 public void run();
2589 }
jrosebe2db602010-09-08 18:40:34 -07002590
2591 @Test
jroseb4be0262011-07-16 15:44:33 -07002592 public void testAsInterfaceInstance() throws Throwable {
jrosebe2db602010-09-08 18:40:34 -07002593 if (CAN_SKIP_WORKING) return;
twisti10d37ec2012-07-24 10:47:44 -07002594 startTest("asInterfaceInstance");
jrosebe2db602010-09-08 18:40:34 -07002595 Lookup lookup = MethodHandles.lookup();
jroseb4be0262011-07-16 15:44:33 -07002596 // test typical case: Runnable.run
jrosebe2db602010-09-08 18:40:34 -07002597 {
jroseb4be0262011-07-16 15:44:33 -07002598 countTest();
2599 if (verbosity >= 2) System.out.println("Runnable");
jrosebe2db602010-09-08 18:40:34 -07002600 MethodType mt = MethodType.methodType(void.class);
2601 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
jrose9b82ad62011-05-26 17:37:36 -07002602 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
jrosebe2db602010-09-08 18:40:34 -07002603 proxy.run();
2604 assertCalled("runForRunnable");
2605 }
jroseb4be0262011-07-16 15:44:33 -07002606 // well known single-name overloaded interface: Appendable.append
jrosebe2db602010-09-08 18:40:34 -07002607 {
jroseb4be0262011-07-16 15:44:33 -07002608 countTest();
2609 if (verbosity >= 2) System.out.println("Appendable");
jrose49494522012-01-18 17:34:29 -08002610 ArrayList<List<?>> appendResults = new ArrayList<>();
jroseb4be0262011-07-16 15:44:33 -07002611 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));
2612 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type
2613 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
2614 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class);
2615 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh);
2616 proxy.append("one");
2617 proxy.append("two", 3, 4);
2618 proxy.append('5');
2619 assertEquals(Arrays.asList(Arrays.asList("one"),
2620 Arrays.asList("two", 3, 4),
2621 Arrays.asList('5')),
2622 appendResults);
2623 if (verbosity >= 3) System.out.println("appendResults="+appendResults);
2624 appendResults.clear();
2625 Formatter formatter = new Formatter(proxy);
2626 String fmt = "foo str=%s char='%c' num=%d";
2627 Object[] fmtArgs = { "str!", 'C', 42 };
2628 String expect = String.format(fmt, fmtArgs);
2629 formatter.format(fmt, fmtArgs);
2630 String actual = "";
2631 if (verbosity >= 3) System.out.println("appendResults="+appendResults);
jrose49494522012-01-18 17:34:29 -08002632 for (List<?> l : appendResults) {
jroseb4be0262011-07-16 15:44:33 -07002633 Object x = l.get(0);
2634 switch (l.size()) {
2635 case 1: actual += x; continue;
jrose49494522012-01-18 17:34:29 -08002636 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue;
jroseb4be0262011-07-16 15:44:33 -07002637 }
2638 actual += l;
2639 }
2640 if (verbosity >= 3) System.out.println("expect="+expect);
2641 if (verbosity >= 3) System.out.println("actual="+actual);
2642 assertEquals(expect, actual);
jrosebe2db602010-09-08 18:40:34 -07002643 }
jroseb4be0262011-07-16 15:44:33 -07002644 // test case of an single name which is overloaded: Fooable.foo(...)
2645 {
2646 if (verbosity >= 2) System.out.println("Fooable");
2647 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable",
2648 MethodType.methodType(Object.class, String.class, Object[].class));
2649 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
2650 for (Method m : Fooable.class.getDeclaredMethods()) {
2651 countTest();
2652 assertSame("foo", m.getName());
2653 if (verbosity > 3)
2654 System.out.println("calling "+m);
2655 MethodHandle invoker = lookup.unreflect(m);
2656 MethodType mt = invoker.type();
2657 Class<?>[] types = mt.parameterArray();
2658 types[0] = int.class; // placeholder
2659 Object[] args = randomArgs(types);
2660 args[0] = proxy;
2661 if (verbosity > 3)
2662 System.out.println("calling "+m+" on "+Arrays.asList(args));
2663 Object result = invoker.invokeWithArguments(args);
2664 if (verbosity > 4)
2665 System.out.println("result = "+result);
2666 String name = "fooForFooable/"+args[1];
2667 Object[] argTail = Arrays.copyOfRange(args, 2, args.length);
2668 assertCalled(name, argTail);
2669 assertEquals(result, logEntry(name, argTail));
2670 }
2671 }
2672 // test processing of thrown exceptions:
jrosebe2db602010-09-08 18:40:34 -07002673 for (Throwable ex : new Throwable[] { new NullPointerException("ok"),
2674 new InternalError("ok"),
2675 new Throwable("fail"),
2676 new Exception("fail"),
2677 new MyCheckedException()
2678 }) {
2679 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
2680 mh = MethodHandles.insertArguments(mh, 0, ex);
jrose9b82ad62011-05-26 17:37:36 -07002681 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
jrosebe2db602010-09-08 18:40:34 -07002682 try {
jroseb4be0262011-07-16 15:44:33 -07002683 countTest();
jrosebe2db602010-09-08 18:40:34 -07002684 proxy.willThrow();
2685 System.out.println("Failed to throw: "+ex);
2686 assertTrue(false);
2687 } catch (Throwable ex1) {
jroseb4be0262011-07-16 15:44:33 -07002688 if (verbosity > 3) {
jrosebe2db602010-09-08 18:40:34 -07002689 System.out.println("throw "+ex);
2690 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));
2691 }
2692 if (ex instanceof RuntimeException ||
2693 ex instanceof Error) {
2694 assertSame("must pass unchecked exception out without wrapping", ex, ex1);
2695 } else if (ex instanceof MyCheckedException) {
2696 assertSame("must pass declared exception out without wrapping", ex, ex1);
2697 } else {
2698 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);
jroseaf751942011-06-14 22:47:12 -07002699 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) {
twisti10d37ec2012-07-24 10:47:44 -07002700 ex1.printStackTrace(System.out);
jroseaf751942011-06-14 22:47:12 -07002701 }
2702 assertSame(ex, ex1.getCause());
jrosebe2db602010-09-08 18:40:34 -07002703 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;
jrosebe2db602010-09-08 18:40:34 -07002704 }
2705 }
2706 }
jroseb4be0262011-07-16 15:44:33 -07002707 // Test error checking on bad interfaces:
jrose49494522012-01-18 17:34:29 -08002708 for (Class<?> nonSMI : new Class<?>[] { Object.class,
jrosebe2db602010-09-08 18:40:34 -07002709 String.class,
2710 CharSequence.class,
jroseb4be0262011-07-16 15:44:33 -07002711 java.io.Serializable.class,
2712 PrivateRunnable.class,
jrosebe2db602010-09-08 18:40:34 -07002713 Example.class }) {
jroseb4be0262011-07-16 15:44:33 -07002714 if (verbosity > 2) System.out.println(nonSMI.getName());
jrosebe2db602010-09-08 18:40:34 -07002715 try {
jroseb4be0262011-07-16 15:44:33 -07002716 countTest(false);
2717 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0));
2718 assertTrue("Failed to throw on "+nonSMI.getName(), false);
jrosebe2db602010-09-08 18:40:34 -07002719 } catch (IllegalArgumentException ex) {
jroseb4be0262011-07-16 15:44:33 -07002720 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex);
2721 // Object: java.lang.IllegalArgumentException:
2722 // not a public interface: java.lang.Object
2723 // String: java.lang.IllegalArgumentException:
2724 // not a public interface: java.lang.String
2725 // CharSequence: java.lang.IllegalArgumentException:
2726 // not a single-method interface: java.lang.CharSequence
2727 // Serializable: java.lang.IllegalArgumentException:
2728 // not a single-method interface: java.io.Serializable
2729 // PrivateRunnable: java.lang.IllegalArgumentException:
2730 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable
2731 // Example: java.lang.IllegalArgumentException:
2732 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example
2733 }
2734 }
2735 // Test error checking on interfaces with the wrong method type:
jrose49494522012-01-18 17:34:29 -08002736 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/,
jroseb4be0262011-07-16 15:44:33 -07002737 Fooable.class /*arity 1 & 2*/ }) {
2738 int badArity = 1; // known to be incompatible
2739 if (verbosity > 2) System.out.println(intfc.getName());
2740 try {
2741 countTest(false);
2742 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity));
2743 assertTrue("Failed to throw on "+intfc.getName(), false);
2744 } catch (WrongMethodTypeException ex) {
2745 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex);
2746 // Runnable: java.lang.invoke.WrongMethodTypeException:
2747 // cannot convert MethodHandle(Object)Object[] to ()void
2748 // Fooable: java.lang.invoke.WrongMethodTypeException:
2749 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object
jrosebe2db602010-09-08 18:40:34 -07002750 }
2751 }
2752 }
jrose43b8c122011-07-16 15:40:13 -07002753
2754 @Test
2755 public void testRunnableProxy() throws Throwable {
2756 if (CAN_SKIP_WORKING) return;
2757 startTest("testRunnableProxy");
2758 MethodHandles.Lookup lookup = MethodHandles.lookup();
2759 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class));
2760 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run);
2761 testRunnableProxy(r);
2762 assertCalled("runForRunnable");
2763 }
2764 private static void testRunnableProxy(Runnable r) {
2765 //7058630: JSR 292 method handle proxy violates contract for Object methods
2766 r.run();
2767 Object o = r;
2768 r = null;
2769 boolean eq = (o == o);
2770 int hc = System.identityHashCode(o);
2771 String st = o.getClass().getName() + "@" + Integer.toHexString(hc);
2772 Object expect = Arrays.asList(st, eq, hc);
2773 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect);
2774 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode());
2775 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual);
2776 assertEquals(expect, actual);
2777 }
jrose55220c32009-10-21 23:19:48 -07002778}
jroseada69fa2011-03-23 23:02:31 -07002779// Local abbreviated copy of sun.invoke.util.ValueConversions
twisti10d37ec2012-07-24 10:47:44 -07002780// This guy tests access from outside the same package member, but inside
2781// the package itself.
jrose55220c32009-10-21 23:19:48 -07002782class ValueConversions {
2783 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
2784 private static final Object[] NO_ARGS_ARRAY = {};
2785 private static Object[] makeArray(Object... args) { return args; }
2786 private static Object[] array() { return NO_ARGS_ARRAY; }
2787 private static Object[] array(Object a0)
2788 { return makeArray(a0); }
2789 private static Object[] array(Object a0, Object a1)
2790 { return makeArray(a0, a1); }
2791 private static Object[] array(Object a0, Object a1, Object a2)
2792 { return makeArray(a0, a1, a2); }
2793 private static Object[] array(Object a0, Object a1, Object a2, Object a3)
2794 { return makeArray(a0, a1, a2, a3); }
2795 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2796 Object a4)
2797 { return makeArray(a0, a1, a2, a3, a4); }
2798 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2799 Object a4, Object a5)
2800 { return makeArray(a0, a1, a2, a3, a4, a5); }
2801 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2802 Object a4, Object a5, Object a6)
2803 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
2804 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2805 Object a4, Object a5, Object a6, Object a7)
2806 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
2807 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2808 Object a4, Object a5, Object a6, Object a7,
2809 Object a8)
2810 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
2811 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
2812 Object a4, Object a5, Object a6, Object a7,
2813 Object a8, Object a9)
2814 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
2815 static MethodHandle[] makeArrays() {
jrose49494522012-01-18 17:34:29 -08002816 ArrayList<MethodHandle> arrays = new ArrayList<>();
jrose55220c32009-10-21 23:19:48 -07002817 MethodHandles.Lookup lookup = IMPL_LOOKUP;
2818 for (;;) {
2819 int nargs = arrays.size();
jrose10f3b682010-01-07 16:16:45 -08002820 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
jrose55220c32009-10-21 23:19:48 -07002821 String name = "array";
2822 MethodHandle array = null;
2823 try {
2824 array = lookup.findStatic(ValueConversions.class, name, type);
jrosef15905c2011-02-11 01:26:32 -08002825 } catch (ReflectiveOperationException ex) {
2826 // break from loop!
jrose55220c32009-10-21 23:19:48 -07002827 }
2828 if (array == null) break;
2829 arrays.add(array);
2830 }
jrosef15905c2011-02-11 01:26:32 -08002831 assertTrue(arrays.size() == 11); // current number of methods
jrose55220c32009-10-21 23:19:48 -07002832 return arrays.toArray(new MethodHandle[0]);
2833 }
2834 static final MethodHandle[] ARRAYS = makeArrays();
2835
2836 /** Return a method handle that takes the indicated number of Object
2837 * arguments and returns an Object array of them, as if for varargs.
2838 */
2839 public static MethodHandle varargsArray(int nargs) {
2840 if (nargs < ARRAYS.length)
2841 return ARRAYS[nargs];
jroseaf751942011-06-14 22:47:12 -07002842 return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);
jrose55220c32009-10-21 23:19:48 -07002843 }
jrose320b7692011-05-12 19:27:49 -07002844 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
2845 Class<?> elemType = arrayType.getComponentType();
2846 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType));
2847 MethodHandle mh = varargsArray(nargs);
2848 if (arrayType != Object[].class)
2849 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType));
2850 return mh.asType(vaType);
2851 }
2852 static Object changeArrayType(Class<?> arrayType, Object[] a) {
2853 Class<?> elemType = arrayType.getComponentType();
2854 if (!elemType.isPrimitive())
2855 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class));
2856 Object b = java.lang.reflect.Array.newInstance(elemType, a.length);
2857 for (int i = 0; i < a.length; i++)
2858 java.lang.reflect.Array.set(b, i, a[i]);
2859 return b;
2860 }
2861 private static final MethodHandle CHANGE_ARRAY_TYPE;
2862 static {
2863 try {
2864 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType",
2865 MethodType.methodType(Object.class, Class.class, Object[].class));
2866 } catch (NoSuchMethodException | IllegalAccessException ex) {
2867 Error err = new InternalError("uncaught exception");
2868 err.initCause(ex);
2869 throw err;
2870 }
2871 }
jrose10f3b682010-01-07 16:16:45 -08002872
2873 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
2874 private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
2875 private static List<Object> list() { return NO_ARGS_LIST; }
2876 private static List<Object> list(Object a0)
2877 { return makeList(a0); }
2878 private static List<Object> list(Object a0, Object a1)
2879 { return makeList(a0, a1); }
2880 private static List<Object> list(Object a0, Object a1, Object a2)
2881 { return makeList(a0, a1, a2); }
2882 private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
2883 { return makeList(a0, a1, a2, a3); }
2884 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2885 Object a4)
2886 { return makeList(a0, a1, a2, a3, a4); }
2887 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2888 Object a4, Object a5)
2889 { return makeList(a0, a1, a2, a3, a4, a5); }
2890 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2891 Object a4, Object a5, Object a6)
2892 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
2893 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2894 Object a4, Object a5, Object a6, Object a7)
2895 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
2896 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2897 Object a4, Object a5, Object a6, Object a7,
2898 Object a8)
2899 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
2900 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
2901 Object a4, Object a5, Object a6, Object a7,
2902 Object a8, Object a9)
2903 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
2904 static MethodHandle[] makeLists() {
jrose49494522012-01-18 17:34:29 -08002905 ArrayList<MethodHandle> lists = new ArrayList<>();
jrose10f3b682010-01-07 16:16:45 -08002906 MethodHandles.Lookup lookup = IMPL_LOOKUP;
2907 for (;;) {
jroseadc650a2011-02-11 01:26:28 -08002908 int nargs = lists.size();
jrose10f3b682010-01-07 16:16:45 -08002909 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
2910 String name = "list";
jroseadc650a2011-02-11 01:26:28 -08002911 MethodHandle list = null;
jrose10f3b682010-01-07 16:16:45 -08002912 try {
jroseadc650a2011-02-11 01:26:28 -08002913 list = lookup.findStatic(ValueConversions.class, name, type);
jrosef15905c2011-02-11 01:26:32 -08002914 } catch (ReflectiveOperationException ex) {
2915 // break from loop!
jrose10f3b682010-01-07 16:16:45 -08002916 }
jroseadc650a2011-02-11 01:26:28 -08002917 if (list == null) break;
2918 lists.add(list);
jrose10f3b682010-01-07 16:16:45 -08002919 }
jrosef15905c2011-02-11 01:26:32 -08002920 assertTrue(lists.size() == 11); // current number of methods
jroseadc650a2011-02-11 01:26:28 -08002921 return lists.toArray(new MethodHandle[0]);
jrose10f3b682010-01-07 16:16:45 -08002922 }
2923 static final MethodHandle[] LISTS = makeLists();
jroseaf751942011-06-14 22:47:12 -07002924 static final MethodHandle AS_LIST;
2925 static {
2926 try {
2927 AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
jrose49494522012-01-18 17:34:29 -08002928 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseaf751942011-06-14 22:47:12 -07002929 }
jrose10f3b682010-01-07 16:16:45 -08002930
2931 /** Return a method handle that takes the indicated number of Object
2932 * arguments and returns List.
2933 */
2934 public static MethodHandle varargsList(int nargs) {
2935 if (nargs < LISTS.length)
2936 return LISTS[nargs];
jroseaf751942011-06-14 22:47:12 -07002937 return AS_LIST.asCollector(Object[].class, nargs);
jrose10f3b682010-01-07 16:16:45 -08002938 }
jrose55220c32009-10-21 23:19:48 -07002939}
2940// This guy tests access from outside the same package member, but inside
2941// the package itself.
2942class PackageSibling {
2943 static Lookup lookup() {
2944 return MethodHandles.lookup();
2945 }
2946}