1 /* 2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @summary unit tests for recursive method handles 26 * @run junit/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -DRicochetTest.MAX_ARITY=10 test.java.lang.invoke.RicochetTest 27 */ 28 /* 29 * @ignore The following test creates an unreasonable number of adapters in -Xcomp mode (7049122) 30 * @run junit/othervm -DRicochetTest.MAX_ARITY=255 test.java.lang.invoke.RicochetTest 31 */ 32 33 package test.java.lang.invoke; 34 35 import java.lang.invoke.*; 36 import java.util.*; 37 import org.junit.*; 38 import static java.lang.invoke.MethodType.*; 39 import static java.lang.invoke.MethodHandles.*; 40 import static org.junit.Assert.*; 41 42 43 /** 44 * 45 * @author jrose 46 */ 47 public class RicochetTest { 48 private static final Class<?> CLASS = RicochetTest.class; 49 private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); 50 main(String... av)51 public static void main(String... av) throws Throwable { 52 RicochetTest test = new RicochetTest(); 53 if (av.length > 0) test.testOnly = Arrays.asList(av).toString(); 54 if (REPEAT == 1 || test.testOnly != null) { 55 test.testAll(); 56 if (test.testOnlyTests == null) throw new RuntimeException("no matching test: "+test.testOnly); 57 } else if (REPEAT == 0) { 58 org.junit.runner.JUnitCore.runClasses(RicochetTest.class); 59 } else { 60 verbose(1, "REPEAT="+REPEAT); 61 for (int i = 0; i < REPEAT; i++) { 62 test.testRepetition = (i+1); 63 verbose(0, "[#"+test.testRepetition+"]"); 64 test.testAll(); 65 } 66 } 67 } 68 int testRepetition; 69 testAll()70 public void testAll() throws Throwable { 71 testNull(); 72 testBoxInteger(); 73 testFilterReturnValue(); 74 testFilterObject(); 75 testBoxLong(); 76 testFilterInteger(); 77 testIntSpreads(); 78 testByteSpreads(); 79 testLongSpreads(); 80 testIntCollects(); 81 testReturns(); 82 testRecursion(); 83 } 84 85 @Test testNull()86 public void testNull() throws Throwable { 87 if (testRepetition > (1+REPEAT/100)) return; // trivial test 88 if (!startTest("testNull")) return; 89 assertEquals(opI(37), opI.invokeWithArguments(37)); 90 assertEqualFunction(opI, opI); 91 } 92 93 @Test testBoxInteger()94 public void testBoxInteger() throws Throwable { 95 if (!startTest("testBoxInteger")) return; 96 assertEqualFunction(opI, opI.asType(opL_I.type()).asType(opI.type())); 97 } 98 99 @Test testFilterReturnValue()100 public void testFilterReturnValue() throws Throwable { 101 if (!startTest("testFilterReturnValue")) return; 102 int[] ints = { 12, 23, 34, 45, 56, 67, 78, 89 }; 103 Object res = list8ints.invokeExact(ints[0], ints[1], ints[2], ints[3], ints[4], ints[5], ints[6], ints[7]); 104 assertEquals(Arrays.toString(ints), res.toString()); 105 MethodHandle idreturn = filterReturnValue(list8ints, identity(Object.class)); 106 res = idreturn.invokeExact(ints[0], ints[1], ints[2], ints[3], ints[4], ints[5], ints[6], ints[7]); 107 assertEquals(Arrays.toString(ints), res.toString()); 108 MethodHandle add0 = addL.bindTo(0); 109 assertEqualFunction(filterReturnValue(opL2, add0), opL2); 110 } 111 112 @Test testFilterObject()113 public void testFilterObject() throws Throwable { 114 if (!startTest("testFilterObject")) return; 115 MethodHandle add0 = addL.bindTo(0); 116 assertEqualFunction(sequence(opL2, add0), opL2); 117 int bump13 = -13; // value near 20 works as long as test values are near [-80..80] 118 MethodHandle add13 = addL.bindTo(bump13); 119 MethodHandle add13_0 = addL.bindTo(opI2(bump13, 0)); 120 MethodHandle add13_1 = addL.bindTo(opI2(0, bump13)); 121 assertEqualFunction(sequence(opL2, add13_0), 122 filterArguments(opL2, 0, add13)); 123 assertEqualFunction(sequence(opL2, add13_1), 124 filterArguments(opL2, 1, add13)); 125 System.out.println("[testFilterObject done]"); 126 } 127 128 @Test testBoxLong()129 public void testBoxLong() throws Throwable { 130 if (!startTest("testBoxLong")) return; 131 assertEqualFunction(opJ, opJ.asType(opL_J.type()).asType(opJ.type())); 132 } 133 134 @Test testFilterInteger()135 public void testFilterInteger() throws Throwable { 136 if (!startTest("testFilterInteger")) return; 137 assertEqualFunction(opI, sequence(convI_L, opL_I)); 138 } 139 140 @Test testIntSpreads()141 public void testIntSpreads() throws Throwable { 142 if (!startTest("testIntSpreads")) return; 143 MethodHandle id = identity(int[].class); 144 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added 145 for (int nargs = 0; nargs <= MAX; nargs++) { 146 if (nargs > 30 && nargs < MAX-20) nargs += 10; 147 int[] args = new int[nargs]; 148 for (int j = 0; j < args.length; j++) args[j] = j + 11; 149 //System.out.println("testIntSpreads "+Arrays.toString(args)); 150 int[] args1 = (int[]) id.invokeExact(args); 151 assertArrayEquals(args, args1); 152 MethodHandle coll = id.asCollector(int[].class, nargs); 153 int[] args2 = args; 154 switch (nargs) { 155 case 0: args2 = (int[]) coll.invokeExact(); break; 156 case 1: args2 = (int[]) coll.invokeExact(args[0]); break; 157 case 2: args2 = (int[]) coll.invokeExact(args[0], args[1]); break; 158 case 3: args2 = (int[]) coll.invokeExact(args[0], args[1], args[2]); break; 159 case 4: args2 = (int[]) coll.invokeExact(args[0], args[1], args[2], args[3]); break; 160 case 5: args2 = (int[]) coll.invokeExact(args[0], args[1], args[2], args[3], args[4]); break; 161 } 162 assertArrayEquals(args, args2); 163 MethodHandle mh = coll.asSpreader(int[].class, nargs); 164 int[] args3 = (int[]) mh.invokeExact(args); 165 assertArrayEquals(args, args3); 166 } 167 } 168 169 @Test testByteSpreads()170 public void testByteSpreads() throws Throwable { 171 if (!startTest("testByteSpreads")) return; 172 MethodHandle id = identity(byte[].class); 173 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added 174 for (int nargs = 0; nargs <= MAX; nargs++) { 175 if (nargs > 30 && nargs < MAX-20) nargs += 10; 176 byte[] args = new byte[nargs]; 177 for (int j = 0; j < args.length; j++) args[j] = (byte)(j + 11); 178 //System.out.println("testByteSpreads "+Arrays.toString(args)); 179 byte[] args1 = (byte[]) id.invokeExact(args); 180 assertArrayEquals(args, args1); 181 MethodHandle coll = id.asCollector(byte[].class, nargs); 182 byte[] args2 = args; 183 switch (nargs) { 184 case 0: args2 = (byte[]) coll.invokeExact(); break; 185 case 1: args2 = (byte[]) coll.invokeExact(args[0]); break; 186 case 2: args2 = (byte[]) coll.invokeExact(args[0], args[1]); break; 187 case 3: args2 = (byte[]) coll.invokeExact(args[0], args[1], args[2]); break; 188 case 4: args2 = (byte[]) coll.invokeExact(args[0], args[1], args[2], args[3]); break; 189 case 5: args2 = (byte[]) coll.invokeExact(args[0], args[1], args[2], args[3], args[4]); break; 190 } 191 assertArrayEquals(args, args2); 192 MethodHandle mh = coll.asSpreader(byte[].class, nargs); 193 byte[] args3 = (byte[]) mh.invokeExact(args); 194 assertArrayEquals(args, args3); 195 } 196 } 197 198 @Test testLongSpreads()199 public void testLongSpreads() throws Throwable { 200 if (!startTest("testLongSpreads")) return; 201 MethodHandle id = identity(long[].class); 202 final int MAX = (MAX_ARITY - 2) / 2; // 253/2+1 would cause parameter overflow with 'this' added 203 for (int nargs = 0; nargs <= MAX; nargs++) { 204 if (nargs > 30 && nargs < MAX-20) nargs += 10; 205 long[] args = new long[nargs]; 206 for (int j = 0; j < args.length; j++) args[j] = (long)(j + 11); 207 //System.out.println("testLongSpreads "+Arrays.toString(args)); 208 long[] args1 = (long[]) id.invokeExact(args); 209 assertArrayEquals(args, args1); 210 MethodHandle coll = id.asCollector(long[].class, nargs); 211 long[] args2 = args; 212 switch (nargs) { 213 case 0: args2 = (long[]) coll.invokeExact(); break; 214 case 1: args2 = (long[]) coll.invokeExact(args[0]); break; 215 case 2: args2 = (long[]) coll.invokeExact(args[0], args[1]); break; 216 case 3: args2 = (long[]) coll.invokeExact(args[0], args[1], args[2]); break; 217 case 4: args2 = (long[]) coll.invokeExact(args[0], args[1], args[2], args[3]); break; 218 case 5: args2 = (long[]) coll.invokeExact(args[0], args[1], args[2], args[3], args[4]); break; 219 } 220 assertArrayEquals(args, args2); 221 MethodHandle mh = coll.asSpreader(long[].class, nargs); 222 long[] args3 = (long[]) mh.invokeExact(args); 223 assertArrayEquals(args, args3); 224 } 225 } 226 227 @Test testIntCollects()228 public void testIntCollects() throws Throwable { 229 if (!startTest("testIntCollects")) return; 230 for (MethodHandle lister : INT_LISTERS) { 231 int outputs = lister.type().parameterCount(); 232 for (int collects = 0; collects <= Math.min(outputs, INT_COLLECTORS.length-1); collects++) { 233 int inputs = outputs - 1 + collects; 234 if (inputs < 0) continue; 235 for (int pos = 0; pos + collects <= inputs; pos++) { 236 MethodHandle collector = INT_COLLECTORS[collects]; 237 int[] args = new int[inputs]; 238 int ap = 0, arg = 31; 239 for (int i = 0; i < pos; i++) 240 args[ap++] = arg++ + 0; 241 for (int i = 0; i < collects; i++) 242 args[ap++] = arg++ + 10; 243 while (ap < args.length) 244 args[ap++] = arg++ + 20; 245 // calculate piecemeal: 246 //System.out.println("testIntCollects "+Arrays.asList(lister, pos, collector)+" on "+Arrays.toString(args)); 247 int[] collargs = Arrays.copyOfRange(args, pos, pos+collects); 248 int coll = (int) collector.asSpreader(int[].class, collargs.length).invokeExact(collargs); 249 int[] listargs = Arrays.copyOfRange(args, 0, outputs); 250 System.arraycopy(args, pos+collects, listargs, pos+1, outputs - (pos+1)); 251 listargs[pos] = coll; 252 //System.out.println(" coll="+coll+" listargs="+Arrays.toString(listargs)); 253 Object expect = lister.asSpreader(int[].class, listargs.length).invokeExact(listargs); 254 //System.out.println(" expect="+expect); 255 256 // now use the combined MH, and test the output: 257 MethodHandle mh = collectArguments(lister, pos, int[].class, INT_COLLECTORS[collects]); 258 if (mh == null) continue; // no infix collection, yet 259 assert(mh.type().parameterCount() == inputs); 260 Object observe = mh.asSpreader(int[].class, args.length).invokeExact(args); 261 assertEquals(expect, observe); 262 } 263 } 264 } 265 } 266 267 @Test testByteCollects()268 public void testByteCollects() throws Throwable { 269 if (!startTest("testByteCollects")) return; 270 for (MethodHandle lister : BYTE_LISTERS) { 271 int outputs = lister.type().parameterCount(); 272 for (int collects = 0; collects <= Math.min(outputs, BYTE_COLLECTORS.length-1); collects++) { 273 int inputs = outputs - 1 + collects; 274 if (inputs < 0) continue; 275 for (int pos = 0; pos + collects <= inputs; pos++) { 276 MethodHandle collector = BYTE_COLLECTORS[collects]; 277 byte[] args = new byte[inputs]; 278 int ap = 0, arg = 31; 279 for (int i = 0; i < pos; i++) 280 args[ap++] = (byte)(arg++ + 0); 281 for (int i = 0; i < collects; i++) 282 args[ap++] = (byte)(arg++ + 10); 283 while (ap < args.length) 284 args[ap++] = (byte)(arg++ + 20); 285 // calculate piecemeal: 286 //System.out.println("testIntCollects "+Arrays.asList(lister, pos, collector)+" on "+Arrays.toString(args)); 287 byte[] collargs = Arrays.copyOfRange(args, pos, pos+collects); 288 byte coll = (byte) collector.asSpreader(byte[].class, collargs.length).invokeExact(collargs); 289 byte[] listargs = Arrays.copyOfRange(args, 0, outputs); 290 System.arraycopy(args, pos+collects, listargs, pos+1, outputs - (pos+1)); 291 listargs[pos] = coll; 292 //System.out.println(" coll="+coll+" listargs="+Arrays.toString(listargs)); 293 Object expect = lister.asSpreader(byte[].class, listargs.length).invokeExact(listargs); 294 //System.out.println(" expect="+expect); 295 296 // now use the combined MH, and test the output: 297 MethodHandle mh = collectArguments(lister, pos, byte[].class, BYTE_COLLECTORS[collects]); 298 if (mh == null) continue; // no infix collection, yet 299 assert(mh.type().parameterCount() == inputs); 300 Object observe = mh.asSpreader(byte[].class, args.length).invokeExact(args); 301 assertEquals(expect, observe); 302 } 303 } 304 } 305 } 306 collectArguments(MethodHandle lister, int pos, Class<?> array, MethodHandle collector)307 private static MethodHandle collectArguments(MethodHandle lister, int pos, Class<?> array, MethodHandle collector) { 308 int collects = collector.type().parameterCount(); 309 int outputs = lister.type().parameterCount(); 310 if (pos == outputs - 1) 311 return MethodHandles.filterArguments(lister, pos, 312 collector.asSpreader(array, collects)) 313 .asCollector(array, collects); 314 //return MethodHandles.collectArguments(lister, pos, collector); //no such animal 315 return null; 316 } 317 318 private static final Class<?>[] RETURN_TYPES = { 319 Object.class, String.class, Integer.class, 320 int.class, long.class, 321 boolean.class, byte.class, char.class, short.class, 322 float.class, double.class, 323 void.class, 324 }; 325 326 @Test testReturns()327 public void testReturns() throws Throwable { 328 if (!startTest("testReturns")) return; 329 // fault injection: 330 int faultCount = 0; // total of 1296 tests 331 faultCount = Integer.getInteger("testReturns.faultCount", 0); 332 for (Class<?> ret : RETURN_TYPES) { 333 // make a complicated identity function and pass something through it 334 System.out.println(ret.getSimpleName()); 335 Class<?> vret = (ret == void.class) ? Void.class : ret; 336 MethodHandle id = // (vret)->ret 337 identity(vret).asType(methodType(ret, vret)); 338 final int LENGTH = 4; 339 int[] index = {0}; 340 Object vals = java.lang.reflect.Array.newInstance(vret, LENGTH); 341 MethodHandle indexGetter = //()->int 342 insertArguments(arrayElementGetter(index.getClass()), 0, index, 0); 343 MethodHandle valSelector = // (int)->vret 344 arrayElementGetter(vals.getClass()).bindTo(vals); 345 MethodHandle valGetter = // ()->vret 346 foldArguments(valSelector, indexGetter); 347 if (ret != void.class) { 348 for (int i = 0; i < LENGTH; i++) { 349 Object val = (i + 50); 350 if (ret == boolean.class) val = (i % 3 == 0); 351 if (ret == String.class) val = "#"+i; 352 if (ret == char.class) val = (char)('a'+i); 353 if (ret == byte.class) val = (byte)~i; 354 if (ret == short.class) val = (short)(1<<i); 355 java.lang.reflect.Array.set(vals, i, val); 356 } 357 } 358 for (int i = 0; i < LENGTH; i++) { 359 Object val = java.lang.reflect.Array.get(vals, i); 360 System.out.println(i+" => "+val); 361 index[0] = i; 362 if (--faultCount == 0) index[0] ^= 1; 363 Object x = valGetter.invokeWithArguments(); 364 assertEquals(val, x); 365 // make a return-filter call: x = id(valGetter()) 366 if (--faultCount == 0) index[0] ^= 1; 367 x = filterReturnValue(valGetter, id).invokeWithArguments(); 368 assertEquals(val, x); 369 // make a filter call: x = id(*,valGetter(),*) 370 for (int len = 1; len <= 4; len++) { 371 for (int pos = 0; pos < len; pos++) { 372 MethodHandle proj = id; // lambda(..., vret x,...){x} 373 for (int j = 0; j < len; j++) { 374 if (j == pos) continue; 375 proj = dropArguments(proj, j, Object.class); 376 } 377 assert(proj.type().parameterCount() == len); 378 // proj: (Object*, pos: vret, Object*)->ret 379 assertEquals(vret, proj.type().parameterType(pos)); 380 MethodHandle vgFilter = dropArguments(valGetter, 0, Object.class); 381 if (--faultCount == 0) index[0] ^= 1; 382 x = filterArguments(proj, pos, vgFilter).invokeWithArguments(new Object[len]); 383 assertEquals(val, x); 384 } 385 } 386 // make a fold call: 387 for (int len = 0; len <= 4; len++) { 388 for (int fold = 0; fold <= len; fold++) { 389 MethodHandle proj = id; // lambda(ret x, ...){x} 390 if (ret == void.class) proj = constant(Object.class, null); 391 int arg0 = (ret == void.class ? 0 : 1); 392 for (int j = 0; j < len; j++) { 393 proj = dropArguments(proj, arg0, Object.class); 394 } 395 assert(proj.type().parameterCount() == arg0 + len); 396 // proj: (Object*, pos: vret, Object*)->ret 397 if (arg0 != 0) assertEquals(vret, proj.type().parameterType(0)); 398 MethodHandle vgFilter = valGetter.asType(methodType(ret)); 399 for (int j = 0; j < fold; j++) { 400 vgFilter = dropArguments(vgFilter, j, Object.class); 401 } 402 x = foldArguments(proj, vgFilter).invokeWithArguments(new Object[len]); 403 if (--faultCount == 0) index[0] ^= 1; 404 assertEquals(val, x); 405 } 406 } 407 } 408 } 409 //System.out.println("faultCount="+faultCount); 410 } 411 412 @Test testRecursion()413 public void testRecursion() throws Throwable { 414 if (!startTest("testRecursion")) return; 415 final int LIMIT = 10; 416 for (int i = 0; i < LIMIT; i++) { 417 RFCB rfcb = new RFCB(i); 418 Object x = "x", y = "y"; 419 Object result = rfcb.recursiveFunction(x, y); 420 verbose(1, result); 421 } 422 } 423 /** Recursive Function Control Block */ 424 private static class RFCB { 425 java.util.Random random; 426 final MethodHandle[] fns; 427 int depth; 428 @SuppressWarnings("LeakingThisInConstructor") RFCB(int seed)429 RFCB(int seed) throws Throwable { 430 this.random = new java.util.Random(seed); 431 this.fns = new MethodHandle[Math.max(29, (1 << MAX_DEPTH-2)/3)]; 432 java.util.Arrays.fill(fns, lookup().bind(this, "recursiveFunction", genericMethodType(2))); 433 for (int i = 5; i < fns.length; i++) { 434 switch (i % 4) { 435 case 0: fns[i] = filterArguments(fns[i - 5], 0, insertArguments(fns[i - 4], 1, ".")); break; 436 case 1: fns[i] = filterArguments(fns[i - 5], 1, insertArguments(fns[i - 3], 1, ".")); break; 437 case 2: fns[i] = filterReturnValue(fns[i - 5], insertArguments(fns[i - 2], 1, ".")); break; 438 } 439 } 440 } recursiveFunction(Object x, Object y)441 Object recursiveFunction(Object x, Object y) throws Throwable { 442 depth++; 443 try { 444 final int ACTION_COUNT = 11; 445 switch (random.nextInt(ACTION_COUNT)) { 446 case 1: 447 Throwable ex = new RuntimeException(); 448 ex.fillInStackTrace(); 449 if (VERBOSITY >= 2) ex.printStackTrace(System.out); 450 x = "ST; " + x; 451 break; 452 case 2: 453 System.gc(); 454 x = "GC; " + x; 455 break; 456 } 457 boolean isLeaf = (depth >= MAX_DEPTH); 458 if (isLeaf) { 459 return Arrays.asList(x, y).toString(); 460 } 461 return fns[random.nextInt(fns.length)].invokeExact(x, y); 462 } finally { 463 depth--; 464 } 465 } 466 } 467 sequence(MethodHandle mh1, MethodHandle... mhs)468 private static MethodHandle sequence(MethodHandle mh1, MethodHandle... mhs) { 469 MethodHandle res = mh1; 470 for (MethodHandle mh2 : mhs) 471 res = filterReturnValue(res, mh2); 472 return res; 473 } assertEqualFunction(MethodHandle x, MethodHandle y)474 private static void assertEqualFunction(MethodHandle x, MethodHandle y) throws Throwable { 475 assertEquals(x.type(), y.type()); //?? 476 MethodType t = x.type(); 477 if (t.parameterCount() == 0) { 478 assertEqualFunctionAt(null, x, y); 479 return; 480 } 481 Class<?> ptype = t.parameterType(0); 482 if (ptype == long.class || ptype == Long.class) { 483 for (long i = -10; i <= 10; i++) { 484 assertEqualFunctionAt(i, x, y); 485 } 486 } else { 487 for (int i = -10; i <= 10; i++) { 488 assertEqualFunctionAt(i, x, y); 489 } 490 } 491 } assertEqualFunctionAt(Object v, MethodHandle x, MethodHandle y)492 private static void assertEqualFunctionAt(Object v, MethodHandle x, MethodHandle y) throws Throwable { 493 Object[] args = new Object[x.type().parameterCount()]; 494 Arrays.fill(args, v); 495 Object xval = invokeWithCatch(x, args); 496 Object yval = invokeWithCatch(y, args); 497 String msg = "ok"; 498 if (!Objects.equals(xval, yval)) { 499 msg = ("applying "+x+" & "+y+" to "+v); 500 } 501 assertEquals(msg, xval, yval); 502 } invokeWithCatch(MethodHandle mh, Object... args)503 private static Object invokeWithCatch(MethodHandle mh, Object... args) throws Throwable { 504 try { 505 return mh.invokeWithArguments(args); 506 } catch (Throwable ex) { 507 System.out.println("threw: "+mh+Arrays.asList(args)); 508 ex.printStackTrace(System.out); 509 return ex; 510 } 511 } 512 513 private static final Lookup LOOKUP = lookup(); findStatic(String name, Class<?> rtype, Class<?>... ptypes)514 private static MethodHandle findStatic(String name, 515 Class<?> rtype, 516 Class<?>... ptypes) { 517 try { 518 return LOOKUP.findStatic(LOOKUP.lookupClass(), name, methodType(rtype, ptypes)); 519 } catch (ReflectiveOperationException ex) { 520 throw new RuntimeException(ex); 521 } 522 } findStatic(String name, Class<?> rtype, List<?> ptypes)523 private static MethodHandle findStatic(String name, 524 Class<?> rtype, 525 List<?> ptypes) { 526 return findStatic(name, rtype, ptypes.toArray(new Class<?>[ptypes.size()])); 527 } getProperty(String name, int dflt)528 static int getProperty(String name, int dflt) { 529 String qual = LOOKUP.lookupClass().getName(); 530 String prop = System.getProperty(qual+"."+name); 531 if (prop == null) prop = System.getProperty(name); 532 if (prop == null) return dflt; 533 return Integer.parseInt(prop); 534 } 535 opI(int... xs)536 private static int opI(int... xs) { 537 stress(); 538 int base = 100; 539 int z = 0; 540 for (int x : xs) { 541 z = (z * base) + (x % base); 542 } 543 verbose("opI", xs.length, xs, z); 544 return z; 545 } opI2(int x, int y)546 private static int opI2(int x, int y) { return opI(x, y); } // x*100 + y%100 opI3(int x, int y, int z)547 private static int opI3(int x, int y, int z) { return opI(x, y, z); } opI4(int w, int x, int y, int z)548 private static int opI4(int w, int x, int y, int z) { return opI(w, x, y, z); } opI(int x)549 private static int opI(int x) { return opI2(x, 37); } opI_L(int x)550 private static Object opI_L(int x) { return (Object) opI(x); } opJ3(long x, long y, long z)551 private static long opJ3(long x, long y, long z) { return (long) opI3((int)x, (int)y, (int)z); } opJ2(long x, long y)552 private static long opJ2(long x, long y) { return (long) opI2((int)x, (int)y); } opJ(long x)553 private static long opJ(long x) { return (long) opI((int)x); } opL2(Object x, Object y)554 private static Object opL2(Object x, Object y) { return (Object) opI2((int)x, (int)y); } opL(Object x)555 private static Object opL(Object x) { return (Object) opI((int)x); } opL2_I(Object x, Object y)556 private static int opL2_I(Object x, Object y) { return opI2((int)x, (int)y); } opL_I(Object x)557 private static int opL_I(Object x) { return opI((int)x); } opL_J(Object x)558 private static long opL_J(Object x) { return (long) opI((int)x); } 559 private static final MethodHandle opI, opI2, opI3, opI4, opI_L, opJ, opJ2, opJ3, opL2, opL, opL2_I, opL_I, opL_J; 560 static { 561 opI4 = findStatic("opI4", int.class, int.class, int.class, int.class, int.class); 562 opI3 = findStatic("opI3", int.class, int.class, int.class, int.class); 563 opI2 = findStatic("opI2", int.class, int.class, int.class); 564 opI = findStatic("opI", int.class, int.class); 565 opI_L = findStatic("opI_L", Object.class, int.class); 566 opJ = findStatic("opJ", long.class, long.class); 567 opJ2 = findStatic("opJ2", long.class, long.class, long.class); 568 opJ3 = findStatic("opJ3", long.class, long.class, long.class, long.class); 569 opL2 = findStatic("opL2", Object.class, Object.class, Object.class); 570 opL = findStatic("opL", Object.class, Object.class); 571 opL2_I = findStatic("opL2_I", int.class, Object.class, Object.class); 572 opL_I = findStatic("opL_I", int.class, Object.class); 573 opL_J = findStatic("opL_J", long.class, Object.class); 574 } 575 private static final MethodHandle[] INT_COLLECTORS = { 576 constant(int.class, 42), opI, opI2, opI3, opI4 577 }; 578 private static final MethodHandle[] BYTE_COLLECTORS = { 579 constant(byte.class, (byte)42), i2b(opI), i2b(opI2), i2b(opI3), i2b(opI4) 580 }; 581 private static final MethodHandle[] LONG_COLLECTORS = { 582 constant(long.class, 42), opJ, opJ2, opJ3 583 }; 584 addI(int x, int y)585 private static int addI(int x, int y) { stress(); return x+y; } addL(Object x, Object y)586 private static Object addL(Object x, Object y) { return addI((int)x, (int)y); } 587 private static final MethodHandle addI, addL; 588 static { 589 addI = findStatic("addI", int.class, int.class, int.class); 590 addL = findStatic("addL", Object.class, Object.class, Object.class); 591 } 592 list8ints(int a, int b, int c, int d, int e, int f, int g, int h)593 private static Object list8ints(int a, int b, int c, int d, int e, int f, int g, int h) { 594 return Arrays.asList(a, b, c, d, e, f, g, h); 595 } list8longs(long a, long b, long c, long d, long e, long f, long g, long h)596 private static Object list8longs(long a, long b, long c, long d, long e, long f, long g, long h) { 597 return Arrays.asList(a, b, c, d, e, f, g, h); 598 } 599 private static final MethodHandle list8ints = findStatic("list8ints", Object.class, 600 Collections.nCopies(8, int.class)); 601 private static final MethodHandle list8longs = findStatic("list8longs", Object.class, 602 Collections.nCopies(8, long.class)); 603 private static final MethodHandle[] INT_LISTERS, LONG_LISTERS, BYTE_LISTERS; 604 static { 605 int listerCount = list8ints.type().parameterCount() + 1; 606 INT_LISTERS = new MethodHandle[listerCount]; 607 LONG_LISTERS = new MethodHandle[listerCount]; 608 BYTE_LISTERS = new MethodHandle[listerCount]; 609 MethodHandle lister = list8ints; 610 MethodHandle llister = list8longs; 611 for (int i = listerCount - 1; ; i--) { 612 INT_LISTERS[i] = lister; 613 LONG_LISTERS[i] = llister; 614 BYTE_LISTERS[i] = i2b(lister); 615 if (i == 0) break; 616 lister = insertArguments(lister, i-1, 0); 617 llister = insertArguments(llister, i-1, 0L); 618 } 619 } i2b(MethodHandle mh)620 private static MethodHandle i2b(MethodHandle mh) { 621 return MethodHandles.explicitCastArguments(mh, subst(mh.type(), int.class, byte.class)); 622 } subst(MethodType mt, Class<?> from, Class<?> to)623 private static MethodType subst(MethodType mt, Class<?> from, Class<?> to) { 624 for (int i = 0; i < mt.parameterCount(); i++) { 625 if (mt.parameterType(i) == from) 626 mt = mt.changeParameterType(i, to); 627 } 628 if (mt.returnType() == from) 629 mt = mt.changeReturnType(to); 630 return mt; 631 } 632 633 convI_L(int x)634 private static Object convI_L(int x) { stress(); return (Object) x; } convL_I(Object x)635 private static int convL_I(Object x) { stress(); return (int) x; } convJ_L(long x)636 private static Object convJ_L(long x) { stress(); return (Object) x; } convL_J(Object x)637 private static long convL_J(Object x) { stress(); return (long) x; } convJ_I(long x)638 private static int convJ_I(long x) { stress(); return (int) x; } convI_J(int x)639 private static long convI_J(int x) { stress(); return (long) x; } 640 private static final MethodHandle convI_L, convL_I, convJ_L, convL_J, convJ_I, convI_J; 641 static { 642 convI_L = findStatic("convI_L", Object.class, int.class); 643 convL_I = findStatic("convL_I", int.class, Object.class); 644 convJ_L = findStatic("convJ_L", Object.class, long.class); 645 convL_J = findStatic("convL_J", long.class, Object.class); 646 convJ_I = findStatic("convJ_I", int.class, long.class); 647 convI_J = findStatic("convI_J", long.class, int.class); 648 } 649 650 // stress modes: 651 private static final int MAX_DEPTH = getProperty("MAX_DEPTH", 5); 652 private static final int REPEAT = getProperty("REPEAT", 0); 653 private static final int STRESS = getProperty("STRESS", 0); 654 private static /*v*/ int STRESS_COUNT; 655 private static final Object[] SINK = new Object[4]; stress()656 private static void stress() { 657 if (STRESS <= 0) return; 658 int count = STRESS + (STRESS_COUNT++ & 0x1); // non-constant value 659 for (int i = 0; i < count; i++) { 660 SINK[i % SINK.length] = new Object[STRESS + i % (SINK.length + 1)]; 661 } 662 } 663 664 // verbosity: 665 private static final int VERBOSITY = getProperty("VERBOSITY", 0) + (REPEAT == 0 ? 0 : -1); verbose(Object a, Object b, Object c, Object d)666 private static void verbose(Object a, Object b, Object c, Object d) { 667 if (VERBOSITY <= 0) return; 668 verbose(1, a, b, c, d); 669 } verbose(Object a, Object b, Object c)670 private static void verbose(Object a, Object b, Object c) { 671 if (VERBOSITY <= 0) return; 672 verbose(1, a, b, c); 673 } verbose(int level, Object a, Object... bcd)674 private static void verbose(int level, Object a, Object... bcd) { 675 if (level > VERBOSITY) return; 676 String m = a.toString(); 677 if (bcd != null && bcd.length > 0) { 678 List<Object> l = new ArrayList<>(bcd.length); 679 for (Object x : bcd) { 680 if (x instanceof Object[]) x = Arrays.asList((Object[])x); 681 if (x instanceof int[]) x = Arrays.toString((int[])x); 682 if (x instanceof long[]) x = Arrays.toString((long[])x); 683 l.add(x); 684 } 685 m = m+Arrays.asList(bcd); 686 } 687 System.out.println(m); 688 } 689 String testOnly; 690 String testOnlyTests; startTest(String name)691 private boolean startTest(String name) { 692 if (testOnly != null && !testOnly.contains(name)) 693 return false; 694 verbose(0, "["+name+"]"); 695 testOnlyTests = (testOnlyTests == null) ? name : testOnlyTests+" "+name; 696 return true; 697 } 698 699 } 700