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