1 /* 2 * Copyright (c) 2018, 2023, 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 /* 25 * @test id=default 26 * @key randomness 27 * @summary Fuzz tests for jdk.internal.vm.Continuation 28 * @requires vm.continuations 29 * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) 30 * @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true 31 * @modules java.base java.base/jdk.internal.vm.annotation java.base/jdk.internal.vm 32 * @library /test/lib 33 * @build java.base/java.lang.StackWalkerHelper 34 * @build jdk.test.whitebox.WhiteBox 35 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 36 * 37 * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. 38 * Fuzz 39 */ 40 41 /* 42 * @test id=preserve-fp 43 * @key randomness 44 * @summary Fuzz tests for jdk.internal.vm.Continuation 45 * @requires vm.continuations 46 * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) 47 * @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true 48 * @modules java.base java.base/jdk.internal.vm.annotation java.base/jdk.internal.vm 49 * @library /test/lib 50 * @build java.base/java.lang.StackWalkerHelper 51 * @build jdk.test.whitebox.WhiteBox 52 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 53 * 54 * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. 55 * -XX:+PreserveFramePointer 56 * Fuzz 57 */ 58 59 import jdk.internal.vm.Continuation; 60 import jdk.internal.vm.ContinuationScope; 61 62 import java.lang.invoke.*; 63 import java.lang.reflect.*; 64 import java.lang.StackWalker.StackFrame; 65 import java.nio.file.*; 66 import java.util.*; 67 import java.util.function.*; 68 import java.util.stream.*; 69 import static java.lang.Math.max; 70 import static java.lang.Math.min; 71 import jdk.internal.vm.annotation.DontInline; 72 import jdk.test.lib.Utils; 73 import jdk.test.whitebox.WhiteBox; 74 75 import jdk.test.lib.Platform; 76 import jtreg.SkippedException; 77 78 public class Fuzz implements Runnable { 79 static final boolean VERIFY_STACK = true; // could add significant time 80 static final boolean FILE = true; 81 static final boolean RANDOM = true; 82 static final boolean VERBOSE = false; 83 84 static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); 85 static int COMPILATION_TIMEOUT = (int)(5_000 * timeoutFactor); // ms 86 87 static final Path TEST_DIR = Path.of(System.getProperty("test.src", ".")); 88 89 public static void main(String[] args) { 90 if (Platform.isSlowDebugBuild() && Platform.isOSX() && Platform.isAArch64()) { 91 throw new SkippedException("Test is unstable with slowdebug bits " 92 + "on macosx-aarch64"); 93 } 94 if (Platform.isPPC()) { 95 COMPILATION_TIMEOUT = COMPILATION_TIMEOUT * 2; 96 } 97 warmup(); 98 for (int compileLevel : new int[]{4}) { 99 for (boolean compileRun : new boolean[]{true}) { 100 COMPILE_LEVEL = compileLevel; 101 COMPILE_RUN = compileRun; 102 resetCompilation(); 103 runTests(); 104 } 105 } 106 } 107 108 static void runTests() { 109 if (FILE) testFile("fuzz.dat"); 110 if (RANDOM) testRandom(System.currentTimeMillis(), 50); 111 } 112 113 //////////////// 114 115 enum Op { 116 CALL_I_INT, CALL_I_DBL, CALL_I_MANY, 117 CALL_C_INT, CALL_C_DBL, CALL_C_MANY, 118 CALL_I_CTCH, CALL_C_CTCH, 119 CALL_I_PIN, CALL_C_PIN, 120 MH_I_INT, MH_C_INT, MH_I_MANY, MH_C_MANY, 121 REF_I_INT, REF_C_INT, REF_I_MANY, REF_C_MANY, 122 LOOP, YIELD, THROW, DONE; 123 124 static final EnumSet<Op> BASIC = EnumSet.of(LOOP, YIELD); 125 static final EnumSet<Op> STANDARD = EnumSet.range(CALL_I_INT, CALL_C_CTCH); 126 static final EnumSet<Op> PIN = EnumSet.range(CALL_I_PIN, CALL_C_PIN); 127 static final EnumSet<Op> MH = EnumSet.range(MH_I_INT, MH_C_MANY); 128 static final EnumSet<Op> REFLECTED = EnumSet.range(REF_I_INT, REF_C_MANY); 129 static final EnumSet<Op> NON_CALLS = EnumSet.range(LOOP, DONE); 130 static final EnumSet<Op> COMPILED = EnumSet.copyOf(Arrays.stream(Op.values()).filter(x -> x.toString().contains("_C_")).collect(Collectors.toList())); 131 static final EnumSet<Op> INTERPRETED = EnumSet.copyOf(Arrays.stream(Op.values()).filter(x -> x.toString().contains("_I_")).collect(Collectors.toList())); 132 133 static Op toInterpreted(Op op) { return INTERPRETED.contains(op) ? op : Enum.valueOf(Op.class, op.toString().replace("_C_", "_I_")); } 134 static Op toCompiled(Op op) { return COMPILED.contains(op) ? op : Enum.valueOf(Op.class, op.toString().replace("_I_", "_C_")); } 135 } 136 137 static class Generator { 138 public Op[] generate() { 139 final int length = max(1, pick(5, 10, 50/*, 200*/) + plusOrMinus(5)); 140 141 Set<Op> highProb = new HashSet<Op>(); 142 Set<Op> lowProb = new HashSet<Op>(); 143 144 if (percent(100)) highProb.addAll(Op.BASIC); 145 if (percent(100)) highProb.addAll(Op.STANDARD); 146 if (percent(1)) lowProb.add(Op.THROW); 147 if (percent(3)) lowProb.addAll(Op.PIN); 148 if (percent(3)) lowProb.addAll(Op.MH); 149 if (percent(0)) lowProb.addAll(Op.REFLECTED); 150 if (percent(50)) { 151 highProb.removeAll(Op.INTERPRETED); 152 lowProb.removeAll(Op.INTERPRETED); 153 } 154 Op[] highProb0 = highProb.toArray(Op[]::new); 155 Op[] lowProb0 = lowProb.toArray(Op[]::new); 156 157 int loops = 7; 158 Op[] trace = new Op[length]; 159 for (int i=0; i < trace.length; i++) { 160 trace[i] = pick((lowProb.isEmpty() || percent(90)) ? highProb0 : lowProb0); 161 if (trace[i] == Op.LOOP && (loops--) <= 0) i--; 162 } 163 return trace; 164 } 165 166 private final Random rnd; 167 public Generator(Random rnd) { this.rnd = rnd; } 168 @SafeVarargs 169 private <T> T pick(T... values) { return values[rnd.nextInt(values.length)]; } 170 private boolean percent(int percent) { return rnd.nextInt(100) < percent; } 171 private int plusOrMinus(int n) { return rnd.nextInt(2*n + 1) - n; } 172 } 173 174 static Stream<Op[]> random(Random rnd) { 175 var g = new Generator(rnd); 176 return Stream.iterate(0, x->x+1).map(__ -> g.generate()); 177 } 178 179 static void testRandom(long seed, int number) { 180 System.out.println("-- RANDOM (seed: " + seed + ") --"); 181 testStream(random(new Random(seed)).limit(number)); 182 } 183 184 static void testFile(String fileName) { 185 System.out.println("-- FILE (" + fileName + ") --"); 186 try { 187 testStream(file(TEST_DIR.resolve(fileName))); 188 } catch (java.io.IOException e) { throw new RuntimeException(e); } 189 } 190 191 static Stream<Op[]> file(Path file) throws java.io.IOException { 192 return Files.lines(file).map(String::trim).filter(s -> !s.isBlank() && !s.startsWith("#")).map(Fuzz::parse); 193 } 194 195 static Op[] parse(String line) { 196 return Arrays.stream(line.split(", ")).map(s -> Enum.valueOf(Op.class, s)) 197 .collect(Collectors.toList()).toArray(Op[]::new); 198 } 199 200 static int testCounter; 201 202 static void testStream(Stream<Op[]> traces) { testCounter = 0; traces.forEach(Fuzz::testTrace); } 203 204 //////////////////////////////////////// 205 206 static void testTrace(Op[] trace) { 207 testCounter++; 208 System.out.println("\n" + testCounter + ": COMPILE_LEVEL: " + COMPILE_LEVEL + " COMPILE_RUN: " + COMPILE_RUN); 209 for (int attempt = 0; attempt < 3; attempt++) { 210 if (attempt > 0) System.out.println("RETRYING " + attempt); 211 212 compile(); 213 214 long start = time(); 215 var fuzz = new Fuzz(trace); 216 fuzz.verbose = VERBOSE && attempt == 0; 217 fuzz.print(); 218 int yields = fuzz.test(); 219 time(start, "Test (" + yields + " yields)"); 220 221 if (fuzz.checkCompilation()) 222 break; 223 } 224 } 225 226 static final ContinuationScope SCOPE = new ContinuationScope() {}; 227 228 static class FuzzException extends RuntimeException { 229 public FuzzException(String msg) { super(msg); } 230 } 231 232 boolean verbose = false; 233 234 private final Op[] trace; 235 private int index = -1; 236 private int result = -1; 237 238 private Fuzz(Op[] trace) { this.trace = trace; } 239 240 int test() { 241 Continuation cont = new Continuation(SCOPE, this) { 242 @Override protected void onPinned(Pinned reason) { if (verbose) System.out.println("PINNED " + reason); } 243 }; 244 245 this.yields = 0; 246 int count = 0; 247 try { 248 while (true) { 249 var start = time(); 250 cont.run(); 251 if (cont.isDone()) break; 252 253 assert !shouldThrow(); 254 verifyStack(cont); 255 count++; 256 time(start, "Iteration"); 257 } 258 verifyResult(result); 259 } catch (FuzzException e) { 260 assert shouldThrow(); 261 assert e.getMessage().equals("EX"); 262 assert cont.isDone(); 263 } 264 assert count == yields : "count: " + count + " yields: " + yields; 265 return count; 266 } 267 268 void print() { printTrace(trace); } 269 270 private Op trace(int i) { return i < trace.length ? trace[i] : Op.DONE; } 271 private Op current() { return trace(index); } 272 private Op next(int c) { logOp(c); index++; return current(); } 273 274 ////// Compilation 275 276 private static boolean COMPILE_RUN; 277 private static int COMPILE_LEVEL; 278 279 static final int WARMUP_ITERS = 15_000; 280 static final Op[] WARMUP_TRACE = {Op.MH_C_INT, Op.MH_C_MANY, Op.REF_C_INT, Op.REF_C_MANY, Op.CALL_C_INT}; 281 282 static void warmup() { 283 final long start = time(); 284 warmup(WARMUP_TRACE, WARMUP_ITERS); // generate (for reflection) and compile method handles 285 time(start, "Warmup"); 286 } 287 288 static void warmup(Op[] trace, int times) { 289 for (int i=0; i<times; i++) { 290 new Fuzz(trace).run(); 291 } 292 } 293 294 static void resetCompilation() { 295 Set<Method> compile = Op.COMPILED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new)); 296 compile.add(run); 297 298 for (Method m : compile) { 299 WB.deoptimizeMethod(m); 300 WB.clearMethodState(m); 301 } 302 } 303 304 static void enqueueForCompilation(Method m) { 305 if (WB.isMethodCompiled(m)) return; 306 // WB compilation tasks do not expire while others do, 307 // so we wait for an existing task to finish before enqueuing. 308 // Alternatively run with -XX:TieredCompileTaskTimeout=5000 309 Utils.waitForCondition(() -> WB.isMethodQueuedForCompilation(m), 1000); 310 if (WB.isMethodCompiled(m)) return; 311 WB.enqueueMethodForCompilation(m, COMPILE_LEVEL); 312 } 313 314 static void waitForCompilation(Method m) { 315 if (!Utils.waitForCondition(() -> WB.isMethodCompiled(m), COMPILATION_TIMEOUT)) { 316 System.out.println(">>> Compilation status for: " + m); 317 System.out.println("isMethodCompiled: " + WB.isMethodCompiled(m) + " " + 318 "isMethodCompilable: " + WB.isMethodCompilable(m) + " " + 319 "isMethodQueuedForCompilation: " + WB.isMethodQueuedForCompilation(m) + " " + 320 "getMethodCompilationLevel: " + WB.getMethodCompilationLevel(m)); 321 throw new AssertionError("Failed to compile " + m + " in " + COMPILATION_TIMEOUT + "ms"); 322 } 323 } 324 325 static void compileContinuation() { 326 var compile = new HashSet<Method>(); 327 for (Method m : Continuation.class.getDeclaredMethods()) { 328 if (!WB.isMethodCompiled(m)) { 329 if (!Modifier.isNative(m.getModifiers()) 330 && (m.getName().startsWith("enter") 331 || m.getName().startsWith("yield"))) { 332 enqueueForCompilation(m); 333 compile.add(m); 334 } 335 } 336 } 337 338 for (Method m : compile) waitForCompilation(m); 339 } 340 341 static void compile() { 342 final long start = time(); 343 344 compileContinuation(); 345 346 Set<Method> compile = Op.COMPILED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new)); 347 Set<Method> interpret = Op.INTERPRETED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new)); 348 (COMPILE_RUN ? compile : interpret).add(run); 349 350 compile.addAll(precompile); 351 352 for (Method m : interpret) WB.makeMethodNotCompilable(m); 353 354 for (Method m : compile) enqueueForCompilation(m); 355 for (Method m : compile) waitForCompilation(m); 356 for (Method m : compile) assert WB.isMethodCompiled(m) : "method: " + m; 357 for (Method m : interpret) assert !WB.isMethodCompiled(m) : "method: " + m; 358 359 time(start, "Compile"); 360 } 361 362 boolean checkContinuationCompilation() { 363 for (Method m : Continuation.class.getDeclaredMethods()) { 364 if (!WB.isMethodCompiled(m)) { 365 if (!Modifier.isNative(m.getModifiers()) 366 && (m.getName().startsWith("enter") 367 || m.getName().startsWith("yield"))) { 368 return false; 369 } 370 } 371 } 372 return true; 373 } 374 375 boolean checkCompilation() { 376 boolean res = true; 377 378 if (!checkContinuationCompilation()) { 379 res = false; 380 System.out.println("CHANGED CONTINUATION COMPILATION"); 381 } 382 383 Op[] newTrace = Arrays.copyOf(trace, trace.length); 384 if (!checkCompilation(newTrace)) { 385 res = false; 386 System.out.println("CHANGED COMPILATION"); 387 printTrace(newTrace); 388 } 389 390 return res; 391 } 392 393 static boolean checkCompilation(Op[] trace) { 394 boolean ok = true; 395 for (int i = 0; i < trace.length; i++) { 396 Op op = trace[i]; 397 if (Op.COMPILED.contains(op) && !WB.isMethodCompiled(method(op))) trace[i] = Op.toInterpreted(op); 398 if (Op.INTERPRETED.contains(op) && WB.isMethodCompiled(method(op))) trace[i] = Op.toCompiled(op); 399 if (op != trace[i]) ok = false; 400 } 401 return ok; 402 } 403 404 /////////// Instance Helpers 405 406 private StackTraceElement[] backtrace; 407 private StackFrame[] fbacktrace; 408 private StackFrame[] lfbacktrace; 409 private int yields; 410 411 void indent(int depth) { 412 // depth = index; 413 for (int i=0; i<depth; i++) System.out.print(" "); 414 } 415 416 void logOp(int iter) { 417 if (!verbose) return; 418 419 int depth = depth(); 420 System.out.print("> " + depth + " "); 421 indent(depth); 422 System.out.println("iter: " + iter + " index: " + index + " op: " + trace(index+1)); 423 } 424 425 <T> T log(T result) { 426 if (!verbose) return result; 427 428 int depth = depth(); 429 System.out.print("> " + depth + " "); 430 indent(depth); 431 System.out.println("result " + result); 432 return result; 433 } 434 435 int depth() { 436 int d = 0; 437 for (int i=0; i<=index && i < trace.length; i++) if (!Op.NON_CALLS.contains(trace[i])) d++; 438 return d; 439 } 440 441 boolean traceHas(Predicate<Op> pred) { 442 for (int i = 0; i < index; i++) if (pred.test(trace[i])) return true; 443 return false; 444 } 445 446 String[] expectedStackTrace() { 447 var ms = new ArrayList<String>(); 448 for (int i = index; i >= 0; i--) if (!Op.NON_CALLS.contains(trace[i])) ms.add(method(trace[i]).getName()); 449 ms.add("run"); 450 return ms.toArray(new String[0]); 451 } 452 453 int computeResult() { 454 // To compute the expected result, we remove all YIELDs from the trace and run it 455 Op[] trace0 = Arrays.stream(trace).filter(op -> op != Op.YIELD) 456 .collect(Collectors.toList()).toArray(Op[]::new); 457 458 Fuzz f0 = new Fuzz(trace0); 459 // if (VERBOSE) { 460 // System.out.println(">>>> RESULT"); 461 // f0.verbose = true; 462 // } 463 f0.run(); 464 return f0.result; 465 } 466 467 void verifyResult(int result) { 468 int computed = computeResult(); 469 assert result == computed : "result: " + result + " expected: " + computed; 470 } 471 472 boolean shouldPin() { 473 return traceHas(Op.PIN::contains) && !(Platform.isX64() || Platform.isAArch64()); 474 } 475 476 void verifyPin(boolean yieldResult) { 477 if (yieldResult) yields++; 478 if (!yieldResult && traceHas(op -> Op.INTERPRETED.contains(op) && Op.REFLECTED.contains(op))) return; 479 assert yieldResult != shouldPin() : "res: " + yieldResult + " shouldPin: " + shouldPin(); 480 } 481 482 boolean shouldThrow() { 483 for (int i = 0; i <= index && i < trace.length; i++) { 484 switch (trace[i]) { 485 case CALL_I_CTCH, CALL_C_CTCH -> { return false; } 486 case THROW -> { return true; } 487 default -> {} 488 } 489 } 490 return false; 491 } 492 493 void captureStack() { 494 // Thread.dumpStack(); 495 if (!VERIFY_STACK) return; 496 backtrace = Thread.currentThread().getStackTrace(); 497 fbacktrace = StackWalkerHelper.getStackFrames(SCOPE); 498 lfbacktrace = StackWalkerHelper.getLiveStackFrames(SCOPE); 499 } 500 501 void verifyStack() { 502 if (!VERIFY_STACK) return; 503 var start = time(); 504 verifyStack(backtrace); 505 verifyStack(backtrace, StackWalkerHelper.toStackTraceElement(fbacktrace)); 506 verifyStack(fbacktrace, lfbacktrace); 507 508 verifyStack(backtrace, Thread.currentThread().getStackTrace()); 509 verifyStack(fbacktrace, StackWalkerHelper.getStackFrames(SCOPE)); 510 verifyStack(lfbacktrace, StackWalkerHelper.getLiveStackFrames(SCOPE)); 511 time(start, "Verify stack"); 512 } 513 514 void verifyStack(Continuation cont) { 515 if (!VERIFY_STACK) return; 516 var start = time(); 517 verifyStack(backtrace); 518 verifyStack(backtrace, StackWalkerHelper.toStackTraceElement(fbacktrace)); 519 verifyStack(fbacktrace, lfbacktrace); 520 521 verifyStack(backtrace, cont.getStackTrace()); 522 verifyStack(fbacktrace, StackWalkerHelper.getStackFrames(cont)); 523 verifyStack(lfbacktrace, StackWalkerHelper.getLiveStackFrames(cont)); 524 time(start, "Verify continuation stack"); 525 } 526 527 static boolean isStackCaptureMechanism(Object sf) { 528 return Fuzz.class.getName().equals(sfClassName(sf)) 529 && ("captureStack".equals(sfMethodName(sf)) || "verifyStack".equals(sfMethodName(sf))); 530 } 531 532 static boolean isPrePostYield(Object sf) { 533 return Fuzz.class.getName().equals(sfClassName(sf)) 534 && ("preYield".equals(sfMethodName(sf)) || "postYield".equals(sfMethodName(sf))); 535 } 536 537 static <T> T[] cutStack(T[] stack) { 538 var list = new ArrayList<T>(); 539 int i = 0; 540 while (i < stack.length && (!Fuzz.class.getName().equals(sfClassName(stack[i])) || isPrePostYield(stack[i]) || isStackCaptureMechanism(stack[i]))) i++; 541 while (i < stack.length && !Continuation.class.getName().equals(sfClassName(stack[i]))) { list.add(stack[i]); i++; } 542 // while (i < stack.length && Continuation.class.getName().equals(sfClassName(stack[i])) && !"enterSpecial".equals(sfMethodName(stack[i]))) { list.add(stack[i]); i++; } 543 return list.toArray(arrayType(stack)); 544 } 545 546 void verifyStack(Object[] observed) { 547 verifyStack( 548 expectedStackTrace(), 549 Arrays.stream(cutStack(observed)).filter(sf -> Fuzz.class.getName().equals(sfClassName(sf))) 550 .collect(Collectors.toList()).toArray(Object[]::new)); 551 } 552 553 static void verifyStack(Object[] expected, Object[] observed) { 554 expected = cutStack(expected); 555 observed = cutStack(observed); 556 boolean equal = true; 557 if (expected.length == observed.length) { 558 for (int i=0; i < expected.length; i++) { 559 if (!sfEquals(expected[i], observed[i])) { 560 // we allow a different line number for the first element 561 if (i > 0 || !Objects.equals(sfClassName(expected[i]), sfClassName(observed[i])) || !Objects.equals(sfMethodName(expected[i]), sfMethodName(observed[i]))) { 562 System.out.println("At index " + i + " expected: " + sfToString(expected[i]) + " observed: " + sfToString(observed[i])); 563 564 equal = false; 565 break; 566 } 567 } 568 } 569 } else { 570 equal = false; 571 System.out.println("Expected length: " + expected.length + " Observed length: " + observed.length); 572 } 573 if (!equal) { 574 System.out.println("Expected: "); for (var sf : expected) System.out.println("\t" + sf); 575 System.out.println("Observed: "); for (var sf : observed) System.out.println("\t" + sf); 576 } 577 assert equal; 578 } 579 580 static String sfClassName(Object f) { 581 return f instanceof String ? Fuzz.class.getName() : 582 (f instanceof StackTraceElement ? ((StackTraceElement)f).getClassName() : ((StackFrame)f).getClassName()); } 583 static String sfMethodName(Object f) { 584 return f instanceof String ? (String)f : 585 (f instanceof StackTraceElement ? ((StackTraceElement)f).getMethodName() : ((StackFrame)f).getMethodName()); } 586 587 static boolean sfEquals(Object a, Object b) { 588 if (a instanceof String) 589 return sfClassName(a).equals(sfClassName(b)) && sfMethodName(a).equals(sfMethodName(b)); 590 591 return a instanceof StackTraceElement ? Objects.equals(a, b) 592 : StackWalkerHelper.equals((StackFrame)a, (StackFrame)b); 593 } 594 595 static String sfToString(Object f) { 596 return f instanceof StackFrame ? StackWalkerHelper.frameToString((StackFrame)f) : Objects.toString(f); 597 } 598 599 //// Static Helpers 600 601 static void rethrow(Throwable t) { 602 if (t instanceof Error) throw (Error)t; 603 if (t instanceof RuntimeException) throw (RuntimeException)t; 604 throw new AssertionError(t); 605 } 606 607 static <T> T[] arrayType(T[] array) { 608 return (T[])java.lang.reflect.Array.newInstance(array.getClass().componentType(), 0); 609 } 610 611 static void printTrace(Op[] trace) { System.out.println(write(trace)); } 612 613 static String write(Op[] trace) { 614 return Arrays.stream(trace).map(Object::toString).collect(Collectors.joining(", ")); 615 } 616 617 static Method method(Op op) { return method.get(op); } 618 static MethodHandle handle(Op op) { return handle.get(op); } 619 620 static long time() { return System.nanoTime(); } 621 static void time(long startNanos, String message) { 622 final long duration = (System.nanoTime() - startNanos)/1_000_000; 623 if (duration > 500) 624 System.out.println(message + " in " + duration + " ms"); 625 } 626 627 ////// 628 629 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 630 631 static final Class<?>[] run_sig = new Class<?>[]{}; 632 static final Class<?>[] int_sig = new Class<?>[]{int.class, int.class}; 633 static final Class<?>[] dbl_sig = new Class<?>[]{int.class, double.class}; 634 static final Class<?>[] mny_sig = new Class<?>[]{int.class, 635 int.class, double.class, long.class, float.class, Object.class, 636 int.class, double.class, long.class, float.class, Object.class, 637 int.class, double.class, long.class, float.class, Object.class, 638 int.class, double.class, long.class, float.class, Object.class}; 639 static final MethodType run_type = MethodType.methodType(void.class, run_sig); 640 static final MethodType int_type = MethodType.methodType(int.class, int_sig); 641 static final MethodType dbl_type = MethodType.methodType(double.class, dbl_sig); 642 static final MethodType mny_type = MethodType.methodType(int.class, mny_sig); 643 644 static final List<Method> precompile = new ArrayList<>(); 645 646 static final Method run; 647 static final Map<Op, Method> method = new EnumMap<>(Op.class); 648 static final Map<Op, MethodHandle> handle = new EnumMap<>(Op.class); 649 650 static { 651 try { 652 run = Fuzz.class.getDeclaredMethod("run", run_sig); 653 // precompile.add(Fuzz.class.getDeclaredMethod("maybeResetIndex", new Class<?>[]{int.class})); 654 655 method.put(Op.CALL_I_INT, Fuzz.class.getDeclaredMethod("int_int", int_sig)); 656 method.put(Op.CALL_C_INT, Fuzz.class.getDeclaredMethod("com_int", int_sig)); 657 method.put(Op.CALL_I_DBL, Fuzz.class.getDeclaredMethod("int_dbl", dbl_sig)); 658 method.put(Op.CALL_C_DBL, Fuzz.class.getDeclaredMethod("com_dbl", dbl_sig)); 659 method.put(Op.CALL_I_MANY, Fuzz.class.getDeclaredMethod("int_mny", mny_sig)); 660 method.put(Op.CALL_C_MANY, Fuzz.class.getDeclaredMethod("com_mny", mny_sig)); 661 method.put(Op.CALL_I_PIN, Fuzz.class.getDeclaredMethod("int_pin", int_sig)); 662 method.put(Op.CALL_C_PIN, Fuzz.class.getDeclaredMethod("com_pin", int_sig)); 663 664 method.put(Op.CALL_I_CTCH, method(Op.CALL_I_INT)); 665 method.put(Op.CALL_C_CTCH, method(Op.CALL_C_INT)); 666 667 method.put(Op.MH_I_INT, method(Op.CALL_I_INT)); 668 method.put(Op.MH_C_INT, method(Op.CALL_C_INT)); 669 method.put(Op.MH_I_MANY, method(Op.CALL_I_MANY)); 670 method.put(Op.MH_C_MANY, method(Op.CALL_C_MANY)); 671 672 method.put(Op.REF_I_INT, method(Op.CALL_I_INT)); 673 method.put(Op.REF_C_INT, method(Op.CALL_C_INT)); 674 method.put(Op.REF_I_MANY, method(Op.CALL_I_MANY)); 675 method.put(Op.REF_C_MANY, method(Op.CALL_C_MANY)); 676 677 MethodHandles.Lookup lookup = MethodHandles.lookup(); 678 679 handle.put(Op.MH_I_INT, lookup.unreflect(method(Op.CALL_I_INT))); 680 handle.put(Op.MH_C_INT, lookup.unreflect(method(Op.CALL_C_INT))); 681 handle.put(Op.MH_I_MANY, lookup.unreflect(method(Op.CALL_I_MANY))); 682 handle.put(Op.MH_C_MANY, lookup.unreflect(method(Op.CALL_C_MANY))); 683 } catch (ReflectiveOperationException e) { 684 throw new AssertionError(e); 685 } 686 } 687 688 @DontInline void preYield() { captureStack(); } 689 @DontInline void postYield(boolean yieldResult) { verifyPin(yieldResult); verifyStack(); } 690 @DontInline void maybeResetIndex(int index0) { this.index = current() != Op.YIELD ? index0 : index; } 691 @DontInline void throwException() { throw new FuzzException("EX"); } 692 693 @Override 694 public void run() { 695 final int depth = 0; 696 int res = 3; 697 698 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 699 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 700 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 701 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 702 Object o1 = res, o2 = res, o3 = res, o4 = res; 703 704 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 705 switch (next(c)) { 706 case THROW -> throwException(); 707 case LOOP -> { c += 2; index0 = index; } 708 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 709 case DONE -> { break; } 710 case CALL_I_INT -> res += int_int(depth+1, (int)res); 711 case CALL_C_INT -> res += com_int(depth+1, (int)res); 712 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 713 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 714 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 715 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 716 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 717 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 718 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 719 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 720 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 721 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 722 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 723 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 724 default -> throw new AssertionError("Unknown op: " + current()); 725 } 726 } 727 728 this.result = log(res); 729 } 730 731 @DontInline 732 int int_int(final int depth, int x) { 733 int res = x; 734 735 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 736 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 737 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 738 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 739 Object o1 = res, o2 = res, o3 = res, o4 = res; 740 741 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 742 switch (next(c)) { 743 case THROW -> throwException(); 744 case LOOP -> { c += 2; index0 = index; } 745 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 746 case DONE -> { break; } 747 case CALL_I_INT -> res += int_int(depth+1, (int)res); 748 case CALL_C_INT -> res += com_int(depth+1, (int)res); 749 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 750 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 751 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 752 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 753 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 754 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 755 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 756 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 757 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 758 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 759 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 760 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 761 default -> throw new AssertionError("Unknown op: " + current()); 762 } 763 } 764 765 return log(res); 766 } 767 768 @DontInline 769 int com_int(final int depth, int x) { 770 int res = x; 771 772 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 773 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 774 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 775 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 776 Object o1 = res, o2 = res, o3 = res, o4 = res; 777 778 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 779 switch (next(c)) { 780 case THROW -> throwException(); 781 case LOOP -> { c += 2; index0 = index; } 782 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 783 case DONE -> { break; } 784 case CALL_I_INT -> res += int_int(depth+1, (int)res); 785 case CALL_C_INT -> res += com_int(depth+1, (int)res); 786 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 787 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 788 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 789 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 790 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 791 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 792 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 793 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 794 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 795 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 796 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 797 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 798 default -> throw new AssertionError("Unknown op: " + current()); 799 } 800 } 801 802 return log(res); 803 } 804 805 @DontInline 806 double int_dbl(final int depth, double x) { 807 double res = 3.0; 808 809 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 810 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 811 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 812 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 813 Object o1 = res, o2 = res, o3 = res, o4 = res; 814 815 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 816 switch (next(c)) { 817 case THROW -> throwException(); 818 case LOOP -> { c += 2; index0 = index; } 819 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 820 case DONE -> { break; } 821 case CALL_I_INT -> res += int_int(depth+1, (int)res); 822 case CALL_C_INT -> res += com_int(depth+1, (int)res); 823 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 824 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 825 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 826 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 827 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 828 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 829 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 830 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 831 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 832 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 833 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 834 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 835 default -> throw new AssertionError("Unknown op: " + current()); 836 } 837 } 838 839 return log(res); 840 } 841 842 @DontInline 843 double com_dbl(final int depth, double x) { 844 double res = 3.0; 845 846 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 847 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 848 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 849 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 850 Object o1 = res, o2 = res, o3 = res, o4 = res; 851 852 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 853 switch (next(c)) { 854 case THROW -> throwException(); 855 case LOOP -> { c += 2; index0 = index; } 856 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 857 case DONE -> { break; } 858 case CALL_I_INT -> res += int_int(depth+1, (int)res); 859 case CALL_C_INT -> res += com_int(depth+1, (int)res); 860 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 861 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 862 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 863 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 864 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 865 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 866 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 867 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 868 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 869 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 870 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 871 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 872 default -> throw new AssertionError("Unknown op: " + current()); 873 } 874 } 875 876 return log(res); 877 } 878 879 @DontInline 880 int int_pin(final int depth, int x) { 881 int res = x; 882 883 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 884 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 885 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 886 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 887 Object o1 = res, o2 = res, o3 = res, o4 = res; 888 889 synchronized (this) { 890 891 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 892 switch (next(c)) { 893 case THROW -> throwException(); 894 case LOOP -> { c += 2; index0 = index; } 895 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 896 case DONE -> { break; } 897 case CALL_I_INT -> res += int_int(depth+1, (int)res); 898 case CALL_C_INT -> res += com_int(depth+1, (int)res); 899 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 900 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 901 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 902 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 903 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 904 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 905 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 906 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 907 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 908 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 909 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 910 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 911 default -> throw new AssertionError("Unknown op: " + current()); 912 } 913 } 914 915 } 916 917 return log(res); 918 } 919 920 @DontInline 921 int com_pin(final int depth, int x) { 922 int res = x; 923 924 int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res; 925 double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res; 926 long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res; 927 float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res; 928 Object o1 = res, o2 = res, o3 = res, o4 = res; 929 930 synchronized (this) { 931 932 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 933 switch (next(c)) { 934 case THROW -> throwException(); 935 case LOOP -> { c += 2; index0 = index; } 936 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 937 case DONE -> { break; } 938 case CALL_I_INT -> res += int_int(depth+1, (int)res); 939 case CALL_C_INT -> res += com_int(depth+1, (int)res); 940 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 941 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 942 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 943 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 944 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 945 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 946 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 947 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 948 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 949 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 950 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 951 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 952 default -> throw new AssertionError("Unknown op: " + current()); 953 } 954 } 955 956 } 957 958 return log(res); 959 } 960 961 @DontInline 962 int int_mny(int depth, 963 int x1, double d1, long l1, float f1, Object o1, 964 int x2, double d2, long l2, float f2, Object o2, 965 int x3, double d3, long l3, float f3, Object o3, 966 int x4, double d4, long l4, float f4, Object o4) { 967 968 double res = x1 + d2 + f3 + l4 + (double)(o4 instanceof Double ? (Double)o4 : (Integer)o4); 969 970 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 971 switch (next(c)) { 972 case THROW -> throwException(); 973 case LOOP -> { c += 2; index0 = index; } 974 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 975 case DONE -> { break; } 976 case CALL_I_INT -> res += int_int(depth+1, (int)res); 977 case CALL_C_INT -> res += com_int(depth+1, (int)res); 978 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 979 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 980 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 981 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 982 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 983 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 984 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 985 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 986 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 987 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 988 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 989 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 990 default -> throw new AssertionError("Unknown op: " + current()); 991 } 992 } 993 994 return log((int)res); 995 } 996 997 @DontInline 998 int com_mny(int depth, 999 int x1, double d1, long l1, float f1, Object o1, 1000 int x2, double d2, long l2, float f2, Object o2, 1001 int x3, double d3, long l3, float f3, Object o3, 1002 int x4, double d4, long l4, float f4, Object o4) { 1003 1004 double res = x1 + d2 + f3 + l4 + (double)(o4 instanceof Double ? (Double)o4 : (Integer)o4); 1005 1006 for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop 1007 switch (next(c)) { 1008 case THROW -> throwException(); 1009 case LOOP -> { c += 2; index0 = index; } 1010 case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; } 1011 case DONE -> { break; } 1012 case CALL_I_INT -> res += int_int(depth+1, (int)res); 1013 case CALL_C_INT -> res += com_int(depth+1, (int)res); 1014 case CALL_I_DBL -> res += (int)int_dbl(depth+1, res); 1015 case CALL_C_DBL -> res += (int)com_dbl(depth+1, res); 1016 case CALL_I_PIN -> res += int_pin(depth+1, (int)res); 1017 case CALL_C_PIN -> res += com_pin(depth+1, (int)res); 1018 case CALL_I_MANY -> res += int_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 1019 case CALL_C_MANY -> res += com_mny(depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); 1020 case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}} 1021 case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}} 1022 case MH_I_INT, MH_C_INT -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res); } catch (Throwable e) { rethrow(e); }} 1023 case MH_I_MANY, MH_C_MANY -> {try { res += (int)handle(current()).invokeExact(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (Throwable e) { rethrow(e); }} 1024 case REF_I_INT, REF_C_INT -> {try { res += (int)method(current()).invoke(this, depth+1, (int)res); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 1025 case REF_I_MANY, REF_C_MANY -> {try { res += (int)method(current()).invoke(this, depth+1, x1, d1, l1, f1, o1, x2, d2, l2, f2, o2, x3, d3, l3, f3, o3, x4, d4, l4, f4, o4); } catch (InvocationTargetException e) { rethrow(e.getCause()); } catch (IllegalAccessException e) { assert false; }} 1026 default -> throw new AssertionError("Unknown op: " + current()); 1027 } 1028 } 1029 1030 return log((int)res); 1031 } 1032 }