1 /* 2 * Copyright (c) 2009, 2013, 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 testInvokersWithCatch(type); 2164 MethodType vtype = type.changeReturnType(void.class); 2165 if (done.add(vtype)) 2166 testInvokersWithCatch(vtype); 2167 } 2168 } 2169 } 2170 } 2171 2172 public void testInvokersWithCatch(MethodType type) throws Throwable { 2173 try { 2174 testInvokers(type); 2175 } catch (Throwable ex) { 2176 System.out.println("*** testInvokers on "+type+" => "); 2177 ex.printStackTrace(System.out); 2178 } 2179 } 2180 public void testInvokers(MethodType type) throws Throwable { 2181 if (verbosity >= 3) 2182 System.out.println("test invokers for "+type); 2183 int nargs = type.parameterCount(); 2184 boolean testRetCode = type.returnType() != void.class; 2185 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee", 2186 MethodType.genericMethodType(0, true)); 2187 assertTrue(target.isVarargsCollector()); 2188 target = target.asType(type); 2189 Object[] args = randomArgs(type.parameterArray()); 2190 List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args)); 2191 targetPlusArgs.add(0, target); 2192 int code = (Integer) invokee(args); 2193 Object log = logEntry("invokee", args); 2194 assertEquals(log.hashCode(), code); 2195 assertCalled("invokee", args); 2196 MethodHandle inv; 2197 Object result; 2198 // exact invoker 2199 countTest(); 2200 calledLog.clear(); 2201 inv = MethodHandles.exactInvoker(type); 2202 result = inv.invokeWithArguments(targetPlusArgs); 2203 if (testRetCode) assertEquals(code, result); 2204 assertCalled("invokee", args); 2205 // generic invoker 2206 countTest(); 2207 inv = MethodHandles.invoker(type); 2208 if (nargs <= 3 && type == type.generic()) { 2209 calledLog.clear(); 2210 switch (nargs) { 2211 case 0: 2212 result = inv.invokeExact(target); 2213 break; 2214 case 1: 2215 result = inv.invokeExact(target, args[0]); 2216 break; 2217 case 2: 2218 result = inv.invokeExact(target, args[0], args[1]); 2219 break; 2220 case 3: 2221 result = inv.invokeExact(target, args[0], args[1], args[2]); 2222 break; 2223 } 2224 if (testRetCode) assertEquals(code, result); 2225 assertCalled("invokee", args); 2226 } 2227 calledLog.clear(); 2228 result = inv.invokeWithArguments(targetPlusArgs); 2229 if (testRetCode) assertEquals(code, result); 2230 assertCalled("invokee", args); 2231 // varargs invoker #0 2232 calledLog.clear(); 2233 inv = MethodHandles.spreadInvoker(type, 0); 2234 if (type.returnType() == Object.class) { 2235 result = inv.invokeExact(target, args); 2236 } else if (type.returnType() == void.class) { 2237 result = null; inv.invokeExact(target, args); 2238 } else { 2239 result = inv.invokeWithArguments(target, (Object) args); 2240 } 2241 if (testRetCode) assertEquals(code, result); 2242 assertCalled("invokee", args); 2243 if (nargs >= 1 && type == type.generic()) { 2244 // varargs invoker #1 2245 calledLog.clear(); 2246 inv = MethodHandles.spreadInvoker(type, 1); 2247 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs)); 2248 if (testRetCode) assertEquals(code, result); 2249 assertCalled("invokee", args); 2250 } 2251 if (nargs >= 2 && type == type.generic()) { 2252 // varargs invoker #2 2253 calledLog.clear(); 2254 inv = MethodHandles.spreadInvoker(type, 2); 2255 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs)); 2256 if (testRetCode) assertEquals(code, result); 2257 assertCalled("invokee", args); 2258 } 2259 if (nargs >= 3 && type == type.generic()) { 2260 // varargs invoker #3 2261 calledLog.clear(); 2262 inv = MethodHandles.spreadInvoker(type, 3); 2263 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs)); 2264 if (testRetCode) assertEquals(code, result); 2265 assertCalled("invokee", args); 2266 } 2267 for (int k = 0; k <= nargs; k++) { 2268 // varargs invoker #0..N 2269 if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue; 2270 countTest(); 2271 calledLog.clear(); 2272 inv = MethodHandles.spreadInvoker(type, k); 2273 MethodType expType = (type.dropParameterTypes(k, nargs) 2274 .appendParameterTypes(Object[].class) 2275 .insertParameterTypes(0, MethodHandle.class)); 2276 assertEquals(expType, inv.type()); 2277 List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs); 2278 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs); 2279 Object[] tail = tailList.toArray(); 2280 tailList.clear(); tailList.add(tail); 2281 result = inv.invokeWithArguments(targetPlusVarArgs); 2282 if (testRetCode) assertEquals(code, result); 2283 assertCalled("invokee", args); 2284 } 2285 2286 // dynamic invoker 2287 countTest(); 2288 CallSite site = new MutableCallSite(type); 2289 inv = site.dynamicInvoker(); 2290 2291 // see if we get the result of the original target: 2292 try { 2293 result = inv.invokeWithArguments(args); 2294 assertTrue("should not reach here", false); 2295 } catch (IllegalStateException ex) { 2296 String msg = ex.getMessage(); 2297 assertTrue(msg, msg.contains("site")); 2298 } 2299 2300 // set new target after invoker is created, to make sure we track target 2301 site.setTarget(target); 2302 calledLog.clear(); 2303 result = inv.invokeWithArguments(args); 2304 if (testRetCode) assertEquals(code, result); 2305 assertCalled("invokee", args); 2306 } 2307 2308 static Object invokee(Object... args) { 2309 return called("invokee", args).hashCode(); 2310 } 2311 2312 private static final String MISSING_ARG = "missingArg"; 2313 private static final String MISSING_ARG_2 = "missingArg#2"; 2314 static Object targetIfEquals() { 2315 return called("targetIfEquals"); 2316 } 2317 static Object fallbackIfNotEquals() { 2318 return called("fallbackIfNotEquals"); 2319 } 2320 static Object targetIfEquals(Object x) { 2321 assertEquals(x, MISSING_ARG); 2322 return called("targetIfEquals", x); 2323 } 2324 static Object fallbackIfNotEquals(Object x) { 2325 assertFalse(x.toString(), x.equals(MISSING_ARG)); 2326 return called("fallbackIfNotEquals", x); 2327 } 2328 static Object targetIfEquals(Object x, Object y) { 2329 assertEquals(x, y); 2330 return called("targetIfEquals", x, y); 2331 } 2332 static Object fallbackIfNotEquals(Object x, Object y) { 2333 assertFalse(x.toString(), x.equals(y)); 2334 return called("fallbackIfNotEquals", x, y); 2335 } 2336 static Object targetIfEquals(Object x, Object y, Object z) { 2337 assertEquals(x, y); 2338 return called("targetIfEquals", x, y, z); 2339 } 2340 static Object fallbackIfNotEquals(Object x, Object y, Object z) { 2341 assertFalse(x.toString(), x.equals(y)); 2342 return called("fallbackIfNotEquals", x, y, z); 2343 } 2344 2345 @Test 2346 public void testGuardWithTest() throws Throwable { 2347 if (CAN_SKIP_WORKING) return; 2348 startTest("guardWithTest"); 2349 for (int nargs = 0; nargs <= 50; nargs++) { 2350 if (CAN_TEST_LIGHTLY && nargs > 7) break; 2351 testGuardWithTest(nargs, Object.class); 2352 testGuardWithTest(nargs, String.class); 2353 } 2354 } 2355 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 2356 testGuardWithTest(nargs, 0, argClass); 2357 if (nargs <= 5 || nargs % 10 == 3) { 2358 for (int testDrops = 1; testDrops <= nargs; testDrops++) 2359 testGuardWithTest(nargs, testDrops, argClass); 2360 } 2361 } 2362 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable { 2363 countTest(); 2364 int nargs1 = Math.min(3, nargs); 2365 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 2366 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1)); 2367 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1)); 2368 while (test.type().parameterCount() > nargs) 2369 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG)) 2370 // 1: test = lambda (_) MISSING_ARG.equals(_) 2371 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 2372 if (argClass != Object.class) { 2373 test = changeArgTypes(test, argClass); 2374 target = changeArgTypes(target, argClass); 2375 fallback = changeArgTypes(fallback, argClass); 2376 } 2377 int testArgs = nargs - testDrops; 2378 assert(testArgs >= 0); 2379 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass); 2380 target = addTrailingArgs(target, nargs, argClass); 2381 fallback = addTrailingArgs(fallback, nargs, argClass); 2382 Object[][] argLists = { 2383 { }, 2384 { "foo" }, { MISSING_ARG }, 2385 { "foo", "foo" }, { "foo", "bar" }, 2386 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 2387 }; 2388 for (Object[] argList : argLists) { 2389 Object[] argList1 = argList; 2390 if (argList.length != nargs) { 2391 if (argList.length != nargs1) continue; 2392 argList1 = Arrays.copyOf(argList, nargs); 2393 Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2); 2394 } 2395 MethodHandle test1 = test; 2396 if (test1.type().parameterCount() > testArgs) { 2397 int pc = test1.type().parameterCount(); 2398 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc)); 2399 } 2400 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback); 2401 assertEquals(target.type(), mh.type()); 2402 boolean equals; 2403 switch (nargs) { 2404 case 0: equals = true; break; 2405 case 1: equals = MISSING_ARG.equals(argList[0]); break; 2406 default: equals = argList[0].equals(argList[1]); break; 2407 } 2408 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 2409 if (verbosity >= 3) 2410 System.out.println(logEntry(willCall, argList)); 2411 Object result = mh.invokeWithArguments(argList1); 2412 assertCalled(willCall, argList); 2413 } 2414 } 2415 2416 @Test 2417 public void testThrowException() throws Throwable { 2418 if (CAN_SKIP_WORKING) return; 2419 startTest("throwException"); 2420 testThrowException(int.class, new ClassCastException("testing")); 2421 testThrowException(void.class, new java.io.IOException("testing")); 2422 testThrowException(String.class, new LinkageError("testing")); 2423 } 2424 2425 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 2426 countTest(); 2427 Class<? extends Throwable> exType = thrown.getClass(); 2428 MethodHandle target = MethodHandles.throwException(returnType, exType); 2429 //System.out.println("throwing with "+target+" : "+thrown); 2430 MethodType expectedType = MethodType.methodType(returnType, exType); 2431 assertEquals(expectedType, target.type()); 2432 target = target.asType(target.type().generic()); 2433 Throwable caught = null; 2434 try { 2435 Object res = target.invokeExact((Object) thrown); 2436 fail("got "+res+" instead of throwing "+thrown); 2437 } catch (Throwable ex) { 2438 if (ex != thrown) { 2439 if (ex instanceof Error) throw (Error)ex; 2440 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 2441 } 2442 caught = ex; 2443 } 2444 assertSame(thrown, caught); 2445 } 2446 2447 @Test 2448 public void testInterfaceCast() throws Throwable { 2449 //if (CAN_SKIP_WORKING) return; 2450 startTest("interfaceCast"); 2451 assert( (((Object)"foo") instanceof CharSequence)); 2452 assert(!(((Object)"foo") instanceof Iterable)); 2453 for (MethodHandle mh : new MethodHandle[]{ 2454 MethodHandles.identity(String.class), 2455 MethodHandles.identity(CharSequence.class), 2456 MethodHandles.identity(Iterable.class) 2457 }) { 2458 if (verbosity > 0) System.out.println("-- mh = "+mh); 2459 for (Class<?> ctype : new Class<?>[]{ 2460 Object.class, String.class, CharSequence.class, 2461 Number.class, Iterable.class 2462 }) { 2463 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); 2464 // doret docast 2465 testInterfaceCast(mh, ctype, false, false); 2466 testInterfaceCast(mh, ctype, true, false); 2467 testInterfaceCast(mh, ctype, false, true); 2468 testInterfaceCast(mh, ctype, true, true); 2469 } 2470 } 2471 } 2472 private static Class<?> i2o(Class<?> c) { 2473 return (c.isInterface() ? Object.class : c); 2474 } 2475 public void testInterfaceCast(MethodHandle mh, Class<?> ctype, 2476 boolean doret, boolean docast) throws Throwable { 2477 MethodHandle mh0 = mh; 2478 if (verbosity > 1) 2479 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast); 2480 String normalRetVal = "normal return value"; 2481 MethodType mt = mh.type(); 2482 MethodType mt0 = mt; 2483 if (doret) mt = mt.changeReturnType(ctype); 2484 else mt = mt.changeParameterType(0, ctype); 2485 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt); 2486 else mh = mh.asType(mt); 2487 assertEquals(mt, mh.type()); 2488 MethodType mt1 = mt; 2489 // this bit is needed to make the interface types disappear for invokeWithArguments: 2490 mh = MethodHandles.explicitCastArguments(mh, mt.generic()); 2491 Class<?>[] step = { 2492 mt1.parameterType(0), // param as passed to mh at first 2493 mt0.parameterType(0), // param after incoming cast 2494 mt0.returnType(), // return value before cast 2495 mt1.returnType(), // return value after outgoing cast 2496 }; 2497 // where might a checkCast occur? 2498 boolean[] checkCast = new boolean[step.length]; 2499 // the string value must pass each step without causing an exception 2500 if (!docast) { 2501 if (!doret) { 2502 if (step[0] != step[1]) 2503 checkCast[1] = true; // incoming value is cast 2504 } else { 2505 if (step[2] != step[3]) 2506 checkCast[3] = true; // outgoing value is cast 2507 } 2508 } 2509 boolean expectFail = false; 2510 for (int i = 0; i < step.length; i++) { 2511 Class<?> c = step[i]; 2512 if (!checkCast[i]) c = i2o(c); 2513 if (!c.isInstance(normalRetVal)) { 2514 if (verbosity > 3) 2515 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast)); 2516 expectFail = true; 2517 break; 2518 } 2519 } 2520 countTest(!expectFail); 2521 if (verbosity > 2) 2522 System.out.println("expectFail="+expectFail+", mt="+mt); 2523 Object res; 2524 try { 2525 res = mh.invokeWithArguments(normalRetVal); 2526 } catch (Exception ex) { 2527 res = ex; 2528 } 2529 boolean sawFail = !(res instanceof String); 2530 if (sawFail != expectFail) { 2531 System.out.println("*** testInterfaceCast: mh0 = "+mh0); 2532 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh); 2533 System.out.println(" call returned "+res); 2534 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal)); 2535 } 2536 if (!expectFail) { 2537 assertFalse(res.toString(), sawFail); 2538 assertEquals(normalRetVal, res); 2539 } else { 2540 assertTrue(res.toString(), sawFail); 2541 } 2542 } 2543 2544 @Test // SLOW 2545 public void testCastFailure() throws Throwable { 2546 if (CAN_SKIP_WORKING) return; 2547 startTest("testCastFailure"); 2548 testCastFailure("cast/argument", 11000); 2549 if (CAN_TEST_LIGHTLY) return; 2550 testCastFailure("unbox/argument", 11000); 2551 testCastFailure("cast/return", 11000); 2552 testCastFailure("unbox/return", 11000); 2553 } 2554 2555 static class Surprise { 2556 public MethodHandle asMethodHandle() { 2557 return VALUE.bindTo(this); 2558 } 2559 Object value(Object x) { 2560 trace("value", x); 2561 if (boo != null) return boo; 2562 return x; 2563 } 2564 Object boo; 2565 void boo(Object x) { boo = x; } 2566 2567 static void trace(String x, Object y) { 2568 if (verbosity > 8) System.out.println(x+"="+y); 2569 } 2570 static Object refIdentity(Object x) { trace("ref.x", x); return x; } 2571 static Integer boxIdentity(Integer x) { trace("box.x", x); return x; } 2572 static int intIdentity(int x) { trace("int.x", x); return x; } 2573 static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY; 2574 static { 2575 try { 2576 VALUE = PRIVATE.findVirtual( 2577 Surprise.class, "value", 2578 MethodType.methodType(Object.class, Object.class)); 2579 REF_IDENTITY = PRIVATE.findStatic( 2580 Surprise.class, "refIdentity", 2581 MethodType.methodType(Object.class, Object.class)); 2582 BOX_IDENTITY = PRIVATE.findStatic( 2583 Surprise.class, "boxIdentity", 2584 MethodType.methodType(Integer.class, Integer.class)); 2585 INT_IDENTITY = PRIVATE.findStatic( 2586 Surprise.class, "intIdentity", 2587 MethodType.methodType(int.class, int.class)); 2588 } catch (NoSuchMethodException | IllegalAccessException ex) { 2589 throw new RuntimeException(ex); 2590 } 2591 } 2592 } 2593 2594 @SuppressWarnings("ConvertToStringSwitch") 2595 void testCastFailure(String mode, int okCount) throws Throwable { 2596 countTest(false); 2597 if (verbosity > 2) System.out.println("mode="+mode); 2598 Surprise boo = new Surprise(); 2599 MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0; 2600 if (mode.endsWith("/return")) { 2601 if (mode.equals("unbox/return")) { 2602 // fail on return to ((Integer)surprise).intValue 2603 surprise = surprise.asType(MethodType.methodType(int.class, Object.class)); 2604 identity = identity.asType(MethodType.methodType(int.class, Object.class)); 2605 } else if (mode.equals("cast/return")) { 2606 // fail on return to (Integer)surprise 2607 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class)); 2608 identity = identity.asType(MethodType.methodType(Integer.class, Object.class)); 2609 } 2610 } else if (mode.endsWith("/argument")) { 2611 MethodHandle callee = null; 2612 if (mode.equals("unbox/argument")) { 2613 // fail on handing surprise to int argument 2614 callee = Surprise.INT_IDENTITY; 2615 } else if (mode.equals("cast/argument")) { 2616 // fail on handing surprise to Integer argument 2617 callee = Surprise.BOX_IDENTITY; 2618 } 2619 if (callee != null) { 2620 callee = callee.asType(MethodType.genericMethodType(1)); 2621 surprise = MethodHandles.filterArguments(callee, 0, surprise); 2622 identity = MethodHandles.filterArguments(callee, 0, identity); 2623 } 2624 } 2625 assertNotSame(mode, surprise, surprise0); 2626 identity = identity.asType(MethodType.genericMethodType(1)); 2627 surprise = surprise.asType(MethodType.genericMethodType(1)); 2628 Object x = 42; 2629 for (int i = 0; i < okCount; i++) { 2630 Object y = identity.invokeExact(x); 2631 assertEquals(x, y); 2632 Object z = surprise.invokeExact(x); 2633 assertEquals(x, z); 2634 } 2635 boo.boo("Boo!"); 2636 Object y = identity.invokeExact(x); 2637 assertEquals(x, y); 2638 try { 2639 Object z = surprise.invokeExact(x); 2640 System.out.println("Failed to throw; got z="+z); 2641 assertTrue(false); 2642 } catch (ClassCastException ex) { 2643 if (verbosity > 2) 2644 System.out.println("caught "+ex); 2645 if (verbosity > 3) 2646 ex.printStackTrace(System.out); 2647 assertTrue(true); // all is well 2648 } 2649 } 2650 2651 static Example userMethod(Object o, String s, int i) { 2652 called("userMethod", o, s, i); 2653 return null; 2654 } 2655 2656 @Test 2657 public void testUserClassInSignature() throws Throwable { 2658 if (CAN_SKIP_WORKING) return; 2659 startTest("testUserClassInSignature"); 2660 Lookup lookup = MethodHandles.lookup(); 2661 String name; MethodType mt; MethodHandle mh; 2662 Object[] args; 2663 2664 // Try a static method. 2665 name = "userMethod"; 2666 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 2667 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 2668 assertEquals(mt, mh.type()); 2669 assertEquals(Example.class, mh.type().returnType()); 2670 args = randomArgs(mh.type().parameterArray()); 2671 mh.invokeWithArguments(args); 2672 assertCalled(name, args); 2673 2674 // Try a virtual method. 2675 name = "v2"; 2676 mt = MethodType.methodType(Object.class, Object.class, int.class); 2677 mh = lookup.findVirtual(Example.class, name, mt); 2678 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 2679 assertTrue(mh.type().parameterList().contains(Example.class)); 2680 args = randomArgs(mh.type().parameterArray()); 2681 mh.invokeWithArguments(args); 2682 assertCalled(name, args); 2683 } 2684 2685 static void runForRunnable() { 2686 called("runForRunnable"); 2687 } 2688 public interface Fooable { 2689 // overloads: 2690 Object foo(Object x, String y); 2691 List<?> foo(String x, int y); 2692 Object foo(String x); 2693 } 2694 static Object fooForFooable(String x, Object... y) { 2695 return called("fooForFooable/"+x, y); 2696 } 2697 @SuppressWarnings("serial") // not really a public API, just a test case 2698 public static class MyCheckedException extends Exception { 2699 } 2700 public interface WillThrow { 2701 void willThrow() throws MyCheckedException; 2702 } 2703 /*non-public*/ interface PrivateRunnable { 2704 public void run(); 2705 } 2706 2707 @Test 2708 public void testAsInterfaceInstance() throws Throwable { 2709 if (CAN_SKIP_WORKING) return; 2710 startTest("asInterfaceInstance"); 2711 Lookup lookup = MethodHandles.lookup(); 2712 // test typical case: Runnable.run 2713 { 2714 countTest(); 2715 if (verbosity >= 2) System.out.println("Runnable"); 2716 MethodType mt = MethodType.methodType(void.class); 2717 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt); 2718 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 2719 proxy.run(); 2720 assertCalled("runForRunnable"); 2721 } 2722 // well known single-name overloaded interface: Appendable.append 2723 { 2724 countTest(); 2725 if (verbosity >= 2) System.out.println("Appendable"); 2726 ArrayList<List<?>> appendResults = new ArrayList<>(); 2727 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); 2728 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type 2729 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 2730 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class); 2731 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh); 2732 proxy.append("one"); 2733 proxy.append("two", 3, 4); 2734 proxy.append('5'); 2735 assertEquals(Arrays.asList(Arrays.asList("one"), 2736 Arrays.asList("two", 3, 4), 2737 Arrays.asList('5')), 2738 appendResults); 2739 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 2740 appendResults.clear(); 2741 Formatter formatter = new Formatter(proxy); 2742 String fmt = "foo str=%s char='%c' num=%d"; 2743 Object[] fmtArgs = { "str!", 'C', 42 }; 2744 String expect = String.format(fmt, fmtArgs); 2745 formatter.format(fmt, fmtArgs); 2746 String actual = ""; 2747 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 2748 for (List<?> l : appendResults) { 2749 Object x = l.get(0); 2750 switch (l.size()) { 2751 case 1: actual += x; continue; 2752 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue; 2753 } 2754 actual += l; 2755 } 2756 if (verbosity >= 3) System.out.println("expect="+expect); 2757 if (verbosity >= 3) System.out.println("actual="+actual); 2758 assertEquals(expect, actual); 2759 } 2760 // test case of an single name which is overloaded: Fooable.foo(...) 2761 { 2762 if (verbosity >= 2) System.out.println("Fooable"); 2763 MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", 2764 MethodType.methodType(Object.class, String.class, Object[].class)); 2765 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 2766 for (Method m : Fooable.class.getDeclaredMethods()) { 2767 countTest(); 2768 assertSame("foo", m.getName()); 2769 if (verbosity > 3) 2770 System.out.println("calling "+m); 2771 MethodHandle invoker = lookup.unreflect(m); 2772 MethodType mt = invoker.type(); 2773 Class<?>[] types = mt.parameterArray(); 2774 types[0] = int.class; // placeholder 2775 Object[] args = randomArgs(types); 2776 args[0] = proxy; 2777 if (verbosity > 3) 2778 System.out.println("calling "+m+" on "+Arrays.asList(args)); 2779 Object result = invoker.invokeWithArguments(args); 2780 if (verbosity > 4) 2781 System.out.println("result = "+result); 2782 String name = "fooForFooable/"+args[1]; 2783 Object[] argTail = Arrays.copyOfRange(args, 2, args.length); 2784 assertCalled(name, argTail); 2785 assertEquals(result, logEntry(name, argTail)); 2786 } 2787 } 2788 // test processing of thrown exceptions: 2789 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 2790 new InternalError("ok"), 2791 new Throwable("fail"), 2792 new Exception("fail"), 2793 new MyCheckedException() 2794 }) { 2795 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 2796 mh = MethodHandles.insertArguments(mh, 0, ex); 2797 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 2798 try { 2799 countTest(); 2800 proxy.willThrow(); 2801 System.out.println("Failed to throw: "+ex); 2802 assertTrue(false); 2803 } catch (Throwable ex1) { 2804 if (verbosity > 3) { 2805 System.out.println("throw "+ex); 2806 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 2807 } 2808 if (ex instanceof RuntimeException || 2809 ex instanceof Error) { 2810 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 2811 } else if (ex instanceof MyCheckedException) { 2812 assertSame("must pass declared exception out without wrapping", ex, ex1); 2813 } else { 2814 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 2815 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { 2816 ex1.printStackTrace(System.out); 2817 } 2818 assertSame(ex, ex1.getCause()); 2819 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 2820 } 2821 } 2822 } 2823 // Test error checking on bad interfaces: 2824 for (Class<?> nonSMI : new Class<?>[] { Object.class, 2825 String.class, 2826 CharSequence.class, 2827 java.io.Serializable.class, 2828 PrivateRunnable.class, 2829 Example.class }) { 2830 if (verbosity > 2) System.out.println(nonSMI.getName()); 2831 try { 2832 countTest(false); 2833 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0)); 2834 assertTrue("Failed to throw on "+nonSMI.getName(), false); 2835 } catch (IllegalArgumentException ex) { 2836 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex); 2837 // Object: java.lang.IllegalArgumentException: 2838 // not a public interface: java.lang.Object 2839 // String: java.lang.IllegalArgumentException: 2840 // not a public interface: java.lang.String 2841 // CharSequence: java.lang.IllegalArgumentException: 2842 // not a single-method interface: java.lang.CharSequence 2843 // Serializable: java.lang.IllegalArgumentException: 2844 // not a single-method interface: java.io.Serializable 2845 // PrivateRunnable: java.lang.IllegalArgumentException: 2846 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable 2847 // Example: java.lang.IllegalArgumentException: 2848 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example 2849 } 2850 } 2851 // Test error checking on interfaces with the wrong method type: 2852 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/, 2853 Fooable.class /*arity 1 & 2*/ }) { 2854 int badArity = 1; // known to be incompatible 2855 if (verbosity > 2) System.out.println(intfc.getName()); 2856 try { 2857 countTest(false); 2858 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity)); 2859 assertTrue("Failed to throw on "+intfc.getName(), false); 2860 } catch (WrongMethodTypeException ex) { 2861 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex); 2862 // Runnable: java.lang.invoke.WrongMethodTypeException: 2863 // cannot convert MethodHandle(Object)Object[] to ()void 2864 // Fooable: java.lang.invoke.WrongMethodTypeException: 2865 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object 2866 } 2867 } 2868 } 2869 2870 @Test 2871 public void testRunnableProxy() throws Throwable { 2872 if (CAN_SKIP_WORKING) return; 2873 startTest("testRunnableProxy"); 2874 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2875 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); 2876 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); 2877 testRunnableProxy(r); 2878 assertCalled("runForRunnable"); 2879 } 2880 private static void testRunnableProxy(Runnable r) { 2881 //7058630: JSR 292 method handle proxy violates contract for Object methods 2882 r.run(); 2883 Object o = r; 2884 r = null; 2885 boolean eq = (o == o); 2886 int hc = System.identityHashCode(o); 2887 String st = o.getClass().getName() + "@" + Integer.toHexString(hc); 2888 Object expect = Arrays.asList(st, eq, hc); 2889 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect); 2890 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode()); 2891 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual); 2892 assertEquals(expect, actual); 2893 } 2894 } 2895 // Local abbreviated copy of sun.invoke.util.ValueConversions 2896 // This guy tests access from outside the same package member, but inside 2897 // the package itself. 2898 class ValueConversions { 2899 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); 2900 private static final Object[] NO_ARGS_ARRAY = {}; 2901 private static Object[] makeArray(Object... args) { return args; } 2902 private static Object[] array() { return NO_ARGS_ARRAY; } 2903 private static Object[] array(Object a0) 2904 { return makeArray(a0); } 2905 private static Object[] array(Object a0, Object a1) 2906 { return makeArray(a0, a1); } 2907 private static Object[] array(Object a0, Object a1, Object a2) 2908 { return makeArray(a0, a1, a2); } 2909 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 2910 { return makeArray(a0, a1, a2, a3); } 2911 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2912 Object a4) 2913 { return makeArray(a0, a1, a2, a3, a4); } 2914 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2915 Object a4, Object a5) 2916 { return makeArray(a0, a1, a2, a3, a4, a5); } 2917 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2918 Object a4, Object a5, Object a6) 2919 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 2920 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2921 Object a4, Object a5, Object a6, Object a7) 2922 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 2923 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2924 Object a4, Object a5, Object a6, Object a7, 2925 Object a8) 2926 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 2927 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 2928 Object a4, Object a5, Object a6, Object a7, 2929 Object a8, Object a9) 2930 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 2931 static MethodHandle[] makeArrays() { 2932 ArrayList<MethodHandle> arrays = new ArrayList<>(); 2933 MethodHandles.Lookup lookup = IMPL_LOOKUP; 2934 for (;;) { 2935 int nargs = arrays.size(); 2936 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); 2937 String name = "array"; 2938 MethodHandle array = null; 2939 try { 2940 array = lookup.findStatic(ValueConversions.class, name, type); 2941 } catch (ReflectiveOperationException ex) { 2942 // break from loop! 2943 } 2944 if (array == null) break; 2945 arrays.add(array); 2946 } 2947 assertTrue(arrays.size() == 11); // current number of methods 2948 return arrays.toArray(new MethodHandle[0]); 2949 } 2950 static final MethodHandle[] ARRAYS = makeArrays(); 2951 2952 /** Return a method handle that takes the indicated number of Object 2953 * arguments and returns an Object array of them, as if for varargs. 2954 */ 2955 public static MethodHandle varargsArray(int nargs) { 2956 if (nargs < ARRAYS.length) 2957 return ARRAYS[nargs]; 2958 return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs); 2959 } 2960 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 2961 Class<?> elemType = arrayType.getComponentType(); 2962 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)); 2963 MethodHandle mh = varargsArray(nargs); 2964 if (arrayType != Object[].class) 2965 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType)); 2966 return mh.asType(vaType); 2967 } 2968 static Object changeArrayType(Class<?> arrayType, Object[] a) { 2969 Class<?> elemType = arrayType.getComponentType(); 2970 if (!elemType.isPrimitive()) 2971 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class)); 2972 Object b = java.lang.reflect.Array.newInstance(elemType, a.length); 2973 for (int i = 0; i < a.length; i++) 2974 java.lang.reflect.Array.set(b, i, a[i]); 2975 return b; 2976 } 2977 private static final MethodHandle CHANGE_ARRAY_TYPE; 2978 static { 2979 try { 2980 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType", 2981 MethodType.methodType(Object.class, Class.class, Object[].class)); 2982 } catch (NoSuchMethodException | IllegalAccessException ex) { 2983 Error err = new InternalError("uncaught exception"); 2984 err.initCause(ex); 2985 throw err; 2986 } 2987 } 2988 2989 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); 2990 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } 2991 private static List<Object> list() { return NO_ARGS_LIST; } 2992 private static List<Object> list(Object a0) 2993 { return makeList(a0); } 2994 private static List<Object> list(Object a0, Object a1) 2995 { return makeList(a0, a1); } 2996 private static List<Object> list(Object a0, Object a1, Object a2) 2997 { return makeList(a0, a1, a2); } 2998 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) 2999 { return makeList(a0, a1, a2, a3); } 3000 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3001 Object a4) 3002 { return makeList(a0, a1, a2, a3, a4); } 3003 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3004 Object a4, Object a5) 3005 { return makeList(a0, a1, a2, a3, a4, a5); } 3006 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3007 Object a4, Object a5, Object a6) 3008 { return makeList(a0, a1, a2, a3, a4, a5, a6); } 3009 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3010 Object a4, Object a5, Object a6, Object a7) 3011 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } 3012 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3013 Object a4, Object a5, Object a6, Object a7, 3014 Object a8) 3015 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 3016 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 3017 Object a4, Object a5, Object a6, Object a7, 3018 Object a8, Object a9) 3019 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 3020 static MethodHandle[] makeLists() { 3021 ArrayList<MethodHandle> lists = new ArrayList<>(); 3022 MethodHandles.Lookup lookup = IMPL_LOOKUP; 3023 for (;;) { 3024 int nargs = lists.size(); 3025 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); 3026 String name = "list"; 3027 MethodHandle list = null; 3028 try { 3029 list = lookup.findStatic(ValueConversions.class, name, type); 3030 } catch (ReflectiveOperationException ex) { 3031 // break from loop! 3032 } 3033 if (list == null) break; 3034 lists.add(list); 3035 } 3036 assertTrue(lists.size() == 11); // current number of methods 3037 return lists.toArray(new MethodHandle[0]); 3038 } 3039 static final MethodHandle[] LISTS = makeLists(); 3040 static final MethodHandle AS_LIST; 3041 static { 3042 try { 3043 AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 3044 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 3045 } 3046 3047 /** Return a method handle that takes the indicated number of Object 3048 * arguments and returns List. 3049 */ 3050 public static MethodHandle varargsList(int nargs) { 3051 if (nargs < LISTS.length) 3052 return LISTS[nargs]; 3053 return AS_LIST.asCollector(Object[].class, nargs); 3054 } 3055 } 3056 // This guy tests access from outside the same package member, but inside 3057 // the package itself. 3058 class PackageSibling { 3059 static Lookup lookup() { 3060 return MethodHandles.lookup(); 3061 } 3062 }