From f2c6bb41a79ff93acae16bede4c4ba42163e5e01 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:27:11 -0700 Subject: [PATCH 1/3] Remove Debug namespace runtime modification --- src/compiler/debug.ts | 46 ++++++------------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index 94838e3f8634a..ffa9674f623a7 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -14,7 +14,6 @@ import { FlowSwitchClause, getEffectiveModifierFlagsNoCache, getEmitFlags, - getOwnKeys, getParseTreeNode, getSourceFileOfNode, getSourceTextOfNodeFromSourceFile, @@ -61,13 +60,11 @@ import { isUnionTypeNode, LiteralType, map, - MatchingKeys, ModifierFlags, Node, NodeArray, NodeFlags, nodeIsSynthesized, - noop, objectAllocator, ObjectFlags, ObjectType, @@ -116,8 +113,6 @@ export namespace Debug { export let loggingHost: LoggingHost | undefined; /* eslint-enable prefer-const */ - type AssertionKeys = MatchingKeys; - export function shouldLog(level: LogLevel): boolean { return currentLogLevel <= level; } @@ -150,47 +145,18 @@ export namespace Debug { } } - const assertionCache: Partial> = {}; - export function getAssertionLevel() { return currentAssertionLevel; } export function setAssertionLevel(level: AssertionLevel) { - const prevAssertionLevel = currentAssertionLevel; currentAssertionLevel = level; - - if (level > prevAssertionLevel) { - // restore assertion functions for the current assertion level (see `shouldAssertFunction`). - for (const key of getOwnKeys(assertionCache) as AssertionKeys[]) { - const cachedFunc = assertionCache[key]; - if (cachedFunc !== undefined && Debug[key] !== cachedFunc.assertion && level >= cachedFunc.level) { - (Debug as any)[key] = cachedFunc; - assertionCache[key] = undefined; - } - } - } } export function shouldAssert(level: AssertionLevel): boolean { return currentAssertionLevel >= level; } - /** - * Tests whether an assertion function should be executed. If it shouldn't, it is cached and replaced with `ts.noop`. - * Replaced assertion functions are restored when `Debug.setAssertionLevel` is set to a high enough level. - * @param level The minimum assertion level required. - * @param name The name of the current assertion function. - */ - function shouldAssertFunction(level: AssertionLevel, name: K): boolean { - if (!shouldAssert(level)) { - assertionCache[name] = { level, assertion: Debug[name] }; - (Debug as any)[name] = noop; - return false; - } - return true; - } - export function fail(message?: string, stackCrawlMark?: AnyFunction): never { debugger; const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure."); @@ -277,7 +243,7 @@ export namespace Debug { export function assertEachNode(nodes: readonly T[] | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[] | undefined; export function assertEachNode(nodes: readonly Node[], test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; export function assertEachNode(nodes: readonly Node[] | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertEachNode")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( test === undefined || every(nodes, test), message || "Unexpected node.", @@ -289,7 +255,7 @@ export namespace Debug { export function assertNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertNode")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( node !== undefined && (test === undefined || test(node)), message || "Unexpected node.", @@ -301,7 +267,7 @@ export namespace Debug { export function assertNotNode(node: T | undefined, test: (node: Node) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is Exclude; export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertNotNode")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( node === undefined || test === undefined || !test(node), message || "Unexpected node.", @@ -314,7 +280,7 @@ export namespace Debug { export function assertOptionalNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U | undefined; export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalNode")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( test === undefined || node === undefined || test(node), message || "Unexpected node.", @@ -327,7 +293,7 @@ export namespace Debug { export function assertOptionalToken(node: T | undefined, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract | undefined; export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction): void; export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalToken")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( kind === undefined || node === undefined || node.kind === kind, message || "Unexpected node.", @@ -338,7 +304,7 @@ export namespace Debug { export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction): asserts node is undefined; export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction) { - if (shouldAssertFunction(AssertionLevel.Normal, "assertMissingNode")) { + if (shouldAssert(AssertionLevel.Normal)) { assert( node === undefined, message || "Unexpected node.", From a6bfdaa7a413a853f1b01ca86c83bbf7b10df444 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 13 Mar 2023 10:09:21 -0700 Subject: [PATCH 2/3] Try using var, like in Parser namespace --- src/compiler/debug.ts | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index ffa9674f623a7..d7b7f7c1ed987 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -106,12 +106,22 @@ export interface LoggingHost { /** @internal */ export namespace Debug { - /* eslint-disable prefer-const */ - let currentAssertionLevel = AssertionLevel.None; - export let currentLogLevel = LogLevel.Warning; - export let isDebugging = false; - export let loggingHost: LoggingHost | undefined; - /* eslint-enable prefer-const */ + // Why var? It avoids TDZ checks in the runtime which can be costly. + // See: https://github.com/microsoft/TypeScript/issues/52924 + // TODO(jakebailey): restore to let/const once Debug is no longer a namespace. + /* eslint-disable no-var */ + var currentAssertionLevel = AssertionLevel.None; + export var currentLogLevel = LogLevel.Warning; + export var isDebugging = false; + export var loggingHost: LoggingHost | undefined; + + var enumMemberCache = new Map>(); + + var isDebugInfoEnabled = false; + + var flowNodeProto: FlowNodeBase | undefined; + var nodeArrayProto: NodeArray | undefined; + /* eslint-enable no-var */ export function shouldLog(level: LogLevel): boolean { return currentLogLevel <= level; @@ -373,7 +383,6 @@ export namespace Debug { return value.toString(); } - const enumMemberCache = new Map>(); function getEnumMembers(enumObject: any) { // Assuming enum objects do not change at runtime, we can cache the enum members list @@ -457,9 +466,7 @@ export namespace Debug { return formatEnum(facts, (ts as any).TypeFacts, /*isFlags*/ true); } - let isDebugInfoEnabled = false; - let flowNodeProto: FlowNodeBase | undefined; function attachFlowNodeDebugInfoWorker(flowNode: FlowNodeBase) { if (!("__debugFlowFlags" in flowNode)) { // eslint-disable-line local/no-in-operator @@ -508,7 +515,7 @@ export namespace Debug { } } - let nodeArrayProto: NodeArray | undefined; + function attachNodeArrayDebugInfoWorker(array: NodeArray) { if (!("__tsDebuggerDisplay" in array)) { // eslint-disable-line local/no-in-operator From 434414dee8659ad04164f010c434ad6e3e9c8003 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 13 Mar 2023 10:14:45 -0700 Subject: [PATCH 3/3] Lint --- src/compiler/debug.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index d7b7f7c1ed987..8c6f60b6b751e 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -515,8 +515,6 @@ export namespace Debug { } } - - function attachNodeArrayDebugInfoWorker(array: NodeArray) { if (!("__tsDebuggerDisplay" in array)) { // eslint-disable-line local/no-in-operator Object.defineProperties(array, {