@samitouri / QOS-React-2 / commits / 871a171a1f

[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);