Skip to content

Commit d7a5f1c

Browse files
authored
Merge pull request #279
More misc compiler fixes
2 parents 7de26c9 + e81319b commit d7a5f1c

22 files changed

+392
-15
lines changed

src/compiler/iroptimizer.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @ts-check
22

33
const {StackOpcode, InputOpcode, InputType} = require('./enums.js');
4+
const log = require('../util/log');
45

56
// These imports are used by jsdoc comments but eslint doesn't know that
67
/* eslint-disable no-unused-vars */
@@ -16,7 +17,7 @@ const {
1617
class TypeState {
1718
constructor () {
1819
/** @type {Object.<string, InputType | 0>}*/
19-
this.variables = {};
20+
this.variables = Object.create(null);
2021
}
2122

2223
/**
@@ -30,7 +31,7 @@ class TypeState {
3031
break;
3132
}
3233
}
33-
this.variables = {};
34+
this.variables = Object.create(null);
3435
return modified;
3536
}
3637

@@ -93,7 +94,7 @@ class TypeState {
9394
after (other) {
9495
return this.mutate(other, varId => {
9596
const otherType = other.variables[varId];
96-
if (otherType !== 0) return otherType;
97+
if (otherType) return otherType;
9798
return this.variables[varId] ?? InputType.ANY;
9899
});
99100
}
@@ -541,29 +542,37 @@ class IROptimizer {
541542
state = state.clone();
542543
}
543544

544-
modified = this.analyzeInputs(inputs, state) || modified;
545-
546545
switch (stackBlock.opcode) {
547546
case StackOpcode.VAR_SET:
547+
modified = this.analyzeInputs(inputs, state) || modified;
548548
modified = state.setVariableType(inputs.variable, inputs.value.type) || modified;
549549
break;
550550
case StackOpcode.CONTROL_WHILE:
551551
case StackOpcode.CONTROL_FOR:
552552
case StackOpcode.CONTROL_REPEAT:
553+
modified = this.analyzeInputs(inputs, state) || modified;
553554
modified = this.analyzeLoopedStack(inputs.do, state, stackBlock) || modified;
554555
break;
555556
case StackOpcode.CONTROL_IF_ELSE: {
557+
modified = this.analyzeInputs(inputs, state) || modified;
556558
const trueState = state.clone();
557559
modified = this.analyzeStack(inputs.whenTrue, trueState) || modified;
558560
modified = this.analyzeStack(inputs.whenFalse, state) || modified;
559561
modified = state.or(trueState) || modified;
560562
break;
561563
}
562564
case StackOpcode.CONTROL_STOP_SCRIPT: {
565+
modified = this.analyzeInputs(inputs, state) || modified;
563566
this.addPossibleExitState(state);
564567
break;
565568
}
569+
case StackOpcode.CONTROL_WAIT_UNTIL: {
570+
modified = state.clear() || modified;
571+
modified = this.analyzeInputs(inputs, state) || modified;
572+
break;
573+
}
566574
case StackOpcode.PROCEDURE_CALL: {
575+
modified = this.analyzeInputs(inputs, state) || modified;
567576
modified = this.analyzeInputs(inputs.inputs, state) || modified;
568577
const script = this.ir.procedures[inputs.variant];
569578

@@ -575,6 +584,7 @@ class IROptimizer {
575584
break;
576585
}
577586
case StackOpcode.COMPATIBILITY_LAYER: {
587+
modified = this.analyzeInputs(inputs, state) || modified;
578588
this.analyzeInputs(inputs.inputs, state);
579589
for (const substackName in inputs.substacks) {
580590
const newState = state.clone();
@@ -583,6 +593,9 @@ class IROptimizer {
583593
}
584594
break;
585595
}
596+
default:
597+
modified = this.analyzeInputs(inputs, state) || modified;
598+
break;
586599
}
587600

588601
return modified;
@@ -635,7 +648,7 @@ class IROptimizer {
635648
do {
636649
// If we are stuck in an apparent infinite loop, give up and assume the worst.
637650
if (iterations > 10000) {
638-
console.error('analyzeLoopedStack stuck in likely infinite loop; quitting', block, state);
651+
log.error('analyzeLoopedStack stuck in likely infinite loop; quitting', block, state);
639652
modified = state.clear();
640653
block.entryState = state.clone();
641654
block.exitState = state.clone();
@@ -646,8 +659,8 @@ class IROptimizer {
646659

647660
const newState = state.clone();
648661
modified = this.analyzeStack(stack, newState) || modified;
649-
modified = this.analyzeInputs(block.inputs, newState) || modified;
650662
modified = (keepLooping = state.or(newState)) || modified;
663+
modified = this.analyzeInputs(block.inputs, state) || modified;
651664
} while (keepLooping);
652665
block.entryState = state.clone();
653666
return modified;
3.2 KB
Binary file not shown.
3.11 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
2.86 KB
Binary file not shown.
3.28 KB
Binary file not shown.

test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ b0.value = (b1.value[(((((+p1 || 0) + (+p0 || 0)) || 0) / 2) | 0) - 1] ?? "");
6767
b2.value = p0;
6868
b3.value = p1;
6969
while (true) {
70-
while (compareLessThan((b1.value[(b2.value | 0) - 1] ?? ""), b0.value)) {
70+
while (compareLessThan(listGet(b1.value, b2.value), b0.value)) {
7171
b2.value = ((+b2.value || 0) + 1);
7272
}
73-
while (compareGreaterThan((b1.value[(b3.value | 0) - 1] ?? ""), b0.value)) {
73+
while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) {
7474
b3.value = ((+b3.value || 0) + -1);
7575
}
7676
if (compareGreaterThan(b2.value, b3.value)) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// TW Snapshot
2+
// Input SHA-256: 3c81a01417b9a927457132a5f89b63e54b2499714376246739535b51dbce2d45
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
8+
return function* genXYZ () {
9+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null);
10+
thread.procedures["Wtest %s"]("random");
11+
if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) {
12+
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null);
13+
}
14+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null);
15+
retire(); return;
16+
}; })
17+
18+
// Sprite1 Wtest %s
19+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
20+
const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
21+
const b1 = stage.variables["t)]?yi[*8XU73qhMqOa8"];
22+
return function funXYZ_test_ (p0) {
23+
b0.value = p0;
24+
while (!(("" + listGet(b1.value, b0.value)).toLowerCase() === "something".toLowerCase())) {
25+
b0.value = ((+b0.value || 0) + 1);
26+
}
27+
return "";
28+
}; })
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// TW Snapshot
2+
// Input SHA-256: be149d21cc69628647000cc698ebd60949252730a0ea7b19f71cc85fe927b294
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
const b1 = stage.variables["%ehs:~!Y0l-5=!mnd-B?"];
8+
const b2 = stage.variables["=3aHfv[mKa)v,Wfpy:y?"];
9+
const b3 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
10+
return function* genXYZ () {
11+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null);
12+
b1.value = [];
13+
b1.value.push((1 + 2));
14+
b1._monitorUpToDate = false;
15+
b1.value.push("eof");
16+
b1._monitorUpToDate = false;
17+
b2.value = 0;
18+
b3.value = "bwah";
19+
while (!(("" + b3.value).toLowerCase() === "eof".toLowerCase())) {
20+
b2.value = ((+b2.value || 0) + 1);
21+
b3.value = (b1.value[(b2.value | 0) - 1] ?? "");
22+
yield;
23+
}
24+
if (((+b2.value || 0) === 2)) {
25+
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "q", null);
26+
}
27+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "o", null);
28+
retire(); return;
29+
}; })

0 commit comments

Comments
 (0)