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
















































































































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


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


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





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


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





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


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





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


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





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


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





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


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








































































































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





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


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





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


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





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


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





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


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