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