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