blob: f8daba6239e1553102b5870a409ed8a9c5321dc5 [file] [log] [blame]
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +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 Kamathe5eb5742016-11-02 14:16:27 +000022import java.lang.reflect.Constructor;
23import java.lang.reflect.Field;
24import java.lang.reflect.Method;
Orion Hodson1c878782016-11-25 15:46:49 +000025import java.nio.charset.Charset;
26import java.nio.charset.StandardCharsets;
27import java.util.ArrayList;
Orion Hodson8797fdf2016-11-16 13:43:26 +000028import java.util.Arrays;
Orion Hodson1c878782016-11-25 15:46:49 +000029import java.util.List;
Narayan Kamathe5eb5742016-11-02 14:16:27 +000030
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010031public class Main {
32
33 public static class A {
Orion Hodson8797fdf2016-11-16 13:43:26 +000034 public A() {}
35
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010036 public void foo() {
37 System.out.println("foo_A");
38 }
39
40 public static final Lookup lookup = MethodHandles.lookup();
41 }
42
43 public static class B extends A {
44 public void foo() {
45 System.out.println("foo_B");
46 }
47
48 public static final Lookup lookup = MethodHandles.lookup();
49 }
50
51 public static class C extends B {
52 public static final Lookup lookup = MethodHandles.lookup();
53 }
54
55 public static class D {
56 private final void privateRyan() {
57 System.out.println("privateRyan_D");
58 }
59
60 public static final Lookup lookup = MethodHandles.lookup();
61 }
62
63 public static class E extends D {
64 public static final Lookup lookup = MethodHandles.lookup();
65 }
66
67 public static void main(String[] args) throws Throwable {
68 testfindSpecial_invokeSuperBehaviour();
69 testfindSpecial_invokeDirectBehaviour();
Narayan Kamath3e0dce02016-10-31 13:55:55 +000070 testExceptionDetailMessages();
Narayan Kamath94bee022016-11-01 10:57:15 +000071 testfindVirtual();
Orion Hodson8797fdf2016-11-16 13:43:26 +000072 testfindStatic();
Narayan Kamathe5eb5742016-11-02 14:16:27 +000073 testUnreflects();
Narayan Kamath0a8485e2016-11-02 18:47:11 +000074 testAsType();
Orion Hodson0d781e62016-11-04 11:09:53 +000075 testConstructors();
76 testStringConstructors();
Orion Hodson1a06f9f2016-11-09 08:32:42 +000077 testReturnValueConversions();
Orion Hodson1c878782016-11-25 15:46:49 +000078 testVariableArity();
Narayan Kamathec08c062017-01-16 14:56:19 +000079 testVariableArity_MethodHandles_bind();
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010080 }
81
82 public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
83 // This is equivalent to an invoke-super instruction where the referrer
84 // is B.class.
85 MethodHandle mh1 = B.lookup.findSpecial(A.class /* refC */, "foo",
86 MethodType.methodType(void.class), B.class /* specialCaller */);
87
88 A aInstance = new A();
89 B bInstance = new B();
90 C cInstance = new C();
91
92 // This should be as if an invoke-super was called from one of B's methods.
93 mh1.invokeExact(bInstance);
94 mh1.invoke(bInstance);
95
96 // This should not work. The receiver type in the handle will be suitably
97 // restricted to B and subclasses.
98 try {
99 mh1.invoke(aInstance);
100 System.out.println("mh1.invoke(aInstance) should not succeeed");
101 } catch (ClassCastException expected) {
102 }
103
104 try {
105 mh1.invokeExact(aInstance);
106 System.out.println("mh1.invoke(aInstance) should not succeeed");
107 } catch (WrongMethodTypeException expected) {
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +0100108 }
109
110 // This should *still* be as if an invoke-super was called from one of C's
111 // methods, despite the fact that we're operating on a C.
112 mh1.invoke(cInstance);
113
114 // Now that C is the special caller, the next invoke will call B.foo.
115 MethodHandle mh2 = C.lookup.findSpecial(A.class /* refC */, "foo",
116 MethodType.methodType(void.class), C.class /* specialCaller */);
117 mh2.invokeExact(cInstance);
118
119 // Shouldn't allow invoke-super semantics from an unrelated special caller.
120 try {
121 C.lookup.findSpecial(A.class, "foo",
122 MethodType.methodType(void.class), D.class /* specialCaller */);
123 System.out.println("findSpecial(A.class, foo, .. D.class) unexpectedly succeeded.");
124 } catch (IllegalAccessException expected) {
125 }
Orion Hodson8797fdf2016-11-16 13:43:26 +0000126
127 // Check return type matches for find.
128 try {
129 B.lookup.findSpecial(A.class /* refC */, "foo",
130 MethodType.methodType(int.class), B.class /* specialCaller */);
131 fail();
132 } catch (NoSuchMethodException e) {}
133 // Check constructors
134 try {
135 B.lookup.findSpecial(A.class /* refC */, "<init>",
136 MethodType.methodType(void.class), B.class /* specialCaller */);
137 fail();
138 } catch (NoSuchMethodException e) {}
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +0100139 }
140
141 public static void testfindSpecial_invokeDirectBehaviour() throws Throwable {
142 D dInstance = new D();
143
144 MethodHandle mh3 = D.lookup.findSpecial(D.class, "privateRyan",
145 MethodType.methodType(void.class), D.class /* specialCaller */);
146 mh3.invoke(dInstance);
147
148 // The private method shouldn't be accessible from any special caller except
149 // itself...
150 try {
151 D.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), C.class);
152 System.out.println("findSpecial(privateRyan, C.class) unexpectedly succeeded");
153 } catch (IllegalAccessException expected) {
154 }
155
156 // ... or from any lookup context except its own.
157 try {
158 E.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), E.class);
159 System.out.println("findSpecial(privateRyan, E.class) unexpectedly succeeded");
160 } catch (IllegalAccessException expected) {
161 }
162 }
Narayan Kamath3e0dce02016-10-31 13:55:55 +0000163
164 public static void testExceptionDetailMessages() throws Throwable {
165 MethodHandle handle = MethodHandles.lookup().findVirtual(String.class, "concat",
166 MethodType.methodType(String.class, String.class));
167
168 try {
169 handle.invokeExact("a", new Object());
170 System.out.println("invokeExact(\"a\", new Object()) unexpectedly succeeded.");
171 } catch (WrongMethodTypeException ex) {
172 System.out.println("Received exception: " + ex.getMessage());
173 }
174 }
Narayan Kamath94bee022016-11-01 10:57:15 +0000175
176 public interface Foo {
177 public String foo();
178 }
179
180 public interface Bar extends Foo {
181 public String bar();
182 }
183
184 public static class BarSuper {
185 public String superPublicMethod() {
186 return "superPublicMethod";
187 }
188
189 public String superProtectedMethod() {
190 return "superProtectedMethod";
191 }
192
193 String superPackageMethod() {
194 return "superPackageMethod";
195 }
196 }
197
198 public static class BarImpl extends BarSuper implements Bar {
199 public BarImpl() {
200 }
201
202 @Override
203 public String foo() {
204 return "foo";
205 }
206
207 @Override
208 public String bar() {
209 return "bar";
210 }
211
Orion Hodson8797fdf2016-11-16 13:43:26 +0000212 public String add(int x, int y) {
213 return Arrays.toString(new int[] { x, y });
214 }
215
Narayan Kamath94bee022016-11-01 10:57:15 +0000216 private String privateMethod() { return "privateMethod"; }
217
Orion Hodson8797fdf2016-11-16 13:43:26 +0000218 public static String staticMethod() { return staticString; }
219
220 private static String staticString;
221
222 {
223 // Static constructor
224 staticString = Long.toString(System.currentTimeMillis());
225 }
Narayan Kamath94bee022016-11-01 10:57:15 +0000226
227 static final MethodHandles.Lookup lookup = MethodHandles.lookup();
228 }
229
230 public static void testfindVirtual() throws Throwable {
231 // Virtual lookups on static methods should not succeed.
232 try {
233 MethodHandles.lookup().findVirtual(
234 BarImpl.class, "staticMethod", MethodType.methodType(String.class));
235 System.out.println("findVirtual(staticMethod) unexpectedly succeeded");
236 } catch (IllegalAccessException expected) {
237 }
238
239 // Virtual lookups on private methods should not succeed, unless the Lookup
240 // context had sufficient privileges.
241 try {
242 MethodHandles.lookup().findVirtual(
243 BarImpl.class, "privateMethod", MethodType.methodType(String.class));
244 System.out.println("findVirtual(privateMethod) unexpectedly succeeded");
245 } catch (IllegalAccessException expected) {
246 }
247
248 // Virtual lookup on a private method with a context that *does* have sufficient
249 // privileges.
250 MethodHandle mh = BarImpl.lookup.findVirtual(
251 BarImpl.class, "privateMethod", MethodType.methodType(String.class));
252 String str = (String) mh.invoke(new BarImpl());
253 if (!"privateMethod".equals(str)) {
254 System.out.println("Unexpected return value for BarImpl#privateMethod: " + str);
255 }
256
257 // Find virtual must find interface methods defined by interfaces implemented
258 // by the class.
259 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo",
260 MethodType.methodType(String.class));
261 str = (String) mh.invoke(new BarImpl());
262 if (!"foo".equals(str)) {
263 System.out.println("Unexpected return value for BarImpl#foo: " + str);
264 }
265
Orion Hodson8797fdf2016-11-16 13:43:26 +0000266 // Find virtual should check rtype.
267 try {
268 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo",
269 MethodType.methodType(void.class));
270 fail();
271 } catch (NoSuchMethodException e) {}
272
273 // And ptypes
274 mh = MethodHandles.lookup().findVirtual(
275 BarImpl.class, "add", MethodType.methodType(String.class, int.class, int.class));
276 try {
277 mh = MethodHandles.lookup().findVirtual(
278 BarImpl.class, "add", MethodType.methodType(String.class, Integer.class, int.class));
279 } catch (NoSuchMethodException e) {}
280
Narayan Kamath94bee022016-11-01 10:57:15 +0000281 // .. and their super-interfaces.
282 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "bar",
283 MethodType.methodType(String.class));
284 str = (String) mh.invoke(new BarImpl());
285 if (!"bar".equals(str)) {
286 System.out.println("Unexpected return value for BarImpl#bar: " + str);
287 }
288
289 // TODO(narayan): Fix this case, we're using the wrong ArtMethod for the
290 // invoke resulting in a failing check in the interpreter.
291 //
292 // mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
293 // MethodType.methodType(String.class));
294 // str = (String) mh.invoke(new BarImpl());
295 // if (!"bar".equals(str)) {
296 // System.out.println("Unexpected return value for BarImpl#bar: " + str);
297 // }
298
299 // We should also be able to lookup public / protected / package methods in
300 // the super class, given sufficient access privileges.
301 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPublicMethod",
302 MethodType.methodType(String.class));
303 str = (String) mh.invoke(new BarImpl());
304 if (!"superPublicMethod".equals(str)) {
305 System.out.println("Unexpected return value for BarImpl#superPublicMethod: " + str);
306 }
307
308 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superProtectedMethod",
309 MethodType.methodType(String.class));
310 str = (String) mh.invoke(new BarImpl());
311 if (!"superProtectedMethod".equals(str)) {
312 System.out.println("Unexpected return value for BarImpl#superProtectedMethod: " + str);
313 }
314
315 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPackageMethod",
316 MethodType.methodType(String.class));
317 str = (String) mh.invoke(new BarImpl());
318 if (!"superPackageMethod".equals(str)) {
319 System.out.println("Unexpected return value for BarImpl#superPackageMethod: " + str);
320 }
Orion Hodson8797fdf2016-11-16 13:43:26 +0000321
322 try {
323 MethodHandles.lookup().findVirtual(BarImpl.class, "<init>",
324 MethodType.methodType(void.class));
325 fail();
326 } catch (NoSuchMethodException e) {}
327 }
328
329 public static void testfindStatic() throws Throwable {
330 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
331 MethodType.methodType(String.class));
332 try {
333 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
334 MethodType.methodType(void.class));
335 fail();
336 } catch (NoSuchMethodException e) {}
337 try {
338 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod",
339 MethodType.methodType(String.class, int.class));
340 fail();
341 } catch (NoSuchMethodException e) {}
342 try {
343 MethodHandles.lookup().findStatic(BarImpl.class, "<clinit>",
344 MethodType.methodType(void.class));
345 fail();
346 } catch (NoSuchMethodException e) {}
347 try {
348 MethodHandles.lookup().findStatic(BarImpl.class, "<init>",
349 MethodType.methodType(void.class));
350 fail();
351 } catch (NoSuchMethodException e) {}
Narayan Kamath94bee022016-11-01 10:57:15 +0000352 }
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000353
354 static class UnreflectTester {
355 public String publicField;
356 private String privateField;
357
358 public static String publicStaticField = "publicStaticValue";
359 private static String privateStaticField = "privateStaticValue";
360
361 private UnreflectTester(String val) {
362 publicField = val;
363 privateField = val;
364 }
365
366 // NOTE: The boolean constructor argument only exists to give this a
367 // different signature.
368 public UnreflectTester(String val, boolean unused) {
369 this(val);
370 }
371
372 private static String privateStaticMethod() {
373 return "privateStaticMethod";
374 }
375
376 private String privateMethod() {
377 return "privateMethod";
378 }
379
380 public static String publicStaticMethod() {
381 return "publicStaticMethod";
382 }
383
384 public String publicMethod() {
385 return "publicMethod";
386 }
387 }
388
389 public static void testUnreflects() throws Throwable {
390 UnreflectTester instance = new UnreflectTester("unused");
391 Method publicMethod = UnreflectTester.class.getMethod("publicMethod");
392
393 MethodHandle mh = MethodHandles.lookup().unreflect(publicMethod);
394 assertEquals("publicMethod", (String) mh.invoke(instance));
395 assertEquals("publicMethod", (String) mh.invokeExact(instance));
396
397 Method publicStaticMethod = UnreflectTester.class.getMethod("publicStaticMethod");
398 mh = MethodHandles.lookup().unreflect(publicStaticMethod);
399 assertEquals("publicStaticMethod", (String) mh.invoke());
400 assertEquals("publicStaticMethod", (String) mh.invokeExact());
401
402 Method privateMethod = UnreflectTester.class.getDeclaredMethod("privateMethod");
403 try {
404 mh = MethodHandles.lookup().unreflect(privateMethod);
405 fail();
406 } catch (IllegalAccessException expected) {}
407
408 privateMethod.setAccessible(true);
409 mh = MethodHandles.lookup().unreflect(privateMethod);
410 assertEquals("privateMethod", (String) mh.invoke(instance));
411 assertEquals("privateMethod", (String) mh.invokeExact(instance));
412
413 Method privateStaticMethod = UnreflectTester.class.getDeclaredMethod("privateStaticMethod");
414 try {
415 mh = MethodHandles.lookup().unreflect(privateStaticMethod);
416 fail();
417 } catch (IllegalAccessException expected) {}
418
419 privateStaticMethod.setAccessible(true);
420 mh = MethodHandles.lookup().unreflect(privateStaticMethod);
421 assertEquals("privateStaticMethod", (String) mh.invoke());
422 assertEquals("privateStaticMethod", (String) mh.invokeExact());
423
424 Constructor privateConstructor = UnreflectTester.class.getDeclaredConstructor(String.class);
425 try {
426 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor);
427 fail();
428 } catch (IllegalAccessException expected) {}
429
430 privateConstructor.setAccessible(true);
431 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor);
Orion Hodson0d781e62016-11-04 11:09:53 +0000432 instance = (UnreflectTester) mh.invokeExact("abc");
433 assertEquals("abc", instance.publicField);
434 instance = (UnreflectTester) mh.invoke("def");
435 assertEquals("def", instance.publicField);
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000436 Constructor publicConstructor = UnreflectTester.class.getConstructor(String.class,
437 boolean.class);
438 mh = MethodHandles.lookup().unreflectConstructor(publicConstructor);
Orion Hodson0d781e62016-11-04 11:09:53 +0000439 instance = (UnreflectTester) mh.invokeExact("abc", false);
440 assertEquals("abc", instance.publicField);
441 instance = (UnreflectTester) mh.invoke("def", true);
442 assertEquals("def", instance.publicField);
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000443
444 // TODO(narayan): Non exact invokes for field sets/gets are not implemented yet.
445 //
446 // assertEquals("instanceValue", (String) mh.invoke(new UnreflectTester("instanceValue")));
447 Field publicField = UnreflectTester.class.getField("publicField");
448 mh = MethodHandles.lookup().unreflectGetter(publicField);
449 instance = new UnreflectTester("instanceValue");
450 assertEquals("instanceValue", (String) mh.invokeExact(instance));
451
452 mh = MethodHandles.lookup().unreflectSetter(publicField);
453 instance = new UnreflectTester("instanceValue");
454 mh.invokeExact(instance, "updatedInstanceValue");
455 assertEquals("updatedInstanceValue", instance.publicField);
456
457 Field publicStaticField = UnreflectTester.class.getField("publicStaticField");
458 mh = MethodHandles.lookup().unreflectGetter(publicStaticField);
459 UnreflectTester.publicStaticField = "updatedStaticValue";
460 assertEquals("updatedStaticValue", (String) mh.invokeExact());
461
462 mh = MethodHandles.lookup().unreflectSetter(publicStaticField);
463 UnreflectTester.publicStaticField = "updatedStaticValue";
464 mh.invokeExact("updatedStaticValue2");
465 assertEquals("updatedStaticValue2", UnreflectTester.publicStaticField);
466
467 Field privateField = UnreflectTester.class.getDeclaredField("privateField");
468 try {
469 mh = MethodHandles.lookup().unreflectGetter(privateField);
470 fail();
471 } catch (IllegalAccessException expected) {
472 }
473 try {
474 mh = MethodHandles.lookup().unreflectSetter(privateField);
475 fail();
476 } catch (IllegalAccessException expected) {
477 }
478
479 privateField.setAccessible(true);
480
481 mh = MethodHandles.lookup().unreflectGetter(privateField);
482 instance = new UnreflectTester("instanceValue");
483 assertEquals("instanceValue", (String) mh.invokeExact(instance));
484
485 mh = MethodHandles.lookup().unreflectSetter(privateField);
486 instance = new UnreflectTester("instanceValue");
487 mh.invokeExact(instance, "updatedInstanceValue");
488 assertEquals("updatedInstanceValue", instance.privateField);
489
490 Field privateStaticField = UnreflectTester.class.getDeclaredField("privateStaticField");
491 try {
492 mh = MethodHandles.lookup().unreflectGetter(privateStaticField);
493 fail();
494 } catch (IllegalAccessException expected) {
495 }
496 try {
497 mh = MethodHandles.lookup().unreflectSetter(privateStaticField);
498 fail();
499 } catch (IllegalAccessException expected) {
500 }
501
502 privateStaticField.setAccessible(true);
503 mh = MethodHandles.lookup().unreflectGetter(privateStaticField);
504 privateStaticField.set(null, "updatedStaticValue");
505 assertEquals("updatedStaticValue", (String) mh.invokeExact());
506
507 mh = MethodHandles.lookup().unreflectSetter(privateStaticField);
508 privateStaticField.set(null, "updatedStaticValue");
509 mh.invokeExact("updatedStaticValue2");
510 assertEquals("updatedStaticValue2", (String) privateStaticField.get(null));
511 }
512
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000513 // This method only exists to fool Jack's handling of types. See b/32536744.
514 public static CharSequence getSequence() {
515 return "foo";
516 }
517
518 public static void testAsType() throws Throwable {
519 // The type of this handle is (String, String)String.
520 MethodHandle mh = MethodHandles.lookup().findVirtual(String.class,
521 "concat", MethodType.methodType(String.class, String.class));
522
523 // Change it to (CharSequence, String)Object.
524 MethodHandle asType = mh.asType(
525 MethodType.methodType(Object.class, CharSequence.class, String.class));
526
527 Object obj = asType.invokeExact((CharSequence) getSequence(), "bar");
528 assertEquals("foobar", (String) obj);
529
530 // Should fail due to a wrong return type.
531 try {
532 String str = (String) asType.invokeExact((CharSequence) getSequence(), "bar");
533 fail();
534 } catch (WrongMethodTypeException expected) {
535 }
536
537 // Should fail due to a wrong argument type (String instead of Charsequence).
538 try {
539 String str = (String) asType.invokeExact("baz", "bar");
540 fail();
541 } catch (WrongMethodTypeException expected) {
542 }
543
544 // Calls to asType should fail if the types are not convertible.
545 //
546 // Bad return type conversion.
547 try {
548 mh.asType(MethodType.methodType(int.class, String.class, String.class));
549 fail();
550 } catch (WrongMethodTypeException expected) {
551 }
552
553 // Bad argument conversion.
554 try {
555 mh.asType(MethodType.methodType(String.class, int.class, String.class));
556 fail();
557 } catch (WrongMethodTypeException expected) {
558 }
559 }
560
Orion Hodson1c878782016-11-25 15:46:49 +0000561 public static void assertTrue(boolean value) {
562 if (!value) {
563 throw new AssertionError("assertTrue value: " + value);
564 }
565 }
566
567 public static void assertFalse(boolean value) {
568 if (value) {
569 throw new AssertionError("assertTrue value: " + value);
570 }
571 }
572
573 public static void assertEquals(int i1, int i2) {
574 if (i1 == i2) { return; }
575 throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2);
576 }
577
578 public static void assertEquals(long i1, long i2) {
579 if (i1 == i2) { return; }
580 throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2);
581 }
582
583 public static void assertEquals(Object o, Object p) {
584 if (o == p) { return; }
585 if (o != null && p != null && o.equals(p)) { return; }
586 throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
587 }
588
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000589 public static void assertEquals(String s1, String s2) {
590 if (s1 == s2) {
591 return;
592 }
593
594 if (s1 != null && s2 != null && s1.equals(s2)) {
595 return;
596 }
597
598 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
599 }
600
601 public static void fail() {
602 System.out.println("fail");
603 Thread.dumpStack();
604 }
Orion Hodson0d781e62016-11-04 11:09:53 +0000605
606 public static void fail(String message) {
607 System.out.println("fail: " + message);
608 Thread.dumpStack();
609 }
610
611 public static void testConstructors() throws Throwable {
612 MethodHandle mh =
613 MethodHandles.lookup().findConstructor(Float.class,
614 MethodType.methodType(void.class,
615 float.class));
616 Float value = (Float) mh.invokeExact(0.33f);
617 if (value.floatValue() != 0.33f) {
618 fail("Unexpected float value from invokeExact " + value.floatValue());
619 }
620
621 value = (Float) mh.invoke(3.34f);
622 if (value.floatValue() != 3.34f) {
623 fail("Unexpected float value from invoke " + value.floatValue());
624 }
625
626 mh = MethodHandles.lookup().findConstructor(Double.class,
627 MethodType.methodType(void.class, String.class));
628 Double d = (Double) mh.invoke("8.45e3");
629 if (d.doubleValue() != 8.45e3) {
630 fail("Unexpected double value from Double(String) " + value.doubleValue());
631 }
632
633 mh = MethodHandles.lookup().findConstructor(Double.class,
634 MethodType.methodType(void.class, double.class));
635 d = (Double) mh.invoke(8.45e3);
636 if (d.doubleValue() != 8.45e3) {
637 fail("Unexpected double value from Double(double) " + value.doubleValue());
638 }
639
640 // Primitive type
641 try {
642 mh = MethodHandles.lookup().findConstructor(int.class, MethodType.methodType(void.class));
643 fail("Unexpected lookup success for primitive constructor");
644 } catch (NoSuchMethodException e) {}
645
646 // Interface
647 try {
648 mh = MethodHandles.lookup().findConstructor(Readable.class,
649 MethodType.methodType(void.class));
650 fail("Unexpected lookup success for interface constructor");
651 } catch (NoSuchMethodException e) {}
652
653 // Abstract
654 mh = MethodHandles.lookup().findConstructor(Process.class, MethodType.methodType(void.class));
655 try {
656 mh.invoke();
657 fail("Unexpected ability to instantiate an abstract class");
658 } catch (InstantiationException e) {}
659
660 // Non-existent
661 try {
662 MethodHandle bad = MethodHandles.lookup().findConstructor(
663 String.class, MethodType.methodType(String.class, Float.class));
664 fail("Unexpected success for non-existent constructor");
665 } catch (NoSuchMethodException e) {}
666
667 // Non-void constructor search. (I)I instead of (I)V.
668 try {
669 MethodHandle foo = MethodHandles.lookup().findConstructor(
670 Integer.class, MethodType.methodType(Integer.class, Integer.class));
671 fail("Unexpected success for non-void type for findConstructor");
672 } catch (NoSuchMethodException e) {}
673 }
674
675 public static void testStringConstructors() throws Throwable {
676 final String testPattern = "The system as we know it is broken";
677
678 // String()
679 MethodHandle mh = MethodHandles.lookup().findConstructor(
680 String.class, MethodType.methodType(void.class));
681 String s = (String) mh.invokeExact();
682 if (!s.equals("")) {
683 fail("Unexpected empty string constructor result: '" + s + "'");
684 }
685
686 // String(String)
687 mh = MethodHandles.lookup().findConstructor(
688 String.class, MethodType.methodType(void.class, String.class));
689 s = (String) mh.invokeExact(testPattern);
690 if (!s.equals(testPattern)) {
691 fail("Unexpected string constructor result: '" + s + "'");
692 }
693
694 // String(char[])
695 mh = MethodHandles.lookup().findConstructor(
696 String.class, MethodType.methodType(void.class, char[].class));
697 s = (String) mh.invokeExact(testPattern.toCharArray());
698 if (!s.equals(testPattern)) {
699 fail("Unexpected string constructor result: '" + s + "'");
700 }
701
702 // String(char[], int, int)
703 mh = MethodHandles.lookup().findConstructor(
704 String.class, MethodType.methodType(void.class, char[].class, int.class, int.class));
705 s = (String) mh.invokeExact(new char [] { 'a', 'b', 'c', 'd', 'e'}, 2, 3);
706 if (!s.equals("cde")) {
707 fail("Unexpected string constructor result: '" + s + "'");
708 }
709
710 // String(int[] codePoints, int offset, int count)
711 StringBuffer sb = new StringBuffer(testPattern);
712 int[] codePoints = new int[sb.codePointCount(0, sb.length())];
713 for (int i = 0; i < sb.length(); ++i) {
714 codePoints[i] = sb.codePointAt(i);
715 }
716 mh = MethodHandles.lookup().findConstructor(
717 String.class, MethodType.methodType(void.class, int[].class, int.class, int.class));
718 s = (String) mh.invokeExact(codePoints, 0, codePoints.length);
719 if (!s.equals(testPattern)) {
720 fail("Unexpected string constructor result: '" + s + "'");
721 }
722
723 // String(byte ascii[], int hibyte, int offset, int count)
724 byte [] ascii = testPattern.getBytes(StandardCharsets.US_ASCII);
725 mh = MethodHandles.lookup().findConstructor(
726 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class));
727 s = (String) mh.invokeExact(ascii, 0, ascii.length);
728 if (!s.equals(testPattern)) {
729 fail("Unexpected string constructor result: '" + s + "'");
730 }
731
732 // String(byte bytes[], int offset, int length, String charsetName)
733 mh = MethodHandles.lookup().findConstructor(
734 String.class,
735 MethodType.methodType(void.class, byte[].class, int.class, int.class, String.class));
736 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII.name());
737 if (!s.equals(testPattern.substring(0, 5))) {
738 fail("Unexpected string constructor result: '" + s + "'");
739 }
740
741 // String(byte bytes[], int offset, int length, Charset charset)
742 mh = MethodHandles.lookup().findConstructor(
743 String.class,
744 MethodType.methodType(void.class, byte[].class, int.class, int.class, Charset.class));
745 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII);
746 if (!s.equals(testPattern.substring(0, 5))) {
747 fail("Unexpected string constructor result: '" + s + "'");
748 }
749
750 // String(byte bytes[], String charsetName)
751 mh = MethodHandles.lookup().findConstructor(
752 String.class,
753 MethodType.methodType(void.class, byte[].class, String.class));
754 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII.name());
755 if (!s.equals(testPattern)) {
756 fail("Unexpected string constructor result: '" + s + "'");
757 }
758
759 // String(byte bytes[], Charset charset)
760 mh = MethodHandles.lookup().findConstructor(
761 String.class, MethodType.methodType(void.class, byte[].class, Charset.class));
762 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII);
763 if (!s.equals(testPattern)) {
764 fail("Unexpected string constructor result: '" + s + "'");
765 }
766
767 // String(byte bytes[], int offset, int length)
768 mh = MethodHandles.lookup().findConstructor(
769 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class));
770 s = (String) mh.invokeExact(ascii, 1, ascii.length - 2);
771 s = testPattern.charAt(0) + s + testPattern.charAt(testPattern.length() - 1);
772 if (!s.equals(testPattern)) {
773 fail("Unexpected string constructor result: '" + s + "'");
774 }
775
776 // String(byte bytes[])
777 mh = MethodHandles.lookup().findConstructor(
778 String.class, MethodType.methodType(void.class, byte[].class));
779 s = (String) mh.invokeExact(ascii);
780 if (!s.equals(testPattern)) {
781 fail("Unexpected string constructor result: '" + s + "'");
782 }
783
784 // String(StringBuffer buffer)
785 mh = MethodHandles.lookup().findConstructor(
786 String.class, MethodType.methodType(void.class, StringBuffer.class));
787 s = (String) mh.invokeExact(sb);
788 if (!s.equals(testPattern)) {
789 fail("Unexpected string constructor result: '" + s + "'");
790 }
791
792 System.out.println("String constructors done.");
793 }
Orion Hodson1a06f9f2016-11-09 08:32:42 +0000794
795 private static void testReferenceReturnValueConversions() throws Throwable {
796 MethodHandle mh = MethodHandles.lookup().findStatic(
797 Float.class, "valueOf", MethodType.methodType(Float.class, String.class));
798
799 // No conversion
800 Float f = (Float) mh.invokeExact("1.375");
801 if (f.floatValue() != 1.375) {
802 fail();
803 }
804 f = (Float) mh.invoke("1.875");
805 if (f.floatValue() != 1.875) {
806 fail();
807 }
808
809 // Bad conversion
810 try {
811 int i = (int) mh.invokeExact("7.77");
812 fail();
813 } catch (WrongMethodTypeException e) {}
814
815 try {
816 int i = (int) mh.invoke("7.77");
817 fail();
818 } catch (WrongMethodTypeException e) {}
819
820 // Assignment to super-class.
821 Number n = (Number) mh.invoke("1.11");
822 try {
823 Number o = (Number) mh.invokeExact("1.11");
824 fail();
825 } catch (WrongMethodTypeException e) {}
826
827 // Assignment to widened boxed primitive class.
828 try {
829 Double u = (Double) mh.invoke("1.11");
830 fail();
831 } catch (ClassCastException e) {}
832
833 try {
834 Double v = (Double) mh.invokeExact("1.11");
835 fail();
836 } catch (WrongMethodTypeException e) {}
837
838 // Unboxed
839 float p = (float) mh.invoke("1.11");
840 if (p != 1.11f) {
841 fail();
842 }
843
844 // Unboxed and widened
845 double d = (double) mh.invoke("2.5");
846 if (d != 2.5) {
847 fail();
848 }
849
850 // Interface
851 Comparable<Float> c = (Comparable<Float>) mh.invoke("2.125");
852 if (c.compareTo(new Float(2.125f)) != 0) {
853 fail();
854 }
855
856 System.out.println("testReferenceReturnValueConversions done.");
857 }
858
859 private static void testPrimitiveReturnValueConversions() throws Throwable {
860 MethodHandle mh = MethodHandles.lookup().findStatic(
861 Math.class, "min", MethodType.methodType(int.class, int.class, int.class));
862
863 final int SMALL = -8972;
864 final int LARGE = 7932529;
865
866 // No conversion
867 if ((int) mh.invokeExact(LARGE, SMALL) != SMALL) {
868 fail();
869 } else if ((int) mh.invoke(LARGE, SMALL) != SMALL) {
870 fail();
871 } else if ((int) mh.invokeExact(SMALL, LARGE) != SMALL) {
872 fail();
873 } else if ((int) mh.invoke(SMALL, LARGE) != SMALL) {
874 fail();
875 }
876
877 // int -> long
878 try {
879 if ((long) mh.invokeExact(LARGE, SMALL) != (long) SMALL) {}
880 fail();
881 } catch (WrongMethodTypeException e) {}
882
883 if ((long) mh.invoke(LARGE, SMALL) != (long) SMALL) {
884 fail();
885 }
886
887 // int -> short
888 try {
889 if ((short) mh.invokeExact(LARGE, SMALL) != (short) SMALL) {}
890 fail();
891 } catch (WrongMethodTypeException e) {}
892
893 try {
894 if ((short) mh.invoke(LARGE, SMALL) != (short) SMALL) {
895 fail();
896 }
897 } catch (WrongMethodTypeException e) {}
898
899 // int -> Integer
900 try {
901 if (!((Integer) mh.invokeExact(LARGE, SMALL)).equals(new Integer(SMALL))) {}
902 fail();
903 } catch (WrongMethodTypeException e) {}
904
905 if (!((Integer) mh.invoke(LARGE, SMALL)).equals(new Integer(SMALL))) {
906 fail();
907 }
908
909 // int -> Long
910 try {
911 Long l = (Long) mh.invokeExact(LARGE, SMALL);
912 fail();
913 } catch (WrongMethodTypeException e) {}
914
915 try {
916 Long l = (Long) mh.invoke(LARGE, SMALL);
917 fail();
918 } catch (WrongMethodTypeException e) {}
919
920 // int -> Short
921 try {
922 Short s = (Short) mh.invokeExact(LARGE, SMALL);
923 fail();
924 } catch (WrongMethodTypeException e) {}
925
926 try {
927 Short s = (Short) mh.invoke(LARGE, SMALL);
928 fail();
929 } catch (WrongMethodTypeException e) {}
930
931 // int -> Process
932 try {
933 Process p = (Process) mh.invokeExact(LARGE, SMALL);
934 fail();
935 } catch (WrongMethodTypeException e) {}
936
937 try {
938 Process p = (Process) mh.invoke(LARGE, SMALL);
939 fail();
940 } catch (WrongMethodTypeException e) {}
941
942 // void -> Object
943 mh = MethodHandles.lookup().findStatic(System.class, "gc", MethodType.methodType(void.class));
944 Object o = (Object) mh.invoke();
945 if (o != null) fail();
946
947 // void -> long
948 long l = (long) mh.invoke();
949 if (l != 0) fail();
950
Orion Hodsonf1412b42016-11-11 12:03:29 +0000951 // boolean -> Boolean
952 mh = MethodHandles.lookup().findStatic(Boolean.class, "parseBoolean",
953 MethodType.methodType(boolean.class, String.class));
954 Boolean z = (Boolean) mh.invoke("True");
955 if (!z.booleanValue()) fail();
956
957 // boolean -> int
958 try {
959 int dummy = (int) mh.invoke("True");
960 fail();
961 } catch (WrongMethodTypeException e) {}
962
963 // boolean -> Integer
964 try {
965 Integer dummy = (Integer) mh.invoke("True");
966 fail();
967 } catch (WrongMethodTypeException e) {}
968
969 // Boolean -> boolean
970 mh = MethodHandles.lookup().findStatic(Boolean.class, "valueOf",
971 MethodType.methodType(Boolean.class, boolean.class));
972 boolean w = (boolean) mh.invoke(false);
973 if (w) fail();
974
975 // Boolean -> int
976 try {
977 int dummy = (int) mh.invoke(false);
978 fail();
979 } catch (WrongMethodTypeException e) {}
980
981 // Boolean -> Integer
982 try {
983 Integer dummy = (Integer) mh.invoke("True");
984 fail();
985 } catch (WrongMethodTypeException e) {}
986
Orion Hodson1a06f9f2016-11-09 08:32:42 +0000987 System.out.println("testPrimitiveReturnValueConversions done.");
988 }
989
990 public static void testReturnValueConversions() throws Throwable {
991 testReferenceReturnValueConversions();
992 testPrimitiveReturnValueConversions();
993 }
Orion Hodson1c878782016-11-25 15:46:49 +0000994
995 public static class BaseVariableArityTester {
996 public String update(Float f0, Float... floats) {
997 return "base " + f0 + ", " + Arrays.toString(floats);
998 }
999 }
1000
1001 public static class VariableArityTester extends BaseVariableArityTester {
1002 private String lastResult;
1003
1004 // Constructors
1005 public VariableArityTester() {}
1006 public VariableArityTester(boolean... booleans) { update(booleans); }
1007 public VariableArityTester(byte... bytes) { update(bytes); }
1008 public VariableArityTester(char... chars) { update(chars); }
1009 public VariableArityTester(short... shorts) { update(shorts); }
1010 public VariableArityTester(int... ints) { update(ints); }
1011 public VariableArityTester(long... longs) { update(longs); }
1012 public VariableArityTester(float... floats) { update(floats); }
1013 public VariableArityTester(double... doubles) { update(doubles); }
1014 public VariableArityTester(Float f0, Float... floats) { update(f0, floats); }
1015 public VariableArityTester(String s0, String... strings) { update(s0, strings); }
1016 public VariableArityTester(char c, Number... numbers) { update(c, numbers); }
1017 @SafeVarargs
1018 public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1019 update(l0, lists);
1020 }
1021 public VariableArityTester(List l0, List... lists) { update(l0, lists); }
1022
1023 // Methods
1024 public String update(boolean... booleans) { return lastResult = tally(booleans); }
1025 public String update(byte... bytes) { return lastResult = tally(bytes); }
1026 public String update(char... chars) { return lastResult = tally(chars); }
1027 public String update(short... shorts) { return lastResult = tally(shorts); }
1028 public String update(int... ints) {
1029 lastResult = tally(ints);
1030 return lastResult;
1031 }
1032 public String update(long... longs) { return lastResult = tally(longs); }
1033 public String update(float... floats) { return lastResult = tally(floats); }
1034 public String update(double... doubles) { return lastResult = tally(doubles); }
1035 @Override
1036 public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); }
1037 public String update(String s0, String... strings) { return lastResult = tally(s0, strings); }
1038 public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); }
1039 @SafeVarargs
1040 public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1041 lastResult = tally(l0, lists);
1042 return lastResult;
1043 }
1044 public String update(List l0, List... lists) { return lastResult = tally(l0, lists); }
1045
1046 public String arrayMethod(Object[] o) {
1047 return Arrays.deepToString(o);
1048 }
1049
1050 public String lastResult() { return lastResult; }
1051
1052 // Static Methods
1053 public static String tally(boolean... booleans) { return Arrays.toString(booleans); }
1054 public static String tally(byte... bytes) { return Arrays.toString(bytes); }
1055 public static String tally(char... chars) { return Arrays.toString(chars); }
1056 public static String tally(short... shorts) { return Arrays.toString(shorts); }
1057 public static String tally(int... ints) { return Arrays.toString(ints); }
1058 public static String tally(long... longs) { return Arrays.toString(longs); }
1059 public static String tally(float... floats) { return Arrays.toString(floats); }
1060 public static String tally(double... doubles) { return Arrays.toString(doubles); }
1061 public static String tally(Float f0, Float... floats) {
1062 return f0 + ", " + Arrays.toString(floats);
1063 }
1064 public static String tally(String s0, String... strings) {
1065 return s0 + ", " + Arrays.toString(strings);
1066 }
1067 public static String tally(char c, Number... numbers) {
1068 return c + ", " + Arrays.toString(numbers);
1069 }
1070 @SafeVarargs
1071 public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1072 return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists);
1073 }
1074 public static String tally(List l0, List... lists) {
1075 return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists);
1076 }
1077 public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); }
1078 public static long sumToPrimitive(int... ints) {
1079 long result = 0;
1080 for (int i : ints) result += i;
1081 return result;
1082 }
1083 public static Long sumToReference(int... ints) {
Nicolas Geoffray0f3be562016-12-11 22:05:15 +00001084 System.out.println("Hi");
Orion Hodson1c878782016-11-25 15:46:49 +00001085 return new Long(sumToPrimitive(ints));
1086 }
1087 public static MethodHandles.Lookup lookup() {
1088 return MethodHandles.lookup();
1089 }
1090 }
1091
1092 // This method only exists to fool Jack's handling of types. See b/32536744.
1093 public static Object getAsObject(String[] strings) {
1094 return (Object) strings;
1095 }
1096
1097 public static void testVariableArity() throws Throwable {
1098 MethodHandle mh;
1099 VariableArityTester vat = new VariableArityTester();
1100
1101 assertEquals("[1]", vat.update(1));
1102 assertEquals("[1, 1]", vat.update(1, 1));
1103 assertEquals("[1, 1, 1]", vat.update(1, 1, 1));
1104
1105 // Methods - boolean
1106 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1107 MethodType.methodType(String.class, boolean[].class));
1108 assertTrue(mh.isVarargsCollector());
1109 assertFalse(mh.asFixedArity().isVarargsCollector());
1110 assertEquals("[]", mh.invoke(vat));
1111 assertEquals("[true, false, true]", mh.invoke(vat, true, false, true));
1112 assertEquals("[true, false, true]", mh.invoke(vat, new boolean[] { true, false, true}));
1113 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), Boolean.valueOf(true)));
1114 try {
1115 mh.invoke(vat, true, true, 0);
1116 fail();
1117 } catch (WrongMethodTypeException e) {}
1118 try {
1119 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), (Boolean) null));
1120 fail();
1121 } catch (NullPointerException e) {}
1122
1123 // Methods - byte
1124 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1125 MethodType.methodType(String.class, byte[].class));
1126 assertTrue(mh.isVarargsCollector());
1127 assertEquals("[]", mh.invoke(vat));
1128 assertEquals("[32, 64, 97]", mh.invoke(vat, (byte) 32, Byte.valueOf((byte) 64), (byte) 97));
1129 assertEquals("[32, 64, 97]", mh.invoke(vat, new byte[] {(byte) 32, (byte) 64, (byte) 97}));
1130 try {
1131 mh.invoke(vat, (byte) 1, Integer.valueOf(3), (byte) 0);
1132 fail();
1133 } catch (WrongMethodTypeException e) {}
1134
1135 // Methods - char
1136 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1137 MethodType.methodType(String.class, char[].class));
1138 assertTrue(mh.isVarargsCollector());
1139 assertEquals("[]", mh.invoke(vat));
1140 assertEquals("[A, B, C]", mh.invoke(vat, 'A', Character.valueOf('B'), 'C'));
1141 assertEquals("[W, X, Y, Z]", mh.invoke(vat, new char[] { 'W', 'X', 'Y', 'Z' }));
1142
1143 // Methods - short
1144 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1145 MethodType.methodType(String.class, short[].class));
1146 assertTrue(mh.isVarargsCollector());
1147 assertEquals("[]", mh.invoke(vat));
1148 assertEquals("[32767, -32768, 0]",
1149 mh.invoke(vat, Short.MAX_VALUE, Short.MIN_VALUE, Short.valueOf((short) 0)));
1150 assertEquals("[1, -1]", mh.invoke(vat, new short[] { (short) 1, (short) -1 }));
1151
1152 // Methods - int
1153 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1154 MethodType.methodType(String.class, int[].class));
1155 assertTrue(mh.isVarargsCollector());
1156 assertEquals("[]", mh.invoke(vat));
1157 assertEquals("[0, 2147483647, -2147483648, 0]",
1158 mh.invoke(vat, Integer.valueOf(0), Integer.MAX_VALUE, Integer.MIN_VALUE, 0));
1159 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new int[] { 0, -1, 1, 0 }));
1160
1161 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, new int [] { 5, 4, 3, 2, 1 }));
1162 try {
1163 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, 5, 4, 3, 2, 1));
1164 fail();
1165 } catch (WrongMethodTypeException e) {}
1166 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invoke(vat, 5, 4, 3, 2, 1));
1167
1168 // Methods - long
1169 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1170 MethodType.methodType(String.class, long[].class));
1171 assertTrue(mh.isVarargsCollector());
1172 assertEquals("[]", mh.invoke(vat));
1173 assertEquals("[0, 9223372036854775807, -9223372036854775808]",
1174 mh.invoke(vat, Long.valueOf(0), Long.MAX_VALUE, Long.MIN_VALUE));
1175 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new long[] { 0, -1, 1, 0 }));
1176
1177 // Methods - float
1178 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1179 MethodType.methodType(String.class, float[].class));
1180 assertTrue(mh.isVarargsCollector());
1181 assertEquals("[]", mh.invoke(vat));
1182 assertEquals("[0.0, 1.25, -1.25]",
1183 mh.invoke(vat, 0.0f, Float.valueOf(1.25f), Float.valueOf(-1.25f)));
1184 assertEquals("[0.0, -1.0, 1.0, 0.0]",
1185 mh.invoke(vat, new float[] { 0.0f, -1.0f, 1.0f, 0.0f }));
1186
1187 // Methods - double
1188 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1189 MethodType.methodType(String.class, double[].class));
1190 assertTrue(mh.isVarargsCollector());
1191 assertEquals("[]", mh.invoke(vat));
1192 assertEquals("[0.0, 1.25, -1.25]",
1193 mh.invoke(vat, 0.0, Double.valueOf(1.25), Double.valueOf(-1.25)));
1194 assertEquals("[0.0, -1.0, 1.0, 0.0]",
1195 mh.invoke(vat, new double[] { 0.0, -1.0, 1.0, 0.0 }));
1196 mh.invoke(vat, 0.3f, 1.33, 1.33);
1197
1198 // Methods - String
1199 mh = MethodHandles.lookup().
1200 findVirtual(VariableArityTester.class, "update",
1201 MethodType.methodType(String.class, String.class, String[].class));
1202 assertTrue(mh.isVarargsCollector());
1203 assertEquals("Echidna, []", mh.invoke(vat, "Echidna"));
1204 assertEquals("Bongo, [Jerboa, Okapi]",
1205 mh.invoke(vat, "Bongo", "Jerboa", "Okapi"));
1206
1207 // Methods - Float
1208 mh = MethodHandles.lookup().
1209 findVirtual(VariableArityTester.class, "update",
1210 MethodType.methodType(String.class, Float.class, Float[].class));
1211 assertTrue(mh.isVarargsCollector());
1212 assertEquals("9.99, [0.0, 0.1, 1.1]",
1213 (String) mh.invoke(vat, Float.valueOf(9.99f),
1214 new Float[] { Float.valueOf(0.0f),
1215 Float.valueOf(0.1f),
1216 Float.valueOf(1.1f) }));
1217 assertEquals("9.99, [0.0, 0.1, 1.1]",
1218 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
1219 Float.valueOf(0.1f), Float.valueOf(1.1f)));
1220 assertEquals("9.99, [0.0, 0.1, 1.1]",
1221 (String) mh.invoke(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
1222 try {
1223 assertEquals("9.99, [77.0, 33.0, 64.0]",
1224 (String) mh.invoke(vat, Float.valueOf(9.99f), 77, 33, 64));
1225 fail();
1226 } catch (WrongMethodTypeException e) {}
1227 assertEquals("9.99, [0.0, 0.1, 1.1]",
1228 (String) mh.invokeExact(vat, Float.valueOf(9.99f),
1229 new Float[] { Float.valueOf(0.0f),
1230 Float.valueOf(0.1f),
1231 Float.valueOf(1.1f) }));
1232 assertEquals("9.99, [0.0, null, 1.1]",
1233 (String) mh.invokeExact(vat, Float.valueOf(9.99f),
1234 new Float[] { Float.valueOf(0.0f),
1235 null,
1236 Float.valueOf(1.1f) }));
1237 try {
1238 assertEquals("9.99, [0.0, 0.1, 1.1]",
1239 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
1240 fail();
1241 } catch (WrongMethodTypeException e) {}
1242
1243 // Methods - Number
1244 mh = MethodHandles.lookup().
1245 findVirtual(VariableArityTester.class, "update",
1246 MethodType.methodType(String.class, char.class, Number[].class));
1247 assertTrue(mh.isVarargsCollector());
1248 assertFalse(mh.asFixedArity().isVarargsCollector());
1249 assertEquals("x, []", (String) mh.invoke(vat, 'x'));
1250 assertEquals("x, [3.141]", (String) mh.invoke(vat, 'x', 3.141));
1251 assertEquals("x, [null, 3.131, 37]",
1252 (String) mh.invoke(vat, 'x', null, 3.131, new Integer(37)));
1253 try {
1254 assertEquals("x, [null, 3.131, bad, 37]",
1255 (String) mh.invoke(vat, 'x', null, 3.131, "bad", new Integer(37)));
1256 assertTrue(false);
1257 fail();
1258 } catch (ClassCastException e) {}
1259 try {
1260 assertEquals("x, [null, 3.131, bad, 37]",
1261 (String) mh.invoke(
1262 vat, 'x', (Process) null, 3.131, "bad", new Integer(37)));
1263 assertTrue(false);
1264 fail();
1265 } catch (ClassCastException e) {}
1266
1267 // Methods - an array method that is not variable arity.
1268 mh = MethodHandles.lookup().findVirtual(
1269 VariableArityTester.class, "arrayMethod",
1270 MethodType.methodType(String.class, Object[].class));
1271 assertFalse(mh.isVarargsCollector());
1272 mh.invoke(vat, new Object[] { "123" });
1273 try {
1274 assertEquals("-", mh.invoke(vat, new Float(3), new Float(4)));
1275 fail();
1276 } catch (WrongMethodTypeException e) {}
1277 mh = mh.asVarargsCollector(Object[].class);
1278 assertTrue(mh.isVarargsCollector());
1279 assertEquals("[3.0, 4.0]", (String) mh.invoke(vat, new Float(3), new Float(4)));
1280
1281 // Constructors - default
1282 mh = MethodHandles.lookup().findConstructor(
1283 VariableArityTester.class, MethodType.methodType(void.class));
1284 assertFalse(mh.isVarargsCollector());
1285
1286 // Constructors - boolean
1287 mh = MethodHandles.lookup().findConstructor(
1288 VariableArityTester.class, MethodType.methodType(void.class, boolean[].class));
1289 assertTrue(mh.isVarargsCollector());
1290 assertEquals("[true, true, false]",
1291 ((VariableArityTester) mh.invoke(new boolean[] {true, true, false})).lastResult());
1292 assertEquals("[true, true, false]",
1293 ((VariableArityTester) mh.invoke(true, true, false)).lastResult());
1294 try {
1295 assertEquals("[true, true, false]",
1296 ((VariableArityTester) mh.invokeExact(true, true, false)).lastResult());
1297 fail();
1298 } catch (WrongMethodTypeException e) {}
1299
1300 // Constructors - byte
1301 mh = MethodHandles.lookup().findConstructor(
1302 VariableArityTester.class, MethodType.methodType(void.class, byte[].class));
1303 assertTrue(mh.isVarargsCollector());
1304 assertEquals("[55, 66, 60]",
1305 ((VariableArityTester)
1306 mh.invoke(new byte[] {(byte) 55, (byte) 66, (byte) 60})).lastResult());
1307 assertEquals("[55, 66, 60]",
1308 ((VariableArityTester) mh.invoke(
1309 (byte) 55, (byte) 66, (byte) 60)).lastResult());
1310 try {
1311 assertEquals("[55, 66, 60]",
1312 ((VariableArityTester) mh.invokeExact(
1313 (byte) 55, (byte) 66, (byte) 60)).lastResult());
1314 fail();
1315 } catch (WrongMethodTypeException e) {}
1316 try {
1317 assertEquals("[3, 3]",
1318 ((VariableArityTester) mh.invoke(
1319 new Number[] { Byte.valueOf((byte) 3), (byte) 3})).lastResult());
1320 fail();
1321 } catch (WrongMethodTypeException e) {}
1322
1323 // Constructors - String (have a different path than other reference types).
1324 mh = MethodHandles.lookup().findConstructor(
1325 VariableArityTester.class, MethodType.methodType(void.class, String.class, String[].class));
1326 assertTrue(mh.isVarargsCollector());
1327 assertEquals("x, []", ((VariableArityTester) mh.invoke("x")).lastResult());
1328 assertEquals("x, [y]", ((VariableArityTester) mh.invoke("x", "y")).lastResult());
1329 assertEquals("x, [y, z]",
1330 ((VariableArityTester) mh.invoke("x", new String[] { "y", "z" })).lastResult());
1331 try {
1332 assertEquals("x, [y]", ((VariableArityTester) mh.invokeExact("x", "y")).lastResult());
1333 fail();
1334 } catch (WrongMethodTypeException e) {}
1335 assertEquals("x, [null, z]",
1336 ((VariableArityTester) mh.invoke("x", new String[] { null, "z" })).lastResult());
1337
1338 // Constructors - Number
1339 mh = MethodHandles.lookup().findConstructor(
1340 VariableArityTester.class, MethodType.methodType(void.class, char.class, Number[].class));
1341 assertTrue(mh.isVarargsCollector());
1342 assertFalse(mh.asFixedArity().isVarargsCollector());
1343 assertEquals("x, []", ((VariableArityTester) mh.invoke('x')).lastResult());
1344 assertEquals("x, [3.141]", ((VariableArityTester) mh.invoke('x', 3.141)).lastResult());
1345 assertEquals("x, [null, 3.131, 37]",
1346 ((VariableArityTester) mh.invoke('x', null, 3.131, new Integer(37))).lastResult());
1347 try {
1348 assertEquals("x, [null, 3.131, bad, 37]",
1349 ((VariableArityTester) mh.invoke(
1350 'x', null, 3.131, "bad", new Integer(37))).lastResult());
1351 assertTrue(false);
1352 fail();
1353 } catch (ClassCastException e) {}
1354 try {
1355 assertEquals("x, [null, 3.131, bad, 37]",
1356 ((VariableArityTester) mh.invoke(
1357 'x', (Process) null, 3.131, "bad", new Integer(37))).lastResult());
1358 assertTrue(false);
1359 fail();
1360 } catch (ClassCastException e) {}
1361
1362 // Static Methods - Float
1363 mh = MethodHandles.lookup().
1364 findStatic(VariableArityTester.class, "tally",
1365 MethodType.methodType(String.class, Float.class, Float[].class));
1366 assertTrue(mh.isVarargsCollector());
1367 assertEquals("9.99, [0.0, 0.1, 1.1]",
1368 (String) mh.invoke(Float.valueOf(9.99f),
1369 new Float[] { Float.valueOf(0.0f),
1370 Float.valueOf(0.1f),
1371 Float.valueOf(1.1f) }));
1372 assertEquals("9.99, [0.0, 0.1, 1.1]",
1373 (String) mh.invoke(Float.valueOf(9.99f), Float.valueOf(0.0f),
1374 Float.valueOf(0.1f), Float.valueOf(1.1f)));
1375 assertEquals("9.99, [0.0, 0.1, 1.1]",
1376 (String) mh.invoke(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
1377 try {
1378 assertEquals("9.99, [77.0, 33.0, 64.0]",
1379 (String) mh.invoke(Float.valueOf(9.99f), 77, 33, 64));
1380 fail();
1381 } catch (WrongMethodTypeException e) {}
1382 assertEquals("9.99, [0.0, 0.1, 1.1]",
1383 (String) mh.invokeExact(Float.valueOf(9.99f),
1384 new Float[] { Float.valueOf(0.0f),
1385 Float.valueOf(0.1f),
1386 Float.valueOf(1.1f) }));
1387 assertEquals("9.99, [0.0, null, 1.1]",
1388 (String) mh.invokeExact(Float.valueOf(9.99f),
1389 new Float[] { Float.valueOf(0.0f),
1390 null,
1391 Float.valueOf(1.1f) }));
1392 try {
1393 assertEquals("9.99, [0.0, 0.1, 1.1]",
1394 (String) mh.invokeExact(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
1395 fail();
1396 } catch (WrongMethodTypeException e) {}
1397
1398 // Special methods - Float
1399 mh = VariableArityTester.lookup().
1400 findSpecial(BaseVariableArityTester.class, "update",
1401 MethodType.methodType(String.class, Float.class, Float[].class),
1402 VariableArityTester.class);
1403 assertTrue(mh.isVarargsCollector());
1404 assertEquals("base 9.99, [0.0, 0.1, 1.1]",
1405 (String) mh.invoke(vat,
1406 Float.valueOf(9.99f),
1407 new Float[] { Float.valueOf(0.0f),
1408 Float.valueOf(0.1f),
1409 Float.valueOf(1.1f) }));
1410 assertEquals("base 9.99, [0.0, 0.1, 1.1]",
1411 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
1412 Float.valueOf(0.1f), Float.valueOf(1.1f)));
1413
1414 // Return value conversions.
1415 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1416 MethodType.methodType(String.class, int[].class));
1417 assertEquals("[1, 2, 3]", (String) mh.invoke(vat, 1, 2, 3));
1418 assertEquals("[1, 2, 3]", (Object) mh.invoke(vat, 1, 2, 3));
1419 try {
1420 assertEquals("[1, 2, 3, 4]", (long) mh.invoke(vat, 1, 2, 3));
1421 fail();
1422 } catch (WrongMethodTypeException e) {}
1423 assertEquals("[1, 2, 3]", vat.lastResult());
1424 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToPrimitive",
1425 MethodType.methodType(long.class, int[].class));
1426 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
1427 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
1428 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToReference",
1429 MethodType.methodType(Long.class, int[].class));
1430 Object o = mh.invoke(1, 2, 3, 4);
1431 long l = (long) mh.invoke(1, 2, 3, 4);
1432 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
1433 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
1434 try {
1435 // WrongMethodTypeException should be raised before invoke here.
Nicolas Geoffray0f3be562016-12-11 22:05:15 +00001436 System.out.print("Expect Hi here: ");
Orion Hodson1c878782016-11-25 15:46:49 +00001437 assertEquals(Long.valueOf(10l), (Byte) mh.invoke(1, 2, 3, 4));
1438 fail();
1439 } catch (ClassCastException e) {}
1440 try {
1441 // WrongMethodTypeException should be raised before invoke here.
Nicolas Geoffray0f3be562016-12-11 22:05:15 +00001442 System.out.println("Don't expect Hi now");
Orion Hodson1c878782016-11-25 15:46:49 +00001443 byte b = (byte) mh.invoke(1, 2, 3, 4);
1444 fail();
1445 } catch (WrongMethodTypeException e) {}
1446
1447 // Return void produces 0 / null.
1448 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "foo",
1449 MethodType.methodType(void.class, int[].class));
1450 assertEquals(null, (Object) mh.invoke(3, 2, 1));
1451 assertEquals(0l, (long) mh.invoke(1, 2, 3));
1452
1453 // Combinators
1454 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
1455 MethodType.methodType(String.class, boolean[].class));
1456 assertTrue(mh.isVarargsCollector());
1457 mh = mh.bindTo(vat);
1458 assertFalse(mh.isVarargsCollector());
1459 mh = mh.asVarargsCollector(boolean[].class);
1460 assertTrue(mh.isVarargsCollector());
1461 assertEquals("[]", mh.invoke());
1462 assertEquals("[true, false, true]", mh.invoke(true, false, true));
1463 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true}));
1464 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true)));
1465 try {
1466 mh.invoke(true, true, 0);
1467 fail();
1468 } catch (WrongMethodTypeException e) {}
1469 }
Narayan Kamathec08c062017-01-16 14:56:19 +00001470
1471 // The same tests as the above, except that we use use MethodHandles.bind instead of
1472 // MethodHandle.bindTo.
1473 public static void testVariableArity_MethodHandles_bind() throws Throwable {
1474 VariableArityTester vat = new VariableArityTester();
1475 MethodHandle mh = MethodHandles.lookup().bind(vat, "update",
1476 MethodType.methodType(String.class, boolean[].class));
1477 assertTrue(mh.isVarargsCollector());
1478
1479 assertEquals("[]", mh.invoke());
1480 assertEquals("[true, false, true]", mh.invoke(true, false, true));
1481 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true}));
1482 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true)));
1483
1484 try {
1485 mh.invoke(true, true, 0);
1486 fail();
1487 } catch (WrongMethodTypeException e) {}
1488 }
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +01001489}