@samitouri / QOS-React-2 / commits / e2cfbeb3d3

[playground] Display only new HIR

Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react-forget/pull/824). * #825 * __->__ #824 [playground] Display only new HIR

Sathya Gunasekaran committed Nov 24, 2022 at 15:24 UTC e2cfbeb3d3457aa4f38bff54a34a04c68c8ab277
4 files changed +141 -316
compiler/forget/packages/playground/components/Editor/CompilerFlagsEditor.tsx deleted
-46
@@ -1,46 +0,0 @@
1 -/*
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - */
4 -import clsx from "clsx";
5 -import type { ForgetCompilerFlags } from "../../lib/compilerDriver";
6 -import { useStore, useStoreDispatch } from "../StoreContext";
7 -
8 -// TODO: Allow collapsing the compiler options editor
9 -export default function CompilerFlagsEditor() {
10 - const store = useStore();
11 - const dispatch = useStoreDispatch();
12 -
13 - return (
14 - <div className="flex flex-col gap-2 px-5 py-4 border-t border-gray-200">
15 - <div>
16 - <h3 className="font-medium">Compiler Options</h3>
17 - </div>
18 - <div className="flex flex-col">
19 - {Object.keys(store.compilerFlags).map((f) => {
20 - const flag = f as keyof ForgetCompilerFlags;
21 - const isChecked = store.compilerFlags[flag];
22 -
23 - return (
24 - <label key={flag} className="flex gap-1.5 text-base">
25 - <input
26 - type="checkbox"
27 - checked={isChecked}
28 - onChange={(e) =>
29 - dispatch({
30 - type: "setCompilerFlag",
31 - payload: { flag, value: e.target.checked },
32 - })
33 - }
34 - />
35 - <span
36 - className={clsx("text-gray-500", { "text-black": isChecked })}
37 - >
38 - {flag}
39 - </span>
40 - </label>
41 - );
42 - })}
43 - </div>
44 - </div>
45 - );
46 -}
compiler/forget/packages/playground/components/Editor/HIRTabContent.tsx deleted
-207
@@ -1,207 +0,0 @@
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 clsx from "clsx";
9 -
10 -import { HIR } from "babel-plugin-react-forget";
11 -import { useState } from "react";
12 -import generate from "@babel/generator";
13 -import prettier from "prettier";
14 -import prettierParserBabel from "prettier/parser-babel";
15 -
16 -const {
17 - parseFunctions,
18 - Environment,
19 - enterSSA,
20 - eliminateRedundantPhi,
21 - inferReferenceEffects,
22 - inferMutableRanges,
23 - leaveSSA,
24 - lower,
25 - printHIR,
26 - codegen,
27 -} = HIR;
28 -
29 -export default function HIRTabContent({ source }: { source: string }) {
30 - const astFunctions = parseFunctions(source);
31 -
32 - const [flags, setFlags] = useState({
33 - codegen: true,
34 - eliminateRedundantPhi: true,
35 - inferReferenceEffects: true,
36 - inferMutableRanges: true,
37 - leaveSSA: true,
38 - });
39 -
40 - return (
41 - <div className="flex flex-col h-full">
42 - <div className="flex-1">
43 - {astFunctions.map((func, index): React.ReactNode => {
44 - let body;
45 - try {
46 - const env = new Environment();
47 - const ir = lower(func, env);
48 - enterSSA(ir, env);
49 - if (flags.eliminateRedundantPhi) {
50 - eliminateRedundantPhi(ir);
51 - }
52 - if (flags.inferReferenceEffects) {
53 - inferReferenceEffects(ir);
54 - }
55 - if (flags.inferMutableRanges) {
56 - inferMutableRanges(ir);
57 - }
58 - if (flags.leaveSSA) {
59 - leaveSSA(ir);
60 - }
61 -
62 - if (flags.codegen) {
63 - const ast = codegen(ir);
64 - const generated = generate(
65 - ast,
66 - {
67 - sourceMaps: true,
68 - sourceFileName: "input.js",
69 - },
70 - source
71 - );
72 - const formatted = prettier.format(generated.code, {
73 - semi: true,
74 - parser: "babel",
75 - plugins: [prettierParserBabel],
76 - });
77 - const sourceMapUrl = getSourceMapUrl(
78 - generated.code,
79 - JSON.stringify(generated.map)
80 - );
81 - body = (
82 - <>
83 - <pre>{formatted}</pre>
84 - {sourceMapUrl && (
85 - <iframe
86 - src={sourceMapUrl}
87 - className="w-full h-96"
88 - title="Generated Code"
89 - />
90 - )}
91 - </>
92 - );
93 - } else {
94 - body = <pre>{printHIR(ir.body)}</pre>;
95 - }
96 - } catch (e: any) {
97 - body = <div>error: ${e.toString()}</div>;
98 - }
99 - const name = func.node.id?.name ?? "anonymous";
100 - return (
101 - <div key={index} className="px-2 py-4 border-b">
102 - <h3 className="mb-2 font-medium">Function: {name}</h3>
103 - {body}
104 - </div>
105 - );
106 - })}
107 - </div>
108 - <CompilerFlagsEditor flags={flags} setFlags={setFlags} />
109 - </div>
110 - );
111 -}
112 -
113 -function utf16ToUTF8(s: string): string {
114 - return unescape(encodeURIComponent(s));
115 -}
116 -
117 -function getSourceMapUrl(code: string, map: string): string | null {
118 - code = utf16ToUTF8(code);
119 - map = utf16ToUTF8(map);
120 - return `https://evanw.github.io/source-map-visualization/#${btoa(
121 - `${code.length}\0${code}${map.length}\0${map}`
122 - )}`;
123 -}
124 -
125 -type Flags = {
126 - eliminateRedundantPhi: boolean;
127 - inferReferenceEffects: boolean;
128 - inferMutableRanges: boolean;
129 - leaveSSA: boolean;
130 - codegen: boolean;
131 -};
132 -
133 -function CompilerFlagsEditor({
134 - flags,
135 - setFlags,
136 -}: {
137 - flags: Flags;
138 - setFlags: (flags: Flags) => void;
139 -}) {
140 - return (
141 - <div className="flex flex-col gap-2 px-5 py-4 border-t border-gray-200">
142 - <h3 className="font-medium">Compiler Options</h3>
143 - <div className="flex flex-col">
144 - <LabeledCheckbox
145 - label="Eliminate Redundant Phi"
146 - value={flags.eliminateRedundantPhi}
147 - onChange={(eliminateRedundantPhi) => {
148 - setFlags({ ...flags, eliminateRedundantPhi });
149 - }}
150 - />
151 - <LabeledCheckbox
152 - label="Infer Reference Effects"
153 - value={flags.inferReferenceEffects}
154 - onChange={(inferReferenceEffects) => {
155 - setFlags({ ...flags, inferReferenceEffects });
156 - }}
157 - />
158 - <LabeledCheckbox
159 - label="Infer Mutable Ranges"
160 - value={flags.inferMutableRanges}
161 - onChange={(inferMutableRanges) => {
162 - setFlags({ ...flags, inferMutableRanges });
163 - }}
164 - />
165 - <LabeledCheckbox
166 - label="Leave SSA"
167 - value={flags.leaveSSA}
168 - onChange={(leaveSSA) => {
169 - setFlags({ ...flags, leaveSSA });
170 - }}
171 - />
172 - <LabeledCheckbox
173 - label="Codegen"
174 - value={flags.codegen}
175 - onChange={(codegen) => {
176 - setFlags({ ...flags, codegen });
177 - }}
178 - />
179 - </div>
180 - </div>
181 - );
182 -}
183 -
184 -function LabeledCheckbox({
185 - label,
186 - value,
187 - onChange,
188 -}: {
189 - label: string;
190 - value: boolean;
191 - onChange: (value: boolean) => void;
192 -}) {
193 - return (
194 - <label className="flex gap-1.5 text-base">
195 - <input
196 - type="checkbox"
197 - checked={value}
198 - onChange={(e) => {
199 - onChange(e.target.checked);
200 - }}
201 - />
202 - <span className={clsx({ "text-gray-500": !value, "text-black": value })}>
203 - {label}
204 - </span>
205 - </label>
206 - );
207 -}
compiler/forget/packages/playground/components/Editor/Output.tsx
+141 -62
@@ -5,21 +5,28 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import TabbedWindow from "../TabbedWindow";
8 +import generate from "@babel/generator";
9 import MonacoEditor from "@monaco-editor/react";
10 -import {
11 - CompilerOutputs,
12 - OutputKind,
13 - stringifyCompilerOutputs,
14 - type Diagnostic,
15 -} from "babel-plugin-react-forget";
16 -import { memo, useEffect, useMemo } from "react";
17 -import compile from "../../lib/compilerDriver";
10 +import { Diagnostic, HIR, OutputKind } from "babel-plugin-react-forget";
11 +import prettier from "prettier";
12 +import prettierParserBabel from "prettier/parser-babel";
13 +import { memo } from "react";
14 import type { Store } from "../../lib/stores";
19 -import GraphView from "../GraphView";
15 +import TabbedWindow from "../TabbedWindow";
16 import { monacoOptions } from "./monacoOptions";
21 -import HIRTabContent from "./HIRTabContent";
17
18 +const {
19 + parseFunctions,
20 + Environment,
21 + enterSSA,
22 + eliminateRedundantPhi,
23 + inferReferenceEffects,
24 + inferMutableRanges,
25 + leaveSSA,
26 + lower,
27 + printHIR,
28 + codegen,
29 +} = HIR;
30 const MemoizedOutput = memo(Output);
31
32 export default MemoizedOutput;
@@ -29,55 +36,141 @@ type Props = {
36 updateDiagnostics: (newDiags: Diagnostic[]) => void;
37 };
38
32 -function Output({ store, updateDiagnostics }: Props) {
33 - const { outputs, diagnostics } = useMemo(
34 - () => compile(store.source, store.compilerFlags),
35 - [store]
36 - );
37 - useEffect(() => {
38 - updateDiagnostics(diagnostics);
39 - }, [diagnostics, updateDiagnostics]);
40 - return (
41 - <TabbedWindow
42 - defaultTab="HIR"
43 - tabs={{
44 - IR: <TextTabContent outputs={outputs} kind={OutputKind.IR} />,
45 - HIR: <HIRTabContent source={store.source} />,
46 - CFG: <TextTabContent outputs={outputs} kind={OutputKind.CFG} />,
47 - ValGraph: (
48 - <GraphTabContent outputs={outputs} kind={OutputKind.ValGraph} />
49 - ),
50 - SCCGraph: (
51 - <GraphTabContent outputs={outputs} kind={OutputKind.SCCGraph} />
52 - ),
53 - RedGraph: (
54 - <GraphTabContent outputs={outputs} kind={OutputKind.RedGraph} />
55 - ),
56 - LIR: <TextTabContent outputs={outputs} kind={OutputKind.LIR} />,
57 - JS: <TextTabContent outputs={outputs} kind={OutputKind.JS} />,
58 - }}
59 - />
60 - );
39 +// TODO(gsn: Update diagnostics ƒrom HIR output
40 +function Output({ store }: Props) {
41 + const astFunctions = parseFunctions(store.source);
42 + if (astFunctions.length === 0) {
43 + return <div></div>;
44 + }
45 +
46 + try {
47 + // TODO: Handle multiple functions
48 + const func = astFunctions[0];
49 + const env = new Environment();
50 + const ir = lower(func, env);
51 +
52 + const hirOutput = printHIR(ir.body);
53 +
54 + enterSSA(ir, env);
55 + const ssaOutput = printHIR(ir.body);
56 +
57 + eliminateRedundantPhi(ir);
58 + const eliminateRedundantPhiOutput = printHIR(ir.body);
59 +
60 + inferReferenceEffects(ir);
61 + const inferReferenceEffectsOutput = printHIR(ir.body);
62 +
63 + inferMutableRanges(ir);
64 + const inferMutableRangesOutput = printHIR(ir.body);
65 +
66 + leaveSSA(ir);
67 + const leaveSSAOutput = printHIR(ir.body);
68 +
69 + codegen(ir);
70 + const ast = codegen(ir);
71 + const generated = generate(
72 + ast,
73 + {
74 + sourceMaps: true,
75 + sourceFileName: "input.js",
76 + },
77 + store.source
78 + );
79 + const sourceMapUrl = getSourceMapUrl(
80 + generated.code,
81 + JSON.stringify(generated.map)
82 + );
83 + const codegenOutput = prettier.format(generated.code, {
84 + semi: true,
85 + parser: "babel",
86 + plugins: [prettierParserBabel],
87 + });
88 + return (
89 + <TabbedWindow
90 + defaultTab="HIR"
91 + tabs={{
92 + HIR: (
93 + <TextTabContent
94 + output={hirOutput}
95 + kind={OutputKind.IR}
96 + ></TextTabContent>
97 + ),
98 + SSA: (
99 + <TextTabContent
100 + output={ssaOutput}
101 + kind={OutputKind.IR}
102 + ></TextTabContent>
103 + ),
104 + EliminateRedundantPhi: (
105 + <TextTabContent
106 + output={eliminateRedundantPhiOutput}
107 + kind={OutputKind.IR}
108 + ></TextTabContent>
109 + ),
110 + InferReferenceEffects: (
111 + <TextTabContent
112 + output={inferReferenceEffectsOutput}
113 + kind={OutputKind.IR}
114 + ></TextTabContent>
115 + ),
116 + InferMutableRanges: (
117 + <TextTabContent
118 + output={inferMutableRangesOutput}
119 + kind={OutputKind.IR}
120 + ></TextTabContent>
121 + ),
122 + LeaveSSA: (
123 + <TextTabContent
124 + output={leaveSSAOutput}
125 + kind={OutputKind.IR}
126 + ></TextTabContent>
127 + ),
128 + JS: <TextTabContent output={codegenOutput} kind={OutputKind.JS} />,
129 + SourceMap: (
130 + <>
131 + {" "}
132 + {sourceMapUrl && (
133 + <iframe
134 + src={sourceMapUrl}
135 + className="w-full h-96"
136 + title="Generated Code"
137 + />
138 + )}
139 + </>
140 + ),
141 + }}
142 + />
143 + );
144 + } catch (e: any) {
145 + return <div>error: ${e.toString()}</div>;
146 + }
147 +}
148 +
149 +function utf16ToUTF8(s: string): string {
150 + return unescape(encodeURIComponent(s));
151 +}
152 +
153 +function getSourceMapUrl(code: string, map: string): string | null {
154 + code = utf16ToUTF8(code);
155 + map = utf16ToUTF8(map);
156 + return `https://evanw.github.io/source-map-visualization/#${btoa(
157 + `${code.length}\0${code}${map.length}\0${map}`
158 + )}`;
159 }
160
161 function TextTabContent({
64 - outputs,
162 + output,
163 kind,
164 }: {
67 - outputs: CompilerOutputs;
165 + output: string;
166 kind: OutputKind;
167 }) {
70 - const prettyOutputs = useMemo(
71 - () => stringifyCompilerOutputs(outputs),
72 - [outputs]
73 - );
74 -
168 return (
169 <div className="w-full h-full">
170 <MonacoEditor
171 path={kind}
172 defaultLanguage="javascript"
80 - value={prettyOutputs[kind] ?? "(Empty)"}
173 + value={output}
174 options={{
175 ...monacoOptions,
176 readOnly: true,
@@ -86,17 +179,3 @@ function TextTabContent({
179 </div>
180 );
181 }
89 -
90 -function GraphTabContent({
91 - outputs,
92 - kind,
93 -}: {
94 - outputs: CompilerOutputs;
95 - kind: OutputKind.ValGraph | OutputKind.SCCGraph | OutputKind.RedGraph;
96 -}) {
97 - return (
98 - <div className="w-full h-full overflow-auto">
99 - <GraphView graphs={outputs[kind]} />
100 - </div>
101 - );
102 -}
compiler/forget/packages/playground/components/Editor/index.tsx
-1
@@ -21,7 +21,6 @@ import {
21 type Store,
22 } from "../../lib/stores";
23 import { useStore, useStoreDispatch } from "../StoreContext";
24 -import CompilerFlagsEditor from "./CompilerFlagsEditor";
24 import Input from "./Input";
25 import Output from "./Output";
26