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