blob: 4035857b9aff67441d8b769d51072b00ac4023f9 [file] [log] [blame]
Narayan Kamath000e1882016-10-24 17:14:25 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.lang.invoke.MethodHandle;
18import java.lang.invoke.MethodHandles;
19import java.lang.invoke.MethodHandles.Lookup;
20import java.lang.invoke.MethodType;
21import java.lang.invoke.WrongMethodTypeException;
Narayan Kamath000e1882016-10-24 17:14:25 +010022
23public class Main {
Narayan Kamath000e1882016-10-24 17:14:25 +010024 public static void main(String[] args) throws Throwable {
25 testThrowException();
Narayan Kamath96120f42016-11-01 09:40:23 +000026 testDropArguments();
27 testCatchException();
28 testGuardWithTest();
Narayan Kamath3314dbb2016-11-03 18:01:32 +000029 testArrayElementGetter();
30 testArrayElementSetter();
31 testIdentity();
32 testConstant();
Narayan Kamath8677d0b2016-11-04 14:41:19 +000033 testBindTo();
Narayan Kamath916a7712016-11-08 18:36:16 +000034 testFilterReturnValue();
Narayan Kamath731f4c62016-11-08 19:38:48 +000035 testPermuteArguments();
Narayan Kamathb79bbd82017-01-16 17:48:28 +000036 testInvokers();
Narayan Kamathbcfd2842017-01-19 20:42:23 +000037 testSpreaders_reference();
38 testSpreaders_primitive();
Narayan Kamathc5889ce2017-01-19 20:42:23 +000039 testInvokeWithArguments();
Narayan Kamath2a3696a2017-01-24 19:16:25 +000040 testAsCollector();
Narayan Kamath000e1882016-10-24 17:14:25 +010041 }
42
43 public static void testThrowException() throws Throwable {
44 MethodHandle handle = MethodHandles.throwException(String.class,
45 IllegalArgumentException.class);
46
47 if (handle.type().returnType() != String.class) {
Orion Hodsonac141392017-01-13 11:53:47 +000048 fail("Unexpected return type for handle: " + handle +
Narayan Kamath000e1882016-10-24 17:14:25 +010049 " [ " + handle.type() + "]");
50 }
51
Narayan Kamath96120f42016-11-01 09:40:23 +000052 final IllegalArgumentException iae = new IllegalArgumentException("boo!");
Narayan Kamath000e1882016-10-24 17:14:25 +010053 try {
Narayan Kamath96120f42016-11-01 09:40:23 +000054 handle.invoke(iae);
Orion Hodsonac141392017-01-13 11:53:47 +000055 fail("Expected an exception of type: java.lang.IllegalArgumentException");
Narayan Kamath000e1882016-10-24 17:14:25 +010056 } catch (IllegalArgumentException expected) {
Narayan Kamath96120f42016-11-01 09:40:23 +000057 if (expected != iae) {
Orion Hodsonac141392017-01-13 11:53:47 +000058 fail("Wrong exception: expected " + iae + " but was " + expected);
Narayan Kamath96120f42016-11-01 09:40:23 +000059 }
Narayan Kamath000e1882016-10-24 17:14:25 +010060 }
61 }
Narayan Kamath96120f42016-11-01 09:40:23 +000062
63 public static void dropArguments_delegate(String message, long message2) {
64 System.out.println("Message: " + message + ", Message2: " + message2);
65 }
66
67 public static void testDropArguments() throws Throwable {
68 MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class,
69 "dropArguments_delegate",
70 MethodType.methodType(void.class, new Class<?>[] { String.class, long.class }));
71
72 MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
73
74 // The transformer will accept two additional arguments at position zero.
75 try {
76 transform.invokeExact("foo", 42l);
77 fail();
78 } catch (WrongMethodTypeException expected) {
79 }
80
81 transform.invokeExact(45, new Object(), "foo", 42l);
82 transform.invoke(45, new Object(), "foo", 42l);
83
84 // Additional arguments at position 1.
85 transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
86 transform.invokeExact("foo", 45, new Object(), 42l);
87 transform.invoke("foo", 45, new Object(), 42l);
88
89 // Additional arguments at position 2.
90 transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
91 transform.invokeExact("foo", 42l, 45, new Object());
92 transform.invoke("foo", 42l, 45, new Object());
93
94 // Note that we still perform argument conversions even for the arguments that
95 // are subsequently dropped.
96 try {
97 transform.invoke("foo", 42l, 45l, new Object());
98 fail();
99 } catch (WrongMethodTypeException expected) {
100 } catch (IllegalArgumentException expected) {
101 // TODO(narayan): We currently throw the wrong type of exception here,
102 // it's IAE and should be WMTE instead.
103 }
104
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000105 // Check that asType works as expected.
106 transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
107 transform = transform.asType(MethodType.methodType(void.class,
108 new Class<?>[] { short.class, Object.class, String.class, long.class }));
109 transform.invokeExact((short) 45, new Object(), "foo", 42l);
110
Narayan Kamath96120f42016-11-01 09:40:23 +0000111 // Invalid argument location, should not be allowed.
112 try {
113 MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
114 fail();
115 } catch (IllegalArgumentException expected) {
116 }
117
118 // Invalid argument location, should not be allowed.
119 try {
120 MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
121 fail();
122 } catch (IllegalArgumentException expected) {
123 }
124
125 try {
126 MethodHandles.dropArguments(delegate, 1, void.class);
127 fail();
128 } catch (IllegalArgumentException expected) {
129 }
130 }
131
132 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
133 throws Throwable {
134 if (exceptionMessage != null) {
135 throw new IllegalArgumentException(exceptionMessage);
136 }
137
138 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2);
139 return "target";
140 }
141
142 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2,
143 String exMsg) {
144 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg);
145 return "handler1";
146 }
147
148 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
149 System.out.println("Handler: " + iae + ", Arg1: " + arg1);
150 return "handler2";
151 }
152
153 public static void testCatchException() throws Throwable {
154 MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
155 "testCatchException_target",
156 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class }));
157
158 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class,
159 "testCatchException_handler",
160 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
161 String.class, long.class, String.class }));
162
163 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
164 handler);
165
166 String returnVal = null;
167
168 // These two should end up calling the target always. We're passing a null exception
169 // message here, which means the target will not throw.
170 returnVal = (String) adapter.invoke("foo", 42, null);
171 assertEquals("target", returnVal);
172 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
173 assertEquals("target", returnVal);
174
175 // We're passing a non-null exception message here, which means the target will throw,
176 // which in turn means that the handler must be called for the next two invokes.
177 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
178 assertEquals("handler1", returnVal);
179 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
180 assertEquals("handler1", returnVal);
181
182 handler = MethodHandles.lookup().findStatic(Main.class,
183 "testCatchException_handler2",
184 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
185 String.class }));
186 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
187
188 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
189 assertEquals("handler2", returnVal);
190 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
191 assertEquals("handler2", returnVal);
192
193 // Test that the type of the invoke doesn't matter. Here we call
194 // IllegalArgumentException.toString() on the exception that was thrown by
195 // the target.
196 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
197 "toString", MethodType.methodType(String.class));
198 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
199
200 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
201 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
202 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2");
203 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000204
205 // Check that asType works as expected.
206 adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
207 handler);
208 adapter = adapter.asType(MethodType.methodType(String.class,
209 new Class<?>[] { String.class, int.class, String.class }));
210 returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
211 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000212 }
213
214 public static boolean testGuardWithTest_test(String arg1, long arg2) {
215 return "target".equals(arg1) && 42 == arg2;
216 }
217
218 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
219 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3);
220 return "target";
221 }
222
223 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
224 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3);
225 return "fallback";
226 }
227
228 public static void testGuardWithTest() throws Throwable {
229 MethodHandle test = MethodHandles.lookup().findStatic(Main.class,
230 "testGuardWithTest_test",
231 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class }));
232
233 final MethodType type = MethodType.methodType(String.class,
234 new Class<?>[] { String.class, long.class, int.class });
235
236 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
237 "testGuardWithTest_target", type);
238 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class,
239 "testGuardWithTest_fallback", type);
240
241 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
242
243 String returnVal = null;
244
245 returnVal = (String) adapter.invoke("target", 42, 56);
246 assertEquals("target", returnVal);
247 returnVal = (String) adapter.invokeExact("target", 42l, 56);
248 assertEquals("target", returnVal);
249
250 returnVal = (String) adapter.invoke("fallback", 42l, 56);
251 assertEquals("fallback", returnVal);
252 returnVal = (String) adapter.invokeExact("target", 42l, 56);
253 assertEquals("target", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000254
255 // Check that asType works as expected.
256 adapter = adapter.asType(MethodType.methodType(String.class,
257 new Class<?>[] { String.class, int.class, int.class }));
258 returnVal = (String) adapter.invokeExact("target", 42, 56);
259 assertEquals("target", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000260 }
261
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000262 public static void testArrayElementGetter() throws Throwable {
263 MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
264
265 {
266 int[] array = new int[1];
267 array[0] = 42;
268 int value = (int) getter.invoke(array, 0);
269 if (value != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000270 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000271 }
272
273 try {
274 value = (int) getter.invoke(array, -1);
275 fail();
276 } catch (ArrayIndexOutOfBoundsException expected) {
277 }
278
279 try {
280 value = (int) getter.invoke(null, -1);
281 fail();
282 } catch (NullPointerException expected) {
283 }
284 }
285
286 {
287 getter = MethodHandles.arrayElementGetter(long[].class);
288 long[] array = new long[1];
289 array[0] = 42;
290 long value = (long) getter.invoke(array, 0);
291 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000292 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000293 }
294 }
295
296 {
297 getter = MethodHandles.arrayElementGetter(short[].class);
298 short[] array = new short[1];
299 array[0] = 42;
300 short value = (short) getter.invoke(array, 0);
301 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000302 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000303 }
304 }
305
306 {
307 getter = MethodHandles.arrayElementGetter(char[].class);
308 char[] array = new char[1];
309 array[0] = 42;
310 char value = (char) getter.invoke(array, 0);
311 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000312 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000313 }
314 }
315
316 {
317 getter = MethodHandles.arrayElementGetter(byte[].class);
318 byte[] array = new byte[1];
319 array[0] = (byte) 0x8;
320 byte value = (byte) getter.invoke(array, 0);
321 if (value != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000322 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000323 }
324 }
325
326 {
327 getter = MethodHandles.arrayElementGetter(boolean[].class);
328 boolean[] array = new boolean[1];
329 array[0] = true;
330 boolean value = (boolean) getter.invoke(array, 0);
331 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000332 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000333 }
334 }
335
336 {
337 getter = MethodHandles.arrayElementGetter(float[].class);
338 float[] array = new float[1];
339 array[0] = 42.0f;
340 float value = (float) getter.invoke(array, 0);
341 if (value != 42.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000342 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000343 }
344 }
345
346 {
347 getter = MethodHandles.arrayElementGetter(double[].class);
348 double[] array = new double[1];
349 array[0] = 42.0;
350 double value = (double) getter.invoke(array, 0);
351 if (value != 42.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000352 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000353 }
354 }
355
356 {
357 getter = MethodHandles.arrayElementGetter(String[].class);
358 String[] array = new String[3];
359 array[0] = "42";
360 array[1] = "48";
361 array[2] = "54";
362 String value = (String) getter.invoke(array, 0);
363 assertEquals("42", value);
364 value = (String) getter.invoke(array, 1);
365 assertEquals("48", value);
366 value = (String) getter.invoke(array, 2);
367 assertEquals("54", value);
368 }
369 }
370
371 public static void testArrayElementSetter() throws Throwable {
372 MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
373
374 {
375 int[] array = new int[2];
376 setter.invoke(array, 0, 42);
377 setter.invoke(array, 1, 43);
378
379 if (array[0] != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000380 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000381 }
382 if (array[1] != 43) {
Orion Hodsonac141392017-01-13 11:53:47 +0000383 fail("Unexpected value: " + array[1]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000384 }
385
386 try {
387 setter.invoke(array, -1, 42);
388 fail();
389 } catch (ArrayIndexOutOfBoundsException expected) {
390 }
391
392 try {
393 setter.invoke(null, 0, 42);
394 fail();
395 } catch (NullPointerException expected) {
396 }
397 }
398
399 {
400 setter = MethodHandles.arrayElementSetter(long[].class);
401 long[] array = new long[1];
402 setter.invoke(array, 0, 42l);
403 if (array[0] != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000404 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000405 }
406 }
407
408 {
409 setter = MethodHandles.arrayElementSetter(short[].class);
410 short[] array = new short[1];
411 setter.invoke(array, 0, (short) 42);
412 if (array[0] != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000413 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000414 }
415 }
416
417 {
418 setter = MethodHandles.arrayElementSetter(char[].class);
419 char[] array = new char[1];
420 setter.invoke(array, 0, (char) 42);
421 if (array[0] != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000422 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000423 }
424 }
425
426 {
427 setter = MethodHandles.arrayElementSetter(byte[].class);
428 byte[] array = new byte[1];
429 setter.invoke(array, 0, (byte) 0x8);
430 if (array[0] != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000431 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000432 }
433 }
434
435 {
436 setter = MethodHandles.arrayElementSetter(boolean[].class);
437 boolean[] array = new boolean[1];
438 setter.invoke(array, 0, true);
439 if (!array[0]) {
Orion Hodsonac141392017-01-13 11:53:47 +0000440 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000441 }
442 }
443
444 {
445 setter = MethodHandles.arrayElementSetter(float[].class);
446 float[] array = new float[1];
447 setter.invoke(array, 0, 42.0f);
448 if (array[0] != 42.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000449 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000450 }
451 }
452
453 {
454 setter = MethodHandles.arrayElementSetter(double[].class);
455 double[] array = new double[1];
456 setter.invoke(array, 0, 42.0);
457 if (array[0] != 42.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000458 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000459 }
460 }
461
462 {
463 setter = MethodHandles.arrayElementSetter(String[].class);
464 String[] array = new String[3];
465 setter.invoke(array, 0, "42");
466 setter.invoke(array, 1, "48");
467 setter.invoke(array, 2, "54");
468 assertEquals("42", array[0]);
469 assertEquals("48", array[1]);
470 assertEquals("54", array[2]);
471 }
472 }
473
474 public static void testIdentity() throws Throwable {
475 {
476 MethodHandle identity = MethodHandles.identity(boolean.class);
477 boolean value = (boolean) identity.invoke(false);
478 if (value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000479 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000480 }
481 }
482
483 {
484 MethodHandle identity = MethodHandles.identity(byte.class);
485 byte value = (byte) identity.invoke((byte) 0x8);
486 if (value != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000487 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000488 }
489 }
490
491 {
492 MethodHandle identity = MethodHandles.identity(char.class);
493 char value = (char) identity.invoke((char) -56);
494 if (value != (char) -56) {
Orion Hodsonac141392017-01-13 11:53:47 +0000495 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000496 }
497 }
498
499 {
500 MethodHandle identity = MethodHandles.identity(short.class);
501 short value = (short) identity.invoke((short) -59);
502 if (value != (short) -59) {
Orion Hodsonac141392017-01-13 11:53:47 +0000503 fail("Unexpected value: " + Short.toString(value));
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000504 }
505 }
506
507 {
508 MethodHandle identity = MethodHandles.identity(int.class);
509 int value = (int) identity.invoke(52);
510 if (value != 52) {
Orion Hodsonac141392017-01-13 11:53:47 +0000511 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000512 }
513 }
514
515 {
516 MethodHandle identity = MethodHandles.identity(long.class);
517 long value = (long) identity.invoke(-76l);
518 if (value != (long) -76) {
Orion Hodsonac141392017-01-13 11:53:47 +0000519 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000520 }
521 }
522
523 {
524 MethodHandle identity = MethodHandles.identity(float.class);
525 float value = (float) identity.invoke(56.0f);
526 if (value != (float) 56.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000527 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000528 }
529 }
530
531 {
532 MethodHandle identity = MethodHandles.identity(double.class);
533 double value = (double) identity.invoke((double) 72.0);
534 if (value != (double) 72.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000535 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000536 }
537 }
538
539 {
540 MethodHandle identity = MethodHandles.identity(String.class);
541 String value = (String) identity.invoke("bazman");
542 assertEquals("bazman", value);
543 }
544 }
545
546 public static void testConstant() throws Throwable {
547 // int constants.
548 {
549 MethodHandle constant = MethodHandles.constant(int.class, 56);
550 int value = (int) constant.invoke();
551 if (value != 56) {
Orion Hodsonac141392017-01-13 11:53:47 +0000552 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000553 }
554
555 // short constant values are converted to int.
556 constant = MethodHandles.constant(int.class, (short) 52);
557 value = (int) constant.invoke();
558 if (value != 52) {
Orion Hodsonac141392017-01-13 11:53:47 +0000559 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000560 }
561
562 // char constant values are converted to int.
563 constant = MethodHandles.constant(int.class, (char) 'b');
564 value = (int) constant.invoke();
565 if (value != (int) 'b') {
Orion Hodsonac141392017-01-13 11:53:47 +0000566 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000567 }
568
569 // int constant values are converted to int.
570 constant = MethodHandles.constant(int.class, (byte) 0x1);
571 value = (int) constant.invoke();
572 if (value != 1) {
Orion Hodsonac141392017-01-13 11:53:47 +0000573 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000574 }
575
576 // boolean, float, double and long primitive constants are not convertible
577 // to int, so the handle creation must fail with a CCE.
578 try {
579 MethodHandles.constant(int.class, false);
580 fail();
581 } catch (ClassCastException expected) {
582 }
583
584 try {
585 MethodHandles.constant(int.class, 0.1f);
586 fail();
587 } catch (ClassCastException expected) {
588 }
589
590 try {
591 MethodHandles.constant(int.class, 0.2);
592 fail();
593 } catch (ClassCastException expected) {
594 }
595
596 try {
597 MethodHandles.constant(int.class, 73l);
598 fail();
599 } catch (ClassCastException expected) {
600 }
601 }
602
603 // long constants.
604 {
605 MethodHandle constant = MethodHandles.constant(long.class, 56l);
606 long value = (long) constant.invoke();
607 if (value != 56l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000608 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000609 }
610
611 constant = MethodHandles.constant(long.class, (int) 56);
612 value = (long) constant.invoke();
613 if (value != 56l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000614 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000615 }
616 }
617
618 // byte constants.
619 {
620 MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12);
621 byte value = (byte) constant.invoke();
622 if (value != (byte) 0x12) {
Orion Hodsonac141392017-01-13 11:53:47 +0000623 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000624 }
625 }
626
627 // boolean constants.
628 {
629 MethodHandle constant = MethodHandles.constant(boolean.class, true);
630 boolean value = (boolean) constant.invoke();
631 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000632 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000633 }
634 }
635
636 // char constants.
637 {
638 MethodHandle constant = MethodHandles.constant(char.class, 'f');
639 char value = (char) constant.invoke();
640 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000641 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000642 }
643 }
644
645 // short constants.
646 {
647 MethodHandle constant = MethodHandles.constant(short.class, (short) 123);
648 short value = (short) constant.invoke();
649 if (value != (short) 123) {
Orion Hodsonac141392017-01-13 11:53:47 +0000650 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000651 }
652 }
653
654 // float constants.
655 {
656 MethodHandle constant = MethodHandles.constant(float.class, 56.0f);
657 float value = (float) constant.invoke();
658 if (value != 56.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000659 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000660 }
661 }
662
663 // double constants.
664 {
665 MethodHandle constant = MethodHandles.constant(double.class, 256.0);
666 double value = (double) constant.invoke();
667 if (value != 256.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000668 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000669 }
670 }
671
672 // reference constants.
673 {
674 MethodHandle constant = MethodHandles.constant(String.class, "256.0");
675 String value = (String) constant.invoke();
676 assertEquals("256.0", value);
677 }
678 }
679
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000680 public static void testBindTo() throws Throwable {
681 MethodHandle stringCharAt = MethodHandles.lookup().findVirtual(
682 String.class, "charAt", MethodType.methodType(char.class, int.class));
683
684 char value = (char) stringCharAt.invoke("foo", 0);
685 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000686 fail("Unexpected value: " + value);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000687 }
688
689 MethodHandle bound = stringCharAt.bindTo("foo");
690 value = (char) bound.invoke(0);
691 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000692 fail("Unexpected value: " + value);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000693 }
694
695 try {
696 stringCharAt.bindTo(new Object());
697 fail();
698 } catch (ClassCastException expected) {
699 }
700
701 bound = stringCharAt.bindTo(null);
702 try {
703 bound.invoke(0);
704 fail();
705 } catch (NullPointerException expected) {
706 }
707
708 MethodHandle integerParseInt = MethodHandles.lookup().findStatic(
709 Integer.class, "parseInt", MethodType.methodType(int.class, String.class));
710
711 bound = integerParseInt.bindTo("78452");
712 int intValue = (int) bound.invoke();
713 if (intValue != 78452) {
Orion Hodsonac141392017-01-13 11:53:47 +0000714 fail("Unexpected value: " + intValue);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000715 }
716 }
717
Narayan Kamath916a7712016-11-08 18:36:16 +0000718 public static String filterReturnValue_target(int a) {
719 return "ReturnValue" + a;
720 }
721
722 public static boolean filterReturnValue_filter(String value) {
723 return value.indexOf("42") != -1;
724 }
725
726 public static int filterReturnValue_intTarget(String a) {
727 return Integer.parseInt(a);
728 }
729
730 public static int filterReturnValue_intFilter(int b) {
731 return b + 1;
732 }
733
734 public static void filterReturnValue_voidTarget() {
735 }
736
737 public static int filterReturnValue_voidFilter() {
738 return 42;
739 }
740
741 public static void testFilterReturnValue() throws Throwable {
742 // A target that returns a reference.
743 {
744 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
745 "filterReturnValue_target", MethodType.methodType(String.class, int.class));
746 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
747 "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class));
748
749 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
750
751 boolean value = (boolean) adapter.invoke((int) 42);
752 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000753 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000754 }
755 value = (boolean) adapter.invoke((int) 43);
756 if (value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000757 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000758 }
759 }
760
761 // A target that returns a primitive.
762 {
763 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
764 "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class));
765 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
766 "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class));
767
768 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
769
770 int value = (int) adapter.invoke("56");
771 if (value != 57) {
Orion Hodsonac141392017-01-13 11:53:47 +0000772 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000773 }
774 }
775
776 // A target that returns void.
777 {
778 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
779 "filterReturnValue_voidTarget", MethodType.methodType(void.class));
780 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
781 "filterReturnValue_voidFilter", MethodType.methodType(int.class));
782
783 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
784
785 int value = (int) adapter.invoke();
786 if (value != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000787 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000788 }
789 }
790 }
791
Narayan Kamath731f4c62016-11-08 19:38:48 +0000792 public static void permuteArguments_callee(boolean a, byte b, char c,
793 short d, int e, long f, float g, double h) {
794 if (a == true && b == (byte) 'b' && c == 'c' && d == (short) 56 &&
795 e == 78 && f == (long) 97 && g == 98.0f && f == 97.0) {
796 return;
797 }
798
Orion Hodsonac141392017-01-13 11:53:47 +0000799 fail("Unexpected arguments: " + a + ", " + b + ", " + c
Narayan Kamath731f4c62016-11-08 19:38:48 +0000800 + ", " + d + ", " + e + ", " + f + ", " + g + ", " + h);
801 }
802
803 public static void permuteArguments_boxingCallee(boolean a, Integer b) {
804 if (a && b.intValue() == 42) {
805 return;
806 }
807
Orion Hodsonac141392017-01-13 11:53:47 +0000808 fail("Unexpected arguments: " + a + ", " + b);
Narayan Kamath731f4c62016-11-08 19:38:48 +0000809 }
810
811 public static void testPermuteArguments() throws Throwable {
812 {
813 final MethodHandle target = MethodHandles.lookup().findStatic(
814 Main.class, "permuteArguments_callee",
815 MethodType.methodType(void.class, new Class<?>[] {
816 boolean.class, byte.class, char.class, short.class, int.class,
817 long.class, float.class, double.class }));
818
819 final MethodType newType = MethodType.methodType(void.class, new Class<?>[] {
820 double.class, float.class, long.class, int.class, short.class, char.class,
821 byte.class, boolean.class });
822
823 final MethodHandle permutation = MethodHandles.permuteArguments(
824 target, newType, new int[] { 7, 6, 5, 4, 3, 2, 1, 0 });
825
826 permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78,
827 (short) 56, 'c', (byte) 'b', (boolean) true);
828
829 // The permutation array was not of the right length.
830 try {
831 MethodHandles.permuteArguments(target, newType,
832 new int[] { 7 });
833 fail();
834 } catch (IllegalArgumentException expected) {
835 }
836
837 // The permutation array has an element that's out of bounds
838 // (there's no argument with idx == 8).
839 try {
840 MethodHandles.permuteArguments(target, newType,
841 new int[] { 8, 6, 5, 4, 3, 2, 1, 0 });
842 fail();
843 } catch (IllegalArgumentException expected) {
844 }
845
846 // The permutation array maps to an incorrect type.
847 try {
848 MethodHandles.permuteArguments(target, newType,
849 new int[] { 7, 7, 5, 4, 3, 2, 1, 0 });
850 fail();
851 } catch (IllegalArgumentException expected) {
852 }
853 }
854
855 // Tests for reference arguments as well as permutations that
856 // repeat arguments.
857 {
858 final MethodHandle target = MethodHandles.lookup().findVirtual(
859 String.class, "concat", MethodType.methodType(String.class, String.class));
860
861 final MethodType newType = MethodType.methodType(String.class, String.class,
862 String.class);
863
864 assertEquals("foobar", (String) target.invoke("foo", "bar"));
865
866 MethodHandle permutation = MethodHandles.permuteArguments(target,
867 newType, new int[] { 1, 0 });
868 assertEquals("barfoo", (String) permutation.invoke("foo", "bar"));
869
870 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 0, 0 });
871 assertEquals("foofoo", (String) permutation.invoke("foo", "bar"));
872
873 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 1, 1 });
874 assertEquals("barbar", (String) permutation.invoke("foo", "bar"));
875 }
876
877 // Tests for boxing and unboxing.
878 {
879 final MethodHandle target = MethodHandles.lookup().findStatic(
880 Main.class, "permuteArguments_boxingCallee",
881 MethodType.methodType(void.class, new Class<?>[] { boolean.class, Integer.class }));
882
883 final MethodType newType = MethodType.methodType(void.class,
884 new Class<?>[] { Integer.class, boolean.class });
885
886 MethodHandle permutation = MethodHandles.permuteArguments(target,
887 newType, new int[] { 1, 0 });
888
889 permutation.invoke(42, true);
890 permutation.invoke(42, Boolean.TRUE);
891 permutation.invoke(Integer.valueOf(42), true);
892 permutation.invoke(Integer.valueOf(42), Boolean.TRUE);
893 }
894 }
895
Narayan Kamathb79bbd82017-01-16 17:48:28 +0000896 private static Object returnBar() {
897 return "bar";
898 }
899
900 public static void testInvokers() throws Throwable {
901 final MethodType targetType = MethodType.methodType(String.class, String.class);
902 final MethodHandle target = MethodHandles.lookup().findVirtual(
903 String.class, "concat", targetType);
904
905 MethodHandle invoker = MethodHandles.invoker(target.type());
906 assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar"));
907 assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar"));
908 try {
909 String foo = (String) invoker.invoke(target, "bar", "bar", 24);
910 fail();
911 } catch (WrongMethodTypeException expected) {
912 }
913
914 MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type());
915 assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar"));
916 try {
917 String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar");
918 fail();
919 } catch (WrongMethodTypeException expected) {
920 }
921 try {
922 String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24);
923 fail();
924 } catch (WrongMethodTypeException expected) {
925 }
926 }
927
Narayan Kamathbcfd2842017-01-19 20:42:23 +0000928 public static int spreadReferences(String a, String b, String c) {
929 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
930 return 42;
931 }
932
933 public static int spreadReferences_Unbox(String a, int b) {
934 System.out.println("a: " + a + ", b:" + b);
935 return 43;
936 }
937
938 public static void testSpreaders_reference() throws Throwable {
939 MethodType methodType = MethodType.methodType(int.class,
940 new Class<?>[] { String.class, String.class, String.class });
941 MethodHandle delegate = MethodHandles.lookup().findStatic(
942 Main.class, "spreadReferences", methodType);
943
944 // Basic checks on array lengths.
945 //
946 // Array size = 0
947 MethodHandle mhAsSpreader = delegate.asSpreader(String[].class, 0);
948 int ret = (int) mhAsSpreader.invoke("a", "b", "c", new String[] {});
949 assertEquals(42, ret);
950 // Array size = 1
951 mhAsSpreader = delegate.asSpreader(String[].class, 1);
952 ret = (int) mhAsSpreader.invoke("a", "b", new String[] { "c" });
953 assertEquals(42, ret);
954 // Array size = 2
955 mhAsSpreader = delegate.asSpreader(String[].class, 2);
956 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" });
957 assertEquals(42, ret);
958 // Array size = 3
959 mhAsSpreader = delegate.asSpreader(String[].class, 3);
960 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b", "c"});
961 assertEquals(42, ret);
962
963 // Exception case, array size = 4 is illegal.
964 try {
965 delegate.asSpreader(String[].class, 4);
966 fail();
967 } catch (IllegalArgumentException expected) {
968 }
969
970 // Exception case, calling with an arg of the wrong size.
971 // Array size = 3
972 mhAsSpreader = delegate.asSpreader(String[].class, 3);
973 try {
974 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b"});
975 } catch (IllegalArgumentException expected) {
976 }
977
978 // Various other hijinks, pass as Object[] arrays, Object etc.
979 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
980 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" });
981 assertEquals(42, ret);
982
983 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
984 ret = (int) mhAsSpreader.invoke("a", new Object[] { "b", "c" });
985 assertEquals(42, ret);
986
987 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
988 ret = (int) mhAsSpreader.invoke("a", (Object) new Object[] { "b", "c" });
989 assertEquals(42, ret);
990
991 // Test implicit unboxing.
992 MethodType methodType2 = MethodType.methodType(int.class,
993 new Class<?>[] { String.class, int.class });
994 MethodHandle delegate2 = MethodHandles.lookup().findStatic(
995 Main.class, "spreadReferences_Unbox", methodType2);
996
997 // .. with an Integer[] array.
998 mhAsSpreader = delegate2.asSpreader(Integer[].class, 1);
999 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 });
1000 assertEquals(43, ret);
1001
1002 // .. with an Integer[] array declared as an Object[] argument type.
1003 mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
1004 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 });
1005 assertEquals(43, ret);
1006
1007 // .. with an Object[] array.
1008 mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
1009 ret = (int) mhAsSpreader.invoke("a", new Object[] { Integer.valueOf(43)});
1010 assertEquals(43, ret);
1011
1012 // -- Part 2--
1013 // Run a subset of these tests on MethodHandles.spreadInvoker, which only accepts
1014 // a trailing argument type of Object[].
1015 MethodHandle spreadInvoker = MethodHandles.spreadInvoker(methodType2, 1);
1016 ret = (int) spreadInvoker.invoke(delegate2, "a", new Object[] { Integer.valueOf(43)});
1017 assertEquals(43, ret);
1018
1019 ret = (int) spreadInvoker.invoke(delegate2, "a", new Integer[] { 43 });
1020 assertEquals(43, ret);
1021
1022 // NOTE: Annoyingly, the second argument here is leadingArgCount and not
1023 // arrayLength.
1024 spreadInvoker = MethodHandles.spreadInvoker(methodType, 3);
1025 ret = (int) spreadInvoker.invoke(delegate, "a", "b", "c", new String[] {});
1026 assertEquals(42, ret);
1027
1028 spreadInvoker = MethodHandles.spreadInvoker(methodType, 0);
1029 ret = (int) spreadInvoker.invoke(delegate, new String[] { "a", "b", "c" });
1030 assertEquals(42, ret);
1031
1032 // Exact invokes: Double check that the expected parameter type is
1033 // Object[] and not T[].
1034 try {
1035 spreadInvoker.invokeExact(delegate, new String[] { "a", "b", "c" });
1036 fail();
1037 } catch (WrongMethodTypeException expected) {
1038 }
1039
1040 ret = (int) spreadInvoker.invoke(delegate, new Object[] { "a", "b", "c" });
1041 assertEquals(42, ret);
1042 }
1043
1044 public static int spreadBoolean(String a, Boolean b, boolean c) {
1045 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
1046 return 44;
1047 }
1048
1049 public static int spreadByte(String a, Byte b, byte c,
1050 short d, int e, long f, float g, double h) {
1051 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1052 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g +
1053 ", h: " + h);
1054 return 45;
1055 }
1056
1057 public static int spreadChar(String a, Character b, char c,
1058 int d, long e, float f, double g) {
1059 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1060 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g);
1061 return 46;
1062 }
1063
1064 public static int spreadShort(String a, Short b, short c,
1065 int d, long e, float f, double g) {
1066 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1067 ", d: " + d + ", e: " + e + ", f:" + f + ", g:" + g);
1068 return 47;
1069 }
1070
1071 public static int spreadInt(String a, Integer b, int c,
1072 long d, float e, double f) {
1073 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1074 ", d: " + d + ", e: " + e + ", f:" + f);
1075 return 48;
1076 }
1077
1078 public static int spreadLong(String a, Long b, long c, float d, double e) {
1079 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1080 ", d: " + d + ", e: " + e);
1081 return 49;
1082 }
1083
1084 public static int spreadFloat(String a, Float b, float c, double d) {
1085 System.out.println("a: " + a + ", b:" + b + ", c: " + c + ", d: " + d);
1086 return 50;
1087 }
1088
1089 public static int spreadDouble(String a, Double b, double c) {
1090 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
1091 return 51;
1092 }
1093
1094 public static void testSpreaders_primitive() throws Throwable {
1095 // boolean[]
1096 // ---------------------
1097 MethodType type = MethodType.methodType(int.class,
1098 new Class<?>[] { String.class, Boolean.class, boolean.class });
1099 MethodHandle delegate = MethodHandles.lookup().findStatic(
1100 Main.class, "spreadBoolean", type);
1101
1102 MethodHandle spreader = delegate.asSpreader(boolean[].class, 2);
1103 int ret = (int) spreader.invokeExact("a", new boolean[] { true, false });
1104 assertEquals(44, ret);
1105 ret = (int) spreader.invoke("a", new boolean[] { true, false });
1106 assertEquals(44, ret);
1107
1108 // boolean can't be cast to String (the first argument to the method).
1109 try {
1110 delegate.asSpreader(boolean[].class, 3);
1111 fail();
1112 } catch (WrongMethodTypeException expected) {
1113 }
1114
1115 // int can't be cast to boolean to supply the last argument to the method.
1116 try {
1117 delegate.asSpreader(int[].class, 1);
1118 fail();
1119 } catch (WrongMethodTypeException expected) {
1120 }
1121
1122 // byte[]
1123 // ---------------------
1124 type = MethodType.methodType(int.class,
1125 new Class<?>[] {
1126 String.class, Byte.class, byte.class,
1127 short.class, int.class, long.class,
1128 float.class, double.class });
1129 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadByte", type);
1130
1131 spreader = delegate.asSpreader(byte[].class, 7);
1132 ret = (int) spreader.invokeExact("a",
1133 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 });
1134 assertEquals(45, ret);
1135 ret = (int) spreader.invoke("a",
1136 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 });
1137 assertEquals(45, ret);
1138
1139 // char[]
1140 // ---------------------
1141 type = MethodType.methodType(int.class,
1142 new Class<?>[] {
1143 String.class, Character.class,char.class,
1144 int.class, long.class, float.class, double.class });
1145 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadChar", type);
1146
1147 spreader = delegate.asSpreader(char[].class, 6);
1148 ret = (int) spreader.invokeExact("a",
1149 new char[] { '1', '2', '3', '4', '5', '6' });
1150 assertEquals(46, ret);
1151 ret = (int) spreader.invokeExact("a",
1152 new char[] { '1', '2', '3', '4', '5', '6' });
1153 assertEquals(46, ret);
1154
1155 // short[]
1156 // ---------------------
1157 type = MethodType.methodType(int.class,
1158 new Class<?>[] {
1159 String.class, Short.class, short.class,
1160 int.class, long.class, float.class, double.class });
1161 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadShort", type);
1162
1163 spreader = delegate.asSpreader(short[].class, 6);
1164 ret = (int) spreader.invokeExact("a",
1165 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
1166 assertEquals(47, ret);
1167 ret = (int) spreader.invoke("a",
1168 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
1169 assertEquals(47, ret);
1170
1171 // int[]
1172 // ---------------------
1173 type = MethodType.methodType(int.class,
1174 new Class<?>[] {
1175 String.class, Integer.class, int.class,
1176 long.class, float.class, double.class });
1177 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadInt", type);
1178
1179 spreader = delegate.asSpreader(int[].class, 5);
1180 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 });
1181 assertEquals(48, ret);
1182 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 });
1183 assertEquals(48, ret);
1184
1185 // long[]
1186 // ---------------------
1187 type = MethodType.methodType(int.class,
1188 new Class<?>[] {
1189 String.class, Long.class, long.class, float.class, double.class });
1190 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadLong", type);
1191
1192 spreader = delegate.asSpreader(long[].class, 4);
1193 ret = (int) spreader.invokeExact("a",
1194 new long[] { 0x1, 0x2, 0x3, 0x4 });
1195 assertEquals(49, ret);
1196 ret = (int) spreader.invoke("a",
1197 new long[] { 0x1, 0x2, 0x3, 0x4 });
1198 assertEquals(49, ret);
1199
1200 // float[]
1201 // ---------------------
1202 type = MethodType.methodType(int.class,
1203 new Class<?>[] {
1204 String.class, Float.class, float.class, double.class });
1205 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadFloat", type);
1206
1207 spreader = delegate.asSpreader(float[].class, 3);
1208 ret = (int) spreader.invokeExact("a",
1209 new float[] { 1.0f, 2.0f, 3.0f });
1210 assertEquals(50, ret);
1211 ret = (int) spreader.invokeExact("a",
1212 new float[] { 1.0f, 2.0f, 3.0f });
1213 assertEquals(50, ret);
1214
1215 // double[]
1216 // ---------------------
1217 type = MethodType.methodType(int.class,
1218 new Class<?>[] { String.class, Double.class, double.class });
1219 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadDouble", type);
1220
1221 spreader = delegate.asSpreader(double[].class, 2);
1222 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 });
1223 assertEquals(51, ret);
1224 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 });
1225 assertEquals(51, ret);
1226 }
1227
Narayan Kamathc5889ce2017-01-19 20:42:23 +00001228 public static void testInvokeWithArguments() throws Throwable {
1229 MethodType methodType = MethodType.methodType(int.class,
1230 new Class<?>[] { String.class, String.class, String.class });
1231 MethodHandle handle = MethodHandles.lookup().findStatic(
1232 Main.class, "spreadReferences", methodType);
1233
1234 Object ret = handle.invokeWithArguments(new Object[] { "a", "b", "c"});
1235 assertEquals(42, (int) ret);
1236 handle.invokeWithArguments(new String[] { "a", "b", "c" });
1237 assertEquals(42, (int) ret);
1238
1239 // Pass in an array that's too small. Should throw an IAE.
1240 try {
1241 handle.invokeWithArguments(new Object[] { "a", "b" });
1242 fail();
1243 } catch (IllegalArgumentException expected) {
Narayan Kamath2a3696a2017-01-24 19:16:25 +00001244 } catch (WrongMethodTypeException expected) {
Narayan Kamathc5889ce2017-01-19 20:42:23 +00001245 }
1246
1247 // Test implicit unboxing.
1248 MethodType methodType2 = MethodType.methodType(int.class,
1249 new Class<?>[] { String.class, int.class });
1250 MethodHandle handle2 = MethodHandles.lookup().findStatic(
1251 Main.class, "spreadReferences_Unbox", methodType2);
1252
1253 ret = (int) handle2.invokeWithArguments(new Object[] { "a", 43 });
1254 assertEquals(43, (int) ret);
1255 }
1256
Narayan Kamath2a3696a2017-01-24 19:16:25 +00001257 public static int collectBoolean(String a, boolean[] b) {
1258 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1259 return 44;
1260 }
1261
1262 public static int collectByte(String a, byte[] b) {
1263 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1264 return 45;
1265 }
1266
1267 public static int collectChar(String a, char[] b) {
1268 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1269 return 46;
1270 }
1271
1272 public static int collectShort(String a, short[] b) {
1273 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1274 return 47;
1275 }
1276
1277 public static int collectInt(String a, int[] b) {
1278 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1279 return 48;
1280 }
1281
1282 public static int collectLong(String a, long[] b) {
1283 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1284 return 49;
1285 }
1286
1287 public static int collectFloat(String a, float[] b) {
1288 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1289 return 50;
1290 }
1291
1292 public static int collectDouble(String a, double[] b) {
1293 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1294 return 51;
1295 }
1296
1297 public static int collectCharSequence(String a, CharSequence[] b) {
1298 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]);
1299 return 99;
1300 }
1301
1302 public static void testAsCollector() throws Throwable {
1303 // Reference arrays.
1304 // -------------------
1305 MethodHandle trailingRef = MethodHandles.lookup().findStatic(
1306 Main.class, "collectCharSequence",
1307 MethodType.methodType(int.class, String.class, CharSequence[].class));
1308
1309 // int[] is not convertible to CharSequence[].class.
1310 try {
1311 trailingRef.asCollector(int[].class, 1);
1312 fail();
1313 } catch (IllegalArgumentException expected) {
1314 }
1315
1316 // Object[] is not convertible to CharSequence[].class.
1317 try {
1318 trailingRef.asCollector(Object[].class, 1);
1319 fail();
1320 } catch (IllegalArgumentException expected) {
1321 }
1322
1323 // String[].class is convertible to CharSequence.class
1324 MethodHandle collector = trailingRef.asCollector(String[].class, 2);
1325 assertEquals(99, (int) collector.invoke("a", "b", "c"));
1326
1327 // Too few arguments should fail with a WMTE.
1328 try {
1329 collector.invoke("a", "b");
1330 fail();
1331 } catch (WrongMethodTypeException expected) {
1332 }
1333
1334 // Too many arguments should fail with a WMTE.
1335 try {
1336 collector.invoke("a", "b", "c", "d");
1337 fail();
1338 } catch (WrongMethodTypeException expected) {
1339 }
1340
1341 // Sanity checks on other array types.
1342
1343 MethodHandle target = MethodHandles.lookup().findStatic(
1344 Main.class, "collectBoolean",
1345 MethodType.methodType(int.class, String.class, boolean[].class));
1346 assertEquals(44, (int) target.asCollector(boolean[].class, 2).invoke("a", true, false));
1347
1348 target = MethodHandles.lookup().findStatic(Main.class, "collectByte",
1349 MethodType.methodType(int.class, String.class, byte[].class));
1350 assertEquals(45, (int) target.asCollector(byte[].class, 2).invoke("a", (byte) 1, (byte) 2));
1351
1352 target = MethodHandles.lookup().findStatic(Main.class, "collectChar",
1353 MethodType.methodType(int.class, String.class, char[].class));
1354 assertEquals(46, (int) target.asCollector(char[].class, 2).invoke("a", 'a', 'b'));
1355
1356 target = MethodHandles.lookup().findStatic(Main.class, "collectShort",
1357 MethodType.methodType(int.class, String.class, short[].class));
1358 assertEquals(47, (int) target.asCollector(short[].class, 2).invoke("a", (short) 3, (short) 4));
1359
1360 target = MethodHandles.lookup().findStatic(Main.class, "collectInt",
1361 MethodType.methodType(int.class, String.class, int[].class));
1362 assertEquals(48, (int) target.asCollector(int[].class, 2).invoke("a", 42, 43));
1363
1364 target = MethodHandles.lookup().findStatic(Main.class, "collectLong",
1365 MethodType.methodType(int.class, String.class, long[].class));
1366 assertEquals(49, (int) target.asCollector(long[].class, 2).invoke("a", 100, 99));
1367
1368 target = MethodHandles.lookup().findStatic(Main.class, "collectFloat",
1369 MethodType.methodType(int.class, String.class, float[].class));
1370 assertEquals(50, (int) target.asCollector(float[].class, 2).invoke("a", 8.9f, 9.1f));
1371
1372 target = MethodHandles.lookup().findStatic(Main.class, "collectDouble",
1373 MethodType.methodType(int.class, String.class, double[].class));
1374 assertEquals(51, (int) target.asCollector(double[].class, 2).invoke("a", 6.7, 7.8));
1375 }
1376
Narayan Kamath96120f42016-11-01 09:40:23 +00001377 public static void fail() {
1378 System.out.println("FAIL");
1379 Thread.dumpStack();
1380 }
1381
Orion Hodsonac141392017-01-13 11:53:47 +00001382 public static void fail(String message) {
1383 System.out.println("fail: " + message);
1384 Thread.dumpStack();
1385 }
1386
Narayan Kamathbcfd2842017-01-19 20:42:23 +00001387 public static void assertEquals(int i1, int i2) {
1388 if (i1 != i2) throw new AssertionError("Expected: " + i1 + " was " + i2);
1389 }
1390
Narayan Kamath96120f42016-11-01 09:40:23 +00001391 public static void assertEquals(String s1, String s2) {
1392 if (s1 == s2) {
1393 return;
1394 }
1395
1396 if (s1 != null && s2 != null && s1.equals(s2)) {
1397 return;
1398 }
1399
1400 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
1401 }
Narayan Kamath000e1882016-10-24 17:14:25 +01001402}