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