@samitouri / QOS-React-2 / commits / e51553f5da

InferReactiveScopes considers all operands, incl terminals

Joe Savona committed Nov 22, 2022 at 14:10 UTC e51553f5da66794e07fde96118e7816b1b92ea20
10 files changed +159 -49
compiler/forget/src/HIR/HIRTreeVisitor.ts
+15 -10
@@ -66,7 +66,9 @@ class Driver<TBlock, TValue, TItem, TCase> {
66 switch (terminal.kind) {
67 case "return": {
68 const value =
69 - terminal.value != null ? this.visitPlace(terminal.value) : null;
69 + terminal.value != null
70 + ? this.visitPlace(terminal.value, terminal.id)
71 + : null;
72 this.visitor.visitTerminalId(terminal.id);
73 this.visitor.appendBlock(
74 blockValue,
@@ -78,7 +80,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
80 break;
81 }
82 case "throw": {
81 - const value = this.visitPlace(terminal.value);
83 + const value = this.visitPlace(terminal.value, terminal.id);
84 this.visitor.visitTerminalId(terminal.id);
85 this.visitor.appendBlock(
86 blockValue,
@@ -90,7 +92,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
92 break;
93 }
94 case "if": {
93 - const test = this.visitPlace(terminal.test);
95 + const test = this.visitPlace(terminal.test, terminal.id);
96 const fallthroughId =
97 terminal.fallthrough !== null &&
98 !this.cx.isScheduled(terminal.fallthrough)
@@ -152,7 +154,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
154 break;
155 }
156 case "switch": {
155 - const test = this.visitPlace(terminal.test);
157 + const test = this.visitPlace(terminal.test, terminal.id);
158 const fallthroughId =
159 terminal.fallthrough !== null &&
160 !this.cx.isScheduled(terminal.fallthrough)
@@ -166,7 +168,10 @@ class Driver<TBlock, TValue, TItem, TCase> {
168 this.visitor.visitTerminalId(terminal.id);
169 const cases: Array<TCase> = [];
170 [...terminal.cases].reverse().forEach((case_, index) => {
169 - const test = case_.test !== null ? this.visitPlace(case_.test) : null;
171 + const test =
172 + case_.test !== null
173 + ? this.visitPlace(case_.test, terminal.id)
174 + : null;
175
176 let consequent;
177 if (this.cx.isScheduled(case_.block)) {
@@ -241,7 +246,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
246 // body.length === bodyLength,
247 // "Expected test to produce only temporaries"
248 // );
244 - const testValue = this.visitPlace(testTerminal.test);
249 + const testValue = this.visitPlace(testTerminal.test, terminal.id);
250 const fallthroughId =
251 terminal.fallthrough !== null &&
252 !this.cx.isScheduled(terminal.fallthrough)
@@ -391,13 +396,13 @@ class Driver<TBlock, TValue, TItem, TCase> {
396 }
397
398 visitInstr(instr: Instruction, blockValue: TBlock): void {
394 - const value = this.visitor.visitValue(instr.value);
399 + const value = this.visitor.visitValue(instr.value, instr.id);
400 const item = this.visitor.visitInstruction(instr, value);
401 this.visitor.appendBlock(blockValue, item);
402 }
403
399 - visitPlace(place: Place): TValue {
400 - return this.visitor.visitValue(place);
404 + visitPlace(place: Place, id: InstructionId): TValue {
405 + return this.visitor.visitValue(place, id);
406 }
407 }
408
@@ -642,7 +647,7 @@ export interface Visitor<TBlock, TValue, TItem, TCase> {
647 * Convert an InstructionValue into the visitor's own representation
648 * of a value.
649 */
645 - visitValue(value: InstructionValue): TValue;
650 + visitValue(value: InstructionValue, id: InstructionId): TValue;
651
652 /**
653 * Convert an Instruction into the visitor's own representation of
compiler/forget/src/HIR/InferReactiveScopes.ts
+24 -6
@@ -17,7 +17,10 @@ import {
17 ScopeId,
18 } from "./HIR";
19 import { BlockTerminal, Visitor, visitTree } from "./HIRTreeVisitor";
20 -import { eachInstructionOperand } from "./visitors";
20 +import {
21 + eachInstructionOperand,
22 + eachInstructionValueOperand,
23 +} from "./visitors";
24
25 /**
26 * This is a second (final) stage of constructing reactive scopes. Prior to this pass,
@@ -249,13 +252,28 @@ class MergeOverlappingReactiveScopesVisitor
252 enterBlock(): void {
253 this.scopes.push(new BlockScope());
254 }
252 - visitValue(value: InstructionValue): void {}
253 - visitInstruction(instruction: Instruction, value: void): void {
254 - const scope = getInstructionScope(instruction);
255 - if (scope !== null && instruction.id < scope.range.end) {
256 - this.visitScope(scope);
255 + visitValue(value: InstructionValue, id: InstructionId): void {
256 + this.visitId(id);
257 + for (const operand of eachInstructionValueOperand(value)) {
258 + if (
259 + operand.identifier.scope !== null &&
260 + id >= operand.identifier.scope.range.start &&
261 + id < operand.identifier.scope.range.end
262 + ) {
263 + this.visitScope(operand.identifier.scope);
264 + }
265 }
266 + }
267 + visitInstruction(instruction: Instruction, value: void): void {
268 this.visitId(instruction.id);
269 + if (
270 + instruction.lvalue !== null &&
271 + instruction.lvalue.place.identifier.scope !== null &&
272 + instruction.id >= instruction.lvalue.place.identifier.scope.range.start &&
273 + instruction.id < instruction.lvalue.place.identifier.scope.range.end
274 + ) {
275 + this.visitScope(instruction.lvalue.place.identifier.scope);
276 + }
277 }
278 visitTerminalId(id: InstructionId): void {
279 this.visitId(id);
compiler/forget/src/HIR/visitors.ts
+6 -1
@@ -10,13 +10,18 @@ import {
10 BasicBlock,
11 BlockId,
12 Instruction,
13 + InstructionValue,
14 makeInstructionId,
15 Place,
16 Terminal,
17 } from "./HIR";
18
19 export function* eachInstructionOperand(instr: Instruction): Iterable<Place> {
19 - const instrValue = instr.value;
20 + yield* eachInstructionValueOperand(instr.value);
21 +}
22 +export function* eachInstructionValueOperand(
23 + instrValue: InstructionValue
24 +): Iterable<Place> {
25 switch (instrValue.kind) {
26 case "NewExpression":
27 case "CallExpression": {
compiler/forget/src/__tests__/fixtures/hir/extend-scopes-if.expect.md
+4 -4
@@ -33,8 +33,8 @@ bb4:
33 [4] If (read c$9) then:bb6 else:bb1
34 bb6:
35 predecessor blocks: bb4
36 - [5] Const mutate $11_@0[1:8] = 0
37 - [6] Call mutate x$10_@0.push(read $11_@0)
36 + [5] Const mutate $11_@1 = 0
37 + [6] Call mutate x$10_@0.push(read $11_@1)
38 [7] Goto bb1
39 bb1:
40 predecessor blocks: bb6 bb4 bb2 bb0
@@ -67,8 +67,8 @@ flowchart TB
67 end
68 subgraph bb6
69 bb6_instrs["
70 - [5] Const mutate $11_@0[1:8] = 0
71 - [6] Call mutate x$10_@0.push(read $11_@0)
70 + [5] Const mutate $11_@1 = 0
71 + [6] Call mutate x$10_@0.push(read $11_@1)
72 "]
73 bb6_instrs --> bb6_terminal(["Goto"])
74 end
compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-interleaved-by-terminal.expect.md new
+72
@@ -0,0 +1,72 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(a, b, c) {
6 + const x = [];
7 + const y = [];
8 +
9 + if (x) {
10 + }
11 +
12 + y.push(a);
13 + x.push(b);
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```
21 +bb0:
22 + [1] Const mutate x$9_@0[1:6] = Array []
23 + [2] Const mutate y$10_@0[1:6] = Array []
24 + [3] If (read x$9_@0) then:bb1 else:bb1
25 +bb1:
26 + predecessor blocks: bb0
27 + [4] Call mutate y$10_@0.push(read a$6)
28 + [5] Call mutate x$9_@0.push(read b$7)
29 + [6] Return
30 +```
31 +
32 +### CFG
33 +
34 +```mermaid
35 +flowchart TB
36 + %% Basic Blocks
37 + subgraph bb0
38 + bb0_instrs["
39 + [1] Const mutate x$9_@0[1:6] = Array []
40 + [2] Const mutate y$10_@0[1:6] = Array []
41 + "]
42 + bb0_instrs --> bb0_terminal(["If (read x$9_@0)"])
43 + end
44 + subgraph bb1
45 + bb1_instrs["
46 + [4] Call mutate y$10_@0.push(read a$6)
47 + [5] Call mutate x$9_@0.push(read b$7)
48 + "]
49 + bb1_instrs --> bb1_terminal(["Return"])
50 + end
51 +
52 + %% Jumps
53 + bb0_terminal -- "then" --> bb1
54 + bb0_terminal -- "else" --> bb1
55 +
56 +```
57 +
58 +## Code
59 +
60 +```javascript
61 +function foo$0(a$1, b$2, c$3) {
62 + const x$4 = [];
63 + const y$5 = [];
64 + bb1: if (x$4) {
65 + }
66 +
67 + y$5.push(a$1);
68 + x$4.push(b$2);
69 +}
70 +
71 +```
72 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-interleaved-by-terminal.js new
+10
@@ -0,0 +1,10 @@
1 +function foo(a, b, c) {
2 + const x = [];
3 + const y = [];
4 +
5 + if (x) {
6 + }
7 +
8 + y.push(a);
9 + x.push(b);
10 +}
compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md
+4 -4
@@ -34,8 +34,8 @@ bb4:
34 bb3:
35 predecessor blocks: bb4 bb2
36 [7] Const mutate $13_@2 = "div"
37 - [8] Const mutate $15_@0[1:11] = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
38 - [9] Call mutate x$11_@0.push(read $15_@0)
37 + [8] Const mutate $15_@3 = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
38 + [9] Call mutate x$11_@0.push(read $15_@3)
39 [10] Goto bb1
40 bb1:
41 predecessor blocks: bb3 bb0
@@ -68,8 +68,8 @@ flowchart TB
68 subgraph bb3
69 bb3_instrs["
70 [7] Const mutate $13_@2 = 'div'
71 - [8] Const mutate $15_@0[1:11] = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
72 - [9] Call mutate x$11_@0.push(read $15_@0)
71 + [8] Const mutate $15_@3 = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
72 + [9] Call mutate x$11_@0.push(read $15_@3)
73 "]
74 bb3_instrs --> bb3_terminal(["Goto"])
75 end
compiler/forget/src/__tests__/fixtures/hir/ssa-shadowing.expect.md
+7 -7
@@ -47,7 +47,7 @@ function log$0() {}
47
48 ```
49 bb0:
50 - [1] Let mutate str$6_@2[0:9] = ""
50 + [1] Let mutate str$6_@0[1:8] = ""
51 [2] If (read cond$5) then:bb2 else:bb3
52 bb2:
53 predecessor blocks: bb0
@@ -56,12 +56,12 @@ bb2:
56 [5] Goto bb1
57 bb3:
58 predecessor blocks: bb0
59 - [6] Reassign mutate str$8_@2[0:9] = "fallthrough test"
59 + [6] Reassign mutate str$8_@0[1:8] = "fallthrough test"
60 [7] Goto bb1
61 bb1:
62 predecessor blocks: bb2 bb3
63 - str$10_@2[0:9]: phi(bb2: str$6_@2, bb3: str$8_@2)
64 - [8] Call mutate log$4_@2(read str$10_@2)
63 + str$10_@0[1:8]: phi(bb2: str$6_@0, bb3: str$8_@0)
64 + [8] Call mutate log$4_@2(read str$10_@0)
65 [9] Return
66 ```
67
@@ -72,7 +72,7 @@ flowchart TB
72 %% Basic Blocks
73 subgraph bb0
74 bb0_instrs["
75 - [1] Let mutate str$6_@2[0:9] = ''
75 + [1] Let mutate str$6_@0[1:8] = ''
76 "]
77 bb0_instrs --> bb0_terminal(["If (read cond$5)"])
78 end
@@ -85,13 +85,13 @@ flowchart TB
85 end
86 subgraph bb3
87 bb3_instrs["
88 - [6] Reassign mutate str$8_@2[0:9] = 'fallthrough test'
88 + [6] Reassign mutate str$8_@0[1:8] = 'fallthrough test'
89 "]
90 bb3_instrs --> bb3_terminal(["Goto"])
91 end
92 subgraph bb1
93 bb1_instrs["
94 - [8] Call mutate log$4_@2(read str$10_@2)
94 + [8] Call mutate log$4_@2(read str$10_@0)
95 "]
96 bb1_instrs --> bb1_terminal(["Return"])
97 end
compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md
+13 -13
@@ -39,23 +39,23 @@ bb0:
39 Default: bb2
40 bb5:
41 predecessor blocks: bb0
42 - [7] Const mutate $15_@6[7:17] = 1
43 - [8] Reassign mutate x$16_@6[7:17] = Binary read x$10_@0 + read $15_@6
42 + [7] Const mutate $15_@5 = 1
43 + [8] Reassign mutate x$16_@6[8:17] = Binary read x$10_@0 + read $15_@5
44 [9] Goto bb1
45 bb3:
46 predecessor blocks: bb0
47 - [10] Const mutate $17_@6[7:17] = 2
48 - [11] Reassign mutate x$18_@6[7:17] = Binary read x$10_@0 + read $17_@6
47 + [10] Const mutate $17_@7 = 2
48 + [11] Reassign mutate x$18_@6[8:17] = Binary read x$10_@0 + read $17_@7
49 [12] Goto bb1
50 bb2:
51 predecessor blocks: bb0
52 [13] Const mutate $19_@8 = 3
53 - [14] Reassign mutate x$20_@6[7:17] = Binary read x$10_@0 + read $19_@8
53 + [14] Reassign mutate x$20_@6[8:17] = Binary read x$10_@0 + read $19_@8
54 [15] Goto bb1
55 bb1:
56 predecessor blocks: bb5 bb3 bb2
57 - x$21_@6[7:17]: phi(bb5: x$16_@6, bb3: x$18_@6, bb2: x$20_@6)
58 - [16] Let mutate y$22_@6[7:17] = read x$21_@6
57 + x$21_@6[8:17]: phi(bb5: x$16_@6, bb3: x$18_@6, bb2: x$20_@6)
58 + [16] Let mutate y$22_@6[8:17] = read x$21_@6
59 [17] Return
60 ```
61
@@ -76,28 +76,28 @@ flowchart TB
76 end
77 subgraph bb5
78 bb5_instrs["
79 - [7] Const mutate $15_@6[7:17] = 1
80 - [8] Reassign mutate x$16_@6[7:17] = Binary read x$10_@0 + read $15_@6
79 + [7] Const mutate $15_@5 = 1
80 + [8] Reassign mutate x$16_@6[8:17] = Binary read x$10_@0 + read $15_@5
81 "]
82 bb5_instrs --> bb5_terminal(["Goto"])
83 end
84 subgraph bb3
85 bb3_instrs["
86 - [10] Const mutate $17_@6[7:17] = 2
87 - [11] Reassign mutate x$18_@6[7:17] = Binary read x$10_@0 + read $17_@6
86 + [10] Const mutate $17_@7 = 2
87 + [11] Reassign mutate x$18_@6[8:17] = Binary read x$10_@0 + read $17_@7
88 "]
89 bb3_instrs --> bb3_terminal(["Goto"])
90 end
91 subgraph bb2
92 bb2_instrs["
93 [13] Const mutate $19_@8 = 3
94 - [14] Reassign mutate x$20_@6[7:17] = Binary read x$10_@0 + read $19_@8
94 + [14] Reassign mutate x$20_@6[8:17] = Binary read x$10_@0 + read $19_@8
95 "]
96 bb2_instrs --> bb2_terminal(["Goto"])
97 end
98 subgraph bb1
99 bb1_instrs["
100 - [16] Let mutate y$22_@6[7:17] = read x$21_@6
100 + [16] Let mutate y$22_@6[8:17] = read x$21_@6
101 "]
102 bb1_instrs --> bb1_terminal(["Return"])
103 end
compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md
+4 -4
@@ -27,8 +27,8 @@ bb1:
27 [5] If (read $8_@2) then:bb3 else:bb2
28 bb3:
29 predecessor blocks: bb1
30 - [6] Const mutate $9_@0[0:9] = 1
31 - [7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@0
30 + [6] Const mutate $9_@3 = 1
31 + [7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@3
32 [8] Goto(Continue) bb1
33 bb2:
34 predecessor blocks: bb1
@@ -55,8 +55,8 @@ flowchart TB
55 end
56 subgraph bb3
57 bb3_instrs["
58 - [6] Const mutate $9_@0[0:9] = 1
59 - [7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@0
58 + [6] Const mutate $9_@3 = 1
59 + [7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@3
60 "]
61 bb3_instrs --> bb3_terminal(["Goto"])
62 end