mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[hir] Introduce ValueKind.Context
This tracks whether a value is a context ref or generated from a context ref. This lets us track mutations to context refs and treat it separately as we want this to be more conservative than our existing inference. ValueKind.Context is exactly like ValueKind.Mutable but is more conservative.
This commit is contained in:
@@ -531,6 +531,7 @@ export enum ValueKind {
|
||||
Frozen = "frozen",
|
||||
Immutable = "immutable",
|
||||
Mutable = "mutable",
|
||||
Context = "context",
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
} from "../HIR/PrintHIR";
|
||||
import {
|
||||
eachInstructionOperand,
|
||||
eachInstructionValueOperand,
|
||||
eachTerminalOperand,
|
||||
eachTerminalSuccessor,
|
||||
} from "../HIR/visitors";
|
||||
@@ -100,7 +101,7 @@ export default function inferReferenceEffects(fn: HIRFunction) {
|
||||
properties: null,
|
||||
loc: ref.loc,
|
||||
};
|
||||
initialEnvironment.initialize(value, ValueKind.Mutable);
|
||||
initialEnvironment.initialize(value, ValueKind.Context);
|
||||
initialEnvironment.define(ref, value);
|
||||
}
|
||||
|
||||
@@ -274,6 +275,7 @@ class Environment {
|
||||
case Effect.Freeze: {
|
||||
if (
|
||||
valueKind === ValueKind.Mutable ||
|
||||
valueKind === ValueKind.Context ||
|
||||
valueKind === ValueKind.MaybeFrozen
|
||||
) {
|
||||
effect = Effect.Freeze;
|
||||
@@ -285,7 +287,10 @@ class Environment {
|
||||
break;
|
||||
}
|
||||
case Effect.Mutate: {
|
||||
if (valueKind === ValueKind.Mutable) {
|
||||
if (
|
||||
valueKind === ValueKind.Mutable ||
|
||||
valueKind === ValueKind.Context
|
||||
) {
|
||||
effect = Effect.Mutate;
|
||||
} else {
|
||||
effect = Effect.Read;
|
||||
@@ -488,6 +493,9 @@ class Environment {
|
||||
* types. To ensure that any sequence of joins btw those three states yields the
|
||||
* correct maybe-frozen, these two have to produce a frozen value.
|
||||
* - <any> | maybe-frozen => maybe-frozen
|
||||
* - immutable | context => context
|
||||
* - mutable | context => context
|
||||
* - frozen | context => maybe-frozen
|
||||
*
|
||||
* ┌──────────────────────────┐
|
||||
* │ Immutable │───┐
|
||||
@@ -513,10 +521,21 @@ function mergeValues(a: ValueKind, b: ValueKind): ValueKind {
|
||||
if (a === ValueKind.Frozen || b === ValueKind.Frozen) {
|
||||
// frozen | mutable
|
||||
return ValueKind.MaybeFrozen;
|
||||
} else if (a === ValueKind.Context || b === ValueKind.Context) {
|
||||
// context | mutable
|
||||
return ValueKind.Context;
|
||||
} else {
|
||||
// mutable | immutable
|
||||
return ValueKind.Mutable;
|
||||
}
|
||||
} else if (a === ValueKind.Context || b === ValueKind.Context) {
|
||||
if (a === ValueKind.Frozen || b === ValueKind.Frozen) {
|
||||
// frozen | context
|
||||
return ValueKind.MaybeFrozen;
|
||||
} else {
|
||||
// context | immutable
|
||||
return ValueKind.Context;
|
||||
}
|
||||
} else {
|
||||
// frozen | immutable
|
||||
return ValueKind.Frozen;
|
||||
@@ -664,7 +683,11 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
continue;
|
||||
}
|
||||
case "PropertyStore": {
|
||||
env.reference(instrValue.value, Effect.Capture);
|
||||
const effect =
|
||||
env.kind(instrValue.object) === ValueKind.Context
|
||||
? Effect.Mutate
|
||||
: Effect.Capture;
|
||||
env.reference(instrValue.value, effect);
|
||||
env.reference(instrValue.object, Effect.Store);
|
||||
|
||||
const lvalue = instr.lvalue;
|
||||
@@ -692,7 +715,11 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
continue;
|
||||
}
|
||||
case "ComputedStore": {
|
||||
env.reference(instrValue.value, Effect.Capture);
|
||||
const effect =
|
||||
env.kind(instrValue.object) === ValueKind.Context
|
||||
? Effect.Mutate
|
||||
: Effect.Capture;
|
||||
env.reference(instrValue.value, effect);
|
||||
env.reference(instrValue.property, Effect.Capture);
|
||||
env.reference(instrValue.object, Effect.Store);
|
||||
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y;
|
||||
(function () {
|
||||
y["x"] = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
const $ = React.unstable_useMemoCache();
|
||||
const c_0 = $[0] !== a;
|
||||
let y;
|
||||
if (c_0) {
|
||||
const x = { a: a };
|
||||
y = undefined;
|
||||
(function () {
|
||||
y["x"] = x;
|
||||
})();
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[1];
|
||||
}
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y;
|
||||
(function () {
|
||||
y["x"] = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y;
|
||||
(function () {
|
||||
y.x = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
const $ = React.unstable_useMemoCache();
|
||||
const c_0 = $[0] !== a;
|
||||
let y;
|
||||
if (c_0) {
|
||||
const x = { a: a };
|
||||
y = undefined;
|
||||
(function () {
|
||||
y.x = x;
|
||||
})();
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[1];
|
||||
}
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y;
|
||||
(function () {
|
||||
y.x = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a["x"] = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
const $ = React.unstable_useMemoCache();
|
||||
const c_0 = $[0] !== a;
|
||||
let y;
|
||||
if (c_0) {
|
||||
const x = { a: a };
|
||||
y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a["x"] = x;
|
||||
})();
|
||||
mutate(y);
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a["x"] = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a.x = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
const $ = React.unstable_useMemoCache();
|
||||
const c_0 = $[0] !== a;
|
||||
let y;
|
||||
if (c_0) {
|
||||
const x = { a: a };
|
||||
y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a.x = x;
|
||||
})();
|
||||
mutate(y);
|
||||
$[0] = a;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
function component(a) {
|
||||
let x = { a };
|
||||
let y = {};
|
||||
(function () {
|
||||
let a = y;
|
||||
a.x = x;
|
||||
})();
|
||||
mutate(y);
|
||||
return y;
|
||||
}
|
||||
Reference in New Issue
Block a user