Account for stores that can occur in object/array literals

This commit is contained in:
Joe Savona
2022-12-22 14:00:49 -08:00
parent 1fd4bad525
commit 74a0d54db2
11 changed files with 167 additions and 64 deletions
+34 -13
View File
@@ -4,9 +4,8 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import invariant from "invariant";
import DisjointSet from "../Utils/DisjointSet";
import { Effect, HIRFunction, Identifier } from "./HIR";
import { Effect, HIRFunction, Identifier, InstructionId, Place } from "./HIR";
export function inferAliasForStores(
func: HIRFunction,
@@ -18,18 +17,40 @@ export function inferAliasForStores(
if (lvalue === null || lvalue.place.effect !== Effect.Store) {
continue;
}
invariant(
value.kind === "Identifier",
"only identifiers can be aliased by stores"
);
if (
lvalue.place.identifier.mutableRange.end > instr.id ||
value.identifier.mutableRange.end > instr.id
) {
aliases.union([lvalue.place.identifier, value.identifier]);
switch (value.kind) {
case "Identifier": {
maybeAlias(aliases, lvalue.place, value, instr.id);
break;
}
case "ArrayExpression": {
for (const item of value.elements) {
maybeAlias(aliases, lvalue.place, item, instr.id);
}
break;
}
case "ObjectExpression": {
if (value.properties !== null) {
for (const [, property] of value.properties) {
maybeAlias(aliases, lvalue.place, property, instr.id);
}
}
break;
}
}
}
}
}
function maybeAlias(
aliases: DisjointSet<Identifier>,
lvalue: Place,
rvalue: Place,
id: InstructionId
): void {
if (
lvalue.identifier.mutableRange.end > id ||
rvalue.identifier.mutableRange.end > id
) {
aliases.union([lvalue.identifier, rvalue.identifier]);
}
}
@@ -516,6 +516,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
for (const instr of block.instructions) {
const instrValue = instr.value;
let effectKind: Effect | null = null;
let lvalueEffect = Effect.Mutate;
let valueKind: ValueKind;
switch (instrValue.kind) {
case "BinaryExpression": {
@@ -526,6 +527,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
case "ArrayExpression": {
valueKind = ValueKind.Mutable;
effectKind = Effect.Read;
lvalueEffect = Effect.Store;
break;
}
case "NewExpression": {
@@ -547,6 +549,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
valueKind = ValueKind.Mutable;
// Object construction captures but does not modify the key/property values
effectKind = Effect.Read;
lvalueEffect = Effect.Store;
break;
}
case "UnaryExpression": {
@@ -645,7 +648,7 @@ function inferBlock(env: Environment, block: BasicBlock) {
} else {
env.reference(instr.lvalue.place, Effect.Mutate);
}
instr.lvalue.place.effect = Effect.Mutate;
instr.lvalue.place.effect = lvalueEffect;
}
}
@@ -0,0 +1,33 @@
## Input
```javascript
function foo() {
const a = [[1]];
const first = a.at(0);
first.set(0, 2);
return a;
}
```
## Code
```javascript
function foo() {
const $ = React.useMemoCache();
let a;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
a = [[1]];
const first = a.at(0);
first.set(0, 2);
$[0] = a;
} else {
a = $[0];
}
return a;
}
```
@@ -0,0 +1,6 @@
function foo() {
const a = [[1]];
const first = a.at(0);
first.set(0, 2);
return a;
}
@@ -16,29 +16,18 @@ function g() {
```javascript
function g() {
const $ = React.useMemoCache();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = {
z: 1,
};
$[0] = t0;
} else {
t0 = $[0];
}
const c_1 = $[1] !== t0;
let x;
if (c_1) {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {
y: t0,
y: {
z: 1,
},
};
x.z.y = x.y.z + 1;
x.z.y = x.y.z * 2;
$[1] = t0;
$[2] = x;
$[0] = x;
} else {
x = $[2];
x = $[0];
}
return x;
@@ -45,32 +45,15 @@ function mutate(x, y) {}
```javascript
function Component(props) {
const $ = React.useMemoCache();
let a;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
a = {};
$[0] = a;
} else {
a = $[0];
}
const a = {};
const b = [a];
let c;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
c = {};
$[1] = c;
} else {
c = $[1];
}
const c = {};
const d = {
c: c,
};
const x = {};
x.b = b;
const y = mutate(x, d);
if (a) {
}
@@ -16,26 +16,16 @@ function foo() {
```javascript
function foo() {
const $ = React.useMemoCache();
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = [];
$[0] = x;
} else {
x = $[0];
}
const c_1 = $[1] !== x;
let y;
if (c_1) {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const x = [];
y = {
x: x,
};
y.x.push([]);
$[1] = x;
$[2] = y;
$[0] = y;
} else {
y = $[2];
y = $[0];
}
return y;
@@ -0,0 +1,33 @@
## Input
```javascript
function foo() {
const x = {};
const y = foo(x);
y.mutate();
return x;
}
```
## Code
```javascript
function foo() {
const $ = React.useMemoCache();
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {};
const y = foo(x);
y.mutate();
$[0] = x;
} else {
x = $[0];
}
return x;
}
```
@@ -0,0 +1,6 @@
function foo() {
const x = {};
const y = foo(x);
y.mutate();
return x;
}
@@ -0,0 +1,33 @@
## Input
```javascript
function Foo() {
const x = {};
const y = new Foo(x);
y.mutate();
return x;
}
```
## Code
```javascript
function Foo() {
const $ = React.useMemoCache();
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {};
const y = new Foo(x);
y.mutate();
$[0] = x;
} else {
x = $[0];
}
return x;
}
```
@@ -0,0 +1,6 @@
function Foo() {
const x = {};
const y = new Foo(x);
y.mutate();
return x;
}