1 /* 2 * Copyright (c) 2009, 2012, 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 MethodHandlesTest.java remote/RemoteExample.java 29 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa test.java.lang.invoke.MethodHandlesTest 30 */ 31 32 package test.java.lang.invoke; 33 34 import test.java.lang.invoke.remote.RemoteExample; 35 import java.lang.invoke.*; 36 import java.lang.invoke.MethodHandles.Lookup; 37 import java.lang.reflect.*; 38 import java.util.*; 39 import org.junit.*; 40 import static org.junit.Assert.*; 41 42 43 /** 44 * 45 * @author jrose 46 */ 47 public class MethodHandlesTest { 48 static final Class<?> THIS_CLASS = MethodHandlesTest.class; 49 // How much output? 50 static int verbosity = 0; 51 static { 52 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity"); 53 if (vstr == null) 54 vstr = System.getProperty(THIS_CLASS.getName()+".verbosity"); 55 if (vstr != null) verbosity = Integer.parseInt(vstr); 56 } 57 58 // Set this true during development if you want to fast-forward to 59 // a particular new, non-working test. Tests which are known to 60 // work (or have recently worked) test this flag and return on true. 61 static final boolean CAN_SKIP_WORKING; 62 static { 63 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING"); 64 if (vstr == null) 65 vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING"); 66 CAN_SKIP_WORKING = Boolean.parseBoolean(vstr); 67 } 68 69 // Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest. 70 // This might be useful with -Xcomp stress tests that compile all method handles. 71 static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY"); 72 73 @Test 74 public void testFirst() throws Throwable { 75 verbosity += 9; try { 76 // left blank for debugging 77 } finally { printCounts(); verbosity -= 9; } 78 } 79 80 static final int MAX_ARG_INCREASE = 3; 81 82 public MethodHandlesTest() { 83 } 84 85 String testName; 86 static int allPosTests, allNegTests; 87 int posTests, negTests; 88 @After 89 public void printCounts() { 90 if (verbosity >= 2 && (posTests | negTests) != 0) { 91 System.out.println(); 92 if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run"); 93 if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run"); 94 allPosTests += posTests; 95 allNegTests += negTests; 96 posTests = negTests = 0; 97 } 98 } 99 void countTest(boolean positive) { 100 if (positive) ++posTests; 101 else ++negTests; 102 } 103 void countTest() { countTest(true); } 104 void startTest(String name) { 105 if (testName != null) printCounts(); 106 if (verbosity >= 1) 107 System.out.println(name); 108 posTests = negTests = 0; 109 testName = name; 110 } 111 112 @BeforeClass 113 public static void setUpClass() throws Exception { 114 calledLog.clear(); 115 calledLog.add(null); 116 nextArgVal = INITIAL_ARG_VAL; 117 } 118 119 @AfterClass 120 public static void tearDownClass() throws Exception { 121 int posTests = allPosTests, negTests = allNegTests; 122 if (verbosity >= 0 && (posTests | negTests) != 0) { 123 System.out.println(); 124 if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases"); 125 if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases"); 126 } 127 } 128 129 static List<Object> calledLog = new ArrayList<>(); 130 static Object logEntry(String name, Object... args) { 131 return Arrays.asList(name, Arrays.asList(args)); 132 } 133 public static Object called(String name, Object... args) { 134 Object entry = logEntry(name, args); 135 calledLog.add(entry); 136 return entry; 137 } 138 static void assertCalled(String name, Object... args) { 139 Object expected = logEntry(name, args); 140 Object actual = calledLog.get(calledLog.size() - 1); 141 if (expected.equals(actual) && verbosity < 9) return; 142 System.out.println("assertCalled "+name+":"); 143 System.out.println("expected: "+deepToString(expected)); 144 System.out.println("actual: "+actual); 145 System.out.println("ex. types: "+getClasses(expected)); 146 System.out.println("act. types: "+getClasses(actual)); 147 assertEquals("previous method call", expected, actual); 148 } 149 static void printCalled(MethodHandle target, String name, Object... args) { 150 if (verbosity >= 3) 151 System.out.println("calling MH="+target+" to "+name+deepToString(args)); 152 } 153 static String deepToString(Object x) { 154 if (x == null) return "null"; 155 if (x instanceof Collection) 156 x = ((Collection)x).toArray(); 157 if (x instanceof Object[]) { 158 Object[] ax = (Object[]) x; 159 ax = Arrays.copyOf(ax, ax.length, Object[].class); 160 for (int i = 0; i < ax.length; i++) 161 ax[i] = deepToString(ax[i]); 162 x = Arrays.deepToString(ax); 163 } 164 if (x.getClass().isArray()) 165 try { 166 x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x); 167 } catch (ReflectiveOperationException ex) { throw new Error(ex); } 168 assert(!(x instanceof Object[])); 169 return x.toString(); 170 } 171 172 static Object castToWrapper(Object value, Class<?> dst) { 173 Object wrap = null; 174 if (value instanceof Number) 175 wrap = castToWrapperOrNull(((Number)value).longValue(), dst); 176 if (value instanceof Character) 177 wrap = castToWrapperOrNull((char)(Character)value, dst); 178 if (wrap != null) return wrap; 179 return dst.cast(value); 180 } 181 182 @SuppressWarnings("cast") // primitive cast to (long) is part of the pattern 183 static Object castToWrapperOrNull(long value, Class<?> dst) { 184 if (dst == int.class || dst == Integer.class) 185 return (int)(value); 186 if (dst == long.class || dst == Long.class) 187 return (long)(value); 188 if (dst == char.class || dst == Character.class) 189 return (char)(value); 190 if (dst == short.class || dst == Short.class) 191 return (short)(value); 192 if (dst == float.class || dst == Float.class) 193 return (float)(value); 194 if (dst == double.class || dst == Double.class) 195 return (double)(value); 196 if (dst == byte.class || dst == Byte.class) 197 return (byte)(value); 198 if (dst == boolean.class || dst == boolean.class) 199 return ((value % 29) & 1) == 0; 200 return null; 201 } 202 203 static final int ONE_MILLION = (1000*1000), // first int value 204 TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits 205 INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit; 206 static long nextArgVal; 207 static long nextArg(boolean moreBits) { 208 long val = nextArgVal++; 209 long sign = -(val & 1); // alternate signs 210 val >>= 1; 211 if (moreBits) 212 // Guarantee some bits in the high word. 213 // In any case keep the decimal representation simple-looking, 214 // with lots of zeroes, so as not to make the printed decimal 215 // strings unnecessarily noisy. 216 val += (val % ONE_MILLION) * TEN_BILLION; 217 return val ^ sign; 218 } 219 static int nextArg() { 220 // Produce a 32-bit result something like ONE_MILLION+(smallint). 221 // Example: 1_000_042. 222 return (int) nextArg(false); 223 } 224 static long nextArg(Class<?> kind) { 225 if (kind == long.class || kind == Long.class || 226 kind == double.class || kind == Double.class) 227 // produce a 64-bit result something like 228 // ((TEN_BILLION+1) * (ONE_MILLION+(smallint))) 229 // Example: 10_000_420_001_000_042. 230 return nextArg(true); 231 return (long) nextArg(); 232 } 233 234 static Object randomArg(Class<?> param) { 235 Object wrap = castToWrapperOrNull(nextArg(param), param); 236 if (wrap != null) { 237 return wrap; 238 } 239 // import sun.invoke.util.Wrapper; 240 // Wrapper wrap = Wrapper.forBasicType(dst); 241 // if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst)) 242 // wrap = Wrapper.forWrapperType(dst); 243 // if (wrap != Wrapper.OBJECT) 244 // return wrap.wrap(nextArg++); 245 if (param.isInterface()) { 246 for (Class<?> c : param.getClasses()) { 247 if (param.isAssignableFrom(c) && !c.isInterface()) 248 { param = c; break; } 249 } 250 } 251 if (param.isArray()) { 252 Class<?> ctype = param.getComponentType(); 253 Object arg = Array.newInstance(ctype, 2); 254 Array.set(arg, 0, randomArg(ctype)); 255 return arg; 256 } 257 if (param.isInterface() && param.isAssignableFrom(List.class)) 258 return Arrays.asList("#"+nextArg()); 259 if (param.isInterface() || param.isAssignableFrom(String.class)) 260 return "#"+nextArg(); 261 else 262 try { 263 return param.newInstance(); 264 } catch (InstantiationException | IllegalAccessException ex) { 265 } 266 return null; // random class not Object, String, Integer, etc. 267 } 268 static Object[] randomArgs(Class<?>... params) { 269 Object[] args = new Object[params.length]; 270 for (int i = 0; i < args.length; i++) 271 args[i] = randomArg(params[i]); 272 return args; 273 } 274 static Object[] randomArgs(int nargs, Class<?> param) { 275 Object[] args = new Object[nargs]; 276 for (int i = 0; i < args.length; i++) 277 args[i] = randomArg(param); 278 return args; 279 } 280 static Object[] randomArgs(List<Class<?>> params) { 281 return randomArgs(params.toArray(new Class<?>[params.size()])); 282 } 283 284 @SafeVarargs @SuppressWarnings("varargs") 285 static <T, E extends T> T[] array(Class<T[]> atype, E... a) { 286 return Arrays.copyOf(a, a.length, atype); 287 } 288 @SafeVarargs @SuppressWarnings("varargs") 289 static <T> T[] cat(T[] a, T... b) { 290 int alen = a.length, blen = b.length; 291 if (blen == 0) return a; 292 T[] c = Arrays.copyOf(a, alen + blen); 293 System.arraycopy(b, 0, c, alen, blen); 294 return c; 295 } 296 static Integer[] boxAll(int... vx) { 297 Integer[] res = new Integer[vx.length]; 298 for (int i = 0; i < res.length; i++) { 299 res[i] = vx[i]; 300 } 301 return res; 302 } 303 static Object getClasses(Object x) { 304 if (x == null) return x; 305 if (x instanceof String) return x; // keep the name 306 if (x instanceof List) { 307 // recursively report classes of the list elements 308 Object[] xa = ((List)x).toArray(); 309 for (int i = 0; i < xa.length; i++) 310 xa[i] = getClasses(xa[i]); 311 return Arrays.asList(xa); 312 } 313 return x.getClass().getSimpleName(); 314 } 315 316 /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */ 317 static MethodHandle varargsList(int arity) { 318 return ValueConversions.varargsList(arity); 319 } 320 /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */ 321 static MethodHandle varargsArray(int arity) { 322 return ValueConversions.varargsArray(arity); 323 } 324 static MethodHandle varargsArray(Class<?> arrayType, int arity) { 325 return ValueConversions.varargsArray(arrayType, arity); 326 } 327 /** Variation of varargsList, but with the given rtype. */ 328 static MethodHandle varargsList(int arity, Class<?> rtype) { 329 MethodHandle list = varargsList(arity); 330 MethodType listType = list.type().changeReturnType(rtype); 331 if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) { 332 // OK 333 } else if (rtype.isAssignableFrom(String.class)) { 334 if (LIST_TO_STRING == null) 335 try { 336 LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString", 337 MethodType.methodType(String.class, List.class)); 338 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 339 list = MethodHandles.filterReturnValue(list, LIST_TO_STRING); 340 } else if (rtype.isPrimitive()) { 341 if (LIST_TO_INT == null) 342 try { 343 LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt", 344 MethodType.methodType(int.class, List.class)); 345 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 346 list = MethodHandles.filterReturnValue(list, LIST_TO_INT); 347 list = MethodHandles.explicitCastArguments(list, listType); 348 } else { 349 throw new RuntimeException("varargsList: "+rtype); 350 } 351 return list.asType(listType); 352 } 353 /** Variation of varargsList, but with the given ptypes and rtype. */ 354 static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) { 355 MethodHandle list = varargsList(ptypes.size(), rtype); 356 return list.asType(MethodType.methodType(rtype, ptypes)); 357 } 358 private static MethodHandle LIST_TO_STRING, LIST_TO_INT; 359 private static String listToString(List<?> x) { return x.toString(); } 360 private static int listToInt(List<?> x) { return x.toString().hashCode(); } 361 362 static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) { 363 return changeArgTypes(target, 0, 999, argType); 364 } 365 static MethodHandle changeArgTypes(MethodHandle target, 366 int beg, int end, Class<?> argType) { 367 MethodType targetType = target.type(); 368 end = Math.min(end, targetType.parameterCount()); 369 ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList()); 370 Collections.fill(argTypes.subList(beg, end), argType); 371 MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); 372 return target.asType(ttype2); 373 } 374 static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) { 375 int targetLen = target.type().parameterCount(); 376 int extra = (nargs - targetLen); 377 if (extra <= 0) return target; 378 List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass); 379 return MethodHandles.dropArguments(target, targetLen, fakeArgs); 380 } 381 382 // This lookup is good for all members in and under MethodHandlesTest. 383 static final Lookup PRIVATE = MethodHandles.lookup(); 384 // This lookup is good for package-private members but not private ones. 385 static final Lookup PACKAGE = PackageSibling.lookup(); 386 // This lookup is good for public members and protected members of PubExample 387 static final Lookup SUBCLASS = RemoteExample.lookup(); 388 // This lookup is good only for public members. 389 static final Lookup PUBLIC = MethodHandles.publicLookup(); 390 391 // Subject methods... 392 static class Example implements IntExample { 393 final String name; 394 public Example() { name = "Example#"+nextArg(); } 395 protected Example(String name) { this.name = name; } 396 @SuppressWarnings("LeakingThisInConstructor") 397 protected Example(int x) { this(); called("protected <init>", this, x); } 398 //Example(Void x) { does not exist; lookup elicts NoSuchMethodException } 399 @Override public String toString() { return name; } 400 401 public void v0() { called("v0", this); } 402 protected void pro_v0() { called("pro_v0", this); } 403 void pkg_v0() { called("pkg_v0", this); } 404 private void pri_v0() { called("pri_v0", this); } 405 public static void s0() { called("s0"); } 406 protected static void pro_s0() { called("pro_s0"); } 407 static void pkg_s0() { called("pkg_s0"); } 408 private static void pri_s0() { called("pri_s0"); } 409 410 public Object v1(Object x) { return called("v1", this, x); } 411 public Object v2(Object x, Object y) { return called("v2", this, x, y); } 412 public Object v2(Object x, int y) { return called("v2", this, x, y); } 413 public Object v2(int x, Object y) { return called("v2", this, x, y); } 414 public Object v2(int x, int y) { return called("v2", this, x, y); } 415 public static Object s1(Object x) { return called("s1", x); } 416 public static Object s2(int x) { return called("s2", x); } 417 public static Object s3(long x) { return called("s3", x); } 418 public static Object s4(int x, int y) { return called("s4", x, y); } 419 public static Object s5(long x, int y) { return called("s5", x, y); } 420 public static Object s6(int x, long y) { return called("s6", x, y); } 421 public static Object s7(float x, double y) { return called("s7", x, y); } 422 423 // for testing findConstructor: 424 public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); } 425 public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); } 426 public Example(int x, int y) { this.name = x+""+y; called("Example.<init>", x, y); } 427 public Example(int x, long y) { this.name = x+""+y; called("Example.<init>", x, y); } 428 public Example(int x, float y) { this.name = x+""+y; called("Example.<init>", x, y); } 429 public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); } 430 public Example(int x, int y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); } 431 public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); } 432 433 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial 434 } 435 static final Lookup EXAMPLE = Example.EXAMPLE; 436 public static class PubExample extends Example { 437 public PubExample() { this("PubExample"); } 438 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); } 439 protected void pro_v0() { called("Pub/pro_v0", this); } 440 protected static void pro_s0() { called("Pub/pro_s0"); } 441 } 442 static class SubExample extends Example { 443 @Override public void v0() { called("Sub/v0", this); } 444 @Override void pkg_v0() { called("Sub/pkg_v0", this); } 445 @SuppressWarnings("LeakingThisInConstructor") 446 private SubExample(int x) { called("<init>", this, x); } 447 public SubExample() { super("SubExample#"+nextArg()); } 448 } 449 public static interface IntExample { 450 public void v0(); 451 public static class Impl implements IntExample { 452 public void v0() { called("Int/v0", this); } 453 final String name; 454 public Impl() { name = "Impl#"+nextArg(); } 455 @Override public String toString() { return name; } 456 } 457 } 458 static interface SubIntExample extends IntExample { } 459 460 static final Object[][][] ACCESS_CASES = { 461 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false 462 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE 463 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false 464 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK 465 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true 466 }; 467 468 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) { 469 Object[][] cases; 470 if (name.contains("pri_") || isSpecial) { 471 cases = ACCESS_CASES[1]; // PRIVATE only 472 } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) { 473 cases = ACCESS_CASES[2]; // not PUBLIC 474 } else if (name.contains("pro_")) { 475 cases = ACCESS_CASES[3]; // PUBLIC class, protected member 476 } else { 477 assertTrue(name.indexOf('_') < 0 || name.contains("fin_")); 478 boolean pubc = Modifier.isPublic(defc.getModifiers()); 479 if (pubc) 480 cases = ACCESS_CASES[4]; // all access levels 481 else 482 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC 483 } 484 if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE) 485 cases = Arrays.copyOfRange(cases, 0, cases.length-1); 486 return cases; 487 } 488 static Object[][] accessCases(Class<?> defc, String name) { 489 return accessCases(defc, name, false); 490 } 491 492 static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) { 493 if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE) 494 // external views stay external 495 return lookup; 496 return lookup.in(defc); 497 } 498 499 /** Is findVirtual (etc.) of "<init<" supposed to elicit a NoSuchMethodException? */ 500 final static boolean INIT_REF_CAUSES_NSME = true; 501 502 @Test 503 public void testFindStatic() throws Throwable { 504 if (CAN_SKIP_WORKING) return; 505 startTest("findStatic"); 506 testFindStatic(PubExample.class, void.class, "s0"); 507 testFindStatic(Example.class, void.class, "s0"); 508 testFindStatic(Example.class, void.class, "pkg_s0"); 509 testFindStatic(Example.class, void.class, "pri_s0"); 510 testFindStatic(Example.class, void.class, "pro_s0"); 511 testFindStatic(PubExample.class, void.class, "Pub/pro_s0"); 512 513 testFindStatic(Example.class, Object.class, "s1", Object.class); 514 testFindStatic(Example.class, Object.class, "s2", int.class); 515 testFindStatic(Example.class, Object.class, "s3", long.class); 516 testFindStatic(Example.class, Object.class, "s4", int.class, int.class); 517 testFindStatic(Example.class, Object.class, "s5", long.class, int.class); 518 testFindStatic(Example.class, Object.class, "s6", int.class, long.class); 519 testFindStatic(Example.class, Object.class, "s7", float.class, double.class); 520 521 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); 522 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class); 523 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 524 testFindStatic(false, PRIVATE, Example.class, void.class, "v0"); 525 } 526 527 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 528 for (Object[] ac : accessCases(defc, name)) { 529 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 530 } 531 } 532 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 533 testFindStatic(true, lookup, defc, ret, name, params); 534 } 535 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 536 countTest(positive); 537 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 538 MethodType type = MethodType.methodType(ret, params); 539 MethodHandle target = null; 540 Exception noAccess = null; 541 try { 542 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 543 target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); 544 } catch (ReflectiveOperationException ex) { 545 noAccess = ex; 546 assertExceptionClass( 547 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 548 ? NoSuchMethodException.class 549 : IllegalAccessException.class, 550 noAccess); 551 if (verbosity >= 5) ex.printStackTrace(System.out); 552 } 553 if (verbosity >= 3) 554 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 555 +(noAccess == null ? "" : " !! "+noAccess)); 556 if (positive && noAccess != null) throw noAccess; 557 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 558 if (!positive) return; // negative test failed as expected 559 assertEquals(type, target.type()); 560 assertNameStringContains(target, methodName); 561 Object[] args = randomArgs(params); 562 printCalled(target, name, args); 563 target.invokeWithArguments(args); 564 assertCalled(name, args); 565 if (verbosity >= 1) 566 System.out.print(':'); 567 } 568 569 static void assertExceptionClass(Class<? extends Throwable> expected, 570 Throwable actual) { 571 if (expected.isInstance(actual)) return; 572 actual.printStackTrace(); 573 assertEquals(expected, actual.getClass()); 574 } 575 576 static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); 577 578 // rough check of name string 579 static void assertNameStringContains(MethodHandle x, String s) { 580 if (!DEBUG_METHOD_HANDLE_NAMES) { 581 // ignore s 582 assertEquals("MethodHandle"+x.type(), x.toString()); 583 return; 584 } 585 if (x.toString().contains(s)) return; 586 assertEquals(s, x); 587 } 588 589 @Test 590 public void testFindVirtual() throws Throwable { 591 if (CAN_SKIP_WORKING) return; 592 startTest("findVirtual"); 593 testFindVirtual(Example.class, void.class, "v0"); 594 testFindVirtual(Example.class, void.class, "pkg_v0"); 595 testFindVirtual(Example.class, void.class, "pri_v0"); 596 testFindVirtual(Example.class, Object.class, "v1", Object.class); 597 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class); 598 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class); 599 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class); 600 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class); 601 testFindVirtual(Example.class, void.class, "pro_v0"); 602 testFindVirtual(PubExample.class, void.class, "Pub/pro_v0"); 603 604 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); 605 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class); 606 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class); 607 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0"); 608 609 // test dispatch 610 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0"); 611 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0"); 612 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0"); 613 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0"); 614 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0"); 615 testFindVirtual(Example.class, IntExample.class, void.class, "v0"); 616 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); 617 } 618 619 @Test 620 public void testFindVirtualClone() throws Throwable { 621 // test some ad hoc system methods 622 testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone"); 623 testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone"); 624 testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone"); 625 for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class }) 626 testFindVirtual(true, PUBLIC, cls, Object.class, "clone"); 627 } 628 629 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 630 Class<?> rcvc = defc; 631 testFindVirtual(rcvc, defc, ret, name, params); 632 } 633 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 634 for (Object[] ac : accessCases(defc, name)) { 635 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params); 636 } 637 } 638 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 639 testFindVirtual(true, lookup, rcvc, defc, ret, name, params); 640 } 641 void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 642 testFindVirtual(positive, lookup, defc, defc, ret, name, params); 643 } 644 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 645 countTest(positive); 646 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 647 MethodType type = MethodType.methodType(ret, params); 648 MethodHandle target = null; 649 Exception noAccess = null; 650 try { 651 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 652 target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type); 653 } catch (ReflectiveOperationException ex) { 654 noAccess = ex; 655 assertExceptionClass( 656 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 657 ? NoSuchMethodException.class 658 : IllegalAccessException.class, 659 noAccess); 660 if (verbosity >= 5) ex.printStackTrace(System.out); 661 } 662 if (verbosity >= 3) 663 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 664 +(noAccess == null ? "" : " !! "+noAccess)); 665 if (positive && noAccess != null) throw noAccess; 666 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 667 if (!positive) return; // negative test failed as expected 668 Class<?> selfc = defc; 669 // predict receiver type narrowing: 670 if (lookup == SUBCLASS && 671 name.contains("pro_") && 672 selfc.isAssignableFrom(lookup.lookupClass())) { 673 selfc = lookup.lookupClass(); 674 if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4); 675 } 676 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params); 677 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 678 assertEquals(typeWithSelf, target.type()); 679 assertNameStringContains(target, methodName); 680 Object[] argsWithSelf = randomArgs(paramsWithSelf); 681 if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc); 682 printCalled(target, name, argsWithSelf); 683 Object res = target.invokeWithArguments(argsWithSelf); 684 if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) { 685 assertCalled(name, argsWithSelf); 686 } else if (name.equals("clone")) { 687 // Ad hoc method call outside Example. For Object[].clone. 688 printCalled(target, name, argsWithSelf); 689 assertEquals(MethodType.methodType(Object.class, rcvc), target.type()); 690 Object orig = argsWithSelf[0]; 691 assertEquals(orig.getClass(), res.getClass()); 692 if (res instanceof Object[]) 693 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]); 694 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]})); 695 } else { 696 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params)); 697 } 698 if (verbosity >= 1) 699 System.out.print(':'); 700 } 701 702 @Test 703 public void testFindSpecial() throws Throwable { 704 if (CAN_SKIP_WORKING) return; 705 startTest("findSpecial"); 706 testFindSpecial(SubExample.class, Example.class, void.class, "v0"); 707 testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0"); 708 testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0"); 709 // Do some negative testing: 710 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) { 711 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); 712 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus"); 713 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class); 714 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class); 715 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); 716 } 717 } 718 719 void testFindSpecial(Class<?> specialCaller, 720 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 721 if (specialCaller == RemoteExample.class) { 722 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params); 723 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params); 724 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params); 725 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params); 726 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 727 return; 728 } 729 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params); 730 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params); 731 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params); 732 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params); 733 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 734 } 735 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller, 736 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 737 countTest(positive); 738 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 739 MethodType type = MethodType.methodType(ret, params); 740 Lookup specialLookup = maybeMoveIn(lookup, specialCaller); 741 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller && 742 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 743 MethodHandle target = null; 744 Exception noAccess = null; 745 try { 746 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 747 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup); 748 target = specialLookup.findSpecial(defc, methodName, type, specialCaller); 749 } catch (ReflectiveOperationException ex) { 750 noAccess = ex; 751 assertExceptionClass( 752 (!specialAccessOK) // this check should happen first 753 ? IllegalAccessException.class 754 : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 755 ? NoSuchMethodException.class 756 : IllegalAccessException.class, 757 noAccess); 758 if (verbosity >= 5) ex.printStackTrace(System.out); 759 } 760 if (verbosity >= 3) 761 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target 762 +(target == null ? "" : target.type()) 763 +(noAccess == null ? "" : " !! "+noAccess)); 764 if (positive && noAccess != null) throw noAccess; 765 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 766 if (!positive) return; // negative test failed as expected 767 assertEquals(specialCaller, target.type().parameterType(0)); 768 assertEquals(type, target.type().dropParameterTypes(0,1)); 769 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params); 770 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 771 assertNameStringContains(target, methodName); 772 Object[] args = randomArgs(paramsWithSelf); 773 printCalled(target, name, args); 774 target.invokeWithArguments(args); 775 assertCalled(name, args); 776 } 777 778 @Test 779 public void testFindConstructor() throws Throwable { 780 if (CAN_SKIP_WORKING) return; 781 startTest("findConstructor"); 782 testFindConstructor(true, EXAMPLE, Example.class); 783 testFindConstructor(true, EXAMPLE, Example.class, int.class); 784 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class); 785 testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class); 786 testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class); 787 testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class); 788 testFindConstructor(true, EXAMPLE, Example.class, String.class); 789 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class); 790 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class); 791 } 792 void testFindConstructor(boolean positive, Lookup lookup, 793 Class<?> defc, Class<?>... params) throws Throwable { 794 countTest(positive); 795 MethodType type = MethodType.methodType(void.class, params); 796 MethodHandle target = null; 797 Exception noAccess = null; 798 try { 799 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type); 800 target = lookup.findConstructor(defc, type); 801 } catch (ReflectiveOperationException ex) { 802 noAccess = ex; 803 assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException); 804 } 805 if (verbosity >= 3) 806 System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target 807 +(target == null ? "" : target.type()) 808 +(noAccess == null ? "" : " !! "+noAccess)); 809 if (positive && noAccess != null) throw noAccess; 810 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 811 if (!positive) return; // negative test failed as expected 812 assertEquals(type.changeReturnType(defc), target.type()); 813 Object[] args = randomArgs(params); 814 printCalled(target, defc.getSimpleName(), args); 815 Object obj = target.invokeWithArguments(args); 816 if (!(defc == Example.class && params.length < 2)) 817 assertCalled(defc.getSimpleName()+".<init>", args); 818 assertTrue("instance of "+defc.getName(), defc.isInstance(obj)); 819 } 820 821 @Test 822 public void testBind() throws Throwable { 823 if (CAN_SKIP_WORKING) return; 824 startTest("bind"); 825 testBind(Example.class, void.class, "v0"); 826 testBind(Example.class, void.class, "pkg_v0"); 827 testBind(Example.class, void.class, "pri_v0"); 828 testBind(Example.class, Object.class, "v1", Object.class); 829 testBind(Example.class, Object.class, "v2", Object.class, Object.class); 830 testBind(Example.class, Object.class, "v2", Object.class, int.class); 831 testBind(Example.class, Object.class, "v2", int.class, Object.class); 832 testBind(Example.class, Object.class, "v2", int.class, int.class); 833 testBind(false, PRIVATE, Example.class, void.class, "bogus"); 834 testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class); 835 testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 836 testBind(SubExample.class, void.class, "Sub/v0"); 837 testBind(SubExample.class, void.class, "Sub/pkg_v0"); 838 testBind(IntExample.Impl.class, void.class, "Int/v0"); 839 } 840 841 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 842 for (Object[] ac : accessCases(defc, name)) { 843 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 844 } 845 } 846 847 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 848 countTest(positive); 849 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 850 MethodType type = MethodType.methodType(ret, params); 851 Object receiver = randomArg(defc); 852 MethodHandle target = null; 853 Exception noAccess = null; 854 try { 855 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 856 target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); 857 } catch (ReflectiveOperationException ex) { 858 noAccess = ex; 859 assertExceptionClass( 860 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 861 ? NoSuchMethodException.class 862 : IllegalAccessException.class, 863 noAccess); 864 if (verbosity >= 5) ex.printStackTrace(System.out); 865 } 866 if (verbosity >= 3) 867 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target 868 +(noAccess == null ? "" : " !! "+noAccess)); 869 if (positive && noAccess != null) throw noAccess; 870 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 871 if (!positive) return; // negative test failed as expected 872 assertEquals(type, target.type()); 873 Object[] args = randomArgs(params); 874 printCalled(target, name, args); 875 target.invokeWithArguments(args); 876 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); 877 assertCalled(name, argsWithReceiver); 878 if (verbosity >= 1) 879 System.out.print(':'); 880 } 881 882 @Test 883 public void testUnreflect() throws Throwable { 884 if (CAN_SKIP_WORKING) return; 885 startTest("unreflect"); 886 testUnreflect(Example.class, true, void.class, "s0"); 887 testUnreflect(Example.class, true, void.class, "pro_s0"); 888 testUnreflect(Example.class, true, void.class, "pkg_s0"); 889 testUnreflect(Example.class, true, void.class, "pri_s0"); 890 891 testUnreflect(Example.class, true, Object.class, "s1", Object.class); 892 testUnreflect(Example.class, true, Object.class, "s2", int.class); 893 testUnreflect(Example.class, true, Object.class, "s3", long.class); 894 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class); 895 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class); 896 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class); 897 898 testUnreflect(Example.class, false, void.class, "v0"); 899 testUnreflect(Example.class, false, void.class, "pkg_v0"); 900 testUnreflect(Example.class, false, void.class, "pri_v0"); 901 testUnreflect(Example.class, false, Object.class, "v1", Object.class); 902 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class); 903 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class); 904 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class); 905 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class); 906 907 // Test a public final member in another package: 908 testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0"); 909 } 910 911 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable { 912 for (Object[] ac : accessCases(defc, name)) { 913 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params); 914 } 915 } 916 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 917 for (Object[] ac : accessCases(defc, name)) { 918 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 919 } 920 } 921 void testUnreflectMaybeSpecial(Class<?> specialCaller, 922 boolean positive, Lookup lookup, 923 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 924 countTest(positive); 925 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 926 MethodType type = MethodType.methodType(ret, params); 927 Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null); 928 boolean specialAccessOK = (specialCaller != null && 929 specialLookup.lookupClass() == specialCaller && 930 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 931 Method rmethod = defc.getDeclaredMethod(methodName, params); 932 MethodHandle target = null; 933 Exception noAccess = null; 934 boolean isStatic = (rcvc == null); 935 boolean isSpecial = (specialCaller != null); 936 try { 937 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 938 if (isSpecial) 939 target = specialLookup.unreflectSpecial(rmethod, specialCaller); 940 else 941 target = maybeMoveIn(lookup, defc).unreflect(rmethod); 942 } catch (ReflectiveOperationException ex) { 943 noAccess = ex; 944 assertExceptionClass( 945 IllegalAccessException.class, // NSME is impossible, since it was already reflected 946 noAccess); 947 if (verbosity >= 5) ex.printStackTrace(System.out); 948 } 949 if (verbosity >= 3) 950 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type 951 +(!isSpecial ? "" : " specialCaller="+specialCaller) 952 +( isStatic ? "" : " receiver="+rcvc) 953 +" => "+target 954 +(noAccess == null ? "" : " !! "+noAccess)); 955 if (positive && noAccess != null) throw noAccess; 956 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 957 if (!positive) return; // negative test failed as expected 958 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers())); 959 Class<?>[] paramsMaybeWithSelf = params; 960 if (!isStatic) { 961 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params); 962 } 963 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf); 964 if (isStatic) { 965 assertEquals(typeMaybeWithSelf, target.type()); 966 } else { 967 if (isSpecial) 968 assertEquals(specialCaller, target.type().parameterType(0)); 969 else 970 assertEquals(defc, target.type().parameterType(0)); 971 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc)); 972 } 973 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf); 974 printCalled(target, name, argsMaybeWithSelf); 975 target.invokeWithArguments(argsMaybeWithSelf); 976 assertCalled(name, argsMaybeWithSelf); 977 if (verbosity >= 1) 978 System.out.print(':'); 979 } 980 981 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 982 for (Object[] ac : accessCases(defc, name, true)) { 983 Class<?> specialCaller = rcvc; 984 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 985 } 986 } 987 988 @Test 989 public void testUnreflectSpecial() throws Throwable { 990 if (CAN_SKIP_WORKING) return; 991 startTest("unreflectSpecial"); 992 testUnreflectSpecial(Example.class, Example.class, void.class, "v0"); 993 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0"); 994 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0"); 995 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0"); 996 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class); 997 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class); 998 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0"); 999 } 1000 1001 public static class HasFields { 1002 boolean fZ = false; 1003 byte fB = (byte)'B'; 1004 short fS = (short)'S'; 1005 char fC = 'C'; 1006 int fI = 'I'; 1007 long fJ = 'J'; 1008 float fF = 'F'; 1009 double fD = 'D'; 1010 static boolean sZ = true; 1011 static byte sB = 1+(byte)'B'; 1012 static short sS = 1+(short)'S'; 1013 static char sC = 1+'C'; 1014 static int sI = 1+'I'; 1015 static long sJ = 1+'J'; 1016 static float sF = 1+'F'; 1017 static double sD = 1+'D'; 1018 1019 Object fL = 'L'; 1020 String fR = "R"; 1021 static Object sL = 'M'; 1022 static String sR = "S"; 1023 1024 static final Object[][] CASES; 1025 static { 1026 ArrayList<Object[]> cases = new ArrayList<>(); 1027 Object types[][] = { 1028 {'L',Object.class}, {'R',String.class}, 1029 {'I',int.class}, {'J',long.class}, 1030 {'F',float.class}, {'D',double.class}, 1031 {'Z',boolean.class}, {'B',byte.class}, 1032 {'S',short.class}, {'C',char.class}, 1033 }; 1034 HasFields fields = new HasFields(); 1035 for (Object[] t : types) { 1036 for (int kind = 0; kind <= 1; kind++) { 1037 boolean isStatic = (kind != 0); 1038 char btc = (Character)t[0]; 1039 String name = (isStatic ? "s" : "f") + btc; 1040 Class<?> type = (Class<?>) t[1]; 1041 Object value; 1042 Field field; 1043 try { 1044 field = HasFields.class.getDeclaredField(name); 1045 } catch (NoSuchFieldException | SecurityException ex) { 1046 throw new InternalError("no field HasFields."+name); 1047 } 1048 try { 1049 value = field.get(fields); 1050 } catch (IllegalArgumentException | IllegalAccessException ex) { 1051 throw new InternalError("cannot fetch field HasFields."+name); 1052 } 1053 if (type == float.class) { 1054 float v = 'F'; 1055 if (isStatic) v++; 1056 assertTrue(value.equals(v)); 1057 } 1058 assertTrue(name.equals(field.getName())); 1059 assertTrue(type.equals(field.getType())); 1060 assertTrue(isStatic == (Modifier.isStatic(field.getModifiers()))); 1061 cases.add(new Object[]{ field, value }); 1062 } 1063 } 1064 cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class }); 1065 cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class }); 1066 CASES = cases.toArray(new Object[0][]); 1067 } 1068 } 1069 1070 static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40; 1071 static boolean testModeMatches(int testMode, boolean isStatic) { 1072 switch (testMode) { 1073 case TEST_FIND_STATIC: return isStatic; 1074 case TEST_FIND_FIELD: return !isStatic; 1075 case TEST_UNREFLECT: return true; // unreflect matches both 1076 } 1077 throw new InternalError("testMode="+testMode); 1078 } 1079 1080 @Test 1081 public void testUnreflectGetter() throws Throwable { 1082 if (CAN_SKIP_WORKING) return; 1083 startTest("unreflectGetter"); 1084 testGetter(TEST_UNREFLECT); 1085 } 1086 @Test 1087 public void testFindGetter() throws Throwable { 1088 if (CAN_SKIP_WORKING) return; 1089 startTest("findGetter"); 1090 testGetter(TEST_FIND_FIELD); 1091 testGetter(TEST_FIND_FIELD | TEST_BOUND); 1092 } 1093 @Test 1094 public void testFindStaticGetter() throws Throwable { 1095 if (CAN_SKIP_WORKING) return; 1096 startTest("findStaticGetter"); 1097 testGetter(TEST_FIND_STATIC); 1098 } 1099 public void testGetter(int testMode) throws Throwable { 1100 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 1101 for (Object[] c : HasFields.CASES) { 1102 boolean positive = (c[1] != Error.class); 1103 testGetter(positive, lookup, c[0], c[1], testMode); 1104 if (positive) 1105 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 1106 } 1107 testGetter(true, lookup, 1108 new Object[]{ true, System.class, "out", java.io.PrintStream.class }, 1109 System.out, testMode); 1110 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 1111 testGetter(false, lookup, 1112 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 1113 null, testMode); 1114 } 1115 } 1116 public void testGetter(boolean positive, MethodHandles.Lookup lookup, 1117 Object fieldRef, Object value, int testMode) throws Throwable { 1118 testAccessor(positive, lookup, fieldRef, value, testMode); 1119 } 1120 1121 public void testAccessor(boolean positive0, MethodHandles.Lookup lookup, 1122 Object fieldRef, Object value, int testMode0) throws Throwable { 1123 if (verbosity >= 4) 1124 System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0})); 1125 boolean isGetter = ((testMode0 & TEST_SETTER) == 0); 1126 boolean doBound = ((testMode0 & TEST_BOUND) != 0); 1127 boolean testNPE = ((testMode0 & TEST_NPE) != 0); 1128 int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE); 1129 boolean positive = positive0 && !testNPE; 1130 boolean isStatic; 1131 Class<?> fclass; 1132 String fname; 1133 Class<?> ftype; 1134 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null); 1135 if (f != null) { 1136 isStatic = Modifier.isStatic(f.getModifiers()); 1137 fclass = f.getDeclaringClass(); 1138 fname = f.getName(); 1139 ftype = f.getType(); 1140 } else { 1141 Object[] scnt = (Object[]) fieldRef; 1142 isStatic = (Boolean) scnt[0]; 1143 fclass = (Class<?>) scnt[1]; 1144 fname = (String) scnt[2]; 1145 ftype = (Class<?>) scnt[3]; 1146 try { 1147 f = fclass.getDeclaredField(fname); 1148 } catch (ReflectiveOperationException ex) { 1149 f = null; 1150 } 1151 } 1152 if (!testModeMatches(testMode, isStatic)) return; 1153 if (f == null && testMode == TEST_UNREFLECT) return; 1154 if (testNPE && isStatic) return; 1155 countTest(positive); 1156 MethodType expType; 1157 if (isGetter) 1158 expType = MethodType.methodType(ftype, HasFields.class); 1159 else 1160 expType = MethodType.methodType(void.class, HasFields.class, ftype); 1161 if (isStatic) expType = expType.dropParameterTypes(0, 1); 1162 Exception noAccess = null; 1163 MethodHandle mh; 1164 try { 1165 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) { 1166 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; 1167 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; 1168 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; 1169 case TEST_SETTER| 1170 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break; 1171 case TEST_SETTER| 1172 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break; 1173 case TEST_SETTER| 1174 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break; 1175 default: 1176 throw new InternalError("testMode="+testMode); 1177 } 1178 } catch (ReflectiveOperationException ex) { 1179 mh = null; 1180 noAccess = ex; 1181 assertExceptionClass( 1182 (fname.contains("bogus")) 1183 ? NoSuchFieldException.class 1184 : IllegalAccessException.class, 1185 noAccess); 1186 if (verbosity >= 5) ex.printStackTrace(System.out); 1187 } 1188 if (verbosity >= 3) 1189 System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype 1190 +" => "+mh 1191 +(noAccess == null ? "" : " !! "+noAccess)); 1192 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess); 1193 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null); 1194 if (!positive && !testNPE) return; // negative access test failed as expected 1195 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); 1196 1197 1198 assertSame(mh.type(), expType); 1199 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs 1200 HasFields fields = new HasFields(); 1201 HasFields fieldsForMH = fields; 1202 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error 1203 if (doBound) 1204 mh = mh.bindTo(fieldsForMH); 1205 Object sawValue; 1206 Class<?> vtype = ftype; 1207 if (ftype != int.class) vtype = Object.class; 1208 if (isGetter) { 1209 mh = mh.asType(mh.type().generic() 1210 .changeReturnType(vtype)); 1211 } else { 1212 int last = mh.type().parameterCount() - 1; 1213 mh = mh.asType(mh.type().generic() 1214 .changeReturnType(void.class) 1215 .changeParameterType(last, vtype)); 1216 } 1217 if (f != null && f.getDeclaringClass() == HasFields.class) { 1218 assertEquals(f.get(fields), value); // clean to start with 1219 } 1220 Throwable caughtEx = null; 1221 if (isGetter) { 1222 Object expValue = value; 1223 for (int i = 0; i <= 1; i++) { 1224 sawValue = null; // make DA rules happy under try/catch 1225 try { 1226 if (isStatic || doBound) { 1227 if (ftype == int.class) 1228 sawValue = (int) mh.invokeExact(); // do these exactly 1229 else 1230 sawValue = mh.invokeExact(); 1231 } else { 1232 if (ftype == int.class) 1233 sawValue = (int) mh.invokeExact((Object) fieldsForMH); 1234 else 1235 sawValue = mh.invokeExact((Object) fieldsForMH); 1236 } 1237 } catch (RuntimeException ex) { 1238 if (ex instanceof NullPointerException && testNPE) { 1239 caughtEx = ex; 1240 break; 1241 } 1242 } 1243 assertEquals(sawValue, expValue); 1244 if (f != null && f.getDeclaringClass() == HasFields.class 1245 && !Modifier.isFinal(f.getModifiers())) { 1246 Object random = randomArg(ftype); 1247 f.set(fields, random); 1248 expValue = random; 1249 } else { 1250 break; 1251 } 1252 } 1253 } else { 1254 for (int i = 0; i <= 1; i++) { 1255 Object putValue = randomArg(ftype); 1256 try { 1257 if (isStatic || doBound) { 1258 if (ftype == int.class) 1259 mh.invokeExact((int)putValue); // do these exactly 1260 else 1261 mh.invokeExact(putValue); 1262 } else { 1263 if (ftype == int.class) 1264 mh.invokeExact((Object) fieldsForMH, (int)putValue); 1265 else 1266 mh.invokeExact((Object) fieldsForMH, putValue); 1267 } 1268 } catch (RuntimeException ex) { 1269 if (ex instanceof NullPointerException && testNPE) { 1270 caughtEx = ex; 1271 break; 1272 } 1273 } 1274 if (f != null && f.getDeclaringClass() == HasFields.class) { 1275 assertEquals(f.get(fields), putValue); 1276 } 1277 } 1278 } 1279 if (f != null && f.getDeclaringClass() == HasFields.class) { 1280 f.set(fields, value); // put it back 1281 } 1282 if (testNPE) { 1283 if (caughtEx == null || !(caughtEx instanceof NullPointerException)) 1284 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx); 1285 caughtEx = null; // nullify expected exception 1286 } 1287 if (caughtEx != null) { 1288 throw new RuntimeException("unexpected exception", caughtEx); 1289 } 1290 } 1291 1292 1293 @Test 1294 public void testUnreflectSetter() throws Throwable { 1295 if (CAN_SKIP_WORKING) return; 1296 startTest("unreflectSetter"); 1297 testSetter(TEST_UNREFLECT); 1298 } 1299 @Test 1300 public void testFindSetter() throws Throwable { 1301 if (CAN_SKIP_WORKING) return; 1302 startTest("findSetter"); 1303 testSetter(TEST_FIND_FIELD); 1304 testSetter(TEST_FIND_FIELD | TEST_BOUND); 1305 } 1306 @Test 1307 public void testFindStaticSetter() throws Throwable { 1308 if (CAN_SKIP_WORKING) return; 1309 startTest("findStaticSetter"); 1310 testSetter(TEST_FIND_STATIC); 1311 } 1312 public void testSetter(int testMode) throws Throwable { 1313 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 1314 startTest("unreflectSetter"); 1315 for (Object[] c : HasFields.CASES) { 1316 boolean positive = (c[1] != Error.class); 1317 testSetter(positive, lookup, c[0], c[1], testMode); 1318 if (positive) 1319 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 1320 } 1321 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 1322 testSetter(false, lookup, 1323 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 1324 null, testMode); 1325 } 1326 } 1327 public void testSetter(boolean positive, MethodHandles.Lookup lookup, 1328 Object fieldRef, Object value, int testMode) throws Throwable { 1329 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER); 1330 } 1331 1332 @Test 1333 public void testArrayElementGetter() throws Throwable { 1334 if (CAN_SKIP_WORKING) return; 1335 startTest("arrayElementGetter"); 1336 testArrayElementGetterSetter(false); 1337 } 1338 1339 @Test 1340 public void testArrayElementSetter() throws Throwable { 1341 if (CAN_SKIP_WORKING) return; 1342 startTest("arrayElementSetter"); 1343 testArrayElementGetterSetter(true); 1344 } 1345 1346 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3; 1347 1348 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { 1349 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE); 1350 } 1351 1352 @Test 1353 public void testArrayElementErrors() throws Throwable { 1354 if (CAN_SKIP_WORKING) return; 1355 startTest("arrayElementErrors"); 1356 testArrayElementGetterSetter(false, TEST_ARRAY_NPE); 1357 testArrayElementGetterSetter(true, TEST_ARRAY_NPE); 1358 testArrayElementGetterSetter(false, TEST_ARRAY_OOB); 1359 testArrayElementGetterSetter(true, TEST_ARRAY_OOB); 1360 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE); 1361 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE); 1362 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE); 1363 } 1364 1365 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable { 1366 testArrayElementGetterSetter(new String[10], testSetter, negTest); 1367 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest); 1368 testArrayElementGetterSetter(new Example[10], testSetter, negTest); 1369 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest); 1370 testArrayElementGetterSetter(new Object[10], testSetter, negTest); 1371 testArrayElementGetterSetter(new boolean[10], testSetter, negTest); 1372 testArrayElementGetterSetter(new byte[10], testSetter, negTest); 1373 testArrayElementGetterSetter(new char[10], testSetter, negTest); 1374 testArrayElementGetterSetter(new short[10], testSetter, negTest); 1375 testArrayElementGetterSetter(new int[10], testSetter, negTest); 1376 testArrayElementGetterSetter(new float[10], testSetter, negTest); 1377 testArrayElementGetterSetter(new long[10], testSetter, negTest); 1378 testArrayElementGetterSetter(new double[10], testSetter, negTest); 1379 } 1380 1381 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable { 1382 boolean positive = (negTest == TEST_ARRAY_NONE); 1383 int length = java.lang.reflect.Array.getLength(array); 1384 Class<?> arrayType = array.getClass(); 1385 Class<?> elemType = arrayType.getComponentType(); 1386 Object arrayToMH = array; 1387 // this stanza allows negative tests to make argument perturbations: 1388 switch (negTest) { 1389 case TEST_ARRAY_NPE: 1390 arrayToMH = null; 1391 break; 1392 case TEST_ARRAY_OOB: 1393 assert(length > 0); 1394 arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0); 1395 break; 1396 case TEST_ARRAY_ASE: 1397 assert(testSetter && !elemType.isPrimitive()); 1398 if (elemType == Object.class) 1399 arrayToMH = new StringBuffer[length]; // very random subclass of Object! 1400 else if (elemType == Example.class) 1401 arrayToMH = new SubExample[length]; 1402 else if (elemType == IntExample.class) 1403 arrayToMH = new SubIntExample[length]; 1404 else 1405 return; // can't make an ArrayStoreException test 1406 assert(arrayType.isInstance(arrayToMH)) 1407 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest); 1408 break; 1409 } 1410 countTest(positive); 1411 if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH}))); 1412 MethodType expType = !testSetter 1413 ? MethodType.methodType(elemType, arrayType, int.class) 1414 : MethodType.methodType(void.class, arrayType, int.class, elemType); 1415 MethodHandle mh = !testSetter 1416 ? MethodHandles.arrayElementGetter(arrayType) 1417 : MethodHandles.arrayElementSetter(arrayType); 1418 assertSame(mh.type(), expType); 1419 if (elemType != int.class && elemType != boolean.class) { 1420 MethodType gtype = mh.type().generic().changeParameterType(1, int.class); 1421 if (testSetter) gtype = gtype.changeReturnType(void.class); 1422 mh = mh.asType(gtype); 1423 } 1424 Object sawValue, expValue; 1425 List<Object> model = array2list(array); 1426 Throwable caughtEx = null; 1427 for (int i = 0; i < length; i++) { 1428 // update array element 1429 Object random = randomArg(elemType); 1430 model.set(i, random); 1431 if (testSetter) { 1432 try { 1433 if (elemType == int.class) 1434 mh.invokeExact((int[]) arrayToMH, i, (int)random); 1435 else if (elemType == boolean.class) 1436 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random); 1437 else 1438 mh.invokeExact(arrayToMH, i, random); 1439 } catch (RuntimeException ex) { 1440 caughtEx = ex; 1441 break; 1442 } 1443 assertEquals(model, array2list(array)); 1444 } else { 1445 Array.set(array, i, random); 1446 } 1447 if (verbosity >= 5) { 1448 List<Object> array2list = array2list(array); 1449 System.out.println("a["+i+"]="+random+" => "+array2list); 1450 if (!array2list.equals(model)) 1451 System.out.println("*** != "+model); 1452 } 1453 // observe array element 1454 sawValue = Array.get(array, i); 1455 if (!testSetter) { 1456 expValue = sawValue; 1457 try { 1458 if (elemType == int.class) 1459 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i); 1460 else if (elemType == boolean.class) 1461 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i); 1462 else 1463 sawValue = mh.invokeExact(arrayToMH, i); 1464 } catch (RuntimeException ex) { 1465 caughtEx = ex; 1466 break; 1467 } 1468 assertEquals(sawValue, expValue); 1469 assertEquals(model, array2list(array)); 1470 } 1471 } 1472 if (!positive) { 1473 if (caughtEx == null) 1474 throw new RuntimeException("failed to catch exception for negTest="+negTest); 1475 // test the kind of exception 1476 Class<?> reqType = null; 1477 switch (negTest) { 1478 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break; 1479 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break; 1480 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break; 1481 default: assert(false); 1482 } 1483 if (reqType.isInstance(caughtEx)) { 1484 caughtEx = null; // nullify expected exception 1485 } 1486 } 1487 if (caughtEx != null) { 1488 throw new RuntimeException("unexpected exception", caughtEx); 1489 } 1490 } 1491 1492 List<Object> array2list(Object array) { 1493 int length = Array.getLength(array); 1494 ArrayList<Object> model = new ArrayList<>(length); 1495 for (int i = 0; i < length; i++) 1496 model.add(Array.get(array, i)); 1497 return model; 1498 } 1499 1500 static class Callee { 1501 static Object id() { return called("id"); } 1502 static Object id(Object x) { return called("id", x); } 1503 static Object id(Object x, Object y) { return called("id", x, y); } 1504 static Object id(Object x, Object y, Object z) { return called("id", x, y, z); } 1505 static Object id(Object... vx) { return called("id", vx); } 1506 static MethodHandle ofType(int n) { 1507 return ofType(Object.class, n); 1508 } 1509 static MethodHandle ofType(Class<?> rtype, int n) { 1510 if (n == -1) 1511 return ofType(MethodType.methodType(rtype, Object[].class)); 1512 return ofType(MethodType.genericMethodType(n).changeReturnType(rtype)); 1513 } 1514 static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) { 1515 return ofType(MethodType.methodType(rtype, ptypes)); 1516 } 1517 static MethodHandle ofType(MethodType type) { 1518 Class<?> rtype = type.returnType(); 1519 String pfx = ""; 1520 if (rtype != Object.class) 1521 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase(); 1522 String name = pfx+"id"; 1523 try { 1524 return PRIVATE.findStatic(Callee.class, name, type); 1525 } catch (NoSuchMethodException | IllegalAccessException ex) { 1526 throw new RuntimeException(ex); 1527 } 1528 } 1529 } 1530 1531 @Test 1532 public void testConvertArguments() throws Throwable { 1533 if (CAN_SKIP_WORKING) return; 1534 startTest("convertArguments"); 1535 testConvert(Callee.ofType(1), null, "id", int.class); 1536 testConvert(Callee.ofType(1), null, "id", String.class); 1537 testConvert(Callee.ofType(1), null, "id", Integer.class); 1538 testConvert(Callee.ofType(1), null, "id", short.class); 1539 testConvert(Callee.ofType(1), null, "id", char.class); 1540 testConvert(Callee.ofType(1), null, "id", byte.class); 1541 } 1542 1543 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1544 testConvert(true, id, rtype, name, params); 1545 } 1546 1547 void testConvert(boolean positive, 1548 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1549 countTest(positive); 1550 MethodType idType = id.type(); 1551 if (rtype == null) rtype = idType.returnType(); 1552 for (int i = 0; i < params.length; i++) { 1553 if (params[i] == null) params[i] = idType.parameterType(i); 1554 } 1555 // simulate the pairwise conversion 1556 MethodType newType = MethodType.methodType(rtype, params); 1557 Object[] args = randomArgs(newType.parameterArray()); 1558 Object[] convArgs = args.clone(); 1559 for (int i = 0; i < args.length; i++) { 1560 Class<?> src = newType.parameterType(i); 1561 Class<?> dst = idType.parameterType(i); 1562 if (src != dst) 1563 convArgs[i] = castToWrapper(convArgs[i], dst); 1564 } 1565 Object convResult = id.invokeWithArguments(convArgs); 1566 { 1567 Class<?> dst = newType.returnType(); 1568 Class<?> src = idType.returnType(); 1569 if (src != dst) 1570 convResult = castToWrapper(convResult, dst); 1571 } 1572 MethodHandle target = null; 1573 RuntimeException error = null; 1574 try { 1575 target = id.asType(newType); 1576 } catch (WrongMethodTypeException ex) { 1577 error = ex; 1578 } 1579 if (verbosity >= 3) 1580 System.out.println("convert "+id+ " to "+newType+" => "+target 1581 +(error == null ? "" : " !! "+error)); 1582 if (positive && error != null) throw error; 1583 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 1584 if (!positive) return; // negative test failed as expected 1585 assertEquals(newType, target.type()); 1586 printCalled(target, id.toString(), args); 1587 Object result = target.invokeWithArguments(args); 1588 assertCalled(name, convArgs); 1589 assertEquals(convResult, result); 1590 if (verbosity >= 1) 1591 System.out.print(':'); 1592 } 1593 1594 @Test 1595 public void testVarargsCollector() throws Throwable { 1596 if (CAN_SKIP_WORKING) return; 1597 startTest("varargsCollector"); 1598 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called", 1599 MethodType.methodType(Object.class, String.class, Object[].class)); 1600 vac0 = vac0.bindTo("vac"); 1601 MethodHandle vac = vac0.asVarargsCollector(Object[].class); 1602 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1603 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1604 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) { 1605 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); 1606 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); 1607 } 1608 } 1609 1610 @Test // SLOW 1611 public void testPermuteArguments() throws Throwable { 1612 if (CAN_SKIP_WORKING) return; 1613 startTest("permuteArguments"); 1614 testPermuteArguments(4, Integer.class, 2, long.class, 6); 1615 if (CAN_TEST_LIGHTLY) return; 1616 testPermuteArguments(4, Integer.class, 2, String.class, 0); 1617 testPermuteArguments(6, Integer.class, 0, null, 30); 1618 } 1619 public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable { 1620 if (verbosity >= 2) 1621 System.out.println("permuteArguments "+max+"*"+type1.getName() 1622 +(t2c==0?"":"/"+t2c+"*"+type2.getName()) 1623 +(dilution > 0 ? " with dilution "+dilution : "")); 1624 int t2pos = t2c == 0 ? 0 : 1; 1625 for (int inargs = t2pos+1; inargs <= max; inargs++) { 1626 Class<?>[] types = new Class<?>[inargs]; 1627 Arrays.fill(types, type1); 1628 if (t2c != 0) { 1629 // Fill in a middle range with type2: 1630 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2); 1631 } 1632 Object[] args = randomArgs(types); 1633 int numcases = 1; 1634 for (int outargs = 0; outargs <= max; outargs++) { 1635 if (outargs - inargs >= MAX_ARG_INCREASE) continue; 1636 int casStep = dilution + 1; 1637 // Avoid some common factors: 1638 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) || 1639 (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0)) 1640 casStep++; 1641 testPermuteArguments(args, types, outargs, numcases, casStep); 1642 numcases *= inargs; 1643 if (CAN_TEST_LIGHTLY && outargs < max-2) continue; 1644 if (dilution > 10 && outargs >= 4) { 1645 if (CAN_TEST_LIGHTLY) continue; 1646 int[] reorder = new int[outargs]; 1647 // Do some special patterns, which we probably missed. 1648 // Replication of a single argument or argument pair. 1649 for (int i = 0; i < inargs; i++) { 1650 Arrays.fill(reorder, i); 1651 testPermuteArguments(args, types, reorder); 1652 for (int d = 1; d <= 2; d++) { 1653 if (i + d >= inargs) continue; 1654 for (int j = 1; j < outargs; j += 2) 1655 reorder[j] += 1; 1656 testPermuteArguments(args, types, reorder); 1657 testPermuteArguments(args, types, reverse(reorder)); 1658 } 1659 } 1660 // Repetition of a sequence of 3 or more arguments. 1661 for (int i = 1; i < inargs; i++) { 1662 for (int len = 3; len <= inargs; len++) { 1663 for (int j = 0; j < outargs; j++) 1664 reorder[j] = (i + (j % len)) % inargs; 1665 testPermuteArguments(args, types, reorder); 1666 testPermuteArguments(args, types, reverse(reorder)); 1667 } 1668 } 1669 } 1670 } 1671 } 1672 } 1673 1674 public void testPermuteArguments(Object[] args, Class<?>[] types, 1675 int outargs, int numcases, int casStep) throws Throwable { 1676 int inargs = args.length; 1677 int[] reorder = new int[outargs]; 1678 for (int cas = 0; cas < numcases; cas += casStep) { 1679 for (int i = 0, c = cas; i < outargs; i++) { 1680 reorder[i] = c % inargs; 1681 c /= inargs; 1682 } 1683 if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2])) continue; 1684 testPermuteArguments(args, types, reorder); 1685 } 1686 } 1687 1688 static int[] reverse(int[] reorder) { 1689 reorder = reorder.clone(); 1690 for (int i = 0, imax = reorder.length / 2; i < imax; i++) { 1691 int j = reorder.length - 1 - i; 1692 int tem = reorder[i]; 1693 reorder[i] = reorder[j]; 1694 reorder[j] = tem; 1695 } 1696 return reorder; 1697 } 1698 1699 void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable { 1700 countTest(); 1701 if (args == null && types == null) { 1702 int max = 0; 1703 for (int j : reorder) { 1704 if (max < j) max = j; 1705 } 1706 args = randomArgs(max+1, Integer.class); 1707 } 1708 if (args == null) { 1709 args = randomArgs(types); 1710 } 1711 if (types == null) { 1712 types = new Class<?>[args.length]; 1713 for (int i = 0; i < args.length; i++) 1714 types[i] = args[i].getClass(); 1715 } 1716 int inargs = args.length, outargs = reorder.length; 1717 assertTrue(inargs == types.length); 1718 if (verbosity >= 3) 1719 System.out.println("permuteArguments "+Arrays.toString(reorder)); 1720 Object[] permArgs = new Object[outargs]; 1721 Class<?>[] permTypes = new Class<?>[outargs]; 1722 for (int i = 0; i < outargs; i++) { 1723 permArgs[i] = args[reorder[i]]; 1724 permTypes[i] = types[reorder[i]]; 1725 } 1726 if (verbosity >= 4) { 1727 System.out.println("in args: "+Arrays.asList(args)); 1728 System.out.println("out args: "+Arrays.asList(permArgs)); 1729 System.out.println("in types: "+Arrays.asList(types)); 1730 System.out.println("out types: "+Arrays.asList(permTypes)); 1731 } 1732 MethodType inType = MethodType.methodType(Object.class, types); 1733 MethodType outType = MethodType.methodType(Object.class, permTypes); 1734 MethodHandle target = varargsList(outargs).asType(outType); 1735 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder); 1736 if (verbosity >= 5) System.out.println("newTarget = "+newTarget); 1737 Object result = newTarget.invokeWithArguments(args); 1738 Object expected = Arrays.asList(permArgs); 1739 if (!expected.equals(result)) { 1740 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types)); 1741 System.out.println("in args: "+Arrays.asList(args)); 1742 System.out.println("out args: "+expected); 1743 System.out.println("bad args: "+result); 1744 } 1745 assertEquals(expected, result); 1746 } 1747 1748 1749 @Test // SLOW 1750 public void testSpreadArguments() throws Throwable { 1751 if (CAN_SKIP_WORKING) return; 1752 startTest("spreadArguments"); 1753 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 1754 if (verbosity >= 3) 1755 System.out.println("spreadArguments "+argType); 1756 for (int nargs = 0; nargs < 50; nargs++) { 1757 if (CAN_TEST_LIGHTLY && nargs > 11) break; 1758 for (int pos = 0; pos <= nargs; pos++) { 1759 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; 1760 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) 1761 continue; 1762 testSpreadArguments(argType, pos, nargs); 1763 } 1764 } 1765 } 1766 } 1767 public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable { 1768 countTest(); 1769 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); 1770 MethodHandle target2 = varargsArray(arrayType, nargs); 1771 MethodHandle target = target2.asType(target2.type().generic()); 1772 if (verbosity >= 3) 1773 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]"); 1774 Object[] args = randomArgs(target2.type().parameterArray()); 1775 // make sure the target does what we think it does: 1776 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) { 1777 Object[] check = (Object[]) target.invokeWithArguments(args); 1778 assertArrayEquals(args, check); 1779 switch (nargs) { 1780 case 0: 1781 check = (Object[]) (Object) target.invokeExact(); 1782 assertArrayEquals(args, check); 1783 break; 1784 case 1: 1785 check = (Object[]) (Object) target.invokeExact(args[0]); 1786 assertArrayEquals(args, check); 1787 break; 1788 case 2: 1789 check = (Object[]) (Object) target.invokeExact(args[0], args[1]); 1790 assertArrayEquals(args, check); 1791 break; 1792 } 1793 } 1794 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList()); 1795 { // modify newParams in place 1796 List<Class<?>> spreadParams = newParams.subList(pos, nargs); 1797 spreadParams.clear(); spreadParams.add(arrayType); 1798 } 1799 MethodType newType = MethodType.methodType(arrayType, newParams); 1800 MethodHandle result = target2.asSpreader(arrayType, nargs-pos); 1801 assert(result.type() == newType) : Arrays.asList(result, newType); 1802 result = result.asType(newType.generic()); 1803 Object returnValue; 1804 if (pos == 0) { 1805 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 1806 returnValue = result.invokeExact(args2); 1807 } else { 1808 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1); 1809 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 1810 returnValue = result.invokeWithArguments(args1); 1811 } 1812 String argstr = Arrays.toString(args); 1813 if (!argType.isPrimitive()) { 1814 Object[] rv = (Object[]) returnValue; 1815 String rvs = Arrays.toString(rv); 1816 if (!Arrays.equals(args, rv)) { 1817 System.out.println("method: "+result); 1818 System.out.println("expected: "+argstr); 1819 System.out.println("returned: "+rvs); 1820 assertArrayEquals(args, rv); 1821 } 1822 } else if (argType == int.class) { 1823 String rvs = Arrays.toString((int[]) returnValue); 1824 if (!argstr.equals(rvs)) { 1825 System.out.println("method: "+result); 1826 System.out.println("expected: "+argstr); 1827 System.out.println("returned: "+rvs); 1828 assertEquals(argstr, rvs); 1829 } 1830 } else if (argType == long.class) { 1831 String rvs = Arrays.toString((long[]) returnValue); 1832 if (!argstr.equals(rvs)) { 1833 System.out.println("method: "+result); 1834 System.out.println("expected: "+argstr); 1835 System.out.println("returned: "+rvs); 1836 assertEquals(argstr, rvs); 1837 } 1838 } else { 1839 // cannot test... 1840 } 1841 } 1842 1843 @Test // SLOW 1844 public void testAsCollector() throws Throwable { 1845 if (CAN_SKIP_WORKING) return; 1846 startTest("asCollector"); 1847 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 1848 if (verbosity >= 3) 1849 System.out.println("asCollector "+argType); 1850 for (int nargs = 0; nargs < 50; nargs++) { 1851 if (CAN_TEST_LIGHTLY && nargs > 11) break; 1852 for (int pos = 0; pos <= nargs; pos++) { 1853 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; 1854 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) 1855 continue; 1856 testAsCollector(argType, pos, nargs); 1857 } 1858 } 1859 } 1860 } 1861 public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable { 1862 countTest(); 1863 // fake up a MH with the same type as the desired adapter: 1864 MethodHandle fake = varargsArray(nargs); 1865 fake = changeArgTypes(fake, argType); 1866 MethodType newType = fake.type(); 1867 Object[] args = randomArgs(newType.parameterArray()); 1868 // here is what should happen: 1869 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1); 1870 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length); 1871 // here is the MH which will witness the collected argument tail: 1872 MethodHandle target = varargsArray(pos+1); 1873 target = changeArgTypes(target, 0, pos, argType); 1874 target = changeArgTypes(target, pos, pos+1, Object[].class); 1875 if (verbosity >= 3) 1876 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]"); 1877 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType); 1878 Object[] returnValue = (Object[]) result.invokeWithArguments(args); 1879 // assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]); 1880 // returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]); 1881 // collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]); 1882 assertArrayEquals(collectedArgs, returnValue); 1883 } 1884 1885 @Test // SLOW 1886 public void testInsertArguments() throws Throwable { 1887 if (CAN_SKIP_WORKING) return; 1888 startTest("insertArguments"); 1889 for (int nargs = 0; nargs < 50; nargs++) { 1890 if (CAN_TEST_LIGHTLY && nargs > 11) break; 1891 for (int ins = 0; ins <= nargs; ins++) { 1892 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3) 1893 continue; 1894 for (int pos = 0; pos <= nargs; pos++) { 1895 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) 1896 continue; 1897 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; 1898 testInsertArguments(nargs, pos, ins); 1899 } 1900 } 1901 } 1902 } 1903 1904 void testInsertArguments(int nargs, int pos, int ins) throws Throwable { 1905 countTest(); 1906 MethodHandle target = varargsArray(nargs + ins); 1907 Object[] args = randomArgs(target.type().parameterArray()); 1908 List<Object> resList = Arrays.asList(args); 1909 List<Object> argsToPass = new ArrayList<>(resList); 1910 List<Object> argsToInsert = argsToPass.subList(pos, pos + ins); 1911 if (verbosity >= 3) 1912 System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target); 1913 @SuppressWarnings("cast") // cast to spread Object... is helpful 1914 MethodHandle target2 = MethodHandles.insertArguments(target, pos, 1915 (Object[]/*...*/) argsToInsert.toArray()); 1916 argsToInsert.clear(); // remove from argsToInsert 1917 Object res2 = target2.invokeWithArguments(argsToPass); 1918 Object res2List = Arrays.asList((Object[])res2); 1919 if (verbosity >= 3) 1920 System.out.println("result: "+res2List); 1921 //if (!resList.equals(res2List)) 1922 // System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List); 1923 assertEquals(resList, res2List); 1924 } 1925 1926 @Test 1927 public void testFilterReturnValue() throws Throwable { 1928 if (CAN_SKIP_WORKING) return; 1929 startTest("filterReturnValue"); 1930 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); 1931 assertTrue(List.class.isAssignableFrom(classOfVCList)); 1932 for (int nargs = 0; nargs <= 3; nargs++) { 1933 for (Class<?> rtype : new Class<?>[] { Object.class, 1934 List.class, 1935 int.class, 1936 byte.class, 1937 long.class, 1938 CharSequence.class, 1939 String.class }) { 1940 testFilterReturnValue(nargs, rtype); 1941 } 1942 } 1943 } 1944 1945 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable { 1946 countTest(); 1947 MethodHandle target = varargsList(nargs, rtype); 1948 MethodHandle filter; 1949 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class)) 1950 filter = varargsList(1); // add another layer of list-ness 1951 else 1952 filter = MethodHandles.identity(rtype); 1953 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype)); 1954 Object[] argsToPass = randomArgs(nargs, Object.class); 1955 if (verbosity >= 3) 1956 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter); 1957 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter); 1958 if (verbosity >= 4) 1959 System.out.println("filtered target: "+target2); 1960 // Simulate expected effect of filter on return value: 1961 Object unfiltered = target.invokeWithArguments(argsToPass); 1962 Object expected = filter.invokeWithArguments(unfiltered); 1963 if (verbosity >= 4) 1964 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName()); 1965 if (verbosity >= 4) 1966 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName()); 1967 Object result = target2.invokeWithArguments(argsToPass); 1968 if (verbosity >= 3) 1969 System.out.println("result: "+result+" : "+result.getClass().getSimpleName()); 1970 if (!expected.equals(result)) 1971 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1972 assertEquals(expected, result); 1973 } 1974 1975 @Test 1976 public void testFilterArguments() throws Throwable { 1977 if (CAN_SKIP_WORKING) return; 1978 startTest("filterArguments"); 1979 for (int nargs = 1; nargs <= 6; nargs++) { 1980 for (int pos = 0; pos < nargs; pos++) { 1981 testFilterArguments(nargs, pos); 1982 } 1983 } 1984 } 1985 1986 void testFilterArguments(int nargs, int pos) throws Throwable { 1987 countTest(); 1988 MethodHandle target = varargsList(nargs); 1989 MethodHandle filter = varargsList(1); 1990 filter = filter.asType(filter.type().generic()); 1991 Object[] argsToPass = randomArgs(nargs, Object.class); 1992 if (verbosity >= 3) 1993 System.out.println("filter "+target+" at "+pos+" with "+filter); 1994 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter); 1995 // Simulate expected effect of filter on arglist: 1996 Object[] filteredArgs = argsToPass.clone(); 1997 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]); 1998 List<Object> expected = Arrays.asList(filteredArgs); 1999 Object result = target2.invokeWithArguments(argsToPass); 2000 if (verbosity >= 3) 2001 System.out.println("result: "+result); 2002 if (!expected.equals(result)) 2003 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 2004 assertEquals(expected, result); 2005 } 2006 2007 @Test 2008 public void testCollectArguments() throws Throwable { 2009 if (CAN_SKIP_WORKING) return; 2010 startTest("collectArguments"); 2011 testFoldOrCollectArguments(true); 2012 } 2013 2014 @Test 2015 public void testFoldArguments() throws Throwable { 2016 if (CAN_SKIP_WORKING) return; 2017 startTest("foldArguments"); 2018 testFoldOrCollectArguments(false); 2019 } 2020 2021 void testFoldOrCollectArguments(boolean isCollect) throws Throwable { 2022 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) { 2023 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) { 2024 int maxArity = 10; 2025 if (collectType != String.class) maxArity = 5; 2026 if (lastType != Object.class) maxArity = 4; 2027 for (int nargs = 0; nargs <= maxArity; nargs++) { 2028 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class)); 2029 int maxMix = 20; 2030 if (collectType != Object.class) maxMix = 0; 2031 Map<Object,Integer> argTypesSeen = new HashMap<>(); 2032 for (int mix = 0; mix <= maxMix; mix++) { 2033 if (!mixArgs(argTypes, mix, argTypesSeen)) continue; 2034 for (int collect = 0; collect <= nargs; collect++) { 2035 for (int pos = 0; pos <= nargs - collect; pos++) { 2036 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect); 2037 } 2038 } 2039 } 2040 } 2041 } 2042 } 2043 } 2044 2045 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) { 2046 assert(mix >= 0); 2047 if (mix == 0) return true; // no change 2048 if ((mix >>> argTypes.size()) != 0) return false; 2049 for (int i = 0; i < argTypes.size(); i++) { 2050 if (i >= 31) break; 2051 boolean bit = (mix & (1 << i)) != 0; 2052 if (bit) { 2053 Class<?> type = argTypes.get(i); 2054 if (type == Object.class) 2055 type = String.class; 2056 else if (type == String.class) 2057 type = int.class; 2058 else 2059 type = Object.class; 2060 argTypes.set(i, type); 2061 } 2062 } 2063 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix); 2064 if (prev != null) { 2065 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes); 2066 return false; 2067 } 2068 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes); 2069 return true; 2070 } 2071 2072 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType 2073 int pos, int fold, // position and length of the folded arguments 2074 Class<?> combineType, // type returned from the combiner 2075 Class<?> lastType, // type returned from the target 2076 boolean isCollect) throws Throwable { 2077 int nargs = argTypes.size(); 2078 if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now 2079 countTest(); 2080 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold); 2081 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes); 2082 if (isCollect) // does targret see arg[pos..pos+cc-1]? 2083 targetArgTypes.subList(pos, pos + fold).clear(); 2084 if (combineType != void.class) 2085 targetArgTypes.add(pos, combineType); 2086 MethodHandle target = varargsList(targetArgTypes, lastType); 2087 MethodHandle combine = varargsList(combineArgTypes, combineType); 2088 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes)); 2089 if (verbosity >= 3) 2090 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine); 2091 MethodHandle target2; 2092 if (isCollect) 2093 target2 = MethodHandles.collectArguments(target, pos, combine); 2094 else 2095 target2 = MethodHandles.foldArguments(target, combine); 2096 // Simulate expected effect of combiner on arglist: 2097 List<Object> expectedList = new ArrayList<>(argsToPass); 2098 List<Object> argsToFold = expectedList.subList(pos, pos + fold); 2099 if (verbosity >= 3) 2100 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2); 2101 Object foldedArgs = combine.invokeWithArguments(argsToFold); 2102 if (isCollect) 2103 argsToFold.clear(); 2104 if (combineType != void.class) 2105 argsToFold.add(0, foldedArgs); 2106 Object result = target2.invokeWithArguments(argsToPass); 2107 if (verbosity >= 3) 2108 System.out.println("result: "+result); 2109 Object expected = target.invokeWithArguments(expectedList); 2110 if (!expected.equals(result)) 2111 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); 2112 assertEquals(expected, result); 2113 } 2114 2115 @Test 2116 public void testDropArguments() throws Throwable { 2117 if (CAN_SKIP_WORKING) return; 2118 startTest("dropArguments"); 2119 for (int nargs = 0; nargs <= 4; nargs++) { 2120 for (int drop = 1; drop <= 4; drop++) { 2121 for (int pos = 0; pos <= nargs; pos++) { 2122 testDropArguments(nargs, pos, drop); 2123 } 2124 } 2125 } 2126 } 2127 2128 void testDropArguments(int nargs, int pos, int drop) throws Throwable { 2129 countTest(); 2130 MethodHandle target = varargsArray(nargs); 2131 Object[] args = randomArgs(target.type().parameterArray()); 2132 MethodHandle target2 = MethodHandles.dropArguments(target, pos, 2133 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0])); 2134 List<Object> resList = Arrays.asList(args); 2135 List<Object> argsToDrop = new ArrayList<>(resList); 2136 for (int i = drop; i > 0; i--) { 2137 argsToDrop.add(pos, "blort#"+i); 2138 } 2139 Object res2 = target2.invokeWithArguments(argsToDrop); 2140 Object res2List = Arrays.asList((Object[])res2); 2141 //if (!resList.equals(res2List)) 2142 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); 2143 assertEquals(resList, res2List); 2144 } 2145 2146 @Test // SLOW 2147 public void testInvokers() throws Throwable { 2148 if (CAN_SKIP_WORKING) return; 2149 startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker"); 2150 // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker 2151 Set<MethodType> done = new HashSet<>(); 2152 for (int i = 0; i <= 6; i++) { 2153 if (CAN_TEST_LIGHTLY && i > 3) break; 2154 MethodType gtype = MethodType.genericMethodType(i); 2155 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 2156 for (int j = -1; j < i; j++) { 2157 MethodType type = gtype; 2158 if (j < 0) 2159 type = type.changeReturnType(argType); 2160 else if (argType == void.class) 2161 continue; 2162 else 2163 type = type.changeParameterType(j, argType); 2164 if (done.add(type)) 2165 testInvokers(type); 2166 MethodType vtype = type.changeReturnType(void.class); 2167 if (done.add(vtype)) 2168 testInvokers(vtype); 2169 } 2170 } 2171 } 2172 } 2173 2174 public void testInvokers(MethodType type) throws Throwable { 2175 if (verbosity >= 3) 2176 System.out.println("test invokers for "+type); 2177 int nargs = type.parameterCount(); 2178 boolean testRetCode = type.returnType() != void.class; 2179 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee", 2180 MethodType.genericMethodType(0, true)); 2181 assertTrue(target.isVarargsCollector()); 2182 target = target.asType(type); 2183 Object[] args = randomArgs(type.parameterArray()); 2184 List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args)); 2185 targetPlusArgs.add(0, target); 2186 int code = (Integer) invokee(args); 2187 Object log = logEntry("invokee", args); 2188 assertEquals(log.hashCode(), code); 2189 assertCalled("invokee", args); 2190 MethodHandle inv; 2191 Object result; 2192 // exact invoker 2193 countTest(); 2194 calledLog.clear(); 2195 inv = MethodHandles.exactInvoker(type); 2196 result = inv.invokeWithArguments(targetPlusArgs); 2197 if (testRetCode) assertEquals(code, result); 2198 assertCalled("invokee", args); 2199 // generic invoker 2200 countTest(); 2201 inv = MethodHandles.invoker(type); 2202 if (nargs <= 3 && type == type.generic()) { 2203 calledLog.clear(); 2204 switch (nargs) { 2205 case 0: 2206 result = inv.invokeExact(target); 2207 break; 2208 case 1: 2209 result = inv.invokeExact(target, args[0]); 2210 break; 2211 case 2: 2212 result = inv.invokeExact(target, args[0], args[1]); 2213 break; 2214 case 3: 2215 result = inv.invokeExact(target, args[0], args[1], args[2]); 2216 break; 2217 } 2218 if (testRetCode) assertEquals(code, result); 2219 assertCalled("invokee", args); 2220 } 2221 calledLog.clear(); 2222 result = inv.invokeWithArguments(targetPlusArgs); 2223 if (testRetCode) assertEquals(code, result); 2224 assertCalled("invokee", args); 2225 // varargs invoker #0 2226 calledLog.clear(); 2227 inv = MethodHandles.spreadInvoker(type, 0); 2228 if (type.returnType() == Object.class) { 2229 result = inv.invokeExact(target, args); 2230 } else if (type.returnType() == void.class) { 2231 result = null; inv.invokeExact(target, args); 2232 } else { 2233 result = inv.invokeWithArguments(target, (Object) args); 2234 } 2235 if (testRetCode) assertEquals(code, result); 2236 assertCalled("invokee", args); 2237 if (nargs >= 1 && type == type.generic()) { 2238 // varargs invoker #1 2239 calledLog.clear(); 2240 inv = MethodHandles.spreadInvoker(type, 1); 2241 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs)); 2242 if (testRetCode) assertEquals(code, result); 2243 assertCalled("invokee", args); 2244 } 2245 if (nargs >= 2 && type == type.generic()) { 2246 // varargs invoker #2 2247 calledLog.clear(); 2248 inv = MethodHandles.spreadInvoker(type, 2); 2249 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs)); 2250 if (testRetCode) assertEquals(code, result); 2251 assertCalled("invokee", args); 2252 } 2253 if (nargs >= 3 && type == type.generic()) { 2254 // varargs invoker #3 2255 calledLog.clear(); 2256 inv = MethodHandles.spreadInvoker(type, 3); 2257 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs)); 2258 if (testRetCode) assertEquals(code, result); 2259 assertCalled("invokee", args); 2260 } 2261 for (int k = 0; k <= nargs; k++) { 2262 // varargs invoker #0..N 2263 if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue; 2264 countTest(); 2265 calledLog.clear(); 2266 inv = MethodHandles.spreadInvoker(type, k); 2267 MethodType expType = (type.dropParameterTypes(k, nargs) 2268 .appendParameterTypes(Object[].class) 2269 .insertParameterTypes(0, MethodHandle.class)); 2270 assertEquals(expType, inv.type()); 2271 List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs); 2272 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs); 2273 Object[] tail = tailList.toArray(); 2274 tailList.clear(); tailList.add(tail); 2275 result = inv.invokeWithArguments(targetPlusVarArgs); 2276 if (testRetCode) assertEquals(code, result); 2277 assertCalled("invokee", args); 2278 } 2279 2280 // dynamic invoker 2281 countTest(); 2282 CallSite site = new MutableCallSite(type); 2283 inv = site.dynamicInvoker(); 2284 2285 // see if we get the result of the original target: 2286 try { 2287 result = inv.invokeWithArguments(args); 2288 assertTrue("should not reach here", false); 2289 } catch (IllegalStateException ex) { 2290 String msg = ex.getMessage(); 2291 assertTrue(msg, msg.contains("site")); 2292 } 2293 2294 // set new target after invoker is created, to make sure we track target 2295 site.setTarget(target); 2296 calledLog.clear(); 2297 result = inv.invokeWithArguments(args); 2298 if (testRetCode) assertEquals(code, result); 2299 assertCalled("invokee", args); 2300 } 2301 2302 static Object invokee(Object... args) { 2303 return called("invokee", args).hashCode(); 2304 } 2305 2306 private static final String MISSING_ARG = "missingArg"; 2307 private static final String MISSING_ARG_2 = "missingArg#2"; 2308 static Object targetIfEquals() { 2309 return called("targetIfEquals"); 2310 } 2311 static Object fallbackIfNotEquals() { 2312 return called("fallbackIfNotEquals"); 2313 } 2314 static Object targetIfEquals(Object x) { 2315 assertEquals(x, MISSING_ARG); 2316 return called("targetIfEquals", x); 2317 } 2318 static Object fallbackIfNotEquals(Object x) { 2319 assertFalse(x.toString(), x.equals(MISSING_ARG)); 2320 return called("fallbackIfNotEquals", x); 2321 } 2322 static Object targetIfEquals(Object x, Object y) { 2323 assertEquals(x, y); 2324 return called("targetIfEquals", x, y); 2325 } 2326 static Object fallbackIfNotEquals(Object x, Object y) { 2327 assertFalse(x.toString(), x.equals(y)); 2328 return called("fallbackIfNotEquals", x, y); 2329 } 2330 static Object targetIfEquals(Object x, Object y, Object z) { 2331 assertEquals(x, y); 2332 return called("targetIfEquals", x, y, z); 2333 } 2334 static Object fallbackIfNotEquals(Object x, Object y, Object z) { 2335 assertFalse(x.toString(), x.equals(y)); 2336 return called("fallbackIfNotEquals", x, y, z); 2337 } 2338 2339 @Test 2340 public void testGuardWithTest() throws Throwable { 2341 if (CAN_SKIP_WORKING) return; 2342 startTest("guardWithTest"); 2343 for (int nargs = 0; nargs <= 50; nargs++) { 2344 if (CAN_TEST_LIGHTLY && nargs > 7) break; 2345 testGuardWithTest(nargs, Object.class); 2346 testGuardWithTest(nargs, String.class); 2347 } 2348 } 2349 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 2350 testGuardWithTest(nargs, 0, argClass); 2351 if (nargs <= 5 || nargs % 10 == 3) { 2352 for (int testDrops = 1; testDrops <= nargs; testDrops++) 2353 testGuardWithTest(nargs, testDrops, argClass); 2354 } 2355 } 2356 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable { 2357 countTest(); 2358 int nargs1 = Math.min(3, nargs); 2359 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 2360 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1)); 2361 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1)); 2362 while (test.type().parameterCount() > nargs) 2363 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG)) 2364 // 1: test = lambda (_) MISSING_ARG.equals(_) 2365 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 2366 if (argClass != Object.class) { 2367 test = changeArgTypes(test, argClass); 2368 target = changeArgTypes(target, argClass); 2369 fallback = changeArgTypes(fallback, argClass); 2370 } 2371 int testArgs = nargs - testDrops; 2372 assert(testArgs >= 0); 2373 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass); 2374 target = addTrailingArgs(target, nargs, argClass); 2375 fallback = addTrailingArgs(fallback, nargs, argClass); 2376 Object[][] argLists = { 2377 { }, 2378 { "foo" }, { MISSING_ARG }, 2379 { "foo", "foo" }, { "foo", "bar" }, 2380 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 2381 }; 2382 for (Object[] argList : argLists) { 2383 Object[] argList1 = argList; 2384 if (argList.length != nargs) { 2385 if (argList.length != nargs1) continue; 2386 argList1 = Arrays.copyOf(argList, nargs); 2387 Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2); 2388 } 2389 MethodHandle test1 = test; 2390 if (test1.type().parameterCount() > testArgs) { 2391 int pc = test1.type().parameterCount(); 2392 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc)); 2393 } 2394 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback); 2395 assertEquals(target.type(), mh.type()); 2396 boolean equals; 2397 switch (nargs) { 2398 case 0: equals = true; break; 2399 case 1: equals = MISSING_ARG.equals(argList[0]); break; 2400 default: equals = argList[0].equals(argList[1]); break; 2401 } 2402 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 2403 if (verbosity >= 3) 2404 System.out.println(logEntry(willCall, argList)); 2405 Object result = mh.invokeWithArguments(argList1); 2406 assertCalled(willCall, argList); 2407 } 2408 } 2409 2410 @Test 2411 public void testCatchException() throws Throwable { 2412 if (CAN_SKIP_WORKING) return; 2413 startTest("catchException"); 2414 for (int nargs = 0; nargs < 40; nargs++) { 2415 if (CAN_TEST_LIGHTLY && nargs > 11) break; 2416 for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) { 2417 testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs); 2418 if (CAN_TEST_LIGHTLY && nargs > 3) continue; 2419 testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs); 2420 testCatchException(String.class, new LinkageError("testing"), throwMode, nargs); 2421 } 2422 } 2423 } 2424 2425 static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4; 2426 2427 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable { 2428 testCatchException(returnType, thrown, throwMode, nargs, 0); 2429 if (nargs <= 5 || nargs % 10 == 3) { 2430 for (int catchDrops = 1; catchDrops <= nargs; catchDrops++) 2431 testCatchException(returnType, thrown, throwMode, nargs, catchDrops); 2432 } 2433 } 2434 2435 private static <T extends Throwable> 2436 Object throwOrReturn(Object normal, T exception) throws T { 2437 if (exception != null) { 2438 called("throwOrReturn/throw", normal, exception); 2439 throw exception; 2440 } 2441 called("throwOrReturn/normal", normal, exception); 2442 return normal; 2443 } 2444 private int fakeIdentityCount; 2445 private Object fakeIdentity(Object x) { 2446 System.out.println("should throw through this!"); 2447 fakeIdentityCount++; 2448 return x; 2449 } 2450 2451 void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable { 2452 countTest(); 2453 if (verbosity >= 3) 2454 System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops); 2455 Class<? extends Throwable> exType = thrown.getClass(); 2456 if (throwMode > THROW_CAUGHT) thrown = new UnsupportedOperationException("do not catch this"); 2457 MethodHandle throwOrReturn 2458 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn", 2459 MethodType.methodType(Object.class, Object.class, Throwable.class)); 2460 if (throwMode == THROW_THROUGH_ADAPTER) { 2461 MethodHandle fakeIdentity 2462 = PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity", 2463 MethodType.methodType(Object.class, Object.class)).bindTo(this); 2464 for (int i = 0; i < 10; i++) 2465 throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity); 2466 } 2467 int nargs1 = Math.max(2, nargs); 2468 MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2)); 2469 thrower = addTrailingArgs(thrower, nargs, Object.class); 2470 int catchArgc = 1 + nargs - catchDrops; 2471 MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc)); 2472 Object[] args = randomArgs(nargs, Object.class); 2473 Object arg0 = MISSING_ARG; 2474 Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown; 2475 if (nargs > 0) arg0 = args[0]; 2476 if (nargs > 1) args[1] = arg1; 2477 assertEquals(nargs1, thrower.type().parameterCount()); 2478 if (nargs < nargs1) { 2479 Object[] appendArgs = { arg0, arg1 }; 2480 appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1); 2481 thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs); 2482 } 2483 assertEquals(nargs, thrower.type().parameterCount()); 2484 MethodHandle target = MethodHandles.catchException(thrower, exType, catcher); 2485 assertEquals(thrower.type(), target.type()); 2486 assertEquals(nargs, target.type().parameterCount()); 2487 //System.out.println("catching with "+target+" : "+throwOrReturn); 2488 Object returned; 2489 try { 2490 returned = target.invokeWithArguments(args); 2491 } catch (Throwable ex) { 2492 assertSame("must get the out-of-band exception", thrown, ex); 2493 if (throwMode <= THROW_CAUGHT) 2494 assertEquals(THROW_UNCAUGHT, throwMode); 2495 returned = ex; 2496 } 2497 assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1); 2498 //System.out.println("return from "+target+" : "+returned); 2499 if (throwMode == THROW_NOTHING) { 2500 assertSame(arg0, returned); 2501 } else if (throwMode == THROW_CAUGHT) { 2502 List<Object> catchArgs = new ArrayList<>(Arrays.asList(args)); 2503 // catcher receives an initial subsequence of target arguments: 2504 catchArgs.subList(nargs - catchDrops, nargs).clear(); 2505 // catcher also receives the exception, prepended: 2506 catchArgs.add(0, thrown); 2507 assertEquals(catchArgs, returned); 2508 } 2509 assertEquals(0, fakeIdentityCount); 2510 } 2511 2512 @Test 2513 public void testThrowException() throws Throwable { 2514 if (CAN_SKIP_WORKING) return; 2515 startTest("throwException"); 2516 testThrowException(int.class, new ClassCastException("testing")); 2517 testThrowException(void.class, new java.io.IOException("testing")); 2518 testThrowException(String.class, new LinkageError("testing")); 2519 } 2520 2521 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 2522 countTest(); 2523 Class<? extends Throwable> exType = thrown.getClass(); 2524 MethodHandle target = MethodHandles.throwException(returnType, exType); 2525 //System.out.println("throwing with "+target+" : "+thrown); 2526 MethodType expectedType = MethodType.methodType(returnType, exType); 2527 assertEquals(expectedType, target.type()); 2528 target = target.asType(target.type().generic()); 2529 Throwable caught = null; 2530 try { 2531 Object res = target.invokeExact((Object) thrown); 2532 fail("got "+res+" instead of throwing "+thrown); 2533 } catch (Throwable ex) { 2534 if (ex != thrown) { 2535 if (ex instanceof Error) throw (Error)ex; 2536 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 2537 } 2538 caught = ex; 2539 } 2540 assertSame(thrown, caught); 2541 } 2542 2543 @Test 2544 public void testInterfaceCast() throws Throwable { 2545 //if (CAN_SKIP_WORKING) return; 2546 startTest("interfaceCast"); 2547 assert( (((Object)"foo") instanceof CharSequence)); 2548 assert(!(((Object)"foo") instanceof Iterable)); 2549 for (MethodHandle mh : new MethodHandle[]{ 2550 MethodHandles.identity(String.class), 2551 MethodHandles.identity(CharSequence.class), 2552 MethodHandles.identity(Iterable.class) 2553 }) { 2554 if (verbosity > 0) System.out.println("-- mh = "+mh); 2555 for (Class<?> ctype : new Class<?>[]{ 2556 Object.class, String.class, CharSequence.class, 2557 Number.class, Iterable.class 2558 }) { 2559 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); 2560 // doret docast 2561 testInterfaceCast(mh, ctype, false, false); 2562 testInterfaceCast(mh, ctype, true, false); 2563 testInterfaceCast(mh, ctype, false, true); 2564 testInterfaceCast(mh, ctype, true, true); 2565 } 2566 } 2567 } 2568 private static Class<?> i2o(Class<?> c) { 2569 return (c.isInterface() ? Object.class : c); 2570 } 2571 public void testInterfaceCast(MethodHandle mh, Class<?> ctype, 2572 boolean doret, boolean docast) throws Throwable { 2573 MethodHandle mh0 = mh; 2574 if (verbosity > 1) 2575 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast); 2576 String normalRetVal = "normal return value"; 2577 MethodType mt = mh.type(); 2578 MethodType mt0 = mt; 2579 if (doret) mt = mt.changeReturnType(ctype); 2580 else mt = mt.changeParameterType(0, ctype); 2581 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt); 2582 else mh = mh.asType(mt); 2583 assertEquals(mt, mh.type()); 2584 MethodType mt1 = mt; 2585 // this bit is needed to make the interface types disappear for invokeWithArguments: 2586 mh = MethodHandles.explicitCastArguments(mh, mt.generic()); 2587 Class<?>[] step = { 2588 mt1.parameterType(0), // param as passed to mh at first 2589 mt0.parameterType(0), // param after incoming cast 2590 mt0.returnType(), // return value before cast 2591 mt1.returnType(), // return value after outgoing cast 2592 }; 2593 // where might a checkCast occur? 2594 boolean[] checkCast = new boolean[step.length]; 2595 // the string value must pass each step without causing an exception 2596 if (!docast) { 2597 if (!doret) { 2598 if (step[0] != step[1]) 2599 checkCast[1] = true; // incoming value is cast 2600 } else { 2601 if (step[2] != step[3]) 2602 checkCast[3] = true; // outgoing value is cast 2603 } 2604 } 2605 boolean expectFail = false; 2606 for (int i = 0; i < step.length; i++) { 2607 Class<?> c = step[i]; 2608 if (!checkCast[i]) c = i2o(c); 2609 if (!c.isInstance(normalRetVal)) { 2610 if (verbosity > 3) 2611 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast)); 2612 expectFail = true; 2613 break; 2614 } 2615 } 2616 countTest(!expectFail); 2617 if (verbosity > 2) 2618 System.out.println("expectFail="+expectFail+", mt="+mt); 2619 Object res; 2620 try { 2621 res = mh.invokeWithArguments(normalRetVal); 2622 } catch (Exception ex) { 2623 res = ex; 2624 } 2625 boolean sawFail = !(res instanceof String); 2626 if (sawFail != expectFail) { 2627 System.out.println("*** testInterfaceCast: mh0 = "+mh0); 2628 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh); 2629 System.out.println(" call returned "+res); 2630 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal)); 2631 } 2632 if (!expectFail) { 2633 assertFalse(res.toString(), sawFail); 2634 assertEquals(normalRetVal, res); 2635 } else { 2636 assertTrue(res.toString(), sawFail); 2637 } 2638 } 2639 2640 @Test // SLOW 2641 public void testCastFailure() throws Throwable { 2642 if (CAN_SKIP_WORKING) return; 2643 startTest("testCastFailure"); 2644 testCastFailure("cast/argument", 11000); 2645 if (CAN_TEST_LIGHTLY) return; 2646 testCastFailure("unbox/argument", 11000); 2647 testCastFailure("cast/return", 11000); 2648 testCastFailure("unbox/return", 11000); 2649 } 2650 2651 static class Surprise { 2652 public MethodHandle asMethodHandle() { 2653 return VALUE.bindTo(this); 2654 } 2655 Object value(Object x) { 2656 trace("value", x); 2657 if (boo != null) return boo; 2658 return x; 2659 } 2660 Object boo; 2661 void boo(Object x) { boo = x; } 2662 2663 static void trace(String x, Object y) { 2664 if (verbosity > 8) System.out.println(x+"="+y); 2665 } 2666 static Object refIdentity(Object x) { trace("ref.x", x); return x; } 2667 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; } 2668 static int intIdentity(int x) { trace("int.x", x); return x; } 2669 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY; 2670 static { 2671 try { 2672 VALUE = PRIVATE.findVirtual( 2673 Surprise.class, "value", 2674 MethodType.methodType(Object.class, Object.class)); 2675 REF_IDENTITY = PRIVATE.findStatic( 2676 Surprise.class, "refIdentity", 2677 MethodType.methodType(Object.class, Object.class)); 2678 BOX_IDENTITY = PRIVATE.findStatic( 2679 Surprise.class, "boxIdentity", 2680 MethodType.methodType(Integer.class, Integer.class)); 2681 INT_IDENTITY = PRIVATE.findStatic( 2682 Surprise.class, "intIdentity", 2683 MethodType.methodType(int.class, int.class)); 2684 } catch (NoSuchMethodException | IllegalAccessException ex) { 2685 throw new RuntimeException(ex); 2686 } 2687 } 2688 } 2689 2690 @SuppressWarnings("ConvertToStringSwitch") 2691 void testCastFailure(String mode, int okCount) throws Throwable { 2692 countTest(false); 2693 if (verbosity > 2) System.out.println("mode="+mode); 2694 Surprise boo = new Surprise(); 2695 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0; 2696 if (mode.endsWith("/return")) { 2697 if (mode.equals("unbox/return")) { 2698 // fail on return to ((Integer)surprise).intValue 2699 surprise = surprise.asType(MethodType.methodType(int.class, Object.class)); 2700 identity = identity.asType(MethodType.methodType(int.class, Object.class)); 2701 } else if (mode.equals("cast/return")) { 2702 // fail on return to (Integer)surprise 2703 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class)); 2704 identity = identity.asType(MethodType.methodType(Integer.class, Object.class)); 2705 } 2706 } else if (mode.endsWith("/argument")) { 2707 MethodHandle callee = null; 2708 if (mode.equals("unbox/argument")) { 2709 // fail on handing surprise to int argument 2710 callee = Surprise.INT_IDENTITY; 2711 } else if (mode.equals("cast/argument")) { 2712 // fail on handing surprise to Integer argument 2713 callee = Surprise.BOX_IDENTITY; 2714 } 2715 if (callee != null) { 2716 callee = callee.asType(MethodType.genericMethodType(1)); 2717 surprise = MethodHandles.filterArguments(callee, 0, surprise); 2718 identity = MethodHandles.filterArguments(callee, 0, identity); 2719 } 2720 } 2721 assertNotSame(mode, surprise, surprise0); 2722 identity = identity.asType(MethodType.genericMethodType(1)); 2723 surprise = surprise.asType(MethodType.genericMethodType(1)); 2724 Object x = 42; 2725 for (int i = 0; i < okCount; i++) { 2726 Object y = identity.invokeExact(x); 2727 assertEquals(x, y); 2728 Object z = surprise.invokeExact(x); 2729 assertEquals(x, z); 2730 } 2731 boo.boo("Boo!"); 2732 Object y = identity.invokeExact(x); 2733 assertEquals(x, y); 2734 try { 2735 Object z = surprise.invokeExact(x); 2736 System.out.println("Failed to throw; got z="+z); 2737 assertTrue(false); 2738 } catch (ClassCastException ex) { 2739 if (verbosity > 2) 2740 System.out.println("caught "+ex); 2741 if (verbosity > 3) 2742 ex.printStackTrace(System.out); 2743 assertTrue(true); // all is well 2744 } 2745 } 2746 2747 static Example userMethod(Object o, String s, int i) { 2748 called("userMethod", o, s, i); 2749 return null; 2750 } 2751 2752 @Test 2753 public void testUserClassInSignature() throws Throwable { 2754 if (CAN_SKIP_WORKING) return; 2755 startTest("testUserClassInSignature"); 2756 Lookup lookup = MethodHandles.lookup(); 2757 String name; MethodType mt; MethodHandle mh; 2758 Object[] args; 2759 2760 // Try a static method. 2761 name = "userMethod"; 2762 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 2763 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 2764 assertEquals(mt, mh.type()); 2765 assertEquals(Example.class, mh.type().returnType()); 2766 args = randomArgs(mh.type().parameterArray()); 2767 mh.invokeWithArguments(args); 2768 assertCalled(name, args); 2769 2770 // Try a virtual method. 2771 name = "v2"; 2772 mt = MethodType.methodType(Object.class, Object.class, int.class); 2773 mh = lookup.findVirtual(Example.class, name, mt); 2774 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 2775 assertTrue(mh.type().parameterList().contains(Example.class)); 2776 args = randomArgs(mh.type().parameterArray()); 2777 mh.invokeWithArguments(args); 2778 assertCalled(name, args); 2779 } 2780 2781 static void runForRunnable() { 2782 called("runForRunnable"); 2783 } 2784 public interface Fooable { 2785 // overloads: 2786 Object foo(Object x, String y); 2787 List<?> foo(String x, int y); 2788 Object foo(String x); 2789 } 2790 static Object fooForFooable(String x, Object... y) { 2791 return called("fooForFooable/"+x, y); 2792 } 2793 @SuppressWarnings("serial") // not really a public API, just a test case 2794 public static class MyCheckedException extends Exception { 2795 } 2796 public interface WillThrow { 2797 void willThrow() throws MyCheckedException; 2798 } 2799 /*non-public*/ interface PrivateRunnable { 2800 public void run(); 2801 } 2802 2803 @Test 2804 public void testAsInterfaceInstance() throws Throwable { 2805 if (CAN_SKIP_WORKING) return; 2806 startTest("asInterfaceInstance"); 2807 Lookup lookup = MethodHandles.lookup(); 2808 // test typical case: Runnable.run 2809 { 2810 countTest(); 2811 if (verbosity >= 2) System.out.println("Runnable"); 2812 MethodType mt = MethodType.methodType(void.class); 2813 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt); 2814 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 2815 proxy.run(); 2816 assertCalled("runForRunnable"); 2817 } 2818 // well known single-name overloaded interface: Appendable.append 2819 { 2820 countTest(); 2821 if (verbosity >= 2) System.out.println("Appendable"); 2822 ArrayList<List<?>> appendResults = new ArrayList<>(); 2823 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); 2824 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type 2825 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 2826 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class); 2827 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh); 2828 proxy.append("one"); 2829 proxy.append("two", 3, 4); 2830 proxy.append('5'); 2831 assertEquals(Arrays.asList(Arrays.asList("one"), 2832 Arrays.asList("two", 3, 4), 2833 Arrays.asList('5')), 2834 appendResults); 2835 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 2836 appendResults.clear(); 2837 Formatter formatter = new Formatter(proxy); 2838 String fmt = "foo str=%s char='%c' num=%d"; 2839 Object[] fmtArgs = { "str!", 'C', 42 }; 2840 String expect = String.format(fmt, fmtArgs); 2841 formatter.format(fmt, fmtArgs); 2842 String actual = ""; 2843 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 2844 for (List<?> l : appendResults) { 2845 Object x = l.get(0); 2846 switch (l.size()) { 2847 case 1: actual += x; continue; 2848 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue; 2849 } 2850 actual += l; 2851 } 2852 if (verbosity >= 3) System.out.println("expect="+expect); 2853 if (verbosity >= 3) System.out.println("actual="+actual); 2854 assertEquals(expect, actual); 2855 } 2856 // test case of an single name which is overloaded: Fooable.foo(...) 2857 { 2858 if (verbosity >= 2) System.out.println("Fooable"); 2859 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", 2860 MethodType.methodType(Object.class, String.class, Object[].class)); 2861 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 2862 for (Method m : Fooable.class.getDeclaredMethods()) { 2863 countTest(); 2864 assertSame("foo", m.getName()); 2865 if (verbosity > 3) 2866 System.out.println("calling "+m); 2867 MethodHandle invoker = lookup.unreflect(m); 2868 MethodType mt = invoker.type(); 2869 Class<?>[] types = mt.parameterArray(); 2870 types[0] = int.class; // placeholder 2871 Object[] args = randomArgs(types); 2872 args[0] = proxy; 2873 if (verbosity > 3) 2874 System.out.println("calling "+m+" on "+Arrays.asList(args)); 2875 Object result = invoker.invokeWithArguments(args); 2876 if (verbosity > 4) 2877 System.out.println("result = "+result); 2878 String name = "fooForFooable/"+args[1]; 2879 Object[] argTail = Arrays.copyOfRange(args, 2, args.length); 2880 assertCalled(name, argTail); 2881 assertEquals(result, logEntry(name, argTail)); 2882 } 2883 } 2884 // test processing of thrown exceptions: 2885 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 2886 new InternalError("ok"), 2887 new Throwable("fail"), 2888 new Exception("fail"), 2889 new MyCheckedException() 2890 }) { 2891 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 2892 mh = MethodHandles.insertArguments(mh, 0, ex); 2893 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 2894 try { 2895 countTest(); 2896 proxy.willThrow(); 2897 System.out.println("Failed to throw: "+ex); 2898 assertTrue(false); 2899 } catch (Throwable ex1) { 2900 if (verbosity > 3) { 2901 System.out.println("throw "+ex); 2902 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 2903 } 2904 if (ex instanceof RuntimeException || 2905 ex instanceof Error) { 2906 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 2907 } else if (ex instanceof MyCheckedException) { 2908 assertSame("must pass declared exception out without wrapping", ex, ex1); 2909 } else { 2910 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 2911 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { 2912 ex1.printStackTrace(System.out); 2913 } 2914 assertSame(ex, ex1.getCause()); 2915 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 2916 } 2917 } 2918 } 2919 // Test error checking on bad interfaces: 2920 for (Class<?> nonSMI : new Class<?>[] { Object.class, 2921 String.class, 2922 CharSequence.class, 2923 java.io.Serializable.class, 2924 PrivateRunnable.class, 2925 Example.class }) { 2926 if (verbosity > 2) System.out.println(nonSMI.getName()); 2927 try { 2928 countTest(false); 2929 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0)); 2930 assertTrue("Failed to throw on "+nonSMI.getName(), false); 2931 } catch (IllegalArgumentException ex) { 2932 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex); 2933 // Object: java.lang.IllegalArgumentException: 2934 // not a public interface: java.lang.Object 2935 // String: java.lang.IllegalArgumentException: 2936 // not a public interface: java.lang.String 2937 // CharSequence: java.lang.IllegalArgumentException: 2938 // not a single-method interface: java.lang.CharSequence 2939 // Serializable: java.lang.IllegalArgumentException: 2940 // not a single-method interface: java.io.Serializable 2941 // PrivateRunnable: java.lang.IllegalArgumentException: 2942 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable 2943 // Example: java.lang.IllegalArgumentException: 2944 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example 2945 } 2946 } 2947 // Test error checking on interfaces with the wrong method type: 2948 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/, 2949 Fooable.class /*arity 1 & 2*/ }) { 2950 int badArity = 1; // known to be incompatible 2951 if (verbosity > 2) System.out.println(intfc.getName()); 2952 try { 2953 countTest(false); 2954 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity)); 2955 assertTrue("Failed to throw on "+intfc.getName(), false); 2956 } catch (WrongMethodTypeException ex) { 2957 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex); 2958 // Runnable: java.lang.invoke.WrongMethodTypeException: 2959 // cannot convert MethodHandle(Object)Object[] to ()void 2960 // Fooable: java.lang.invoke.WrongMethodTypeException: 2961 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object 2962 } 2963 } 2964 } 2965 2966 @Test 2967 public void testRunnableProxy() throws Throwable { 2968 if (CAN_SKIP_WORKING) return; 2969 startTest("testRunnableProxy"); 2970 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2971 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); 2972 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); 2973 testRunnableProxy(r); 2974 assertCalled("runForRunnable"); 2975 } 2976 private static void testRunnableProxy(Runnable r) { 2977 //7058630: JSR 292 method handle proxy violates contract for Object methods 2978 r.run(); 2979 Object o = r; 2980 r = null; 2981 boolean eq = (o == o); 2982 int hc = System.identityHashCode(o); 2983 String st = o.getClass().getName() + "@" + Integer.toHexString(hc); 2984 Object expect = Arrays.asList(st, eq, hc); 2985 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect); 2986 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode()); 2987 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual); 2988 assertEquals(expect, actual); 2989 } 2990 } 2991 // Local abbreviated copy of sun.invoke.util.ValueConversions 2992 // This guy tests access from outside the same package member, but inside 2993 // the package itself. 2994 class ValueConversions { 2995 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); 2996 private static final Object[] NO_ARGS_ARRAY = {}; 2997 private static Object[] makeArray(Object... args) { return args; } 2998 private static Object[] array() { return NO_ARGS_ARRAY; } 2999 private static Object[] array(Object a0) 3000 { return makeArray(a0); } 3001 private static Object[] array(Object a0, Object a1) 3002 { return makeArray(a0, a1); } 3003 private static Object[] array(Object a0, Object a1, Object a2) 3004 { return makeArray(a0, a1, a2); } 3005 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 3006 { return makeArray(a0, a1, a2, a3); } 3007 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3008 Object a4) 3009 { return makeArray(a0, a1, a2, a3, a4); } 3010 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3011 Object a4, Object a5) 3012 { return makeArray(a0, a1, a2, a3, a4, a5); } 3013 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3014 Object a4, Object a5, Object a6) 3015 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 3016 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3017 Object a4, Object a5, Object a6, Object a7) 3018 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 3019 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3020 Object a4, Object a5, Object a6, Object a7, 3021 Object a8) 3022 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 3023 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 3024 Object a4, Object a5, Object a6, Object a7, 3025 Object a8, Object a9) 3026 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 3027 static MethodHandle[] makeArrays() { 3028 ArrayList<MethodHandle> arrays = new ArrayList<>(); 3029 MethodHandles.Lookup lookup = IMPL_LOOKUP; 3030 for (;;) { 3031 int nargs = arrays.size(); 3032 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); 3033 String name = "array"; 3034 MethodHandle array = null; 3035 try { 3036 array = lookup.findStatic(ValueConversions.class, name, type); 3037 } catch (ReflectiveOperationException ex) { 3038 // break from loop! 3039 } 3040 if (array == null) break; 3041 arrays.add(array); 3042 } 3043 assertTrue(arrays.size() == 11); // current number of methods 3044 return arrays.toArray(new MethodHandle[0]); 3045 } 3046 static final MethodHandle[] ARRAYS = makeArrays(); 3047 3048 /** Return a method handle that takes the indicated number of Object 3049 * arguments and returns an Object array of them, as if for varargs. 3050 */ 3051 public static MethodHandle varargsArray(int nargs) { 3052 if (nargs < ARRAYS.length) 3053 return ARRAYS[nargs]; 3054 return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs); 3055 } 3056 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 3057 Class<?> elemType = arrayType.getComponentType(); 3058 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)); 3059 MethodHandle mh = varargsArray(nargs); 3060 if (arrayType != Object[].class) 3061 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType)); 3062 return mh.asType(vaType); 3063 } 3064 static Object changeArrayType(Class<?> arrayType, Object[] a) { 3065 Class<?> elemType = arrayType.getComponentType(); 3066 if (!elemType.isPrimitive()) 3067 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class)); 3068 Object b = java.lang.reflect.Array.newInstance(elemType, a.length); 3069 for (int i = 0; i < a.length; i++) 3070 java.lang.reflect.Array.set(b, i, a[i]); 3071 return b; 3072 } 3073 private static final MethodHandle CHANGE_ARRAY_TYPE; 3074 static { 3075 try { 3076 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType", 3077 MethodType.methodType(Object.class, Class.class, Object[].class)); 3078 } catch (NoSuchMethodException | IllegalAccessException ex) { 3079 Error err = new InternalError("uncaught exception"); 3080 err.initCause(ex); 3081 throw err; 3082 } 3083 } 3084 3085 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); 3086 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } 3087 private static List<Object> list() { return NO_ARGS_LIST; } 3088 private static List<Object> list(Object a0) 3089 { return makeList(a0); } 3090 private static List<Object> list(Object a0, Object a1) 3091 { return makeList(a0, a1); } 3092 private static List<Object> list(Object a0, Object a1, Object a2) 3093 { return makeList(a0, a1, a2); } 3094 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) 3095 { return makeList(a0, a1, a2, a3); } 3096 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3097 Object a4) 3098 { return makeList(a0, a1, a2, a3, a4); } 3099 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3100 Object a4, Object a5) 3101 { return makeList(a0, a1, a2, a3, a4, a5); } 3102 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3103 Object a4, Object a5, Object a6) 3104 { return makeList(a0, a1, a2, a3, a4, a5, a6); } 3105 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3106 Object a4, Object a5, Object a6, Object a7) 3107 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } 3108 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3109 Object a4, Object a5, Object a6, Object a7, 3110 Object a8) 3111 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 3112 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3113 Object a4, Object a5, Object a6, Object a7, 3114 Object a8, Object a9) 3115 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 3116 static MethodHandle[] makeLists() { 3117 ArrayList<MethodHandle> lists = new ArrayList<>(); 3118 MethodHandles.Lookup lookup = IMPL_LOOKUP; 3119 for (;;) { 3120 int nargs = lists.size(); 3121 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); 3122 String name = "list"; 3123 MethodHandle list = null; 3124 try { 3125 list = lookup.findStatic(ValueConversions.class, name, type); 3126 } catch (ReflectiveOperationException ex) { 3127 // break from loop! 3128 } 3129 if (list == null) break; 3130 lists.add(list); 3131 } 3132 assertTrue(lists.size() == 11); // current number of methods 3133 return lists.toArray(new MethodHandle[0]); 3134 } 3135 static final MethodHandle[] LISTS = makeLists(); 3136 static final MethodHandle AS_LIST; 3137 static { 3138 try { 3139 AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 3140 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 3141 } 3142 3143 /** Return a method handle that takes the indicated number of Object 3144 * arguments and returns List. 3145 */ 3146 public static MethodHandle varargsList(int nargs) { 3147 if (nargs < LISTS.length) 3148 return LISTS[nargs]; 3149 return AS_LIST.asCollector(Object[].class, nargs); 3150 } 3151 } 3152 // This guy tests access from outside the same package member, but inside 3153 // the package itself. 3154 class PackageSibling { 3155 static Lookup lookup() { 3156 return MethodHandles.lookup(); 3157 } 3158 }