MethodHandlesTest.java revision 4251:f09930d526ba
1/* 2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26/* @test 27 * @summary unit tests for java.lang.invoke.MethodHandles 28 * @compile -source 7 -target 7 MethodHandlesTest.java 29 * @run junit/othervm test.java.lang.invoke.MethodHandlesTest 30 */ 31 32package test.java.lang.invoke; 33 34import java.lang.invoke.*; 35import java.lang.invoke.MethodHandles.Lookup; 36import java.lang.reflect.*; 37import java.util.*; 38import org.junit.*; 39import static org.junit.Assert.*; 40import static org.junit.Assume.*; 41 42 43/** 44 * 45 * @author jrose 46 */ 47public class MethodHandlesTest { 48 // How much output? 49 static int verbosity = 0; 50 static { 51 String vstr = System.getProperty("test.java.lang.invoke.MethodHandlesTest.verbosity"); 52 if (vstr != null) verbosity = Integer.parseInt(vstr); 53 } 54 55 // Set this true during development if you want to fast-forward to 56 // a particular new, non-working test. Tests which are known to 57 // work (or have recently worked) test this flag and return on true. 58 static boolean CAN_SKIP_WORKING = false; 59 //static { CAN_SKIP_WORKING = true; } 60 61 // Set true to test more calls. If false, some tests are just 62 // lookups, without exercising the actual method handle. 63 static boolean DO_MORE_CALLS = true; 64 65 @Test 66 public void testFirst() throws Throwable { 67 verbosity += 9; try { 68 // left blank for debugging 69 } finally { printCounts(); verbosity -= 9; } 70 } 71 72 // current failures 73 @Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric") 74 public void testFail_1() throws Throwable { 75 // AMH.<init>: IllegalArgumentException: bad adapter (conversion=0xfffab300): adapter pushes too many parameters 76 testSpreadArguments(int.class, 0, 6); 77 } 78 @Test @Ignore("failure in JVM when expanding the stack using asm stub for _adapter_spread_args") 79 public void testFail_2() throws Throwable { 80 // if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes: 81 testSpreadArguments(Object.class, 0, 2); 82 } 83 @Test @Ignore("IllArgEx failure in call to ToGeneric.make") 84 public void testFail_3() throws Throwable { 85 // ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object 86 testSpreadArguments(int.class, 1, 2); 87 } 88 @Test @Ignore("IllArgEx failure in call to ToGeneric.make") 89 public void testFail_4() throws Throwable { 90 // ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object 91 testCollectArguments(int.class, 1, 2); 92 } 93 @Test @Ignore("cannot collect leading primitive types") 94 public void testFail_5() throws Throwable { 95 // ToGeneric.<init>: UnsupportedOperationException: NYI: primitive parameters must follow references; entryType = (int,java.lang.Object)java.lang.Object 96 testInvokers(MethodType.genericMethodType(2).changeParameterType(0, int.class)); 97 } 98 @Test @Ignore("should not insert arguments beyond MethodHandlePushLimit") 99 public void testFail_6() throws Throwable { 100 // ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13 101 testInsertArguments(0, 0, MAX_ARG_INCREASE+10); 102 } 103 @Test @Ignore("permuteArguments has trouble with double slots") 104 public void testFail_7() throws Throwable { 105 testPermuteArguments(new Object[]{10, 200L}, 106 new Class<?>[]{Integer.class, long.class}, 107 new int[]{1,0}); 108 testPermuteArguments(new Object[]{10, 200L, 5000L}, 109 new Class<?>[]{Integer.class, long.class, long.class}, 110 new int[]{2,0,1}); //rot 111 testPermuteArguments(new Object[]{10, 200L, 5000L}, 112 new Class<?>[]{Integer.class, long.class, long.class}, 113 new int[]{1,2,0}); //rot 114 testPermuteArguments(new Object[]{10, 200L, 5000L}, 115 new Class<?>[]{Integer.class, long.class, long.class}, 116 new int[]{2,1,0}); //swap 117 testPermuteArguments(new Object[]{10, 200L, 5000L}, 118 new Class<?>[]{Integer.class, long.class, long.class}, 119 new int[]{0,1,2,2}); //dup 120 testPermuteArguments(new Object[]{10, 200L, 5000L}, 121 new Class<?>[]{Integer.class, long.class, long.class}, 122 new int[]{2,0,1,2}); 123 testPermuteArguments(new Object[]{10, 200L, 5000L}, 124 new Class<?>[]{Integer.class, long.class, long.class}, 125 new int[]{2,2,0,1}); 126 testPermuteArguments(4, Integer.class, 2, long.class, 6); 127 } 128 static final int MAX_ARG_INCREASE = 3; 129 130 public MethodHandlesTest() { 131 } 132 133 String testName; 134 static int allPosTests, allNegTests; 135 int posTests, negTests; 136 @After 137 public void printCounts() { 138 if (verbosity >= 2 && (posTests | negTests) != 0) { 139 System.out.println(); 140 if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run"); 141 if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run"); 142 allPosTests += posTests; 143 allNegTests += negTests; 144 posTests = negTests = 0; 145 } 146 } 147 void countTest(boolean positive) { 148 if (positive) ++posTests; 149 else ++negTests; 150 } 151 void countTest() { countTest(true); } 152 void startTest(String name) { 153 if (testName != null) printCounts(); 154 if (verbosity >= 1) 155 System.out.println(name); 156 posTests = negTests = 0; 157 testName = name; 158 } 159 160 @BeforeClass 161 public static void setUpClass() throws Exception { 162 calledLog.clear(); 163 calledLog.add(null); 164 nextArgVal = INITIAL_ARG_VAL; 165 } 166 167 @AfterClass 168 public static void tearDownClass() throws Exception { 169 int posTests = allPosTests, negTests = allNegTests; 170 if (verbosity >= 2 && (posTests | negTests) != 0) { 171 System.out.println(); 172 if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases"); 173 if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases"); 174 } 175 } 176 177 static List<Object> calledLog = new ArrayList<Object>(); 178 static Object logEntry(String name, Object... args) { 179 return Arrays.asList(name, Arrays.asList(args)); 180 } 181 static Object called(String name, Object... args) { 182 Object entry = logEntry(name, args); 183 calledLog.add(entry); 184 return entry; 185 } 186 static void assertCalled(String name, Object... args) { 187 Object expected = logEntry(name, args); 188 Object actual = calledLog.get(calledLog.size() - 1); 189 if (expected.equals(actual) && verbosity < 9) return; 190 System.out.println("assertCalled "+name+":"); 191 System.out.println("expected: "+expected); 192 System.out.println("actual: "+actual); 193 System.out.println("ex. types: "+getClasses(expected)); 194 System.out.println("act. types: "+getClasses(actual)); 195 assertEquals("previous method call", expected, actual); 196 } 197 static void printCalled(MethodHandle target, String name, Object... args) { 198 if (verbosity >= 3) 199 System.out.println("calling MH="+target+" to "+name+Arrays.toString(args)); 200 } 201 202 static Object castToWrapper(Object value, Class<?> dst) { 203 Object wrap = null; 204 if (value instanceof Number) 205 wrap = castToWrapperOrNull(((Number)value).longValue(), dst); 206 if (value instanceof Character) 207 wrap = castToWrapperOrNull((char)(Character)value, dst); 208 if (wrap != null) return wrap; 209 return dst.cast(value); 210 } 211 212 static Object castToWrapperOrNull(long value, Class<?> dst) { 213 if (dst == int.class || dst == Integer.class) 214 return (int)(value); 215 if (dst == long.class || dst == Long.class) 216 return (long)(value); 217 if (dst == char.class || dst == Character.class) 218 return (char)(value); 219 if (dst == short.class || dst == Short.class) 220 return (short)(value); 221 if (dst == float.class || dst == Float.class) 222 return (float)(value); 223 if (dst == double.class || dst == Double.class) 224 return (double)(value); 225 if (dst == byte.class || dst == Byte.class) 226 return (byte)(value); 227 if (dst == boolean.class || dst == boolean.class) 228 return ((value % 29) & 1) == 0; 229 return null; 230 } 231 232 static final int ONE_MILLION = (1000*1000), // first int value 233 TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits 234 INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit; 235 static long nextArgVal; 236 static long nextArg(boolean moreBits) { 237 long val = nextArgVal++; 238 long sign = -(val & 1); // alternate signs 239 val >>= 1; 240 if (moreBits) 241 // Guarantee some bits in the high word. 242 // In any case keep the decimal representation simple-looking, 243 // with lots of zeroes, so as not to make the printed decimal 244 // strings unnecessarily noisy. 245 val += (val % ONE_MILLION) * TEN_BILLION; 246 return val ^ sign; 247 } 248 static int nextArg() { 249 // Produce a 32-bit result something like ONE_MILLION+(smallint). 250 // Example: 1_000_042. 251 return (int) nextArg(false); 252 } 253 static long nextArg(Class<?> kind) { 254 if (kind == long.class || kind == Long.class || 255 kind == double.class || kind == Double.class) 256 // produce a 64-bit result something like 257 // ((TEN_BILLION+1) * (ONE_MILLION+(smallint))) 258 // Example: 10_000_420_001_000_042. 259 return nextArg(true); 260 return (long) nextArg(); 261 } 262 263 static Object randomArg(Class<?> param) { 264 Object wrap = castToWrapperOrNull(nextArg(param), param); 265 if (wrap != null) { 266 return wrap; 267 } 268// import sun.invoke.util.Wrapper; 269// Wrapper wrap = Wrapper.forBasicType(dst); 270// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst)) 271// wrap = Wrapper.forWrapperType(dst); 272// if (wrap != Wrapper.OBJECT) 273// return wrap.wrap(nextArg++); 274 if (param.isInterface()) { 275 for (Class<?> c : param.getClasses()) { 276 if (param.isAssignableFrom(c) && !c.isInterface()) 277 { param = c; break; } 278 } 279 } 280 if (param.isInterface() || param.isAssignableFrom(String.class)) 281 return "#"+nextArg(); 282 else 283 try { 284 return param.newInstance(); 285 } catch (InstantiationException ex) { 286 } catch (IllegalAccessException ex) { 287 } 288 return null; // random class not Object, String, Integer, etc. 289 } 290 static Object[] randomArgs(Class<?>... params) { 291 Object[] args = new Object[params.length]; 292 for (int i = 0; i < args.length; i++) 293 args[i] = randomArg(params[i]); 294 return args; 295 } 296 static Object[] randomArgs(int nargs, Class<?> param) { 297 Object[] args = new Object[nargs]; 298 for (int i = 0; i < args.length; i++) 299 args[i] = randomArg(param); 300 return args; 301 } 302 303 static <T, E extends T> T[] array(Class<T[]> atype, E... a) { 304 return Arrays.copyOf(a, a.length, atype); 305 } 306 static <T> T[] cat(T[] a, T... b) { 307 int alen = a.length, blen = b.length; 308 if (blen == 0) return a; 309 T[] c = Arrays.copyOf(a, alen + blen); 310 System.arraycopy(b, 0, c, alen, blen); 311 return c; 312 } 313 static Integer[] boxAll(int... vx) { 314 Integer[] res = new Integer[vx.length]; 315 for (int i = 0; i < res.length; i++) { 316 res[i] = vx[i]; 317 } 318 return res; 319 } 320 static Object getClasses(Object x) { 321 if (x == null) return x; 322 if (x instanceof String) return x; // keep the name 323 if (x instanceof List) { 324 // recursively report classes of the list elements 325 Object[] xa = ((List)x).toArray(); 326 for (int i = 0; i < xa.length; i++) 327 xa[i] = getClasses(xa[i]); 328 return Arrays.asList(xa); 329 } 330 return x.getClass().getSimpleName(); 331 } 332 333 /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */ 334 static MethodHandle varargsList(int arity) { 335 return ValueConversions.varargsList(arity); 336 } 337 /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */ 338 static MethodHandle varargsArray(int arity) { 339 return ValueConversions.varargsArray(arity); 340 } 341 static MethodHandle varargsArray(Class<?> arrayType, int arity) { 342 return ValueConversions.varargsArray(arrayType, arity); 343 } 344 /** Variation of varargsList, but with the given rtype. */ 345 static MethodHandle varargsList(int arity, Class<?> rtype) { 346 MethodHandle list = varargsList(arity); 347 MethodType listType = list.type().changeReturnType(rtype); 348 if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) { 349 // OK 350 } else if (rtype.isAssignableFrom(String.class)) { 351 if (LIST_TO_STRING == null) 352 try { 353 LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString", 354 MethodType.methodType(String.class, List.class)); 355 } catch (Exception ex) { throw new RuntimeException(ex); } 356 list = MethodHandles.filterReturnValue(list, LIST_TO_STRING); 357 } else if (rtype.isPrimitive()) { 358 if (LIST_TO_INT == null) 359 try { 360 LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt", 361 MethodType.methodType(int.class, List.class)); 362 } catch (Exception ex) { throw new RuntimeException(ex); } 363 list = MethodHandles.filterReturnValue(list, LIST_TO_INT); 364 list = MethodHandles.explicitCastArguments(list, listType); 365 } else { 366 throw new RuntimeException("varargsList: "+rtype); 367 } 368 return list.asType(listType); 369 } 370 private static MethodHandle LIST_TO_STRING, LIST_TO_INT; 371 private static String listToString(List x) { return x.toString(); } 372 private static int listToInt(List x) { return x.toString().hashCode(); } 373 374 static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) { 375 return changeArgTypes(target, 0, 999, argType); 376 } 377 static MethodHandle changeArgTypes(MethodHandle target, 378 int beg, int end, Class<?> argType) { 379 MethodType targetType = target.type(); 380 end = Math.min(end, targetType.parameterCount()); 381 ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList()); 382 Collections.fill(argTypes.subList(beg, end), argType); 383 MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); 384 return target.asType(ttype2); 385 } 386 387 // This lookup is good for all members in and under MethodHandlesTest. 388 static final Lookup PRIVATE = MethodHandles.lookup(); 389 // This lookup is good for package-private members but not private ones. 390 static final Lookup PACKAGE = PackageSibling.lookup(); 391 // This lookup is good only for public members. 392 static final Lookup PUBLIC = MethodHandles.publicLookup(); 393 394 // Subject methods... 395 static class Example implements IntExample { 396 final String name; 397 public Example() { name = "Example#"+nextArg(); } 398 protected Example(String name) { this.name = name; } 399 protected Example(int x) { this(); called("protected <init>", this, x); } 400 @Override public String toString() { return name; } 401 402 public void v0() { called("v0", this); } 403 void pkg_v0() { called("pkg_v0", this); } 404 private void pri_v0() { called("pri_v0", this); } 405 public static void s0() { called("s0"); } 406 static void pkg_s0() { called("pkg_s0"); } 407 private static void pri_s0() { called("pri_s0"); } 408 409 public Object v1(Object x) { return called("v1", this, x); } 410 public Object v2(Object x, Object y) { return called("v2", this, x, y); } 411 public Object v2(Object x, int y) { return called("v2", this, x, y); } 412 public Object v2(int x, Object y) { return called("v2", this, x, y); } 413 public Object v2(int x, int y) { return called("v2", this, x, y); } 414 public static Object s1(Object x) { return called("s1", x); } 415 public static Object s2(int x) { return called("s2", x); } 416 public static Object s3(long x) { return called("s3", x); } 417 public static Object s4(int x, int y) { return called("s4", x, y); } 418 public static Object s5(long x, int y) { return called("s5", x, y); } 419 public static Object s6(int x, long y) { return called("s6", x, y); } 420 public static Object s7(float x, double y) { return called("s7", x, y); } 421 422 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial 423 } 424 static final Lookup EXAMPLE = Example.EXAMPLE; 425 public static class PubExample extends Example { 426 public PubExample() { super("PubExample#"+nextArg()); } 427 } 428 static class SubExample extends Example { 429 @Override public void v0() { called("Sub/v0", this); } 430 @Override void pkg_v0() { called("Sub/pkg_v0", this); } 431 private SubExample(int x) { called("<init>", this, x); } 432 public SubExample() { super("SubExample#"+nextArg()); } 433 } 434 public static interface IntExample { 435 public void v0(); 436 public static class Impl implements IntExample { 437 public void v0() { called("Int/v0", this); } 438 final String name; 439 public Impl() { name = "Impl#"+nextArg(); } 440 @Override public String toString() { return name; } 441 } 442 } 443 444 static final Object[][][] ACCESS_CASES = { 445 { { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false 446 { { false, PUBLIC }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE 447 { { false, PUBLIC }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false 448 { { true, PUBLIC }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: all true 449 }; 450 451 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) { 452 Object[][] cases; 453 if (name.contains("pri_") || isSpecial) { 454 cases = ACCESS_CASES[1]; // PRIVATE only 455 } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) { 456 cases = ACCESS_CASES[2]; // not PUBLIC 457 } else { 458 assertTrue(name.indexOf('_') < 0); 459 boolean pubc = Modifier.isPublic(defc.getModifiers()); 460 if (pubc) 461 cases = ACCESS_CASES[3]; // all access levels 462 else 463 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC 464 } 465 if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE) 466 cases = Arrays.copyOfRange(cases, 0, cases.length-1); 467 return cases; 468 } 469 static Object[][] accessCases(Class<?> defc, String name) { 470 return accessCases(defc, name, false); 471 } 472 473 @Test 474 public void testFindStatic() throws Throwable { 475 if (CAN_SKIP_WORKING) return; 476 startTest("findStatic"); 477 testFindStatic(PubExample.class, void.class, "s0"); 478 testFindStatic(Example.class, void.class, "s0"); 479 testFindStatic(Example.class, void.class, "pkg_s0"); 480 testFindStatic(Example.class, void.class, "pri_s0"); 481 482 testFindStatic(Example.class, Object.class, "s1", Object.class); 483 testFindStatic(Example.class, Object.class, "s2", int.class); 484 testFindStatic(Example.class, Object.class, "s3", long.class); 485 testFindStatic(Example.class, Object.class, "s4", int.class, int.class); 486 testFindStatic(Example.class, Object.class, "s5", long.class, int.class); 487 testFindStatic(Example.class, Object.class, "s6", int.class, long.class); 488 testFindStatic(Example.class, Object.class, "s7", float.class, double.class); 489 490 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); 491 } 492 493 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 494 for (Object[] ac : accessCases(defc, name)) { 495 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 496 } 497 } 498 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 499 testFindStatic(true, lookup, defc, ret, name, params); 500 } 501 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 502 countTest(positive); 503 MethodType type = MethodType.methodType(ret, params); 504 MethodHandle target = null; 505 Exception noAccess = null; 506 try { 507 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 508 target = lookup.in(defc).findStatic(defc, name, type); 509 } catch (ReflectiveOperationException ex) { 510 noAccess = ex; 511 if (name.contains("bogus")) 512 assertTrue(noAccess instanceof NoSuchMethodException); 513 else 514 assertTrue(noAccess instanceof IllegalAccessException); 515 } 516 if (verbosity >= 3) 517 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 518 +(noAccess == null ? "" : " !! "+noAccess)); 519 if (positive && noAccess != null) throw noAccess; 520 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 521 if (!positive) return; // negative test failed as expected 522 assertEquals(type, target.type()); 523 assertNameStringContains(target, name); 524 if (!DO_MORE_CALLS && lookup != PRIVATE) return; 525 Object[] args = randomArgs(params); 526 printCalled(target, name, args); 527 target.invokeWithArguments(args); 528 assertCalled(name, args); 529 if (verbosity >= 1) 530 System.out.print(':'); 531 } 532 533 static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); 534 535 // rough check of name string 536 static void assertNameStringContains(MethodHandle x, String s) { 537 if (!DEBUG_METHOD_HANDLE_NAMES) { 538 // ignore s 539 assertEquals("MethodHandle"+x.type(), x.toString()); 540 return; 541 } 542 if (x.toString().contains(s)) return; 543 assertEquals(s, x); 544 } 545 546 @Test 547 public void testFindVirtual() throws Throwable { 548 if (CAN_SKIP_WORKING) return; 549 startTest("findVirtual"); 550 testFindVirtual(Example.class, void.class, "v0"); 551 testFindVirtual(Example.class, void.class, "pkg_v0"); 552 testFindVirtual(Example.class, void.class, "pri_v0"); 553 testFindVirtual(Example.class, Object.class, "v1", Object.class); 554 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class); 555 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class); 556 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class); 557 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class); 558 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); 559 // test dispatch 560 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0"); 561 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0"); 562 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0"); 563 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0"); 564 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0"); 565 testFindVirtual(Example.class, IntExample.class, void.class, "v0"); 566 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); 567 } 568 569 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 570 Class<?> rcvc = defc; 571 testFindVirtual(rcvc, defc, ret, name, params); 572 } 573 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 574 for (Object[] ac : accessCases(defc, name)) { 575 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params); 576 } 577 } 578 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 579 testFindVirtual(true, lookup, rcvc, defc, ret, name, params); 580 } 581 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 582 countTest(positive); 583 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 584 MethodType type = MethodType.methodType(ret, params); 585 MethodHandle target = null; 586 Exception noAccess = null; 587 try { 588 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 589 target = lookup.in(defc).findVirtual(defc, methodName, type); 590 } catch (ReflectiveOperationException ex) { 591 noAccess = ex; 592 if (name.contains("bogus")) 593 assertTrue(noAccess instanceof NoSuchMethodException); 594 else 595 assertTrue(noAccess instanceof IllegalAccessException); 596 } 597 if (verbosity >= 3) 598 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 599 +(noAccess == null ? "" : " !! "+noAccess)); 600 if (positive && noAccess != null) throw noAccess; 601 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 602 if (!positive) return; // negative test failed as expected 603 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params); 604 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 605 assertEquals(typeWithSelf, target.type()); 606 assertNameStringContains(target, methodName); 607 if (!DO_MORE_CALLS && lookup != PRIVATE) return; 608 Object[] argsWithSelf = randomArgs(paramsWithSelf); 609 if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc); 610 printCalled(target, name, argsWithSelf); 611 target.invokeWithArguments(argsWithSelf); 612 assertCalled(name, argsWithSelf); 613 if (verbosity >= 1) 614 System.out.print(':'); 615 } 616 617 @Test 618 public void testFindSpecial() throws Throwable { 619 if (CAN_SKIP_WORKING) return; 620 startTest("findSpecial"); 621 testFindSpecial(SubExample.class, Example.class, void.class, "v0"); 622 testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0"); 623 // Do some negative testing: 624 testFindSpecial(false, EXAMPLE, SubExample.class, Example.class, void.class, "bogus"); 625 testFindSpecial(false, PRIVATE, SubExample.class, Example.class, void.class, "bogus"); 626 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) { 627 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); 628 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class); 629 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); 630 } 631 } 632 633 void testFindSpecial(Class<?> specialCaller, 634 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 635 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params); 636 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params); 637 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params); 638 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 639 } 640 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller, 641 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 642 countTest(positive); 643 MethodType type = MethodType.methodType(ret, params); 644 MethodHandle target = null; 645 Exception noAccess = null; 646 try { 647 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 648 if (verbosity >= 5) System.out.println(" lookup => "+lookup.in(specialCaller)); 649 target = lookup.in(specialCaller).findSpecial(defc, name, type, specialCaller); 650 } catch (ReflectiveOperationException ex) { 651 noAccess = ex; 652 if (name.contains("bogus")) 653 assertTrue(noAccess instanceof NoSuchMethodException); 654 else 655 assertTrue(noAccess instanceof IllegalAccessException); 656 } 657 if (verbosity >= 3) 658 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target 659 +(target == null ? "" : target.type()) 660 +(noAccess == null ? "" : " !! "+noAccess)); 661 if (positive && noAccess != null) throw noAccess; 662 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 663 if (!positive) return; // negative test failed as expected 664 assertEquals(specialCaller, target.type().parameterType(0)); 665 assertEquals(type, target.type().dropParameterTypes(0,1)); 666 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params); 667 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 668 assertNameStringContains(target, name); 669 if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return; 670 Object[] args = randomArgs(paramsWithSelf); 671 printCalled(target, name, args); 672 target.invokeWithArguments(args); 673 assertCalled(name, args); 674 } 675 676 @Test 677 public void testBind() throws Throwable { 678 if (CAN_SKIP_WORKING) return; 679 startTest("bind"); 680 testBind(Example.class, void.class, "v0"); 681 testBind(Example.class, void.class, "pkg_v0"); 682 testBind(Example.class, void.class, "pri_v0"); 683 testBind(Example.class, Object.class, "v1", Object.class); 684 testBind(Example.class, Object.class, "v2", Object.class, Object.class); 685 testBind(Example.class, Object.class, "v2", Object.class, int.class); 686 testBind(Example.class, Object.class, "v2", int.class, Object.class); 687 testBind(Example.class, Object.class, "v2", int.class, int.class); 688 testBind(false, PRIVATE, Example.class, void.class, "bogus"); 689 testBind(SubExample.class, void.class, "Sub/v0"); 690 testBind(SubExample.class, void.class, "Sub/pkg_v0"); 691 testBind(IntExample.Impl.class, void.class, "Int/v0"); 692 } 693 694 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 695 for (Object[] ac : accessCases(defc, name)) { 696 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 697 } 698 } 699 700 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 701 countTest(positive); 702 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 703 MethodType type = MethodType.methodType(ret, params); 704 Object receiver = randomArg(defc); 705 MethodHandle target = null; 706 Exception noAccess = null; 707 try { 708 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 709 target = lookup.in(defc).bind(receiver, methodName, type); 710 } catch (ReflectiveOperationException ex) { 711 noAccess = ex; 712 if (name.contains("bogus")) 713 assertTrue(noAccess instanceof NoSuchMethodException); 714 else 715 assertTrue(noAccess instanceof IllegalAccessException); 716 } 717 if (verbosity >= 3) 718 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target 719 +(noAccess == null ? "" : " !! "+noAccess)); 720 if (positive && noAccess != null) throw noAccess; 721 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 722 if (!positive) return; // negative test failed as expected 723 assertEquals(type, target.type()); 724 Object[] args = randomArgs(params); 725 printCalled(target, name, args); 726 target.invokeWithArguments(args); 727 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); 728 assertCalled(name, argsWithReceiver); 729 if (verbosity >= 1) 730 System.out.print(':'); 731 } 732 733 @Test 734 public void testUnreflect() throws Throwable { 735 if (CAN_SKIP_WORKING) return; 736 startTest("unreflect"); 737 testUnreflect(Example.class, true, void.class, "s0"); 738 testUnreflect(Example.class, true, void.class, "pkg_s0"); 739 testUnreflect(Example.class, true, void.class, "pri_s0"); 740 741 testUnreflect(Example.class, true, Object.class, "s1", Object.class); 742 testUnreflect(Example.class, true, Object.class, "s2", int.class); 743 testUnreflect(Example.class, true, Object.class, "s3", long.class); 744 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class); 745 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class); 746 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class); 747 748 testUnreflect(Example.class, false, void.class, "v0"); 749 testUnreflect(Example.class, false, void.class, "pkg_v0"); 750 testUnreflect(Example.class, false, void.class, "pri_v0"); 751 testUnreflect(Example.class, false, Object.class, "v1", Object.class); 752 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class); 753 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class); 754 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class); 755 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class); 756 } 757 758 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable { 759 for (Object[] ac : accessCases(defc, name)) { 760 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params); 761 } 762 } 763 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 764 for (Object[] ac : accessCases(defc, name)) { 765 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 766 } 767 } 768 void testUnreflectMaybeSpecial(Class<?> specialCaller, 769 boolean positive, Lookup lookup, 770 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 771 countTest(positive); 772 MethodType type = MethodType.methodType(ret, params); 773 Method rmethod = defc.getDeclaredMethod(name, params); 774 MethodHandle target = null; 775 Exception noAccess = null; 776 boolean isStatic = (rcvc == null); 777 boolean isSpecial = (specialCaller != null); 778 try { 779 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 780 if (isSpecial) 781 target = lookup.in(specialCaller).unreflectSpecial(rmethod, specialCaller); 782 else 783 target = lookup.in(defc).unreflect(rmethod); 784 } catch (ReflectiveOperationException ex) { 785 noAccess = ex; 786 if (name.contains("bogus")) 787 assertTrue(noAccess instanceof NoSuchMethodException); 788 else 789 assertTrue(noAccess instanceof IllegalAccessException); 790 } 791 if (verbosity >= 3) 792 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type 793 +(!isSpecial ? "" : " specialCaller="+specialCaller) 794 +( isStatic ? "" : " receiver="+rcvc) 795 +" => "+target 796 +(noAccess == null ? "" : " !! "+noAccess)); 797 if (positive && noAccess != null) throw noAccess; 798 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 799 if (!positive) return; // negative test failed as expected 800 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers())); 801 Class<?>[] paramsMaybeWithSelf = params; 802 if (!isStatic) { 803 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params); 804 } 805 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf); 806 if (isStatic) { 807 assertEquals(typeMaybeWithSelf, target.type()); 808 } else { 809 if (isSpecial) 810 assertEquals(specialCaller, target.type().parameterType(0)); 811 else 812 assertEquals(defc, target.type().parameterType(0)); 813 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc)); 814 } 815 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf); 816 printCalled(target, name, argsMaybeWithSelf); 817 target.invokeWithArguments(argsMaybeWithSelf); 818 assertCalled(name, argsMaybeWithSelf); 819 if (verbosity >= 1) 820 System.out.print(':'); 821 } 822 823 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 824 for (Object[] ac : accessCases(defc, name, true)) { 825 Class<?> specialCaller = rcvc; 826 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 827 } 828 } 829 830 @Test 831 public void testUnreflectSpecial() throws Throwable { 832 if (CAN_SKIP_WORKING) return; 833 startTest("unreflectSpecial"); 834 testUnreflectSpecial(Example.class, Example.class, void.class, "v0"); 835 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0"); 836 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0"); 837 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0"); 838 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class); 839 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class); 840 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0"); 841 } 842 843 public static class HasFields { 844 boolean fZ = false; 845 byte fB = (byte)'B'; 846 short fS = (short)'S'; 847 char fC = 'C'; 848 int fI = 'I'; 849 long fJ = 'J'; 850 float fF = 'F'; 851 double fD = 'D'; 852 static boolean sZ = true; 853 static byte sB = 1+(byte)'B'; 854 static short sS = 1+(short)'S'; 855 static char sC = 1+'C'; 856 static int sI = 1+'I'; 857 static long sJ = 1+'J'; 858 static float sF = 1+'F'; 859 static double sD = 1+'D'; 860 861 Object fL = 'L'; 862 String fR = "R"; 863 static Object sL = 'M'; 864 static String sR = "S"; 865 866 static final Object[][] CASES; 867 static { 868 ArrayList<Object[]> cases = new ArrayList<Object[]>(); 869 Object types[][] = { 870 {'L',Object.class}, {'R',String.class}, 871 {'I',int.class}, {'J',long.class}, 872 {'F',float.class}, {'D',double.class}, 873 {'Z',boolean.class}, {'B',byte.class}, 874 {'S',short.class}, {'C',char.class}, 875 }; 876 HasFields fields = new HasFields(); 877 for (Object[] t : types) { 878 for (int kind = 0; kind <= 1; kind++) { 879 boolean isStatic = (kind != 0); 880 char btc = (Character)t[0]; 881 String name = (isStatic ? "s" : "f") + btc; 882 Class<?> type = (Class<?>) t[1]; 883 Object value; 884 Field field; 885 try { 886 field = HasFields.class.getDeclaredField(name); 887 } catch (Exception ex) { 888 throw new InternalError("no field HasFields."+name); 889 } 890 try { 891 value = field.get(fields); 892 } catch (Exception ex) { 893 throw new InternalError("cannot fetch field HasFields."+name); 894 } 895 if (type == float.class) { 896 float v = 'F'; 897 if (isStatic) v++; 898 assertTrue(value.equals(v)); 899 } 900 assertTrue(name.equals(field.getName())); 901 assertTrue(type.equals(field.getType())); 902 assertTrue(isStatic == (Modifier.isStatic(field.getModifiers()))); 903 cases.add(new Object[]{ field, value }); 904 } 905 } 906 cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class }); 907 cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class }); 908 CASES = cases.toArray(new Object[0][]); 909 } 910 } 911 912 static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10; 913 static boolean testModeMatches(int testMode, boolean isStatic) { 914 switch (testMode) { 915 case TEST_FIND_STATIC: return isStatic; 916 case TEST_FIND_FIELD: return !isStatic; 917 case TEST_UNREFLECT: return true; // unreflect matches both 918 } 919 throw new InternalError("testMode="+testMode); 920 } 921 922 @Test 923 public void testUnreflectGetter() throws Throwable { 924 startTest("unreflectGetter"); 925 testGetter(TEST_UNREFLECT); 926 } 927 @Test 928 public void testFindGetter() throws Throwable { 929 startTest("findGetter"); 930 testGetter(TEST_FIND_FIELD); 931 } 932 @Test 933 public void testFindStaticGetter() throws Throwable { 934 startTest("findStaticGetter"); 935 testGetter(TEST_FIND_STATIC); 936 } 937 public void testGetter(int testMode) throws Throwable { 938 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 939 for (Object[] c : HasFields.CASES) { 940 boolean positive = (c[1] != Error.class); 941 testGetter(positive, lookup, c[0], c[1], testMode); 942 } 943 testGetter(true, lookup, 944 new Object[]{ true, System.class, "out", java.io.PrintStream.class }, 945 System.out, testMode); 946 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 947 testGetter(false, lookup, 948 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 949 null, testMode); 950 } 951 } 952 public void testGetter(boolean positive, MethodHandles.Lookup lookup, 953 Object fieldRef, Object value, int testMode) throws Throwable { 954 testAccessor(positive, lookup, fieldRef, value, testMode); 955 } 956 957 public void testAccessor(boolean positive, MethodHandles.Lookup lookup, 958 Object fieldRef, Object value, int testMode0) throws Throwable { 959 boolean isGetter = ((testMode0 & TEST_SETTER) == 0); 960 int testMode = testMode0 & ~TEST_SETTER; 961 boolean isStatic; 962 Class<?> fclass; 963 String fname; 964 Class<?> ftype; 965 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null); 966 if (f != null) { 967 isStatic = Modifier.isStatic(f.getModifiers()); 968 fclass = f.getDeclaringClass(); 969 fname = f.getName(); 970 ftype = f.getType(); 971 } else { 972 Object[] scnt = (Object[]) fieldRef; 973 isStatic = (Boolean) scnt[0]; 974 fclass = (Class<?>) scnt[1]; 975 fname = (String) scnt[2]; 976 ftype = (Class<?>) scnt[3]; 977 try { 978 f = fclass.getDeclaredField(fname); 979 } catch (ReflectiveOperationException ex) { 980 f = null; 981 } 982 } 983 if (!testModeMatches(testMode, isStatic)) return; 984 if (f == null && testMode == TEST_UNREFLECT) return; 985 countTest(positive); 986 MethodType expType; 987 if (isGetter) 988 expType = MethodType.methodType(ftype, HasFields.class); 989 else 990 expType = MethodType.methodType(void.class, HasFields.class, ftype); 991 if (isStatic) expType = expType.dropParameterTypes(0, 1); 992 Exception noAccess = null; 993 MethodHandle mh; 994 try { 995 switch (testMode0) { 996 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; 997 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; 998 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; 999 case TEST_SETTER| 1000 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break; 1001 case TEST_SETTER| 1002 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break; 1003 case TEST_SETTER| 1004 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break; 1005 default: 1006 throw new InternalError("testMode="+testMode); 1007 } 1008 } catch (ReflectiveOperationException ex) { 1009 mh = null; 1010 noAccess = ex; 1011 if (fname.contains("bogus")) 1012 assertTrue(noAccess instanceof NoSuchFieldException); 1013 else 1014 assertTrue(noAccess instanceof IllegalAccessException); 1015 } 1016 if (verbosity >= 3) 1017 System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype 1018 +" => "+mh 1019 +(noAccess == null ? "" : " !! "+noAccess)); 1020 if (positive && noAccess != null) throw new RuntimeException(noAccess); 1021 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, mh != null); 1022 if (!positive) return; // negative test failed as expected 1023 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); 1024 1025 1026 assertSame(mh.type(), expType); 1027 assertNameStringContains(mh, fname); 1028 HasFields fields = new HasFields(); 1029 Object sawValue; 1030 Class<?> vtype = ftype; 1031 if (ftype != int.class) vtype = Object.class; 1032 if (isGetter) { 1033 mh = mh.asType(mh.type().generic() 1034 .changeReturnType(vtype)); 1035 } else { 1036 int last = mh.type().parameterCount() - 1; 1037 mh = mh.asType(mh.type().generic() 1038 .changeReturnType(void.class) 1039 .changeParameterType(last, vtype)); 1040 } 1041 if (f != null && f.getDeclaringClass() == HasFields.class) { 1042 assertEquals(f.get(fields), value); // clean to start with 1043 } 1044 if (isGetter) { 1045 Object expValue = value; 1046 for (int i = 0; i <= 1; i++) { 1047 if (isStatic) { 1048 if (ftype == int.class) 1049 sawValue = (int) mh.invokeExact(); // do these exactly 1050 else 1051 sawValue = mh.invokeExact(); 1052 } else { 1053 if (ftype == int.class) 1054 sawValue = (int) mh.invokeExact((Object) fields); 1055 else 1056 sawValue = mh.invokeExact((Object) fields); 1057 } 1058 assertEquals(sawValue, expValue); 1059 if (f != null && f.getDeclaringClass() == HasFields.class 1060 && !Modifier.isFinal(f.getModifiers())) { 1061 Object random = randomArg(ftype); 1062 f.set(fields, random); 1063 expValue = random; 1064 } else { 1065 break; 1066 } 1067 } 1068 } else { 1069 for (int i = 0; i <= 1; i++) { 1070 Object putValue = randomArg(ftype); 1071 if (isStatic) { 1072 if (ftype == int.class) 1073 mh.invokeExact((int)putValue); // do these exactly 1074 else 1075 mh.invokeExact(putValue); 1076 } else { 1077 if (ftype == int.class) 1078 mh.invokeExact((Object) fields, (int)putValue); 1079 else 1080 mh.invokeExact((Object) fields, putValue); 1081 } 1082 if (f != null && f.getDeclaringClass() == HasFields.class) { 1083 assertEquals(f.get(fields), putValue); 1084 } 1085 } 1086 } 1087 if (f != null && f.getDeclaringClass() == HasFields.class) { 1088 f.set(fields, value); // put it back 1089 } 1090 } 1091 1092 1093 @Test 1094 public void testUnreflectSetter() throws Throwable { 1095 startTest("unreflectSetter"); 1096 testSetter(TEST_UNREFLECT); 1097 } 1098 @Test 1099 public void testFindSetter() throws Throwable { 1100 startTest("findSetter"); 1101 testSetter(TEST_FIND_FIELD); 1102 } 1103 @Test 1104 public void testFindStaticSetter() throws Throwable { 1105 startTest("findStaticSetter"); 1106 testSetter(TEST_FIND_STATIC); 1107 } 1108 public void testSetter(int testMode) throws Throwable { 1109 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 1110 startTest("unreflectSetter"); 1111 for (Object[] c : HasFields.CASES) { 1112 boolean positive = (c[1] != Error.class); 1113 testSetter(positive, lookup, c[0], c[1], testMode); 1114 } 1115 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 1116 testSetter(false, lookup, 1117 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 1118 null, testMode); 1119 } 1120 } 1121 public void testSetter(boolean positive, MethodHandles.Lookup lookup, 1122 Object fieldRef, Object value, int testMode) throws Throwable { 1123 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER); 1124 } 1125 1126 @Test 1127 public void testArrayElementGetter() throws Throwable { 1128 startTest("arrayElementGetter"); 1129 testArrayElementGetterSetter(false); 1130 } 1131 1132 @Test 1133 public void testArrayElementSetter() throws Throwable { 1134 startTest("arrayElementSetter"); 1135 testArrayElementGetterSetter(true); 1136 } 1137 1138 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { 1139 testArrayElementGetterSetter(new Object[10], testSetter); 1140 testArrayElementGetterSetter(new String[10], testSetter); 1141 testArrayElementGetterSetter(new boolean[10], testSetter); 1142 testArrayElementGetterSetter(new byte[10], testSetter); 1143 testArrayElementGetterSetter(new char[10], testSetter); 1144 testArrayElementGetterSetter(new short[10], testSetter); 1145 testArrayElementGetterSetter(new int[10], testSetter); 1146 testArrayElementGetterSetter(new float[10], testSetter); 1147 testArrayElementGetterSetter(new long[10], testSetter); 1148 testArrayElementGetterSetter(new double[10], testSetter); 1149 } 1150 1151 public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable { 1152 countTest(true); 1153 if (verbosity >= 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]"); 1154 Class<?> arrayType = array.getClass(); 1155 Class<?> elemType = arrayType.getComponentType(); 1156 MethodType expType = !testSetter 1157 ? MethodType.methodType(elemType, arrayType, int.class) 1158 : MethodType.methodType(void.class, arrayType, int.class, elemType); 1159 MethodHandle mh = !testSetter 1160 ? MethodHandles.arrayElementGetter(arrayType) 1161 : MethodHandles.arrayElementSetter(arrayType); 1162 assertSame(mh.type(), expType); 1163 if (elemType != int.class && elemType != boolean.class) { 1164 // FIXME: change Integer.class and (Integer) below to int.class and (int) below. 1165 MethodType gtype = mh.type().generic().changeParameterType(1, Integer.class); 1166 if (testSetter) gtype = gtype.changeReturnType(void.class); 1167 mh = mh.asType(gtype); 1168 } 1169 Object sawValue, expValue; 1170 List<Object> model = array2list(array); 1171 int length = Array.getLength(array); 1172 for (int i = 0; i < length; i++) { 1173 // update array element 1174 Object random = randomArg(elemType); 1175 model.set(i, random); 1176 if (testSetter) { 1177 if (elemType == int.class) 1178 mh.invokeExact((int[]) array, i, (int)random); 1179 else if (elemType == boolean.class) 1180 mh.invokeExact((boolean[]) array, i, (boolean)random); 1181 else 1182 mh.invokeExact(array, (Integer)i, random); 1183 assertEquals(model, array2list(array)); 1184 } else { 1185 Array.set(array, i, random); 1186 } 1187 if (verbosity >= 5) { 1188 List<Object> array2list = array2list(array); 1189 System.out.println("a["+i+"]="+random+" => "+array2list); 1190 if (!array2list.equals(model)) 1191 System.out.println("*** != "+model); 1192 } 1193 // observe array element 1194 sawValue = Array.get(array, i); 1195 if (!testSetter) { 1196 expValue = sawValue; 1197 if (elemType == int.class) 1198 sawValue = (int) mh.invokeExact((int[]) array, i); 1199 else if (elemType == boolean.class) 1200 sawValue = (boolean) mh.invokeExact((boolean[]) array, i); 1201 else 1202 sawValue = mh.invokeExact(array, (Integer)i); 1203 assertEquals(sawValue, expValue); 1204 assertEquals(model, array2list(array)); 1205 } 1206 } 1207 } 1208 1209 List<Object> array2list(Object array) { 1210 int length = Array.getLength(array); 1211 ArrayList<Object> model = new ArrayList<Object>(length); 1212 for (int i = 0; i < length; i++) 1213 model.add(Array.get(array, i)); 1214 return model; 1215 } 1216 1217 static class Callee { 1218 static Object id() { return called("id"); } 1219 static Object id(Object x) { return called("id", x); } 1220 static Object id(Object x, Object y) { return called("id", x, y); } 1221 static Object id(Object x, Object y, Object z) { return called("id", x, y, z); } 1222 static Object id(Object... vx) { return called("id", vx); } 1223 static MethodHandle ofType(int n) { 1224 return ofType(Object.class, n); 1225 } 1226 static MethodHandle ofType(Class<?> rtype, int n) { 1227 if (n == -1) 1228 return ofType(MethodType.methodType(rtype, Object[].class)); 1229 return ofType(MethodType.genericMethodType(n).changeReturnType(rtype)); 1230 } 1231 static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) { 1232 return ofType(MethodType.methodType(rtype, ptypes)); 1233 } 1234 static MethodHandle ofType(MethodType type) { 1235 Class<?> rtype = type.returnType(); 1236 String pfx = ""; 1237 if (rtype != Object.class) 1238 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase(); 1239 String name = pfx+"id"; 1240 try { 1241 return PRIVATE.findStatic(Callee.class, name, type); 1242 } catch (Exception ex) { 1243 throw new RuntimeException(ex); 1244 } 1245 } 1246 } 1247 1248 @Test 1249 public void testConvertArguments() throws Throwable { 1250 if (CAN_SKIP_WORKING) return; 1251 startTest("convertArguments"); 1252 testConvert(Callee.ofType(1), null, "id", int.class); 1253 testConvert(Callee.ofType(1), null, "id", String.class); 1254 testConvert(Callee.ofType(1), null, "id", Integer.class); 1255 testConvert(Callee.ofType(1), null, "id", short.class); 1256 testConvert(Callee.ofType(1), null, "id", char.class); 1257 testConvert(Callee.ofType(1), null, "id", byte.class); 1258 } 1259 1260 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1261 testConvert(true, id, rtype, name, params); 1262 } 1263 1264 void testConvert(boolean positive, 1265 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1266 countTest(positive); 1267 MethodType idType = id.type(); 1268 if (rtype == null) rtype = idType.returnType(); 1269 for (int i = 0; i < params.length; i++) { 1270 if (params[i] == null) params[i] = idType.parameterType(i); 1271 } 1272 // simulate the pairwise conversion 1273 MethodType newType = MethodType.methodType(rtype, params); 1274 Object[] args = randomArgs(newType.parameterArray()); 1275 Object[] convArgs = args.clone(); 1276 for (int i = 0; i < args.length; i++) { 1277 Class<?> src = newType.parameterType(i); 1278 Class<?> dst = idType.parameterType(i); 1279 if (src != dst) 1280 convArgs[i] = castToWrapper(convArgs[i], dst); 1281 } 1282 Object convResult = id.invokeWithArguments(convArgs); 1283 { 1284 Class<?> dst = newType.returnType(); 1285 Class<?> src = idType.returnType(); 1286 if (src != dst) 1287 convResult = castToWrapper(convResult, dst); 1288 } 1289 MethodHandle target = null; 1290 RuntimeException error = null; 1291 try { 1292 target = id.asType(newType); 1293 } catch (RuntimeException ex) { 1294 error = ex; 1295 } 1296 if (verbosity >= 3) 1297 System.out.println("convert "+id+ " to "+newType+" => "+target 1298 +(error == null ? "" : " !! "+error)); 1299 if (positive && error != null) throw error; 1300 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 1301 if (!positive) return; // negative test failed as expected 1302 assertEquals(newType, target.type()); 1303 printCalled(target, id.toString(), args); 1304 Object result = target.invokeWithArguments(args); 1305 assertCalled(name, convArgs); 1306 assertEquals(convResult, result); 1307 if (verbosity >= 1) 1308 System.out.print(':'); 1309 } 1310 1311 @Test 1312 public void testVarargsCollector() throws Throwable { 1313 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called", 1314 MethodType.methodType(Object.class, String.class, Object[].class)); 1315 vac0 = vac0.bindTo("vac"); 1316 MethodHandle vac = vac0.asVarargsCollector(Object[].class); 1317 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1318 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1319 for (Class<?> at : new Class[] { Object.class, String.class, Integer.class }) { 1320 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); 1321 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); 1322 } 1323 } 1324 1325 @Test 1326 public void testPermuteArguments() throws Throwable { 1327 if (CAN_SKIP_WORKING) return; 1328 startTest("permuteArguments"); 1329 testPermuteArguments(4, Integer.class, 2, String.class, 0); 1330 testPermuteArguments(6, Integer.class, 0, null, 30); 1331 //testPermuteArguments(4, Integer.class, 2, long.class, 6); // FIXME Fail_7 1332 } 1333 public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable { 1334 if (verbosity >= 2) 1335 System.out.println("permuteArguments "+max+"*"+type1.getName() 1336 +(t2c==0?"":"/"+t2c+"*"+type2.getName()) 1337 +(dilution > 0 ? " with dilution "+dilution : "")); 1338 int t2pos = t2c == 0 ? 0 : 1; 1339 for (int inargs = t2pos+1; inargs <= max; inargs++) { 1340 Class<?>[] types = new Class<?>[inargs]; 1341 Arrays.fill(types, type1); 1342 if (t2c != 0) { 1343 // Fill in a middle range with type2: 1344 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2); 1345 } 1346 Object[] args = randomArgs(types); 1347 int numcases = 1; 1348 for (int outargs = 0; outargs <= max; outargs++) { 1349 if (outargs - inargs >= MAX_ARG_INCREASE) continue; 1350 int casStep = dilution + 1; 1351 // Avoid some common factors: 1352 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) || 1353 (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0)) 1354 casStep++; 1355 testPermuteArguments(args, types, outargs, numcases, casStep); 1356 numcases *= inargs; 1357 if (dilution > 10 && outargs >= 4) { 1358 int[] reorder = new int[outargs]; 1359 // Do some special patterns, which we probably missed. 1360 // Replication of a single argument or argument pair. 1361 for (int i = 0; i < inargs; i++) { 1362 Arrays.fill(reorder, i); 1363 testPermuteArguments(args, types, reorder); 1364 for (int d = 1; d <= 2; d++) { 1365 if (i + d >= inargs) continue; 1366 for (int j = 1; j < outargs; j += 2) 1367 reorder[j] += 1; 1368 testPermuteArguments(args, types, reorder); 1369 testPermuteArguments(args, types, reverse(reorder)); 1370 } 1371 } 1372 // Repetition of a sequence of 3 or more arguments. 1373 for (int i = 1; i < inargs; i++) { 1374 for (int len = 3; len <= inargs; len++) { 1375 for (int j = 0; j < outargs; j++) 1376 reorder[j] = (i + (j % len)) % inargs; 1377 testPermuteArguments(args, types, reorder); 1378 testPermuteArguments(args, types, reverse(reorder)); 1379 } 1380 } 1381 } 1382 } 1383 } 1384 } 1385 1386 public void testPermuteArguments(Object[] args, Class<?>[] types, 1387 int outargs, int numcases, int casStep) throws Throwable { 1388 int inargs = args.length; 1389 int[] reorder = new int[outargs]; 1390 for (int cas = 0; cas < numcases; cas += casStep) { 1391 for (int i = 0, c = cas; i < outargs; i++) { 1392 reorder[i] = c % inargs; 1393 c /= inargs; 1394 } 1395 testPermuteArguments(args, types, reorder); 1396 } 1397 } 1398 1399 static int[] reverse(int[] reorder) { 1400 reorder = reorder.clone(); 1401 for (int i = 0, imax = reorder.length / 2; i < imax; i++) { 1402 int j = reorder.length - 1 - i; 1403 int tem = reorder[i]; 1404 reorder[i] = reorder[j]; 1405 reorder[j] = tem; 1406 } 1407 return reorder; 1408 } 1409 1410 void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable { 1411 countTest(); 1412 if (args == null && types == null) { 1413 int max = 0; 1414 for (int j : reorder) { 1415 if (max < j) max = j; 1416 } 1417 args = randomArgs(max+1, Integer.class); 1418 } 1419 if (args == null) { 1420 args = randomArgs(types); 1421 } 1422 if (types == null) { 1423 types = new Class<?>[args.length]; 1424 for (int i = 0; i < args.length; i++) 1425 types[i] = args[i].getClass(); 1426 } 1427 int inargs = args.length, outargs = reorder.length; 1428 assertTrue(inargs == types.length); 1429 if (verbosity >= 3) 1430 System.out.println("permuteArguments "+Arrays.toString(reorder)); 1431 Object[] permArgs = new Object[outargs]; 1432 Class<?>[] permTypes = new Class<?>[outargs]; 1433 for (int i = 0; i < outargs; i++) { 1434 permArgs[i] = args[reorder[i]]; 1435 permTypes[i] = types[reorder[i]]; 1436 } 1437 if (verbosity >= 4) { 1438 System.out.println("in args: "+Arrays.asList(args)); 1439 System.out.println("out args: "+Arrays.asList(permArgs)); 1440 System.out.println("in types: "+Arrays.asList(types)); 1441 System.out.println("out types: "+Arrays.asList(permTypes)); 1442 } 1443 MethodType inType = MethodType.methodType(Object.class, types); 1444 MethodType outType = MethodType.methodType(Object.class, permTypes); 1445 MethodHandle target = varargsList(outargs).asType(outType); 1446 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder); 1447 if (verbosity >= 5) System.out.println("newTarget = "+newTarget); 1448 Object result = newTarget.invokeWithArguments(args); 1449 Object expected = Arrays.asList(permArgs); 1450 if (!expected.equals(result)) { 1451 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types)); 1452 System.out.println("in args: "+Arrays.asList(args)); 1453 System.out.println("out args: "+expected); 1454 System.out.println("bad args: "+result); 1455 } 1456 assertEquals(expected, result); 1457 } 1458 1459 1460 @Test 1461 public void testSpreadArguments() throws Throwable { 1462 if (CAN_SKIP_WORKING) return; 1463 startTest("spreadArguments"); 1464 for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { 1465 if (verbosity >= 3) 1466 System.out.println("spreadArguments "+argType); 1467 // FIXME: enable _adapter_spread_args and fix Fail_2 1468 for (int nargs = 0; nargs < 10; nargs++) { 1469 if (argType == int.class && nargs >= 6) continue; // FIXME Fail_1 1470 for (int pos = 0; pos < nargs; pos++) { 1471 if (argType == int.class && pos > 0) continue; // FIXME Fail_3 1472 testSpreadArguments(argType, pos, nargs); 1473 } 1474 } 1475 } 1476 } 1477 public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable { 1478 countTest(); 1479 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); 1480 MethodHandle target2 = varargsArray(arrayType, nargs); 1481 MethodHandle target = target2.asType(target2.type().generic()); 1482 if (verbosity >= 3) 1483 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]"); 1484 Object[] args = randomArgs(target2.type().parameterArray()); 1485 // make sure the target does what we think it does: 1486 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) { 1487 Object[] check = (Object[]) (Object) target.invokeWithArguments(args); 1488 assertArrayEquals(args, check); 1489 switch (nargs) { 1490 case 0: 1491 check = (Object[]) (Object) target.invokeExact(); 1492 assertArrayEquals(args, check); 1493 break; 1494 case 1: 1495 check = (Object[]) (Object) target.invokeExact(args[0]); 1496 assertArrayEquals(args, check); 1497 break; 1498 case 2: 1499 check = (Object[]) (Object) target.invokeExact(args[0], args[1]); 1500 assertArrayEquals(args, check); 1501 break; 1502 } 1503 } 1504 List<Class<?>> newParams = new ArrayList<Class<?>>(target2.type().parameterList()); 1505 { // modify newParams in place 1506 List<Class<?>> spreadParams = newParams.subList(pos, nargs); 1507 spreadParams.clear(); spreadParams.add(arrayType); 1508 } 1509 MethodType newType = MethodType.methodType(arrayType, newParams); 1510 MethodHandle result = target2.asSpreader(arrayType, nargs-pos); 1511 assert(result.type() == newType) : Arrays.asList(result, newType); 1512 result = result.asType(newType.generic()); 1513 Object returnValue; 1514 if (pos == 0) { 1515 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 1516 returnValue = result.invokeExact(args2); 1517 } else { 1518 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1); 1519 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 1520 returnValue = result.invokeWithArguments(args1); 1521 } 1522 String argstr = Arrays.toString(args); 1523 if (!argType.isPrimitive()) { 1524 Object[] rv = (Object[]) returnValue; 1525 String rvs = Arrays.toString(rv); 1526 if (!Arrays.equals(args, rv)) { 1527 System.out.println("method: "+result); 1528 System.out.println("expected: "+argstr); 1529 System.out.println("returned: "+rvs); 1530 assertArrayEquals(args, rv); 1531 } 1532 } else if (argType == int.class) { 1533 String rvs = Arrays.toString((int[]) returnValue); 1534 if (!argstr.equals(rvs)) { 1535 System.out.println("method: "+result); 1536 System.out.println("expected: "+argstr); 1537 System.out.println("returned: "+rvs); 1538 assertEquals(argstr, rvs); 1539 } 1540 } else if (argType == long.class) { 1541 String rvs = Arrays.toString((long[]) returnValue); 1542 if (!argstr.equals(rvs)) { 1543 System.out.println("method: "+result); 1544 System.out.println("expected: "+argstr); 1545 System.out.println("returned: "+rvs); 1546 assertEquals(argstr, rvs); 1547 } 1548 } else { 1549 // cannot test... 1550 } 1551 } 1552 1553 @Test 1554 public void testCollectArguments() throws Throwable { 1555 if (CAN_SKIP_WORKING) return; 1556 startTest("collectArguments"); 1557 for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { 1558 if (verbosity >= 3) 1559 System.out.println("collectArguments "+argType); 1560 for (int nargs = 0; nargs < 10; nargs++) { 1561 for (int pos = 0; pos < nargs; pos++) { 1562 if (argType == int.class) continue; // FIXME Fail_4 1563 testCollectArguments(argType, pos, nargs); 1564 } 1565 } 1566 } 1567 } 1568 public void testCollectArguments(Class<?> argType, int pos, int nargs) throws Throwable { 1569 countTest(); 1570 // fake up a MH with the same type as the desired adapter: 1571 MethodHandle fake = varargsArray(nargs); 1572 fake = changeArgTypes(fake, argType); 1573 MethodType newType = fake.type(); 1574 Object[] args = randomArgs(newType.parameterArray()); 1575 // here is what should happen: 1576 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1); 1577 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length); 1578 // here is the MH which will witness the collected argument tail: 1579 MethodHandle target = varargsArray(pos+1); 1580 target = changeArgTypes(target, 0, pos, argType); 1581 target = changeArgTypes(target, pos, pos+1, Object[].class); 1582 if (verbosity >= 3) 1583 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]"); 1584 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType); 1585 Object[] returnValue = (Object[]) result.invokeWithArguments(args); 1586// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]); 1587// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]); 1588// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]); 1589 assertArrayEquals(collectedArgs, returnValue); 1590 } 1591 1592 @Test 1593 public void testInsertArguments() throws Throwable { 1594 if (CAN_SKIP_WORKING) return; 1595 startTest("insertArguments"); 1596 for (int nargs = 0; nargs <= 4; nargs++) { 1597 for (int ins = 0; ins <= 4; ins++) { 1598 if (ins > MAX_ARG_INCREASE) continue; // FIXME Fail_6 1599 for (int pos = 0; pos <= nargs; pos++) { 1600 testInsertArguments(nargs, pos, ins); 1601 } 1602 } 1603 } 1604 } 1605 1606 void testInsertArguments(int nargs, int pos, int ins) throws Throwable { 1607 countTest(); 1608 MethodHandle target = varargsArray(nargs + ins); 1609 Object[] args = randomArgs(target.type().parameterArray()); 1610 List<Object> resList = Arrays.asList(args); 1611 List<Object> argsToPass = new ArrayList<Object>(resList); 1612 List<Object> argsToInsert = argsToPass.subList(pos, pos + ins); 1613 if (verbosity >= 3) 1614 System.out.println("insert: "+argsToInsert+" into "+target); 1615 MethodHandle target2 = MethodHandles.insertArguments(target, pos, 1616 (Object[]) argsToInsert.toArray()); 1617 argsToInsert.clear(); // remove from argsToInsert 1618 Object res2 = target2.invokeWithArguments(argsToPass); 1619 Object res2List = Arrays.asList((Object[])res2); 1620 if (verbosity >= 3) 1621 System.out.println("result: "+res2List); 1622 //if (!resList.equals(res2List)) 1623 // System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List); 1624 assertEquals(resList, res2List); 1625 } 1626 1627 @Test 1628 public void testFilterReturnValue() throws Throwable { 1629 if (CAN_SKIP_WORKING) return; 1630 startTest("filterReturnValue"); 1631 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); 1632 assertTrue(List.class.isAssignableFrom(classOfVCList)); 1633 for (int nargs = 0; nargs <= 3; nargs++) { 1634 for (Class<?> rtype : new Class[] { Object.class, 1635 List.class, 1636 int.class, 1637 //byte.class, //FIXME: add this 1638 //long.class, //FIXME: add this 1639 CharSequence.class, 1640 String.class }) { 1641 testFilterReturnValue(nargs, rtype); 1642 } 1643 } 1644 } 1645 1646 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable { 1647 countTest(); 1648 MethodHandle target = varargsList(nargs, rtype); 1649 MethodHandle filter; 1650 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class)) 1651 filter = varargsList(1); // add another layer of list-ness 1652 else 1653 filter = MethodHandles.identity(rtype); 1654 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype)); 1655 Object[] argsToPass = randomArgs(nargs, Object.class); 1656 if (verbosity >= 3) 1657 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter); 1658 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter); 1659 if (verbosity >= 4) 1660 System.out.println("filtered target: "+target2); 1661 // Simulate expected effect of filter on return value: 1662 Object unfiltered = target.invokeWithArguments(argsToPass); 1663 Object expected = filter.invokeWithArguments(unfiltered); 1664 if (verbosity >= 4) 1665 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName()); 1666 if (verbosity >= 4) 1667 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName()); 1668 Object result = target2.invokeWithArguments(argsToPass); 1669 if (verbosity >= 3) 1670 System.out.println("result: "+result+" : "+result.getClass().getSimpleName()); 1671 if (!expected.equals(result)) 1672 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1673 assertEquals(expected, result); 1674 } 1675 1676 @Test 1677 public void testFilterArguments() throws Throwable { 1678 if (CAN_SKIP_WORKING) return; 1679 startTest("filterArguments"); 1680 for (int nargs = 1; nargs <= 6; nargs++) { 1681 for (int pos = 0; pos < nargs; pos++) { 1682 testFilterArguments(nargs, pos); 1683 } 1684 } 1685 } 1686 1687 void testFilterArguments(int nargs, int pos) throws Throwable { 1688 countTest(); 1689 MethodHandle target = varargsList(nargs); 1690 MethodHandle filter = varargsList(1); 1691 filter = filter.asType(filter.type().generic()); 1692 Object[] argsToPass = randomArgs(nargs, Object.class); 1693 if (verbosity >= 3) 1694 System.out.println("filter "+target+" at "+pos+" with "+filter); 1695 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter); 1696 // Simulate expected effect of filter on arglist: 1697 Object[] filteredArgs = argsToPass.clone(); 1698 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]); 1699 List<Object> expected = Arrays.asList(filteredArgs); 1700 Object result = target2.invokeWithArguments(argsToPass); 1701 if (verbosity >= 3) 1702 System.out.println("result: "+result); 1703 if (!expected.equals(result)) 1704 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1705 assertEquals(expected, result); 1706 } 1707 1708 @Test 1709 public void testFoldArguments() throws Throwable { 1710 if (CAN_SKIP_WORKING) return; 1711 startTest("foldArguments"); 1712 for (int nargs = 0; nargs <= 4; nargs++) { 1713 for (int fold = 0; fold <= nargs; fold++) { 1714 for (int pos = 0; pos <= nargs; pos++) { 1715 testFoldArguments(nargs, pos, fold); 1716 } 1717 } 1718 } 1719 } 1720 1721 void testFoldArguments(int nargs, int pos, int fold) throws Throwable { 1722 if (pos != 0) return; // can fold only at pos=0 for now 1723 countTest(); 1724 MethodHandle target = varargsList(1 + nargs); 1725 MethodHandle combine = varargsList(fold).asType(MethodType.genericMethodType(fold)); 1726 List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class)); 1727 if (verbosity >= 3) 1728 System.out.println("fold "+target+" with "+combine); 1729 MethodHandle target2 = MethodHandles.foldArguments(target, combine); 1730 // Simulate expected effect of combiner on arglist: 1731 List<Object> expected = new ArrayList<Object>(argsToPass); 1732 List<Object> argsToFold = expected.subList(pos, pos + fold); 1733 if (verbosity >= 3) 1734 System.out.println("fold: "+argsToFold+" into "+target2); 1735 Object foldedArgs = combine.invokeWithArguments(argsToFold); 1736 argsToFold.add(0, foldedArgs); 1737 Object result = target2.invokeWithArguments(argsToPass); 1738 if (verbosity >= 3) 1739 System.out.println("result: "+result); 1740 if (!expected.equals(result)) 1741 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); 1742 assertEquals(expected, result); 1743 } 1744 1745 @Test 1746 public void testDropArguments() throws Throwable { 1747 if (CAN_SKIP_WORKING) return; 1748 startTest("dropArguments"); 1749 for (int nargs = 0; nargs <= 4; nargs++) { 1750 for (int drop = 1; drop <= 4; drop++) { 1751 for (int pos = 0; pos <= nargs; pos++) { 1752 testDropArguments(nargs, pos, drop); 1753 } 1754 } 1755 } 1756 } 1757 1758 void testDropArguments(int nargs, int pos, int drop) throws Throwable { 1759 countTest(); 1760 MethodHandle target = varargsArray(nargs); 1761 Object[] args = randomArgs(target.type().parameterArray()); 1762 MethodHandle target2 = MethodHandles.dropArguments(target, pos, 1763 Collections.nCopies(drop, Object.class).toArray(new Class[0])); 1764 List<Object> resList = Arrays.asList(args); 1765 List<Object> argsToDrop = new ArrayList<Object>(resList); 1766 for (int i = drop; i > 0; i--) { 1767 argsToDrop.add(pos, "blort#"+i); 1768 } 1769 Object res2 = target2.invokeWithArguments(argsToDrop); 1770 Object res2List = Arrays.asList((Object[])res2); 1771 //if (!resList.equals(res2List)) 1772 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); 1773 assertEquals(resList, res2List); 1774 } 1775 1776 @Test 1777 public void testInvokers() throws Throwable { 1778 if (CAN_SKIP_WORKING) return; 1779 startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker"); 1780 // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker 1781 Set<MethodType> done = new HashSet<MethodType>(); 1782 for (int i = 0; i <= 6; i++) { 1783 MethodType gtype = MethodType.genericMethodType(i); 1784 for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { 1785 for (int j = -1; j < i; j++) { 1786 MethodType type = gtype; 1787 if (j < 0) 1788 type = type.changeReturnType(argType); 1789 else if (argType == void.class) 1790 continue; 1791 else 1792 type = type.changeParameterType(j, argType); 1793 if (argType.isPrimitive() && j != i-1) continue; // FIXME Fail_5 1794 if (done.add(type)) 1795 testInvokers(type); 1796 MethodType vtype = type.changeReturnType(void.class); 1797 if (done.add(vtype)) 1798 testInvokers(vtype); 1799 } 1800 } 1801 } 1802 } 1803 1804 public void testInvokers(MethodType type) throws Throwable { 1805 if (verbosity >= 3) 1806 System.out.println("test invokers for "+type); 1807 int nargs = type.parameterCount(); 1808 boolean testRetCode = type.returnType() != void.class; 1809 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee", 1810 MethodType.genericMethodType(0, true)); 1811 assertTrue(target.isVarargsCollector()); 1812 target = target.asType(type); 1813 Object[] args = randomArgs(type.parameterArray()); 1814 List<Object> targetPlusArgs = new ArrayList<Object>(Arrays.asList(args)); 1815 targetPlusArgs.add(0, target); 1816 int code = (Integer) invokee(args); 1817 Object log = logEntry("invokee", args); 1818 assertEquals(log.hashCode(), code); 1819 assertCalled("invokee", args); 1820 MethodHandle inv; 1821 Object result; 1822 // exact invoker 1823 countTest(); 1824 calledLog.clear(); 1825 inv = MethodHandles.exactInvoker(type); 1826 result = inv.invokeWithArguments(targetPlusArgs); 1827 if (testRetCode) assertEquals(code, result); 1828 assertCalled("invokee", args); 1829 // generic invoker 1830 countTest(); 1831 inv = MethodHandles.invoker(type); 1832 if (nargs <= 3 && type == type.generic()) { 1833 calledLog.clear(); 1834 switch (nargs) { 1835 case 0: 1836 result = inv.invokeExact(target); 1837 break; 1838 case 1: 1839 result = inv.invokeExact(target, args[0]); 1840 break; 1841 case 2: 1842 result = inv.invokeExact(target, args[0], args[1]); 1843 break; 1844 case 3: 1845 result = inv.invokeExact(target, args[0], args[1], args[2]); 1846 break; 1847 } 1848 if (testRetCode) assertEquals(code, result); 1849 assertCalled("invokee", args); 1850 } 1851 calledLog.clear(); 1852 result = inv.invokeWithArguments(targetPlusArgs); 1853 if (testRetCode) assertEquals(code, result); 1854 assertCalled("invokee", args); 1855 // varargs invoker #0 1856 calledLog.clear(); 1857 inv = MethodHandles.spreadInvoker(type, 0); 1858 if (type.returnType() == Object.class) { 1859 result = inv.invokeExact(target, args); 1860 } else if (type.returnType() == void.class) { 1861 result = null; inv.invokeExact(target, args); 1862 } else { 1863 result = inv.invokeWithArguments(target, (Object) args); 1864 } 1865 if (testRetCode) assertEquals(code, result); 1866 assertCalled("invokee", args); 1867 if (nargs >= 1 && type == type.generic()) { 1868 // varargs invoker #1 1869 calledLog.clear(); 1870 inv = MethodHandles.spreadInvoker(type, 1); 1871 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs)); 1872 if (testRetCode) assertEquals(code, result); 1873 assertCalled("invokee", args); 1874 } 1875 if (nargs >= 2 && type == type.generic()) { 1876 // varargs invoker #2 1877 calledLog.clear(); 1878 inv = MethodHandles.spreadInvoker(type, 2); 1879 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs)); 1880 if (testRetCode) assertEquals(code, result); 1881 assertCalled("invokee", args); 1882 } 1883 if (nargs >= 3 && type == type.generic()) { 1884 // varargs invoker #3 1885 calledLog.clear(); 1886 inv = MethodHandles.spreadInvoker(type, 3); 1887 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs)); 1888 if (testRetCode) assertEquals(code, result); 1889 assertCalled("invokee", args); 1890 } 1891 for (int k = 0; k <= nargs; k++) { 1892 // varargs invoker #0..N 1893 countTest(); 1894 calledLog.clear(); 1895 inv = MethodHandles.spreadInvoker(type, k); 1896 MethodType expType = (type.dropParameterTypes(k, nargs) 1897 .appendParameterTypes(Object[].class) 1898 .insertParameterTypes(0, MethodHandle.class)); 1899 assertEquals(expType, inv.type()); 1900 List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs); 1901 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs); 1902 Object[] tail = tailList.toArray(); 1903 tailList.clear(); tailList.add(tail); 1904 result = inv.invokeWithArguments(targetPlusVarArgs); 1905 if (testRetCode) assertEquals(code, result); 1906 assertCalled("invokee", args); 1907 } 1908 1909 // dynamic invoker 1910 countTest(); 1911 CallSite site = new MutableCallSite(type); 1912 inv = site.dynamicInvoker(); 1913 1914 // see if we get the result of the original target: 1915 try { 1916 result = inv.invokeWithArguments(args); 1917 assertTrue("should not reach here", false); 1918 } catch (IllegalStateException ex) { 1919 String msg = ex.getMessage(); 1920 assertTrue(msg, msg.contains("site")); 1921 } 1922 1923 // set new target after invoker is created, to make sure we track target 1924 site.setTarget(target); 1925 calledLog.clear(); 1926 result = inv.invokeWithArguments(args); 1927 if (testRetCode) assertEquals(code, result); 1928 assertCalled("invokee", args); 1929 } 1930 1931 static Object invokee(Object... args) { 1932 return called("invokee", args).hashCode(); 1933 } 1934 1935 private static final String MISSING_ARG = "missingArg"; 1936 static Object targetIfEquals() { 1937 return called("targetIfEquals"); 1938 } 1939 static Object fallbackIfNotEquals() { 1940 return called("fallbackIfNotEquals"); 1941 } 1942 static Object targetIfEquals(Object x) { 1943 assertEquals(x, MISSING_ARG); 1944 return called("targetIfEquals", x); 1945 } 1946 static Object fallbackIfNotEquals(Object x) { 1947 assertFalse(x.toString(), x.equals(MISSING_ARG)); 1948 return called("fallbackIfNotEquals", x); 1949 } 1950 static Object targetIfEquals(Object x, Object y) { 1951 assertEquals(x, y); 1952 return called("targetIfEquals", x, y); 1953 } 1954 static Object fallbackIfNotEquals(Object x, Object y) { 1955 assertFalse(x.toString(), x.equals(y)); 1956 return called("fallbackIfNotEquals", x, y); 1957 } 1958 static Object targetIfEquals(Object x, Object y, Object z) { 1959 assertEquals(x, y); 1960 return called("targetIfEquals", x, y, z); 1961 } 1962 static Object fallbackIfNotEquals(Object x, Object y, Object z) { 1963 assertFalse(x.toString(), x.equals(y)); 1964 return called("fallbackIfNotEquals", x, y, z); 1965 } 1966 1967 @Test 1968 public void testGuardWithTest() throws Throwable { 1969 if (CAN_SKIP_WORKING) return; 1970 startTest("guardWithTest"); 1971 for (int nargs = 0; nargs <= 3; nargs++) { 1972 if (nargs != 2) continue; // FIXME: test more later 1973 testGuardWithTest(nargs, Object.class); 1974 testGuardWithTest(nargs, String.class); 1975 } 1976 } 1977 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 1978 countTest(); 1979 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 1980 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs)); 1981 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs)); 1982 while (test.type().parameterCount() < nargs) 1983 test = MethodHandles.dropArguments(test, test.type().parameterCount()-1, Object.class); 1984 while (test.type().parameterCount() > nargs) 1985 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 1986 if (argClass != Object.class) { 1987 test = changeArgTypes(test, argClass); 1988 target = changeArgTypes(target, argClass); 1989 fallback = changeArgTypes(fallback, argClass); 1990 } 1991 MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback); 1992 assertEquals(target.type(), mh.type()); 1993 Object[][] argLists = { 1994 { }, 1995 { "foo" }, { MISSING_ARG }, 1996 { "foo", "foo" }, { "foo", "bar" }, 1997 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 1998 }; 1999 for (Object[] argList : argLists) { 2000 if (argList.length != nargs) continue; 2001 boolean equals; 2002 switch (nargs) { 2003 case 0: equals = true; break; 2004 case 1: equals = MISSING_ARG.equals(argList[0]); break; 2005 default: equals = argList[0].equals(argList[1]); break; 2006 } 2007 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 2008 if (verbosity >= 3) 2009 System.out.println(logEntry(willCall, argList)); 2010 Object result = mh.invokeWithArguments(argList); 2011 assertCalled(willCall, argList); 2012 } 2013 } 2014 2015 @Test 2016 public void testCatchException() throws Throwable { 2017 if (CAN_SKIP_WORKING) return; 2018 startTest("catchException"); 2019 for (int nargs = 2; nargs <= 6; nargs++) { 2020 for (int ti = 0; ti <= 1; ti++) { 2021 boolean throwIt = (ti != 0); 2022 testCatchException(int.class, new ClassCastException("testing"), throwIt, nargs); 2023 testCatchException(void.class, new java.io.IOException("testing"), throwIt, nargs); 2024 testCatchException(String.class, new LinkageError("testing"), throwIt, nargs); 2025 } 2026 } 2027 } 2028 2029 private static <T extends Throwable> 2030 Object throwOrReturn(Object normal, T exception) throws T { 2031 if (exception != null) throw exception; 2032 return normal; 2033 } 2034 2035 void testCatchException(Class<?> returnType, Throwable thrown, boolean throwIt, int nargs) throws Throwable { 2036 countTest(); 2037 if (verbosity >= 3) 2038 System.out.println("catchException rt="+returnType+" throw="+throwIt+" nargs="+nargs); 2039 Class<? extends Throwable> exType = thrown.getClass(); 2040 MethodHandle throwOrReturn 2041 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn", 2042 MethodType.methodType(Object.class, Object.class, Throwable.class)); 2043 MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2)); 2044 while (thrower.type().parameterCount() < nargs) 2045 thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class); 2046 MethodHandle catcher = varargsList(1+nargs).asType(MethodType.genericMethodType(1+nargs)); 2047 MethodHandle target = MethodHandles.catchException(thrower, 2048 thrown.getClass(), catcher); 2049 assertEquals(thrower.type(), target.type()); 2050 //System.out.println("catching with "+target+" : "+throwOrReturn); 2051 Object[] args = randomArgs(nargs, Object.class); 2052 args[1] = (throwIt ? thrown : null); 2053 Object returned = target.invokeWithArguments(args); 2054 //System.out.println("return from "+target+" : "+returned); 2055 if (!throwIt) { 2056 assertSame(args[0], returned); 2057 } else { 2058 List<Object> catchArgs = new ArrayList<Object>(Arrays.asList(args)); 2059 catchArgs.add(0, thrown); 2060 assertEquals(catchArgs, returned); 2061 } 2062 } 2063 2064 @Test 2065 public void testThrowException() throws Throwable { 2066 if (CAN_SKIP_WORKING) return; 2067 startTest("throwException"); 2068 testThrowException(int.class, new ClassCastException("testing")); 2069 testThrowException(void.class, new java.io.IOException("testing")); 2070 testThrowException(String.class, new LinkageError("testing")); 2071 } 2072 2073 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 2074 countTest(); 2075 Class<? extends Throwable> exType = thrown.getClass(); 2076 MethodHandle target = MethodHandles.throwException(returnType, exType); 2077 //System.out.println("throwing with "+target+" : "+thrown); 2078 MethodType expectedType = MethodType.methodType(returnType, exType); 2079 assertEquals(expectedType, target.type()); 2080 target = target.asType(target.type().generic()); 2081 Throwable caught = null; 2082 try { 2083 Object res = target.invokeExact((Object) thrown); 2084 fail("got "+res+" instead of throwing "+thrown); 2085 } catch (Throwable ex) { 2086 if (ex != thrown) { 2087 if (ex instanceof Error) throw (Error)ex; 2088 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 2089 } 2090 caught = ex; 2091 } 2092 assertSame(thrown, caught); 2093 } 2094 2095 @Test 2096 public void testCastFailure() throws Throwable { 2097 if (CAN_SKIP_WORKING) return; 2098 startTest("testCastFailure"); 2099 testCastFailure("cast/argument", 11000); 2100 testCastFailure("unbox/argument", 11000); 2101 testCastFailure("cast/return", 11000); 2102 testCastFailure("unbox/return", 11000); 2103 } 2104 2105 static class Surprise { 2106 public MethodHandle asMethodHandle() { 2107 return VALUE.bindTo(this); 2108 } 2109 Object value(Object x) { 2110 trace("value", x); 2111 if (boo != null) return boo; 2112 return x; 2113 } 2114 Object boo; 2115 void boo(Object x) { boo = x; } 2116 2117 static void trace(String x, Object y) { 2118 if (verbosity > 8) System.out.println(x+"="+y); 2119 } 2120 static Object refIdentity(Object x) { trace("ref.x", x); return x; } 2121 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; } 2122 static int intIdentity(int x) { trace("int.x", x); return x; } 2123 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY; 2124 static { 2125 try { 2126 VALUE = PRIVATE.findVirtual( 2127 Surprise.class, "value", 2128 MethodType.methodType(Object.class, Object.class)); 2129 REF_IDENTITY = PRIVATE.findStatic( 2130 Surprise.class, "refIdentity", 2131 MethodType.methodType(Object.class, Object.class)); 2132 BOX_IDENTITY = PRIVATE.findStatic( 2133 Surprise.class, "boxIdentity", 2134 MethodType.methodType(Integer.class, Integer.class)); 2135 INT_IDENTITY = PRIVATE.findStatic( 2136 Surprise.class, "intIdentity", 2137 MethodType.methodType(int.class, int.class)); 2138 } catch (Exception ex) { 2139 throw new RuntimeException(ex); 2140 } 2141 } 2142 } 2143 2144 void testCastFailure(String mode, int okCount) throws Throwable { 2145 countTest(false); 2146 if (verbosity > 2) System.out.println("mode="+mode); 2147 Surprise boo = new Surprise(); 2148 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0; 2149 if (mode.endsWith("/return")) { 2150 if (mode.equals("unbox/return")) { 2151 // fail on return to ((Integer)surprise).intValue 2152 surprise = surprise.asType(MethodType.methodType(int.class, Object.class)); 2153 identity = identity.asType(MethodType.methodType(int.class, Object.class)); 2154 } else if (mode.equals("cast/return")) { 2155 // fail on return to (Integer)surprise 2156 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class)); 2157 identity = identity.asType(MethodType.methodType(Integer.class, Object.class)); 2158 } 2159 } else if (mode.endsWith("/argument")) { 2160 MethodHandle callee = null; 2161 if (mode.equals("unbox/argument")) { 2162 // fail on handing surprise to int argument 2163 callee = Surprise.INT_IDENTITY; 2164 } else if (mode.equals("cast/argument")) { 2165 // fail on handing surprise to Integer argument 2166 callee = Surprise.BOX_IDENTITY; 2167 } 2168 if (callee != null) { 2169 callee = callee.asType(MethodType.genericMethodType(1)); 2170 surprise = MethodHandles.filterArguments(callee, 0, surprise); 2171 identity = MethodHandles.filterArguments(callee, 0, identity); 2172 } 2173 } 2174 assertNotSame(mode, surprise, surprise0); 2175 identity = identity.asType(MethodType.genericMethodType(1)); 2176 surprise = surprise.asType(MethodType.genericMethodType(1)); 2177 Object x = 42; 2178 for (int i = 0; i < okCount; i++) { 2179 Object y = identity.invokeExact(x); 2180 assertEquals(x, y); 2181 Object z = surprise.invokeExact(x); 2182 assertEquals(x, z); 2183 } 2184 boo.boo("Boo!"); 2185 Object y = identity.invokeExact(x); 2186 assertEquals(x, y); 2187 try { 2188 Object z = surprise.invokeExact(x); 2189 System.out.println("Failed to throw; got z="+z); 2190 assertTrue(false); 2191 } catch (ClassCastException ex) { 2192 if (verbosity > 2) 2193 System.out.println("caught "+ex); 2194 if (verbosity > 3) 2195 ex.printStackTrace(); 2196 assertTrue(true); // all is well 2197 } 2198 } 2199 2200 static Example userMethod(Object o, String s, int i) { 2201 called("userMethod", o, s, i); 2202 return null; 2203 } 2204 2205 @Test 2206 public void testUserClassInSignature() throws Throwable { 2207 if (CAN_SKIP_WORKING) return; 2208 startTest("testUserClassInSignature"); 2209 Lookup lookup = MethodHandles.lookup(); 2210 String name; MethodType mt; MethodHandle mh; 2211 Object[] args; 2212 2213 // Try a static method. 2214 name = "userMethod"; 2215 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 2216 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 2217 assertEquals(mt, mh.type()); 2218 assertEquals(Example.class, mh.type().returnType()); 2219 args = randomArgs(mh.type().parameterArray()); 2220 mh.invokeWithArguments(args); 2221 assertCalled(name, args); 2222 2223 // Try a virtual method. 2224 name = "v2"; 2225 mt = MethodType.methodType(Object.class, Object.class, int.class); 2226 mh = lookup.findVirtual(Example.class, name, mt); 2227 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 2228 assertTrue(mh.type().parameterList().contains(Example.class)); 2229 args = randomArgs(mh.type().parameterArray()); 2230 mh.invokeWithArguments(args); 2231 assertCalled(name, args); 2232 } 2233 2234 static void runForRunnable() { 2235 called("runForRunnable"); 2236 } 2237 private interface Fooable { 2238 Object foo(Fooable x, Object y); 2239 // this is for randomArg: 2240 public class Impl implements Fooable { 2241 public Object foo(Fooable x, Object y) { 2242 throw new RuntimeException("do not call"); 2243 } 2244 final String name; 2245 public Impl() { name = "Fooable#"+nextArg(); } 2246 @Override public String toString() { return name; } 2247 } 2248 } 2249 static Object fooForFooable(Fooable x, Object y) { 2250 return called("fooForFooable", x, y); 2251 } 2252 private static class MyCheckedException extends Exception { 2253 } 2254 private interface WillThrow { 2255 void willThrow() throws MyCheckedException; 2256 } 2257 2258 @Test 2259 public void testAsInstance() throws Throwable { 2260 if (CAN_SKIP_WORKING) return; 2261 Lookup lookup = MethodHandles.lookup(); 2262 { 2263 MethodType mt = MethodType.methodType(void.class); 2264 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt); 2265 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 2266 proxy.run(); 2267 assertCalled("runForRunnable"); 2268 } 2269 { 2270 MethodType mt = MethodType.methodType(Object.class, Fooable.class, Object.class); 2271 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", mt); 2272 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 2273 Object[] args = randomArgs(mt.parameterArray()); 2274 Object result = proxy.foo((Fooable) args[0], args[1]); 2275 assertCalled("fooForFooable", args); 2276 assertEquals(result, logEntry("fooForFooable", args)); 2277 } 2278 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 2279 new InternalError("ok"), 2280 new Throwable("fail"), 2281 new Exception("fail"), 2282 new MyCheckedException() 2283 }) { 2284 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 2285 mh = MethodHandles.insertArguments(mh, 0, ex); 2286 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 2287 try { 2288 proxy.willThrow(); 2289 System.out.println("Failed to throw: "+ex); 2290 assertTrue(false); 2291 } catch (Throwable ex1) { 2292 if (verbosity > 2) { 2293 System.out.println("throw "+ex); 2294 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 2295 } 2296 if (ex instanceof RuntimeException || 2297 ex instanceof Error) { 2298 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 2299 } else if (ex instanceof MyCheckedException) { 2300 assertSame("must pass declared exception out without wrapping", ex, ex1); 2301 } else { 2302 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 2303 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 2304 assertSame(ex, utex.getCause()); 2305 } 2306 } 2307 } 2308 // Test error checking: 2309 for (Class<?> nonSAM : new Class[] { Object.class, 2310 String.class, 2311 CharSequence.class, 2312 Example.class }) { 2313 try { 2314 MethodHandleProxies.asInterfaceInstance(nonSAM, varargsArray(0)); 2315 System.out.println("Failed to throw"); 2316 assertTrue(false); 2317 } catch (IllegalArgumentException ex) { 2318 } 2319 } 2320 } 2321} 2322// Local abbreviated copy of sun.invoke.util.ValueConversions 2323class ValueConversions { 2324 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); 2325 private static final Object[] NO_ARGS_ARRAY = {}; 2326 private static Object[] makeArray(Object... args) { return args; } 2327 private static Object[] array() { return NO_ARGS_ARRAY; } 2328 private static Object[] array(Object a0) 2329 { return makeArray(a0); } 2330 private static Object[] array(Object a0, Object a1) 2331 { return makeArray(a0, a1); } 2332 private static Object[] array(Object a0, Object a1, Object a2) 2333 { return makeArray(a0, a1, a2); } 2334 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 2335 { return makeArray(a0, a1, a2, a3); } 2336 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2337 Object a4) 2338 { return makeArray(a0, a1, a2, a3, a4); } 2339 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2340 Object a4, Object a5) 2341 { return makeArray(a0, a1, a2, a3, a4, a5); } 2342 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2343 Object a4, Object a5, Object a6) 2344 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 2345 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2346 Object a4, Object a5, Object a6, Object a7) 2347 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 2348 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2349 Object a4, Object a5, Object a6, Object a7, 2350 Object a8) 2351 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 2352 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2353 Object a4, Object a5, Object a6, Object a7, 2354 Object a8, Object a9) 2355 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 2356 static MethodHandle[] makeArrays() { 2357 ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>(); 2358 MethodHandles.Lookup lookup = IMPL_LOOKUP; 2359 for (;;) { 2360 int nargs = arrays.size(); 2361 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); 2362 String name = "array"; 2363 MethodHandle array = null; 2364 try { 2365 array = lookup.findStatic(ValueConversions.class, name, type); 2366 } catch (ReflectiveOperationException ex) { 2367 // break from loop! 2368 } 2369 if (array == null) break; 2370 arrays.add(array); 2371 } 2372 assertTrue(arrays.size() == 11); // current number of methods 2373 return arrays.toArray(new MethodHandle[0]); 2374 } 2375 static final MethodHandle[] ARRAYS = makeArrays(); 2376 2377 /** Return a method handle that takes the indicated number of Object 2378 * arguments and returns an Object array of them, as if for varargs. 2379 */ 2380 public static MethodHandle varargsArray(int nargs) { 2381 if (nargs < ARRAYS.length) 2382 return ARRAYS[nargs]; 2383 // else need to spin bytecode or do something else fancy 2384 throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs); 2385 } 2386 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 2387 Class<?> elemType = arrayType.getComponentType(); 2388 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)); 2389 MethodHandle mh = varargsArray(nargs); 2390 if (arrayType != Object[].class) 2391 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType)); 2392 return mh.asType(vaType); 2393 } 2394 static Object changeArrayType(Class<?> arrayType, Object[] a) { 2395 Class<?> elemType = arrayType.getComponentType(); 2396 if (!elemType.isPrimitive()) 2397 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class)); 2398 Object b = java.lang.reflect.Array.newInstance(elemType, a.length); 2399 for (int i = 0; i < a.length; i++) 2400 java.lang.reflect.Array.set(b, i, a[i]); 2401 return b; 2402 } 2403 private static final MethodHandle CHANGE_ARRAY_TYPE; 2404 static { 2405 try { 2406 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType", 2407 MethodType.methodType(Object.class, Class.class, Object[].class)); 2408 } catch (NoSuchMethodException | IllegalAccessException ex) { 2409 Error err = new InternalError("uncaught exception"); 2410 err.initCause(ex); 2411 throw err; 2412 } 2413 } 2414 2415 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); 2416 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } 2417 private static List<Object> list() { return NO_ARGS_LIST; } 2418 private static List<Object> list(Object a0) 2419 { return makeList(a0); } 2420 private static List<Object> list(Object a0, Object a1) 2421 { return makeList(a0, a1); } 2422 private static List<Object> list(Object a0, Object a1, Object a2) 2423 { return makeList(a0, a1, a2); } 2424 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) 2425 { return makeList(a0, a1, a2, a3); } 2426 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2427 Object a4) 2428 { return makeList(a0, a1, a2, a3, a4); } 2429 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2430 Object a4, Object a5) 2431 { return makeList(a0, a1, a2, a3, a4, a5); } 2432 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2433 Object a4, Object a5, Object a6) 2434 { return makeList(a0, a1, a2, a3, a4, a5, a6); } 2435 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2436 Object a4, Object a5, Object a6, Object a7) 2437 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } 2438 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2439 Object a4, Object a5, Object a6, Object a7, 2440 Object a8) 2441 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 2442 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 2443 Object a4, Object a5, Object a6, Object a7, 2444 Object a8, Object a9) 2445 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 2446 static MethodHandle[] makeLists() { 2447 ArrayList<MethodHandle> lists = new ArrayList<MethodHandle>(); 2448 MethodHandles.Lookup lookup = IMPL_LOOKUP; 2449 for (;;) { 2450 int nargs = lists.size(); 2451 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); 2452 String name = "list"; 2453 MethodHandle list = null; 2454 try { 2455 list = lookup.findStatic(ValueConversions.class, name, type); 2456 } catch (ReflectiveOperationException ex) { 2457 // break from loop! 2458 } 2459 if (list == null) break; 2460 lists.add(list); 2461 } 2462 assertTrue(lists.size() == 11); // current number of methods 2463 return lists.toArray(new MethodHandle[0]); 2464 } 2465 static final MethodHandle[] LISTS = makeLists(); 2466 2467 /** Return a method handle that takes the indicated number of Object 2468 * arguments and returns List. 2469 */ 2470 public static MethodHandle varargsList(int nargs) { 2471 if (nargs < LISTS.length) 2472 return LISTS[nargs]; 2473 // else need to spin bytecode or do something else fancy 2474 throw new UnsupportedOperationException("NYI"); 2475 } 2476} 2477// This guy tests access from outside the same package member, but inside 2478// the package itself. 2479class PackageSibling { 2480 static Lookup lookup() { 2481 return MethodHandles.lookup(); 2482 } 2483} 2484