[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:
Sathya Gunasekaran
2023-02-10 17:59:56 +00:00
parent 2a9fab001a
commit fa57551dd5
10 changed files with 234 additions and 4 deletions
+1
View File
@@ -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);
@@ -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;
}
@@ -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;
}
@@ -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;
}