MemoizeFbtOperandsInSameScope operates on HIR
Moves this pass to operate against HIRFunction instead of ReactiveFunction, no logic changes.
Joe Savona committed
Mar 6, 2024 at 14:02 UTC
ebbada309db9094cae1c0a2a4e5faffae0422318
2 files changed
+80
-86
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts
+7
-7
@@ -211,6 +211,13 @@ function* runWithEnvironment(
211
value: hir,
212
});
213
214
+ memoizeFbtOperandsInSameScope(hir);
215
+ yield log({
216
+ kind: "hir",
217
+ name: "MemoizeFbtOperandsInSameScope",
218
+ value: hir,
219
+ });
220
+
221
const reactiveFunction = buildReactiveFunction(hir);
222
yield log({
223
kind: "reactive",
@@ -225,13 +232,6 @@ function* runWithEnvironment(
232
value: reactiveFunction,
233
});
234
228
- memoizeFbtOperandsInSameScope(reactiveFunction);
229
- yield log({
230
- kind: "reactive",
231
- name: "MemoizeFbtOperandsInSameScope",
232
- value: reactiveFunction,
233
- });
234
-
235
alignReactiveScopesToBlockScopes(reactiveFunction);
236
yield log({
237
kind: "reactive",
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/MemoizeFbtOperandsInSameScope.ts
+73
-79
@@ -6,18 +6,13 @@
6
*/
7
8
import {
9
+ HIRFunction,
10
IdentifierId,
11
makeInstructionId,
12
Place,
12
- ReactiveFunction,
13
- ReactiveInstruction,
13
ReactiveValue,
14
} from "../HIR";
16
-import {
17
- eachReactiveValueOperand,
18
- ReactiveFunctionVisitor,
19
- visitReactiveFunction,
20
-} from "./visitors";
15
+import { eachReactiveValueOperand } from "./visitors";
16
17
/*
18
* This pass supports the `fbt` translation system (https://facebook.github.io/fbt/).
@@ -33,12 +28,12 @@ import {
28
* Note that this still allows the props/arguments of `<fbt:param>`/`fbt.param()`
29
* to be independently memoized
30
*/
36
-export function memoizeFbtOperandsInSameScope(fn: ReactiveFunction): void {
37
- const transform = new Transform();
31
+export function memoizeFbtOperandsInSameScope(fn: HIRFunction): void {
32
+ const fbtValues: Set<IdentifierId> = new Set();
33
while (true) {
39
- let size = transform.fbtValues.size;
40
- visitReactiveFunction(fn, transform, undefined);
41
- if (size === transform.fbtValues.size) {
34
+ let size = fbtValues.size;
35
+ visit(fn, fbtValues);
36
+ if (size === fbtValues.size) {
37
break;
38
}
39
}
@@ -47,80 +42,79 @@ export function memoizeFbtOperandsInSameScope(fn: ReactiveFunction): void {
42
export const FBT_TAGS: Set<string> = new Set(["fbt", "fbt:param"]);
43
export const SINGLE_CHILD_FBT_TAGS: Set<string> = new Set(["fbt:param"]);
44
50
-class Transform extends ReactiveFunctionVisitor<void> {
51
- /*
52
- * Values that represent *potential* references of `fbt` as a JSX tag name
53
- * or as a callee.
54
- */
55
- fbtValues: Set<IdentifierId> = new Set();
56
-
57
- override visitInstruction(
58
- instruction: ReactiveInstruction,
59
- _state: void
60
- ): void {
61
- const { lvalue, value } = instruction;
62
- if (lvalue === null) {
63
- return;
64
- }
65
- if (
66
- value.kind === "Primitive" &&
67
- typeof value.value === "string" &&
68
- FBT_TAGS.has(value.value)
69
- ) {
70
- /*
71
- * We don't distinguish between tag names and strings, so record
72
- * all `fbt` string literals in case they are used as a jsx tag.
73
- */
74
- this.fbtValues.add(lvalue.identifier.id);
75
- } else if (value.kind === "LoadGlobal" && FBT_TAGS.has(value.name)) {
76
- // Record references to `fbt` as a global
77
- this.fbtValues.add(lvalue.identifier.id);
78
- } else if (isFbtCallExpression(this.fbtValues, value)) {
79
- const fbtScope = lvalue.identifier.scope;
80
- if (fbtScope === null) {
81
- return;
82
- }
83
-
84
- /*
85
- * if the JSX element's tag was `fbt`, mark all its operands
86
- * to ensure that they end up in the same scope as the jsx element
87
- * itself.
88
- */
89
- for (const operand of eachReactiveValueOperand(value)) {
90
- operand.identifier.scope = fbtScope;
91
-
92
- // Expand the jsx element's range to account for its operands
93
- fbtScope.range.start = makeInstructionId(
94
- Math.min(fbtScope.range.start, operand.identifier.mutableRange.start)
95
- );
96
- }
97
- } else if (
98
- isFbtJsxExpression(this.fbtValues, value) ||
99
- isFbtJsxChild(this.fbtValues, lvalue, value)
100
- ) {
101
- const fbtScope = lvalue.identifier.scope;
102
- if (fbtScope === null) {
45
+function visit(fn: HIRFunction, fbtValues: Set<IdentifierId>): void {
46
+ for (const [, block] of fn.body.blocks) {
47
+ for (const instruction of block.instructions) {
48
+ const { lvalue, value } = instruction;
49
+ if (lvalue === null) {
50
return;
51
}
52
+ if (
53
+ value.kind === "Primitive" &&
54
+ typeof value.value === "string" &&
55
+ FBT_TAGS.has(value.value)
56
+ ) {
57
+ /*
58
+ * We don't distinguish between tag names and strings, so record
59
+ * all `fbt` string literals in case they are used as a jsx tag.
60
+ */
61
+ fbtValues.add(lvalue.identifier.id);
62
+ } else if (value.kind === "LoadGlobal" && FBT_TAGS.has(value.name)) {
63
+ // Record references to `fbt` as a global
64
+ fbtValues.add(lvalue.identifier.id);
65
+ } else if (isFbtCallExpression(fbtValues, value)) {
66
+ const fbtScope = lvalue.identifier.scope;
67
+ if (fbtScope === null) {
68
+ return;
69
+ }
70
106
- /*
107
- * if the JSX element's tag was `fbt`, mark all its operands
108
- * to ensure that they end up in the same scope as the jsx element
109
- * itself.
110
- */
111
- for (const operand of eachReactiveValueOperand(value)) {
112
- operand.identifier.scope = fbtScope;
71
+ /*
72
+ * if the JSX element's tag was `fbt`, mark all its operands
73
+ * to ensure that they end up in the same scope as the jsx element
74
+ * itself.
75
+ */
76
+ for (const operand of eachReactiveValueOperand(value)) {
77
+ operand.identifier.scope = fbtScope;
78
114
- // Expand the jsx element's range to account for its operands
115
- fbtScope.range.start = makeInstructionId(
116
- Math.min(fbtScope.range.start, operand.identifier.mutableRange.start)
117
- );
79
+ // Expand the jsx element's range to account for its operands
80
+ fbtScope.range.start = makeInstructionId(
81
+ Math.min(
82
+ fbtScope.range.start,
83
+ operand.identifier.mutableRange.start
84
+ )
85
+ );
86
+ }
87
+ } else if (
88
+ isFbtJsxExpression(fbtValues, value) ||
89
+ isFbtJsxChild(fbtValues, lvalue, value)
90
+ ) {
91
+ const fbtScope = lvalue.identifier.scope;
92
+ if (fbtScope === null) {
93
+ return;
94
+ }
95
96
/*
120
- * NOTE: we add the operands as fbt values so that they are also
121
- * grouped with this expression
97
+ * if the JSX element's tag was `fbt`, mark all its operands
98
+ * to ensure that they end up in the same scope as the jsx element
99
+ * itself.
100
*/
123
- this.fbtValues.add(operand.identifier.id);
101
+ for (const operand of eachReactiveValueOperand(value)) {
102
+ operand.identifier.scope = fbtScope;
103
+
104
+ // Expand the jsx element's range to account for its operands
105
+ fbtScope.range.start = makeInstructionId(
106
+ Math.min(
107
+ fbtScope.range.start,
108
+ operand.identifier.mutableRange.start
109
+ )
110
+ );
111
+
112
+ /*
113
+ * NOTE: we add the operands as fbt values so that they are also
114
+ * grouped with this expression
115
+ */
116
+ fbtValues.add(operand.identifier.id);
117
+ }
118
}
119
}
120
}