1 /*
   2 * Copyright (c) 2018, 2025, 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=1200 -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=1200 -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 import com.sun.management.HotSpotDiagnosticMXBean;
  79 import java.lang.management.ManagementFactory;
  80 
  81 public class Fuzz implements Runnable {
  82     static final boolean VERIFY_STACK = true; // could add significant time
  83     static final boolean FILE    = true;
  84     static final boolean RANDOM  = true;
  85     static final boolean VERBOSE = false;

  86 
  87     static int COMPILATION_TIMEOUT = (int)(5_000 * Utils.TIMEOUT_FACTOR); // ms
  88 
  89     static final Path TEST_DIR = Path.of(System.getProperty("test.src", "."));
  90 
  91     public static void main(String[] args) {
  92         if (Platform.isSlowDebugBuild() && Platform.isOSX() && Platform.isAArch64()) {
  93             throw new SkippedException("Test is unstable with slowdebug bits "
  94                                        + "on macosx-aarch64");
  95         }
  96         if (Platform.isPPC()) {
  97             COMPILATION_TIMEOUT = COMPILATION_TIMEOUT * 2;
  98         }
  99         if (Platform.isDebugBuild()) {
 100             COMPILATION_TIMEOUT = COMPILATION_TIMEOUT * 2;
 101         }
 102         warmup();
 103         for (int compileLevel : new int[]{4}) {
 104             for (boolean compileRun : new boolean[]{true}) {
 105                 COMPILE_LEVEL = compileLevel;
 106                 COMPILE_RUN   = compileRun;
 107                 resetCompilation();
 108                 runTests();
 109             }
 110         }
 111     }
 112 
 113     static void runTests() {
 114         if (FILE)   testFile("fuzz.dat");
 115         if (RANDOM) testRandom(System.currentTimeMillis(), 50);
 116     }
 117 
 118     ////////////////
 119 
 120     enum Op {
 121         CALL_I_INT, CALL_I_DBL, CALL_I_MANY,
 122         CALL_C_INT, CALL_C_DBL, CALL_C_MANY,
 123         CALL_I_CTCH, CALL_C_CTCH,
 124         CALL_I_PIN, CALL_C_PIN,
 125         MH_I_INT, MH_C_INT, MH_I_MANY, MH_C_MANY,
 126         REF_I_INT, REF_C_INT, REF_I_MANY, REF_C_MANY,
 127         LOOP, YIELD, THROW, DONE;
 128 
 129         static final EnumSet<Op> BASIC       = EnumSet.of(LOOP, YIELD);
 130         static final EnumSet<Op> STANDARD    = EnumSet.range(CALL_I_INT, CALL_C_CTCH);
 131         static final EnumSet<Op> PIN         = EnumSet.range(CALL_I_PIN, CALL_C_PIN);
 132         static final EnumSet<Op> MH          = EnumSet.range(MH_I_INT, MH_C_MANY);
 133         static final EnumSet<Op> REFLECTED   = EnumSet.range(REF_I_INT, REF_C_MANY);
 134         static final EnumSet<Op> NON_CALLS   = EnumSet.range(LOOP, DONE);
 135         static final EnumSet<Op> COMPILED    = EnumSet.copyOf(Arrays.stream(Op.values()).filter(x -> x.toString().contains("_C_")).collect(Collectors.toList()));
 136         static final EnumSet<Op> INTERPRETED = EnumSet.copyOf(Arrays.stream(Op.values()).filter(x -> x.toString().contains("_I_")).collect(Collectors.toList()));
 137 
 138         static Op toInterpreted(Op op) { return INTERPRETED.contains(op) ? op : Enum.valueOf(Op.class, op.toString().replace("_C_", "_I_")); }
 139         static Op toCompiled(Op op)    { return COMPILED.contains(op)    ? op : Enum.valueOf(Op.class, op.toString().replace("_I_", "_C_")); }
 140     }
 141 
 142     static class Generator {
 143         public Op[] generate() {
 144             final int length = max(1, pick(5, 10, 50/*, 200*/) + plusOrMinus(5));
 145 
 146             Set<Op> highProb = new HashSet<Op>();
 147             Set<Op> lowProb  = new HashSet<Op>();
 148 
 149             if (percent(100)) highProb.addAll(Op.BASIC);
 150             if (percent(100)) highProb.addAll(Op.STANDARD);
 151             if (percent(1)) lowProb.add(Op.THROW);
 152             if (percent(3)) lowProb.addAll(Op.PIN);
 153             if (percent(3)) lowProb.addAll(Op.MH);
 154             if (percent(0)) lowProb.addAll(Op.REFLECTED);
 155             if (percent(50)) {
 156                 highProb.removeAll(Op.INTERPRETED);
 157                 lowProb.removeAll(Op.INTERPRETED);
 158             }
 159             Op[] highProb0 = highProb.toArray(Op[]::new);
 160             Op[] lowProb0  = lowProb.toArray(Op[]::new);
 161 
 162             int loops = 7;
 163             Op[] trace = new Op[length];
 164             for (int i=0; i < trace.length; i++) {
 165                 trace[i] = pick((lowProb.isEmpty() || percent(90)) ? highProb0 : lowProb0);
 166                 if (trace[i] == Op.LOOP && (loops--) <= 0) i--;
 167             }
 168             return trace;
 169         }
 170 
 171         private final Random rnd;
 172         public Generator(Random rnd) { this.rnd = rnd; }
 173         @SafeVarargs
 174         private <T> T pick(T... values) { return values[rnd.nextInt(values.length)]; }
 175         private boolean percent(int percent) { return rnd.nextInt(100) < percent; }
 176         private int plusOrMinus(int n) { return rnd.nextInt(2*n + 1) - n; }
 177     }
 178 
 179     static Stream<Op[]> random(Random rnd) {
 180         var g = new Generator(rnd);
 181         return Stream.iterate(0, x->x+1).map(__ -> g.generate());
 182     }
 183 
 184     static void testRandom(long seed, int number) {
 185         System.out.println("-- RANDOM (seed: " + seed + ") --");
 186         testStream(random(new Random(seed)).limit(number));
 187     }
 188 
 189     static void testFile(String fileName) {
 190         System.out.println("-- FILE (" + fileName + ") --");
 191         try {
 192             testStream(file(TEST_DIR.resolve(fileName)));
 193         } catch (java.io.IOException e) { throw new RuntimeException(e); }
 194     }
 195 
 196     static Stream<Op[]> file(Path file) throws java.io.IOException {
 197         return Files.lines(file).map(String::trim).filter(s -> !s.isBlank() && !s.startsWith("#")).map(Fuzz::parse);
 198     }
 199 
 200     static Op[] parse(String line) {
 201         return Arrays.stream(line.split(", ")).map(s -> Enum.valueOf(Op.class, s))
 202             .collect(Collectors.toList()).toArray(Op[]::new);
 203     }
 204 
 205     static int testCounter;
 206 
 207     static void testStream(Stream<Op[]> traces) { testCounter = 0; traces.forEach(Fuzz::testTrace); }
 208 
 209     ////////////////////////////////////////
 210 
 211     static void testTrace(Op[] trace) {
 212         testCounter++;
 213         System.out.println("\n" + testCounter + ": COMPILE_LEVEL: " + COMPILE_LEVEL + " COMPILE_RUN: " + COMPILE_RUN);
 214         for (int attempt = 0; attempt < 3; attempt++) {
 215             if (attempt > 0) System.out.println("RETRYING " + attempt);
 216 
 217             compile();
 218 
 219             long start = time();
 220             var fuzz = new Fuzz(trace);
 221             fuzz.verbose = VERBOSE && attempt == 0;
 222             fuzz.print();
 223             int yields = fuzz.test();
 224             time(start, "Test (" + yields + " yields)");
 225 
 226             if (fuzz.checkCompilation())
 227                 break;
 228         }
 229     }
 230 
 231     static final ContinuationScope SCOPE = new ContinuationScope() {};
 232 
 233     static class FuzzException extends RuntimeException {
 234         public FuzzException(String msg) { super(msg); }
 235     }
 236 
 237     boolean verbose = false;
 238 
 239     private final Op[] trace;
 240     private int index  = -1;
 241     private int result = -1;
 242 
 243     private Fuzz(Op[] trace) { this.trace = trace; }
 244 
 245     int test() {
 246         Continuation cont = new Continuation(SCOPE, this) {
 247             @Override protected void onPinned(Pinned reason) { if (verbose) System.out.println("PINNED " + reason); }
 248         };
 249 
 250         this.yields = 0;
 251         int count = 0;
 252         try {
 253             while (true) {
 254                 var start = time();
 255                 cont.run();
 256                 if (cont.isDone()) break;
 257 
 258                 assert !shouldThrow();
 259                 verifyStack(cont);
 260                 count++;
 261                 time(start, "Iteration");
 262             }
 263             verifyResult(result);
 264         } catch (FuzzException e) {
 265             assert shouldThrow();
 266             assert e.getMessage().equals("EX");
 267             assert cont.isDone();
 268         }
 269         assert count == yields : "count: " + count + " yields: " + yields;
 270         return count;
 271     }
 272 
 273     void print() { printTrace(trace); }
 274 
 275     private Op trace(int i) { return i < trace.length ? trace[i] : Op.DONE; }
 276     private Op current()    { return trace(index); }
 277     private Op next(int c)  { logOp(c); index++; return current(); }
 278 
 279     ////// Compilation
 280 
 281     private static boolean COMPILE_RUN;
 282     private static int COMPILE_LEVEL;
 283 
 284     static final int  WARMUP_ITERS = 15_000;
 285     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};
 286 
 287     static void warmup() {
 288         final long start = time();
 289         warmup(WARMUP_TRACE, WARMUP_ITERS); // generate (for reflection) and compile method handles
 290         time(start, "Warmup");
 291     }
 292 
 293     static void warmup(Op[] trace, int times) {
 294         for (int i=0; i<times; i++) {
 295             new Fuzz(trace).run();
 296         }
 297     }
 298 
 299     static void resetCompilation() {
 300         Set<Method> compile = Op.COMPILED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new));
 301         compile.add(run);
 302 
 303         for (Method m : compile) {
 304             WB.deoptimizeMethod(m);
 305             WB.clearMethodState(m);
 306         }
 307     }
 308 
 309     static void enqueueForCompilation(Method m) {
 310         if (WB.isMethodCompiled(m)) return;
 311         // WB compilation tasks do not expire while others do,
 312         // so we wait for an existing task to finish before enqueuing.
 313         // Alternatively run with -XX:TieredCompileTaskTimeout=5000
 314         Utils.waitForCondition(() -> WB.isMethodQueuedForCompilation(m), 1000);
 315         if (WB.isMethodCompiled(m)) return;
 316         WB.enqueueMethodForCompilation(m, COMPILE_LEVEL);
 317     }
 318 
 319     static void waitForCompilation(Method m) {
 320         if (!Utils.waitForCondition(() -> WB.isMethodCompiled(m), COMPILATION_TIMEOUT)) {
 321             System.out.println(">>> Compilation status for: " + m);
 322             System.out.println("isMethodCompiled: " + WB.isMethodCompiled(m) + " " +
 323                                 "isMethodCompilable: " + WB.isMethodCompilable(m) + " " +
 324                                 "isMethodQueuedForCompilation: " + WB.isMethodQueuedForCompilation(m) + " " +
 325                                 "getMethodCompilationLevel: " + WB.getMethodCompilationLevel(m));
 326             throw new AssertionError("Failed to compile " + m + " in " + COMPILATION_TIMEOUT + "ms");
 327         }
 328     }
 329 
 330     static void compileContinuation() {
 331         var compile = new HashSet<Method>();
 332         for (Method m : Continuation.class.getDeclaredMethods()) {
 333             if (!WB.isMethodCompiled(m)) {
 334                 if (!Modifier.isNative(m.getModifiers())
 335                     && (m.getName().startsWith("enter")
 336                      || m.getName().startsWith("yield"))) {
 337                     enqueueForCompilation(m);
 338                     compile.add(m);
 339                 }
 340             }
 341         }
 342 
 343         for (Method m : compile) waitForCompilation(m);
 344     }
 345 
 346     static void compile() {
 347         final long start = time();
 348 
 349         compileContinuation();
 350 
 351         Set<Method> compile   =    Op.COMPILED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new));
 352         Set<Method> interpret = Op.INTERPRETED.stream().map(Fuzz::method).collect(Collectors.toCollection(HashSet::new));
 353         (COMPILE_RUN ? compile : interpret).add(run);
 354 
 355         compile.addAll(precompile);
 356 
 357         for (Method m : interpret) WB.makeMethodNotCompilable(m);
 358 
 359         for (Method m : compile)   enqueueForCompilation(m);
 360         for (Method m : compile)   waitForCompilation(m);
 361         for (Method m : compile)   assert  WB.isMethodCompiled(m) : "method: " + m;
 362         for (Method m : interpret) assert !WB.isMethodCompiled(m) : "method: " + m;
 363 
 364         time(start, "Compile");
 365     }
 366 
 367     boolean checkContinuationCompilation() {
 368         for (Method m : Continuation.class.getDeclaredMethods()) {
 369             if (!WB.isMethodCompiled(m)) {
 370                 if (!Modifier.isNative(m.getModifiers())
 371                     && (m.getName().startsWith("enter")
 372                      || m.getName().startsWith("yield"))) {
 373                     return false;
 374                 }
 375             }
 376         }
 377         return true;
 378     }
 379 
 380     boolean checkCompilation() {
 381         boolean res = true;
 382 
 383         if (!checkContinuationCompilation()) {
 384             res = false;
 385             System.out.println("CHANGED CONTINUATION COMPILATION");
 386         }
 387 
 388         Op[] newTrace = Arrays.copyOf(trace, trace.length);
 389         if (!checkCompilation(newTrace)) {
 390             res = false;
 391             System.out.println("CHANGED COMPILATION");
 392             printTrace(newTrace);
 393         }
 394 
 395         return res;
 396     }
 397 
 398     static boolean checkCompilation(Op[] trace) {
 399         boolean ok = true;
 400         for (int i = 0; i < trace.length; i++) {
 401             Op op = trace[i];
 402             if (Op.COMPILED.contains(op)    && !WB.isMethodCompiled(method(op))) trace[i] = Op.toInterpreted(op);
 403             if (Op.INTERPRETED.contains(op) &&  WB.isMethodCompiled(method(op))) trace[i] = Op.toCompiled(op);
 404             if (op != trace[i]) ok = false;
 405         }
 406         return ok;
 407     }
 408 
 409     /////////// Instance Helpers
 410 
 411     private StackTraceElement[] backtrace;
 412     private StackFrame[] fbacktrace;
 413     private StackFrame[] lfbacktrace;
 414     private int yields;
 415 
 416     void indent(int depth) {
 417         // depth = index;
 418         for (int i=0; i<depth; i++) System.out.print("  ");
 419     }
 420 
 421     void logOp(int iter) {
 422         if (!verbose) return;
 423 
 424         int depth = depth();
 425         System.out.print("> " + depth + " ");
 426         indent(depth);
 427         System.out.println("iter: " + iter + " index: " + index + " op: " + trace(index+1));
 428     }
 429 
 430     <T> T log(T result) {
 431         if (!verbose) return result;
 432 
 433         int depth = depth();
 434         System.out.print("> " + depth + " ");
 435         indent(depth);
 436         System.out.println("result " + result);
 437         return result;
 438     }
 439 
 440     int depth() {
 441         int d = 0;
 442         for (int i=0; i<=index && i < trace.length; i++) if (!Op.NON_CALLS.contains(trace[i])) d++;
 443         return d;
 444     }
 445 
 446     boolean traceHas(Predicate<Op> pred) {
 447         for (int i = 0; i < index; i++) if (pred.test(trace[i])) return true;
 448         return false;
 449     }
 450 
 451     String[] expectedStackTrace() {
 452         var ms = new ArrayList<String>();
 453         for (int i = index; i >= 0; i--) if (!Op.NON_CALLS.contains(trace[i])) ms.add(method(trace[i]).getName());
 454         ms.add("run");
 455         return ms.toArray(new String[0]);
 456     }
 457 
 458     int computeResult() {
 459         // To compute the expected result, we remove all YIELDs from the trace and run it
 460         Op[] trace0 = Arrays.stream(trace).filter(op -> op != Op.YIELD)
 461             .collect(Collectors.toList()).toArray(Op[]::new);
 462 
 463         Fuzz f0 = new Fuzz(trace0);
 464         // if (VERBOSE) {
 465         //     System.out.println(">>>> RESULT");
 466         //     f0.verbose = true;
 467         // }
 468         f0.run();
 469         return f0.result;
 470     }
 471 
 472     void verifyResult(int result) {
 473         int computed = computeResult();
 474         assert result == computed : "result: " + result + " expected: " + computed;
 475     }
 476 
 477     boolean shouldPin() {
 478         // Returns false since we never pin after we removed legacy locking.
 479         return traceHas(Op.PIN::contains) && false;
 480     }
 481 
 482     void verifyPin(boolean yieldResult) {
 483         if (yieldResult) yields++;
 484         if (!yieldResult && traceHas(op -> Op.INTERPRETED.contains(op) && Op.REFLECTED.contains(op))) return;
 485         assert yieldResult != shouldPin() : "res: " + yieldResult + " shouldPin: " + shouldPin();
 486     }
 487 
 488     boolean shouldThrow() {
 489         for (int i = 0; i <= index && i < trace.length; i++) {
 490             switch (trace[i]) {
 491                 case CALL_I_CTCH, CALL_C_CTCH -> { return false; }
 492                 case THROW -> { return true; }
 493                 default -> {}
 494             }
 495         }
 496         return false;
 497     }
 498 
 499     void captureStack() {
 500         // Thread.dumpStack();
 501         if (!VERIFY_STACK) return;
 502         backtrace = Thread.currentThread().getStackTrace();
 503         fbacktrace = StackWalkerHelper.getStackFrames(SCOPE);
 504         lfbacktrace = StackWalkerHelper.getLiveStackFrames(SCOPE);
 505     }
 506 
 507     void verifyStack() {
 508         if (!VERIFY_STACK) return;
 509         var start = time();
 510         verifyStack(backtrace);
 511         verifyStack(backtrace, StackWalkerHelper.toStackTraceElement(fbacktrace));
 512         verifyStack(fbacktrace, lfbacktrace);
 513 
 514         verifyStack(backtrace, Thread.currentThread().getStackTrace());
 515         verifyStack(fbacktrace, StackWalkerHelper.getStackFrames(SCOPE));
 516         verifyStack(lfbacktrace, StackWalkerHelper.getLiveStackFrames(SCOPE));
 517         time(start, "Verify stack");
 518     }
 519 
 520     void verifyStack(Continuation cont) {
 521         if (!VERIFY_STACK) return;
 522         var start = time();
 523         verifyStack(backtrace);
 524         verifyStack(backtrace, StackWalkerHelper.toStackTraceElement(fbacktrace));
 525         verifyStack(fbacktrace, lfbacktrace);
 526 
 527         verifyStack(backtrace, cont.getStackTrace());
 528         verifyStack(fbacktrace, StackWalkerHelper.getStackFrames(cont));
 529         verifyStack(lfbacktrace, StackWalkerHelper.getLiveStackFrames(cont));
 530         time(start, "Verify continuation stack");
 531     }
 532 
 533     static boolean isStackCaptureMechanism(Object sf) {
 534         return Fuzz.class.getName().equals(sfClassName(sf))
 535             && ("captureStack".equals(sfMethodName(sf)) || "verifyStack".equals(sfMethodName(sf)));
 536     }
 537 
 538     static boolean isPrePostYield(Object sf) {
 539         return Fuzz.class.getName().equals(sfClassName(sf))
 540             && ("preYield".equals(sfMethodName(sf)) || "postYield".equals(sfMethodName(sf)));
 541     }
 542 
 543     static <T> T[] cutStack(T[] stack) {
 544         var list = new ArrayList<T>();
 545         int i = 0;
 546         while (i < stack.length && (!Fuzz.class.getName().equals(sfClassName(stack[i])) || isPrePostYield(stack[i]) || isStackCaptureMechanism(stack[i]))) i++;
 547         while (i < stack.length && !Continuation.class.getName().equals(sfClassName(stack[i]))) { list.add(stack[i]); i++; }
 548         // while (i < stack.length && Continuation.class.getName().equals(sfClassName(stack[i])) && !"enterSpecial".equals(sfMethodName(stack[i]))) { list.add(stack[i]); i++; }
 549         return list.toArray(arrayType(stack));
 550     }
 551 
 552     void verifyStack(Object[] observed) {
 553         verifyStack(
 554             expectedStackTrace(),
 555             Arrays.stream(cutStack(observed)).filter(sf -> Fuzz.class.getName().equals(sfClassName(sf)))
 556                             .collect(Collectors.toList()).toArray(Object[]::new));
 557     }
 558 
 559     static void verifyStack(Object[] expected, Object[] observed) {
 560         expected = cutStack(expected);
 561         observed = cutStack(observed);
 562         boolean equal = true;
 563         if (expected.length == observed.length) {
 564             for (int i=0; i < expected.length; i++) {
 565                 if (!sfEquals(expected[i], observed[i])) {
 566                     // we allow a different line number for the first element
 567                     if (i > 0 || !Objects.equals(sfClassName(expected[i]), sfClassName(observed[i])) || !Objects.equals(sfMethodName(expected[i]), sfMethodName(observed[i]))) {
 568                         System.out.println("At index " + i + " expected: " + sfToString(expected[i]) + " observed: " + sfToString(observed[i]));
 569 
 570                         equal = false;
 571                         break;
 572                     }
 573                 }
 574             }
 575         } else {
 576             equal = false;
 577             System.out.println("Expected length: " + expected.length + " Observed length: " + observed.length);
 578         }
 579         if (!equal) {
 580             System.out.println("Expected: "); for (var sf : expected) System.out.println("\t" + sf);
 581             System.out.println("Observed: "); for (var sf : observed) System.out.println("\t" + sf);
 582         }
 583         assert equal;
 584     }
 585 
 586     static String sfClassName(Object f)  {
 587         return f instanceof String ? Fuzz.class.getName() :
 588             (f instanceof StackTraceElement ? ((StackTraceElement)f).getClassName()  : ((StackFrame)f).getClassName()); }
 589     static String sfMethodName(Object f) {
 590         return f instanceof String ? (String)f :
 591             (f instanceof StackTraceElement ? ((StackTraceElement)f).getMethodName() : ((StackFrame)f).getMethodName()); }
 592 
 593     static boolean sfEquals(Object a, Object b) {
 594         if (a instanceof String)
 595             return sfClassName(a).equals(sfClassName(b)) && sfMethodName(a).equals(sfMethodName(b));
 596 
 597         return a instanceof StackTraceElement ? Objects.equals(a, b)
 598                                               : StackWalkerHelper.equals((StackFrame)a, (StackFrame)b);
 599     }
 600 
 601     static String sfToString(Object f) {
 602         return f instanceof StackFrame ? StackWalkerHelper.frameToString((StackFrame)f) : Objects.toString(f);
 603     }
 604 
















































































































 605     //// Static Helpers
 606 
 607     static void rethrow(Throwable t) {
 608         if (t instanceof Error) throw (Error)t;
 609         if (t instanceof RuntimeException) throw (RuntimeException)t;
 610         throw new AssertionError(t);
 611     }
 612 
 613     static <T> T[] arrayType(T[] array) {
 614         return (T[])java.lang.reflect.Array.newInstance(array.getClass().componentType(), 0);
 615     }
 616 
 617     static void printTrace(Op[] trace) { System.out.println(write(trace)); }
 618 
 619     static String write(Op[] trace) {
 620         return Arrays.stream(trace).map(Object::toString).collect(Collectors.joining(", "));
 621     }
 622 
 623     static Method method(Op op)       { return method.get(op); }
 624     static MethodHandle handle(Op op) { return handle.get(op); }
 625 
 626     static long time() { return System.nanoTime(); }
 627     static void time(long startNanos, String message) {
 628         final long duration = (System.nanoTime() - startNanos)/1_000_000;
 629         if (duration > 500)
 630             System.out.println(message + " in " + duration + " ms");
 631     }
 632 
 633     //////
 634 
 635     private static final WhiteBox WB = WhiteBox.getWhiteBox();
 636 
 637     static final Class<?>[] run_sig = new Class<?>[]{};
 638     static final Class<?>[] int_sig = new Class<?>[]{int.class, int.class};
 639     static final Class<?>[] dbl_sig = new Class<?>[]{int.class, double.class};


 640     static final Class<?>[] mny_sig = new Class<?>[]{int.class,
 641         int.class, double.class, long.class, float.class, Object.class,
 642         int.class, double.class, long.class, float.class, Object.class,
 643         int.class, double.class, long.class, float.class, Object.class,
 644         int.class, double.class, long.class, float.class, Object.class};
 645     static final MethodType run_type = MethodType.methodType(void.class, run_sig);
 646     static final MethodType int_type = MethodType.methodType(int.class, int_sig);
 647     static final MethodType dbl_type = MethodType.methodType(double.class, dbl_sig);
 648     static final MethodType mny_type = MethodType.methodType(int.class, mny_sig);
 649 
 650     static final List<Method> precompile = new ArrayList<>();
 651 
 652     static final Method run;
 653     static final Map<Op, Method>       method = new EnumMap<>(Op.class);
 654     static final Map<Op, MethodHandle> handle = new EnumMap<>(Op.class);
 655 
 656     static {
 657         try {
 658             run = Fuzz.class.getDeclaredMethod("run", run_sig);
 659             // precompile.add(Fuzz.class.getDeclaredMethod("maybeResetIndex", new Class<?>[]{int.class}));
 660 
 661             method.put(Op.CALL_I_INT,  Fuzz.class.getDeclaredMethod("int_int", int_sig));
 662             method.put(Op.CALL_C_INT,  Fuzz.class.getDeclaredMethod("com_int", int_sig));
 663             method.put(Op.CALL_I_DBL,  Fuzz.class.getDeclaredMethod("int_dbl", dbl_sig));
 664             method.put(Op.CALL_C_DBL,  Fuzz.class.getDeclaredMethod("com_dbl", dbl_sig));


 665             method.put(Op.CALL_I_MANY, Fuzz.class.getDeclaredMethod("int_mny", mny_sig));
 666             method.put(Op.CALL_C_MANY, Fuzz.class.getDeclaredMethod("com_mny", mny_sig));
 667             method.put(Op.CALL_I_PIN,  Fuzz.class.getDeclaredMethod("int_pin", int_sig));
 668             method.put(Op.CALL_C_PIN,  Fuzz.class.getDeclaredMethod("com_pin", int_sig));
 669 
 670             method.put(Op.CALL_I_CTCH, method(Op.CALL_I_INT));
 671             method.put(Op.CALL_C_CTCH, method(Op.CALL_C_INT));
 672 
 673             method.put(Op.MH_I_INT,  method(Op.CALL_I_INT));
 674             method.put(Op.MH_C_INT,  method(Op.CALL_C_INT));
 675             method.put(Op.MH_I_MANY, method(Op.CALL_I_MANY));
 676             method.put(Op.MH_C_MANY, method(Op.CALL_C_MANY));
 677 
 678             method.put(Op.REF_I_INT,  method(Op.CALL_I_INT));
 679             method.put(Op.REF_C_INT,  method(Op.CALL_C_INT));
 680             method.put(Op.REF_I_MANY, method(Op.CALL_I_MANY));
 681             method.put(Op.REF_C_MANY, method(Op.CALL_C_MANY));
 682 
 683             MethodHandles.Lookup lookup = MethodHandles.lookup();
 684 
 685             handle.put(Op.MH_I_INT,  lookup.unreflect(method(Op.CALL_I_INT)));
 686             handle.put(Op.MH_C_INT,  lookup.unreflect(method(Op.CALL_C_INT)));
 687             handle.put(Op.MH_I_MANY, lookup.unreflect(method(Op.CALL_I_MANY)));
 688             handle.put(Op.MH_C_MANY, lookup.unreflect(method(Op.CALL_C_MANY)));
 689         } catch (ReflectiveOperationException e) {
 690             throw new AssertionError(e);
 691         }
 692     }
 693 
 694     @DontInline void preYield() { captureStack(); }
 695     @DontInline void postYield(boolean yieldResult) { verifyPin(yieldResult); verifyStack(); }
 696     @DontInline void maybeResetIndex(int index0) { this.index = current() != Op.YIELD ? index0 : index; }
 697     @DontInline void throwException() { throw new FuzzException("EX"); }
 698 
 699     @Override
 700     public void run() {
 701         final int depth = 0;
 702         int res = 3;
 703 
 704         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 705         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 706         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 707         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 708         Object o1 = res, o2 = res, o3 = res, o4 = res;





 709 
 710         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 711             switch (next(c)) {
 712             case THROW -> throwException();
 713             case LOOP  -> { c += 2; index0 = index; }
 714             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 715             case DONE  -> { break; }
 716             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 717             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 718             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 719             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 720             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 721             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 722             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);
 723             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);
 724             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 725             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 726             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 727             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); }}
 728             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; }}
 729             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; }}
 730             default -> throw new AssertionError("Unknown op: " + current());
 731             }
 732         }
 733 
 734         this.result = log(res);
 735     }
 736 
 737     @DontInline
 738     int int_int(final int depth, int x) {
 739         int res = x;
 740 
 741         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 742         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 743         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 744         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 745         Object o1 = res, o2 = res, o3 = res, o4 = res;





 746 
 747         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 748             switch (next(c)) {
 749             case THROW -> throwException();
 750             case LOOP  -> { c += 2; index0 = index; }
 751             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 752             case DONE  -> { break; }
 753             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 754             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 755             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 756             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 757             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 758             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 759             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);
 760             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);
 761             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 762             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 763             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 764             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); }}
 765             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; }}
 766             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; }}
 767             default -> throw new AssertionError("Unknown op: " + current());
 768             }
 769         }
 770 
 771         return log(res);
 772     }
 773 
 774     @DontInline
 775     int com_int(final int depth, int x) {
 776         int res = x;
 777 
 778         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 779         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 780         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 781         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 782         Object o1 = res, o2 = res, o3 = res, o4 = res;





 783 
 784         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 785             switch (next(c)) {
 786             case THROW -> throwException();
 787             case LOOP  -> { c += 2; index0 = index; }
 788             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 789             case DONE  -> { break; }
 790             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 791             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 792             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 793             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 794             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 795             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 796             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);
 797             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);
 798             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 799             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 800             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 801             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); }}
 802             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; }}
 803             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; }}
 804             default -> throw new AssertionError("Unknown op: " + current());
 805             }
 806         }
 807 
 808         return log(res);
 809     }
 810 
 811     @DontInline
 812     double int_dbl(final int depth, double x) {
 813         double res = 3.0;
 814 
 815         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 816         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 817         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 818         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 819         Object o1 = res, o2 = res, o3 = res, o4 = res;





 820 
 821         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 822             switch (next(c)) {
 823             case THROW -> throwException();
 824             case LOOP  -> { c += 2; index0 = index; }
 825             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 826             case DONE  -> { break; }
 827             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 828             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 829             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 830             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 831             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 832             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 833             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);
 834             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);
 835             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 836             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 837             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 838             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); }}
 839             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; }}
 840             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; }}
 841             default -> throw new AssertionError("Unknown op: " + current());
 842             }
 843         }
 844 
 845         return log(res);
 846     }
 847 
 848     @DontInline
 849     double com_dbl(final int depth, double x) {
 850         double res = 3.0;
 851 
 852         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 853         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 854         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 855         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 856         Object o1 = res, o2 = res, o3 = res, o4 = res;





 857 
 858         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 859             switch (next(c)) {
 860             case THROW -> throwException();
 861             case LOOP  -> { c += 2; index0 = index; }
 862             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 863             case DONE  -> { break; }
 864             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 865             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 866             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 867             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 868             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 869             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 870             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);
 871             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);
 872             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 873             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 874             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 875             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); }}
 876             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; }}
 877             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; }}
 878             default -> throw new AssertionError("Unknown op: " + current());
 879             }
 880         }
 881 
 882         return log(res);
 883     }
 884 








































































































 885     @DontInline
 886     int int_pin(final int depth, int x) {
 887         int res = x;
 888 
 889         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 890         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 891         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 892         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 893         Object o1 = res, o2 = res, o3 = res, o4 = res;





 894 
 895         synchronized (this) {
 896 
 897         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 898             switch (next(c)) {
 899             case THROW -> throwException();
 900             case LOOP  -> { c += 2; index0 = index; }
 901             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 902             case DONE  -> { break; }
 903             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 904             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 905             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 906             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 907             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 908             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 909             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);
 910             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);
 911             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 912             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 913             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 914             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); }}
 915             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; }}
 916             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; }}
 917             default -> throw new AssertionError("Unknown op: " + current());
 918             }
 919         }
 920 
 921         }
 922 
 923         return log(res);
 924     }
 925 
 926     @DontInline
 927     int com_pin(final int depth, int x) {
 928         int res = x;
 929 
 930         int x1 = (int)res, x2 = (int)res, x3 = (int)res, x4 = (int)res;
 931         double d1 = (double)res, d2 = (double)res, d3 = (double)res, d4 = (double)res;
 932         long l1 = (long)res, l2 = (long)res, l3 = (long)res, l4 = (long)res;
 933         float f1 = (float)res, f2 = (float)res, f3 = (float)res, f4 = (float)res;
 934         Object o1 = res, o2 = res, o3 = res, o4 = res;





 935 
 936         synchronized (this) {
 937 
 938         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 939             switch (next(c)) {
 940             case THROW -> throwException();
 941             case LOOP  -> { c += 2; index0 = index; }
 942             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 943             case DONE  -> { break; }
 944             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 945             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 946             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 947             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 948             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 949             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 950             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);
 951             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);
 952             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 953             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 954             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 955             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); }}
 956             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; }}
 957             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; }}
 958             default -> throw new AssertionError("Unknown op: " + current());
 959             }
 960         }
 961 
 962         }
 963 
 964         return log(res);
 965     }
 966 
 967     @DontInline
 968     int int_mny(int depth,
 969         int x1, double d1, long l1, float f1, Object o1,
 970         int x2, double d2, long l2, float f2, Object o2,
 971         int x3, double d3, long l3, float f3, Object o3,
 972         int x4, double d4, long l4, float f4, Object o4) {
 973 
 974         double res = x1 + d2 + f3 + l4 + (double)(o4 instanceof Double ? (Double)o4 : (Integer)o4);





 975 
 976         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
 977             switch (next(c)) {
 978             case THROW -> throwException();
 979             case LOOP  -> { c += 2; index0 = index; }
 980             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
 981             case DONE  -> { break; }
 982             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
 983             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
 984             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
 985             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


 986             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
 987             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
 988             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);
 989             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);
 990             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
 991             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
 992             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
 993             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); }}
 994             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; }}
 995             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; }}
 996             default -> throw new AssertionError("Unknown op: " + current());
 997             }
 998         }
 999 
