blob: 5806509fc37abc5cb812b8de1331913a747722ae [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 Kamath000e1882016-10-24 17:14:25 +010036 }
37
38 public static void testThrowException() throws Throwable {
39 MethodHandle handle = MethodHandles.throwException(String.class,
40 IllegalArgumentException.class);
41
42 if (handle.type().returnType() != String.class) {
43 System.out.println("Unexpected return type for handle: " + handle +
44 " [ " + handle.type() + "]");
45 }
46
Narayan Kamath96120f42016-11-01 09:40:23 +000047 final IllegalArgumentException iae = new IllegalArgumentException("boo!");
Narayan Kamath000e1882016-10-24 17:14:25 +010048 try {
Narayan Kamath96120f42016-11-01 09:40:23 +000049 handle.invoke(iae);
Narayan Kamath000e1882016-10-24 17:14:25 +010050 System.out.println("Expected an exception of type: java.lang.IllegalArgumentException");
51 } catch (IllegalArgumentException expected) {
Narayan Kamath96120f42016-11-01 09:40:23 +000052 if (expected != iae) {
53 System.out.println("Wrong exception: expected " + iae + " but was " + expected);
54 }
Narayan Kamath000e1882016-10-24 17:14:25 +010055 }
56 }
Narayan Kamath96120f42016-11-01 09:40:23 +000057
58 public static void dropArguments_delegate(String message, long message2) {
59 System.out.println("Message: " + message + ", Message2: " + message2);
60 }
61
62 public static void testDropArguments() throws Throwable {
63 MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class,
64 "dropArguments_delegate",
65 MethodType.methodType(void.class, new Class<?>[] { String.class, long.class }));
66
67 MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
68
69 // The transformer will accept two additional arguments at position zero.
70 try {
71 transform.invokeExact("foo", 42l);
72 fail();
73 } catch (WrongMethodTypeException expected) {
74 }
75
76 transform.invokeExact(45, new Object(), "foo", 42l);
77 transform.invoke(45, new Object(), "foo", 42l);
78
79 // Additional arguments at position 1.
80 transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
81 transform.invokeExact("foo", 45, new Object(), 42l);
82 transform.invoke("foo", 45, new Object(), 42l);
83
84 // Additional arguments at position 2.
85 transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
86 transform.invokeExact("foo", 42l, 45, new Object());
87 transform.invoke("foo", 42l, 45, new Object());
88
89 // Note that we still perform argument conversions even for the arguments that
90 // are subsequently dropped.
91 try {
92 transform.invoke("foo", 42l, 45l, new Object());
93 fail();
94 } catch (WrongMethodTypeException expected) {
95 } catch (IllegalArgumentException expected) {
96 // TODO(narayan): We currently throw the wrong type of exception here,
97 // it's IAE and should be WMTE instead.
98 }
99
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000100 // Check that asType works as expected.
101 transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
102 transform = transform.asType(MethodType.methodType(void.class,
103 new Class<?>[] { short.class, Object.class, String.class, long.class }));
104 transform.invokeExact((short) 45, new Object(), "foo", 42l);
105
Narayan Kamath96120f42016-11-01 09:40:23 +0000106 // Invalid argument location, should not be allowed.
107 try {
108 MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
109 fail();
110 } catch (IllegalArgumentException expected) {
111 }
112
113 // Invalid argument location, should not be allowed.
114 try {
115 MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
116 fail();
117 } catch (IllegalArgumentException expected) {
118 }
119
120 try {
121 MethodHandles.dropArguments(delegate, 1, void.class);
122 fail();
123 } catch (IllegalArgumentException expected) {
124 }
125 }
126
127 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
128 throws Throwable {
129 if (exceptionMessage != null) {
130 throw new IllegalArgumentException(exceptionMessage);
131 }
132
133 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2);
134 return "target";
135 }
136
137 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2,
138 String exMsg) {
139 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg);
140 return "handler1";
141 }
142
143 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
144 System.out.println("Handler: " + iae + ", Arg1: " + arg1);
145 return "handler2";
146 }
147
148 public static void testCatchException() throws Throwable {
149 MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
150 "testCatchException_target",
151 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class }));
152
153 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class,
154 "testCatchException_handler",
155 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
156 String.class, long.class, String.class }));
157
158 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
159 handler);
160
161 String returnVal = null;
162
163 // These two should end up calling the target always. We're passing a null exception
164 // message here, which means the target will not throw.
165 returnVal = (String) adapter.invoke("foo", 42, null);
166 assertEquals("target", returnVal);
167 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
168 assertEquals("target", returnVal);
169
170 // We're passing a non-null exception message here, which means the target will throw,
171 // which in turn means that the handler must be called for the next two invokes.
172 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
173 assertEquals("handler1", returnVal);
174 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
175 assertEquals("handler1", returnVal);
176
177 handler = MethodHandles.lookup().findStatic(Main.class,
178 "testCatchException_handler2",
179 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
180 String.class }));
181 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
182
183 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
184 assertEquals("handler2", returnVal);
185 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
186 assertEquals("handler2", returnVal);
187
188 // Test that the type of the invoke doesn't matter. Here we call
189 // IllegalArgumentException.toString() on the exception that was thrown by
190 // the target.
191 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
192 "toString", MethodType.methodType(String.class));
193 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
194
195 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
196 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
197 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2");
198 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000199
200 // Check that asType works as expected.
201 adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
202 handler);
203 adapter = adapter.asType(MethodType.methodType(String.class,
204 new Class<?>[] { String.class, int.class, String.class }));
205 returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
206 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000207 }
208
209 public static boolean testGuardWithTest_test(String arg1, long arg2) {
210 return "target".equals(arg1) && 42 == arg2;
211 }
212
213 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
214 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3);
215 return "target";
216 }
217
218 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
219 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3);
220 return "fallback";
221 }
222
223 public static void testGuardWithTest() throws Throwable {
224 MethodHandle test = MethodHandles.lookup().findStatic(Main.class,
225 "testGuardWithTest_test",
226 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class }));
227
228 final MethodType type = MethodType.methodType(String.class,
229 new Class<?>[] { String.class, long.class, int.class });
230
231 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
232 "testGuardWithTest_target", type);
233 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class,
234 "testGuardWithTest_fallback", type);
235
236 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
237
238 String returnVal = null;
239
240 returnVal = (String) adapter.invoke("target", 42, 56);
241 assertEquals("target", returnVal);
242 returnVal = (String) adapter.invokeExact("target", 42l, 56);
243 assertEquals("target", returnVal);
244
245 returnVal = (String) adapter.invoke("fallback", 42l, 56);
246 assertEquals("fallback", returnVal);
247 returnVal = (String) adapter.invokeExact("target", 42l, 56);
248 assertEquals("target", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000249
250 // Check that asType works as expected.
251 adapter = adapter.asType(MethodType.methodType(String.class,
252 new Class<?>[] { String.class, int.class, int.class }));
253 returnVal = (String) adapter.invokeExact("target", 42, 56);
254 assertEquals("target", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000255 }
256
Narayan Kamath3314dbb2016-11-03 18:01:32 +0000257 public static void testArrayElementGetter() throws Throwable {
258 MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
259
260 {
261 int[] array = new int[1];
262 array[0] = 42;
263 int value = (int) getter.invoke(array, 0);
264 if (value != 42) {
265 System.out.println("Unexpected value: " + value);
266 }
267
268 try {
269 value = (int) getter.invoke(array, -1);
270 fail();
271 } catch (ArrayIndexOutOfBoundsException expected) {
272 }
273
274 try {
275 value = (int) getter.invoke(null, -1);
276 fail();
277 } catch (NullPointerException expected) {
278 }
279 }
280
281 {
282 getter = MethodHandles.arrayElementGetter(long[].class);
283 long[] array = new long[1];
284 array[0] = 42;
285 long value = (long) getter.invoke(array, 0);
286 if (value != 42l) {
287 System.out.println("Unexpected value: " + value);
288 }
289 }
290
291 {
292 getter = MethodHandles.arrayElementGetter(short[].class);
293 short[] array = new short[1];
294 array[0] = 42;
295 short value = (short) getter.invoke(array, 0);
296 if (value != 42l) {
297 System.out.println("Unexpected value: " + value);
298 }
299 }
300
301 {
302 getter = MethodHandles.arrayElementGetter(char[].class);
303 char[] array = new char[1];
304 array[0] = 42;
305 char value = (char) getter.invoke(array, 0);
306 if (value != 42l) {
307 System.out.println("Unexpected value: " + value);
308 }
309 }
310
311 {
312 getter = MethodHandles.arrayElementGetter(byte[].class);
313 byte[] array = new byte[1];
314 array[0] = (byte) 0x8;
315 byte value = (byte) getter.invoke(array, 0);
316 if (value != (byte) 0x8) {
317 System.out.println("Unexpected value: " + value);
318 }
319 }
320
321 {
322 getter = MethodHandles.arrayElementGetter(boolean[].class);
323 boolean[] array = new boolean[1];
324 array[0] = true;
325 boolean value = (boolean) getter.invoke(array, 0);
326 if (!value) {
327 System.out.println("Unexpected value: " + value);
328 }
329 }
330
331 {
332 getter = MethodHandles.arrayElementGetter(float[].class);
333 float[] array = new float[1];
334 array[0] = 42.0f;
335 float value = (float) getter.invoke(array, 0);
336 if (value != 42.0f) {
337 System.out.println("Unexpected value: " + value);
338 }
339 }
340
341 {
342 getter = MethodHandles.arrayElementGetter(double[].class);
343 double[] array = new double[1];
344 array[0] = 42.0;
345 double value = (double) getter.invoke(array, 0);
346 if (value != 42.0) {
347 System.out.println("Unexpected value: " + value);
348 }
349 }
350
351 {
352 getter = MethodHandles.arrayElementGetter(String[].class);
353 String[] array = new String[3];
354 array[0] = "42";
355 array[1] = "48";
356 array[2] = "54";
357 String value = (String) getter.invoke(array, 0);
358 assertEquals("42", value);
359 value = (String) getter.invoke(array, 1);
360 assertEquals("48", value);
361 value = (String) getter.invoke(array, 2);
362 assertEquals("54", value);
363 }
364 }
365
366 public static void testArrayElementSetter() throws Throwable {
367 MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
368
369 {
370 int[] array = new int[2];
371 setter.invoke(array, 0, 42);
372 setter.invoke(array, 1, 43);
373
374 if (array[0] != 42) {
375 System.out.println("Unexpected value: " + array[0]);
376 }
377 if (array[1] != 43) {
378 System.out.println("Unexpected value: " + array[1]);
379 }
380
381 try {
382 setter.invoke(array, -1, 42);
383 fail();
384 } catch (ArrayIndexOutOfBoundsException expected) {
385 }
386
387 try {
388 setter.invoke(null, 0, 42);
389 fail();
390 } catch (NullPointerException expected) {
391 }
392 }
393
394 {
395 setter = MethodHandles.arrayElementSetter(long[].class);
396 long[] array = new long[1];
397 setter.invoke(array, 0, 42l);
398 if (array[0] != 42l) {
399 System.out.println("Unexpected value: " + array[0]);
400 }
401 }
402
403 {
404 setter = MethodHandles.arrayElementSetter(short[].class);
405 short[] array = new short[1];
406 setter.invoke(array, 0, (short) 42);
407 if (array[0] != 42l) {
408 System.out.println("Unexpected value: " + array[0]);
409 }
410 }
411
412 {
413 setter = MethodHandles.arrayElementSetter(char[].class);
414 char[] array = new char[1];
415 setter.invoke(array, 0, (char) 42);
416 if (array[0] != 42) {
417 System.out.println("Unexpected value: " + array[0]);
418 }
419 }
420
421 {
422 setter = MethodHandles.arrayElementSetter(byte[].class);
423 byte[] array = new byte[1];
424 setter.invoke(array, 0, (byte) 0x8);
425 if (array[0] != (byte) 0x8) {
426 System.out.println("Unexpected value: " + array[0]);
427 }
428 }
429
430 {
431 setter = MethodHandles.arrayElementSetter(boolean[].class);
432 boolean[] array = new boolean[1];
433 setter.invoke(array, 0, true);
434 if (!array[0]) {
435 System.out.println("Unexpected value: " + array[0]);
436 }
437 }
438
439 {
440 setter = MethodHandles.arrayElementSetter(float[].class);
441 float[] array = new float[1];
442 setter.invoke(array, 0, 42.0f);
443 if (array[0] != 42.0f) {
444 System.out.println("Unexpected value: " + array[0]);
445 }
446 }
447
448 {
449 setter = MethodHandles.arrayElementSetter(double[].class);
450 double[] array = new double[1];
451 setter.invoke(array, 0, 42.0);
452 if (array[0] != 42.0) {
453 System.out.println("Unexpected value: " + array[0]);
454 }
455 }
456
457 {
458 setter = MethodHandles.arrayElementSetter(String[].class);
459 String[] array = new String[3];
460 setter.invoke(array, 0, "42");
461 setter.invoke(array, 1, "48");
462 setter.invoke(array, 2, "54");
463 assertEquals("42", array[0]);
464 assertEquals("48", array[1]);
465 assertEquals("54", array[2]);
466 }
467 }
468
469 public static void testIdentity() throws Throwable {
470 {
471 MethodHandle identity = MethodHandles.identity(boolean.class);
472 boolean value = (boolean) identity.invoke(false);
473 if (value) {
474 System.out.println("Unexpected value: " + value);
475 }
476 }
477
478 {
479 MethodHandle identity = MethodHandles.identity(byte.class);
480 byte value = (byte) identity.invoke((byte) 0x8);
481 if (value != (byte) 0x8) {
482 System.out.println("Unexpected value: " + value);
483 }
484 }
485
486 {
487 MethodHandle identity = MethodHandles.identity(char.class);
488 char value = (char) identity.invoke((char) -56);
489 if (value != (char) -56) {
490 System.out.println("Unexpected value: " + value);
491 }
492 }
493
494 {
495 MethodHandle identity = MethodHandles.identity(short.class);
496 short value = (short) identity.invoke((short) -59);
497 if (value != (short) -59) {
498 System.out.println("Unexpected value: " + value);
499 }
500 }
501
502 {
503 MethodHandle identity = MethodHandles.identity(int.class);
504 int value = (int) identity.invoke(52);
505 if (value != 52) {
506 System.out.println("Unexpected value: " + value);
507 }
508 }
509
510 {
511 MethodHandle identity = MethodHandles.identity(long.class);
512 long value = (long) identity.invoke(-76l);
513 if (value != (long) -76) {
514 System.out.println("Unexpected value: " + value);
515 }
516 }
517
518 {
519 MethodHandle identity = MethodHandles.identity(float.class);
520 float value = (float) identity.invoke(56.0f);
521 if (value != (float) 56.0f) {
522 System.out.println("Unexpected value: " + value);
523 }
524 }
525
526 {
527 MethodHandle identity = MethodHandles.identity(double.class);
528 double value = (double) identity.invoke((double) 72.0);
529 if (value != (double) 72.0) {
530 System.out.println("Unexpected value: " + value);
531 }
532 }
533
534 {
535 MethodHandle identity = MethodHandles.identity(String.class);
536 String value = (String) identity.invoke("bazman");
537 assertEquals("bazman", value);
538 }
539 }
540
541 public static void testConstant() throws Throwable {
542 // int constants.
543 {
544 MethodHandle constant = MethodHandles.constant(int.class, 56);
545 int value = (int) constant.invoke();
546 if (value != 56) {
547 System.out.println("Unexpected value: " + value);
548 }
549
550 // short constant values are converted to int.
551 constant = MethodHandles.constant(int.class, (short) 52);
552 value = (int) constant.invoke();
553 if (value != 52) {
554 System.out.println("Unexpected value: " + value);
555 }
556
557 // char constant values are converted to int.
558 constant = MethodHandles.constant(int.class, (char) 'b');
559 value = (int) constant.invoke();
560 if (value != (int) 'b') {
561 System.out.println("Unexpected value: " + value);
562 }
563
564 // int constant values are converted to int.
565 constant = MethodHandles.constant(int.class, (byte) 0x1);
566 value = (int) constant.invoke();
567 if (value != 1) {
568 System.out.println("Unexpected value: " + value);
569 }
570
571 // boolean, float, double and long primitive constants are not convertible
572 // to int, so the handle creation must fail with a CCE.
573 try {
574 MethodHandles.constant(int.class, false);
575 fail();
576 } catch (ClassCastException expected) {
577 }
578
579 try {
580 MethodHandles.constant(int.class, 0.1f);
581 fail();
582 } catch (ClassCastException expected) {
583 }
584
585 try {
586 MethodHandles.constant(int.class, 0.2);
587 fail();
588 } catch (ClassCastException expected) {
589 }
590
591 try {
592 MethodHandles.constant(int.class, 73l);
593 fail();
594 } catch (ClassCastException expected) {
595 }
596 }
597
598 // long constants.
599 {
600 MethodHandle constant = MethodHandles.constant(long.class, 56l);
601 long value = (long) constant.invoke();
602 if (value != 56l) {
603 System.out.println("Unexpected value: " + value);
604 }
605
606 constant = MethodHandles.constant(long.class, (int) 56);
607 value = (long) constant.invoke();
608 if (value != 56l) {
609 System.out.println("Unexpected value: " + value);
610 }
611 }
612
613 // byte constants.
614 {
615 MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12);
616 byte value = (byte) constant.invoke();
617 if (value != (byte) 0x12) {
618 System.out.println("Unexpected value: " + value);
619 }
620 }
621
622 // boolean constants.
623 {
624 MethodHandle constant = MethodHandles.constant(boolean.class, true);
625 boolean value = (boolean) constant.invoke();
626 if (!value) {
627 System.out.println("Unexpected value: " + value);
628 }
629 }
630
631 // char constants.
632 {
633 MethodHandle constant = MethodHandles.constant(char.class, 'f');
634 char value = (char) constant.invoke();
635 if (value != 'f') {
636 System.out.println("Unexpected value: " + value);
637 }
638 }
639
640 // short constants.
641 {
642 MethodHandle constant = MethodHandles.constant(short.class, (short) 123);
643 short value = (short) constant.invoke();
644 if (value != (short) 123) {
645 System.out.println("Unexpected value: " + value);
646 }
647 }
648
649 // float constants.
650 {
651 MethodHandle constant = MethodHandles.constant(float.class, 56.0f);
652 float value = (float) constant.invoke();
653 if (value != 56.0f) {
654 System.out.println("Unexpected value: " + value);
655 }
656 }
657
658 // double constants.
659 {
660 MethodHandle constant = MethodHandles.constant(double.class, 256.0);
661 double value = (double) constant.invoke();
662 if (value != 256.0) {
663 System.out.println("Unexpected value: " + value);
664 }
665 }
666
667 // reference constants.
668 {
669 MethodHandle constant = MethodHandles.constant(String.class, "256.0");
670 String value = (String) constant.invoke();
671 assertEquals("256.0", value);
672 }
673 }
674
Narayan Kamath8677d0b2016-11-04 14:41:19 +0000675 public static void testBindTo() throws Throwable {
676 MethodHandle stringCharAt = MethodHandles.lookup().findVirtual(
677 String.class, "charAt", MethodType.methodType(char.class, int.class));
678
679 char value = (char) stringCharAt.invoke("foo", 0);
680 if (value != 'f') {
681 System.out.println("Unexpected value: " + value);
682 }
683
684 MethodHandle bound = stringCharAt.bindTo("foo");
685 value = (char) bound.invoke(0);
686 if (value != 'f') {
687 System.out.println("Unexpected value: " + value);
688 }
689
690 try {
691 stringCharAt.bindTo(new Object());
692 fail();
693 } catch (ClassCastException expected) {
694 }
695
696 bound = stringCharAt.bindTo(null);
697 try {
698 bound.invoke(0);
699 fail();
700 } catch (NullPointerException expected) {
701 }
702
703 MethodHandle integerParseInt = MethodHandles.lookup().findStatic(
704 Integer.class, "parseInt", MethodType.methodType(int.class, String.class));
705
706 bound = integerParseInt.bindTo("78452");
707 int intValue = (int) bound.invoke();
708 if (intValue != 78452) {
709 System.out.println("Unexpected value: " + intValue);
710 }
711 }
712
Narayan Kamath916a7712016-11-08 18:36:16 +0000713 public static String filterReturnValue_target(int a) {
714 return "ReturnValue" + a;
715 }
716
717 public static boolean filterReturnValue_filter(String value) {
718 return value.indexOf("42") != -1;
719 }
720
721 public static int filterReturnValue_intTarget(String a) {
722 return Integer.parseInt(a);
723 }
724
725 public static int filterReturnValue_intFilter(int b) {
726 return b + 1;
727 }
728
729 public static void filterReturnValue_voidTarget() {
730 }
731
732 public static int filterReturnValue_voidFilter() {
733 return 42;
734 }
735
736 public static void testFilterReturnValue() throws Throwable {
737 // A target that returns a reference.
738 {
739 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
740 "filterReturnValue_target", MethodType.methodType(String.class, int.class));
741 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
742 "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class));
743
744 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
745
746 boolean value = (boolean) adapter.invoke((int) 42);
747 if (!value) {
748 System.out.println("Unexpected value: " + value);
749 }
750 value = (boolean) adapter.invoke((int) 43);
751 if (value) {
752 System.out.println("Unexpected value: " + value);
753 }
754 }
755
756 // A target that returns a primitive.
757 {
758 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
759 "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class));
760 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
761 "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class));
762
763 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
764
765 int value = (int) adapter.invoke("56");
766 if (value != 57) {
767 System.out.println("Unexpected value: " + value);
768 }
769 }
770
771 // A target that returns void.
772 {
773 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
774 "filterReturnValue_voidTarget", MethodType.methodType(void.class));
775 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class,
776 "filterReturnValue_voidFilter", MethodType.methodType(int.class));
777
778 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
779
780 int value = (int) adapter.invoke();
781 if (value != 42) {
782 System.out.println("Unexpected value: " + value);
783 }
784 }
785 }
786
Narayan Kamath731f4c62016-11-08 19:38:48 +0000787 public static void permuteArguments_callee(boolean a, byte b, char c,
788 short d, int e, long f, float g, double h) {
789 if (a == true && b == (byte) 'b' && c == 'c' && d == (short) 56 &&
790 e == 78 && f == (long) 97 && g == 98.0f && f == 97.0) {
791 return;
792 }
793
794 System.out.println("Unexpected arguments: " + a + ", " + b + ", " + c
795 + ", " + d + ", " + e + ", " + f + ", " + g + ", " + h);
796 }
797
798 public static void permuteArguments_boxingCallee(boolean a, Integer b) {
799 if (a && b.intValue() == 42) {
800 return;
801 }
802
803 System.out.println("Unexpected arguments: " + a + ", " + b);
804 }
805
806 public static void testPermuteArguments() throws Throwable {
807 {
808 final MethodHandle target = MethodHandles.lookup().findStatic(
809 Main.class, "permuteArguments_callee",
810 MethodType.methodType(void.class, new Class<?>[] {
811 boolean.class, byte.class, char.class, short.class, int.class,
812 long.class, float.class, double.class }));
813
814 final MethodType newType = MethodType.methodType(void.class, new Class<?>[] {
815 double.class, float.class, long.class, int.class, short.class, char.class,
816 byte.class, boolean.class });
817
818 final MethodHandle permutation = MethodHandles.permuteArguments(
819 target, newType, new int[] { 7, 6, 5, 4, 3, 2, 1, 0 });
820
821 permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78,
822 (short) 56, 'c', (byte) 'b', (boolean) true);
823
824 // The permutation array was not of the right length.
825 try {
826 MethodHandles.permuteArguments(target, newType,
827 new int[] { 7 });
828 fail();
829 } catch (IllegalArgumentException expected) {
830 }
831
832 // The permutation array has an element that's out of bounds
833 // (there's no argument with idx == 8).
834 try {
835 MethodHandles.permuteArguments(target, newType,
836 new int[] { 8, 6, 5, 4, 3, 2, 1, 0 });
837 fail();
838 } catch (IllegalArgumentException expected) {
839 }
840
841 // The permutation array maps to an incorrect type.
842 try {
843 MethodHandles.permuteArguments(target, newType,
844 new int[] { 7, 7, 5, 4, 3, 2, 1, 0 });
845 fail();
846 } catch (IllegalArgumentException expected) {
847 }
848 }
849
850 // Tests for reference arguments as well as permutations that
851 // repeat arguments.
852 {
853 final MethodHandle target = MethodHandles.lookup().findVirtual(
854 String.class, "concat", MethodType.methodType(String.class, String.class));
855
856 final MethodType newType = MethodType.methodType(String.class, String.class,
857 String.class);
858
859 assertEquals("foobar", (String) target.invoke("foo", "bar"));
860
861 MethodHandle permutation = MethodHandles.permuteArguments(target,
862 newType, new int[] { 1, 0 });
863 assertEquals("barfoo", (String) permutation.invoke("foo", "bar"));
864
865 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 0, 0 });
866 assertEquals("foofoo", (String) permutation.invoke("foo", "bar"));
867
868 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 1, 1 });
869 assertEquals("barbar", (String) permutation.invoke("foo", "bar"));
870 }
871
872 // Tests for boxing and unboxing.
873 {
874 final MethodHandle target = MethodHandles.lookup().findStatic(
875 Main.class, "permuteArguments_boxingCallee",
876 MethodType.methodType(void.class, new Class<?>[] { boolean.class, Integer.class }));
877
878 final MethodType newType = MethodType.methodType(void.class,
879 new Class<?>[] { Integer.class, boolean.class });
880
881 MethodHandle permutation = MethodHandles.permuteArguments(target,
882 newType, new int[] { 1, 0 });
883
884 permutation.invoke(42, true);
885 permutation.invoke(42, Boolean.TRUE);
886 permutation.invoke(Integer.valueOf(42), true);
887 permutation.invoke(Integer.valueOf(42), Boolean.TRUE);
888 }
889 }
890
Narayan Kamath96120f42016-11-01 09:40:23 +0000891 public static void fail() {
892 System.out.println("FAIL");
893 Thread.dumpStack();
894 }
895
896 public static void assertEquals(String s1, String s2) {
897 if (s1 == s2) {
898 return;
899 }
900
901 if (s1 != null && s2 != null && s1.equals(s2)) {
902 return;
903 }
904
905 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
906 }
Narayan Kamath000e1882016-10-24 17:14:25 +0100907}