MutableIfOperandsAreMutable flag handles mutation via capturing

There was one missing piece to the optimization from the previous PR: Array#map 
can return an alias to the receiver in its output, which means that mutations of 
the result have to be treated as mutations of the receiver. This means we need 
to use a Capture effect on the receiver. If that doesn't get downgraded to a 
Read bc the value was immutable, we then also need to make the lvalue effect a 
Store (so that InferMutableRanges actually looks at it for aliasing).
This commit is contained in:
Joe Savona
2023-11-29 10:46:44 -08:00
parent f7d16db544
commit 75c7fdcbd0
3 changed files with 70 additions and 3 deletions
@@ -851,16 +851,19 @@ function inferBlock(
) {
/*
* None of the args are mutable or mutate their params, we can downgrade to
* treating as all reads
* treating as all reads (except that the receiver may be captured)
*/
for (const arg of instrValue.args) {
const place = arg.kind === "Identifier" ? arg : arg.place;
state.reference(place, Effect.Read);
}
state.reference(instrValue.receiver, Effect.Read);
state.reference(instrValue.receiver, Effect.Capture);
state.initialize(instrValue, signature.returnValueKind);
state.define(instr.lvalue, instrValue);
instr.lvalue.effect = Effect.ConditionallyMutate;
instr.lvalue.effect =
instrValue.receiver.effect === Effect.Capture
? Effect.Store
: Effect.ConditionallyMutate;
continue;
}
@@ -0,0 +1,50 @@
## Input
```javascript
function Component(props) {
const x = [{}];
const y = x.map((item) => {
return item;
});
y[0].flag = true;
return [x, y];
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
isComponent: false,
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const x = [{}];
const y = x.map((item) => item);
y[0].flag = true;
t0 = [x, y];
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
isComponent: false,
};
```
### Eval output
(kind: ok) [[{"flag":true}],["[[ cyclic ref *2 ]]"]]
@@ -0,0 +1,14 @@
function Component(props) {
const x = [{}];
const y = x.map((item) => {
return item;
});
y[0].flag = true;
return [x, y];
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
isComponent: false,
};