@samitouri / QOS-React-1 / commits / 57d746e3c4

HIR terminal for representing reactive scopes

ghstack-source-id: f7d5b68bc5217555b6060ade3bfa253bb15660ad Pull Request resolved: https://github.com/facebook/react-forget/pull/2830

Joe Savona committed Apr 8, 2024 at 17:43 UTC 57d746e3c4a89aefb9ec59912120ea284e74e1c5
5 files changed +87 -5
compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts
+11 -1
@@ -347,7 +347,8 @@ export type Terminal =
347 | LabelTerminal
348 | SequenceTerminal
349 | MaybeThrowTerminal
350 - | TryTerminal;
350 + | TryTerminal
351 + | ReactiveScopeTerminal;
352
353 function _staticInvariantTerminalHasLocation(
354 terminal: Terminal
@@ -543,6 +544,15 @@ export type MaybeThrowTerminal = {
544 loc: SourceLocation;
545 };
546
547 +export type ReactiveScopeTerminal = {
548 + kind: "scope";
549 + fallthrough: BlockId;
550 + block: BlockId;
551 + scope: ReactiveScope;
552 + id: InstructionId;
553 + loc: SourceLocation;
554 +};
555 +
556 /*
557 * Instructions generally represent expressions but with all nesting flattened away,
558 * such that all operands to each instruction are either primitive values OR are
compiler/packages/babel-plugin-react-forget/src/HIR/HIRBuilder.ts
+4
@@ -795,6 +795,10 @@ function getReversePostorderedBlocks(func: HIR): HIR["blocks"] {
795 visit(terminal.block);
796 break;
797 }
798 + case "scope": {
799 + visit(terminal.block);
800 + break;
801 + }
802 case "unsupported": {
803 break;
804 }
compiler/packages/babel-plugin-react-forget/src/HIR/PrintHIR.ts
+9 -1
@@ -8,6 +8,7 @@
8 import generate from "@babel/generator";
9 import { printReactiveFunction } from "..";
10 import { CompilerError } from "../CompilerError";
11 +import { printReactiveScopeSummary } from "../ReactiveScopes/PrintReactiveFunction";
12 import DisjointSet from "../Utils/DisjointSet";
13 import { assertExhaustive } from "../Utils/utils";
14 import type {
@@ -124,7 +125,8 @@ export function printMixedHIR(
125 case "goto":
126 case "do-while":
127 case "for-in":
127 - case "for-of": {
128 + case "for-of":
129 + case "scope": {
130 const terminal = printTerminal(value);
131 if (Array.isArray(terminal)) {
132 return terminal.join("; ");
@@ -267,6 +269,12 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
269 value = `MaybeThrow continuation=bb${terminal.continuation} handler=bb${terminal.handler}`;
270 break;
271 }
272 + case "scope": {
273 + value = `Scope ${printReactiveScopeSummary(terminal.scope)} block=bb${
274 + terminal.block
275 + } fallthrough=bb${terminal.fallthrough}`;
276 + break;
277 + }
278 case "try": {
279 value = `Try block=bb${terminal.block} handler=bb${terminal.handler}${
280 terminal.handlerBinding !== null
compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts
+32 -3
@@ -833,6 +833,18 @@ export function mapTerminalSuccessors(
833 loc: terminal.loc,
834 };
835 }
836 + case "scope": {
837 + const block = fn(terminal.block);
838 + const fallthrough = fn(terminal.fallthrough);
839 + return {
840 + kind: "scope",
841 + scope: terminal.scope,
842 + block,
843 + fallthrough,
844 + id: makeInstructionId(0),
845 + loc: terminal.loc,
846 + };
847 + }
848 case "unsupported": {
849 return terminal;
850 }
@@ -872,7 +884,8 @@ export function terminalFallthrough(terminal: Terminal): BlockId | null {
884 case "sequence":
885 case "switch":
886 case "ternary":
875 - case "while": {
887 + case "while":
888 + case "scope": {
889 return terminal.fallthrough;
890 }
891 default: {
@@ -935,21 +948,31 @@ export function mapOptionalFallthroughs(
948 const _: BlockId = terminal.fallthrough;
949 break;
950 }
951 + case "scope": {
952 + const _: BlockId = terminal.fallthrough;
953 + break;
954 + }
955 case "switch": {
956 if (terminal.fallthrough !== null) {
957 terminal.fallthrough = fn(terminal.fallthrough);
958 + } else {
959 + terminal.fallthrough = null;
960 }
961 break;
962 }
963 case "if": {
964 if (terminal.fallthrough !== null) {
965 terminal.fallthrough = fn(terminal.fallthrough);
966 + } else {
967 + terminal.fallthrough = null;
968 }
969 break;
970 }
971 case "label": {
972 if (terminal.fallthrough !== null) {
973 terminal.fallthrough = fn(terminal.fallthrough);
974 + } else {
975 + terminal.fallthrough = null;
976 }
977 break;
978 }
@@ -1050,6 +1073,10 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
1073 yield terminal.block;
1074 break;
1075 }
1076 + case "scope": {
1077 + yield terminal.block;
1078 + break;
1079 + }
1080 case "unsupported":
1081 break;
1082 default: {
@@ -1109,7 +1136,8 @@ export function mapTerminalOperands(
1136 case "for-of":
1137 case "for-in":
1138 case "goto":
1112 - case "unsupported": {
1139 + case "unsupported":
1140 + case "scope": {
1141 // no-op
1142 break;
1143 }
@@ -1165,7 +1193,8 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
1193 case "for-of":
1194 case "for-in":
1195 case "goto":
1168 - case "unsupported": {
1196 + case "unsupported":
1197 + case "scope": {
1198 // no-op
1199 break;
1200 }
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts
+31
@@ -786,6 +786,37 @@ class Driver {
786 }
787 break;
788 }
789 + case "scope": {
790 + const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
791 + ? terminal.fallthrough
792 + : null;
793 + if (fallthroughId !== null) {
794 + const scheduleId = this.cx.schedule(fallthroughId, "if");
795 + scheduleIds.push(scheduleId);
796 + }
797 +
798 + let block: ReactiveBlock;
799 + if (this.cx.isScheduled(terminal.block)) {
800 + CompilerError.invariant(false, {
801 + reason: `Unexpected 'scope' where the block is already scheduled`,
802 + loc: terminal.loc,
803 + });
804 + } else {
805 + block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!);
806 + }
807 +
808 + this.cx.unscheduleAll(scheduleIds);
809 + blockValue.push({
810 + kind: "scope",
811 + instructions: block,
812 + scope: terminal.scope,
813 + });
814 + if (fallthroughId !== null) {
815 + this.visitBlock(this.cx.ir.blocks.get(fallthroughId)!, blockValue);
816 + }
817 +
818 + break;
819 + }
820 case "unsupported": {
821 CompilerError.invariant(false, {
822 reason: "Unexpected unsupported terminal",