diff --git a/src/compiler/iroptimizer.js b/src/compiler/iroptimizer.js index 100f3890..f44dd730 100644 --- a/src/compiler/iroptimizer.js +++ b/src/compiler/iroptimizer.js @@ -627,9 +627,21 @@ class IROptimizer { return this.analyzeStack(stack, state) || modified; } + let iterations = 0; let modified = false; let keepLooping; do { + // If we are stuck in an apparent infinite loop, give up and assume the worst. + if (iterations > 10000) { + console.error('analyzeLoopedStack stuck in likely infinite loop; quitting', block, state); + modified = state.clear(); + block.entryState = state.clone(); + block.exitState = state.clone(); + modified = this.analyzeInputs(block.inputs, state) || modified; + return this.analyzeStack(stack, state) || modified; + } + iterations++; + const newState = state.clone(); modified = this.analyzeStack(stack, newState) || modified; modified = (keepLooping = state.or(newState)) || modified; diff --git a/test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 b/test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 new file mode 100644 index 00000000..1d91e7bc Binary files /dev/null and b/test/fixtures/execute/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3 differ diff --git a/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot new file mode 100644 index 00000000..2244a1bf --- /dev/null +++ b/test/snapshot/__snapshots__/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -0,0 +1,29 @@ +// TW Snapshot +// Input SHA-256: a12680688ca945364abe1e094b35cf53326f70189cb09b58d5f52b4de0c3b2a9 + +// Text script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +thread.procedures["Wtest 1"](); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +retire(); return; +}; }) + +// Text Wtest 1 +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; +return function funXYZ_test_1 () { +for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { +b0.value = ((+b0.value || 0) + 1); +} +return ""; +}; }) + +// Text Wany procedure reporter +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function funXYZ_any_procedure_report () { +return 0; +return ""; +}; }) diff --git a/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot new file mode 100644 index 00000000..f3b5937c --- /dev/null +++ b/test/snapshot/__snapshots__/warp-timer/tw-repeat-procedure-reporter-infinite-analyzer-loop.sb3.tw-snapshot @@ -0,0 +1,30 @@ +// TW Snapshot +// Input SHA-256: a12680688ca945364abe1e094b35cf53326f70189cb09b58d5f52b4de0c3b2a9 + +// Text script +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = runtime.getOpcodeFunction("looks_say"); +return function* genXYZ () { +yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a~", null); +yield* thread.procedures["Wtest 1"](); +yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "dh", null); +retire(); return; +}; }) + +// Text Wtest 1 +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +const b0 = target.variables["ts-.PQ{/]mN_9@MbG:m/"]; +return function* genXYZ_test_1 () { +for (var a0 = (+thread.procedures["Wany procedure reporter"]() || 0); a0 >= 0.5; a0--) { +b0.value = ((+b0.value || 0) + 1); +if (isStuck()) yield; +} +return ""; +}; }) + +// Text Wany procedure reporter +(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); +return function funXYZ_any_procedure_report () { +return 0; +return ""; +}; })