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