[effects] Allow capture-store effects in rvals

--- 

Some typed functions need to annotate callees or arguments as `Effect.Store`. 
This PR modifies alias analysis (`InferAliasForStores`) to account for this
This commit is contained in:
Mofei Zhang
2023-05-10 21:55:56 -04:00
parent f3d4d16918
commit 5e80821aa2
7 changed files with 147 additions and 2 deletions
+1 -1
View File
@@ -159,7 +159,7 @@ addObject(BUILTIN_SHAPES, BuiltInArrayId, [
positionalParams: [],
restParam: Effect.Capture,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Mutate,
calleeEffect: Effect.Store,
}),
],
// TODO: rest of Array properties
@@ -25,7 +25,15 @@ export function inferAliasForStores(
for (const [_, block] of func.body.blocks) {
for (const instr of block.instructions) {
const { value, lvalue } = instr;
if (lvalue.effect !== Effect.Store) {
const isStore =
lvalue.effect === Effect.Store ||
// Some typed functions annotate callees or arguments
// as Effect.Store.
![...eachInstructionValueOperand(value)].every(
(operand) => operand.effect !== Effect.Store
);
if (!isStore) {
continue;
}
for (const operand of eachInstructionLValue(instr)) {
@@ -323,6 +323,20 @@ class InferenceState {
break;
}
case Effect.Store: {
if (
valueKind !== ValueKind.Mutable &&
valueKind !== ValueKind.Context &&
shouldError
) {
CompilerError.invalidInput(
`InferReferenceEffects: inferred mutation of known immutable value`,
place.loc,
`Found mutation of ${printIdentifier(place.identifier)}${printType(
place.identifier.type
)} (${valueKind})`
);
}
// TODO(gsn): This should be bailout once we add bailout infra.
//
// invariant(
@@ -0,0 +1,51 @@
## Input
```javascript
function Component() {
// a's mutable range should be the same as x's mutable range,
// since a is captured into x (which gets mutated later)
let a = someObj();
let x = [];
x.push(a);
mutate(x);
return [x, a];
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component() {
const $ = useMemoCache(3);
let x;
let a;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
a = someObj();
x = [];
x.push(a);
mutate(x);
$[0] = x;
$[1] = a;
} else {
x = $[0];
a = $[1];
}
let t0;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t0 = [x, a];
$[2] = t0;
} else {
t0 = $[2];
}
return t0;
}
```
@@ -0,0 +1,11 @@
function Component() {
// a's mutable range should be the same as x's mutable range,
// since a is captured into x (which gets mutated later)
let a = someObj();
let x = [];
x.push(a);
mutate(x);
return [x, a];
}
@@ -0,0 +1,51 @@
## Input
```javascript
function Component() {
// a's mutable range should be limited
// the following line
let a = someObj();
let x = [];
x.push(a);
return [x, a];
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component() {
const $ = useMemoCache(3);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = someObj();
$[0] = t0;
} else {
t0 = $[0];
}
const a = t0;
let x;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
x = [];
x.push(a);
$[1] = x;
} else {
x = $[1];
}
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [x, a];
$[2] = t1;
} else {
t1 = $[2];
}
return t1;
}
```
@@ -0,0 +1,10 @@
function Component() {
// a's mutable range should be limited
// the following line
let a = someObj();
let x = [];
x.push(a);
return [x, a];
}