mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -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 ]]"]]
|
||||
+14
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user