[compiler] Cleanup for @enablePreserveExistingMemoizationGuarantees (#34346)

I tried turning on `@enablePreserveExistingMemoizationGuarantees` by
default and cleaned up a couple small things:

* We emit freeze calls for StartMemoize deps but these had
ValueReason.Other so the message wasn't great. We now treat these like
other hook arguments.
* PruneNonEscapingScopes was being too aggressive in this mode and
memoizing even loads of globals. Switching to
MemoizationLevel.Conditional ensures we build a graph that connects
through to primitive-returning function calls, but doesn't unnecessarily
force memoization otherwise.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34346).
* #34347
* __->__ #34346
This commit is contained in:
Joseph Savona 2025-09-03 21:30:52 -07:00 committed by GitHub
parent 735e9ac54e
commit 2710795a1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 139 additions and 24 deletions

View File

@ -2089,7 +2089,7 @@ function computeSignatureForInstruction(
effects.push({
kind: 'Freeze',
value: operand,
reason: ValueReason.Other,
reason: ValueReason.HookCaptured,
});
}
}

View File

@ -546,7 +546,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
* memoization. Note: we may still prune primitive-producing scopes if
* they don't ultimately escape at all.
*/
const level = MemoizationLevel.Memoized;
const level = MemoizationLevel.Conditional;
return {
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],
rvalues: [...eachReactiveValueOperand(value)],
@ -701,9 +701,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
}
case 'ComputedLoad':
case 'PropertyLoad': {
const level = options.forceMemoizePrimitives
? MemoizationLevel.Memoized
: MemoizationLevel.Conditional;
const level = MemoizationLevel.Conditional;
return {
// Indirection for the inner value, memoized if the value is
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],

View File

@ -2,6 +2,7 @@
## Input
```javascript
// @compilationMode:"infer"
import {makeArray} from 'shared-runtime';
function Component() {
@ -30,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @compilationMode:"infer"
import { makeArray } from "shared-runtime";
function Component() {

View File

@ -1,3 +1,4 @@
// @compilationMode:"infer"
import {makeArray} from 'shared-runtime';
function Component() {

View File

@ -0,0 +1,86 @@
## Input
```javascript
// @enablePreserveExistingMemoizationGuarantees
import {fbt} from 'fbt';
function Component() {
const buttonLabel = () => {
if (!someCondition) {
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
} else if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return (
<fbt desc="Gift button's label">
{'Gift | '}
<fbt:param name="price">
{item?.current_gift_offer?.price?.formatted}
</fbt:param>
</fbt>
);
} else if (!iconOnly && !showPrice) {
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
}
};
return (
<View>
<Button text={buttonLabel()} />
</View>
);
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
import { fbt } from "fbt";
function Component() {
const $ = _c(1);
const buttonLabel = _temp;
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<View>
<Button text={buttonLabel()} />
</View>
);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
function _temp() {
if (!someCondition) {
return fbt._("Purchase as a gift", null, { hk: "1gHj4g" });
} else {
if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return fbt._(
"Gift | {price}",
[fbt._param("price", item?.current_gift_offer?.price?.formatted)],
{ hk: "3GTnGE" },
);
} else {
if (!iconOnly && !showPrice) {
return fbt._("Gift", null, { hk: "3fqfrk" });
}
}
}
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@ -0,0 +1,31 @@
// @enablePreserveExistingMemoizationGuarantees
import {fbt} from 'fbt';
function Component() {
const buttonLabel = () => {
if (!someCondition) {
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
} else if (
!iconOnly &&
showPrice &&
item?.current_gift_offer?.price?.formatted != null
) {
return (
<fbt desc="Gift button's label">
{'Gift | '}
<fbt:param name="price">
{item?.current_gift_offer?.price?.formatted}
</fbt:param>
</fbt>
);
} else if (!iconOnly && !showPrice) {
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
}
};
return (
<View>
<Button text={buttonLabel()} />
</View>
);
}

View File

@ -2,7 +2,7 @@
## Input
```javascript
// @enableForest
// @enablePreserveExistingMemoizationGuarantees
function Component({base, start, increment, test}) {
let value = base;
for (let i = start; i < test; i += increment) {
@ -27,25 +27,23 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableForest
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
function Component(t0) {
const $ = _c(5);
const $ = _c(2);
const { base, start, increment, test } = t0;
let value;
if ($[0] !== base || $[1] !== increment || $[2] !== start || $[3] !== test) {
value = base;
for (let i = start; i < test; i = i + increment, i) {
value = value + i;
}
$[0] = base;
$[1] = increment;
$[2] = start;
$[3] = test;
$[4] = value;
} else {
value = $[4];
let value = base;
for (let i = start; i < test; i = i + increment, i) {
value = value + i;
}
return <div>{value}</div>;
let t1;
if ($[0] !== value) {
t1 = <div>{value}</div>;
$[0] = value;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {

View File

@ -1,4 +1,4 @@
// @enableForest
// @enablePreserveExistingMemoizationGuarantees
function Component({base, start, increment, test}) {
let value = base;
for (let i = start; i < test; i += increment) {