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