1000         return log((int)res);
1001     }
1002 
1003     @DontInline
1004     int com_mny(int depth,
1005         int x1, double d1, long l1, float f1, Object o1,
1006         int x2, double d2, long l2, float f2, Object o2,
1007         int x3, double d3, long l3, float f3, Object o3,
1008         int x4, double d4, long l4, float f4, Object o4) {
1009 
1010         double res = x1 + d2 + f3 + l4 + (double)(o4 instanceof Double ? (Double)o4 : (Integer)o4);





1011 
1012         for (int c = 1, index0 = index; c > 0; c--, maybeResetIndex(index0)) { // index0 is the index to which we return when we loop
1013             switch (next(c)) {
1014             case THROW -> throwException();
1015             case LOOP  -> { c += 2; index0 = index; }
1016             case YIELD -> { preYield(); boolean y = Continuation.yield(SCOPE); postYield(y); c++; }
1017             case DONE  -> { break; }
1018             case CALL_I_INT  -> res += int_int(depth+1, (int)res);
1019             case CALL_C_INT  -> res += com_int(depth+1, (int)res);
1020             case CALL_I_DBL  -> res += (int)int_dbl(depth+1, res);
1021             case CALL_C_DBL  -> res += (int)com_dbl(depth+1, res);


1022             case CALL_I_PIN  -> res += int_pin(depth+1, (int)res);
1023             case CALL_C_PIN  -> res += com_pin(depth+1, (int)res);
1024             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);
1025             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);
1026             case CALL_I_CTCH -> {try { res += int_int(depth+1, (int)res); } catch (FuzzException e) {}}
1027             case CALL_C_CTCH -> {try { res += com_int(depth+1, (int)res); } catch (FuzzException e) {}}
1028             case MH_I_INT, MH_C_INT     -> {try { res += (int)handle(current()).invokeExact(this, depth+1, (int)res);  } catch (Throwable e) { rethrow(e); }}
1029             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); }}
1030             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; }}
1031             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; }}
1032             default -> throw new AssertionError("Unknown op: " + current());
1033             }
1034         }
1035 
1036         return log((int)res);
1037     }
1038 }
--- EOF ---