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