blob: d0bd816837faef29b2012ecdb26f7b8f4d55ec53 [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 Kamath000e1882016-10-24 17:14:25 +010040 }
41
42 public static void testThrowException() throws Throwable {
43 MethodHandle handle = MethodHandles.throwException(String.class,
44 IllegalArgumentException.class);
45
46 if (handle.type().returnType() != String.class) {
Orion Hodsonac141392017-01-13 11:53:47 +000047 fail("Unexpected return type for handle: " + handle +
Narayan Kamath000e1882016-10-24 17:14:25 +010048 " [ " + handle.type() + "]");
49 }
50
Narayan Kamath96120f42016-11-01 09:40:23 +000051 final IllegalArgumentException iae = new IllegalArgumentException("boo!");
Narayan Kamath000e1882016-10-24 17:14:25 +010052 try {
Narayan Kamath96120f42016-11-01 09:40:23 +000053 handle.invoke(iae);
Orion Hodsonac141392017-01-13 11:53:47 +000054 fail("Expected an exception of type: java.lang.IllegalArgumentException");
Narayan Kamath000e1882016-10-24 17:14:25 +010055 } catch (IllegalArgumentException expected) {
Narayan Kamath96120f42016-11-01 09:40:23 +000056 if (expected != iae) {
Orion Hodsonac141392017-01-13 11:53:47 +000057 fail("Wrong exception: expected " + iae + " but was " + expected);
Narayan Kamath96120f42016-11-01 09:40:23 +000058 }
Narayan Kamath000e1882016-10-24 17:14:25 +010059 }
60 }
Narayan Kamath96120f42016-11-01 09:40:23 +000061
62 public static void dropArguments_delegate(String message, long message2) {
63 System.out.println("Message: " + message + ", Message2: " + message2);
64 }
65
66 public static void testDropArguments() throws Throwable {
67 MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class,
68 "dropArguments_delegate",
69 MethodType.methodType(void.class, new Class<?>[] { String.class, long.class }));
70
71 MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
72
73 // The transformer will accept two additional arguments at position zero.
74 try {
75 transform.invokeExact("foo", 42l);
76 fail();
77 } catch (WrongMethodTypeException expected) {
78 }
79
80 transform.invokeExact(45, new Object(), "foo", 42l);
81 transform.invoke(45, new Object(), "foo", 42l);
82
83 // Additional arguments at position 1.
84 transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
85 transform.invokeExact("foo", 45, new Object(), 42l);
86 transform.invoke("foo", 45, new Object(), 42l);
87
88 // Additional arguments at position 2.
89 transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
90 transform.invokeExact("foo", 42l, 45, new Object());
91 transform.invoke("foo", 42l, 45, new Object());
92
93 // Note that we still perform argument conversions even for the arguments that
94 // are subsequently dropped.
95 try {
96 transform.invoke("foo", 42l, 45l, new Object());
97 fail();
98 } catch (WrongMethodTypeException expected) {
99 } catch (IllegalArgumentException expected) {
100 // TODO(narayan): We currently throw the wrong type of exception here,
101 // it's IAE and should be WMTE instead.
102 }
103
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000104 // Check that asType works as expected.
105 transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
106 transform = transform.asType(MethodType.methodType(void.class,
107 new Class<?>[] { short.class, Object.class, String.class, long.class }));
108 transform.invokeExact((short) 45, new Object(), "foo", 42l);
109
Narayan Kamath96120f42016-11-01 09:40:23 +0000110 // Invalid argument location, should not be allowed.
111 try {
112 MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
113 fail();
114 } catch (IllegalArgumentException expected) {
115 }
116
117 // Invalid argument location, should not be allowed.
118 try {
119 MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
120 fail();
121 } catch (IllegalArgumentException expected) {
122 }
123
124 try {
125 MethodHandles.dropArguments(delegate, 1, void.class);
126 fail();
127 } catch (IllegalArgumentException expected) {
128 }
129 }
130
131 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
132 throws Throwable {
133 if (exceptionMessage != null) {
134 throw new IllegalArgumentException(exceptionMessage);
135 }
136
137 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2);
138 return "target";
139 }
140
141 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2,
142 String exMsg) {
143 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg);
144 return "handler1";
145 }
146
147 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
148 System.out.println("Handler: " + iae + ", Arg1: " + arg1);
149 return "handler2";
150 }
151
152 public static void testCatchException() throws Throwable {
153 MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
154 "testCatchException_target",
155 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class }));
156
157 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class,
158 "testCatchException_handler",
159 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
160 String.class, long.class, String.class }));
161
162 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
163 handler);
164
165 String returnVal = null;
166
167 // These two should end up calling the target always. We're passing a null exception
168 // message here, which means the target will not throw.
169 returnVal = (String) adapter.invoke("foo", 42, null);
170 assertEquals("target", returnVal);
171 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
172 assertEquals("target", returnVal);
173
174 // We're passing a non-null exception message here, which means the target will throw,
175 // which in turn means that the handler must be called for the next two invokes.
176 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
177 assertEquals("handler1", returnVal);
178 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
179 assertEquals("handler1", returnVal);
180
181 handler = MethodHandles.lookup().findStatic(Main.class,
182 "testCatchException_handler2",
183 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
184 String.class }));
185 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
186
187 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
188 assertEquals("handler2", returnVal);
189 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
190 assertEquals("handler2", returnVal);
191
192 // Test that the type of the invoke doesn't matter. Here we call
193 // IllegalArgumentException.toString() on the exception that was thrown by
194 // the target.
195 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
196 "toString", MethodType.methodType(String.class));
197 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
198
199 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
200 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
201 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2");
202 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000203
204 // Check that asType works as expected.
205 adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
206 handler);
207 adapter = adapter.asType(MethodType.methodType(String.class,
208 new Class<?>[] { String.class, int.class, String.class }));
209 returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
210 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000211 }
212
213 public static boolean testGuardWithTest_test(String arg1, long arg2) {
214 return "target".equals(arg1) && 42 == arg2;
215 }
216
217 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
218 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3);
219 return "target";
220 }
221
222 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
223 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3);
224 return "fallback";
225 }
226
227 public static void testGuardWithTest() throws Throwable {
228 MethodHandle test = MethodHandles.lookup().findStatic(Main.class,
229 "testGuardWithTest_test",
230 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class }));
231
232 final MethodType type = MethodType.methodType(String.class,
233 new Class<?>[] { String.class, long.class, int.class });
234
235 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
236 "testGuardWithTest_target", type);
237 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class,
238 "testGuardWithTest_fallback", type);
239
240 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
241
242 String returnVal = null;
243
244 returnVal = (String) adapter.invoke("target", 42, 56);
245 assertEquals("target", returnVal);
246 returnVal = (String) adapter.invokeExact("target", 42l, 56);
247 assertEquals("target", returnVal);
248
249 returnVal = (String) adapter.invoke("fallback", 42l, 56);
250 assertEquals("fallback", returnVal);
251 returnVal = (String) adapter.invokeExact("target", 42l, 56);
252 assertEquals("target", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000253
254 // Check that asType works as expected.
255 adapter = adapter.asType(MethodType.methodType(String.class,
256 new Class<?>[] { String.class, int.class, int.class }));
257 returnVal = (String) adapter.invokeExact("target", 42, 56);
258 assertEquals("target", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000259 }
260
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000261 public static void testArrayElementGetter() throws Throwable {
262 MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
263
264 {
265 int[] array = new int[1];
266 array[0] = 42;
267 int value = (int) getter.invoke(array, 0);
268 if (value != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000269 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000270 }
271
272 try {
273 value = (int) getter.invoke(array, -1);
274 fail();
275 } catch (ArrayIndexOutOfBoundsException expected) {
276 }
277
278 try {
279 value = (int) getter.invoke(null, -1);
280 fail();
281 } catch (NullPointerException expected) {
282 }
283 }
284
285 {
286 getter = MethodHandles.arrayElementGetter(long[].class);
287 long[] array = new long[1];
288 array[0] = 42;
289 long value = (long) getter.invoke(array, 0);
290 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000291 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000292 }
293 }
294
295 {
296 getter = MethodHandles.arrayElementGetter(short[].class);
297 short[] array = new short[1];
298 array[0] = 42;
299 short value = (short) getter.invoke(array, 0);
300 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000301 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000302 }
303 }
304
305 {
306 getter = MethodHandles.arrayElementGetter(char[].class);
307 char[] array = new char[1];
308 array[0] = 42;
309 char value = (char) getter.invoke(array, 0);
310 if (value != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000311 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000312 }
313 }
314
315 {
316 getter = MethodHandles.arrayElementGetter(byte[].class);
317 byte[] array = new byte[1];
318 array[0] = (byte) 0x8;
319 byte value = (byte) getter.invoke(array, 0);
320 if (value != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000321 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000322 }
323 }
324
325 {
326 getter = MethodHandles.arrayElementGetter(boolean[].class);
327 boolean[] array = new boolean[1];
328 array[0] = true;
329 boolean value = (boolean) getter.invoke(array, 0);
330 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000331 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000332 }
333 }
334
335 {
336 getter = MethodHandles.arrayElementGetter(float[].class);
337 float[] array = new float[1];
338 array[0] = 42.0f;
339 float value = (float) getter.invoke(array, 0);
340 if (value != 42.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000341 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000342 }
343 }
344
345 {
346 getter = MethodHandles.arrayElementGetter(double[].class);
347 double[] array = new double[1];
348 array[0] = 42.0;
349 double value = (double) getter.invoke(array, 0);
350 if (value != 42.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000351 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000352 }
353 }
354
355 {
356 getter = MethodHandles.arrayElementGetter(String[].class);
357 String[] array = new String[3];
358 array[0] = "42";
359 array[1] = "48";
360 array[2] = "54";
361 String value = (String) getter.invoke(array, 0);
362 assertEquals("42", value);
363 value = (String) getter.invoke(array, 1);
364 assertEquals("48", value);
365 value = (String) getter.invoke(array, 2);
366 assertEquals("54", value);
367 }
368 }
369
370 public static void testArrayElementSetter() throws Throwable {
371 MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
372
373 {
374 int[] array = new int[2];
375 setter.invoke(array, 0, 42);
376 setter.invoke(array, 1, 43);
377
378 if (array[0] != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000379 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000380 }
381 if (array[1] != 43) {
Orion Hodsonac141392017-01-13 11:53:47 +0000382 fail("Unexpected value: " + array[1]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000383 }
384
385 try {
386 setter.invoke(array, -1, 42);
387 fail();
388 } catch (ArrayIndexOutOfBoundsException expected) {
389 }
390
391 try {
392 setter.invoke(null, 0, 42);
393 fail();
394 } catch (NullPointerException expected) {
395 }
396 }
397
398 {
399 setter = MethodHandles.arrayElementSetter(long[].class);
400 long[] array = new long[1];
401 setter.invoke(array, 0, 42l);
402 if (array[0] != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000403 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000404 }
405 }
406
407 {
408 setter = MethodHandles.arrayElementSetter(short[].class);
409 short[] array = new short[1];
410 setter.invoke(array, 0, (short) 42);
411 if (array[0] != 42l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000412 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000413 }
414 }
415
416 {
417 setter = MethodHandles.arrayElementSetter(char[].class);
418 char[] array = new char[1];
419 setter.invoke(array, 0, (char) 42);
420 if (array[0] != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000421 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000422 }
423 }
424
425 {
426 setter = MethodHandles.arrayElementSetter(byte[].class);
427 byte[] array = new byte[1];
428 setter.invoke(array, 0, (byte) 0x8);
429 if (array[0] != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000430 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000431 }
432 }
433
434 {
435 setter = MethodHandles.arrayElementSetter(boolean[].class);
436 boolean[] array = new boolean[1];
437 setter.invoke(array, 0, true);
438 if (!array[0]) {
Orion Hodsonac141392017-01-13 11:53:47 +0000439 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000440 }
441 }
442
443 {
444 setter = MethodHandles.arrayElementSetter(float[].class);
445 float[] array = new float[1];
446 setter.invoke(array, 0, 42.0f);
447 if (array[0] != 42.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000448 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000449 }
450 }
451
452 {
453 setter = MethodHandles.arrayElementSetter(double[].class);
454 double[] array = new double[1];
455 setter.invoke(array, 0, 42.0);
456 if (array[0] != 42.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000457 fail("Unexpected value: " + array[0]);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000458 }
459 }
460
461 {
462 setter = MethodHandles.arrayElementSetter(String[].class);
463 String[] array = new String[3];
464 setter.invoke(array, 0, "42");
465 setter.invoke(array, 1, "48");
466 setter.invoke(array, 2, "54");
467 assertEquals("42", array[0]);
468 assertEquals("48", array[1]);
469 assertEquals("54", array[2]);
470 }
471 }
472
473 public static void testIdentity() throws Throwable {
474 {
475 MethodHandle identity = MethodHandles.identity(boolean.class);
476 boolean value = (boolean) identity.invoke(false);
477 if (value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000478 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000479 }
480 }
481
482 {
483 MethodHandle identity = MethodHandles.identity(byte.class);
484 byte value = (byte) identity.invoke((byte) 0x8);
485 if (value != (byte) 0x8) {
Orion Hodsonac141392017-01-13 11:53:47 +0000486 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000487 }
488 }
489
490 {
491 MethodHandle identity = MethodHandles.identity(char.class);
492 char value = (char) identity.invoke((char) -56);
493 if (value != (char) -56) {
Orion Hodsonac141392017-01-13 11:53:47 +0000494 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000495 }
496 }
497
498 {
499 MethodHandle identity = MethodHandles.identity(short.class);
500 short value = (short) identity.invoke((short) -59);
501 if (value != (short) -59) {
Orion Hodsonac141392017-01-13 11:53:47 +0000502 fail("Unexpected value: " + Short.toString(value));
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000503 }
504 }
505
506 {
507 MethodHandle identity = MethodHandles.identity(int.class);
508 int value = (int) identity.invoke(52);
509 if (value != 52) {
Orion Hodsonac141392017-01-13 11:53:47 +0000510 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000511 }
512 }
513
514 {
515 MethodHandle identity = MethodHandles.identity(long.class);
516 long value = (long) identity.invoke(-76l);
517 if (value != (long) -76) {
Orion Hodsonac141392017-01-13 11:53:47 +0000518 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000519 }
520 }
521
522 {
523 MethodHandle identity = MethodHandles.identity(float.class);
524 float value = (float) identity.invoke(56.0f);
525 if (value != (float) 56.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000526 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000527 }
528 }
529
530 {
531 MethodHandle identity = MethodHandles.identity(double.class);
532 double value = (double) identity.invoke((double) 72.0);
533 if (value != (double) 72.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000534 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000535 }
536 }
537
538 {
539 MethodHandle identity = MethodHandles.identity(String.class);
540 String value = (String) identity.invoke("bazman");
541 assertEquals("bazman", value);
542 }
543 }
544
545 public static void testConstant() throws Throwable {
546 // int constants.
547 {
548 MethodHandle constant = MethodHandles.constant(int.class, 56);
549 int value = (int) constant.invoke();
550 if (value != 56) {
Orion Hodsonac141392017-01-13 11:53:47 +0000551 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000552 }
553
554 // short constant values are converted to int.
555 constant = MethodHandles.constant(int.class, (short) 52);
556 value = (int) constant.invoke();
557 if (value != 52) {
Orion Hodsonac141392017-01-13 11:53:47 +0000558 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000559 }
560
561 // char constant values are converted to int.
562 constant = MethodHandles.constant(int.class, (char) 'b');
563 value = (int) constant.invoke();
564 if (value != (int) 'b') {
Orion Hodsonac141392017-01-13 11:53:47 +0000565 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000566 }
567
568 // int constant values are converted to int.
569 constant = MethodHandles.constant(int.class, (byte) 0x1);
570 value = (int) constant.invoke();
571 if (value != 1) {
Orion Hodsonac141392017-01-13 11:53:47 +0000572 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000573 }
574
575 // boolean, float, double and long primitive constants are not convertible
576 // to int, so the handle creation must fail with a CCE.
577 try {
578 MethodHandles.constant(int.class, false);
579 fail();
580 } catch (ClassCastException expected) {
581 }
582
583 try {
584 MethodHandles.constant(int.class, 0.1f);
585 fail();
586 } catch (ClassCastException expected) {
587 }
588
589 try {
590 MethodHandles.constant(int.class, 0.2);
591 fail();
592 } catch (ClassCastException expected) {
593 }
594
595 try {
596 MethodHandles.constant(int.class, 73l);
597 fail();
598 } catch (ClassCastException expected) {
599 }
600 }
601
602 // long constants.
603 {
604 MethodHandle constant = MethodHandles.constant(long.class, 56l);
605 long value = (long) constant.invoke();
606 if (value != 56l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000607 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000608 }
609
610 constant = MethodHandles.constant(long.class, (int) 56);
611 value = (long) constant.invoke();
612 if (value != 56l) {
Orion Hodsonac141392017-01-13 11:53:47 +0000613 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000614 }
615 }
616
617 // byte constants.
618 {
619 MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12);
620 byte value = (byte) constant.invoke();
621 if (value != (byte) 0x12) {
Orion Hodsonac141392017-01-13 11:53:47 +0000622 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000623 }
624 }
625
626 // boolean constants.
627 {
628 MethodHandle constant = MethodHandles.constant(boolean.class, true);
629 boolean value = (boolean) constant.invoke();
630 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000631 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000632 }
633 }
634
635 // char constants.
636 {
637 MethodHandle constant = MethodHandles.constant(char.class, 'f');
638 char value = (char) constant.invoke();
639 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000640 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000641 }
642 }
643
644 // short constants.
645 {
646 MethodHandle constant = MethodHandles.constant(short.class, (short) 123);
647 short value = (short) constant.invoke();
648 if (value != (short) 123) {
Orion Hodsonac141392017-01-13 11:53:47 +0000649 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000650 }
651 }
652
653 // float constants.
654 {
655 MethodHandle constant = MethodHandles.constant(float.class, 56.0f);
656 float value = (float) constant.invoke();
657 if (value != 56.0f) {
Orion Hodsonac141392017-01-13 11:53:47 +0000658 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000659 }
660 }
661
662 // double constants.
663 {
664 MethodHandle constant = MethodHandles.constant(double.class, 256.0);
665 double value = (double) constant.invoke();
666 if (value != 256.0) {
Orion Hodsonac141392017-01-13 11:53:47 +0000667 fail("Unexpected value: " + value);
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000668 }
669 }
670
671 // reference constants.
672 {
673 MethodHandle constant = MethodHandles.constant(String.class, "256.0");
674 String value = (String) constant.invoke();
675 assertEquals("256.0", value);
676 }
677 }
678
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000679 public static void testBindTo() throws Throwable {
680 MethodHandle stringCharAt = MethodHandles.lookup().findVirtual(
681 String.class, "charAt", MethodType.methodType(char.class, int.class));
682
683 char value = (char) stringCharAt.invoke("foo", 0);
684 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000685 fail("Unexpected value: " + value);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000686 }
687
688 MethodHandle bound = stringCharAt.bindTo("foo");
689 value = (char) bound.invoke(0);
690 if (value != 'f') {
Orion Hodsonac141392017-01-13 11:53:47 +0000691 fail("Unexpected value: " + value);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000692 }
693
694 try {
695 stringCharAt.bindTo(new Object());
696 fail();
697 } catch (ClassCastException expected) {
698 }
699
700 bound = stringCharAt.bindTo(null);
701 try {
702 bound.invoke(0);
703 fail();
704 } catch (NullPointerException expected) {
705 }
706
707 MethodHandle integerParseInt = MethodHandles.lookup().findStatic(
708 Integer.class, "parseInt", MethodType.methodType(int.class, String.class));
709
710 bound = integerParseInt.bindTo("78452");
711 int intValue = (int) bound.invoke();
712 if (intValue != 78452) {
Orion Hodsonac141392017-01-13 11:53:47 +0000713 fail("Unexpected value: " + intValue);
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000714 }
715 }
716
Narayan Kamath916a7712016-11-08 18:36:16 +0000717 public static String filterReturnValue_target(int a) {
718 return "ReturnValue" + a;
719 }
720
721 public static boolean filterReturnValue_filter(String value) {
722 return value.indexOf("42") != -1;
723 }
724
725 public static int filterReturnValue_intTarget(String a) {
726 return Integer.parseInt(a);
727 }
728
729 public static int filterReturnValue_intFilter(int b) {
730 return b + 1;
731 }
732
733 public static void filterReturnValue_voidTarget() {
734 }
735
736 public static int filterReturnValue_voidFilter() {
737 return 42;
738 }
739
740 public static void testFilterReturnValue() throws Throwable {
741 // A target that returns a reference.
742 {
743 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
744 "filterReturnValue_target", MethodType.methodType(String.class, int.class));
745 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
746 "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class));
747
748 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
749
750 boolean value = (boolean) adapter.invoke((int) 42);
751 if (!value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000752 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000753 }
754 value = (boolean) adapter.invoke((int) 43);
755 if (value) {
Orion Hodsonac141392017-01-13 11:53:47 +0000756 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000757 }
758 }
759
760 // A target that returns a primitive.
761 {
762 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
763 "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class));
764 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
765 "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class));
766
767 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
768
769 int value = (int) adapter.invoke("56");
770 if (value != 57) {
Orion Hodsonac141392017-01-13 11:53:47 +0000771 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000772 }
773 }
774
775 // A target that returns void.
776 {
777 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
778 "filterReturnValue_voidTarget", MethodType.methodType(void.class));
779 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
780 "filterReturnValue_voidFilter", MethodType.methodType(int.class));
781
782 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
783
784 int value = (int) adapter.invoke();
785 if (value != 42) {
Orion Hodsonac141392017-01-13 11:53:47 +0000786 fail("Unexpected value: " + value);
Narayan Kamath916a7712016-11-08 18:36:16 +0000787 }
788 }
789 }
790
Narayan Kamath731f4c62016-11-08 19:38:48 +0000791 public static void permuteArguments_callee(boolean a, byte b, char c,
792 short d, int e, long f, float g, double h) {
793 if (a == true && b == (byte) 'b' && c == 'c' && d == (short) 56 &&
794 e == 78 && f == (long) 97 && g == 98.0f && f == 97.0) {
795 return;
796 }
797
Orion Hodsonac141392017-01-13 11:53:47 +0000798 fail("Unexpected arguments: " + a + ", " + b + ", " + c
Narayan Kamath731f4c62016-11-08 19:38:48 +0000799 + ", " + d + ", " + e + ", " + f + ", " + g + ", " + h);
800 }
801
802 public static void permuteArguments_boxingCallee(boolean a, Integer b) {
803 if (a && b.intValue() == 42) {
804 return;
805 }
806
Orion Hodsonac141392017-01-13 11:53:47 +0000807 fail("Unexpected arguments: " + a + ", " + b);
Narayan Kamath731f4c62016-11-08 19:38:48 +0000808 }
809
810 public static void testPermuteArguments() throws Throwable {
811 {
812 final MethodHandle target = MethodHandles.lookup().findStatic(
813 Main.class, "permuteArguments_callee",
814 MethodType.methodType(void.class, new Class<?>[] {
815 boolean.class, byte.class, char.class, short.class, int.class,
816 long.class, float.class, double.class }));
817
818 final MethodType newType = MethodType.methodType(void.class, new Class<?>[] {
819 double.class, float.class, long.class, int.class, short.class, char.class,
820 byte.class, boolean.class });
821
822 final MethodHandle permutation = MethodHandles.permuteArguments(
823 target, newType, new int[] { 7, 6, 5, 4, 3, 2, 1, 0 });
824
825 permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78,
826 (short) 56, 'c', (byte) 'b', (boolean) true);
827
828 // The permutation array was not of the right length.
829 try {
830 MethodHandles.permuteArguments(target, newType,
831 new int[] { 7 });
832 fail();
833 } catch (IllegalArgumentException expected) {
834 }
835
836 // The permutation array has an element that's out of bounds
837 // (there's no argument with idx == 8).
838 try {
839 MethodHandles.permuteArguments(target, newType,
840 new int[] { 8, 6, 5, 4, 3, 2, 1, 0 });
841 fail();
842 } catch (IllegalArgumentException expected) {
843 }
844
845 // The permutation array maps to an incorrect type.
846 try {
847 MethodHandles.permuteArguments(target, newType,
848 new int[] { 7, 7, 5, 4, 3, 2, 1, 0 });
849 fail();
850 } catch (IllegalArgumentException expected) {
851 }
852 }
853
854 // Tests for reference arguments as well as permutations that
855 // repeat arguments.
856 {
857 final MethodHandle target = MethodHandles.lookup().findVirtual(
858 String.class, "concat", MethodType.methodType(String.class, String.class));
859
860 final MethodType newType = MethodType.methodType(String.class, String.class,
861 String.class);
862
863 assertEquals("foobar", (String) target.invoke("foo", "bar"));
864
865 MethodHandle permutation = MethodHandles.permuteArguments(target,
866 newType, new int[] { 1, 0 });
867 assertEquals("barfoo", (String) permutation.invoke("foo", "bar"));
868
869 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 0, 0 });
870 assertEquals("foofoo", (String) permutation.invoke("foo", "bar"));
871
872 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 1, 1 });
873 assertEquals("barbar", (String) permutation.invoke("foo", "bar"));
874 }
875
876 // Tests for boxing and unboxing.
877 {
878 final MethodHandle target = MethodHandles.lookup().findStatic(
879 Main.class, "permuteArguments_boxingCallee",
880 MethodType.methodType(void.class, new Class<?>[] { boolean.class, Integer.class }));
881
882 final MethodType newType = MethodType.methodType(void.class,
883 new Class<?>[] { Integer.class, boolean.class });
884
885 MethodHandle permutation = MethodHandles.permuteArguments(target,
886 newType, new int[] { 1, 0 });
887
888 permutation.invoke(42, true);
889 permutation.invoke(42, Boolean.TRUE);
890 permutation.invoke(Integer.valueOf(42), true);
891 permutation.invoke(Integer.valueOf(42), Boolean.TRUE);
892 }
893 }
894
Narayan Kamathb79bbd82017-01-16 17:48:28 +0000895 private static Object returnBar() {
896 return "bar";
897 }
898
899 public static void testInvokers() throws Throwable {
900 final MethodType targetType = MethodType.methodType(String.class, String.class);
901 final MethodHandle target = MethodHandles.lookup().findVirtual(
902 String.class, "concat", targetType);
903
904 MethodHandle invoker = MethodHandles.invoker(target.type());
905 assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar"));
906 assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar"));
907 try {
908 String foo = (String) invoker.invoke(target, "bar", "bar", 24);
909 fail();
910 } catch (WrongMethodTypeException expected) {
911 }
912
913 MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type());
914 assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar"));
915 try {
916 String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar");
917 fail();
918 } catch (WrongMethodTypeException expected) {
919 }
920 try {
921 String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24);
922 fail();
923 } catch (WrongMethodTypeException expected) {
924 }
925 }
926
Narayan Kamathbcfd2842017-01-19 20:42:23 +0000927 public static int spreadReferences(String a, String b, String c) {
928 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
929 return 42;
930 }
931
932 public static int spreadReferences_Unbox(String a, int b) {
933 System.out.println("a: " + a + ", b:" + b);
934 return 43;
935 }
936
937 public static void testSpreaders_reference() throws Throwable {
938 MethodType methodType = MethodType.methodType(int.class,
939 new Class<?>[] { String.class, String.class, String.class });
940 MethodHandle delegate = MethodHandles.lookup().findStatic(
941 Main.class, "spreadReferences", methodType);
942
943 // Basic checks on array lengths.
944 //
945 // Array size = 0
946 MethodHandle mhAsSpreader = delegate.asSpreader(String[].class, 0);
947 int ret = (int) mhAsSpreader.invoke("a", "b", "c", new String[] {});
948 assertEquals(42, ret);
949 // Array size = 1
950 mhAsSpreader = delegate.asSpreader(String[].class, 1);
951 ret = (int) mhAsSpreader.invoke("a", "b", new String[] { "c" });
952 assertEquals(42, ret);
953 // Array size = 2
954 mhAsSpreader = delegate.asSpreader(String[].class, 2);
955 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" });
956 assertEquals(42, ret);
957 // Array size = 3
958 mhAsSpreader = delegate.asSpreader(String[].class, 3);
959 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b", "c"});
960 assertEquals(42, ret);
961
962 // Exception case, array size = 4 is illegal.
963 try {
964 delegate.asSpreader(String[].class, 4);
965 fail();
966 } catch (IllegalArgumentException expected) {
967 }
968
969 // Exception case, calling with an arg of the wrong size.
970 // Array size = 3
971 mhAsSpreader = delegate.asSpreader(String[].class, 3);
972 try {
973 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b"});
974 } catch (IllegalArgumentException expected) {
975 }
976
977 // Various other hijinks, pass as Object[] arrays, Object etc.
978 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
979 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" });
980 assertEquals(42, ret);
981
982 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
983 ret = (int) mhAsSpreader.invoke("a", new Object[] { "b", "c" });
984 assertEquals(42, ret);
985
986 mhAsSpreader = delegate.asSpreader(Object[].class, 2);
987 ret = (int) mhAsSpreader.invoke("a", (Object) new Object[] { "b", "c" });
988 assertEquals(42, ret);
989
990 // Test implicit unboxing.
991 MethodType methodType2 = MethodType.methodType(int.class,
992 new Class<?>[] { String.class, int.class });
993 MethodHandle delegate2 = MethodHandles.lookup().findStatic(
994 Main.class, "spreadReferences_Unbox", methodType2);
995
996 // .. with an Integer[] array.
997 mhAsSpreader = delegate2.asSpreader(Integer[].class, 1);
998 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 });
999 assertEquals(43, ret);
1000
1001 // .. with an Integer[] array declared as an Object[] argument type.
1002 mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
1003 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 });
1004 assertEquals(43, ret);
1005
1006 // .. with an Object[] array.
1007 mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
1008 ret = (int) mhAsSpreader.invoke("a", new Object[] { Integer.valueOf(43)});
1009 assertEquals(43, ret);
1010
1011 // -- Part 2--
1012 // Run a subset of these tests on MethodHandles.spreadInvoker, which only accepts
1013 // a trailing argument type of Object[].
1014 MethodHandle spreadInvoker = MethodHandles.spreadInvoker(methodType2, 1);
1015 ret = (int) spreadInvoker.invoke(delegate2, "a", new Object[] { Integer.valueOf(43)});
1016 assertEquals(43, ret);
1017
1018 ret = (int) spreadInvoker.invoke(delegate2, "a", new Integer[] { 43 });
1019 assertEquals(43, ret);
1020
1021 // NOTE: Annoyingly, the second argument here is leadingArgCount and not
1022 // arrayLength.
1023 spreadInvoker = MethodHandles.spreadInvoker(methodType, 3);
1024 ret = (int) spreadInvoker.invoke(delegate, "a", "b", "c", new String[] {});
1025 assertEquals(42, ret);
1026
1027 spreadInvoker = MethodHandles.spreadInvoker(methodType, 0);
1028 ret = (int) spreadInvoker.invoke(delegate, new String[] { "a", "b", "c" });
1029 assertEquals(42, ret);
1030
1031 // Exact invokes: Double check that the expected parameter type is
1032 // Object[] and not T[].
1033 try {
1034 spreadInvoker.invokeExact(delegate, new String[] { "a", "b", "c" });
1035 fail();
1036 } catch (WrongMethodTypeException expected) {
1037 }
1038
1039 ret = (int) spreadInvoker.invoke(delegate, new Object[] { "a", "b", "c" });
1040 assertEquals(42, ret);
1041 }
1042
1043 public static int spreadBoolean(String a, Boolean b, boolean c) {
1044 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
1045 return 44;
1046 }
1047
1048 public static int spreadByte(String a, Byte b, byte c,
1049 short d, int e, long f, float g, double h) {
1050 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1051 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g +
1052 ", h: " + h);
1053 return 45;
1054 }
1055
1056 public static int spreadChar(String a, Character b, char c,
1057 int d, long e, float f, double g) {
1058 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1059 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g);
1060 return 46;
1061 }
1062
1063 public static int spreadShort(String a, Short b, short c,
1064 int d, long e, float f, double g) {
1065 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1066 ", d: " + d + ", e: " + e + ", f:" + f + ", g:" + g);
1067 return 47;
1068 }
1069
1070 public static int spreadInt(String a, Integer b, int c,
1071 long d, float e, double f) {
1072 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1073 ", d: " + d + ", e: " + e + ", f:" + f);
1074 return 48;
1075 }
1076
1077 public static int spreadLong(String a, Long b, long c, float d, double e) {
1078 System.out.println("a: " + a + ", b:" + b + ", c: " + c +
1079 ", d: " + d + ", e: " + e);
1080 return 49;
1081 }
1082
1083 public static int spreadFloat(String a, Float b, float c, double d) {
1084 System.out.println("a: " + a + ", b:" + b + ", c: " + c + ", d: " + d);
1085 return 50;
1086 }
1087
1088 public static int spreadDouble(String a, Double b, double c) {
1089 System.out.println("a: " + a + ", b:" + b + ", c: " + c);
1090 return 51;
1091 }
1092
1093 public static void testSpreaders_primitive() throws Throwable {
1094 // boolean[]
1095 // ---------------------
1096 MethodType type = MethodType.methodType(int.class,
1097 new Class<?>[] { String.class, Boolean.class, boolean.class });
1098 MethodHandle delegate = MethodHandles.lookup().findStatic(
1099 Main.class, "spreadBoolean", type);
1100
1101 MethodHandle spreader = delegate.asSpreader(boolean[].class, 2);
1102 int ret = (int) spreader.invokeExact("a", new boolean[] { true, false });
1103 assertEquals(44, ret);
1104 ret = (int) spreader.invoke("a", new boolean[] { true, false });
1105 assertEquals(44, ret);
1106
1107 // boolean can't be cast to String (the first argument to the method).
1108 try {
1109 delegate.asSpreader(boolean[].class, 3);
1110 fail();
1111 } catch (WrongMethodTypeException expected) {
1112 }
1113
1114 // int can't be cast to boolean to supply the last argument to the method.
1115 try {
1116 delegate.asSpreader(int[].class, 1);
1117 fail();
1118 } catch (WrongMethodTypeException expected) {
1119 }
1120
1121 // byte[]
1122 // ---------------------
1123 type = MethodType.methodType(int.class,
1124 new Class<?>[] {
1125 String.class, Byte.class, byte.class,
1126 short.class, int.class, long.class,
1127 float.class, double.class });
1128 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadByte", type);
1129
1130 spreader = delegate.asSpreader(byte[].class, 7);
1131 ret = (int) spreader.invokeExact("a",
1132 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 });
1133 assertEquals(45, ret);
1134 ret = (int) spreader.invoke("a",
1135 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 });
1136 assertEquals(45, ret);
1137
1138 // char[]
1139 // ---------------------
1140 type = MethodType.methodType(int.class,
1141 new Class<?>[] {
1142 String.class, Character.class,char.class,
1143 int.class, long.class, float.class, double.class });
1144 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadChar", type);
1145
1146 spreader = delegate.asSpreader(char[].class, 6);
1147 ret = (int) spreader.invokeExact("a",
1148 new char[] { '1', '2', '3', '4', '5', '6' });
1149 assertEquals(46, ret);
1150 ret = (int) spreader.invokeExact("a",
1151 new char[] { '1', '2', '3', '4', '5', '6' });
1152 assertEquals(46, ret);
1153
1154 // short[]
1155 // ---------------------
1156 type = MethodType.methodType(int.class,
1157 new Class<?>[] {
1158 String.class, Short.class, short.class,
1159 int.class, long.class, float.class, double.class });
1160 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadShort", type);
1161
1162 spreader = delegate.asSpreader(short[].class, 6);
1163 ret = (int) spreader.invokeExact("a",
1164 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
1165 assertEquals(47, ret);
1166 ret = (int) spreader.invoke("a",
1167 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
1168 assertEquals(47, ret);
1169
1170 // int[]
1171 // ---------------------
1172 type = MethodType.methodType(int.class,
1173 new Class<?>[] {
1174 String.class, Integer.class, int.class,
1175 long.class, float.class, double.class });
1176 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadInt", type);
1177
1178 spreader = delegate.asSpreader(int[].class, 5);
1179 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 });
1180 assertEquals(48, ret);
1181 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 });
1182 assertEquals(48, ret);
1183
1184 // long[]
1185 // ---------------------
1186 type = MethodType.methodType(int.class,
1187 new Class<?>[] {
1188 String.class, Long.class, long.class, float.class, double.class });
1189 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadLong", type);
1190
1191 spreader = delegate.asSpreader(long[].class, 4);
1192 ret = (int) spreader.invokeExact("a",
1193 new long[] { 0x1, 0x2, 0x3, 0x4 });
1194 assertEquals(49, ret);
1195 ret = (int) spreader.invoke("a",
1196 new long[] { 0x1, 0x2, 0x3, 0x4 });
1197 assertEquals(49, ret);
1198
1199 // float[]
1200 // ---------------------
1201 type = MethodType.methodType(int.class,
1202 new Class<?>[] {
1203 String.class, Float.class, float.class, double.class });
1204 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadFloat", type);
1205
1206 spreader = delegate.asSpreader(float[].class, 3);
1207 ret = (int) spreader.invokeExact("a",
1208 new float[] { 1.0f, 2.0f, 3.0f });
1209 assertEquals(50, ret);
1210 ret = (int) spreader.invokeExact("a",
1211 new float[] { 1.0f, 2.0f, 3.0f });
1212 assertEquals(50, ret);
1213
1214 // double[]
1215 // ---------------------
1216 type = MethodType.methodType(int.class,
1217 new Class<?>[] { String.class, Double.class, double.class });
1218 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadDouble", type);
1219
1220 spreader = delegate.asSpreader(double[].class, 2);
1221 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 });
1222 assertEquals(51, ret);
1223 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 });
1224 assertEquals(51, ret);
1225 }
1226
Narayan Kamathc5889ce2017-01-19 20:42:23 +00001227 public static void testInvokeWithArguments() throws Throwable {
1228 MethodType methodType = MethodType.methodType(int.class,
1229 new Class<?>[] { String.class, String.class, String.class });
1230 MethodHandle handle = MethodHandles.lookup().findStatic(
1231 Main.class, "spreadReferences", methodType);
1232
1233 Object ret = handle.invokeWithArguments(new Object[] { "a", "b", "c"});
1234 assertEquals(42, (int) ret);
1235 handle.invokeWithArguments(new String[] { "a", "b", "c" });
1236 assertEquals(42, (int) ret);
1237
1238 // Pass in an array that's too small. Should throw an IAE.
1239 try {
1240 handle.invokeWithArguments(new Object[] { "a", "b" });
1241 fail();
1242 } catch (IllegalArgumentException expected) {
1243 }
1244
1245 // Test implicit unboxing.
1246 MethodType methodType2 = MethodType.methodType(int.class,
1247 new Class<?>[] { String.class, int.class });
1248 MethodHandle handle2 = MethodHandles.lookup().findStatic(
1249 Main.class, "spreadReferences_Unbox", methodType2);
1250
1251 ret = (int) handle2.invokeWithArguments(new Object[] { "a", 43 });
1252 assertEquals(43, (int) ret);
1253 }
1254
Narayan Kamath96120f42016-11-01 09:40:23 +00001255 public static void fail() {
1256 System.out.println("FAIL");
1257 Thread.dumpStack();
1258 }
1259
Orion Hodsonac141392017-01-13 11:53:47 +00001260 public static void fail(String message) {
1261 System.out.println("fail: " + message);
1262 Thread.dumpStack();
1263 }
1264
Narayan Kamathbcfd2842017-01-19 20:42:23 +00001265 public static void assertEquals(int i1, int i2) {
1266 if (i1 != i2) throw new AssertionError("Expected: " + i1 + " was " + i2);
1267 }
1268
Narayan Kamath96120f42016-11-01 09:40:23 +00001269 public static void assertEquals(String s1, String s2) {
1270 if (s1 == s2) {
1271 return;
1272 }
1273
1274 if (s1 != null && s2 != null && s1.equals(s2)) {
1275 return;
1276 }
1277
1278 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
1279 }
Narayan Kamath000e1882016-10-24 17:14:25 +01001280}