dillon1000/react
Commit
Browse files Inline useMemo callbacks to allow improved memoization
This is a simplified version of #1454. The goal of this PR is to inline the
contents of `useMemo()` callbacks, rather than just immediately invoke the
lambda. Turning useMemo() into an IIFE works, but it means that we can't
optimize within the lambda block. Our investigations showed that there's a lot
of room to optimize at a finer granularity than manually written useMemo calls.
For example, one product instance had a useMemo that created a list of child JSX
elements. Most of those elements only relied on a single variable (`a`), but a
few relied on a second variable (`b). Thus _all_ elements were invalidated
whenever `b` changed. If Forget retains the original lambda, we have no choice
but to keep that (coarse) granularity for memoization. When we inline, we can
optimize to make e.g. individual JSX elements depend on their precise
dependencies.
The rough idea is:
* Keep track of all function expressions
* When we find a useMemo, lookup its function expression, and add its CFG to the
main function (the previous PR ensures that BlockIds won't collide)
* Replace any return statements with a StoreLocal to save the result and a Goto
to the code following the useMemo call.
* Then we run the usual set of passes to patch the HIR back up again.
Example:
```javascript
// Before
function Component(props) {
const x = useMemo(() => {
if (props.cond) {
return null;
}
return foo(props.x);
}, [props.x]);
return x + props.y;
}
// Intended - **before** memoization
function Component(props) {
let x;
if (props.cond) {
x = null;
} else {
x = foo(props.x);
}
return x + props.y;
}
```Changed paths16 files
First-parent comparisoncompiler/forget/src/CompilerPipeline.ts ModifiedM compiler/forget/src/HIR/MergeConsecutiveBlocks.ts ModifiedA compiler/forget/src/Inference/InlineUseMemo.ts AddedM compiler/forget/src/Inference/index.ts ModifiedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-if-else-multiple-return.expect.md AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-if-else-multiple-return.js AddedM compiler/forget/src/__tests__/fixtures/compiler/useMemo-independently-memoizeable.expect.md ModifiedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-labeled-statement-unconditional-return.expect.md AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-labeled-statement-unconditional-return.js AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-logical.expect.md AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-logical.js AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.js AddedM compiler/forget/src/__tests__/fixtures/compiler/useMemo-simple.expect.md ModifiedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-switch-no-fallthrough.expect.md AddedA compiler/forget/src/__tests__/fixtures/compiler/useMemo-switch-no-fallthrough.js AddedPatch
Files changed
Rendering syntax-highlighted changes…