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 ---