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