[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: e1d166352df6b0725e4c4915a19445437916251f
Pull Request resolved: https://github.com/facebook/react/pull/29838
This commit is contained in:
Joe Savona 2024-06-10 13:22:12 -07:00
parent f7b871a8d5
commit 43c17d13ef
2 changed files with 87 additions and 8 deletions

View File

@ -70,7 +70,9 @@ import {
} from "../ReactiveScopes";
import { alignMethodCallScopes } from "../ReactiveScopes/AlignMethodCallScopes";
import { alignReactiveScopesToBlockScopesHIR } from "../ReactiveScopes/AlignReactiveScopesToBlockScopesHIR";
import { flattenReactiveLoopsHIR } from "../ReactiveScopes/FlattenReactiveLoopsHIR";
import { pruneAlwaysInvalidatingScopes } from "../ReactiveScopes/PruneAlwaysInvalidatingScopes";
import pruneInitializationDependencies from "../ReactiveScopes/PruneInitializationDependencies";
import { stabilizeBlockIds } from "../ReactiveScopes/StabilizeBlockIds";
import { eliminateRedundantPhi, enterSSA, leaveSSA } from "../SSA";
import { inferTypes } from "../TypeInference";
@ -91,7 +93,6 @@ import {
validatePreservedManualMemoization,
validateUseMemo,
} from "../Validation";
import pruneInitializationDependencies from "../ReactiveScopes/PruneInitializationDependencies";
export type CompilerPipelineValue =
| { kind: "ast"; name: string; value: CodegenFunction }
@ -281,6 +282,13 @@ function* runWithEnvironment(
});
assertValidBlockNesting(hir);
flattenReactiveLoopsHIR(hir);
yield log({
kind: "hir",
name: "FlattenReactiveLoopsHIR",
value: hir,
});
}
const reactiveFunction = buildReactiveFunction(hir);
@ -320,14 +328,14 @@ function* runWithEnvironment(
name: "BuildReactiveBlocks",
value: reactiveFunction,
});
}
flattenReactiveLoops(reactiveFunction);
yield log({
kind: "reactive",
name: "FlattenReactiveLoops",
value: reactiveFunction,
});
flattenReactiveLoops(reactiveFunction);
yield log({
kind: "reactive",
name: "FlattenReactiveLoops",
value: reactiveFunction,
});
}
assertScopeInstructionsWithinScopes(reactiveFunction);

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { BlockId, HIRFunction, PrunedScopeTerminal } from "../HIR";
import { assertExhaustive, retainWhere } from "../Utils/utils";
/**
* Prunes any reactive scopes that are within a loop (for, while, etc). We don't yet
* support memoization within loops because this would require an extra layer of reconciliation
* (plus a way to identify values across runs, similar to how we use `key` in JSX for lists).
* Eventually we may integrate more deeply into the runtime so that we can do a single level
* of reconciliation, but for now we've found it's sufficient to memoize *around* the loop.
*/
export function flattenReactiveLoopsHIR(fn: HIRFunction): void {
const activeLoops = Array<BlockId>();
for (const [, block] of fn.body.blocks) {
retainWhere(activeLoops, (id) => id !== block.id);
const { terminal } = block;
switch (terminal.kind) {
case "do-while":
case "for":
case "for-in":
case "for-of":
case "while": {
activeLoops.push(terminal.fallthrough);
break;
}
case "scope": {
if (activeLoops.length !== 0) {
block.terminal = {
kind: "pruned-scope",
block: terminal.block,
fallthrough: terminal.fallthrough,
id: terminal.id,
loc: terminal.loc,
scope: terminal.scope,
} as PrunedScopeTerminal;
}
break;
}
case "branch":
case "goto":
case "if":
case "label":
case "logical":
case "maybe-throw":
case "optional":
case "pruned-scope":
case "return":
case "sequence":
case "switch":
case "ternary":
case "throw":
case "try":
case "unreachable":
case "unsupported": {
break;
}
default: {
assertExhaustive(
terminal,
`Unexpected terminal kind \`${(terminal as any).kind}\``
);
}
}
}
}