Skip to content

Commit 43c17d1

Browse files
committed
[compiler] HIR-based FlattenReactiveLoops
Pre the title, this implements an HIR-based version of FlattenReactiveLoops. Another step on the way to HIR-everywhere. ghstack-source-id: e1d1663 Pull Request resolved: #29838
1 parent f7b871a commit 43c17d1

File tree

2 files changed

+87
-8
lines changed

2 files changed

+87
-8
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ import {
7070
} from "../ReactiveScopes";
7171
import { alignMethodCallScopes } from "../ReactiveScopes/AlignMethodCallScopes";
7272
import { alignReactiveScopesToBlockScopesHIR } from "../ReactiveScopes/AlignReactiveScopesToBlockScopesHIR";
73+
import { flattenReactiveLoopsHIR } from "../ReactiveScopes/FlattenReactiveLoopsHIR";
7374
import { pruneAlwaysInvalidatingScopes } from "../ReactiveScopes/PruneAlwaysInvalidatingScopes";
75+
import pruneInitializationDependencies from "../ReactiveScopes/PruneInitializationDependencies";
7476
import { stabilizeBlockIds } from "../ReactiveScopes/StabilizeBlockIds";
7577
import { eliminateRedundantPhi, enterSSA, leaveSSA } from "../SSA";
7678
import { inferTypes } from "../TypeInference";
@@ -91,7 +93,6 @@ import {
9193
validatePreservedManualMemoization,
9294
validateUseMemo,
9395
} from "../Validation";
94-
import pruneInitializationDependencies from "../ReactiveScopes/PruneInitializationDependencies";
9596

9697
export type CompilerPipelineValue =
9798
| { kind: "ast"; name: string; value: CodegenFunction }
@@ -281,6 +282,13 @@ function* runWithEnvironment(
281282
});
282283

283284
assertValidBlockNesting(hir);
285+
286+
flattenReactiveLoopsHIR(hir);
287+
yield log({
288+
kind: "hir",
289+
name: "FlattenReactiveLoopsHIR",
290+
value: hir,
291+
});
284292
}
285293

286294
const reactiveFunction = buildReactiveFunction(hir);
@@ -320,14 +328,14 @@ function* runWithEnvironment(
320328
name: "BuildReactiveBlocks",
321329
value: reactiveFunction,
322330
});
323-
}
324331

325-
flattenReactiveLoops(reactiveFunction);
326-
yield log({
327-
kind: "reactive",
328-
name: "FlattenReactiveLoops",
329-
value: reactiveFunction,
330-
});
332+
flattenReactiveLoops(reactiveFunction);
333+
yield log({
334+
kind: "reactive",
335+
name: "FlattenReactiveLoops",
336+
value: reactiveFunction,
337+
});
338+
}
331339

332340
assertScopeInstructionsWithinScopes(reactiveFunction);
333341

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { BlockId, HIRFunction, PrunedScopeTerminal } from "../HIR";
9+
import { assertExhaustive, retainWhere } from "../Utils/utils";
10+
11+
/**
12+
* Prunes any reactive scopes that are within a loop (for, while, etc). We don't yet
13+
* support memoization within loops because this would require an extra layer of reconciliation
14+
* (plus a way to identify values across runs, similar to how we use `key` in JSX for lists).
15+
* Eventually we may integrate more deeply into the runtime so that we can do a single level
16+
* of reconciliation, but for now we've found it's sufficient to memoize *around* the loop.
17+
*/
18+
export function flattenReactiveLoopsHIR(fn: HIRFunction): void {
19+
const activeLoops = Array<BlockId>();
20+
for (const [, block] of fn.body.blocks) {
21+
retainWhere(activeLoops, (id) => id !== block.id);
22+
const { terminal } = block;
23+
switch (terminal.kind) {
24+
case "do-while":
25+
case "for":
26+
case "for-in":
27+
case "for-of":
28+
case "while": {
29+
activeLoops.push(terminal.fallthrough);
30+
break;
31+
}
32+
case "scope": {
33+
if (activeLoops.length !== 0) {
34+
block.terminal = {
35+
kind: "pruned-scope",
36+
block: terminal.block,
37+
fallthrough: terminal.fallthrough,
38+
id: terminal.id,
39+
loc: terminal.loc,
40+
scope: terminal.scope,
41+
} as PrunedScopeTerminal;
42+
}
43+
break;
44+
}
45+
case "branch":
46+
case "goto":
47+
case "if":
48+
case "label":
49+
case "logical":
50+
case "maybe-throw":
51+
case "optional":
52+
case "pruned-scope":
53+
case "return":
54+
case "sequence":
55+
case "switch":
56+
case "ternary":
57+
case "throw":
58+
case "try":
59+
case "unreachable":
60+
case "unsupported": {
61+
break;
62+
}
63+
default: {
64+
assertExhaustive(
65+
terminal,
66+
`Unexpected terminal kind \`${(terminal as any).kind}\``
67+
);
68+
}
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)