@samitouri / QOS-React-1 / commits / d325f872de

[compiler][be] Logger based debug printing in test runner (#31809)

Avoid mutable logging enabled state and writing to `process.stdout` within our babel transform.

mofeiZ committed Dec 16, 2024 at 15:15 UTC d325f872de658fc26127a91c965c135d8ad4e877
8 files changed +78 -173
compiler/packages/babel-plugin-react-compiler/package.json
-2
@@ -42,9 +42,7 @@
42 "babel-jest": "^29.0.3",
43 "babel-plugin-fbt": "^1.0.0",
44 "babel-plugin-fbt-runtime": "^1.0.0",
45 - "chalk": "4",
45 "eslint": "^8.57.1",
47 - "glob": "^7.1.6",
46 "invariant": "^2.2.4",
47 "jest": "^29.0.3",
48 "jest-environment-jsdom": "^29.0.3",
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+2 -42
@@ -79,13 +79,6 @@ import {
79 rewriteInstructionKindsBasedOnReassignment,
80 } from '../SSA';
81 import {inferTypes} from '../TypeInference';
82 -import {
83 - logCodegenFunction,
84 - logDebug,
85 - logHIRFunction,
86 - logReactiveFunction,
87 -} from '../Utils/logger';
88 -import {assertExhaustive} from '../Utils/utils';
82 import {
83 validateContextVariableLValues,
84 validateHooksUsage,
@@ -139,13 +132,7 @@ function run(
132 name: 'EnvironmentConfig',
133 value: prettyFormat(env.config),
134 });
142 - printLog({
143 - kind: 'debug',
144 - name: 'EnvironmentConfig',
145 - value: prettyFormat(env.config),
146 - });
147 - const ast = runWithEnvironment(func, env);
148 - return ast;
135 + return runWithEnvironment(func, env);
136 }
137
138 /*
@@ -158,10 +145,8 @@ function runWithEnvironment(
145 >,
146 env: Environment,
147 ): CodegenFunction {
161 - const log = (value: CompilerPipelineValue): CompilerPipelineValue => {
162 - printLog(value);
148 + const log = (value: CompilerPipelineValue): void => {
149 env.logger?.debugLogIRs?.(value);
164 - return value;
150 };
151 const hir = lower(func, env).unwrap();
152 log({kind: 'hir', name: 'HIR', value: hir});
@@ -545,28 +530,3 @@ export function compileFn(
530 code,
531 );
532 }
548 -
549 -function printLog(value: CompilerPipelineValue): CompilerPipelineValue {
550 - switch (value.kind) {
551 - case 'ast': {
552 - logCodegenFunction(value.name, value.value);
553 - break;
554 - }
555 - case 'hir': {
556 - logHIRFunction(value.name, value.value);
557 - break;
558 - }
559 - case 'reactive': {
560 - logReactiveFunction(value.name, value.value);
561 - break;
562 - }
563 - case 'debug': {
564 - logDebug(value.name, value.value);
565 - break;
566 - }
567 - default: {
568 - assertExhaustive(value, 'Unexpected compilation kind');
569 - }
570 - }
571 - return value;
572 -}
compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts
+5 -2
@@ -19,7 +19,6 @@ import {
19 import {deadCodeElimination} from '../Optimization';
20 import {inferReactiveScopeVariables} from '../ReactiveScopes';
21 import {rewriteInstructionKindsBasedOnReassignment} from '../SSA';
22 -import {logHIRFunction} from '../Utils/logger';
22 import {inferMutableContextVariables} from './InferMutableContextVariables';
23 import {inferMutableRanges} from './InferMutableRanges';
24 import inferReferenceEffects from './InferReferenceEffects';
@@ -112,7 +111,11 @@ function lower(func: HIRFunction): void {
111 rewriteInstructionKindsBasedOnReassignment(func);
112 inferReactiveScopeVariables(func);
113 inferMutableContextVariables(func);
115 - logHIRFunction('AnalyseFunction (inner)', func);
114 + func.env.logger?.debugLogIRs?.({
115 + kind: 'hir',
116 + name: 'AnalyseFunction (inner)',
117 + value: func,
118 + });
119 }
120
121 function infer(
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts
+5 -2
@@ -25,7 +25,6 @@ import {
25 eachPatternOperand,
26 } from '../HIR/visitors';
27 import DisjointSet from '../Utils/DisjointSet';
28 -import {logHIRFunction} from '../Utils/logger';
28 import {assertExhaustive} from '../Utils/utils';
29
30 /*
@@ -156,7 +155,11 @@ export function inferReactiveScopeVariables(fn: HIRFunction): void {
155 scope.range.end > maxInstruction + 1
156 ) {
157 // Make it easier to debug why the error occurred
159 - logHIRFunction('InferReactiveScopeVariables (invalid scope)', fn);
158 + fn.env.logger?.debugLogIRs?.({
159 + kind: 'hir',
160 + name: 'InferReactiveScopeVariables (invalid scope)',
161 + value: fn,
162 + });
163 CompilerError.invariant(false, {
164 reason: `Invalid mutable range for scope`,
165 loc: GeneratedSource,
compiler/packages/babel-plugin-react-compiler/src/Utils/logger.ts deleted
-110
@@ -1,110 +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 generate from '@babel/generator';
9 -import * as t from '@babel/types';
10 -import chalk from 'chalk';
11 -import {HIR, HIRFunction, ReactiveFunction} from '../HIR/HIR';
12 -import {printFunctionWithOutlined, printHIR} from '../HIR/PrintHIR';
13 -import {CodegenFunction} from '../ReactiveScopes';
14 -import {printReactiveFunctionWithOutlined} from '../ReactiveScopes/PrintReactiveFunction';
15 -
16 -let ENABLED: boolean = false;
17 -
18 -let lastLogged: string;
19 -
20 -export function toggleLogging(enabled: boolean): void {
21 - ENABLED = enabled;
22 -}
23 -
24 -export function logDebug(step: string, value: string): void {
25 - if (ENABLED) {
26 - process.stdout.write(`${chalk.green(step)}:\n${value}\n\n`);
27 - }
28 -}
29 -
30 -export function logHIR(step: string, ir: HIR): void {
31 - if (ENABLED) {
32 - const printed = printHIR(ir);
33 - if (printed !== lastLogged) {
34 - lastLogged = printed;
35 - process.stdout.write(`${chalk.green(step)}:\n${printed}\n\n`);
36 - } else {
37 - process.stdout.write(`${chalk.blue(step)}: (no change)\n\n`);
38 - }
39 - }
40 -}
41 -
42 -export function logCodegenFunction(step: string, fn: CodegenFunction): void {
43 - if (ENABLED) {
44 - let printed: string | null = null;
45 - try {
46 - const node = t.functionDeclaration(
47 - fn.id,
48 - fn.params,
49 - fn.body,
50 - fn.generator,
51 - fn.async,
52 - );
53 - const ast = generate(node);
54 - printed = ast.code;
55 - } catch (e) {
56 - let errMsg: string;
57 - if (
58 - typeof e === 'object' &&
59 - e != null &&
60 - 'message' in e &&
61 - typeof e.message === 'string'
62 - ) {
63 - errMsg = e.message.toString();
64 - } else {
65 - errMsg = '[empty]';
66 - }
67 - console.log('Error formatting AST: ' + errMsg);
68 - }
69 - if (printed === null) {
70 - return;
71 - }
72 - if (printed !== lastLogged) {
73 - lastLogged = printed;
74 - process.stdout.write(`${chalk.green(step)}:\n${printed}\n\n`);
75 - } else {
76 - process.stdout.write(`${chalk.blue(step)}: (no change)\n\n`);
77 - }
78 - }
79 -}
80 -
81 -export function logHIRFunction(step: string, fn: HIRFunction): void {
82 - if (ENABLED) {
83 - const printed = printFunctionWithOutlined(fn);
84 - if (printed !== lastLogged) {
85 - lastLogged = printed;
86 - process.stdout.write(`${chalk.green(step)}:\n${printed}\n\n`);
87 - } else {
88 - process.stdout.write(`${chalk.blue(step)}: (no change)\n\n`);
89 - }
90 - }
91 -}
92 -
93 -export function logReactiveFunction(step: string, fn: ReactiveFunction): void {
94 - if (ENABLED) {
95 - const printed = printReactiveFunctionWithOutlined(fn);
96 - if (printed !== lastLogged) {
97 - lastLogged = printed;
98 - process.stdout.write(`${chalk.green(step)}:\n${printed}\n\n`);
99 - } else {
100 - process.stdout.write(`${chalk.blue(step)}: (no change)\n\n`);
101 - }
102 - }
103 -}
104 -
105 -export function log(fn: () => string): void {
106 - if (ENABLED) {
107 - const message = fn();
108 - process.stdout.write(message.trim() + '\n\n');
109 - }
110 -}
compiler/packages/snap/src/compiler.ts
+13 -9
@@ -19,6 +19,7 @@ import type {
19 PanicThresholdOptions,
20 PluginOptions,
21 CompilerReactTarget,
22 + CompilerPipelineValue,
23 } from 'babel-plugin-react-compiler/src/Entrypoint';
24 import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
25 import type {
@@ -45,6 +46,7 @@ export function parseLanguage(source: string): 'flow' | 'typescript' {
46 function makePluginOptions(
47 firstLine: string,
48 parseConfigPragmaFn: typeof ParseConfigPragma,
49 + debugIRLogger: (value: CompilerPipelineValue) => void,
50 EffectEnum: typeof Effect,
51 ValueKindEnum: typeof ValueKind,
52 ): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
@@ -182,15 +184,15 @@ function makePluginOptions(
184 .filter(s => s.length > 0);
185 }
186
185 - let logs: Array<{filename: string | null; event: LoggerEvent}> = [];
186 - let logger: Logger | null = null;
187 - if (firstLine.includes('@logger')) {
188 - logger = {
189 - logEvent(filename: string | null, event: LoggerEvent): void {
190 - logs.push({filename, event});
191 - },
192 - };
193 - }
187 + const logs: Array<{filename: string | null; event: LoggerEvent}> = [];
188 + const logger: Logger = {
189 + logEvent: firstLine.includes('@logger')
190 + ? (filename, event) => {
191 + logs.push({filename, event});
192 + }
193 + : () => {},
194 + debugLogIRs: debugIRLogger,
195 + };
196
197 const config = parseConfigPragmaFn(firstLine);
198 const options = {
@@ -338,6 +340,7 @@ export async function transformFixtureInput(
340 parseConfigPragmaFn: typeof ParseConfigPragma,
341 plugin: BabelCore.PluginObj,
342 includeEvaluator: boolean,
343 + debugIRLogger: (value: CompilerPipelineValue) => void,
344 EffectEnum: typeof Effect,
345 ValueKindEnum: typeof ValueKind,
346 ): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> {
@@ -365,6 +368,7 @@ export async function transformFixtureInput(
368 const [options, logs] = makePluginOptions(
369 firstLine,
370 parseConfigPragmaFn,
371 + debugIRLogger,
372 EffectEnum,
373 ValueKindEnum,
374 );
compiler/packages/snap/src/constants.ts
+9 -3
@@ -18,11 +18,17 @@ export const COMPILER_PATH = path.join(
18 'BabelPlugin.js',
19 );
20 export const COMPILER_INDEX_PATH = path.join(process.cwd(), 'dist', 'index');
21 -export const LOGGER_PATH = path.join(
21 +export const PRINT_HIR_PATH = path.join(
22 process.cwd(),
23 'dist',
24 - 'Utils',
25 - 'logger.js',
24 + 'HIR',
25 + 'PrintHIR.js',
26 +);
27 +export const PRINT_REACTIVE_IR_PATH = path.join(
28 + process.cwd(),
29 + 'dist',
30 + 'ReactiveScopes',
31 + 'PrintReactiveFunction.js',
32 );
33 export const PARSE_CONFIG_PRAGMA_PATH = path.join(
34 process.cwd(),
compiler/packages/snap/src/runner-worker.ts
+44 -3
@@ -8,16 +8,21 @@
8 import {codeFrameColumns} from '@babel/code-frame';
9 import type {PluginObj} from '@babel/core';
10 import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/HIR/Environment';
11 +import type {printFunctionWithOutlined as PrintFunctionWithOutlined} from 'babel-plugin-react-compiler/src/HIR/PrintHIR';
12 +import type {printReactiveFunctionWithOutlined as PrintReactiveFunctionWithOutlined} from 'babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction';
13 import {TransformResult, transformFixtureInput} from './compiler';
14 import {
15 COMPILER_PATH,
16 COMPILER_INDEX_PATH,
15 - LOGGER_PATH,
17 PARSE_CONFIG_PRAGMA_PATH,
18 + PRINT_HIR_PATH,
19 + PRINT_REACTIVE_IR_PATH,
20 } from './constants';
21 import {TestFixture, getBasename, isExpectError} from './fixture-utils';
22 import {TestResult, writeOutputToString} from './reporter';
23 import {runSprout} from './sprout';
24 +import {CompilerPipelineValue} from 'babel-plugin-react-compiler/src';
25 +import chalk from 'chalk';
26
27 const originalConsoleError = console.error;
28
@@ -64,20 +69,56 @@ async function compile(
69 const {Effect: EffectEnum, ValueKind: ValueKindEnum} = require(
70 COMPILER_INDEX_PATH,
71 );
67 - const {toggleLogging} = require(LOGGER_PATH);
72 + const {printFunctionWithOutlined} = require(PRINT_HIR_PATH) as {
73 + printFunctionWithOutlined: typeof PrintFunctionWithOutlined;
74 + };
75 + const {printReactiveFunctionWithOutlined} = require(
76 + PRINT_REACTIVE_IR_PATH,
77 + ) as {
78 + printReactiveFunctionWithOutlined: typeof PrintReactiveFunctionWithOutlined;
79 + };
80 +
81 + let lastLogged: string | null = null;
82 + const debugIRLogger = shouldLog
83 + ? (value: CompilerPipelineValue) => {
84 + let printed: string;
85 + switch (value.kind) {
86 + case 'hir':
87 + printed = printFunctionWithOutlined(value.value);
88 + break;
89 + case 'reactive':
90 + printed = printReactiveFunctionWithOutlined(value.value);
91 + break;
92 + case 'debug':
93 + printed = value.value;
94 + break;
95 + case 'ast':
96 + // skip printing ast as we already write fixture output JS
97 + printed = '(ast)';
98 + break;
99 + }
100 +
101 + if (printed !== lastLogged) {
102 + lastLogged = printed;
103 + console.log(`${chalk.green(value.name)}:\n ${printed}\n`);
104 + } else {
105 + console.log(`${chalk.blue(value.name)}: (no change)\n`);
106 + }
107 + }
108 + : () => {};
109 const {parseConfigPragmaForTests} = require(PARSE_CONFIG_PRAGMA_PATH) as {
110 parseConfigPragmaForTests: typeof ParseConfigPragma;
111 };
112
113 // only try logging if we filtered out all but one fixture,
114 // since console log order is non-deterministic
74 - toggleLogging(shouldLog);
115 const result = await transformFixtureInput(
116 input,
117 fixturePath,
118 parseConfigPragmaForTests,
119 BabelPluginReactCompiler,
120 includeEvaluator,
121 + debugIRLogger,
122 EffectEnum,
123 ValueKindEnum,
124 );