@samitouri / QOS-React-2 / commits / 454fb35065

[compiler] add fixture for optimization across scopes

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: e637a3814077559a1a56724eafe2567efed0b8d7 Pull Request resolved: https://github.com/facebook/react/pull/29998

Joe Savona committed Jun 21, 2024 at 16:48 UTC 454fb35065053d5572689af1a7c125a41849604a
2 files changed +153
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md new
+109
@@ -0,0 +1,109 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { Stringify } from "shared-runtime";
6 +
7 +function Component({ config }) {
8 + /**
9 + * The original memoization is optimal in the sense that it has
10 + * one output (the object) and one dependency (`config`). Both
11 + * the `a` and `b` functions will have to be recreated whenever
12 + * `config` changes, cascading to update the object.
13 + *
14 + * However, we currently only consider consecutive scopes for
15 + * merging, so we first see the `a` scope, then the `b` scope,
16 + * and see that the output of the `a` scope is used later -
17 + * so we don't merge these scopes, and so on.
18 + *
19 + * The more optimal thing would be to build a dependency graph
20 + * of scopes so that we can see the data flow is along the lines
21 + * of:
22 + *
23 + * config
24 + * / \
25 + * [a] [b]
26 + * \ /
27 + * [object]
28 + *
29 + * All the scopes (shown in []) are transitively dependent on
30 + * `config`, so they can be merged.
31 + */
32 + const object = useMemo(() => {
33 + const a = (event) => {
34 + config?.onA?.(event);
35 + };
36 +
37 + const b = (event) => {
38 + config?.onB?.(event);
39 + };
40 +
41 + return {
42 + b,
43 + a,
44 + };
45 + }, [config]);
46 +
47 + return <Stringify value={object} />;
48 +}
49 +
50 +```
51 +
52 +## Code
53 +
54 +```javascript
55 +import { c as _c } from "react/compiler-runtime";
56 +import { Stringify } from "shared-runtime";
57 +
58 +function Component(t0) {
59 + const $ = _c(9);
60 + const { config } = t0;
61 + let t1;
62 + let t2;
63 + if ($[0] !== config) {
64 + t2 = (event) => {
65 + config?.onA?.(event);
66 + };
67 + $[0] = config;
68 + $[1] = t2;
69 + } else {
70 + t2 = $[1];
71 + }
72 + const a = t2;
73 + let t3;
74 + if ($[2] !== config) {
75 + t3 = (event_0) => {
76 + config?.onB?.(event_0);
77 + };
78 + $[2] = config;
79 + $[3] = t3;
80 + } else {
81 + t3 = $[3];
82 + }
83 + const b = t3;
84 + let t4;
85 + if ($[4] !== b || $[5] !== a) {
86 + t4 = { b, a };
87 + $[4] = b;
88 + $[5] = a;
89 + $[6] = t4;
90 + } else {
91 + t4 = $[6];
92 + }
93 + t1 = t4;
94 + const object = t1;
95 + let t5;
96 + if ($[7] !== object) {
97 + t5 = <Stringify value={object} />;
98 + $[7] = object;
99 + $[8] = t5;
100 + } else {
101 + t5 = $[8];
102 + }
103 + return t5;
104 +}
105 +
106 +```
107 +
108 +### Eval output
109 +(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.js new
+44
@@ -0,0 +1,44 @@
1 +import { Stringify } from "shared-runtime";
2 +
3 +function Component({ config }) {
4 + /**
5 + * The original memoization is optimal in the sense that it has
6 + * one output (the object) and one dependency (`config`). Both
7 + * the `a` and `b` functions will have to be recreated whenever
8 + * `config` changes, cascading to update the object.
9 + *
10 + * However, we currently only consider consecutive scopes for
11 + * merging, so we first see the `a` scope, then the `b` scope,
12 + * and see that the output of the `a` scope is used later -
13 + * so we don't merge these scopes, and so on.
14 + *
15 + * The more optimal thing would be to build a dependency graph
16 + * of scopes so that we can see the data flow is along the lines
17 + * of:
18 + *
19 + * config
20 + * / \
21 + * [a] [b]
22 + * \ /
23 + * [object]
24 + *
25 + * All the scopes (shown in []) are transitively dependent on
26 + * `config`, so they can be merged.
27 + */
28 + const object = useMemo(() => {
29 + const a = (event) => {
30 + config?.onA?.(event);
31 + };
32 +
33 + const b = (event) => {
34 + config?.onB?.(event);
35 + };
36 +
37 + return {
38 + b,
39 + a,
40 + };
41 + }, [config]);
42 +
43 + return <Stringify value={object} />;
44 +}