blob: 37da9b0c8a0103a63d7f92edcf3bd9187d110889 [file] [log] [blame]
jrose55220c32009-10-21 23:19:48 -07001/*
alanb0d058232012-11-02 15:50:11 +00002 * Copyright (c) 2009, 2012, 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
jiangli52f57082012-11-05 12:51:14 -050029 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa 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+":");
jroseb5cd3912013-10-05 05:30:38 -0700143 System.out.println("expected: "+deepToString(expected));
jrose55220c32009-10-21 23:19:48 -0700144 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)
jroseb5cd3912013-10-05 05:30:38 -0700151 System.out.println("calling MH="+target+" to "+name+deepToString(args));
152 }
153 static String deepToString(Object x) {
154 if (x == null) return "null";
155 if (x instanceof Collection)
156 x = ((Collection)x).toArray();
157 if (x instanceof Object[]) {
158 Object[] ax = (Object[]) x;
159 ax = Arrays.copyOf(ax, ax.length, Object[].class);
160 for (int i = 0; i < ax.length; i++)
161 ax[i] = deepToString(ax[i]);
162 x = Arrays.deepToString(ax);
163 }
164 if (x.getClass().isArray())
165 try {
166 x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);
167 } catch (ReflectiveOperationException ex) { throw new Error(ex); }
168 assert(!(x instanceof Object[]));
169 return x.toString();
jrose55220c32009-10-21 23:19:48 -0700170 }
171
172 static Object castToWrapper(Object value, Class<?> dst) {
173 Object wrap = null;
174 if (value instanceof Number)
175 wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
176 if (value instanceof Character)
177 wrap = castToWrapperOrNull((char)(Character)value, dst);
178 if (wrap != null) return wrap;
179 return dst.cast(value);
180 }
181
jrose49494522012-01-18 17:34:29 -0800182 @SuppressWarnings("cast") // primitive cast to (long) is part of the pattern
jrose55220c32009-10-21 23:19:48 -0700183 static Object castToWrapperOrNull(long value, Class<?> dst) {
184 if (dst == int.class || dst == Integer.class)
185 return (int)(value);
186 if (dst == long.class || dst == Long.class)
187 return (long)(value);
188 if (dst == char.class || dst == Character.class)
189 return (char)(value);
190 if (dst == short.class || dst == Short.class)
191 return (short)(value);
192 if (dst == float.class || dst == Float.class)
193 return (float)(value);
194 if (dst == double.class || dst == Double.class)
195 return (double)(value);
jrose10f3b682010-01-07 16:16:45 -0800196 if (dst == byte.class || dst == Byte.class)
197 return (byte)(value);
198 if (dst == boolean.class || dst == boolean.class)
199 return ((value % 29) & 1) == 0;
jrose55220c32009-10-21 23:19:48 -0700200 return null;
201 }
202
jrose2cc9c832010-04-30 23:48:23 -0700203 static final int ONE_MILLION = (1000*1000), // first int value
204 TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits
205 INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;
206 static long nextArgVal;
207 static long nextArg(boolean moreBits) {
208 long val = nextArgVal++;
209 long sign = -(val & 1); // alternate signs
210 val >>= 1;
211 if (moreBits)
212 // Guarantee some bits in the high word.
213 // In any case keep the decimal representation simple-looking,
214 // with lots of zeroes, so as not to make the printed decimal
215 // strings unnecessarily noisy.
216 val += (val % ONE_MILLION) * TEN_BILLION;
217 return val ^ sign;
218 }
219 static int nextArg() {
220 // Produce a 32-bit result something like ONE_MILLION+(smallint).
221 // Example: 1_000_042.
222 return (int) nextArg(false);
223 }
224 static long nextArg(Class<?> kind) {
225 if (kind == long.class || kind == Long.class ||
226 kind == double.class || kind == Double.class)
227 // produce a 64-bit result something like
228 // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
229 // Example: 10_000_420_001_000_042.
230 return nextArg(true);
231 return (long) nextArg();
232 }
233
jrose55220c32009-10-21 23:19:48 -0700234 static Object randomArg(Class<?> param) {
jrose2cc9c832010-04-30 23:48:23 -0700235 Object wrap = castToWrapperOrNull(nextArg(param), param);
jrose55220c32009-10-21 23:19:48 -0700236 if (wrap != null) {
jrose55220c32009-10-21 23:19:48 -0700237 return wrap;
238 }
jroseada69fa2011-03-23 23:02:31 -0700239// import sun.invoke.util.Wrapper;
jrose55220c32009-10-21 23:19:48 -0700240// Wrapper wrap = Wrapper.forBasicType(dst);
241// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
242// wrap = Wrapper.forWrapperType(dst);
243// if (wrap != Wrapper.OBJECT)
244// return wrap.wrap(nextArg++);
jrosebe2db602010-09-08 18:40:34 -0700245 if (param.isInterface()) {
246 for (Class<?> c : param.getClasses()) {
247 if (param.isAssignableFrom(c) && !c.isInterface())
248 { param = c; break; }
249 }
250 }
jroseb5cd3912013-10-05 05:30:38 -0700251 if (param.isArray()) {
252 Class<?> ctype = param.getComponentType();
253 Object arg = Array.newInstance(ctype, 2);
254 Array.set(arg, 0, randomArg(ctype));
255 return arg;
256 }
jrose485df122012-07-12 00:11:35 -0700257 if (param.isInterface() && param.isAssignableFrom(List.class))
258 return Arrays.asList("#"+nextArg());
jrose55220c32009-10-21 23:19:48 -0700259 if (param.isInterface() || param.isAssignableFrom(String.class))
jrose2cc9c832010-04-30 23:48:23 -0700260 return "#"+nextArg();
jrose55220c32009-10-21 23:19:48 -0700261 else
262 try {
263 return param.newInstance();
jrose49494522012-01-18 17:34:29 -0800264 } catch (InstantiationException | IllegalAccessException ex) {
jrose55220c32009-10-21 23:19:48 -0700265 }
266 return null; // random class not Object, String, Integer, etc.
267 }
268 static Object[] randomArgs(Class<?>... params) {
269 Object[] args = new Object[params.length];
270 for (int i = 0; i < args.length; i++)
271 args[i] = randomArg(params[i]);
272 return args;
273 }
274 static Object[] randomArgs(int nargs, Class<?> param) {
275 Object[] args = new Object[nargs];
276 for (int i = 0; i < args.length; i++)
277 args[i] = randomArg(param);
278 return args;
279 }
jrose1ccb8a72013-10-05 05:30:39 -0700280 static Object[] randomArgs(List<Class<?>> params) {
281 return randomArgs(params.toArray(new Class<?>[params.size()]));
282 }
jrose55220c32009-10-21 23:19:48 -0700283
jrose49494522012-01-18 17:34:29 -0800284 @SafeVarargs @SuppressWarnings("varargs")
jrose55220c32009-10-21 23:19:48 -0700285 static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
286 return Arrays.copyOf(a, a.length, atype);
287 }
jrose49494522012-01-18 17:34:29 -0800288 @SafeVarargs @SuppressWarnings("varargs")
jrose55220c32009-10-21 23:19:48 -0700289 static <T> T[] cat(T[] a, T... b) {
290 int alen = a.length, blen = b.length;
291 if (blen == 0) return a;
292 T[] c = Arrays.copyOf(a, alen + blen);
293 System.arraycopy(b, 0, c, alen, blen);
294 return c;
295 }
296 static Integer[] boxAll(int... vx) {
297 Integer[] res = new Integer[vx.length];
298 for (int i = 0; i < res.length; i++) {
299 res[i] = vx[i];
300 }
301 return res;
302 }
303 static Object getClasses(Object x) {
304 if (x == null) return x;
305 if (x instanceof String) return x; // keep the name
306 if (x instanceof List) {
307 // recursively report classes of the list elements
308 Object[] xa = ((List)x).toArray();
309 for (int i = 0; i < xa.length; i++)
310 xa[i] = getClasses(xa[i]);
311 return Arrays.asList(xa);
312 }
313 return x.getClass().getSimpleName();
314 }
315
jroseadc650a2011-02-11 01:26:28 -0800316 /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */
317 static MethodHandle varargsList(int arity) {
318 return ValueConversions.varargsList(arity);
319 }
320 /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */
321 static MethodHandle varargsArray(int arity) {
322 return ValueConversions.varargsArray(arity);
323 }
jrose320b7692011-05-12 19:27:49 -0700324 static MethodHandle varargsArray(Class<?> arrayType, int arity) {
325 return ValueConversions.varargsArray(arrayType, arity);
326 }
jroseadc650a2011-02-11 01:26:28 -0800327 /** Variation of varargsList, but with the given rtype. */
328 static MethodHandle varargsList(int arity, Class<?> rtype) {
329 MethodHandle list = varargsList(arity);
330 MethodType listType = list.type().changeReturnType(rtype);
331 if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) {
332 // OK
333 } else if (rtype.isAssignableFrom(String.class)) {
334 if (LIST_TO_STRING == null)
335 try {
336 LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",
337 MethodType.methodType(String.class, List.class));
jrose49494522012-01-18 17:34:29 -0800338 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseadc650a2011-02-11 01:26:28 -0800339 list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);
340 } else if (rtype.isPrimitive()) {
341 if (LIST_TO_INT == null)
342 try {
343 LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",
344 MethodType.methodType(int.class, List.class));
jrose49494522012-01-18 17:34:29 -0800345 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseadc650a2011-02-11 01:26:28 -0800346 list = MethodHandles.filterReturnValue(list, LIST_TO_INT);
347 list = MethodHandles.explicitCastArguments(list, listType);
348 } else {
349 throw new RuntimeException("varargsList: "+rtype);
350 }
351 return list.asType(listType);
352 }
jrose1ccb8a72013-10-05 05:30:39 -0700353 /** Variation of varargsList, but with the given ptypes and rtype. */
354 static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {
355 MethodHandle list = varargsList(ptypes.size(), rtype);
356 return list.asType(MethodType.methodType(rtype, ptypes));
357 }
jroseadc650a2011-02-11 01:26:28 -0800358 private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
jrose49494522012-01-18 17:34:29 -0800359 private static String listToString(List<?> x) { return x.toString(); }
360 private static int listToInt(List<?> x) { return x.toString().hashCode(); }
jroseadc650a2011-02-11 01:26:28 -0800361
jrose55220c32009-10-21 23:19:48 -0700362 static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
363 return changeArgTypes(target, 0, 999, argType);
364 }
365 static MethodHandle changeArgTypes(MethodHandle target,
366 int beg, int end, Class<?> argType) {
367 MethodType targetType = target.type();
368 end = Math.min(end, targetType.parameterCount());
jrose49494522012-01-18 17:34:29 -0800369 ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
jrose55220c32009-10-21 23:19:48 -0700370 Collections.fill(argTypes.subList(beg, end), argType);
jrose10f3b682010-01-07 16:16:45 -0800371 MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
jrose9b82ad62011-05-26 17:37:36 -0700372 return target.asType(ttype2);
jrose55220c32009-10-21 23:19:48 -0700373 }
jroseb4be0262011-07-16 15:44:33 -0700374 static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {
375 int targetLen = target.type().parameterCount();
376 int extra = (nargs - targetLen);
377 if (extra <= 0) return target;
378 List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);
379 return MethodHandles.dropArguments(target, targetLen, fakeArgs);
380 }
jrose55220c32009-10-21 23:19:48 -0700381
382 // This lookup is good for all members in and under MethodHandlesTest.
383 static final Lookup PRIVATE = MethodHandles.lookup();
384 // This lookup is good for package-private members but not private ones.
385 static final Lookup PACKAGE = PackageSibling.lookup();
twisti10d37ec2012-07-24 10:47:44 -0700386 // This lookup is good for public members and protected members of PubExample
387 static final Lookup SUBCLASS = RemoteExample.lookup();
jrose55220c32009-10-21 23:19:48 -0700388 // This lookup is good only for public members.
jrose10f3b682010-01-07 16:16:45 -0800389 static final Lookup PUBLIC = MethodHandles.publicLookup();
jrose55220c32009-10-21 23:19:48 -0700390
391 // Subject methods...
392 static class Example implements IntExample {
393 final String name;
jrose2cc9c832010-04-30 23:48:23 -0700394 public Example() { name = "Example#"+nextArg(); }
jrose55220c32009-10-21 23:19:48 -0700395 protected Example(String name) { this.name = name; }
jrose49494522012-01-18 17:34:29 -0800396 @SuppressWarnings("LeakingThisInConstructor")
jrose55220c32009-10-21 23:19:48 -0700397 protected Example(int x) { this(); called("protected <init>", this, x); }
jrose942f3d32013-10-05 05:30:39 -0700398 //Example(Void x) { does not exist; lookup elicts NoSuchMethodException }
jrose55220c32009-10-21 23:19:48 -0700399 @Override public String toString() { return name; }
400
401 public void v0() { called("v0", this); }
twisti10d37ec2012-07-24 10:47:44 -0700402 protected void pro_v0() { called("pro_v0", this); }
jrose55220c32009-10-21 23:19:48 -0700403 void pkg_v0() { called("pkg_v0", this); }
404 private void pri_v0() { called("pri_v0", this); }
405 public static void s0() { called("s0"); }
twisti10d37ec2012-07-24 10:47:44 -0700406 protected static void pro_s0() { called("pro_s0"); }
jrose55220c32009-10-21 23:19:48 -0700407 static void pkg_s0() { called("pkg_s0"); }
408 private static void pri_s0() { called("pri_s0"); }
409
410 public Object v1(Object x) { return called("v1", this, x); }
411 public Object v2(Object x, Object y) { return called("v2", this, x, y); }
412 public Object v2(Object x, int y) { return called("v2", this, x, y); }
413 public Object v2(int x, Object y) { return called("v2", this, x, y); }
414 public Object v2(int x, int y) { return called("v2", this, x, y); }
415 public static Object s1(Object x) { return called("s1", x); }
416 public static Object s2(int x) { return called("s2", x); }
417 public static Object s3(long x) { return called("s3", x); }
418 public static Object s4(int x, int y) { return called("s4", x, y); }
419 public static Object s5(long x, int y) { return called("s5", x, y); }
420 public static Object s6(int x, long y) { return called("s6", x, y); }
421 public static Object s7(float x, double y) { return called("s7", x, y); }
jrose2cc9c832010-04-30 23:48:23 -0700422
jroseb4be0262011-07-16 15:44:33 -0700423 // for testing findConstructor:
424 public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }
425 public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }
twisti10d37ec2012-07-24 10:47:44 -0700426 public Example(int x, int y) { this.name = x+""+y; called("Example.<init>", x, y); }
427 public Example(int x, long y) { this.name = x+""+y; called("Example.<init>", x, y); }
428 public Example(int x, float y) { this.name = x+""+y; called("Example.<init>", x, y); }
429 public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); }
430 public Example(int x, int y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); }
431 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 -0700432
jrose2cc9c832010-04-30 23:48:23 -0700433 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
jrose55220c32009-10-21 23:19:48 -0700434 }
jrose2cc9c832010-04-30 23:48:23 -0700435 static final Lookup EXAMPLE = Example.EXAMPLE;
jrose55220c32009-10-21 23:19:48 -0700436 public static class PubExample extends Example {
twisti10d37ec2012-07-24 10:47:44 -0700437 public PubExample() { this("PubExample"); }
438 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
439 protected void pro_v0() { called("Pub/pro_v0", this); }
440 protected static void pro_s0() { called("Pub/pro_s0"); }
jrose55220c32009-10-21 23:19:48 -0700441 }
442 static class SubExample extends Example {
443 @Override public void v0() { called("Sub/v0", this); }
444 @Override void pkg_v0() { called("Sub/pkg_v0", this); }
jrose49494522012-01-18 17:34:29 -0800445 @SuppressWarnings("LeakingThisInConstructor")
jrose55220c32009-10-21 23:19:48 -0700446 private SubExample(int x) { called("<init>", this, x); }
jrose2cc9c832010-04-30 23:48:23 -0700447 public SubExample() { super("SubExample#"+nextArg()); }
jrose55220c32009-10-21 23:19:48 -0700448 }
449 public static interface IntExample {
450 public void v0();
jrosebe2db602010-09-08 18:40:34 -0700451 public static class Impl implements IntExample {
jrose55220c32009-10-21 23:19:48 -0700452 public void v0() { called("Int/v0", this); }
453 final String name;
jrose2cc9c832010-04-30 23:48:23 -0700454 public Impl() { name = "Impl#"+nextArg(); }
455 @Override public String toString() { return name; }
jrose55220c32009-10-21 23:19:48 -0700456 }
457 }
jrose485df122012-07-12 00:11:35 -0700458 static interface SubIntExample extends IntExample { }
jrose55220c32009-10-21 23:19:48 -0700459
460 static final Object[][][] ACCESS_CASES = {
twisti10d37ec2012-07-24 10:47:44 -0700461 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
462 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
463 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
464 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK
465 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true
jrose55220c32009-10-21 23:19:48 -0700466 };
467
jrose2cc9c832010-04-30 23:48:23 -0700468 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
469 Object[][] cases;
470 if (name.contains("pri_") || isSpecial) {
471 cases = ACCESS_CASES[1]; // PRIVATE only
472 } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {
473 cases = ACCESS_CASES[2]; // not PUBLIC
twisti10d37ec2012-07-24 10:47:44 -0700474 } else if (name.contains("pro_")) {
475 cases = ACCESS_CASES[3]; // PUBLIC class, protected member
jrose10f3b682010-01-07 16:16:45 -0800476 } else {
twisti10d37ec2012-07-24 10:47:44 -0700477 assertTrue(name.indexOf('_') < 0 || name.contains("fin_"));
jrose10f3b682010-01-07 16:16:45 -0800478 boolean pubc = Modifier.isPublic(defc.getModifiers());
479 if (pubc)
twisti10d37ec2012-07-24 10:47:44 -0700480 cases = ACCESS_CASES[4]; // all access levels
jrose2cc9c832010-04-30 23:48:23 -0700481 else
482 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC
jrose10f3b682010-01-07 16:16:45 -0800483 }
jrose2cc9c832010-04-30 23:48:23 -0700484 if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)
485 cases = Arrays.copyOfRange(cases, 0, cases.length-1);
486 return cases;
487 }
488 static Object[][] accessCases(Class<?> defc, String name) {
489 return accessCases(defc, name, false);
jrose55220c32009-10-21 23:19:48 -0700490 }
491
twisti10d37ec2012-07-24 10:47:44 -0700492 static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) {
493 if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE)
494 // external views stay external
495 return lookup;
496 return lookup.in(defc);
497 }
498
jrose8347af82013-10-05 05:30:40 -0700499 /** Is findVirtual (etc.) of "&lt;init&lt;" supposed to elicit a NoSuchMethodException? */
jrose942f3d32013-10-05 05:30:39 -0700500 final static boolean INIT_REF_CAUSES_NSME = true;
501
jrose55220c32009-10-21 23:19:48 -0700502 @Test
503 public void testFindStatic() throws Throwable {
504 if (CAN_SKIP_WORKING) return;
505 startTest("findStatic");
506 testFindStatic(PubExample.class, void.class, "s0");
507 testFindStatic(Example.class, void.class, "s0");
508 testFindStatic(Example.class, void.class, "pkg_s0");
509 testFindStatic(Example.class, void.class, "pri_s0");
twisti10d37ec2012-07-24 10:47:44 -0700510 testFindStatic(Example.class, void.class, "pro_s0");
511 testFindStatic(PubExample.class, void.class, "Pub/pro_s0");
jrose55220c32009-10-21 23:19:48 -0700512
513 testFindStatic(Example.class, Object.class, "s1", Object.class);
514 testFindStatic(Example.class, Object.class, "s2", int.class);
515 testFindStatic(Example.class, Object.class, "s3", long.class);
516 testFindStatic(Example.class, Object.class, "s4", int.class, int.class);
517 testFindStatic(Example.class, Object.class, "s5", long.class, int.class);
518 testFindStatic(Example.class, Object.class, "s6", int.class, long.class);
519 testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
520
521 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
jrose942f3d32013-10-05 05:30:39 -0700522 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class);
523 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
twisti10d37ec2012-07-24 10:47:44 -0700524 testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
jrose55220c32009-10-21 23:19:48 -0700525 }
526
527 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
528 for (Object[] ac : accessCases(defc, name)) {
529 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
530 }
531 }
532 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
533 testFindStatic(true, lookup, defc, ret, name, params);
534 }
535 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
536 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700537 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800538 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700539 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700540 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700541 try {
jrose2cc9c832010-04-30 23:48:23 -0700542 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700543 target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800544 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700545 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700546 assertExceptionClass(
547 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
548 ? NoSuchMethodException.class
549 : IllegalAccessException.class,
550 noAccess);
twisti10d37ec2012-07-24 10:47:44 -0700551 if (verbosity >= 5) ex.printStackTrace(System.out);
jrose55220c32009-10-21 23:19:48 -0700552 }
jrose2cc9c832010-04-30 23:48:23 -0700553 if (verbosity >= 3)
554 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
jrose55220c32009-10-21 23:19:48 -0700555 +(noAccess == null ? "" : " !! "+noAccess));
556 if (positive && noAccess != null) throw noAccess;
557 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
558 if (!positive) return; // negative test failed as expected
559 assertEquals(type, target.type());
twisti10d37ec2012-07-24 10:47:44 -0700560 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700561 Object[] args = randomArgs(params);
562 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700563 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700564 assertCalled(name, args);
jrose2cc9c832010-04-30 23:48:23 -0700565 if (verbosity >= 1)
566 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700567 }
568
jrose942f3d32013-10-05 05:30:39 -0700569 static void assertExceptionClass(Class<? extends Throwable> expected,
570 Throwable actual) {
571 if (expected.isInstance(actual)) return;
572 actual.printStackTrace();
573 assertEquals(expected, actual.getClass());
574 }
575
jrose73016262011-05-17 19:48:19 -0700576 static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
577
jrose900bafd2010-10-30 21:08:23 -0700578 // rough check of name string
jrose73016262011-05-17 19:48:19 -0700579 static void assertNameStringContains(MethodHandle x, String s) {
580 if (!DEBUG_METHOD_HANDLE_NAMES) {
581 // ignore s
582 assertEquals("MethodHandle"+x.type(), x.toString());
583 return;
584 }
jrose900bafd2010-10-30 21:08:23 -0700585 if (x.toString().contains(s)) return;
586 assertEquals(s, x);
587 }
588
jrose55220c32009-10-21 23:19:48 -0700589 @Test
590 public void testFindVirtual() throws Throwable {
591 if (CAN_SKIP_WORKING) return;
592 startTest("findVirtual");
593 testFindVirtual(Example.class, void.class, "v0");
594 testFindVirtual(Example.class, void.class, "pkg_v0");
595 testFindVirtual(Example.class, void.class, "pri_v0");
596 testFindVirtual(Example.class, Object.class, "v1", Object.class);
597 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class);
598 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class);
599 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class);
600 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700601 testFindVirtual(Example.class, void.class, "pro_v0");
602 testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");
603
jrose55220c32009-10-21 23:19:48 -0700604 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
jrose942f3d32013-10-05 05:30:39 -0700605 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class);
606 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class);
twisti10d37ec2012-07-24 10:47:44 -0700607 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
608
jrose55220c32009-10-21 23:19:48 -0700609 // test dispatch
610 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0");
611 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0");
612 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0");
613 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0");
614 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0");
615 testFindVirtual(Example.class, IntExample.class, void.class, "v0");
616 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
617 }
618
jroseb5cd3912013-10-05 05:30:38 -0700619 @Test
620 public void testFindVirtualClone() throws Throwable {
621 // test some ad hoc system methods
622 testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");
623 testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");
624 testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");
625 for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })
626 testFindVirtual(true, PUBLIC, cls, Object.class, "clone");
627 }
628
jrose55220c32009-10-21 23:19:48 -0700629 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
630 Class<?> rcvc = defc;
631 testFindVirtual(rcvc, defc, ret, name, params);
632 }
633 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
634 for (Object[] ac : accessCases(defc, name)) {
635 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params);
636 }
637 }
638 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
639 testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
640 }
jroseb5cd3912013-10-05 05:30:38 -0700641 void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
642 testFindVirtual(positive, lookup, defc, defc, ret, name, params);
643 }
jrose55220c32009-10-21 23:19:48 -0700644 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
645 countTest(positive);
646 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800647 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700648 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700649 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700650 try {
jrose2cc9c832010-04-30 23:48:23 -0700651 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700652 target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800653 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700654 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700655 assertExceptionClass(
656 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
657 ? NoSuchMethodException.class
658 : IllegalAccessException.class,
659 noAccess);
twisti10d37ec2012-07-24 10:47:44 -0700660 if (verbosity >= 5) ex.printStackTrace(System.out);
jrose55220c32009-10-21 23:19:48 -0700661 }
jrose2cc9c832010-04-30 23:48:23 -0700662 if (verbosity >= 3)
663 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
jrose55220c32009-10-21 23:19:48 -0700664 +(noAccess == null ? "" : " !! "+noAccess));
665 if (positive && noAccess != null) throw noAccess;
666 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
667 if (!positive) return; // negative test failed as expected
twisti10d37ec2012-07-24 10:47:44 -0700668 Class<?> selfc = defc;
669 // predict receiver type narrowing:
670 if (lookup == SUBCLASS &&
671 name.contains("pro_") &&
672 selfc.isAssignableFrom(lookup.lookupClass())) {
673 selfc = lookup.lookupClass();
674 if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4);
675 }
676 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params);
jrose10f3b682010-01-07 16:16:45 -0800677 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700678 assertEquals(typeWithSelf, target.type());
jrose900bafd2010-10-30 21:08:23 -0700679 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700680 Object[] argsWithSelf = randomArgs(paramsWithSelf);
twisti10d37ec2012-07-24 10:47:44 -0700681 if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc);
jrose55220c32009-10-21 23:19:48 -0700682 printCalled(target, name, argsWithSelf);
jroseb5cd3912013-10-05 05:30:38 -0700683 Object res = target.invokeWithArguments(argsWithSelf);
684 if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) {
685 assertCalled(name, argsWithSelf);
686 } else if (name.equals("clone")) {
687 // Ad hoc method call outside Example. For Object[].clone.
688 printCalled(target, name, argsWithSelf);
689 assertEquals(MethodType.methodType(Object.class, rcvc), target.type());
690 Object orig = argsWithSelf[0];
691 assertEquals(orig.getClass(), res.getClass());
692 if (res instanceof Object[])
693 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
694 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
695 } else {
696 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
697 }
jrose2cc9c832010-04-30 23:48:23 -0700698 if (verbosity >= 1)
699 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700700 }
701
702 @Test
703 public void testFindSpecial() throws Throwable {
704 if (CAN_SKIP_WORKING) return;
705 startTest("findSpecial");
jrose2cc9c832010-04-30 23:48:23 -0700706 testFindSpecial(SubExample.class, Example.class, void.class, "v0");
707 testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
twisti10d37ec2012-07-24 10:47:44 -0700708 testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
jrose2cc9c832010-04-30 23:48:23 -0700709 // Do some negative testing:
710 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
711 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
jrose942f3d32013-10-05 05:30:39 -0700712 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
jrose2cc9c832010-04-30 23:48:23 -0700713 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
jrose942f3d32013-10-05 05:30:39 -0700714 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
jrose2cc9c832010-04-30 23:48:23 -0700715 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
jrose2cc9c832010-04-30 23:48:23 -0700716 }
jrose55220c32009-10-21 23:19:48 -0700717 }
718
jrose2cc9c832010-04-30 23:48:23 -0700719 void testFindSpecial(Class<?> specialCaller,
720 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -0700721 if (specialCaller == RemoteExample.class) {
722 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
723 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
724 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
725 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params);
726 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
727 return;
728 }
729 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
730 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
731 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
732 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
733 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
jrose55220c32009-10-21 23:19:48 -0700734 }
jrose2cc9c832010-04-30 23:48:23 -0700735 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
736 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -0700737 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700738 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800739 MethodType type = MethodType.methodType(ret, params);
jrose942f3d32013-10-05 05:30:39 -0700740 Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
741 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
742 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
jrose55220c32009-10-21 23:19:48 -0700743 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700744 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700745 try {
jrose2cc9c832010-04-30 23:48:23 -0700746 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
jrose942f3d32013-10-05 05:30:39 -0700747 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup);
748 target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
jrosef15905c2011-02-11 01:26:32 -0800749 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700750 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700751 assertExceptionClass(
752 (!specialAccessOK) // this check should happen first
753 ? IllegalAccessException.class
754 : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
755 ? NoSuchMethodException.class
756 : IllegalAccessException.class,
757 noAccess);
twisti10d37ec2012-07-24 10:47:44 -0700758 if (verbosity >= 5) ex.printStackTrace(System.out);
jrose55220c32009-10-21 23:19:48 -0700759 }
jrose2cc9c832010-04-30 23:48:23 -0700760 if (verbosity >= 3)
761 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
762 +(target == null ? "" : target.type())
763 +(noAccess == null ? "" : " !! "+noAccess));
jrose55220c32009-10-21 23:19:48 -0700764 if (positive && noAccess != null) throw noAccess;
765 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
766 if (!positive) return; // negative test failed as expected
jrose2cc9c832010-04-30 23:48:23 -0700767 assertEquals(specialCaller, target.type().parameterType(0));
768 assertEquals(type, target.type().dropParameterTypes(0,1));
769 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
jrose10f3b682010-01-07 16:16:45 -0800770 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
twisti10d37ec2012-07-24 10:47:44 -0700771 assertNameStringContains(target, methodName);
jrose55220c32009-10-21 23:19:48 -0700772 Object[] args = randomArgs(paramsWithSelf);
773 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700774 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700775 assertCalled(name, args);
jrose55220c32009-10-21 23:19:48 -0700776 }
777
778 @Test
jroseb4be0262011-07-16 15:44:33 -0700779 public void testFindConstructor() throws Throwable {
780 if (CAN_SKIP_WORKING) return;
781 startTest("findConstructor");
782 testFindConstructor(true, EXAMPLE, Example.class);
783 testFindConstructor(true, EXAMPLE, Example.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700784 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class);
785 testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class);
786 testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class);
787 testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class);
jroseb4be0262011-07-16 15:44:33 -0700788 testFindConstructor(true, EXAMPLE, Example.class, String.class);
twisti10d37ec2012-07-24 10:47:44 -0700789 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class);
790 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class);
jroseb4be0262011-07-16 15:44:33 -0700791 }
792 void testFindConstructor(boolean positive, Lookup lookup,
793 Class<?> defc, Class<?>... params) throws Throwable {
794 countTest(positive);
795 MethodType type = MethodType.methodType(void.class, params);
796 MethodHandle target = null;
797 Exception noAccess = null;
798 try {
799 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type);
800 target = lookup.findConstructor(defc, type);
801 } catch (ReflectiveOperationException ex) {
802 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700803 assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);
jroseb4be0262011-07-16 15:44:33 -0700804 }
805 if (verbosity >= 3)
806 System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
807 +(target == null ? "" : target.type())
808 +(noAccess == null ? "" : " !! "+noAccess));
809 if (positive && noAccess != null) throw noAccess;
810 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
811 if (!positive) return; // negative test failed as expected
812 assertEquals(type.changeReturnType(defc), target.type());
813 Object[] args = randomArgs(params);
814 printCalled(target, defc.getSimpleName(), args);
815 Object obj = target.invokeWithArguments(args);
816 if (!(defc == Example.class && params.length < 2))
817 assertCalled(defc.getSimpleName()+".<init>", args);
818 assertTrue("instance of "+defc.getName(), defc.isInstance(obj));
819 }
820
821 @Test
jrose55220c32009-10-21 23:19:48 -0700822 public void testBind() throws Throwable {
823 if (CAN_SKIP_WORKING) return;
824 startTest("bind");
825 testBind(Example.class, void.class, "v0");
826 testBind(Example.class, void.class, "pkg_v0");
827 testBind(Example.class, void.class, "pri_v0");
828 testBind(Example.class, Object.class, "v1", Object.class);
829 testBind(Example.class, Object.class, "v2", Object.class, Object.class);
830 testBind(Example.class, Object.class, "v2", Object.class, int.class);
831 testBind(Example.class, Object.class, "v2", int.class, Object.class);
832 testBind(Example.class, Object.class, "v2", int.class, int.class);
833 testBind(false, PRIVATE, Example.class, void.class, "bogus");
jrose942f3d32013-10-05 05:30:39 -0700834 testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class);
835 testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
jrose55220c32009-10-21 23:19:48 -0700836 testBind(SubExample.class, void.class, "Sub/v0");
837 testBind(SubExample.class, void.class, "Sub/pkg_v0");
838 testBind(IntExample.Impl.class, void.class, "Int/v0");
839 }
840
841 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
842 for (Object[] ac : accessCases(defc, name)) {
843 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
844 }
845 }
846
847 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
848 countTest(positive);
849 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800850 MethodType type = MethodType.methodType(ret, params);
jrose55220c32009-10-21 23:19:48 -0700851 Object receiver = randomArg(defc);
852 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700853 Exception noAccess = null;
jrose55220c32009-10-21 23:19:48 -0700854 try {
jrose2cc9c832010-04-30 23:48:23 -0700855 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
twisti10d37ec2012-07-24 10:47:44 -0700856 target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
jrosef15905c2011-02-11 01:26:32 -0800857 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700858 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700859 assertExceptionClass(
860 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
861 ? NoSuchMethodException.class
862 : IllegalAccessException.class,
863 noAccess);
twisti10d37ec2012-07-24 10:47:44 -0700864 if (verbosity >= 5) ex.printStackTrace(System.out);
jrose55220c32009-10-21 23:19:48 -0700865 }
jrose2cc9c832010-04-30 23:48:23 -0700866 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -0700867 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
868 +(noAccess == null ? "" : " !! "+noAccess));
869 if (positive && noAccess != null) throw noAccess;
870 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
871 if (!positive) return; // negative test failed as expected
872 assertEquals(type, target.type());
873 Object[] args = randomArgs(params);
874 printCalled(target, name, args);
jrose900bafd2010-10-30 21:08:23 -0700875 target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -0700876 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
877 assertCalled(name, argsWithReceiver);
jrose2cc9c832010-04-30 23:48:23 -0700878 if (verbosity >= 1)
879 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700880 }
881
882 @Test
883 public void testUnreflect() throws Throwable {
884 if (CAN_SKIP_WORKING) return;
885 startTest("unreflect");
886 testUnreflect(Example.class, true, void.class, "s0");
twisti10d37ec2012-07-24 10:47:44 -0700887 testUnreflect(Example.class, true, void.class, "pro_s0");
jrose55220c32009-10-21 23:19:48 -0700888 testUnreflect(Example.class, true, void.class, "pkg_s0");
889 testUnreflect(Example.class, true, void.class, "pri_s0");
890
891 testUnreflect(Example.class, true, Object.class, "s1", Object.class);
892 testUnreflect(Example.class, true, Object.class, "s2", int.class);
jrose2cc9c832010-04-30 23:48:23 -0700893 testUnreflect(Example.class, true, Object.class, "s3", long.class);
894 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
895 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
896 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
jrose55220c32009-10-21 23:19:48 -0700897
898 testUnreflect(Example.class, false, void.class, "v0");
899 testUnreflect(Example.class, false, void.class, "pkg_v0");
900 testUnreflect(Example.class, false, void.class, "pri_v0");
901 testUnreflect(Example.class, false, Object.class, "v1", Object.class);
902 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class);
903 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class);
904 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class);
905 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class);
twisti10d37ec2012-07-24 10:47:44 -0700906
907 // Test a public final member in another package:
908 testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0");
jrose55220c32009-10-21 23:19:48 -0700909 }
910
911 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
912 for (Object[] ac : accessCases(defc, name)) {
jrose2cc9c832010-04-30 23:48:23 -0700913 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params);
jrose55220c32009-10-21 23:19:48 -0700914 }
915 }
jrose2cc9c832010-04-30 23:48:23 -0700916 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
917 for (Object[] ac : accessCases(defc, name)) {
918 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
919 }
920 }
921 void testUnreflectMaybeSpecial(Class<?> specialCaller,
922 boolean positive, Lookup lookup,
923 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -0700924 countTest(positive);
twisti10d37ec2012-07-24 10:47:44 -0700925 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
jrose10f3b682010-01-07 16:16:45 -0800926 MethodType type = MethodType.methodType(ret, params);
jrose942f3d32013-10-05 05:30:39 -0700927 Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null);
928 boolean specialAccessOK = (specialCaller != null &&
929 specialLookup.lookupClass() == specialCaller &&
930 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
twisti10d37ec2012-07-24 10:47:44 -0700931 Method rmethod = defc.getDeclaredMethod(methodName, params);
jrose55220c32009-10-21 23:19:48 -0700932 MethodHandle target = null;
jrosea1ebbe62010-09-08 18:40:23 -0700933 Exception noAccess = null;
jrose2cc9c832010-04-30 23:48:23 -0700934 boolean isStatic = (rcvc == null);
935 boolean isSpecial = (specialCaller != null);
jrose55220c32009-10-21 23:19:48 -0700936 try {
jrose2cc9c832010-04-30 23:48:23 -0700937 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
938 if (isSpecial)
jrose942f3d32013-10-05 05:30:39 -0700939 target = specialLookup.unreflectSpecial(rmethod, specialCaller);
jrose2cc9c832010-04-30 23:48:23 -0700940 else
twisti10d37ec2012-07-24 10:47:44 -0700941 target = maybeMoveIn(lookup, defc).unreflect(rmethod);
jrosef15905c2011-02-11 01:26:32 -0800942 } catch (ReflectiveOperationException ex) {
jrose55220c32009-10-21 23:19:48 -0700943 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -0700944 assertExceptionClass(
945 IllegalAccessException.class, // NSME is impossible, since it was already reflected
946 noAccess);
twisti10d37ec2012-07-24 10:47:44 -0700947 if (verbosity >= 5) ex.printStackTrace(System.out);
jrose55220c32009-10-21 23:19:48 -0700948 }
jrose2cc9c832010-04-30 23:48:23 -0700949 if (verbosity >= 3)
950 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
951 +(!isSpecial ? "" : " specialCaller="+specialCaller)
952 +( isStatic ? "" : " receiver="+rcvc)
953 +" => "+target
954 +(noAccess == null ? "" : " !! "+noAccess));
jrose55220c32009-10-21 23:19:48 -0700955 if (positive && noAccess != null) throw noAccess;
956 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
957 if (!positive) return; // negative test failed as expected
jrose2cc9c832010-04-30 23:48:23 -0700958 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
jrose55220c32009-10-21 23:19:48 -0700959 Class<?>[] paramsMaybeWithSelf = params;
960 if (!isStatic) {
jrose2cc9c832010-04-30 23:48:23 -0700961 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params);
jrose55220c32009-10-21 23:19:48 -0700962 }
jrose10f3b682010-01-07 16:16:45 -0800963 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700964 if (isStatic) {
965 assertEquals(typeMaybeWithSelf, target.type());
966 } else {
jrose2cc9c832010-04-30 23:48:23 -0700967 if (isSpecial)
968 assertEquals(specialCaller, target.type().parameterType(0));
969 else
970 assertEquals(defc, target.type().parameterType(0));
971 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc));
972 }
jrose55220c32009-10-21 23:19:48 -0700973 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
974 printCalled(target, name, argsMaybeWithSelf);
jrose900bafd2010-10-30 21:08:23 -0700975 target.invokeWithArguments(argsMaybeWithSelf);
jrose55220c32009-10-21 23:19:48 -0700976 assertCalled(name, argsMaybeWithSelf);
jrose2cc9c832010-04-30 23:48:23 -0700977 if (verbosity >= 1)
978 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -0700979 }
980
jrose2cc9c832010-04-30 23:48:23 -0700981 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
982 for (Object[] ac : accessCases(defc, name, true)) {
983 Class<?> specialCaller = rcvc;
984 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
985 }
986 }
987
988 @Test
jrose55220c32009-10-21 23:19:48 -0700989 public void testUnreflectSpecial() throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -0700990 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -0700991 startTest("unreflectSpecial");
jrose2cc9c832010-04-30 23:48:23 -0700992 testUnreflectSpecial(Example.class, Example.class, void.class, "v0");
993 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0");
994 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0");
995 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0");
996 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class);
997 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class);
998 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0");
jrose55220c32009-10-21 23:19:48 -0700999 }
1000
jrose10f3b682010-01-07 16:16:45 -08001001 public static class HasFields {
1002 boolean fZ = false;
1003 byte fB = (byte)'B';
1004 short fS = (short)'S';
1005 char fC = 'C';
1006 int fI = 'I';
1007 long fJ = 'J';
1008 float fF = 'F';
1009 double fD = 'D';
1010 static boolean sZ = true;
1011 static byte sB = 1+(byte)'B';
1012 static short sS = 1+(short)'S';
1013 static char sC = 1+'C';
1014 static int sI = 1+'I';
1015 static long sJ = 1+'J';
1016 static float sF = 1+'F';
1017 static double sD = 1+'D';
1018
1019 Object fL = 'L';
1020 String fR = "R";
1021 static Object sL = 'M';
1022 static String sR = "S";
1023
1024 static final Object[][] CASES;
1025 static {
jrose49494522012-01-18 17:34:29 -08001026 ArrayList<Object[]> cases = new ArrayList<>();
jrose10f3b682010-01-07 16:16:45 -08001027 Object types[][] = {
1028 {'L',Object.class}, {'R',String.class},
1029 {'I',int.class}, {'J',long.class},
1030 {'F',float.class}, {'D',double.class},
1031 {'Z',boolean.class}, {'B',byte.class},
1032 {'S',short.class}, {'C',char.class},
1033 };
1034 HasFields fields = new HasFields();
1035 for (Object[] t : types) {
1036 for (int kind = 0; kind <= 1; kind++) {
1037 boolean isStatic = (kind != 0);
1038 char btc = (Character)t[0];
1039 String name = (isStatic ? "s" : "f") + btc;
1040 Class<?> type = (Class<?>) t[1];
1041 Object value;
1042 Field field;
jrose320b7692011-05-12 19:27:49 -07001043 try {
jrose10f3b682010-01-07 16:16:45 -08001044 field = HasFields.class.getDeclaredField(name);
jrose49494522012-01-18 17:34:29 -08001045 } catch (NoSuchFieldException | SecurityException ex) {
jrose10f3b682010-01-07 16:16:45 -08001046 throw new InternalError("no field HasFields."+name);
1047 }
1048 try {
1049 value = field.get(fields);
jrose49494522012-01-18 17:34:29 -08001050 } catch (IllegalArgumentException | IllegalAccessException ex) {
jrose10f3b682010-01-07 16:16:45 -08001051 throw new InternalError("cannot fetch field HasFields."+name);
1052 }
1053 if (type == float.class) {
1054 float v = 'F';
1055 if (isStatic) v++;
jrosef15905c2011-02-11 01:26:32 -08001056 assertTrue(value.equals(v));
jrose10f3b682010-01-07 16:16:45 -08001057 }
jrosef15905c2011-02-11 01:26:32 -08001058 assertTrue(name.equals(field.getName()));
1059 assertTrue(type.equals(field.getType()));
1060 assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));
jrose10f3b682010-01-07 16:16:45 -08001061 cases.add(new Object[]{ field, value });
1062 }
1063 }
jrosef15905c2011-02-11 01:26:32 -08001064 cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class });
1065 cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class });
jrose10f3b682010-01-07 16:16:45 -08001066 CASES = cases.toArray(new Object[0][]);
1067 }
1068 }
1069
twisti10d37ec2012-07-24 10:47:44 -07001070 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 -07001071 static boolean testModeMatches(int testMode, boolean isStatic) {
1072 switch (testMode) {
jrosef15905c2011-02-11 01:26:32 -08001073 case TEST_FIND_STATIC: return isStatic;
jrosecf98d422010-06-08 23:08:56 -07001074 case TEST_FIND_FIELD: return !isStatic;
jrosef15905c2011-02-11 01:26:32 -08001075 case TEST_UNREFLECT: return true; // unreflect matches both
jrosecf98d422010-06-08 23:08:56 -07001076 }
jrosef15905c2011-02-11 01:26:32 -08001077 throw new InternalError("testMode="+testMode);
jrosecf98d422010-06-08 23:08:56 -07001078 }
1079
jrose10f3b682010-01-07 16:16:45 -08001080 @Test
jrose55220c32009-10-21 23:19:48 -07001081 public void testUnreflectGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001082 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -07001083 startTest("unreflectGetter");
jrosecf98d422010-06-08 23:08:56 -07001084 testGetter(TEST_UNREFLECT);
1085 }
1086 @Test
1087 public void testFindGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001088 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001089 startTest("findGetter");
1090 testGetter(TEST_FIND_FIELD);
twisti10d37ec2012-07-24 10:47:44 -07001091 testGetter(TEST_FIND_FIELD | TEST_BOUND);
jrosecf98d422010-06-08 23:08:56 -07001092 }
1093 @Test
1094 public void testFindStaticGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001095 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001096 startTest("findStaticGetter");
jrosef15905c2011-02-11 01:26:32 -08001097 testGetter(TEST_FIND_STATIC);
jrosecf98d422010-06-08 23:08:56 -07001098 }
1099 public void testGetter(int testMode) throws Throwable {
1100 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
jrose10f3b682010-01-07 16:16:45 -08001101 for (Object[] c : HasFields.CASES) {
jrosef15905c2011-02-11 01:26:32 -08001102 boolean positive = (c[1] != Error.class);
1103 testGetter(positive, lookup, c[0], c[1], testMode);
jrose485df122012-07-12 00:11:35 -07001104 if (positive)
1105 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
jrosef15905c2011-02-11 01:26:32 -08001106 }
1107 testGetter(true, lookup,
1108 new Object[]{ true, System.class, "out", java.io.PrintStream.class },
1109 System.out, testMode);
1110 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1111 testGetter(false, lookup,
1112 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1113 null, testMode);
jrose10f3b682010-01-07 16:16:45 -08001114 }
1115 }
jrosef15905c2011-02-11 01:26:32 -08001116 public void testGetter(boolean positive, MethodHandles.Lookup lookup,
1117 Object fieldRef, Object value, int testMode) throws Throwable {
1118 testAccessor(positive, lookup, fieldRef, value, testMode);
1119 }
1120
jrose485df122012-07-12 00:11:35 -07001121 public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,
jrosef15905c2011-02-11 01:26:32 -08001122 Object fieldRef, Object value, int testMode0) throws Throwable {
jroseb4be0262011-07-16 15:44:33 -07001123 if (verbosity >= 4)
jrose485df122012-07-12 00:11:35 -07001124 System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));
jrosef15905c2011-02-11 01:26:32 -08001125 boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
twisti10d37ec2012-07-24 10:47:44 -07001126 boolean doBound = ((testMode0 & TEST_BOUND) != 0);
jrose485df122012-07-12 00:11:35 -07001127 boolean testNPE = ((testMode0 & TEST_NPE) != 0);
twisti10d37ec2012-07-24 10:47:44 -07001128 int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE);
jrose485df122012-07-12 00:11:35 -07001129 boolean positive = positive0 && !testNPE;
jrosef15905c2011-02-11 01:26:32 -08001130 boolean isStatic;
1131 Class<?> fclass;
1132 String fname;
1133 Class<?> ftype;
1134 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null);
1135 if (f != null) {
1136 isStatic = Modifier.isStatic(f.getModifiers());
1137 fclass = f.getDeclaringClass();
1138 fname = f.getName();
1139 ftype = f.getType();
1140 } else {
1141 Object[] scnt = (Object[]) fieldRef;
1142 isStatic = (Boolean) scnt[0];
1143 fclass = (Class<?>) scnt[1];
1144 fname = (String) scnt[2];
1145 ftype = (Class<?>) scnt[3];
1146 try {
1147 f = fclass.getDeclaredField(fname);
1148 } catch (ReflectiveOperationException ex) {
1149 f = null;
1150 }
1151 }
jrosecf98d422010-06-08 23:08:56 -07001152 if (!testModeMatches(testMode, isStatic)) return;
jrosef15905c2011-02-11 01:26:32 -08001153 if (f == null && testMode == TEST_UNREFLECT) return;
jrose485df122012-07-12 00:11:35 -07001154 if (testNPE && isStatic) return;
jrosef15905c2011-02-11 01:26:32 -08001155 countTest(positive);
1156 MethodType expType;
1157 if (isGetter)
1158 expType = MethodType.methodType(ftype, HasFields.class);
1159 else
1160 expType = MethodType.methodType(void.class, HasFields.class, ftype);
jrose10f3b682010-01-07 16:16:45 -08001161 if (isStatic) expType = expType.dropParameterTypes(0, 1);
jrosef15905c2011-02-11 01:26:32 -08001162 Exception noAccess = null;
1163 MethodHandle mh;
1164 try {
twisti10d37ec2012-07-24 10:47:44 -07001165 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) {
jrosef15905c2011-02-11 01:26:32 -08001166 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break;
1167 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break;
1168 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break;
1169 case TEST_SETTER|
1170 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break;
1171 case TEST_SETTER|
1172 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break;
1173 case TEST_SETTER|
1174 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break;
1175 default:
1176 throw new InternalError("testMode="+testMode);
1177 }
1178 } catch (ReflectiveOperationException ex) {
1179 mh = null;
1180 noAccess = ex;
jrose942f3d32013-10-05 05:30:39 -07001181 assertExceptionClass(
1182 (fname.contains("bogus"))
1183 ? NoSuchFieldException.class
1184 : IllegalAccessException.class,
1185 noAccess);
twisti10d37ec2012-07-24 10:47:44 -07001186 if (verbosity >= 5) ex.printStackTrace(System.out);
jrosef15905c2011-02-11 01:26:32 -08001187 }
1188 if (verbosity >= 3)
1189 System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
1190 +" => "+mh
1191 +(noAccess == null ? "" : " !! "+noAccess));
jrose485df122012-07-12 00:11:35 -07001192 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess);
1193 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
1194 if (!positive && !testNPE) return; // negative access test failed as expected
jrosef15905c2011-02-11 01:26:32 -08001195 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
1196
1197
jrose10f3b682010-01-07 16:16:45 -08001198 assertSame(mh.type(), expType);
twisti10d37ec2012-07-24 10:47:44 -07001199 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs
jrose10f3b682010-01-07 16:16:45 -08001200 HasFields fields = new HasFields();
jrose485df122012-07-12 00:11:35 -07001201 HasFields fieldsForMH = fields;
1202 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error
twisti10d37ec2012-07-24 10:47:44 -07001203 if (doBound)
1204 mh = mh.bindTo(fieldsForMH);
jrose10f3b682010-01-07 16:16:45 -08001205 Object sawValue;
jrosef15905c2011-02-11 01:26:32 -08001206 Class<?> vtype = ftype;
1207 if (ftype != int.class) vtype = Object.class;
1208 if (isGetter) {
jrose9b82ad62011-05-26 17:37:36 -07001209 mh = mh.asType(mh.type().generic()
1210 .changeReturnType(vtype));
jrosef15905c2011-02-11 01:26:32 -08001211 } else {
1212 int last = mh.type().parameterCount() - 1;
jrose9b82ad62011-05-26 17:37:36 -07001213 mh = mh.asType(mh.type().generic()
1214 .changeReturnType(void.class)
1215 .changeParameterType(last, vtype));
jrose10f3b682010-01-07 16:16:45 -08001216 }
jrosef15905c2011-02-11 01:26:32 -08001217 if (f != null && f.getDeclaringClass() == HasFields.class) {
1218 assertEquals(f.get(fields), value); // clean to start with
1219 }
jrose485df122012-07-12 00:11:35 -07001220 Throwable caughtEx = null;
jrosef15905c2011-02-11 01:26:32 -08001221 if (isGetter) {
1222 Object expValue = value;
1223 for (int i = 0; i <= 1; i++) {
twisti10d37ec2012-07-24 10:47:44 -07001224 sawValue = null; // make DA rules happy under try/catch
1225 try {
1226 if (isStatic || doBound) {
1227 if (ftype == int.class)
1228 sawValue = (int) mh.invokeExact(); // do these exactly
1229 else
1230 sawValue = mh.invokeExact();
1231 } else {
jrose485df122012-07-12 00:11:35 -07001232 if (ftype == int.class)
1233 sawValue = (int) mh.invokeExact((Object) fieldsForMH);
1234 else
1235 sawValue = mh.invokeExact((Object) fieldsForMH);
twisti10d37ec2012-07-24 10:47:44 -07001236 }
1237 } catch (RuntimeException ex) {
1238 if (ex instanceof NullPointerException && testNPE) {
1239 caughtEx = ex;
1240 break;
jrose485df122012-07-12 00:11:35 -07001241 }
jrosef15905c2011-02-11 01:26:32 -08001242 }
1243 assertEquals(sawValue, expValue);
1244 if (f != null && f.getDeclaringClass() == HasFields.class
1245 && !Modifier.isFinal(f.getModifiers())) {
1246 Object random = randomArg(ftype);
1247 f.set(fields, random);
1248 expValue = random;
1249 } else {
1250 break;
1251 }
1252 }
1253 } else {
1254 for (int i = 0; i <= 1; i++) {
1255 Object putValue = randomArg(ftype);
twisti10d37ec2012-07-24 10:47:44 -07001256 try {
1257 if (isStatic || doBound) {
1258 if (ftype == int.class)
1259 mh.invokeExact((int)putValue); // do these exactly
1260 else
1261 mh.invokeExact(putValue);
1262 } else {
jrose485df122012-07-12 00:11:35 -07001263 if (ftype == int.class)
1264 mh.invokeExact((Object) fieldsForMH, (int)putValue);
1265 else
1266 mh.invokeExact((Object) fieldsForMH, putValue);
twisti10d37ec2012-07-24 10:47:44 -07001267 }
1268 } catch (RuntimeException ex) {
1269 if (ex instanceof NullPointerException && testNPE) {
1270 caughtEx = ex;
1271 break;
jrose485df122012-07-12 00:11:35 -07001272 }
jrosef15905c2011-02-11 01:26:32 -08001273 }
1274 if (f != null && f.getDeclaringClass() == HasFields.class) {
1275 assertEquals(f.get(fields), putValue);
1276 }
1277 }
1278 }
1279 if (f != null && f.getDeclaringClass() == HasFields.class) {
1280 f.set(fields, value); // put it back
1281 }
jrose485df122012-07-12 00:11:35 -07001282 if (testNPE) {
1283 if (caughtEx == null || !(caughtEx instanceof NullPointerException))
1284 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);
1285 caughtEx = null; // nullify expected exception
1286 }
1287 if (caughtEx != null) {
1288 throw new RuntimeException("unexpected exception", caughtEx);
1289 }
jrose55220c32009-10-21 23:19:48 -07001290 }
1291
jrose10f3b682010-01-07 16:16:45 -08001292
1293 @Test
jrose55220c32009-10-21 23:19:48 -07001294 public void testUnreflectSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001295 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001296 startTest("unreflectSetter");
1297 testSetter(TEST_UNREFLECT);
1298 }
1299 @Test
1300 public void testFindSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001301 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001302 startTest("findSetter");
1303 testSetter(TEST_FIND_FIELD);
twisti10d37ec2012-07-24 10:47:44 -07001304 testSetter(TEST_FIND_FIELD | TEST_BOUND);
jrosecf98d422010-06-08 23:08:56 -07001305 }
1306 @Test
1307 public void testFindStaticSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001308 if (CAN_SKIP_WORKING) return;
jrosecf98d422010-06-08 23:08:56 -07001309 startTest("findStaticSetter");
jrosef15905c2011-02-11 01:26:32 -08001310 testSetter(TEST_FIND_STATIC);
jrosecf98d422010-06-08 23:08:56 -07001311 }
1312 public void testSetter(int testMode) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001313 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
1314 startTest("unreflectSetter");
jrose10f3b682010-01-07 16:16:45 -08001315 for (Object[] c : HasFields.CASES) {
jrosef15905c2011-02-11 01:26:32 -08001316 boolean positive = (c[1] != Error.class);
1317 testSetter(positive, lookup, c[0], c[1], testMode);
jrose485df122012-07-12 00:11:35 -07001318 if (positive)
1319 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
jrosef15905c2011-02-11 01:26:32 -08001320 }
1321 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1322 testSetter(false, lookup,
1323 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1324 null, testMode);
jrose10f3b682010-01-07 16:16:45 -08001325 }
1326 }
jrosef15905c2011-02-11 01:26:32 -08001327 public void testSetter(boolean positive, MethodHandles.Lookup lookup,
1328 Object fieldRef, Object value, int testMode) throws Throwable {
1329 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER);
jrose55220c32009-10-21 23:19:48 -07001330 }
1331
jrose10f3b682010-01-07 16:16:45 -08001332 @Test
jrose55220c32009-10-21 23:19:48 -07001333 public void testArrayElementGetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001334 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -07001335 startTest("arrayElementGetter");
jrose2cc9c832010-04-30 23:48:23 -07001336 testArrayElementGetterSetter(false);
jrose55220c32009-10-21 23:19:48 -07001337 }
1338
jrose10f3b682010-01-07 16:16:45 -08001339 @Test
jrose55220c32009-10-21 23:19:48 -07001340 public void testArrayElementSetter() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001341 if (CAN_SKIP_WORKING) return;
jrose55220c32009-10-21 23:19:48 -07001342 startTest("arrayElementSetter");
jrose2cc9c832010-04-30 23:48:23 -07001343 testArrayElementGetterSetter(true);
1344 }
1345
jrose485df122012-07-12 00:11:35 -07001346 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;
1347
jrose2cc9c832010-04-30 23:48:23 -07001348 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
jrose485df122012-07-12 00:11:35 -07001349 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);
jrose10f3b682010-01-07 16:16:45 -08001350 }
1351
jrose485df122012-07-12 00:11:35 -07001352 @Test
1353 public void testArrayElementErrors() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001354 if (CAN_SKIP_WORKING) return;
jrose485df122012-07-12 00:11:35 -07001355 startTest("arrayElementErrors");
1356 testArrayElementGetterSetter(false, TEST_ARRAY_NPE);
1357 testArrayElementGetterSetter(true, TEST_ARRAY_NPE);
1358 testArrayElementGetterSetter(false, TEST_ARRAY_OOB);
1359 testArrayElementGetterSetter(true, TEST_ARRAY_OOB);
1360 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);
1361 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);
1362 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);
1363 }
1364
1365 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {
1366 testArrayElementGetterSetter(new String[10], testSetter, negTest);
1367 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);
1368 testArrayElementGetterSetter(new Example[10], testSetter, negTest);
1369 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);
1370 testArrayElementGetterSetter(new Object[10], testSetter, negTest);
1371 testArrayElementGetterSetter(new boolean[10], testSetter, negTest);
1372 testArrayElementGetterSetter(new byte[10], testSetter, negTest);
1373 testArrayElementGetterSetter(new char[10], testSetter, negTest);
1374 testArrayElementGetterSetter(new short[10], testSetter, negTest);
1375 testArrayElementGetterSetter(new int[10], testSetter, negTest);
1376 testArrayElementGetterSetter(new float[10], testSetter, negTest);
1377 testArrayElementGetterSetter(new long[10], testSetter, negTest);
1378 testArrayElementGetterSetter(new double[10], testSetter, negTest);
1379 }
1380
1381 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {
1382 boolean positive = (negTest == TEST_ARRAY_NONE);
1383 int length = java.lang.reflect.Array.getLength(array);
jrose10f3b682010-01-07 16:16:45 -08001384 Class<?> arrayType = array.getClass();
1385 Class<?> elemType = arrayType.getComponentType();
jrose485df122012-07-12 00:11:35 -07001386 Object arrayToMH = array;
1387 // this stanza allows negative tests to make argument perturbations:
1388 switch (negTest) {
1389 case TEST_ARRAY_NPE:
1390 arrayToMH = null;
1391 break;
1392 case TEST_ARRAY_OOB:
1393 assert(length > 0);
1394 arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);
1395 break;
1396 case TEST_ARRAY_ASE:
1397 assert(testSetter && !elemType.isPrimitive());
1398 if (elemType == Object.class)
1399 arrayToMH = new StringBuffer[length]; // very random subclass of Object!
1400 else if (elemType == Example.class)
1401 arrayToMH = new SubExample[length];
1402 else if (elemType == IntExample.class)
1403 arrayToMH = new SubIntExample[length];
1404 else
1405 return; // can't make an ArrayStoreException test
1406 assert(arrayType.isInstance(arrayToMH))
1407 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);
1408 break;
1409 }
1410 countTest(positive);
1411 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 -08001412 MethodType expType = !testSetter
1413 ? MethodType.methodType(elemType, arrayType, int.class)
1414 : MethodType.methodType(void.class, arrayType, int.class, elemType);
1415 MethodHandle mh = !testSetter
1416 ? MethodHandles.arrayElementGetter(arrayType)
1417 : MethodHandles.arrayElementSetter(arrayType);
1418 assertSame(mh.type(), expType);
jrose2cc9c832010-04-30 23:48:23 -07001419 if (elemType != int.class && elemType != boolean.class) {
jrose485df122012-07-12 00:11:35 -07001420 MethodType gtype = mh.type().generic().changeParameterType(1, int.class);
jrose320b7692011-05-12 19:27:49 -07001421 if (testSetter) gtype = gtype.changeReturnType(void.class);
jrose9b82ad62011-05-26 17:37:36 -07001422 mh = mh.asType(gtype);
jrose2cc9c832010-04-30 23:48:23 -07001423 }
jrose10f3b682010-01-07 16:16:45 -08001424 Object sawValue, expValue;
1425 List<Object> model = array2list(array);
jrose485df122012-07-12 00:11:35 -07001426 Throwable caughtEx = null;
jrose10f3b682010-01-07 16:16:45 -08001427 for (int i = 0; i < length; i++) {
1428 // update array element
1429 Object random = randomArg(elemType);
1430 model.set(i, random);
1431 if (testSetter) {
jrose485df122012-07-12 00:11:35 -07001432 try {
1433 if (elemType == int.class)
1434 mh.invokeExact((int[]) arrayToMH, i, (int)random);
1435 else if (elemType == boolean.class)
1436 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);
1437 else
1438 mh.invokeExact(arrayToMH, i, random);
1439 } catch (RuntimeException ex) {
1440 caughtEx = ex;
1441 break;
1442 }
jrose10f3b682010-01-07 16:16:45 -08001443 assertEquals(model, array2list(array));
1444 } else {
1445 Array.set(array, i, random);
jrose2cc9c832010-04-30 23:48:23 -07001446 }
1447 if (verbosity >= 5) {
1448 List<Object> array2list = array2list(array);
1449 System.out.println("a["+i+"]="+random+" => "+array2list);
1450 if (!array2list.equals(model))
1451 System.out.println("*** != "+model);
jrose10f3b682010-01-07 16:16:45 -08001452 }
1453 // observe array element
1454 sawValue = Array.get(array, i);
1455 if (!testSetter) {
1456 expValue = sawValue;
jrose485df122012-07-12 00:11:35 -07001457 try {
1458 if (elemType == int.class)
1459 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);
1460 else if (elemType == boolean.class)
1461 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);
1462 else
1463 sawValue = mh.invokeExact(arrayToMH, i);
1464 } catch (RuntimeException ex) {
1465 caughtEx = ex;
1466 break;
1467 }
jrose10f3b682010-01-07 16:16:45 -08001468 assertEquals(sawValue, expValue);
1469 assertEquals(model, array2list(array));
1470 }
1471 }
jrose485df122012-07-12 00:11:35 -07001472 if (!positive) {
1473 if (caughtEx == null)
1474 throw new RuntimeException("failed to catch exception for negTest="+negTest);
1475 // test the kind of exception
1476 Class<?> reqType = null;
1477 switch (negTest) {
1478 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break;
1479 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break;
1480 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break;
1481 default: assert(false);
1482 }
1483 if (reqType.isInstance(caughtEx)) {
1484 caughtEx = null; // nullify expected exception
1485 }
1486 }
1487 if (caughtEx != null) {
1488 throw new RuntimeException("unexpected exception", caughtEx);
1489 }
jrose10f3b682010-01-07 16:16:45 -08001490 }
1491
1492 List<Object> array2list(Object array) {
1493 int length = Array.getLength(array);
jrose49494522012-01-18 17:34:29 -08001494 ArrayList<Object> model = new ArrayList<>(length);
jrose10f3b682010-01-07 16:16:45 -08001495 for (int i = 0; i < length; i++)
1496 model.add(Array.get(array, i));
1497 return model;
jrose55220c32009-10-21 23:19:48 -07001498 }
1499
1500 static class Callee {
1501 static Object id() { return called("id"); }
1502 static Object id(Object x) { return called("id", x); }
1503 static Object id(Object x, Object y) { return called("id", x, y); }
1504 static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }
1505 static Object id(Object... vx) { return called("id", vx); }
1506 static MethodHandle ofType(int n) {
1507 return ofType(Object.class, n);
1508 }
1509 static MethodHandle ofType(Class<?> rtype, int n) {
1510 if (n == -1)
jrose10f3b682010-01-07 16:16:45 -08001511 return ofType(MethodType.methodType(rtype, Object[].class));
1512 return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));
jrose55220c32009-10-21 23:19:48 -07001513 }
1514 static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {
jrose10f3b682010-01-07 16:16:45 -08001515 return ofType(MethodType.methodType(rtype, ptypes));
jrose55220c32009-10-21 23:19:48 -07001516 }
1517 static MethodHandle ofType(MethodType type) {
1518 Class<?> rtype = type.returnType();
1519 String pfx = "";
1520 if (rtype != Object.class)
1521 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
1522 String name = pfx+"id";
jrosea1ebbe62010-09-08 18:40:23 -07001523 try {
1524 return PRIVATE.findStatic(Callee.class, name, type);
jrose49494522012-01-18 17:34:29 -08001525 } catch (NoSuchMethodException | IllegalAccessException ex) {
jrosea1ebbe62010-09-08 18:40:23 -07001526 throw new RuntimeException(ex);
1527 }
jrose55220c32009-10-21 23:19:48 -07001528 }
1529 }
1530
1531 @Test
1532 public void testConvertArguments() throws Throwable {
1533 if (CAN_SKIP_WORKING) return;
1534 startTest("convertArguments");
1535 testConvert(Callee.ofType(1), null, "id", int.class);
1536 testConvert(Callee.ofType(1), null, "id", String.class);
1537 testConvert(Callee.ofType(1), null, "id", Integer.class);
1538 testConvert(Callee.ofType(1), null, "id", short.class);
jrose2cc9c832010-04-30 23:48:23 -07001539 testConvert(Callee.ofType(1), null, "id", char.class);
1540 testConvert(Callee.ofType(1), null, "id", byte.class);
jrose55220c32009-10-21 23:19:48 -07001541 }
1542
1543 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
jrose9b82ad62011-05-26 17:37:36 -07001544 testConvert(true, id, rtype, name, params);
jrose55220c32009-10-21 23:19:48 -07001545 }
1546
jrose9b82ad62011-05-26 17:37:36 -07001547 void testConvert(boolean positive,
jrose900bafd2010-10-30 21:08:23 -07001548 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001549 countTest(positive);
1550 MethodType idType = id.type();
1551 if (rtype == null) rtype = idType.returnType();
1552 for (int i = 0; i < params.length; i++) {
1553 if (params[i] == null) params[i] = idType.parameterType(i);
1554 }
1555 // simulate the pairwise conversion
jrose10f3b682010-01-07 16:16:45 -08001556 MethodType newType = MethodType.methodType(rtype, params);
jrose55220c32009-10-21 23:19:48 -07001557 Object[] args = randomArgs(newType.parameterArray());
1558 Object[] convArgs = args.clone();
1559 for (int i = 0; i < args.length; i++) {
1560 Class<?> src = newType.parameterType(i);
1561 Class<?> dst = idType.parameterType(i);
1562 if (src != dst)
1563 convArgs[i] = castToWrapper(convArgs[i], dst);
1564 }
jrose900bafd2010-10-30 21:08:23 -07001565 Object convResult = id.invokeWithArguments(convArgs);
jrose55220c32009-10-21 23:19:48 -07001566 {
1567 Class<?> dst = newType.returnType();
1568 Class<?> src = idType.returnType();
1569 if (src != dst)
1570 convResult = castToWrapper(convResult, dst);
1571 }
1572 MethodHandle target = null;
1573 RuntimeException error = null;
1574 try {
jrose9b82ad62011-05-26 17:37:36 -07001575 target = id.asType(newType);
jrose4f019ca2012-08-17 13:42:25 -07001576 } catch (WrongMethodTypeException ex) {
jrose55220c32009-10-21 23:19:48 -07001577 error = ex;
1578 }
jrose2cc9c832010-04-30 23:48:23 -07001579 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -07001580 System.out.println("convert "+id+ " to "+newType+" => "+target
1581 +(error == null ? "" : " !! "+error));
1582 if (positive && error != null) throw error;
1583 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
1584 if (!positive) return; // negative test failed as expected
1585 assertEquals(newType, target.type());
1586 printCalled(target, id.toString(), args);
jrose900bafd2010-10-30 21:08:23 -07001587 Object result = target.invokeWithArguments(args);
jrose55220c32009-10-21 23:19:48 -07001588 assertCalled(name, convArgs);
1589 assertEquals(convResult, result);
jrose2cc9c832010-04-30 23:48:23 -07001590 if (verbosity >= 1)
1591 System.out.print(':');
jrose55220c32009-10-21 23:19:48 -07001592 }
1593
1594 @Test
jrosef108fc02011-02-11 01:26:24 -08001595 public void testVarargsCollector() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07001596 if (CAN_SKIP_WORKING) return;
1597 startTest("varargsCollector");
jrosef108fc02011-02-11 01:26:24 -08001598 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called",
1599 MethodType.methodType(Object.class, String.class, Object[].class));
1600 vac0 = vac0.bindTo("vac");
1601 MethodHandle vac = vac0.asVarargsCollector(Object[].class);
jrose9b82ad62011-05-26 17:37:36 -07001602 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
1603 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
jrose49494522012-01-18 17:34:29 -08001604 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) {
jrose9b82ad62011-05-26 17:37:36 -07001605 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
1606 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
jrosef108fc02011-02-11 01:26:24 -08001607 }
1608 }
1609
twisti10d37ec2012-07-24 10:47:44 -07001610 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001611 public void testPermuteArguments() throws Throwable {
1612 if (CAN_SKIP_WORKING) return;
1613 startTest("permuteArguments");
jroseb4be0262011-07-16 15:44:33 -07001614 testPermuteArguments(4, Integer.class, 2, long.class, 6);
1615 if (CAN_TEST_LIGHTLY) return;
jrose10f3b682010-01-07 16:16:45 -08001616 testPermuteArguments(4, Integer.class, 2, String.class, 0);
jrose9b82ad62011-05-26 17:37:36 -07001617 testPermuteArguments(6, Integer.class, 0, null, 30);
jrose10f3b682010-01-07 16:16:45 -08001618 }
1619 public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -07001620 if (verbosity >= 2)
jrose10f3b682010-01-07 16:16:45 -08001621 System.out.println("permuteArguments "+max+"*"+type1.getName()
1622 +(t2c==0?"":"/"+t2c+"*"+type2.getName())
1623 +(dilution > 0 ? " with dilution "+dilution : ""));
1624 int t2pos = t2c == 0 ? 0 : 1;
1625 for (int inargs = t2pos+1; inargs <= max; inargs++) {
1626 Class<?>[] types = new Class<?>[inargs];
1627 Arrays.fill(types, type1);
1628 if (t2c != 0) {
1629 // Fill in a middle range with type2:
1630 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);
1631 }
1632 Object[] args = randomArgs(types);
1633 int numcases = 1;
1634 for (int outargs = 0; outargs <= max; outargs++) {
1635 if (outargs - inargs >= MAX_ARG_INCREASE) continue;
jrose10f3b682010-01-07 16:16:45 -08001636 int casStep = dilution + 1;
1637 // Avoid some common factors:
1638 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||
1639 (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))
1640 casStep++;
jrose320b7692011-05-12 19:27:49 -07001641 testPermuteArguments(args, types, outargs, numcases, casStep);
jrose10f3b682010-01-07 16:16:45 -08001642 numcases *= inargs;
jroseb4be0262011-07-16 15:44:33 -07001643 if (CAN_TEST_LIGHTLY && outargs < max-2) continue;
jrose10f3b682010-01-07 16:16:45 -08001644 if (dilution > 10 && outargs >= 4) {
jroseb4be0262011-07-16 15:44:33 -07001645 if (CAN_TEST_LIGHTLY) continue;
jrose320b7692011-05-12 19:27:49 -07001646 int[] reorder = new int[outargs];
jrose10f3b682010-01-07 16:16:45 -08001647 // Do some special patterns, which we probably missed.
1648 // Replication of a single argument or argument pair.
1649 for (int i = 0; i < inargs; i++) {
1650 Arrays.fill(reorder, i);
1651 testPermuteArguments(args, types, reorder);
1652 for (int d = 1; d <= 2; d++) {
1653 if (i + d >= inargs) continue;
1654 for (int j = 1; j < outargs; j += 2)
1655 reorder[j] += 1;
1656 testPermuteArguments(args, types, reorder);
1657 testPermuteArguments(args, types, reverse(reorder));
1658 }
1659 }
1660 // Repetition of a sequence of 3 or more arguments.
1661 for (int i = 1; i < inargs; i++) {
1662 for (int len = 3; len <= inargs; len++) {
1663 for (int j = 0; j < outargs; j++)
1664 reorder[j] = (i + (j % len)) % inargs;
1665 testPermuteArguments(args, types, reorder);
1666 testPermuteArguments(args, types, reverse(reorder));
1667 }
1668 }
1669 }
1670 }
1671 }
1672 }
1673
jrose320b7692011-05-12 19:27:49 -07001674 public void testPermuteArguments(Object[] args, Class<?>[] types,
1675 int outargs, int numcases, int casStep) throws Throwable {
1676 int inargs = args.length;
1677 int[] reorder = new int[outargs];
1678 for (int cas = 0; cas < numcases; cas += casStep) {
1679 for (int i = 0, c = cas; i < outargs; i++) {
1680 reorder[i] = c % inargs;
1681 c /= inargs;
1682 }
jroseb4be0262011-07-16 15:44:33 -07001683 if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2])) continue;
jrose320b7692011-05-12 19:27:49 -07001684 testPermuteArguments(args, types, reorder);
1685 }
1686 }
1687
jrose10f3b682010-01-07 16:16:45 -08001688 static int[] reverse(int[] reorder) {
1689 reorder = reorder.clone();
1690 for (int i = 0, imax = reorder.length / 2; i < imax; i++) {
1691 int j = reorder.length - 1 - i;
1692 int tem = reorder[i];
1693 reorder[i] = reorder[j];
1694 reorder[j] = tem;
1695 }
1696 return reorder;
1697 }
1698
1699 void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {
1700 countTest();
1701 if (args == null && types == null) {
1702 int max = 0;
1703 for (int j : reorder) {
1704 if (max < j) max = j;
1705 }
1706 args = randomArgs(max+1, Integer.class);
1707 }
1708 if (args == null) {
1709 args = randomArgs(types);
1710 }
1711 if (types == null) {
1712 types = new Class<?>[args.length];
1713 for (int i = 0; i < args.length; i++)
1714 types[i] = args[i].getClass();
1715 }
1716 int inargs = args.length, outargs = reorder.length;
jrosef15905c2011-02-11 01:26:32 -08001717 assertTrue(inargs == types.length);
jrose2cc9c832010-04-30 23:48:23 -07001718 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001719 System.out.println("permuteArguments "+Arrays.toString(reorder));
1720 Object[] permArgs = new Object[outargs];
1721 Class<?>[] permTypes = new Class<?>[outargs];
1722 for (int i = 0; i < outargs; i++) {
1723 permArgs[i] = args[reorder[i]];
1724 permTypes[i] = types[reorder[i]];
1725 }
jrose2cc9c832010-04-30 23:48:23 -07001726 if (verbosity >= 4) {
jrose10f3b682010-01-07 16:16:45 -08001727 System.out.println("in args: "+Arrays.asList(args));
1728 System.out.println("out args: "+Arrays.asList(permArgs));
1729 System.out.println("in types: "+Arrays.asList(types));
1730 System.out.println("out types: "+Arrays.asList(permTypes));
1731 }
1732 MethodType inType = MethodType.methodType(Object.class, types);
1733 MethodType outType = MethodType.methodType(Object.class, permTypes);
jrose9b82ad62011-05-26 17:37:36 -07001734 MethodHandle target = varargsList(outargs).asType(outType);
jrose10f3b682010-01-07 16:16:45 -08001735 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
jrose9b82ad62011-05-26 17:37:36 -07001736 if (verbosity >= 5) System.out.println("newTarget = "+newTarget);
jrose900bafd2010-10-30 21:08:23 -07001737 Object result = newTarget.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001738 Object expected = Arrays.asList(permArgs);
jrose320b7692011-05-12 19:27:49 -07001739 if (!expected.equals(result)) {
1740 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));
1741 System.out.println("in args: "+Arrays.asList(args));
1742 System.out.println("out args: "+expected);
1743 System.out.println("bad args: "+result);
1744 }
jrose10f3b682010-01-07 16:16:45 -08001745 assertEquals(expected, result);
1746 }
1747
1748
twisti10d37ec2012-07-24 10:47:44 -07001749 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08001750 public void testSpreadArguments() throws Throwable {
1751 if (CAN_SKIP_WORKING) return;
1752 startTest("spreadArguments");
jrose49494522012-01-18 17:34:29 -08001753 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose2cc9c832010-04-30 23:48:23 -07001754 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001755 System.out.println("spreadArguments "+argType);
jroseb4be0262011-07-16 15:44:33 -07001756 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001757 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001758 for (int pos = 0; pos <= nargs; pos++) {
1759 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1760 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1761 continue;
1762 testSpreadArguments(argType, pos, nargs);
jrose10f3b682010-01-07 16:16:45 -08001763 }
1764 }
1765 }
1766 }
1767 public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
1768 countTest();
jrose320b7692011-05-12 19:27:49 -07001769 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1770 MethodHandle target2 = varargsArray(arrayType, nargs);
1771 MethodHandle target = target2.asType(target2.type().generic());
jrose2cc9c832010-04-30 23:48:23 -07001772 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001773 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
1774 Object[] args = randomArgs(target2.type().parameterArray());
1775 // make sure the target does what we think it does:
jrose320b7692011-05-12 19:27:49 -07001776 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
jrose49494522012-01-18 17:34:29 -08001777 Object[] check = (Object[]) target.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001778 assertArrayEquals(args, check);
1779 switch (nargs) {
1780 case 0:
jrose320b7692011-05-12 19:27:49 -07001781 check = (Object[]) (Object) target.invokeExact();
jrose10f3b682010-01-07 16:16:45 -08001782 assertArrayEquals(args, check);
1783 break;
1784 case 1:
jrose320b7692011-05-12 19:27:49 -07001785 check = (Object[]) (Object) target.invokeExact(args[0]);
jrose10f3b682010-01-07 16:16:45 -08001786 assertArrayEquals(args, check);
1787 break;
1788 case 2:
jrose320b7692011-05-12 19:27:49 -07001789 check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
jrose10f3b682010-01-07 16:16:45 -08001790 assertArrayEquals(args, check);
1791 break;
1792 }
1793 }
jrose49494522012-01-18 17:34:29 -08001794 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
jrose10f3b682010-01-07 16:16:45 -08001795 { // modify newParams in place
1796 List<Class<?>> spreadParams = newParams.subList(pos, nargs);
jrose320b7692011-05-12 19:27:49 -07001797 spreadParams.clear(); spreadParams.add(arrayType);
jrose10f3b682010-01-07 16:16:45 -08001798 }
jrose320b7692011-05-12 19:27:49 -07001799 MethodType newType = MethodType.methodType(arrayType, newParams);
1800 MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
1801 assert(result.type() == newType) : Arrays.asList(result, newType);
1802 result = result.asType(newType.generic());
1803 Object returnValue;
jrose10f3b682010-01-07 16:16:45 -08001804 if (pos == 0) {
jrose320b7692011-05-12 19:27:49 -07001805 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1806 returnValue = result.invokeExact(args2);
jrose10f3b682010-01-07 16:16:45 -08001807 } else {
1808 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
jrose320b7692011-05-12 19:27:49 -07001809 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1810 returnValue = result.invokeWithArguments(args1);
jrose10f3b682010-01-07 16:16:45 -08001811 }
jrose320b7692011-05-12 19:27:49 -07001812 String argstr = Arrays.toString(args);
1813 if (!argType.isPrimitive()) {
1814 Object[] rv = (Object[]) returnValue;
1815 String rvs = Arrays.toString(rv);
1816 if (!Arrays.equals(args, rv)) {
1817 System.out.println("method: "+result);
1818 System.out.println("expected: "+argstr);
1819 System.out.println("returned: "+rvs);
1820 assertArrayEquals(args, rv);
1821 }
1822 } else if (argType == int.class) {
1823 String rvs = Arrays.toString((int[]) returnValue);
1824 if (!argstr.equals(rvs)) {
1825 System.out.println("method: "+result);
1826 System.out.println("expected: "+argstr);
1827 System.out.println("returned: "+rvs);
1828 assertEquals(argstr, rvs);
1829 }
1830 } else if (argType == long.class) {
1831 String rvs = Arrays.toString((long[]) returnValue);
1832 if (!argstr.equals(rvs)) {
1833 System.out.println("method: "+result);
1834 System.out.println("expected: "+argstr);
1835 System.out.println("returned: "+rvs);
1836 assertEquals(argstr, rvs);
1837 }
1838 } else {
1839 // cannot test...
1840 }
jrose10f3b682010-01-07 16:16:45 -08001841 }
1842
twisti10d37ec2012-07-24 10:47:44 -07001843 @Test // SLOW
jrose1ccb8a72013-10-05 05:30:39 -07001844 public void testAsCollector() throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08001845 if (CAN_SKIP_WORKING) return;
jrose1ccb8a72013-10-05 05:30:39 -07001846 startTest("asCollector");
jrose49494522012-01-18 17:34:29 -08001847 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose2cc9c832010-04-30 23:48:23 -07001848 if (verbosity >= 3)
jrose1ccb8a72013-10-05 05:30:39 -07001849 System.out.println("asCollector "+argType);
jroseb4be0262011-07-16 15:44:33 -07001850 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001851 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001852 for (int pos = 0; pos <= nargs; pos++) {
1853 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1854 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1855 continue;
jrose1ccb8a72013-10-05 05:30:39 -07001856 testAsCollector(argType, pos, nargs);
jrose10f3b682010-01-07 16:16:45 -08001857 }
1858 }
1859 }
1860 }
jrose1ccb8a72013-10-05 05:30:39 -07001861 public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08001862 countTest();
1863 // fake up a MH with the same type as the desired adapter:
jroseadc650a2011-02-11 01:26:28 -08001864 MethodHandle fake = varargsArray(nargs);
jrose10f3b682010-01-07 16:16:45 -08001865 fake = changeArgTypes(fake, argType);
1866 MethodType newType = fake.type();
1867 Object[] args = randomArgs(newType.parameterArray());
1868 // here is what should happen:
1869 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
1870 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
1871 // here is the MH which will witness the collected argument tail:
jroseadc650a2011-02-11 01:26:28 -08001872 MethodHandle target = varargsArray(pos+1);
jrose10f3b682010-01-07 16:16:45 -08001873 target = changeArgTypes(target, 0, pos, argType);
1874 target = changeArgTypes(target, pos, pos+1, Object[].class);
jrose2cc9c832010-04-30 23:48:23 -07001875 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001876 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
jroseadc650a2011-02-11 01:26:28 -08001877 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
jrose900bafd2010-10-30 21:08:23 -07001878 Object[] returnValue = (Object[]) result.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08001879// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
1880// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
1881// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
1882 assertArrayEquals(collectedArgs, returnValue);
1883 }
1884
twisti10d37ec2012-07-24 10:47:44 -07001885 @Test // SLOW
jrose55220c32009-10-21 23:19:48 -07001886 public void testInsertArguments() throws Throwable {
1887 if (CAN_SKIP_WORKING) return;
1888 startTest("insertArguments");
jroseb4be0262011-07-16 15:44:33 -07001889 for (int nargs = 0; nargs < 50; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07001890 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07001891 for (int ins = 0; ins <= nargs; ins++) {
1892 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
1893 continue;
jrose55220c32009-10-21 23:19:48 -07001894 for (int pos = 0; pos <= nargs; pos++) {
jroseb4be0262011-07-16 15:44:33 -07001895 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1896 continue;
1897 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
jrose55220c32009-10-21 23:19:48 -07001898 testInsertArguments(nargs, pos, ins);
1899 }
1900 }
1901 }
1902 }
1903
1904 void testInsertArguments(int nargs, int pos, int ins) throws Throwable {
jrose55220c32009-10-21 23:19:48 -07001905 countTest();
jroseadc650a2011-02-11 01:26:28 -08001906 MethodHandle target = varargsArray(nargs + ins);
jrose55220c32009-10-21 23:19:48 -07001907 Object[] args = randomArgs(target.type().parameterArray());
1908 List<Object> resList = Arrays.asList(args);
jrose49494522012-01-18 17:34:29 -08001909 List<Object> argsToPass = new ArrayList<>(resList);
jrose55220c32009-10-21 23:19:48 -07001910 List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
jrose2cc9c832010-04-30 23:48:23 -07001911 if (verbosity >= 3)
twisti10d37ec2012-07-24 10:47:44 -07001912 System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
jrose49494522012-01-18 17:34:29 -08001913 @SuppressWarnings("cast") // cast to spread Object... is helpful
jrose10f3b682010-01-07 16:16:45 -08001914 MethodHandle target2 = MethodHandles.insertArguments(target, pos,
jrose49494522012-01-18 17:34:29 -08001915 (Object[]/*...*/) argsToInsert.toArray());
jrose55220c32009-10-21 23:19:48 -07001916 argsToInsert.clear(); // remove from argsToInsert
jrose900bafd2010-10-30 21:08:23 -07001917 Object res2 = target2.invokeWithArguments(argsToPass);
jrose55220c32009-10-21 23:19:48 -07001918 Object res2List = Arrays.asList((Object[])res2);
jrose2cc9c832010-04-30 23:48:23 -07001919 if (verbosity >= 3)
jrose55220c32009-10-21 23:19:48 -07001920 System.out.println("result: "+res2List);
1921 //if (!resList.equals(res2List))
1922 // System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
1923 assertEquals(resList, res2List);
1924 }
1925
jrose10f3b682010-01-07 16:16:45 -08001926 @Test
jroseadc650a2011-02-11 01:26:28 -08001927 public void testFilterReturnValue() throws Throwable {
1928 if (CAN_SKIP_WORKING) return;
1929 startTest("filterReturnValue");
1930 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass();
1931 assertTrue(List.class.isAssignableFrom(classOfVCList));
1932 for (int nargs = 0; nargs <= 3; nargs++) {
jrose49494522012-01-18 17:34:29 -08001933 for (Class<?> rtype : new Class<?>[] { Object.class,
jroseadc650a2011-02-11 01:26:28 -08001934 List.class,
1935 int.class,
jroseb4be0262011-07-16 15:44:33 -07001936 byte.class,
1937 long.class,
jroseadc650a2011-02-11 01:26:28 -08001938 CharSequence.class,
1939 String.class }) {
1940 testFilterReturnValue(nargs, rtype);
1941 }
1942 }
1943 }
1944
1945 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable {
1946 countTest();
1947 MethodHandle target = varargsList(nargs, rtype);
1948 MethodHandle filter;
1949 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class))
1950 filter = varargsList(1); // add another layer of list-ness
1951 else
1952 filter = MethodHandles.identity(rtype);
1953 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype));
1954 Object[] argsToPass = randomArgs(nargs, Object.class);
1955 if (verbosity >= 3)
1956 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter);
1957 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter);
1958 if (verbosity >= 4)
1959 System.out.println("filtered target: "+target2);
1960 // Simulate expected effect of filter on return value:
1961 Object unfiltered = target.invokeWithArguments(argsToPass);
1962 Object expected = filter.invokeWithArguments(unfiltered);
1963 if (verbosity >= 4)
1964 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName());
1965 if (verbosity >= 4)
1966 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName());
1967 Object result = target2.invokeWithArguments(argsToPass);
1968 if (verbosity >= 3)
1969 System.out.println("result: "+result+" : "+result.getClass().getSimpleName());
1970 if (!expected.equals(result))
1971 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
1972 assertEquals(expected, result);
1973 }
1974
1975 @Test
jrose10f3b682010-01-07 16:16:45 -08001976 public void testFilterArguments() throws Throwable {
1977 if (CAN_SKIP_WORKING) return;
1978 startTest("filterArguments");
1979 for (int nargs = 1; nargs <= 6; nargs++) {
1980 for (int pos = 0; pos < nargs; pos++) {
1981 testFilterArguments(nargs, pos);
1982 }
1983 }
1984 }
1985
1986 void testFilterArguments(int nargs, int pos) throws Throwable {
1987 countTest();
jroseadc650a2011-02-11 01:26:28 -08001988 MethodHandle target = varargsList(nargs);
1989 MethodHandle filter = varargsList(1);
jrose9b82ad62011-05-26 17:37:36 -07001990 filter = filter.asType(filter.type().generic());
jrose10f3b682010-01-07 16:16:45 -08001991 Object[] argsToPass = randomArgs(nargs, Object.class);
jrose2cc9c832010-04-30 23:48:23 -07001992 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08001993 System.out.println("filter "+target+" at "+pos+" with "+filter);
jrose900bafd2010-10-30 21:08:23 -07001994 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);
jrose10f3b682010-01-07 16:16:45 -08001995 // Simulate expected effect of filter on arglist:
1996 Object[] filteredArgs = argsToPass.clone();
jrose2cc9c832010-04-30 23:48:23 -07001997 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
jrose10f3b682010-01-07 16:16:45 -08001998 List<Object> expected = Arrays.asList(filteredArgs);
jrose900bafd2010-10-30 21:08:23 -07001999 Object result = target2.invokeWithArguments(argsToPass);
jrose2cc9c832010-04-30 23:48:23 -07002000 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002001 System.out.println("result: "+result);
2002 if (!expected.equals(result))
jroseadc650a2011-02-11 01:26:28 -08002003 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
jrose10f3b682010-01-07 16:16:45 -08002004 assertEquals(expected, result);
2005 }
2006
2007 @Test
jrose1ccb8a72013-10-05 05:30:39 -07002008 public void testCollectArguments() throws Throwable {
2009 if (CAN_SKIP_WORKING) return;
2010 startTest("collectArguments");
2011 testFoldOrCollectArguments(true);
2012 }
2013
2014 @Test
jrose10f3b682010-01-07 16:16:45 -08002015 public void testFoldArguments() throws Throwable {
2016 if (CAN_SKIP_WORKING) return;
2017 startTest("foldArguments");
jrose1ccb8a72013-10-05 05:30:39 -07002018 testFoldOrCollectArguments(false);
2019 }
2020
2021 void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
2022 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
2023 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
2024 int maxArity = 10;
2025 if (collectType != String.class) maxArity = 5;
2026 if (lastType != Object.class) maxArity = 4;
2027 for (int nargs = 0; nargs <= maxArity; nargs++) {
2028 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
2029 int maxMix = 20;
2030 if (collectType != Object.class) maxMix = 0;
2031 Map<Object,Integer> argTypesSeen = new HashMap<>();
2032 for (int mix = 0; mix <= maxMix; mix++) {
2033 if (!mixArgs(argTypes, mix, argTypesSeen)) continue;
2034 for (int collect = 0; collect <= nargs; collect++) {
2035 for (int pos = 0; pos <= nargs - collect; pos++) {
2036 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
2037 }
2038 }
2039 }
jrose10f3b682010-01-07 16:16:45 -08002040 }
2041 }
2042 }
2043 }
2044
jrose1ccb8a72013-10-05 05:30:39 -07002045 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
2046 assert(mix >= 0);
2047 if (mix == 0) return true; // no change
2048 if ((mix >>> argTypes.size()) != 0) return false;
2049 for (int i = 0; i < argTypes.size(); i++) {
2050 if (i >= 31) break;
2051 boolean bit = (mix & (1 << i)) != 0;
2052 if (bit) {
2053 Class<?> type = argTypes.get(i);
2054 if (type == Object.class)
2055 type = String.class;
2056 else if (type == String.class)
2057 type = int.class;
2058 else
2059 type = Object.class;
2060 argTypes.set(i, type);
2061 }
2062 }
2063 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
2064 if (prev != null) {
2065 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
2066 return false;
2067 }
2068 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes);
2069 return true;
2070 }
2071
2072 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType
2073 int pos, int fold, // position and length of the folded arguments
2074 Class<?> combineType, // type returned from the combiner
2075 Class<?> lastType, // type returned from the target
2076 boolean isCollect) throws Throwable {
2077 int nargs = argTypes.size();
2078 if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now
jrose10f3b682010-01-07 16:16:45 -08002079 countTest();
jrose1ccb8a72013-10-05 05:30:39 -07002080 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
2081 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
2082 if (isCollect) // does targret see arg[pos..pos+cc-1]?
2083 targetArgTypes.subList(pos, pos + fold).clear();
2084 if (combineType != void.class)
2085 targetArgTypes.add(pos, combineType);
2086 MethodHandle target = varargsList(targetArgTypes, lastType);
2087 MethodHandle combine = varargsList(combineArgTypes, combineType);
2088 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
jrose2cc9c832010-04-30 23:48:23 -07002089 if (verbosity >= 3)
jrose1ccb8a72013-10-05 05:30:39 -07002090 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
2091 MethodHandle target2;
2092 if (isCollect)
2093 target2 = MethodHandles.collectArguments(target, pos, combine);
2094 else
2095 target2 = MethodHandles.foldArguments(target, combine);
jrose10f3b682010-01-07 16:16:45 -08002096 // Simulate expected effect of combiner on arglist:
jrose1ccb8a72013-10-05 05:30:39 -07002097 List<Object> expectedList = new ArrayList<>(argsToPass);
2098 List<Object> argsToFold = expectedList.subList(pos, pos + fold);
jrose2cc9c832010-04-30 23:48:23 -07002099 if (verbosity >= 3)
jrose1ccb8a72013-10-05 05:30:39 -07002100 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
jrose900bafd2010-10-30 21:08:23 -07002101 Object foldedArgs = combine.invokeWithArguments(argsToFold);
jrose1ccb8a72013-10-05 05:30:39 -07002102 if (isCollect)
2103 argsToFold.clear();
2104 if (combineType != void.class)
2105 argsToFold.add(0, foldedArgs);
jrose900bafd2010-10-30 21:08:23 -07002106 Object result = target2.invokeWithArguments(argsToPass);
jrose2cc9c832010-04-30 23:48:23 -07002107 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002108 System.out.println("result: "+result);
jrose1ccb8a72013-10-05 05:30:39 -07002109 Object expected = target.invokeWithArguments(expectedList);
jrose10f3b682010-01-07 16:16:45 -08002110 if (!expected.equals(result))
jroseadc650a2011-02-11 01:26:28 -08002111 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
jrose10f3b682010-01-07 16:16:45 -08002112 assertEquals(expected, result);
2113 }
2114
2115 @Test
2116 public void testDropArguments() throws Throwable {
2117 if (CAN_SKIP_WORKING) return;
2118 startTest("dropArguments");
2119 for (int nargs = 0; nargs <= 4; nargs++) {
2120 for (int drop = 1; drop <= 4; drop++) {
2121 for (int pos = 0; pos <= nargs; pos++) {
2122 testDropArguments(nargs, pos, drop);
2123 }
2124 }
2125 }
2126 }
2127
2128 void testDropArguments(int nargs, int pos, int drop) throws Throwable {
2129 countTest();
jroseadc650a2011-02-11 01:26:28 -08002130 MethodHandle target = varargsArray(nargs);
jrose10f3b682010-01-07 16:16:45 -08002131 Object[] args = randomArgs(target.type().parameterArray());
2132 MethodHandle target2 = MethodHandles.dropArguments(target, pos,
jrose49494522012-01-18 17:34:29 -08002133 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0]));
jrose10f3b682010-01-07 16:16:45 -08002134 List<Object> resList = Arrays.asList(args);
jrose49494522012-01-18 17:34:29 -08002135 List<Object> argsToDrop = new ArrayList<>(resList);
jrose10f3b682010-01-07 16:16:45 -08002136 for (int i = drop; i > 0; i--) {
2137 argsToDrop.add(pos, "blort#"+i);
2138 }
jrose900bafd2010-10-30 21:08:23 -07002139 Object res2 = target2.invokeWithArguments(argsToDrop);
jrose10f3b682010-01-07 16:16:45 -08002140 Object res2List = Arrays.asList((Object[])res2);
2141 //if (!resList.equals(res2List))
2142 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
2143 assertEquals(resList, res2List);
2144 }
2145
twisti10d37ec2012-07-24 10:47:44 -07002146 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08002147 public void testInvokers() throws Throwable {
2148 if (CAN_SKIP_WORKING) return;
2149 startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
2150 // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
jrose49494522012-01-18 17:34:29 -08002151 Set<MethodType> done = new HashSet<>();
jrose10f3b682010-01-07 16:16:45 -08002152 for (int i = 0; i <= 6; i++) {
jroseb4be0262011-07-16 15:44:33 -07002153 if (CAN_TEST_LIGHTLY && i > 3) break;
jrose10f3b682010-01-07 16:16:45 -08002154 MethodType gtype = MethodType.genericMethodType(i);
jrose49494522012-01-18 17:34:29 -08002155 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
jrose10f3b682010-01-07 16:16:45 -08002156 for (int j = -1; j < i; j++) {
2157 MethodType type = gtype;
2158 if (j < 0)
2159 type = type.changeReturnType(argType);
2160 else if (argType == void.class)
2161 continue;
2162 else
2163 type = type.changeParameterType(j, argType);
jrose10f3b682010-01-07 16:16:45 -08002164 if (done.add(type))
2165 testInvokers(type);
2166 MethodType vtype = type.changeReturnType(void.class);
2167 if (done.add(vtype))
2168 testInvokers(vtype);
2169 }
2170 }
2171 }
2172 }
2173
2174 public void testInvokers(MethodType type) throws Throwable {
jrose2cc9c832010-04-30 23:48:23 -07002175 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002176 System.out.println("test invokers for "+type);
2177 int nargs = type.parameterCount();
2178 boolean testRetCode = type.returnType() != void.class;
2179 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",
2180 MethodType.genericMethodType(0, true));
jroseadc650a2011-02-11 01:26:28 -08002181 assertTrue(target.isVarargsCollector());
2182 target = target.asType(type);
jrose10f3b682010-01-07 16:16:45 -08002183 Object[] args = randomArgs(type.parameterArray());
jrose49494522012-01-18 17:34:29 -08002184 List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args));
jrose10f3b682010-01-07 16:16:45 -08002185 targetPlusArgs.add(0, target);
2186 int code = (Integer) invokee(args);
2187 Object log = logEntry("invokee", args);
2188 assertEquals(log.hashCode(), code);
2189 assertCalled("invokee", args);
2190 MethodHandle inv;
2191 Object result;
2192 // exact invoker
2193 countTest();
2194 calledLog.clear();
2195 inv = MethodHandles.exactInvoker(type);
jrose900bafd2010-10-30 21:08:23 -07002196 result = inv.invokeWithArguments(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002197 if (testRetCode) assertEquals(code, result);
2198 assertCalled("invokee", args);
2199 // generic invoker
2200 countTest();
jrose79e0a6c2011-05-12 19:27:33 -07002201 inv = MethodHandles.invoker(type);
jrose9b82ad62011-05-26 17:37:36 -07002202 if (nargs <= 3 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002203 calledLog.clear();
2204 switch (nargs) {
2205 case 0:
jrose2cc9c832010-04-30 23:48:23 -07002206 result = inv.invokeExact(target);
jrose10f3b682010-01-07 16:16:45 -08002207 break;
2208 case 1:
jrose2cc9c832010-04-30 23:48:23 -07002209 result = inv.invokeExact(target, args[0]);
jrose10f3b682010-01-07 16:16:45 -08002210 break;
2211 case 2:
jrose2cc9c832010-04-30 23:48:23 -07002212 result = inv.invokeExact(target, args[0], args[1]);
jrose10f3b682010-01-07 16:16:45 -08002213 break;
2214 case 3:
jrose2cc9c832010-04-30 23:48:23 -07002215 result = inv.invokeExact(target, args[0], args[1], args[2]);
jrose10f3b682010-01-07 16:16:45 -08002216 break;
2217 }
2218 if (testRetCode) assertEquals(code, result);
2219 assertCalled("invokee", args);
2220 }
2221 calledLog.clear();
jrose900bafd2010-10-30 21:08:23 -07002222 result = inv.invokeWithArguments(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002223 if (testRetCode) assertEquals(code, result);
2224 assertCalled("invokee", args);
2225 // varargs invoker #0
2226 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002227 inv = MethodHandles.spreadInvoker(type, 0);
jrose9b82ad62011-05-26 17:37:36 -07002228 if (type.returnType() == Object.class) {
2229 result = inv.invokeExact(target, args);
2230 } else if (type.returnType() == void.class) {
2231 result = null; inv.invokeExact(target, args);
2232 } else {
2233 result = inv.invokeWithArguments(target, (Object) args);
2234 }
jrose10f3b682010-01-07 16:16:45 -08002235 if (testRetCode) assertEquals(code, result);
2236 assertCalled("invokee", args);
jrose9b82ad62011-05-26 17:37:36 -07002237 if (nargs >= 1 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002238 // varargs invoker #1
2239 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002240 inv = MethodHandles.spreadInvoker(type, 1);
jrose2cc9c832010-04-30 23:48:23 -07002241 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs));
jrose10f3b682010-01-07 16:16:45 -08002242 if (testRetCode) assertEquals(code, result);
2243 assertCalled("invokee", args);
2244 }
jrose9b82ad62011-05-26 17:37:36 -07002245 if (nargs >= 2 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002246 // varargs invoker #2
2247 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002248 inv = MethodHandles.spreadInvoker(type, 2);
jrose2cc9c832010-04-30 23:48:23 -07002249 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
jrose10f3b682010-01-07 16:16:45 -08002250 if (testRetCode) assertEquals(code, result);
2251 assertCalled("invokee", args);
2252 }
jrose9b82ad62011-05-26 17:37:36 -07002253 if (nargs >= 3 && type == type.generic()) {
jrose10f3b682010-01-07 16:16:45 -08002254 // varargs invoker #3
2255 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002256 inv = MethodHandles.spreadInvoker(type, 3);
jrose2cc9c832010-04-30 23:48:23 -07002257 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
jrose10f3b682010-01-07 16:16:45 -08002258 if (testRetCode) assertEquals(code, result);
2259 assertCalled("invokee", args);
2260 }
2261 for (int k = 0; k <= nargs; k++) {
2262 // varargs invoker #0..N
jroseb4be0262011-07-16 15:44:33 -07002263 if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue;
jrose10f3b682010-01-07 16:16:45 -08002264 countTest();
2265 calledLog.clear();
jrosef108fc02011-02-11 01:26:24 -08002266 inv = MethodHandles.spreadInvoker(type, k);
jrose9b82ad62011-05-26 17:37:36 -07002267 MethodType expType = (type.dropParameterTypes(k, nargs)
2268 .appendParameterTypes(Object[].class)
2269 .insertParameterTypes(0, MethodHandle.class));
2270 assertEquals(expType, inv.type());
jrose49494522012-01-18 17:34:29 -08002271 List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs);
jrose10f3b682010-01-07 16:16:45 -08002272 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
2273 Object[] tail = tailList.toArray();
2274 tailList.clear(); tailList.add(tail);
jrose900bafd2010-10-30 21:08:23 -07002275 result = inv.invokeWithArguments(targetPlusVarArgs);
jrose10f3b682010-01-07 16:16:45 -08002276 if (testRetCode) assertEquals(code, result);
2277 assertCalled("invokee", args);
2278 }
jrose900bafd2010-10-30 21:08:23 -07002279
jrose10f3b682010-01-07 16:16:45 -08002280 // dynamic invoker
2281 countTest();
jroseb90d2e72010-12-16 15:59:27 -08002282 CallSite site = new MutableCallSite(type);
2283 inv = site.dynamicInvoker();
jrose900bafd2010-10-30 21:08:23 -07002284
2285 // see if we get the result of the original target:
2286 try {
2287 result = inv.invokeWithArguments(args);
2288 assertTrue("should not reach here", false);
2289 } catch (IllegalStateException ex) {
2290 String msg = ex.getMessage();
2291 assertTrue(msg, msg.contains("site"));
2292 }
2293
2294 // set new target after invoker is created, to make sure we track target
jrose10f3b682010-01-07 16:16:45 -08002295 site.setTarget(target);
2296 calledLog.clear();
jrose900bafd2010-10-30 21:08:23 -07002297 result = inv.invokeWithArguments(args);
jrose10f3b682010-01-07 16:16:45 -08002298 if (testRetCode) assertEquals(code, result);
2299 assertCalled("invokee", args);
2300 }
2301
2302 static Object invokee(Object... args) {
2303 return called("invokee", args).hashCode();
2304 }
2305
jrose55220c32009-10-21 23:19:48 -07002306 private static final String MISSING_ARG = "missingArg";
jroseb4be0262011-07-16 15:44:33 -07002307 private static final String MISSING_ARG_2 = "missingArg#2";
jrose55220c32009-10-21 23:19:48 -07002308 static Object targetIfEquals() {
2309 return called("targetIfEquals");
2310 }
2311 static Object fallbackIfNotEquals() {
2312 return called("fallbackIfNotEquals");
2313 }
2314 static Object targetIfEquals(Object x) {
2315 assertEquals(x, MISSING_ARG);
2316 return called("targetIfEquals", x);
2317 }
2318 static Object fallbackIfNotEquals(Object x) {
2319 assertFalse(x.toString(), x.equals(MISSING_ARG));
2320 return called("fallbackIfNotEquals", x);
2321 }
2322 static Object targetIfEquals(Object x, Object y) {
2323 assertEquals(x, y);
2324 return called("targetIfEquals", x, y);
2325 }
2326 static Object fallbackIfNotEquals(Object x, Object y) {
2327 assertFalse(x.toString(), x.equals(y));
2328 return called("fallbackIfNotEquals", x, y);
2329 }
2330 static Object targetIfEquals(Object x, Object y, Object z) {
2331 assertEquals(x, y);
2332 return called("targetIfEquals", x, y, z);
2333 }
2334 static Object fallbackIfNotEquals(Object x, Object y, Object z) {
2335 assertFalse(x.toString(), x.equals(y));
2336 return called("fallbackIfNotEquals", x, y, z);
2337 }
2338
jrose10f3b682010-01-07 16:16:45 -08002339 @Test
2340 public void testGuardWithTest() throws Throwable {
2341 if (CAN_SKIP_WORKING) return;
2342 startTest("guardWithTest");
jroseb4be0262011-07-16 15:44:33 -07002343 for (int nargs = 0; nargs <= 50; nargs++) {
2344 if (CAN_TEST_LIGHTLY && nargs > 7) break;
jrose10f3b682010-01-07 16:16:45 -08002345 testGuardWithTest(nargs, Object.class);
2346 testGuardWithTest(nargs, String.class);
2347 }
2348 }
2349 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {
jroseb4be0262011-07-16 15:44:33 -07002350 testGuardWithTest(nargs, 0, argClass);
2351 if (nargs <= 5 || nargs % 10 == 3) {
2352 for (int testDrops = 1; testDrops <= nargs; testDrops++)
2353 testGuardWithTest(nargs, testDrops, argClass);
2354 }
2355 }
2356 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08002357 countTest();
jroseb4be0262011-07-16 15:44:33 -07002358 int nargs1 = Math.min(3, nargs);
jrose10f3b682010-01-07 16:16:45 -08002359 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
jroseb4be0262011-07-16 15:44:33 -07002360 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1));
2361 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1));
jrose10f3b682010-01-07 16:16:45 -08002362 while (test.type().parameterCount() > nargs)
jroseb4be0262011-07-16 15:44:33 -07002363 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG))
2364 // 1: test = lambda (_) MISSING_ARG.equals(_)
jrose10f3b682010-01-07 16:16:45 -08002365 test = MethodHandles.insertArguments(test, 0, MISSING_ARG);
2366 if (argClass != Object.class) {
2367 test = changeArgTypes(test, argClass);
2368 target = changeArgTypes(target, argClass);
2369 fallback = changeArgTypes(fallback, argClass);
2370 }
jroseb4be0262011-07-16 15:44:33 -07002371 int testArgs = nargs - testDrops;
2372 assert(testArgs >= 0);
2373 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass);
2374 target = addTrailingArgs(target, nargs, argClass);
2375 fallback = addTrailingArgs(fallback, nargs, argClass);
jrose10f3b682010-01-07 16:16:45 -08002376 Object[][] argLists = {
2377 { },
2378 { "foo" }, { MISSING_ARG },
2379 { "foo", "foo" }, { "foo", "bar" },
2380 { "foo", "foo", "baz" }, { "foo", "bar", "baz" }
2381 };
2382 for (Object[] argList : argLists) {
jroseb4be0262011-07-16 15:44:33 -07002383 Object[] argList1 = argList;
2384 if (argList.length != nargs) {
2385 if (argList.length != nargs1) continue;
2386 argList1 = Arrays.copyOf(argList, nargs);
2387 Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2);
2388 }
2389 MethodHandle test1 = test;
2390 if (test1.type().parameterCount() > testArgs) {
2391 int pc = test1.type().parameterCount();
2392 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
2393 }
2394 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
2395 assertEquals(target.type(), mh.type());
jrose10f3b682010-01-07 16:16:45 -08002396 boolean equals;
2397 switch (nargs) {
2398 case 0: equals = true; break;
2399 case 1: equals = MISSING_ARG.equals(argList[0]); break;
2400 default: equals = argList[0].equals(argList[1]); break;
2401 }
2402 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
jrose2cc9c832010-04-30 23:48:23 -07002403 if (verbosity >= 3)
jrose10f3b682010-01-07 16:16:45 -08002404 System.out.println(logEntry(willCall, argList));
jroseb4be0262011-07-16 15:44:33 -07002405 Object result = mh.invokeWithArguments(argList1);
jrose10f3b682010-01-07 16:16:45 -08002406 assertCalled(willCall, argList);
2407 }
2408 }
2409
2410 @Test
2411 public void testCatchException() throws Throwable {
2412 if (CAN_SKIP_WORKING) return;
2413 startTest("catchException");
jroseb4be0262011-07-16 15:44:33 -07002414 for (int nargs = 0; nargs < 40; nargs++) {
twisti10d37ec2012-07-24 10:47:44 -07002415 if (CAN_TEST_LIGHTLY && nargs > 11) break;
jroseb4be0262011-07-16 15:44:33 -07002416 for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) {
2417 testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs);
2418 if (CAN_TEST_LIGHTLY && nargs > 3) continue;
2419 testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs);
2420 testCatchException(String.class, new LinkageError("testing"), throwMode, nargs);
jrose10f3b682010-01-07 16:16:45 -08002421 }
2422 }
2423 }
2424
jroseb4be0262011-07-16 15:44:33 -07002425 static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4;
2426
2427 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable {
2428 testCatchException(returnType, thrown, throwMode, nargs, 0);
2429 if (nargs <= 5 || nargs % 10 == 3) {
2430 for (int catchDrops = 1; catchDrops <= nargs; catchDrops++)
2431 testCatchException(returnType, thrown, throwMode, nargs, catchDrops);
2432 }
2433 }
2434
jrose10f3b682010-01-07 16:16:45 -08002435 private static <T extends Throwable>
2436 Object throwOrReturn(Object normal, T exception) throws T {
jroseb4be0262011-07-16 15:44:33 -07002437 if (exception != null) {
2438 called("throwOrReturn/throw", normal, exception);
2439 throw exception;
2440 }
2441 called("throwOrReturn/normal", normal, exception);
jrose10f3b682010-01-07 16:16:45 -08002442 return normal;
2443 }
jroseb4be0262011-07-16 15:44:33 -07002444 private int fakeIdentityCount;
2445 private Object fakeIdentity(Object x) {
2446 System.out.println("should throw through this!");
2447 fakeIdentityCount++;
2448 return x;
2449 }
jrose10f3b682010-01-07 16:16:45 -08002450
jroseb4be0262011-07-16 15:44:33 -07002451 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable {
jrose10f3b682010-01-07 16:16:45 -08002452 countTest();
jrose2cc9c832010-04-30 23:48:23 -07002453 if (verbosity >= 3)
jroseb4be0262011-07-16 15:44:33 -07002454 System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops);
jrose10f3b682010-01-07 16:16:45 -08002455 Class<? extends Throwable> exType = thrown.getClass();
jroseb4be0262011-07-16 15:44:33 -07002456 if (throwMode > THROW_CAUGHT) thrown = new UnsupportedOperationException("do not catch this");
jrose10f3b682010-01-07 16:16:45 -08002457 MethodHandle throwOrReturn
2458 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
2459 MethodType.methodType(Object.class, Object.class, Throwable.class));
jroseb4be0262011-07-16 15:44:33 -07002460 if (throwMode == THROW_THROUGH_ADAPTER) {
2461 MethodHandle fakeIdentity
2462 = PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity",
2463 MethodType.methodType(Object.class, Object.class)).bindTo(this);
2464 for (int i = 0; i < 10; i++)
2465 throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity);
2466 }
2467 int nargs1 = Math.max(2, nargs);
jroseb90d2e72010-12-16 15:59:27 -08002468 MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
jroseb4be0262011-07-16 15:44:33 -07002469 thrower = addTrailingArgs(thrower, nargs, Object.class);
2470 int catchArgc = 1 + nargs - catchDrops;
2471 MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc));
jrose10f3b682010-01-07 16:16:45 -08002472 Object[] args = randomArgs(nargs, Object.class);
jroseb4be0262011-07-16 15:44:33 -07002473 Object arg0 = MISSING_ARG;
2474 Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown;
2475 if (nargs > 0) arg0 = args[0];
2476 if (nargs > 1) args[1] = arg1;
2477 assertEquals(nargs1, thrower.type().parameterCount());
2478 if (nargs < nargs1) {
2479 Object[] appendArgs = { arg0, arg1 };
2480 appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1);
2481 thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs);
2482 }
2483 assertEquals(nargs, thrower.type().parameterCount());
2484 MethodHandle target = MethodHandles.catchException(thrower, exType, catcher);
2485 assertEquals(thrower.type(), target.type());
2486 assertEquals(nargs, target.type().parameterCount());
2487 //System.out.println("catching with "+target+" : "+throwOrReturn);
2488 Object returned;
2489 try {
2490 returned = target.invokeWithArguments(args);
2491 } catch (Throwable ex) {
2492 assertSame("must get the out-of-band exception", thrown, ex);
2493 if (throwMode <= THROW_CAUGHT)
2494 assertEquals(THROW_UNCAUGHT, throwMode);
2495 returned = ex;
2496 }
2497 assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1);
jrose10f3b682010-01-07 16:16:45 -08002498 //System.out.println("return from "+target+" : "+returned);
jroseb4be0262011-07-16 15:44:33 -07002499 if (throwMode == THROW_NOTHING) {
2500 assertSame(arg0, returned);
2501 } else if (throwMode == THROW_CAUGHT) {
jrose49494522012-01-18 17:34:29 -08002502 List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
jroseb4be0262011-07-16 15:44:33 -07002503 // catcher receives an initial subsequence of target arguments:
2504 catchArgs.subList(nargs - catchDrops, nargs).clear();
2505 // catcher also receives the exception, prepended:
jrose10f3b682010-01-07 16:16:45 -08002506 catchArgs.add(0, thrown);
2507 assertEquals(catchArgs, returned);
2508 }
jroseb4be0262011-07-16 15:44:33 -07002509 assertEquals(0, fakeIdentityCount);
jrose10f3b682010-01-07 16:16:45 -08002510 }
2511
2512 @Test
2513 public void testThrowException() throws Throwable {
2514 if (CAN_SKIP_WORKING) return;
2515 startTest("throwException");
2516 testThrowException(int.class, new ClassCastException("testing"));
2517 testThrowException(void.class, new java.io.IOException("testing"));
2518 testThrowException(String.class, new LinkageError("testing"));
2519 }
2520
2521 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
2522 countTest();
2523 Class<? extends Throwable> exType = thrown.getClass();
2524 MethodHandle target = MethodHandles.throwException(returnType, exType);
2525 //System.out.println("throwing with "+target+" : "+thrown);
2526 MethodType expectedType = MethodType.methodType(returnType, exType);
2527 assertEquals(expectedType, target.type());
jrose9b82ad62011-05-26 17:37:36 -07002528 target = target.asType(target.type().generic());
jrose10f3b682010-01-07 16:16:45 -08002529 Throwable caught = null;
2530 try {
jrose2cc9c832010-04-30 23:48:23 -07002531 Object res = target.invokeExact((Object) thrown);
jrose10f3b682010-01-07 16:16:45 -08002532 fail("got "+res+" instead of throwing "+thrown);
2533 } catch (Throwable ex) {
2534 if (ex != thrown) {
2535 if (ex instanceof Error) throw (Error)ex;
2536 if (ex instanceof RuntimeException) throw (RuntimeException)ex;
2537 }
2538 caught = ex;
2539 }
2540 assertSame(thrown, caught);
2541 }
2542
jrose4f019ca2012-08-17 13:42:25 -07002543 @Test
jroseb4be0262011-07-16 15:44:33 -07002544 public void testInterfaceCast() throws Throwable {
twisti10d37ec2012-07-24 10:47:44 -07002545 //if (CAN_SKIP_WORKING) return;
2546 startTest("interfaceCast");
jrose4f019ca2012-08-17 13:42:25 -07002547 assert( (((Object)"foo") instanceof CharSequence));
2548 assert(!(((Object)"foo") instanceof Iterable));
2549 for (MethodHandle mh : new MethodHandle[]{
2550 MethodHandles.identity(String.class),
2551 MethodHandles.identity(CharSequence.class),
2552 MethodHandles.identity(Iterable.class)
2553 }) {
2554 if (verbosity > 0) System.out.println("-- mh = "+mh);
2555 for (Class<?> ctype : new Class<?>[]{
2556 Object.class, String.class, CharSequence.class,
2557 Number.class, Iterable.class
2558 }) {
2559 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName());
2560 // doret docast
2561 testInterfaceCast(mh, ctype, false, false);
2562 testInterfaceCast(mh, ctype, true, false);
2563 testInterfaceCast(mh, ctype, false, true);
2564 testInterfaceCast(mh, ctype, true, true);
2565 }
jroseb4be0262011-07-16 15:44:33 -07002566 }
2567 }
jrose4f019ca2012-08-17 13:42:25 -07002568 private static Class<?> i2o(Class<?> c) {
2569 return (c.isInterface() ? Object.class : c);
2570 }
2571 public void testInterfaceCast(MethodHandle mh, Class<?> ctype,
2572 boolean doret, boolean docast) throws Throwable {
2573 MethodHandle mh0 = mh;
2574 if (verbosity > 1)
2575 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast);
2576 String normalRetVal = "normal return value";
jroseb4be0262011-07-16 15:44:33 -07002577 MethodType mt = mh.type();
jrose4f019ca2012-08-17 13:42:25 -07002578 MethodType mt0 = mt;
jroseb4be0262011-07-16 15:44:33 -07002579 if (doret) mt = mt.changeReturnType(ctype);
2580 else mt = mt.changeParameterType(0, ctype);
2581 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt);
2582 else mh = mh.asType(mt);
jrose4f019ca2012-08-17 13:42:25 -07002583 assertEquals(mt, mh.type());
2584 MethodType mt1 = mt;
jroseb4be0262011-07-16 15:44:33 -07002585 // this bit is needed to make the interface types disappear for invokeWithArguments:
2586 mh = MethodHandles.explicitCastArguments(mh, mt.generic());
jrose4f019ca2012-08-17 13:42:25 -07002587 Class<?>[] step = {
2588 mt1.parameterType(0), // param as passed to mh at first
2589 mt0.parameterType(0), // param after incoming cast
2590 mt0.returnType(), // return value before cast
2591 mt1.returnType(), // return value after outgoing cast
2592 };
2593 // where might a checkCast occur?
2594 boolean[] checkCast = new boolean[step.length];
2595 // the string value must pass each step without causing an exception
2596 if (!docast) {
2597 if (!doret) {
2598 if (step[0] != step[1])
2599 checkCast[1] = true; // incoming value is cast
2600 } else {
2601 if (step[2] != step[3])
2602 checkCast[3] = true; // outgoing value is cast
2603 }
jroseb4be0262011-07-16 15:44:33 -07002604 }
jrose4f019ca2012-08-17 13:42:25 -07002605 boolean expectFail = false;
2606 for (int i = 0; i < step.length; i++) {
2607 Class<?> c = step[i];
2608 if (!checkCast[i]) c = i2o(c);
2609 if (!c.isInstance(normalRetVal)) {
2610 if (verbosity > 3)
2611 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast));
2612 expectFail = true;
2613 break;
2614 }
2615 }
2616 countTest(!expectFail);
2617 if (verbosity > 2)
2618 System.out.println("expectFail="+expectFail+", mt="+mt);
jroseb4be0262011-07-16 15:44:33 -07002619 Object res;
2620 try {
jrose4f019ca2012-08-17 13:42:25 -07002621 res = mh.invokeWithArguments(normalRetVal);
jroseb4be0262011-07-16 15:44:33 -07002622 } catch (Exception ex) {
2623 res = ex;
2624 }
2625 boolean sawFail = !(res instanceof String);
2626 if (sawFail != expectFail) {
jrose4f019ca2012-08-17 13:42:25 -07002627 System.out.println("*** testInterfaceCast: mh0 = "+mh0);
2628 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh);
2629 System.out.println(" call returned "+res);
2630 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal));
jroseb4be0262011-07-16 15:44:33 -07002631 }
jrose4f019ca2012-08-17 13:42:25 -07002632 if (!expectFail) {
2633 assertFalse(res.toString(), sawFail);
2634 assertEquals(normalRetVal, res);
jroseb4be0262011-07-16 15:44:33 -07002635 } else {
jrose4f019ca2012-08-17 13:42:25 -07002636 assertTrue(res.toString(), sawFail);
jroseb4be0262011-07-16 15:44:33 -07002637 }
2638 }
2639
twisti10d37ec2012-07-24 10:47:44 -07002640 @Test // SLOW
jrose10f3b682010-01-07 16:16:45 -08002641 public void testCastFailure() throws Throwable {
2642 if (CAN_SKIP_WORKING) return;
2643 startTest("testCastFailure");
2644 testCastFailure("cast/argument", 11000);
twisti10d37ec2012-07-24 10:47:44 -07002645 if (CAN_TEST_LIGHTLY) return;
jrose10f3b682010-01-07 16:16:45 -08002646 testCastFailure("unbox/argument", 11000);
2647 testCastFailure("cast/return", 11000);
2648 testCastFailure("unbox/return", 11000);
2649 }
2650
jrose900bafd2010-10-30 21:08:23 -07002651 static class Surprise {
jrosea1ebbe62010-09-08 18:40:23 -07002652 public MethodHandle asMethodHandle() {
2653 return VALUE.bindTo(this);
2654 }
jrose10f3b682010-01-07 16:16:45 -08002655 Object value(Object x) {
2656 trace("value", x);
2657 if (boo != null) return boo;
2658 return x;
2659 }
2660 Object boo;
2661 void boo(Object x) { boo = x; }
2662
2663 static void trace(String x, Object y) {
2664 if (verbosity > 8) System.out.println(x+"="+y);
2665 }
2666 static Object refIdentity(Object x) { trace("ref.x", x); return x; }
2667 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }
2668 static int intIdentity(int x) { trace("int.x", x); return x; }
jrosea1ebbe62010-09-08 18:40:23 -07002669 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY;
2670 static {
2671 try {
2672 VALUE = PRIVATE.findVirtual(
2673 Surprise.class, "value",
2674 MethodType.methodType(Object.class, Object.class));
2675 REF_IDENTITY = PRIVATE.findStatic(
2676 Surprise.class, "refIdentity",
2677 MethodType.methodType(Object.class, Object.class));
2678 BOX_IDENTITY = PRIVATE.findStatic(
2679 Surprise.class, "boxIdentity",
2680 MethodType.methodType(Integer.class, Integer.class));
2681 INT_IDENTITY = PRIVATE.findStatic(
2682 Surprise.class, "intIdentity",
2683 MethodType.methodType(int.class, int.class));
jrose49494522012-01-18 17:34:29 -08002684 } catch (NoSuchMethodException | IllegalAccessException ex) {
jrosea1ebbe62010-09-08 18:40:23 -07002685 throw new RuntimeException(ex);
2686 }
2687 }
jrose10f3b682010-01-07 16:16:45 -08002688 }
2689
jrose49494522012-01-18 17:34:29 -08002690 @SuppressWarnings("ConvertToStringSwitch")
jrose10f3b682010-01-07 16:16:45 -08002691 void testCastFailure(String mode, int okCount) throws Throwable {
2692 countTest(false);
jrose2cc9c832010-04-30 23:48:23 -07002693 if (verbosity > 2) System.out.println("mode="+mode);
jrose10f3b682010-01-07 16:16:45 -08002694 Surprise boo = new Surprise();
jrosea1ebbe62010-09-08 18:40:23 -07002695 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0;
jrose10f3b682010-01-07 16:16:45 -08002696 if (mode.endsWith("/return")) {
2697 if (mode.equals("unbox/return")) {
2698 // fail on return to ((Integer)surprise).intValue
jrose9b82ad62011-05-26 17:37:36 -07002699 surprise = surprise.asType(MethodType.methodType(int.class, Object.class));
2700 identity = identity.asType(MethodType.methodType(int.class, Object.class));
jrose10f3b682010-01-07 16:16:45 -08002701 } else if (mode.equals("cast/return")) {
2702 // fail on return to (Integer)surprise
jrose9b82ad62011-05-26 17:37:36 -07002703 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));
2704 identity = identity.asType(MethodType.methodType(Integer.class, Object.class));
jrose10f3b682010-01-07 16:16:45 -08002705 }
2706 } else if (mode.endsWith("/argument")) {
2707 MethodHandle callee = null;
2708 if (mode.equals("unbox/argument")) {
2709 // fail on handing surprise to int argument
2710 callee = Surprise.INT_IDENTITY;
2711 } else if (mode.equals("cast/argument")) {
2712 // fail on handing surprise to Integer argument
2713 callee = Surprise.BOX_IDENTITY;
2714 }
2715 if (callee != null) {
jrose9b82ad62011-05-26 17:37:36 -07002716 callee = callee.asType(MethodType.genericMethodType(1));
jrose900bafd2010-10-30 21:08:23 -07002717 surprise = MethodHandles.filterArguments(callee, 0, surprise);
2718 identity = MethodHandles.filterArguments(callee, 0, identity);
jrose10f3b682010-01-07 16:16:45 -08002719 }
2720 }
jrosea1ebbe62010-09-08 18:40:23 -07002721 assertNotSame(mode, surprise, surprise0);
jrose9b82ad62011-05-26 17:37:36 -07002722 identity = identity.asType(MethodType.genericMethodType(1));
2723 surprise = surprise.asType(MethodType.genericMethodType(1));
jrose10f3b682010-01-07 16:16:45 -08002724 Object x = 42;
2725 for (int i = 0; i < okCount; i++) {
jrose2cc9c832010-04-30 23:48:23 -07002726 Object y = identity.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002727 assertEquals(x, y);
jrose2cc9c832010-04-30 23:48:23 -07002728 Object z = surprise.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002729 assertEquals(x, z);
2730 }
2731 boo.boo("Boo!");
jrose2cc9c832010-04-30 23:48:23 -07002732 Object y = identity.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002733 assertEquals(x, y);
2734 try {
jrose2cc9c832010-04-30 23:48:23 -07002735 Object z = surprise.invokeExact(x);
jrose10f3b682010-01-07 16:16:45 -08002736 System.out.println("Failed to throw; got z="+z);
2737 assertTrue(false);
jrose320b7692011-05-12 19:27:49 -07002738 } catch (ClassCastException ex) {
jrose10f3b682010-01-07 16:16:45 -08002739 if (verbosity > 2)
jrose2cc9c832010-04-30 23:48:23 -07002740 System.out.println("caught "+ex);
2741 if (verbosity > 3)
twisti10d37ec2012-07-24 10:47:44 -07002742 ex.printStackTrace(System.out);
jrose320b7692011-05-12 19:27:49 -07002743 assertTrue(true); // all is well
jrose10f3b682010-01-07 16:16:45 -08002744 }
2745 }
2746
jrose45b7a332010-05-03 23:32:47 -07002747 static Example userMethod(Object o, String s, int i) {
2748 called("userMethod", o, s, i);
2749 return null;
2750 }
2751
2752 @Test
2753 public void testUserClassInSignature() throws Throwable {
2754 if (CAN_SKIP_WORKING) return;
2755 startTest("testUserClassInSignature");
2756 Lookup lookup = MethodHandles.lookup();
2757 String name; MethodType mt; MethodHandle mh;
2758 Object[] args;
2759
2760 // Try a static method.
2761 name = "userMethod";
2762 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class);
2763 mh = lookup.findStatic(lookup.lookupClass(), name, mt);
2764 assertEquals(mt, mh.type());
2765 assertEquals(Example.class, mh.type().returnType());
2766 args = randomArgs(mh.type().parameterArray());
jrose900bafd2010-10-30 21:08:23 -07002767 mh.invokeWithArguments(args);
jrose45b7a332010-05-03 23:32:47 -07002768 assertCalled(name, args);
2769
2770 // Try a virtual method.
2771 name = "v2";
2772 mt = MethodType.methodType(Object.class, Object.class, int.class);
2773 mh = lookup.findVirtual(Example.class, name, mt);
2774 assertEquals(mt, mh.type().dropParameterTypes(0,1));
2775 assertTrue(mh.type().parameterList().contains(Example.class));
2776 args = randomArgs(mh.type().parameterArray());
jrose900bafd2010-10-30 21:08:23 -07002777 mh.invokeWithArguments(args);
jrose45b7a332010-05-03 23:32:47 -07002778 assertCalled(name, args);
2779 }
jrosebe2db602010-09-08 18:40:34 -07002780
2781 static void runForRunnable() {
2782 called("runForRunnable");
2783 }
jroseaf751942011-06-14 22:47:12 -07002784 public interface Fooable {
jroseb4be0262011-07-16 15:44:33 -07002785 // overloads:
jrose49494522012-01-18 17:34:29 -08002786 Object foo(Object x, String y);
2787 List<?> foo(String x, int y);
2788 Object foo(String x);
jrosebe2db602010-09-08 18:40:34 -07002789 }
jroseb4be0262011-07-16 15:44:33 -07002790 static Object fooForFooable(String x, Object... y) {
2791 return called("fooForFooable/"+x, y);
jrosebe2db602010-09-08 18:40:34 -07002792 }
jrose49494522012-01-18 17:34:29 -08002793 @SuppressWarnings("serial") // not really a public API, just a test case
jroseaf751942011-06-14 22:47:12 -07002794 public static class MyCheckedException extends Exception {
jrosebe2db602010-09-08 18:40:34 -07002795 }
jroseaf751942011-06-14 22:47:12 -07002796 public interface WillThrow {
jrosebe2db602010-09-08 18:40:34 -07002797 void willThrow() throws MyCheckedException;
2798 }
jroseb4be0262011-07-16 15:44:33 -07002799 /*non-public*/ interface PrivateRunnable {
2800 public void run();
2801 }
jrosebe2db602010-09-08 18:40:34 -07002802
2803 @Test
jroseb4be0262011-07-16 15:44:33 -07002804 public void testAsInterfaceInstance() throws Throwable {
jrosebe2db602010-09-08 18:40:34 -07002805 if (CAN_SKIP_WORKING) return;
twisti10d37ec2012-07-24 10:47:44 -07002806 startTest("asInterfaceInstance");
jrosebe2db602010-09-08 18:40:34 -07002807 Lookup lookup = MethodHandles.lookup();
jroseb4be0262011-07-16 15:44:33 -07002808 // test typical case: Runnable.run
jrosebe2db602010-09-08 18:40:34 -07002809 {
jroseb4be0262011-07-16 15:44:33 -07002810 countTest();
2811 if (verbosity >= 2) System.out.println("Runnable");
jrosebe2db602010-09-08 18:40:34 -07002812 MethodType mt = MethodType.methodType(void.class);
2813 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
jrose9b82ad62011-05-26 17:37:36 -07002814 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
jrosebe2db602010-09-08 18:40:34 -07002815 proxy.run();
2816 assertCalled("runForRunnable");
2817 }
jroseb4be0262011-07-16 15:44:33 -07002818 // well known single-name overloaded interface: Appendable.append
jrosebe2db602010-09-08 18:40:34 -07002819 {
jroseb4be0262011-07-16 15:44:33 -07002820 countTest();
2821 if (verbosity >= 2) System.out.println("Appendable");
jrose49494522012-01-18 17:34:29 -08002822 ArrayList<List<?>> appendResults = new ArrayList<>();
jroseb4be0262011-07-16 15:44:33 -07002823 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));
2824 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type
2825 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
2826 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class);
2827 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh);
2828 proxy.append("one");
2829 proxy.append("two", 3, 4);
2830 proxy.append('5');
2831 assertEquals(Arrays.asList(Arrays.asList("one"),
2832 Arrays.asList("two", 3, 4),
2833 Arrays.asList('5')),
2834 appendResults);
2835 if (verbosity >= 3) System.out.println("appendResults="+appendResults);
2836 appendResults.clear();
2837 Formatter formatter = new Formatter(proxy);
2838 String fmt = "foo str=%s char='%c' num=%d";
2839 Object[] fmtArgs = { "str!", 'C', 42 };
2840 String expect = String.format(fmt, fmtArgs);
2841 formatter.format(fmt, fmtArgs);
2842 String actual = "";
2843 if (verbosity >= 3) System.out.println("appendResults="+appendResults);
jrose49494522012-01-18 17:34:29 -08002844 for (List<?> l : appendResults) {
jroseb4be0262011-07-16 15:44:33 -07002845 Object x = l.get(0);
2846 switch (l.size()) {
2847 case 1: actual += x; continue;
jrose49494522012-01-18 17:34:29 -08002848 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue;
jroseb4be0262011-07-16 15:44:33 -07002849 }
2850 actual += l;
2851 }
2852 if (verbosity >= 3) System.out.println("expect="+expect);
2853 if (verbosity >= 3) System.out.println("actual="+actual);
2854 assertEquals(expect, actual);
jrosebe2db602010-09-08 18:40:34 -07002855 }
jroseb4be0262011-07-16 15:44:33 -07002856 // test case of an single name which is overloaded: Fooable.foo(...)
2857 {
2858 if (verbosity >= 2) System.out.println("Fooable");
2859 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable",
2860 MethodType.methodType(Object.class, String.class, Object[].class));
2861 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
2862 for (Method m : Fooable.class.getDeclaredMethods()) {
2863 countTest();
2864 assertSame("foo", m.getName());
2865 if (verbosity > 3)
2866 System.out.println("calling "+m);
2867 MethodHandle invoker = lookup.unreflect(m);
2868 MethodType mt = invoker.type();
2869 Class<?>[] types = mt.parameterArray();
2870 types[0] = int.class; // placeholder
2871 Object[] args = randomArgs(types);
2872 args[0] = proxy;
2873 if (verbosity > 3)
2874 System.out.println("calling "+m+" on "+Arrays.asList(args));
2875 Object result = invoker.invokeWithArguments(args);
2876 if (verbosity > 4)
2877 System.out.println("result = "+result);
2878 String name = "fooForFooable/"+args[1];
2879 Object[] argTail = Arrays.copyOfRange(args, 2, args.length);
2880 assertCalled(name, argTail);
2881 assertEquals(result, logEntry(name, argTail));
2882 }
2883 }
2884 // test processing of thrown exceptions:
jrosebe2db602010-09-08 18:40:34 -07002885 for (Throwable ex : new Throwable[] { new NullPointerException("ok"),
2886 new InternalError("ok"),
2887 new Throwable("fail"),
2888 new Exception("fail"),
2889 new MyCheckedException()
2890 }) {
2891 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
2892 mh = MethodHandles.insertArguments(mh, 0, ex);
jrose9b82ad62011-05-26 17:37:36 -07002893 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
jrosebe2db602010-09-08 18:40:34 -07002894 try {
jroseb4be0262011-07-16 15:44:33 -07002895 countTest();
jrosebe2db602010-09-08 18:40:34 -07002896 proxy.willThrow();
2897 System.out.println("Failed to throw: "+ex);
2898 assertTrue(false);
2899 } catch (Throwable ex1) {
jroseb4be0262011-07-16 15:44:33 -07002900 if (verbosity > 3) {
jrosebe2db602010-09-08 18:40:34 -07002901 System.out.println("throw "+ex);
2902 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));
2903 }
2904 if (ex instanceof RuntimeException ||
2905 ex instanceof Error) {
2906 assertSame("must pass unchecked exception out without wrapping", ex, ex1);
2907 } else if (ex instanceof MyCheckedException) {
2908 assertSame("must pass declared exception out without wrapping", ex, ex1);
2909 } else {
2910 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);
jroseaf751942011-06-14 22:47:12 -07002911 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) {
twisti10d37ec2012-07-24 10:47:44 -07002912 ex1.printStackTrace(System.out);
jroseaf751942011-06-14 22:47:12 -07002913 }
2914 assertSame(ex, ex1.getCause());
jrosebe2db602010-09-08 18:40:34 -07002915 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;
jrosebe2db602010-09-08 18:40:34 -07002916 }
2917 }
2918 }
jroseb4be0262011-07-16 15:44:33 -07002919 // Test error checking on bad interfaces:
jrose49494522012-01-18 17:34:29 -08002920 for (Class<?> nonSMI : new Class<?>[] { Object.class,
jrosebe2db602010-09-08 18:40:34 -07002921 String.class,
2922 CharSequence.class,
jroseb4be0262011-07-16 15:44:33 -07002923 java.io.Serializable.class,
2924 PrivateRunnable.class,
jrosebe2db602010-09-08 18:40:34 -07002925 Example.class }) {
jroseb4be0262011-07-16 15:44:33 -07002926 if (verbosity > 2) System.out.println(nonSMI.getName());
jrosebe2db602010-09-08 18:40:34 -07002927 try {
jroseb4be0262011-07-16 15:44:33 -07002928 countTest(false);
2929 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0));
2930 assertTrue("Failed to throw on "+nonSMI.getName(), false);
jrosebe2db602010-09-08 18:40:34 -07002931 } catch (IllegalArgumentException ex) {
jroseb4be0262011-07-16 15:44:33 -07002932 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex);
2933 // Object: java.lang.IllegalArgumentException:
2934 // not a public interface: java.lang.Object
2935 // String: java.lang.IllegalArgumentException:
2936 // not a public interface: java.lang.String
2937 // CharSequence: java.lang.IllegalArgumentException:
2938 // not a single-method interface: java.lang.CharSequence
2939 // Serializable: java.lang.IllegalArgumentException:
2940 // not a single-method interface: java.io.Serializable
2941 // PrivateRunnable: java.lang.IllegalArgumentException:
2942 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable
2943 // Example: java.lang.IllegalArgumentException:
2944 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example
2945 }
2946 }
2947 // Test error checking on interfaces with the wrong method type:
jrose49494522012-01-18 17:34:29 -08002948 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/,
jroseb4be0262011-07-16 15:44:33 -07002949 Fooable.class /*arity 1 & 2*/ }) {
2950 int badArity = 1; // known to be incompatible
2951 if (verbosity > 2) System.out.println(intfc.getName());
2952 try {
2953 countTest(false);
2954 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity));
2955 assertTrue("Failed to throw on "+intfc.getName(), false);
2956 } catch (WrongMethodTypeException ex) {
2957 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex);
2958 // Runnable: java.lang.invoke.WrongMethodTypeException:
2959 // cannot convert MethodHandle(Object)Object[] to ()void
2960 // Fooable: java.lang.invoke.WrongMethodTypeException:
2961 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object
jrosebe2db602010-09-08 18:40:34 -07002962 }
2963 }
2964 }
jrose43b8c122011-07-16 15:40:13 -07002965
2966 @Test
2967 public void testRunnableProxy() throws Throwable {
2968 if (CAN_SKIP_WORKING) return;
2969 startTest("testRunnableProxy");
2970 MethodHandles.Lookup lookup = MethodHandles.lookup();
2971 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class));
2972 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run);
2973 testRunnableProxy(r);
2974 assertCalled("runForRunnable");
2975 }
2976 private static void testRunnableProxy(Runnable r) {
2977 //7058630: JSR 292 method handle proxy violates contract for Object methods
2978 r.run();
2979 Object o = r;
2980 r = null;
2981 boolean eq = (o == o);
2982 int hc = System.identityHashCode(o);
2983 String st = o.getClass().getName() + "@" + Integer.toHexString(hc);
2984 Object expect = Arrays.asList(st, eq, hc);
2985 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect);
2986 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode());
2987 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual);
2988 assertEquals(expect, actual);
2989 }
jrose55220c32009-10-21 23:19:48 -07002990}
jroseada69fa2011-03-23 23:02:31 -07002991// Local abbreviated copy of sun.invoke.util.ValueConversions
twisti10d37ec2012-07-24 10:47:44 -07002992// This guy tests access from outside the same package member, but inside
2993// the package itself.
jrose55220c32009-10-21 23:19:48 -07002994class ValueConversions {
2995 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
2996 private static final Object[] NO_ARGS_ARRAY = {};
2997 private static Object[] makeArray(Object... args) { return args; }
2998 private static Object[] array() { return NO_ARGS_ARRAY; }
2999 private static Object[] array(Object a0)
3000 { return makeArray(a0); }
3001 private static Object[] array(Object a0, Object a1)
3002 { return makeArray(a0, a1); }
3003 private static Object[] array(Object a0, Object a1, Object a2)
3004 { return makeArray(a0, a1, a2); }
3005 private static Object[] array(Object a0, Object a1, Object a2, Object a3)
3006 { return makeArray(a0, a1, a2, a3); }
3007 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3008 Object a4)
3009 { return makeArray(a0, a1, a2, a3, a4); }
3010 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3011 Object a4, Object a5)
3012 { return makeArray(a0, a1, a2, a3, a4, a5); }
3013 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3014 Object a4, Object a5, Object a6)
3015 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
3016 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3017 Object a4, Object a5, Object a6, Object a7)
3018 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
3019 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3020 Object a4, Object a5, Object a6, Object a7,
3021 Object a8)
3022 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
3023 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3024 Object a4, Object a5, Object a6, Object a7,
3025 Object a8, Object a9)
3026 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
3027 static MethodHandle[] makeArrays() {
jrose49494522012-01-18 17:34:29 -08003028 ArrayList<MethodHandle> arrays = new ArrayList<>();
jrose55220c32009-10-21 23:19:48 -07003029 MethodHandles.Lookup lookup = IMPL_LOOKUP;
3030 for (;;) {
3031 int nargs = arrays.size();
jrose10f3b682010-01-07 16:16:45 -08003032 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
jrose55220c32009-10-21 23:19:48 -07003033 String name = "array";
3034 MethodHandle array = null;
3035 try {
3036 array = lookup.findStatic(ValueConversions.class, name, type);
jrosef15905c2011-02-11 01:26:32 -08003037 } catch (ReflectiveOperationException ex) {
3038 // break from loop!
jrose55220c32009-10-21 23:19:48 -07003039 }
3040 if (array == null) break;
3041 arrays.add(array);
3042 }
jrosef15905c2011-02-11 01:26:32 -08003043 assertTrue(arrays.size() == 11); // current number of methods
jrose55220c32009-10-21 23:19:48 -07003044 return arrays.toArray(new MethodHandle[0]);
3045 }
3046 static final MethodHandle[] ARRAYS = makeArrays();
3047
3048 /** Return a method handle that takes the indicated number of Object
3049 * arguments and returns an Object array of them, as if for varargs.
3050 */
3051 public static MethodHandle varargsArray(int nargs) {
3052 if (nargs < ARRAYS.length)
3053 return ARRAYS[nargs];
jroseaf751942011-06-14 22:47:12 -07003054 return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);
jrose55220c32009-10-21 23:19:48 -07003055 }
jrose320b7692011-05-12 19:27:49 -07003056 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
3057 Class<?> elemType = arrayType.getComponentType();
3058 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType));
3059 MethodHandle mh = varargsArray(nargs);
3060 if (arrayType != Object[].class)
3061 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType));
3062 return mh.asType(vaType);
3063 }
3064 static Object changeArrayType(Class<?> arrayType, Object[] a) {
3065 Class<?> elemType = arrayType.getComponentType();
3066 if (!elemType.isPrimitive())
3067 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class));
3068 Object b = java.lang.reflect.Array.newInstance(elemType, a.length);
3069 for (int i = 0; i < a.length; i++)
3070 java.lang.reflect.Array.set(b, i, a[i]);
3071 return b;
3072 }
3073 private static final MethodHandle CHANGE_ARRAY_TYPE;
3074 static {
3075 try {
3076 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType",
3077 MethodType.methodType(Object.class, Class.class, Object[].class));
3078 } catch (NoSuchMethodException | IllegalAccessException ex) {
3079 Error err = new InternalError("uncaught exception");
3080 err.initCause(ex);
3081 throw err;
3082 }
3083 }
jrose10f3b682010-01-07 16:16:45 -08003084
3085 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
3086 private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
3087 private static List<Object> list() { return NO_ARGS_LIST; }
3088 private static List<Object> list(Object a0)
3089 { return makeList(a0); }
3090 private static List<Object> list(Object a0, Object a1)
3091 { return makeList(a0, a1); }
3092 private static List<Object> list(Object a0, Object a1, Object a2)
3093 { return makeList(a0, a1, a2); }
3094 private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
3095 { return makeList(a0, a1, a2, a3); }
3096 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3097 Object a4)
3098 { return makeList(a0, a1, a2, a3, a4); }
3099 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3100 Object a4, Object a5)
3101 { return makeList(a0, a1, a2, a3, a4, a5); }
3102 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3103 Object a4, Object a5, Object a6)
3104 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
3105 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3106 Object a4, Object a5, Object a6, Object a7)
3107 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
3108 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3109 Object a4, Object a5, Object a6, Object a7,
3110 Object a8)
3111 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
3112 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3113 Object a4, Object a5, Object a6, Object a7,
3114 Object a8, Object a9)
3115 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
3116 static MethodHandle[] makeLists() {
jrose49494522012-01-18 17:34:29 -08003117 ArrayList<MethodHandle> lists = new ArrayList<>();
jrose10f3b682010-01-07 16:16:45 -08003118 MethodHandles.Lookup lookup = IMPL_LOOKUP;
3119 for (;;) {
jroseadc650a2011-02-11 01:26:28 -08003120 int nargs = lists.size();
jrose10f3b682010-01-07 16:16:45 -08003121 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
3122 String name = "list";
jroseadc650a2011-02-11 01:26:28 -08003123 MethodHandle list = null;
jrose10f3b682010-01-07 16:16:45 -08003124 try {
jroseadc650a2011-02-11 01:26:28 -08003125 list = lookup.findStatic(ValueConversions.class, name, type);
jrosef15905c2011-02-11 01:26:32 -08003126 } catch (ReflectiveOperationException ex) {
3127 // break from loop!
jrose10f3b682010-01-07 16:16:45 -08003128 }
jroseadc650a2011-02-11 01:26:28 -08003129 if (list == null) break;
3130 lists.add(list);
jrose10f3b682010-01-07 16:16:45 -08003131 }
jrosef15905c2011-02-11 01:26:32 -08003132 assertTrue(lists.size() == 11); // current number of methods
jroseadc650a2011-02-11 01:26:28 -08003133 return lists.toArray(new MethodHandle[0]);
jrose10f3b682010-01-07 16:16:45 -08003134 }
3135 static final MethodHandle[] LISTS = makeLists();
jroseaf751942011-06-14 22:47:12 -07003136 static final MethodHandle AS_LIST;
3137 static {
3138 try {
3139 AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
jrose49494522012-01-18 17:34:29 -08003140 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
jroseaf751942011-06-14 22:47:12 -07003141 }
jrose10f3b682010-01-07 16:16:45 -08003142
3143 /** Return a method handle that takes the indicated number of Object
3144 * arguments and returns List.
3145 */
3146 public static MethodHandle varargsList(int nargs) {
3147 if (nargs < LISTS.length)
3148 return LISTS[nargs];
jroseaf751942011-06-14 22:47:12 -07003149 return AS_LIST.asCollector(Object[].class, nargs);
jrose10f3b682010-01-07 16:16:45 -08003150 }
jrose55220c32009-10-21 23:19:48 -07003151}
3152// This guy tests access from outside the same package member, but inside
3153// the package itself.
3154class PackageSibling {
3155 static Lookup lookup() {
3156 return MethodHandles.lookup();
3157 }
3158}