Account for stores that can occur in object/array literals
Joe Savona committed
Dec 22, 2022 at 14:00 UTC
74a0d54db2e96ebcedfb5e39e41cb2bbd3acacef
11 files changed
+167
-64
compiler/forget/src/HIR/InferAliasForStores.ts
+34
-13
@@ -4,9 +4,8 @@
4
* This source code is licensed under the MIT license found in the
5
* LICENSE file in the root directory of this source tree.
6
*/
7
-import invariant from "invariant";
7
import DisjointSet from "../Utils/DisjointSet";
9
-import { Effect, HIRFunction, Identifier } from "./HIR";
8
+import { Effect, HIRFunction, Identifier, InstructionId, Place } from "./HIR";
9
10
export function inferAliasForStores(
11
func: HIRFunction,
@@ -18,18 +17,40 @@ export function inferAliasForStores(
17
if (lvalue === null || lvalue.place.effect !== Effect.Store) {
18
continue;
19
}
21
-
22
- invariant(
23
- value.kind === "Identifier",
24
- "only identifiers can be aliased by stores"
25
- );
26
-
27
- if (
28
- lvalue.place.identifier.mutableRange.end > instr.id ||
29
- value.identifier.mutableRange.end > instr.id
30
- ) {
31
- aliases.union([lvalue.place.identifier, value.identifier]);
20
+ switch (value.kind) {
21
+ case "Identifier": {
22
+ maybeAlias(aliases, lvalue.place, value, instr.id);
23
+ break;
24
+ }
25
+ case "ArrayExpression": {
26
+ for (const item of value.elements) {
27
+ maybeAlias(aliases, lvalue.place, item, instr.id);
28
+ }
29
+ break;
30
+ }
31
+ case "ObjectExpression": {
32
+ if (value.properties !== null) {
33
+ for (const [, property] of value.properties) {
34
+ maybeAlias(aliases, lvalue.place, property, instr.id);
35
+ }
36
+ }
37
+ break;
38
+ }
39
}
40
}
41
}
42
}
43
+
44
+function maybeAlias(
45
+ aliases: DisjointSet<Identifier>,
46
+ lvalue: Place,
47
+ rvalue: Place,
48
+ id: InstructionId
49
+): void {
50
+ if (
51
+ lvalue.identifier.mutableRange.end > id ||
52
+ rvalue.identifier.mutableRange.end > id
53
+ ) {
54
+ aliases.union([lvalue.identifier, rvalue.identifier]);
55
+ }
56
+}
compiler/forget/src/HIR/InferReferenceEffects.ts
+4
-1
@@ -516,6 +516,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
516
for (const instr of block.instructions) {
517
const instrValue = instr.value;
518
let effectKind: Effect | null = null;
519
+ let lvalueEffect = Effect.Mutate;
520
let valueKind: ValueKind;
521
switch (instrValue.kind) {
522
case "BinaryExpression": {
@@ -526,6 +527,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
527
case "ArrayExpression": {
528
valueKind = ValueKind.Mutable;
529
effectKind = Effect.Read;
530
+ lvalueEffect = Effect.Store;
531
break;
532
}
533
case "NewExpression": {
@@ -547,6 +549,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
549
valueKind = ValueKind.Mutable;
550
// Object construction captures but does not modify the key/property values
551
effectKind = Effect.Read;
552
+ lvalueEffect = Effect.Store;
553
break;
554
}
555
case "UnaryExpression": {
@@ -645,7 +648,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
648
} else {
649
env.reference(instr.lvalue.place, Effect.Mutate);
650
}
648
- instr.lvalue.place.effect = Effect.Mutate;
651
+ instr.lvalue.place.effect = lvalueEffect;
652
}
653
}
654
compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.expect.md
new
+33
@@ -0,0 +1,33 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function foo() {
6
+ const a = [[1]];
7
+ const first = a.at(0);
8
+ first.set(0, 2);
9
+ return a;
10
+}
11
+
12
+```
13
+
14
+## Code
15
+
16
+```javascript
17
+function foo() {
18
+ const $ = React.useMemoCache();
19
+ let a;
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
+ a = [[1]];
22
+ const first = a.at(0);
23
+ first.set(0, 2);
24
+ $[0] = a;
25
+ } else {
26
+ a = $[0];
27
+ }
28
+
29
+ return a;
30
+}
31
+
32
+```
33
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue-array.js
new
+6
@@ -0,0 +1,6 @@
1
+function foo() {
2
+ const a = [[1]];
3
+ const first = a.at(0);
4
+ first.set(0, 2);
5
+ return a;
6
+}
compiler/forget/src/__tests__/fixtures/hir/assignment-variations-complex-lvalue.expect.md
+6
-17
@@ -16,29 +16,18 @@ function g() {
16
```javascript
17
function g() {
18
const $ = React.useMemoCache();
19
- let t0;
20
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
- t0 = {
22
- z: 1,
23
- };
24
- $[0] = t0;
25
- } else {
26
- t0 = $[0];
27
- }
28
-
29
- const c_1 = $[1] !== t0;
19
let x;
31
-
32
- if (c_1) {
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
x = {
34
- y: t0,
22
+ y: {
23
+ z: 1,
24
+ },
25
};
26
x.z.y = x.y.z + 1;
27
x.z.y = x.y.z * 2;
38
- $[1] = t0;
39
- $[2] = x;
28
+ $[0] = x;
29
} else {
41
- x = $[2];
30
+ x = $[0];
31
}
32
33
return x;
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md
+2
-19
@@ -45,32 +45,15 @@ function mutate(x, y) {}
45
46
```javascript
47
function Component(props) {
48
- const $ = React.useMemoCache();
49
- let a;
50
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
51
- a = {};
52
- $[0] = a;
53
- } else {
54
- a = $[0];
55
- }
56
-
48
+ const a = {};
49
const b = [a];
58
- let c;
59
-
60
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
61
- c = {};
62
- $[1] = c;
63
- } else {
64
- c = $[1];
65
- }
66
-
50
+ const c = {};
51
const d = {
52
c: c,
53
};
54
const x = {};
55
x.b = b;
56
const y = mutate(x, d);
73
-
57
if (a) {
58
}
59
compiler/forget/src/__tests__/fixtures/hir/ssa-property-call.expect.md
+4
-14
@@ -16,26 +16,16 @@ function foo() {
16
```javascript
17
function foo() {
18
const $ = React.useMemoCache();
19
- let x;
20
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
- x = [];
22
- $[0] = x;
23
- } else {
24
- x = $[0];
25
- }
26
-
27
- const c_1 = $[1] !== x;
19
let y;
29
-
30
- if (c_1) {
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
+ const x = [];
22
y = {
23
x: x,
24
};
25
y.x.push([]);
35
- $[1] = x;
36
- $[2] = y;
26
+ $[0] = y;
27
} else {
38
- y = $[2];
28
+ y = $[0];
29
}
30
31
return y;
compiler/forget/src/__tests__/fixtures/hir/store-via-call.expect.md
new
+33
@@ -0,0 +1,33 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function foo() {
6
+ const x = {};
7
+ const y = foo(x);
8
+ y.mutate();
9
+ return x;
10
+}
11
+
12
+```
13
+
14
+## Code
15
+
16
+```javascript
17
+function foo() {
18
+ const $ = React.useMemoCache();
19
+ let x;
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
+ x = {};
22
+ const y = foo(x);
23
+ y.mutate();
24
+ $[0] = x;
25
+ } else {
26
+ x = $[0];
27
+ }
28
+
29
+ return x;
30
+}
31
+
32
+```
33
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/store-via-call.js
new
+6
@@ -0,0 +1,6 @@
1
+function foo() {
2
+ const x = {};
3
+ const y = foo(x);
4
+ y.mutate();
5
+ return x;
6
+}
compiler/forget/src/__tests__/fixtures/hir/store-via-new.expect.md
new
+33
@@ -0,0 +1,33 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo() {
6
+ const x = {};
7
+ const y = new Foo(x);
8
+ y.mutate();
9
+ return x;
10
+}
11
+
12
+```
13
+
14
+## Code
15
+
16
+```javascript
17
+function Foo() {
18
+ const $ = React.useMemoCache();
19
+ let x;
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
+ x = {};
22
+ const y = new Foo(x);
23
+ y.mutate();
24
+ $[0] = x;
25
+ } else {
26
+ x = $[0];
27
+ }
28
+
29
+ return x;
30
+}
31
+
32
+```
33
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/store-via-new.js
new
+6
@@ -0,0 +1,6 @@
1
+function Foo() {
2
+ const x = {};
3
+ const y = new Foo(x);
4
+ y.mutate();
5
+ return x;
6
+}