[hir] Add InferMutableRange pass
Sathya Gunasekaran committed
Nov 4, 2022 at 16:39 UTC
871a171a1f6f04a473c71238a2bfa56fc3807883
26 files changed
+414
-55
compiler/forget/src/HIR/InferMutableLifetimes.ts
+123
-6
@@ -5,7 +5,9 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import { HIRFunction } from "./HIR";
8
+import { assertExhaustive } from "../Common/utils";
9
+import { Effect, HIRFunction, Instruction, Place } from "./HIR";
10
+import { printInstruction, printPlace } from "./PrintHIR";
11
12
/**
13
* For each usage of a value in the given function, determines if the usage
@@ -24,6 +26,7 @@ import { HIRFunction } from "./HIR";
26
*
27
* == Algorithm
28
*
29
+ * TODO:
30
* 1. Forward data-flow analysis to determine aliasing. Unlike InferReferenceCapability
31
* which only tracks aliasing of top-level variables (`y = x`), this analysis needs
32
* to know if a value is aliased anywhere (`y.x = x`). The forward data flow tracks
@@ -38,10 +41,9 @@ import { HIRFunction } from "./HIR";
41
* mutate(y); // can infer that y mutates v0 and v1
42
* ```
43
*
41
- * 2. Backward data-flow analysis to compute mutability liveness. Walk backwards over
42
- * the CFG and track which values are mutated in a successor. Then when visiting
43
- * preceding statements, mark any reference to a value that is known mutated as
44
- * mutable.
44
+ * DONE:
45
+ * 2. Forward data-flow analysis to compute mutability liveness. Walk forwards over
46
+ * the CFG and track which values are mutated in a successor.
47
*
48
* ```
49
* mutate(y); // mutable y => v0, v1 mutated
@@ -49,4 +51,119 @@ import { HIRFunction } from "./HIR";
51
* ...
52
* ```
53
*/
52
-function inferMutableLifetimes(fn: HIRFunction) {}
54
+
55
+function inferPlace(place: Place, instr: Instruction) {
56
+ switch (place.effect) {
57
+ case Effect.Unknown: {
58
+ throw new Error(
59
+ `Found an unkown place ${printPlace(place)} at ${printInstruction(
60
+ instr
61
+ )}!`
62
+ );
63
+ }
64
+ case Effect.Read:
65
+ case Effect.Freeze:
66
+ return;
67
+ case Effect.Mutate: {
68
+ place.identifier.mutableRange.end = instr.id;
69
+ return;
70
+ }
71
+ default:
72
+ assertExhaustive(place.effect, `Unexpected ${printPlace(place)} effect`);
73
+ }
74
+}
75
+
76
+export function inferMutableRanges(func: HIRFunction) {
77
+ for (const [_, block] of func.body.blocks) {
78
+ for (const phi of block.phis) {
79
+ phi.id.mutableRange = {
80
+ start: -1, // TODO(gsn): This is a hack, we should assign proper ids to phis.
81
+ end: -1,
82
+ };
83
+ }
84
+
85
+ for (const instr of block.instructions) {
86
+ for (const input of collectInputs(instr)) {
87
+ inferPlace(input, instr);
88
+ }
89
+
90
+ if (instr.lvalue !== null) {
91
+ if (instr.lvalue.place.memberPath === null) {
92
+ const lvalueId = instr.lvalue.place.identifier;
93
+
94
+ // lvalue start being mutable when they're initially assigned a
95
+ // value.
96
+ lvalueId.mutableRange.start = instr.id;
97
+
98
+ // Let's be optimistic and assume this lvalue is not mutable by
99
+ // default.
100
+ lvalueId.mutableRange.end = instr.id;
101
+ } else {
102
+ inferPlace(instr.lvalue.place, instr);
103
+ }
104
+ }
105
+ }
106
+ }
107
+}
108
+
109
+function* collectInputs(instr: Instruction) {
110
+ const instrValue = instr.value;
111
+ switch (instrValue.kind) {
112
+ case "NewExpression":
113
+ case "CallExpression": {
114
+ yield instrValue.callee;
115
+ for (const arg of instrValue.args) {
116
+ yield arg;
117
+ }
118
+ break;
119
+ }
120
+ case "BinaryExpression": {
121
+ yield instrValue.left;
122
+ yield instrValue.right;
123
+ break;
124
+ }
125
+ case "Identifier": {
126
+ yield instrValue;
127
+ break;
128
+ }
129
+ case "UnaryExpression": {
130
+ yield instrValue.value;
131
+ break;
132
+ }
133
+ case "JsxExpression": {
134
+ yield instrValue.tag;
135
+ for (const place of instrValue.props.values()) {
136
+ yield place;
137
+ }
138
+ if (instrValue.children) {
139
+ for (const c of instrValue.children) {
140
+ yield c;
141
+ }
142
+ }
143
+ break;
144
+ }
145
+ case "ObjectExpression": {
146
+ if (instrValue.properties !== null) {
147
+ const props = instrValue.properties;
148
+ for (const place of props.values()) {
149
+ yield place;
150
+ }
151
+ }
152
+ break;
153
+ }
154
+ case "ArrayExpression": {
155
+ for (const e of instrValue.elements) {
156
+ yield e;
157
+ }
158
+ break;
159
+ }
160
+ case "OtherStatement":
161
+ case "Primitive":
162
+ case "JSXText": {
163
+ break;
164
+ }
165
+ default: {
166
+ console.log(`unhandled instruction: ${printInstruction(instr)}`);
167
+ }
168
+ }
169
+}
compiler/forget/src/__tests__/fixtures/hir/call.expect.md
+2
-2
@@ -34,8 +34,8 @@ function foo$0() {
34
35
```
36
bb0:
37
- [1] Const mutate a$10 = Array []
38
- [2] Const mutate b$11 = Object { }
37
+ [1] Const mutate a$10[1:3] = Array []
38
+ [2] Const mutate b$11[2:6] = Object { }
39
[3] Call mutate foo$4(mutate a$10, mutate b$11)
40
[4] Const mutate $12 = "div"
41
[5] Let mutate _$13 = JSX <read $12 a={freeze a$10} ></read $12>
compiler/forget/src/__tests__/fixtures/hir/component.expect.md
+3
-3
@@ -45,9 +45,9 @@ bb0:
45
bb1:
46
predecessor blocks: bb0 bb4 bb7
47
items$33: phi(bb0: items$27, bb4: items$33, bb7: items$33)
48
- item$35: phi(bb0: item$10, bb4: item$35, bb7: item$35)
49
- seen$38: phi(bb0: seen$30, bb4: seen$38, bb7: seen$38)
50
- renderedItems$46: phi(bb0: renderedItems$29, bb4: renderedItems$46, bb7: renderedItems$46)
48
+ item$35[-1:11]: phi(bb0: item$10, bb4: item$35, bb7: item$35)
49
+ seen$38[-1:11]: phi(bb0: seen$30, bb4: seen$38, bb7: seen$38)
50
+ renderedItems$46[-1:14]: phi(bb0: renderedItems$29, bb4: renderedItems$46, bb7: renderedItems$46)
51
max$48: phi(bb0: max$32, bb4: max$48, bb7: max$48)
52
If (read items$33) then:bb3 else:bb2
53
bb3:
compiler/forget/src/__tests__/fixtures/hir/conditional-break.expect.md
+5
-5
@@ -78,7 +78,7 @@ function Component(props) {
78
79
```
80
bb0:
81
- [1] Const mutate a_DEBUG$5 = Array []
81
+ [1] Const mutate a_DEBUG$5[1:4] = Array []
82
[2] Call mutate a_DEBUG$5.push(read props$4.a)
83
If (read props$4.b) then:bb2 else:bb1
84
bb2:
@@ -110,7 +110,7 @@ function Component$0(props$4) {
110
111
```
112
bb0:
113
- [1] Const mutate a$4 = Array []
113
+ [1] Const mutate a$4[1:4] = Array []
114
[2] Call mutate a$4.push(read props$3.a)
115
If (read props$3.b) then:bb2 else:bb1
116
bb2:
@@ -143,7 +143,7 @@ function Component$0(props$3) {
143
144
```
145
bb0:
146
- [1] Const mutate a$5 = Array []
146
+ [1] Const mutate a$5[1:5] = Array []
147
[2] Call mutate a$5.push(read props$4.a)
148
If (read props$4.b) then:bb2 else:bb1
149
bb2:
@@ -177,7 +177,7 @@ function Component$0(props$4) {
177
178
```
179
bb0:
180
- [1] Const mutate a$4 = Array []
180
+ [1] Const mutate a$4[1:4] = Array []
181
[2] Call mutate a$4.push(read props$3.a)
182
If (read props$3.b) then:bb2 else:bb1
183
bb2:
@@ -210,7 +210,7 @@ function Component$0(props$3) {
210
211
```
212
bb0:
213
- [1] Const mutate a$4 = Array []
213
+ [1] Const mutate a$4[1:4] = Array []
214
[2] Call mutate a$4.push(read props$3.a)
215
If (read props$3.b) then:bb1 else:bb2
216
bb2:
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md
+4
-4
@@ -67,8 +67,8 @@ function mayMutate() {}
67
68
```
69
bb0:
70
- [1] Const mutate a$7 = Array []
71
- [2] Const mutate b$8 = Array []
70
+ [1] Const mutate a$7[1:3] = Array []
71
+ [2] Const mutate b$8[2:4] = Array []
72
If (read b$8) then:bb2 else:bb1
73
bb2:
74
predecessor blocks: bb0
@@ -111,8 +111,8 @@ function Component$0(props$6) {
111
112
```
113
bb0:
114
- [1] Const mutate a$9 = Array []
115
- [2] Const mutate b$10 = Array []
114
+ [1] Const mutate a$9[1:4] = Array []
115
+ [2] Const mutate b$10[2:5] = Array []
116
[3] Const mutate $11 = Call mutate mayMutate$4(mutate b$10)
117
If (read $11) then:bb2 else:bb1
118
bb2:
compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md
+2
-2
@@ -34,8 +34,8 @@ function Foo$0() {
34
35
```
36
bb0:
37
- [1] Const mutate a$10 = Array []
38
- [2] Const mutate b$11 = Object { }
37
+ [1] Const mutate a$10[1:3] = Array []
38
+ [2] Const mutate b$11[2:6] = Object { }
39
[3] New mutate Foo$4(mutate a$10, mutate b$11)
40
[4] Const mutate $12 = "div"
41
[5] Let mutate _$13 = JSX <read $12 a={freeze a$10} ></read $12>
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md
+2
-2
@@ -97,8 +97,8 @@ function Foo$0() {
97
98
```
99
bb0:
100
- [1] Const mutate a$9 = Call mutate compute$3(read props$8.a)
101
- [2] Const mutate b$10 = Call mutate compute$3(read props$8.b)
100
+ [1] Const mutate a$9[1:3] = Call mutate compute$3(read props$8.a)
101
+ [2] Const mutate b$10[2:4] = Call mutate compute$3(read props$8.b)
102
If (read props$8.c) then:bb2 else:bb1
103
bb2:
104
predecessor blocks: bb0
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md
+2
-2
@@ -76,8 +76,8 @@ function Foo$0() {
76
77
```
78
bb0:
79
- [1] Const mutate a$9 = Call mutate compute$3(read props$8.a)
80
- [2] Const mutate b$10 = Call mutate compute$3(read props$8.b)
79
+ [1] Const mutate a$9[1:3] = Call mutate compute$3(read props$8.a)
80
+ [2] Const mutate b$10[2:3] = Call mutate compute$3(read props$8.b)
81
If (read props$8.c) then:bb2 else:bb1
82
bb2:
83
predecessor blocks: bb0
compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md
+2
-2
@@ -28,8 +28,8 @@ function Foo() {}
28
29
```
30
bb0:
31
- [1] Const mutate a$9 = Call mutate compute$3(read props$8.a)
32
- [2] Const mutate b$10 = Call mutate compute$3(read props$8.b)
31
+ [1] Const mutate a$9[1:3] = Call mutate compute$3(read props$8.a)
32
+ [2] Const mutate b$10[2:3] = Call mutate compute$3(read props$8.b)
33
[3] Call mutate foo$5(mutate a$9, mutate b$10)
34
[4] Const mutate $11 = JSX <read Foo$6 a={freeze a$9} b={freeze b$10} ></read Foo$6>
35
Return read $11
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+5
-5
@@ -84,15 +84,15 @@ bb1:
84
b$20: phi(bb0: b$14, bb3: b$23)
85
c$22: phi(bb0: c$15, bb3: c$25)
86
d$24: phi(bb0: d$16, bb3: d$26)
87
- mutate$27: phi(bb0: mutate$7, bb3: mutate$27)
88
- cond$28: phi(bb0: cond$8, bb3: cond$28)
87
+ mutate$27[-1:14]: phi(bb0: mutate$7, bb3: mutate$27)
88
+ cond$28[-1:12]: phi(bb0: cond$8, bb3: cond$28)
89
[5] Const mutate $17 = true
90
If (read $17) then:bb3 else:bb2
91
bb3:
92
predecessor blocks: bb1
93
[6] Let mutate z$19 = read a$18
94
- [7] Reassign mutate a$21 = read b$20
95
- [8] Reassign mutate b$23 = read c$22
94
+ [7] Reassign mutate a$21[7:12] = read b$20
95
+ [8] Reassign mutate b$23[8:11] = read c$22
96
[9] Reassign mutate c$25 = read d$24
97
[10] Reassign mutate d$26 = read z$19
98
[11] Call mutate mutate$27(mutate a$21, mutate b$23)
@@ -103,7 +103,7 @@ bb2:
103
a$30: phi(bb1: a$18, bb3: a$21)
104
b$31: phi(bb1: b$20, bb3: b$23)
105
c$32: phi(bb1: c$22, bb3: c$25)
106
- d$33: phi(bb1: d$24, bb3: d$26)
106
+ d$33[-1:14]: phi(bb1: d$24, bb3: d$26)
107
If (read a$30) then:bb7 else:bb7
108
bb7:
109
predecessor blocks: bb2
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md
+3
-3
@@ -57,9 +57,9 @@ bb0:
57
[1] Const mutate a$11 = Object { }
58
[2] Const mutate b$12 = Array [read a$11]
59
[3] Const mutate c$13 = Object { }
60
- [4] Const mutate d$14 = Object { c: read c$13 }
61
- [5] Const mutate x$15 = Object { }
62
- [6] Reassign mutate x$15.b = read b$12
60
+ [4] Const mutate d$14[4:7] = Object { c: read c$13 }
61
+ [5] Const mutate x$15[5:9] = Object { }
62
+ [6] Reassign mutate x$15.b[5:9] = read b$12
63
[7] Const mutate y$16 = Call mutate mutate$8(mutate x$15, mutate d$14)
64
If (read a$11) then:bb1 else:bb1
65
bb1:
compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md
new
+122
@@ -0,0 +1,122 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function mutate() {}
6
+function cond() {}
7
+
8
+function Component(props) {
9
+ let a = {};
10
+ let b = {};
11
+ let c = {};
12
+ let d = {};
13
+ while (true) {
14
+ mutate(a, b);
15
+ if (cond(a)) {
16
+ break;
17
+ }
18
+ }
19
+
20
+ // all of these tests are seemingly readonly, since the values are never directly
21
+ // mutated again. but they are all aliased by `d`, which is later modified, and
22
+ // these are therefore mutable references:
23
+ if (a) {
24
+ }
25
+ if (b) {
26
+ }
27
+ if (c) {
28
+ }
29
+ if (d) {
30
+ }
31
+
32
+ mutate(d, null);
33
+}
34
+
35
+```
36
+
37
+## HIR
38
+
39
+```
40
+bb0:
41
+ Return
42
+```
43
+
44
+## Code
45
+
46
+```javascript
47
+function mutate$0() {
48
+ return;
49
+}
50
+
51
+```
52
+## HIR
53
+
54
+```
55
+bb0:
56
+ Return
57
+```
58
+
59
+## Code
60
+
61
+```javascript
62
+function cond$0() {
63
+ return;
64
+}
65
+
66
+```
67
+## HIR
68
+
69
+```
70
+bb0:
71
+ [1] Let mutate a$12 = Object { }
72
+ [2] Let mutate b$13 = Object { }
73
+ [3] Let mutate c$14 = Object { }
74
+ [4] Let mutate d$15 = Object { }
75
+ Goto bb1
76
+bb1:
77
+ predecessor blocks: bb0 bb3
78
+ mutate$17[-1:9]: phi(bb0: mutate$6, bb3: mutate$17)
79
+ a$18[-1:7]: phi(bb0: a$12, bb3: a$18)
80
+ b$19[-1:6]: phi(bb0: b$13, bb3: b$19)
81
+ cond$20[-1:7]: phi(bb0: cond$7, bb3: cond$20)
82
+ c$25: phi(bb0: c$14, bb3: c$25)
83
+ d$27[-1:9]: phi(bb0: d$15, bb3: d$27)
84
+ [5] Const mutate $16 = true
85
+ If (read $16) then:bb3 else:bb2
86
+bb3:
87
+ predecessor blocks: bb1
88
+ [6] Call mutate mutate$17(mutate a$18, mutate b$19)
89
+ [7] Const mutate $21 = Call mutate cond$20(mutate a$18)
90
+ If (read $21) then:bb2 else:bb1
91
+bb2:
92
+ predecessor blocks: bb1 bb3
93
+ If (read a$18) then:bb7 else:bb7
94
+bb7:
95
+ predecessor blocks: bb2
96
+ If (read b$19) then:bb9 else:bb9
97
+bb9:
98
+ predecessor blocks: bb7
99
+ If (read c$25) then:bb11 else:bb11
100
+bb11:
101
+ predecessor blocks: bb9
102
+ If (read d$27) then:bb13 else:bb13
103
+bb13:
104
+ predecessor blocks: bb11
105
+ [8] Const mutate $28 = null
106
+ [9] Call mutate mutate$17(mutate d$27, read $28)
107
+ Return
108
+```
109
+
110
+## Code
111
+
112
+```javascript
113
+function Component$0(props$11) {
114
+ let a$12 = {};
115
+ let b$13 = {};
116
+ let c$14 = {};
117
+ let d$15 = {};
118
+ ("<<TODO: handle complex control flow in codegen>>");
119
+}
120
+
121
+```
122
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.js
new
+29
@@ -0,0 +1,29 @@
1
+function mutate() {}
2
+function cond() {}
3
+
4
+function Component(props) {
5
+ let a = {};
6
+ let b = {};
7
+ let c = {};
8
+ let d = {};
9
+ while (true) {
10
+ mutate(a, b);
11
+ if (cond(a)) {
12
+ break;
13
+ }
14
+ }
15
+
16
+ // all of these tests are seemingly readonly, since the values are never directly
17
+ // mutated again. but they are all aliased by `d`, which is later modified, and
18
+ // these are therefore mutable references:
19
+ if (a) {
20
+ }
21
+ if (b) {
22
+ }
23
+ if (c) {
24
+ }
25
+ if (d) {
26
+ }
27
+
28
+ mutate(d, null);
29
+}
compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md
+2
-2
@@ -17,9 +17,9 @@ function Component(props) {
17
18
```
19
bb0:
20
- [1] Const mutate x$7 = Object { }
20
+ [1] Const mutate x$7[1:5] = Object { }
21
[2] Const mutate y$8 = Array []
22
- [3] Reassign mutate x$7.y = read y$8
22
+ [3] Reassign mutate x$7.y[1:5] = read y$8
23
[4] Const mutate child$9 = JSX <read Component$0 data={freeze y$8} ></read Component$0>
24
[5] Call mutate x$7.y.push(read props$6.p0)
25
[6] Const mutate $10 = JSX <read Component$0 data={freeze x$7} >{read child$9}</read Component$0>
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md
+1
-1
@@ -23,7 +23,7 @@ function Component(props) {
23
24
```
25
bb0:
26
- [1] Let mutate x$7 = Array []
26
+ [1] Let mutate x$7[1:2] = Array []
27
[2] Call mutate x$7.push(read props$6.p0)
28
[3] Let mutate y$8 = read x$7
29
If (read props$6.p1) then:bb2 else:bb1
compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md
+2
-2
@@ -21,9 +21,9 @@ function Component(props) {
21
22
```
23
bb0:
24
- [1] Let mutate x$7 = Array []
24
+ [1] Let mutate x$7[1:2] = Array []
25
[2] Call mutate x$7.push(read props$6.p0)
26
- [3] Let mutate y$8 = read x$7
26
+ [3] Let mutate y$8[3:6] = read x$7
27
[4] Reassign mutate x$9 = Array []
28
[5] Let mutate _$10 = JSX <read Component$0 x={freeze x$9} ></read Component$0>
29
[6] Call mutate y$8.push(read props$6.p1)
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md
new
+76
@@ -0,0 +1,76 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @Pass runMutableRangeAnalysis
6
+function foo() {}
7
+
8
+function Component(props) {
9
+ const a = [];
10
+ const b = {};
11
+ foo(a, b);
12
+ if (foo()) {
13
+ let _ = <div a={a} />;
14
+ }
15
+ foo(a, b);
16
+ return <div a={a} b={b} />;
17
+}
18
+
19
+```
20
+
21
+## HIR
22
+
23
+```
24
+bb0:
25
+ Return
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+function foo$0() {
32
+ return;
33
+}
34
+
35
+```
36
+## HIR
37
+
38
+```
39
+bb0:
40
+ [1] Const mutate a$11[1:3] = Array []
41
+ [2] Const mutate b$12[2:7] = Object { }
42
+ [3] Call mutate foo$4(mutate a$11, mutate b$12)
43
+ [4] Const mutate $13 = Call mutate foo$4()
44
+ If (read $13) then:bb2 else:bb1
45
+bb2:
46
+ predecessor blocks: bb0
47
+ [5] Const mutate $14 = "div"
48
+ [6] Let mutate _$15 = JSX <read $14 a={freeze a$11} ></read $14>
49
+ Goto bb1
50
+bb1:
51
+ predecessor blocks: bb0 bb2
52
+ [7] Call mutate foo$4(read a$11, mutate b$12)
53
+ [8] Const mutate $19 = "div"
54
+ [9] Const mutate $20 = JSX <read $19 a={freeze a$11} b={freeze b$12} ></read $19>
55
+ Return read $20
56
+```
57
+
58
+## Code
59
+
60
+```javascript
61
+function Component$0(props$10) {
62
+ const a$11 = [];
63
+ const b$12 = {};
64
+ foo$4(a$11, b$12);
65
+ if (foo$4()) {
66
+ let _$15 = <div a={a$11}></div>;
67
+
68
+ ("<<TODO: handle complex control flow in codegen>>");
69
+ }
70
+
71
+ foo$4(a$11, b$12);
72
+ return <div a={a$11} b={b$12}></div>;
73
+}
74
+
75
+```
76
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.js
new
+13
@@ -0,0 +1,13 @@
1
+// @Pass runMutableRangeAnalysis
2
+function foo() {}
3
+
4
+function Component(props) {
5
+ const a = [];
6
+ const b = {};
7
+ foo(a, b);
8
+ if (foo()) {
9
+ let _ = <div a={a} />;
10
+ }
11
+ foo(a, b);
12
+ return <div a={a} b={b} />;
13
+}
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md
+5
-5
@@ -9,7 +9,7 @@ function Component(props) {
9
const b = {};
10
foo(a, b);
11
let _ = <div a={a} />;
12
- foo(b);
12
+ foo(a, b);
13
return <div a={a} b={b} />;
14
}
15
@@ -34,12 +34,12 @@ function foo$0() {
34
35
```
36
bb0:
37
- [1] Const mutate a$10 = Array []
38
- [2] Const mutate b$11 = Object { }
37
+ [1] Const mutate a$10[1:3] = Array []
38
+ [2] Const mutate b$11[2:6] = Object { }
39
[3] Call mutate foo$4(mutate a$10, mutate b$11)
40
[4] Const mutate $12 = "div"
41
[5] Let mutate _$13 = JSX <read $12 a={freeze a$10} ></read $12>
42
- [6] Call mutate foo$4(mutate b$11)
42
+ [6] Call mutate foo$4(read a$10, mutate b$11)
43
[7] Const mutate $14 = "div"
44
[8] Const mutate $15 = JSX <read $14 a={read a$10} b={freeze b$11} ></read $14>
45
Return read $15
@@ -54,7 +54,7 @@ function Component$0(props$9) {
54
foo$4(a$10, b$11);
55
let _$13 = <div a={a$10}></div>;
56
57
- foo$4(b$11);
57
+ foo$4(a$10, b$11);
58
return <div a={a$10} b={b$11}></div>;
59
}
60
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.js
+1
-1
@@ -5,6 +5,6 @@ function Component(props) {
5
const b = {};
6
foo(a, b);
7
let _ = <div a={a} />;
8
- foo(b);
8
+ foo(a, b);
9
return <div a={a} b={b} />;
10
}
compiler/forget/src/__tests__/fixtures/hir/ssa-newexpression.expect.md
+2
-2
@@ -32,8 +32,8 @@ function Foo$0() {
32
33
```
34
bb0:
35
- [1] Const mutate a$7 = Array []
36
- [2] Const mutate b$8 = Object { }
35
+ [1] Const mutate a$7[1:3] = Array []
36
+ [2] Const mutate b$8[2:3] = Object { }
37
[3] Let mutate c$9 = New mutate Foo$5(mutate a$7, mutate b$8)
38
Return freeze c$9
39
```
compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md
+2
-2
@@ -16,8 +16,8 @@ function foo() {
16
```
17
bb0:
18
[1] Const mutate x$4 = Array []
19
- [2] Const mutate y$5 = Object { x: read x$4 }
20
- [3] Const mutate $6 = Array []
19
+ [2] Const mutate y$5[2:4] = Object { x: read x$4 }
20
+ [3] Const mutate $6[3:4] = Array []
21
[4] Call mutate y$5.x.push(mutate $6)
22
Return freeze y$5
23
```
compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md
+2
-2
@@ -16,8 +16,8 @@ function foo() {
16
```
17
bb0:
18
[1] Const mutate x$3 = Array []
19
- [2] Const mutate y$4 = Object { }
20
- [3] Reassign mutate y$4.x = read x$3
19
+ [2] Const mutate y$4[2:3] = Object { }
20
+ [3] Reassign mutate y$4.x[2:3] = read x$3
21
Return freeze y$4
22
```
23
compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md
+1
-1
@@ -32,7 +32,7 @@ function Component(props) {
32
33
```
34
bb0:
35
- [1] Let mutate x$10 = Array []
35
+ [1] Let mutate x$10[1:6] = Array []
36
[2] Let mutate y$11 = undefined
37
[3] Const mutate $12 = false
38
[4] Const mutate $13 = true
compiler/forget/src/__tests__/fixtures/hir/switch.expect.md
+1
-1
@@ -28,7 +28,7 @@ function Component(props) {
28
29
```
30
bb0:
31
- [1] Let mutate x$9 = Array []
31
+ [1] Let mutate x$9[1:6] = Array []
32
[2] Let mutate y$10 = undefined
33
[3] Const mutate $11 = false
34
[4] Const mutate $12 = true
compiler/forget/src/__tests__/hir-test.ts
+2
@@ -18,6 +18,7 @@ import { lower } from "../HIR/BuildHIR";
18
import codegen from "../HIR/Codegen";
19
import { HIRFunction } from "../HIR/HIR";
20
import { Environment } from "../HIR/HIRBuilder";
21
+import { inferMutableRanges } from "../HIR/InferMutableLifetimes";
22
import inferReferenceEffects from "../HIR/InferReferenceEffects";
23
import printHIR from "../HIR/PrintHIR";
24
import buildSSA from "../HIR/SSAify";
@@ -64,6 +65,7 @@ describe("React Forget (HIR version)", () => {
65
const ir: HIRFunction = lower(nodePath, env);
66
buildSSA(ir, env);
67
inferReferenceEffects(ir);
68
+ inferMutableRanges(ir);
69
// const lifetimeGraph = buildDefUseGraph(ir);
70
const textHIR = printHIR(ir.body);
71
// const textLifetimeGraph = printGraph(lifetimeGraph);