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