Skip to content

Commit

Permalink
[compiler] add fixture for optimization across scopes
Browse files Browse the repository at this point in the history
Adds a fixture based on internal case where our current output is quite a bit more verbose than the original memoization. See the comment in the fixture for more about the heuristic we can apply.

ghstack-source-id: 05f3ddaa98f3f937777dc963ef25912be4281045
Pull Request resolved: #29998
  • Loading branch information
josephsavona committed Jun 21, 2024
1 parent 4f24498 commit 93201d1
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

## Input

```javascript
import { Stringify } from "shared-runtime";

function Component({ config }) {
/**
* The original memoization is optimal in the sense that it has
* one output (the object) and one dependency (`config`). Both
* the `a` and `b` functions will have to be recreated whenever
* `config` changes, cascading to update the object.
*
* However, we currently only consider consecutive scopes for
* merging, so we first see the `a` scope, then the `b` scope,
* and see that the output of the `a` scope is used later -
* so we don't merge these scopes, and so on.
*
* The more optimal thing would be to build a dependency graph
* of scopes so that we can see the data flow is along the lines
* of:
*
* config
* / \
* [a] [b]
* \ /
* [object]
*
* All the scopes (shown in []) are transitively dependent on
* `config`, so they can be merged.
*/
const object = useMemo(() => {
const a = (event) => {
config?.onA?.(event);
};

const b = (event) => {
config?.onB?.(event);
};

return {
b,
a,
};
}, [config]);

return <Stringify value={object} />;
}

```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";

function Component(t0) {
const $ = _c(9);
const { config } = t0;
let t1;
let t2;
if ($[0] !== config) {
t2 = (event) => {
config?.onA?.(event);
};
$[0] = config;
$[1] = t2;
} else {
t2 = $[1];
}
const a = t2;
let t3;
if ($[2] !== config) {
t3 = (event_0) => {
config?.onB?.(event_0);
};
$[2] = config;
$[3] = t3;
} else {
t3 = $[3];
}
const b = t3;
let t4;
if ($[4] !== b || $[5] !== a) {
t4 = { b, a };
$[4] = b;
$[5] = a;
$[6] = t4;
} else {
t4 = $[6];
}
t1 = t4;
const object = t1;
let t5;
if ($[7] !== object) {
t5 = <Stringify value={object} />;
$[7] = object;
$[8] = t5;
} else {
t5 = $[8];
}
return t5;
}

```
### Eval output
(kind: exception) Fixture not implemented
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Stringify } from "shared-runtime";

function Component({ config }) {
/**
* The original memoization is optimal in the sense that it has
* one output (the object) and one dependency (`config`). Both
* the `a` and `b` functions will have to be recreated whenever
* `config` changes, cascading to update the object.
*
* However, we currently only consider consecutive scopes for
* merging, so we first see the `a` scope, then the `b` scope,
* and see that the output of the `a` scope is used later -
* so we don't merge these scopes, and so on.
*
* The more optimal thing would be to build a dependency graph
* of scopes so that we can see the data flow is along the lines
* of:
*
* config
* / \
* [a] [b]
* \ /
* [object]
*
* All the scopes (shown in []) are transitively dependent on
* `config`, so they can be merged.
*/
const object = useMemo(() => {
const a = (event) => {
config?.onA?.(event);
};

const b = (event) => {
config?.onB?.(event);
};

return {
b,
a,
};
}, [config]);

return <Stringify value={object} />;
}

0 comments on commit 93201d1

Please sign in to comment.