[λ] Run analyseFunctions on inner func exprs

Previously we would skip out on calling analyseFunctions on inner function  
exprs so we missed out on catching aliased mutation in a different scope.
This commit is contained in:
Sathya Gunasekaran
2023-02-02 14:05:35 +00:00
parent 0522d5233b
commit aa2403e068
6 changed files with 156 additions and 48 deletions
+12 -11
View File
@@ -440,17 +440,7 @@ export type InstructionData =
| { kind: "ComputedStore"; object: Place; property: Place; value: Place }
// load `object[index]` - like PropertyLoad but with a dynamic property
| { kind: "ComputedLoad"; object: Place; property: Place }
| {
kind: "FunctionExpression";
name: string | null;
params: Array<string>;
dependencies: Array<Place>;
// TODO(gsn): Remove this mutatedDeps array and use dependencies as single
// source of truth.
mutatedDeps: Array<Place>;
loweredFunc: HIRFunction;
expr: t.ArrowFunctionExpression | t.FunctionExpression;
}
| FunctionExpression
| {
kind: "TaggedTemplateExpression";
tag: Place;
@@ -471,6 +461,17 @@ export type JsxAttribute =
| { kind: "JsxSpreadAttribute"; argument: Place }
| { kind: "JsxAttribute"; name: string; place: Place };
export type FunctionExpression = {
kind: "FunctionExpression";
name: string | null;
params: Array<string>;
dependencies: Array<Place>;
// TODO(gsn): Remove this mutatedDeps array and use dependencies as single
// source of truth.
mutatedDeps: Array<Place>;
loweredFunc: HIRFunction;
expr: t.ArrowFunctionExpression | t.FunctionExpression;
};
/**
* A place where data may be read from / written to:
* - a variable (identifier)
@@ -1,4 +1,10 @@
import { HIRFunction, Identifier, mergeConsecutiveBlocks, Place } from "../HIR";
import {
HIRFunction,
FunctionExpression,
Identifier,
mergeConsecutiveBlocks,
Place,
} from "../HIR";
import { constantPropagation } from "../Optimization";
import { eliminateRedundantPhi, enterSSA } from "../SSA";
import { inferTypes } from "../TypeInference";
@@ -30,18 +36,15 @@ function declareProperty(
properties.set(lvalue.identifier, nextDependency);
}
export default function (func: HIRFunction) {
export default function analyseFunctions(func: HIRFunction) {
const properties: Map<Identifier, Dependency> = new Map();
for (const [_, block] of func.body.blocks) {
for (const instr of block.instructions) {
switch (instr.value.kind) {
case "FunctionExpression": {
instr.value.mutatedDeps = buildMutatedDeps(
analyzeMutatedPlaces(instr.value.loweredFunc),
instr.value.dependencies,
properties
);
lower(instr.value.loweredFunc);
infer(instr.value, properties);
break;
}
case "PropertyLoad": {
@@ -57,6 +60,37 @@ export default function (func: HIRFunction) {
}
}
function lower(func: HIRFunction) {
mergeConsecutiveBlocks(func);
enterSSA(func);
eliminateRedundantPhi(func);
constantPropagation(func);
inferTypes(func);
analyseFunctions(func);
inferReferenceEffects(func);
inferMutableRanges(func);
logHIRFunction("AnalyseFunction (inner)", func);
}
function infer(
value: FunctionExpression,
properties: Map<Identifier, Dependency>
) {
const func = value.loweredFunc;
const mutations: Array<Place> = func.context.filter((dep) =>
isMutated(dep.identifier)
);
value.mutatedDeps = buildMutatedDeps(
mutations,
value.dependencies,
properties
);
}
function isMutated(id: Identifier) {
return id.mutableRange.end - id.mutableRange.start > 1;
}
function buildMutatedDeps(
mutations: Place[],
capturedDeps: Place[],
@@ -89,33 +123,3 @@ function buildMutatedDeps(
return mutatedDeps;
}
function analyzeMutatedPlaces(func: HIRFunction): Array<Place> {
mergeConsecutiveBlocks(func);
enterSSA(func);
eliminateRedundantPhi(func);
constantPropagation(func);
inferTypes(func);
inferReferenceEffects(func);
inferMutableRanges(func);
logHIRFunction("AnalyseFunction (inner)", func);
const mutations: Array<Place> = [];
for (const [_, block] of func.body.blocks) {
for (const instr of block.instructions) {
if (
instr.value.kind === "FunctionExpression" &&
instr.value.loweredFunc !== null
) {
mutations.push(...analyzeMutatedPlaces(instr.value.loweredFunc));
}
}
}
mutations.push(...func.context.filter((dep) => isMutated(dep.identifier)));
return mutations;
}
function isMutated(id: Identifier) {
return id.mutableRange.end - id.mutableRange.start > 1;
}
@@ -0,0 +1,40 @@
## Input
```javascript
function component(a) {
let z = { a };
(function () {
(function () {
z.b = 1;
})();
})();
return z;
}
```
## Code
```javascript
function component(a) {
const $ = React.useMemoCache();
const c_0 = $[0] !== a;
let z;
if (c_0) {
z = { a: a };
$[0] = a;
$[1] = z;
} else {
z = $[1];
}
(function () {
(function () {
z.b = 1;
})();
})();
return z;
}
```
@@ -0,0 +1,9 @@
function component(a) {
let z = { a };
(function () {
(function () {
z.b = 1;
})();
})();
return z;
}
@@ -0,0 +1,43 @@
## Input
```javascript
function component(a) {
let x = { a };
(function () {
let q = x;
(function () {
q.b = 1;
})();
})();
return x;
}
```
## Code
```javascript
function component(a) {
const $ = React.useMemoCache();
const c_0 = $[0] !== a;
let x;
if (c_0) {
x = { a: a };
(function () {
let q = x;
(function () {
q.b = 1;
})();
})();
$[0] = a;
$[1] = x;
} else {
x = $[1];
}
return x;
}
```
@@ -0,0 +1,11 @@
function component(a) {
let x = { a };
(function () {
let q = x;
(function () {
q.b = 1;
})();
})();
return x;
}