From f209dfcedda015939dcbdcdf1d0ef0480b277cb3 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 22 Sep 2023 13:56:37 -0400 Subject: [PATCH] Add port of ConcurrentMap from .NET --- scripts/build/tests.mjs | 2 +- src/compiler/_namespaces/ts.ts | 38 +- src/compiler/core.ts | 145 ++- src/compiler/factory/nodeFactory.ts | 4 +- src/compiler/parser.ts | 12 +- src/compiler/performance.ts | 44 + src/compiler/program.ts | 183 +-- src/compiler/sharing/atomicValue.ts | 127 +++ .../sharing/collections/concurrentMap.ts | 516 +++++++++ src/compiler/sharing/collections/deque.ts | 126 +++ src/compiler/sharing/collections/hash.ts | 37 + src/compiler/sharing/collections/hashData.ts | 37 +- src/compiler/sharing/sharedNode.ts | 1007 +++++++---------- src/compiler/sharing/sharedNodeAdapter.ts | 10 +- src/compiler/sharing/sharedNodeArray.ts | 13 +- src/compiler/sharing/sharedObjectAllocator.ts | 4 +- src/compiler/sharing/sharedParserState.ts | 8 +- .../sharing/structs/sharedStructsGlobals.ts | 17 +- src/compiler/sharing/structs/taggedStruct.ts | 7 + src/compiler/sharing/structs/wrapper.ts | 65 ++ src/compiler/symbolDisposeShim.ts | 107 +- src/compiler/threading/condition.ts | 18 +- src/compiler/threading/countdownEvent.ts | 2 +- src/compiler/threading/lockable.ts | 8 +- src/compiler/threading/manualResetEvent.ts | 6 +- src/compiler/threading/mutex.ts | 13 +- src/compiler/threading/scopedLock.ts | 62 +- src/compiler/threading/semaphore.ts | 93 ++ src/compiler/threading/sharedGuard.ts | 102 ++ src/compiler/threading/sharedLock.ts | 16 +- src/compiler/threading/sharedMutex.ts | 7 +- src/compiler/threading/sleep.ts | 15 + src/compiler/threading/spinWait.ts | 31 + src/compiler/threading/threadPool.ts | 387 +++++-- src/compiler/threading/uniqueLock.ts | 26 +- src/compiler/tracing.ts | 12 + src/compiler/tsbuildPublic.ts | 20 +- src/compiler/tsconfig.json | 3 +- src/compiler/types.ts | 7 +- src/compiler/watch.ts | 19 +- src/compiler/watchPublic.ts | 10 +- src/compiler/watchUtilities.ts | 45 +- src/compiler/worker.ts | 35 +- src/executeCommandLine/executeCommandLine.ts | 56 +- src/harness/fakesHosts.ts | 1 - src/services/services.ts | 2 +- src/testRunner/tests.ts | 2 +- .../unittests/sharing/concurrentMap.ts | 145 +++ src/testRunner/unittests/sharing/hashData.ts | 2 +- .../unittests/sharing/resizableArray.ts | 9 - 50 files changed, 2541 insertions(+), 1122 deletions(-) create mode 100644 src/compiler/sharing/atomicValue.ts create mode 100644 src/compiler/sharing/collections/concurrentMap.ts create mode 100644 src/compiler/sharing/collections/deque.ts create mode 100644 src/compiler/sharing/collections/hash.ts create mode 100644 src/compiler/sharing/structs/wrapper.ts create mode 100644 src/compiler/threading/semaphore.ts create mode 100644 src/compiler/threading/sharedGuard.ts create mode 100644 src/compiler/threading/sleep.ts create mode 100644 src/compiler/threading/spinWait.ts create mode 100644 src/testRunner/unittests/sharing/concurrentMap.ts delete mode 100644 src/testRunner/unittests/sharing/resizableArray.ts diff --git a/scripts/build/tests.mjs b/scripts/build/tests.mjs index d5e2f085988..31b54b9dcde 100644 --- a/scripts/build/tests.mjs +++ b/scripts/build/tests.mjs @@ -123,7 +123,7 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt if (structs) { args.unshift("--harmony-struct"); args.unshift("--shared-string-table"); - args.unshift("--enable-source-map"); + args.unshift("--enable-source-maps"); } /** @type {number | undefined} */ diff --git a/src/compiler/_namespaces/ts.ts b/src/compiler/_namespaces/ts.ts index d1c778bc373..a5a61d16be5 100644 --- a/src/compiler/_namespaces/ts.ts +++ b/src/compiler/_namespaces/ts.ts @@ -10,6 +10,26 @@ export * from "../tracing"; export * from "../types"; export * from "../sys"; export * from "../workerThreads"; +export * from "../sharing/structs/fakeSharedStruct"; +export * from "../sharing/structs/identifiableStruct"; +export * from "../sharing/structs/shareable"; +export * from "../sharing/structs/sharedStruct"; +export * from "../sharing/structs/taggedStruct"; +export * from "../sharing/structs/wrapper"; +export * from "../sharing/collections/hashData"; +export * from "../sharing/collections/sharedLinkedList"; +export * from "../sharing/collections/concurrentMap"; +export * from "../sharing/collections/sharedMap"; +export * from "../sharing/collections/sharedResizableArray"; +export * from "../sharing/collections/sharedSet"; +export * from "../sharing/collections/xxhash32"; +export * from "../sharing/sharedDiagnostics"; +export * from "../sharing/sharedNode"; +export * from "../sharing/sharedNodeAdapter"; +export * from "../sharing/sharedNodeArray"; +export * from "../sharing/sharedObjectAllocator"; +export * from "../sharing/sharedParserState"; +export * from "../sharing/sharedSymbol"; export * from "../threading/condition"; export * from "../threading/countdownEvent"; export * from "../threading/lockable"; @@ -20,24 +40,6 @@ export * from "../threading/sharedLockable"; export * from "../threading/sharedMutex"; export * from "../threading/threadPool"; export * from "../threading/uniqueLock"; -export * from "../sharing/collections/hashData"; -export * from "../sharing/collections/sharedLinkedList"; -export * from "../sharing/collections/sharedMap"; -export * from "../sharing/collections/sharedResizableArray"; -export * from "../sharing/collections/sharedSet"; -export * from "../sharing/collections/xxhash32"; -export * from "../sharing/structs/fakeSharedStruct"; -export * from "../sharing/structs/identifiableStruct"; -export * from "../sharing/structs/shareable"; -export * from "../sharing/structs/sharedStruct"; -export * from "../sharing/structs/taggedStruct"; -export * from "../sharing/sharedDiagnostics"; -export * from "../sharing/sharedNode"; -export * from "../sharing/sharedNodeAdapter"; -export * from "../sharing/sharedNodeArray"; -export * from "../sharing/sharedObjectAllocator"; -export * from "../sharing/sharedParserState"; -export * from "../sharing/sharedSymbol"; export * from "../path"; export * from "../diagnosticInformationMap.generated"; export * from "../scanner"; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 12f61f0dcec..b0c038ca842 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1,23 +1,19 @@ import { - __String, CharacterCodes, Comparer, Comparison, Debug, EqualityComparer, - isTaggedStruct, isWhiteSpaceLike, MapLike, - Queue, - SharedNodeArray, + Queue, SharedNodeArray, SortedArray, SortedReadonlyArray, - TextSpan, + TextSpan } from "./_namespaces/ts"; -import { SharedNodeBase } from "./sharing/sharedNode"; +import { SharedNode } from "./sharing/sharedNode"; import { isShareableNonPrimitive, isSharedArray } from "./sharing/structs/shareable"; -import { Tag } from "./sharing/structs/taggedStruct"; - +import { isTaggedStruct, Tag } from "./sharing/structs/taggedStruct"; /** @internal */ export const emptyArray: never[] = [] as never[]; @@ -27,7 +23,23 @@ export const emptyMap: ReadonlyMap = new Map(); export const emptySet: ReadonlySet = new Set(); /** @internal */ -export function length(array: readonly any[] | undefined): number { +export type Sequence = + | readonly T[] + | (T extends Shareable ? SharedArray : never) + | (T extends SharedNode ? SharedNodeArray : never) + ; + +function getArrayLike(sequence: Sequence): ArrayLike; +function getArrayLike(sequence: Sequence | undefined): ArrayLike | undefined; +function getArrayLike(sequence: Sequence | undefined): ArrayLike | undefined { + return !sequence || isArray(sequence) || isSharedArray(sequence) ? sequence : + sequence instanceof SharedNodeArray ? sequence.items : + undefined; +} + +/** @internal */ +export function length(sequence: Sequence | undefined): number { + const array = getArrayLike(sequence); return array ? array.length : 0; } @@ -38,9 +50,11 @@ export function length(array: readonly any[] | undefined): number { * * @internal */ -export function forEach(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function forEach(sequence: Sequence | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + const array = getArrayLike(sequence); if (array) { - for (let i = 0; i < array.length; i++) { + const length = array.length; + for (let i = 0; i < length; i++) { const result = callback(array[i], i); if (result) { return result; @@ -55,7 +69,8 @@ export function forEach(array: readonly T[] | undefined, callback: (elemen * * @internal */ -export function forEachRight(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function forEachRight(sequence: Sequence | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + const array = getArrayLike(sequence); if (array) { for (let i = array.length - 1; i >= 0; i--) { const result = callback(array[i], i); @@ -72,12 +87,14 @@ export function forEachRight(array: readonly T[] | undefined, callback: (e * * @internal */ -export function firstDefined(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function firstDefined(sequence: Sequence | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { + const array = getArrayLike(sequence); if (array === undefined) { return undefined; } - for (let i = 0; i < array.length; i++) { + const length = array.length; + for (let i = 0; i < length; i++) { const result = callback(array[i], i); if (result !== undefined) { return result; @@ -111,8 +128,10 @@ export function reduceLeftIterator(iterator: Iterable | undefined, f: ( } /** @internal */ -export function zipWith(arrayA: readonly T[], arrayB: readonly U[], callback: (a: T, b: U, index: number) => V): V[] { +export function zipWith(sequenceA: Sequence, sequenceB: Sequence, callback: (a: T, b: U, index: number) => V): V[] { const result: V[] = []; + const arrayA = getArrayLike(sequenceA); + const arrayB = getArrayLike(sequenceB); Debug.assertEqual(arrayA.length, arrayB.length); for (let i = 0; i < arrayA.length; i++) { result.push(callback(arrayA[i], arrayB[i], i)); @@ -149,10 +168,14 @@ export function every(array: readonly T[], callback: (element: T /** @internal */ export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; /** @internal */ -export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; -export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean { +export function every(sequence: Sequence | undefined, callback: (element: T, index: number) => element is U): sequence is Sequence | undefined; +/** @internal */ +export function every(sequence: Sequence | undefined, callback: (element: T, index: number) => boolean): boolean; +export function every(sequence: Sequence | undefined, callback: (element: T, index: number) => boolean): boolean { + const array = getArrayLike(sequence); if (array) { - for (let i = 0; i < array.length; i++) { + const length = array.length; + for (let i = 0; i < length; i++) { if (!callback(array[i], i)) { return false; } @@ -167,13 +190,15 @@ export function every(array: readonly T[] | undefined, callback: (element: T, * * @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; +export function find(sequence: Sequence | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; /** @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; +export function find(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; /** @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { +export function find(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { + const array = getArrayLike(sequence); if (array === undefined) return undefined; - for (let i = startIndex ?? 0; i < array.length; i++) { + const length = array.length; + for (let i = startIndex ?? 0; i < length; i++) { const value = array[i]; if (predicate(value, i)) { return value; @@ -183,11 +208,12 @@ export function find(array: readonly T[] | undefined, predicate: (element: T, } /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; +export function findLast(sequence: Sequence | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; +export function findLast(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { +export function findLast(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { + const array = getArrayLike(sequence); if (array === undefined) return undefined; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { const value = array[i]; @@ -203,9 +229,11 @@ export function findLast(array: readonly T[] | undefined, predicate: (element * * @internal */ -export function findIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { +export function findIndex(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { + const array = getArrayLike(sequence); if (array === undefined) return -1; - for (let i = startIndex ?? 0; i < array.length; i++) { + const length = array.length; + for (let i = startIndex ?? 0; i < length; i++) { if (predicate(array[i], i)) { return i; } @@ -214,7 +242,8 @@ export function findIndex(array: readonly T[] | undefined, predicate: (elemen } /** @internal */ -export function findLastIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { +export function findLastIndex(sequence: Sequence | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { + const array = getArrayLike(sequence); if (array === undefined) return -1; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { if (predicate(array[i], i)) { @@ -230,8 +259,10 @@ export function findLastIndex(array: readonly T[] | undefined, predicate: (el * * @internal */ -export function findMap(array: readonly T[], callback: (element: T, index: number) => U | undefined): U { - for (let i = 0; i < array.length; i++) { +export function findMap(sequence: Sequence, callback: (element: T, index: number) => U | undefined): U { + const array = getArrayLike(sequence)!; + const length = array.length; + for (let i = 0; i < length; i++) { const result = callback(array[i], i); if (result) { return result; @@ -241,10 +272,12 @@ export function findMap(array: readonly T[], callback: (element: T, index: } /** @internal */ -export function contains(array: readonly T[] | undefined, value: T, equalityComparer: EqualityComparer = equateValues): boolean { +export function contains(sequence: Sequence | undefined, value: T, equalityComparer: EqualityComparer = equateValues): boolean { + const array = getArrayLike(sequence); if (array) { - for (const v of array) { - if (equalityComparer(v, value)) { + const length = array.length; + for (let i = 0; i < length; i++) { + if (equalityComparer(array[i], value)) { return true; } } @@ -253,8 +286,10 @@ export function contains(array: readonly T[] | undefined, value: T, equalityC } /** @internal */ -export function arraysEqual(a: readonly T[], b: readonly T[], equalityComparer: EqualityComparer = equateValues): boolean { - return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i])); +export function arraysEqual(sequenceA: Sequence, sequenceB: Sequence, equalityComparer: EqualityComparer = equateValues): boolean { + const arrayA = getArrayLike(sequenceA); + const arrayB = getArrayLike(sequenceB); + return arrayA.length === arrayB.length && Array.prototype.every.call(arrayA, (x: T, i: number) => equalityComparer(x, arrayB[i])); } /** @internal */ @@ -268,10 +303,12 @@ export function indexOfAnyCharCode(text: string, charCodes: readonly number[], s } /** @internal */ -export function countWhere(array: readonly T[] | undefined, predicate: (x: T, i: number) => boolean): number { +export function countWhere(sequence: Sequence | undefined, predicate: (x: T, i: number) => boolean): number { let count = 0; + const array = getArrayLike(sequence); if (array) { - for (let i = 0; i < array.length; i++) { + const length = array.length; + for (let i = 0; i < length; i++) { const v = array[i]; if (predicate(v, i)) { count++; @@ -665,22 +702,23 @@ export function mapEntries(map: ReadonlyMap | undefined, } /** @internal */ -export function some(array: readonly T[] | SharedNodeArray> | undefined): array is readonly T[] | SharedNodeArray>; +export function some(array: readonly T[] | SharedNodeArray> | undefined): array is readonly T[] | SharedNodeArray>; /** @internal */ -export function some(array: readonly T[] | SharedNodeArray> | undefined, predicate: (value: T) => boolean): boolean; +export function some(array: readonly T[] | SharedNodeArray> | undefined, predicate: (value: T) => boolean): boolean; /** @internal */ -export function some(array: readonly T[] | SharedNodeArray> | undefined, predicate?: (value: T) => boolean): boolean { +export function some(array: readonly T[] | SharedNodeArray> | undefined, predicate?: (value: T) => boolean): boolean { if (array) { if (predicate) { - const iterable = isTaggedStruct(array, Tag.NodeArray) ? SharedNodeArray.values(array) : array; - for (const v of iterable) { - if (predicate(v)) { + const arrayLike = isTaggedStruct(array, Tag.NodeArray) ? (array as SharedNodeArray).items : array; + const length = arrayLike.length; + for (let i = 0; i < length; i++) { + if (predicate(arrayLike[i])) { return true; } } } else { - return (array instanceof SharedNodeArray ? array.items.length : array.length) > 0; + return (isTaggedStruct(array, Tag.NodeArray) ? (array as SharedNodeArray).items.length : array.length) > 0; } } return false; @@ -1846,6 +1884,13 @@ export function isArray(value: any): value is readonly unknown[] { return Array.isArray(value); } +/** + * @internal + */ +export function isIterable(value: any): value is Iterable { + return value !== undefined && !isNull(value) && Symbol.iterator in value +} + /** @internal */ export function toArray(value: T | T[] | SharedArray>): T[]; /** @internal */ @@ -1855,6 +1900,11 @@ export function toArray(value: T | T[] | SharedArray>): return isSharedArray(value) ? Array.from(value) : isArray(value) ? value : [value]; } +/** @internal */ +export function iterateValues(values: ArrayLike): IterableIterator { + return Array.prototype.values.call(values); +} + /** * Tests whether a value is string * @@ -1888,7 +1938,7 @@ export function cast(value: TIn | undefined, test: if ("__tag__" in valueArg) { const tag = valueArg.__tag__ as Tag; if (tag === Tag.Node) { - const kind = (valueArg as SharedNodeBase).kind; + const kind = (valueArg as SharedNode).kind; valueArg = `[object SharedNodeBase(${Debug.formatSyntaxKind(kind)})]`; } else { @@ -2947,3 +2997,8 @@ export class Lazy { } } } + +/** @internal */ +export function dispose(obj: Disposable | undefined) { + obj?.[Symbol.dispose](); +} diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 3f2323c50aa..4622dc7c476 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -475,7 +475,7 @@ import { WithStatement, YieldExpression, } from "../_namespaces/ts"; -import { SharedNodeBase } from "../sharing/sharedNode"; +import { SharedNode } from "../sharing/sharedNode"; import { SharedNodeArray } from "../sharing/sharedNodeArray"; import { isShareableNonPrimitive } from "../sharing/structs/shareable"; @@ -7182,7 +7182,7 @@ function propagateChildrenFlags(children: NodeArray | undefined): Transfor return children ? children.transformFlags : TransformFlags.None; } -function aggregateChildrenFlags(children: MutableNodeArray | SharedNodeArray) { +function aggregateChildrenFlags(children: MutableNodeArray | SharedNodeArray) { let subtreeFlags = TransformFlags.None; const values = children instanceof SharedNodeArray ? Array.from(children.items) : children; for (const child of values) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7b0ad2445fb..ace8dd6072d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -408,7 +408,7 @@ import { } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; import { SharedDiagnostic, SharedDiagnosticMessageChain, SharedDiagnosticRelatedInformation, SharedDiagnosticWithLocation } from "./sharing/sharedDiagnostics"; -import { SharedAmdDependency, SharedCheckJsDirective, SharedCommentDirective, SharedCommentRange, SharedFileReference, SharedNodeBase, SharedPragma, SharedPragmaArguments, SharedPragmaSpan, SharedSourceFile, SharedTextRange } from "./sharing/sharedNode"; +import { SharedAmdDependency, SharedCheckJsDirective, SharedCommentDirective, SharedCommentRange, SharedFileReference, SharedNode, SharedPragma, SharedPragmaArguments, SharedPragmaSpan, SharedSourceFile, SharedTextRange } from "./sharing/sharedNode"; import { SharedNodeArray } from "./sharing/sharedNodeArray"; import { isShareableNonPrimitive } from "./sharing/structs/shareable"; import { Tag, TaggedStruct } from "./sharing/structs/taggedStruct"; @@ -461,8 +461,10 @@ function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); if (jsDoc.length) { - if (node instanceof SharedNodeBase) { - node.jsDoc = shareArray(jsDoc, n => n as unknown as SharedNodeBase) as unknown as JSDoc[]; + if (node instanceof SharedNode) { + node.jsDoc = shareArray(jsDoc, n => n as unknown as SharedNode) as unknown as JSDoc[]; } else { node.jsDoc = jsDoc; diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts index 4f2096ec720..21514184422 100644 --- a/src/compiler/performance.ts +++ b/src/compiler/performance.ts @@ -1,3 +1,5 @@ +import "./symbolDisposeShim"; + import { Debug, noop, @@ -64,6 +66,48 @@ const marks = new Map(); const counts = new Map(); const durations = new Map(); +class MeasureActivity implements Disposable { + active = false; + measureName!: string; + startMarkName!: string; + endMarkName: string | undefined; + + [Symbol.dispose](): void { + if (this.active) { + this.active = false; + if (this.endMarkName) { + mark(this.endMarkName); + } + measure(this.measureName, this.startMarkName, this.endMarkName); + if (measureActivityPool.length < measureActivityPoolSize) { + measureActivityPool.push(this); + } + } + } +} + +const measureActivityPoolSize = 3; +const measureActivityPool: MeasureActivity[] = []; + +/** + * Marks a performance event when called, and measures the performance event when the result is disposed. + * @internal + */ +export function measureActivity(measureName: string, startMarkName?: string, endMarkName?: string): Disposable | undefined { + if (!enabled) { + return undefined; + } + + const activity = measureActivityPool.pop() ?? new MeasureActivity(); + Debug.assert(!activity.active); + activity.measureName = measureName; + activity.startMarkName = startMarkName ?? `${measureName}-start-${Date.now()}`; + activity.endMarkName = endMarkName; + activity.active = true; + mark(activity.startMarkName); + return activity; +} + /** * Marks a performance event. * diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c103a885c4d..d9064e48b81 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -342,11 +342,10 @@ import { zipToModeAwareCache } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; -import { SharedMap } from "./sharing/collections/sharedMap"; +import { ConcurrentMap } from "./sharing/collections/concurrentMap"; import { adoptSharedSourceFile } from "./sharing/sharedNodeAdapter"; import { SharedParserState, SharedSourceFileEntry } from "./sharing/sharedParserState"; import { Condition } from "./threading/condition"; -import { SharedLock } from "./threading/sharedLock"; import { UniqueLock } from "./threading/uniqueLock"; export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string | undefined { @@ -412,6 +411,101 @@ export function createCompilerHost(options: CompilerOptions, setParentNodes?: bo return createCompilerHostWorker(options, setParentNodes); } +/** @internal */ +export function makeCompilerHostParallel( + host: CompilerHost, + threadPool: ThreadPool, + setParentNodes: boolean | undefined, +): CompilerHost { + Debug.assert(!host.threadPool && !host.requestSourceFile, "Compiler host may already be parallelized."); + + const sharedEntryMap = new Map(); + const parserState = new SharedParserState(); + const savedGetSourceFile = host.getSourceFile; + host.threadPool = threadPool; + host.requestSourceFile = (fileName, languageVersionOrOptions, shouldCreateNewSourceFile) => { + using _measure = performance.measureActivity("Parallel: Request Source File", "beforeParserPausedRequest", "afterParserPausedRequest"); + + if (!ConcurrentMap.has(parserState.files, fileName)) { + const entry = new SharedSourceFileEntry( + parserState, + !!host.createHash, + !!setParentNodes, + fileName, + typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions, + typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined, + shouldCreateNewSourceFile); + if (ConcurrentMap.insert(parserState.files, fileName, entry)) { + // we inserted the entry, queue a task to parse it + threadPool.queueWorkItem("Program.requestSourceFile", entry); + } + } + + // // quick check before allocating an entry + // { + // using _ = new SharedLock(parserState.sharedMutex); + // if (SharedMap.has(parserState.files, fileName)) { + // return; + // } + // } + + // const entry = new SharedSourceFileEntry( + // parserState, + // !!host.createHash, + // !!setParentNodes, + // fileName, + // typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions, + // typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined, + // shouldCreateNewSourceFile); + + // using _ = new UniqueLock(parserState.sharedMutex); + // if (!SharedMap.has(parserState.files, fileName)) { + // SharedMap.set(parserState.files, fileName, entry); + // // we inserted the entry, queue a task to parse it + // threadPool.queueWorkItem("Program.requestSourceFile", entry); + // } + }; + host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { + using _ = performance.measureActivity("Parallel: Get Source File", "beforeParserPausedRead", "afterParserPausedRead"); + + const sharedFileEntry = ConcurrentMap.get(parserState.files, fileName); + + // let sharedFileEntry: SharedSourceFileEntry | undefined; + // { + // using _ = new SharedLock(parserState.sharedMutex); + // sharedFileEntry = SharedMap.get(parserState.files, fileName); + // } + + if (sharedFileEntry) { + let file = sharedEntryMap.get(sharedFileEntry); + if (file !== undefined) { + return file || undefined; + } + + // wait until the file has actually been parsed before we proceed. + { + using lck = new UniqueLock(sharedFileEntry.fileMutex); + Condition.wait(sharedFileEntry.fileCondition, lck, () => sharedFileEntry!.done || sharedFileEntry!.error); + } + + // if the worker thread reported a crash, we should crash the main thread. + if (sharedFileEntry.error) { + host.threadPool?.abort(); + sys.exit(-1); + } + + file = sharedFileEntry.file && adoptSharedSourceFile(sharedFileEntry.file, parseNodeFactory); + if (file) { + file.bindDiagnostics = []; + } + return file; + } + + return savedGetSourceFile.call(host, fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); + }; + return host; +} + /** @internal */ export function createGetSourceFile( readFile: ProgramHost["readFile"], @@ -483,25 +577,6 @@ export function createWriteFileMeasuringIO( }; } -/** @internal */ -export function createRequestSourceFile(threadPool: ThreadPool, setParentNodes: boolean | undefined): CompilerHost["requestSourceFile"] { - return (parserState, fileName, languageVersionOrOptions, shouldCreateNewSourceFile, setFileVersion = false) => { - using _ = new UniqueLock(parserState.sharedMutex); - if (!SharedMap.has(parserState.files, fileName)) { - const entry = new SharedSourceFileEntry( - parserState, - setFileVersion, - !!setParentNodes, - fileName, - typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions, - typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined, - shouldCreateNewSourceFile); - SharedMap.set(parserState.files, fileName, entry); - threadPool.queueWorkItem("Program.requestSourceFile", entry); - } - }; -} - /** @internal */ export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system: System = sys, workerThreads?: WorkerThreadsHost, threadPool?: ThreadPool, overideObjectAllocator?: ObjectAllocator): CompilerHost { const existingDirectories = new Map(); @@ -525,7 +600,6 @@ export function createCompilerHostWorker(options: CompilerOptions, setParentNode const newLine = getNewLineCharacter(options); const realpath = system.realpath && ((path: string) => system.realpath!(path)); const compilerHost: CompilerHost = { - requestSourceFile: threadPool && createRequestSourceFile(threadPool, setParentNodes), getSourceFile: createGetSourceFile(fileName => compilerHost.readFile(fileName), () => options, setParentNodes, overideObjectAllocator), getDefaultLibLocation, getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)), @@ -549,8 +623,10 @@ export function createCompilerHostWorker(options: CompilerOptions, setParentNode createDirectory: d => system.createDirectory(d), createHash: maybeBind(system, system.createHash), workerThreads, - threadPool, }; + if (threadPool) { + makeCompilerHostParallel(compilerHost, threadPool, setParentNodes); + } return compilerHost; } @@ -3613,18 +3689,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return redirect; } - // Get source file from normalized fileName - function* findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined, currentNodeModulesDepth: number): Generator { - tracing?.push(tracing.Phase.Program, "findSourceFile", { - fileName, - isDefaultLib: isDefaultLib || undefined, - fileIncludeKind: (FileIncludeKind as any)[reason.kind], - }); - const result = yield* findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId, currentNodeModulesDepth); - tracing?.pop(); - return result; - } - function getCreateSourceFileOptions(fileName: string, moduleResolutionCache: ModuleResolutionCache | undefined, host: CompilerHost, options: CompilerOptions): CreateSourceFileOptions { // It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache // and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way @@ -3637,7 +3701,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator }; } - function* findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined, currentNodeModulesDepth: number): Generator { + // Get source file from normalized fileName + function* findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined, currentNodeModulesDepth: number): Generator { + using _ = tracing?.traceActivity(tracing.Phase.Program, "findSourceFile", { + fileName, + isDefaultLib: isDefaultLib || undefined, + fileIncludeKind: (FileIncludeKind as any)[reason.kind], + }); + const path = toPath(fileName); if (useSourceOfProjectReferenceRedirect) { let source = getSourceOfProjectReferenceRedirect(path); @@ -3736,38 +3807,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // We haven't looked for this file, do so now and cache result const sourceFileOptions = getCreateSourceFileOptions(fileName, moduleResolutionCache, host, options); - let fileParsedInBackground = false; - let file: SourceFile | undefined; - if (parserState) { - let sharedFileEntry: SharedSourceFileEntry | undefined; - { - using _ = new SharedLock(parserState.sharedMutex); - sharedFileEntry = SharedMap.get(parserState.files, fileName); - } - if (sharedFileEntry) { - using lck = new UniqueLock(sharedFileEntry.fileMutex); - Condition.wait(sharedFileEntry.fileCondition, lck, () => sharedFileEntry!.done || sharedFileEntry!.error); - if (sharedFileEntry.error) { - host.threadPool?.abort(); - sys.exit(-1); - } - file = sharedFileEntry.file && adoptSharedSourceFile(sharedFileEntry.file, parseNodeFactory); - if (file) { - file.bindDiagnostics = []; - } - fileParsedInBackground = true; - } - } - - if (!fileParsedInBackground) { - file = host.getSourceFile( - fileName, - sourceFileOptions, - hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]), - shouldCreateNewSourceFile, - ); - } - + const file = host.getSourceFile( + fileName, + sourceFileOptions, + hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]), + shouldCreateNewSourceFile, + ); if (packageId) { const packageIdKey = packageIdToString(packageId); @@ -5152,7 +5197,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function* requestFile(fileName: string) { if (parserState && host.requestSourceFile) { - host.requestSourceFile?.(parserState, fileName, getEmitScriptTarget(options)); + host.requestSourceFile?.(fileName, getEmitScriptTarget(options)); yield; } } diff --git a/src/compiler/sharing/atomicValue.ts b/src/compiler/sharing/atomicValue.ts new file mode 100644 index 00000000000..91e82de9d03 --- /dev/null +++ b/src/compiler/sharing/atomicValue.ts @@ -0,0 +1,127 @@ +import { Shared, SharedStructBase } from "./structs/sharedStruct"; + +/** @internal */ +@Shared() +export class AtomicValue extends SharedStructBase { + @Shared() unsafeValue: T; + + constructor(value: T) { + super(); + this.unsafeValue = value; + } + + static load(self: AtomicValue) { + return Atomics.load(self, "unsafeValue"); + } + + static store(self: AtomicValue, value: T) { + return Atomics.store(self, "unsafeValue", value); + } + + static exchange(self: AtomicValue, value: T) { + return Atomics.exchange(self, "unsafeValue", value); + } + + static compareExchange(self: AtomicValue, expectedValue: T, replacementValue: T) { + return Atomics.compareExchange(self, "unsafeValue", expectedValue, replacementValue); + } + + static compareAndSet(self: AtomicValue, expectedValue: T, replacementValue: T) { + return expectedValue === AtomicValue.compareExchange(self, expectedValue, replacementValue); + } + + static add(self: AtomicValue, value: number) { + let currentValue = AtomicValue.load(self); + while (!AtomicValue.compareAndSet(self, currentValue, (currentValue + value) >> 0)) { + currentValue = AtomicValue.load(self); + } + return currentValue; + } + + static sub(self: AtomicValue, value: number) { + let currentValue = AtomicValue.load(self); + while (!AtomicValue.compareAndSet(self, currentValue, (currentValue - value) >> 0)) { + currentValue = AtomicValue.load(self); + } + return currentValue; + } + + static increment(self: AtomicValue) { + return AtomicValue.add(self, 1); + } + + static decrement(self: AtomicValue) { + return AtomicValue.sub(self, 1); + } +} + +/** @internal */ +export class AtomicRef { + private _value: AtomicValue | undefined; + + constructor(value: AtomicValue | undefined) { + this._value = value; + } + + get disposed() { + return !this._value; + } + + get value() { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.load(this._value); + } + + set value(value) { + if (!this._value) throw new ReferenceError("Object is disposed"); + AtomicValue.store(this._value, value); + } + + unsafeGet() { + if (!this._value) throw new ReferenceError("Object is disposed"); + return this._value.unsafeValue; + } + + unsafeSet(value: T) { + if (!this._value) throw new ReferenceError("Object is disposed"); + this._value.unsafeValue = value; + } + + exchange(value: T) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.exchange(this._value, value); + } + + compareExchange(expectedValue: T, replacementValue: T) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.compareExchange(this._value, expectedValue, replacementValue); + } + + increment(this: AtomicRef) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.increment(this._value); + } + + decrement(this: AtomicRef) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.decrement(this._value); + } + + add(this: AtomicRef, value: number) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.add(this._value, value); + } + + sub(this: AtomicRef, value: number) { + if (!this._value) throw new ReferenceError("Object is disposed"); + return AtomicValue.sub(this._value, value); + } + + dispose() { + this._value = undefined; + } + + [Symbol.dispose]() { + this._value = undefined; + } +} \ No newline at end of file diff --git a/src/compiler/sharing/collections/concurrentMap.ts b/src/compiler/sharing/collections/concurrentMap.ts new file mode 100644 index 00000000000..704f759ca57 --- /dev/null +++ b/src/compiler/sharing/collections/concurrentMap.ts @@ -0,0 +1,516 @@ +import { iterateValues } from "../../core"; +import { Debug } from "../../debug"; +import { sys } from "../../sys"; +import { Mutex } from "../../threading/mutex"; +import { ScopedLock } from "../../threading/scopedLock"; +import { UniqueLock } from "../../threading/uniqueLock"; +import { AtomicValue } from "../atomicValue"; +import { Shared, SharedStructBase } from "../structs/sharedStruct"; +import { Tag, Tagged } from "../structs/taggedStruct"; +import { StructWrapperTypes } from "../structs/wrapper"; +import { generateHashSeed, identityHash } from "./hash"; +import { getPrime } from "./hashData"; + +// Portions of the following are derived from .NET Core. See ThirdPartyNoticeText.txt in the root of this repository +// for the related license notice. + +@Shared() +class Node, V extends NonNullable> extends SharedStructBase { + @Shared() readonly key: K; + @Shared() value: V; + @Shared() readonly next: AtomicValue | undefined>; + @Shared() readonly hashCode: number; + + constructor(key: K, value: V, hashCode: number, next?: Node) { + super(); + this.key = key; + this.value = value; + this.hashCode = hashCode; + this.next = new AtomicValue(next); + } +} + +@Shared() +class Tables, V extends NonNullable> extends SharedStructBase { + @Shared() readonly buckets: SharedArray | undefined>>; + @Shared() readonly locks: SharedArray; + @Shared() readonly countsPerLock: SharedArray; + @Shared() readonly seed: number | undefined; + + constructor(buckets: SharedArray | undefined>>, locks: SharedArray, countsPerLock: SharedArray, seed?: number) { + super(); + Debug.assert(Array.prototype.every.call(buckets, x => x !== undefined)); + Debug.assert(Array.prototype.every.call(locks, x => x !== undefined)); + Debug.assert(Array.prototype.every.call(countsPerLock, x => x !== undefined)); + this.buckets = buckets; + this.locks = locks; + this.countsPerLock = countsPerLock; + this.seed = seed; + } +} + +const DefaultCapacity = 31; +const MaxLockNumber = 1024; +const SHARED_ARRAY_MAX_LENGTH = 2 ** 14 - 2; +const MAX_INT32 = 2 ** 31 - 1; + +const WILDCARD = Symbol(); +const EXIST = Symbol(); +const NOT_EXIST = Symbol(); + +type WILDCARD = typeof WILDCARD; +type EXIST = typeof EXIST; +type NOT_EXIST = typeof NOT_EXIST; + +/** @internal */ +@Shared() +export class ConcurrentMap, V extends NonNullable> extends Tagged(SharedStructBase, Tag.ConcurrentMap) { + declare [StructWrapperTypes]: [ + [typeof ConcurrentMap, { + size(): number; + has(key: K): boolean; + get(key: K): V | undefined; + set(key: K, value: V): void; + delete(key: K, expectedValue?: V): V | undefined; + insert(key: K, value: V): boolean; + replace(key: K, expectedValue: V, replacementValue: V): V | undefined; + exchange(key: K, value: V | undefined): V | undefined; + compareExchange(key: K, expectedValue: V | undefined, replacementValue: V | undefined): V | undefined; + clear(): void; + keys(): IterableIterator; + values(): IterableIterator; + entries(): IterableIterator<[K, V]>; + }] + ]; + + @Shared() private readonly _tables: AtomicValue>; + @Shared() private _budget: number; + @Shared() private readonly _growLockArray: boolean; + + constructor(); + constructor(items: ConcurrentMap | Iterable<[K, V]>); + constructor(concurrencyLevel: number, items: ConcurrentMap | Iterable<[K, V]>); + constructor(concurrencyLevel: number, capacity: number); + constructor(concurrencyLevelOrItems?: number | ConcurrentMap | Iterable<[K, V]>, capacityOrItems?: number | ConcurrentMap | Iterable<[K, V]>) { + let concurrencyLevel: number | undefined; + let capacity: number | undefined; + let items: ConcurrentMap | Iterable<[K, V]> | undefined; + if (typeof concurrencyLevelOrItems === "object") { + items = concurrencyLevelOrItems; + concurrencyLevel = sys.cpuCount?.() ?? 1; + capacity = ConcurrentMap.getCapacityFromItems(items); + } + else { + concurrencyLevel = concurrencyLevelOrItems ?? sys.cpuCount?.() ?? 1; + if (typeof capacityOrItems === "object") { + items = capacityOrItems; + capacity = ConcurrentMap.getCapacityFromItems(items); + } + else { + capacity = capacityOrItems ?? DefaultCapacity; + } + } + + Debug.assert(concurrencyLevel >= 1); + + super(); + + if (capacity < concurrencyLevel) capacity = concurrencyLevel; + capacity = getPrime(capacity); + + const locks = new SharedArray(concurrencyLevel); + for (let i = 0; i < concurrencyLevel; i++) { + locks[i] = new Mutex(); + } + + const countsPerLock = new SharedArray(concurrencyLevel); + Array.prototype.fill.call(countsPerLock, 0); + + const buckets = new SharedArray | undefined>>(capacity); + for (let i = 0; i < capacity; i++) { + buckets[i] = new AtomicValue | undefined>(/*value*/ undefined); + } + + this._tables = new AtomicValue(new Tables(buckets, locks, countsPerLock)); + this._growLockArray = arguments.length > 0; + this._budget = (buckets.length / locks.length) | 0; + + if (items) { + if (items instanceof ConcurrentMap) { + items = ConcurrentMap.entries(items); + } + + for (const [key, value] of items) { + const previousValue = ConcurrentMap.compareExchangeInternal( + this, + AtomicValue.load(this._tables), + key, + /*hashCode*/ undefined, + NOT_EXIST, + value, + /*acquireLock*/ false + ) + Debug.assert(previousValue === undefined, "duplicate key in items"); + } + + if (this._budget === 0) { + const tables = AtomicValue.load(this._tables); + this._budget = (tables.buckets.length / tables.locks.length) | 0; + } + } + } + + private static getCapacityFromItems, V extends NonNullable>(items: ConcurrentMap | Iterable<[K, V]>) { + if (items instanceof ConcurrentMap) return Math.max(DefaultCapacity, ConcurrentMap.size(items)); + if (items instanceof Map) return Math.max(DefaultCapacity, items.size); + if (items instanceof Set) return Math.max(DefaultCapacity, items.size); + if (Array.isArray(items)) return Math.max(DefaultCapacity, items.length); + return DefaultCapacity; + } + + static size, V extends NonNullable>(self: ConcurrentMap) { + using _ = new ScopedLock(AtomicValue.load(self._tables).locks); + return ConcurrentMap.getSizeNoLocks(self); + } + + static has, V extends NonNullable>(self: ConcurrentMap, key: K) { + return ConcurrentMap.get(self, key) !== undefined; + } + + static get, V extends NonNullable>(self: ConcurrentMap, key: K) { + const tables = AtomicValue.load(self._tables); + const hashCode = identityHash(key, tables.seed); + for (let node: Node | undefined = ConcurrentMap.getBucket(tables, hashCode); node; node = AtomicValue.load(node.next)) { + if (hashCode === node.hashCode && key === node.key) { + return node.value; + } + } + return undefined; + } + + static set, V extends NonNullable>(self: ConcurrentMap, key: K, value: V) { + ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + WILDCARD, + value + ); + } + + static insert, V extends NonNullable>(self: ConcurrentMap, key: K, value: V) { + return undefined === ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + NOT_EXIST, + value + ); + } + + static replace, V extends NonNullable>(self: ConcurrentMap, key: K, expectedValue: V, replacementValue: V) { + return undefined !== ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + expectedValue, + replacementValue + ); + } + + static delete, V extends NonNullable>(self: ConcurrentMap, key: K, expectedValue?: V) { + return ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + expectedValue ?? EXIST, + NOT_EXIST + ); + } + + static exchange, V extends NonNullable>(self: ConcurrentMap, key: K, value: V | undefined) { + return ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + WILDCARD, + value ?? NOT_EXIST + ); + } + + static compareExchange, V extends NonNullable>(self: ConcurrentMap, key: K, expectedValue: V | undefined, replacementValue: V | undefined) { + return ConcurrentMap.compareExchangeInternal( + self, + AtomicValue.load(self._tables), + key, + /*hashCode*/ undefined, + expectedValue ?? NOT_EXIST, + replacementValue ?? NOT_EXIST + ); + } + + private static compareExchangeInternal, V extends NonNullable>( + self: ConcurrentMap, + tables: Tables, + key: K, + hashCode = identityHash(key, tables.seed), + expectedValue: V | WILDCARD | EXIST | NOT_EXIST, + replacementValue: V | NOT_EXIST, + acquireLock = true + ) { + let seed = tables.seed; + while (true) { + const locks = tables.locks; + const { bucket, lockNo } = ConcurrentMap.getBucketAndLock(tables, hashCode); + let resizeDesired = false; + let forceRehash = false; + + // perf: if we're deleting the value and there are no entries for that bucket, we can exit early. We can also + // perf: if we're updating a value that must exist and there are no entries for that bucket, we can exit early. + if ((replacementValue === NOT_EXIST || expectedValue === EXIST) && tables.countsPerLock[lockNo] === 0) { + return undefined; + } + + // block ensures we release the lock below prior to attempting to grow the table + { + using _ = acquireLock ? new UniqueLock(locks[lockNo]) : undefined; + if (tables !== AtomicValue.load(self._tables)) { + tables = AtomicValue.load(self._tables); + if (seed !== tables.seed) { + seed = tables.seed; + hashCode = identityHash(key, tables.seed); + } + continue; + } + + let prev: Node | undefined; + let collisionCount = 0; + for (let node: Node | undefined = AtomicValue.load(bucket); node; node = AtomicValue.load(node.next)) { + Debug.assert((prev === undefined && node === AtomicValue.load(bucket)) || AtomicValue.load(prev!.next) === node); + if (hashCode === node.hashCode && key === node.key) { + const currentValue = node.value; + // We've matched the key, now match the value. + if (expectedValue === NOT_EXIST) { + // If we are inserting (`expectedValue === NOT_EXIST`) then we may not update if an entry exists. + return currentValue; + } + else if (expectedValue === WILDCARD || expectedValue === EXIST || expectedValue === currentValue) { + // We are either unconditionally setting (`expectedValue === WILDCARD`), updating/deleting + // (`expectedValue === EXIST`), or deleting/replacing (`expectedValue === currentValue`). + Debug.assert(expectedValue !== NOT_EXIST as unknown); + if (replacementValue === NOT_EXIST) { + // performing delete + if (!prev) { + AtomicValue.store(bucket, AtomicValue.load(node.next)); + } + else { + AtomicValue.store(prev.next, AtomicValue.load(node.next)); + } + tables.countsPerLock[lockNo]--; + } + else { + // performing unconditional set or update update + if (isLockFree(replacementValue)) { + node.value = replacementValue; + } + else { + const newNode = new Node(node.key, replacementValue, hashCode, AtomicValue.load(node.next)); + if (!prev) { + AtomicValue.store(bucket, newNode); + } + else { + AtomicValue.store(prev.next, newNode); + } + } + } + } + return currentValue; + } + prev = node; + if (typeof key === "string") { + collisionCount++; + } + } + + // if we failed to find a matching key and we are either deleting or updating, we exit early indicating + // there was no match. + if (replacementValue === NOT_EXIST || expectedValue === EXIST) { + return undefined; + } + + // otherwise, we are inserting or setting so we can add the entry. + const resultNode = new Node(key, replacementValue, hashCode, AtomicValue.load(bucket)); + AtomicValue.store(bucket, resultNode); + tables.countsPerLock[lockNo]++; + + if (tables.countsPerLock[lockNo] > self._budget) { + resizeDesired = true; + } + + if (typeof key === "string" && collisionCount > 10 && tables.seed === undefined) { + forceRehash = true; + } + } + + if (resizeDesired || forceRehash) { + ConcurrentMap.growTable(self, tables, resizeDesired, forceRehash); + } + + return undefined; + } + } + + static clear, V extends NonNullable>(self: ConcurrentMap) { + using _ = new ScopedLock(AtomicValue.load(self._tables).locks); + if (ConcurrentMap.allBucketsAreEmpty(self)) { + return; + } + + const tables = AtomicValue.load(self._tables); + const buckets = new SharedArray | undefined>>(getPrime(DefaultCapacity)); + for (let i = 0; i < buckets.length; i++) { + buckets[i] = new AtomicValue | undefined>(/*value*/ undefined); + } + + const counts = new SharedArray(tables.countsPerLock.length); + Array.prototype.fill.call(counts, 0); + + const newTables = new Tables(buckets, tables.locks, counts, tables.seed); + AtomicValue.store(self._tables, newTables); + self._budget = Math.max(1, (newTables.buckets.length / newTables.locks.length) | 0); + } + + static * keys, V extends NonNullable>(self: ConcurrentMap): IterableIterator { + const buckets = AtomicValue.load(self._tables).buckets; + for (let i = 0; i < buckets.length; i++) { + for (let node: Node | undefined = AtomicValue.load(buckets[i]); node; node = AtomicValue.load(node.next)) { + yield node.key; + } + } + } + + static * values, V extends NonNullable>(self: ConcurrentMap): IterableIterator { + const buckets = AtomicValue.load(self._tables).buckets; + for (let i = 0; i < buckets.length; i++) { + for (let node: Node | undefined = AtomicValue.load(buckets[i]); node; node = AtomicValue.load(node.next)) { + yield node.value; + } + } + } + + static * entries, V extends NonNullable>(self: ConcurrentMap): IterableIterator<[K, V]> { + const buckets = AtomicValue.load(self._tables).buckets; + for (let i = 0; i < buckets.length; i++) { + for (let node: Node | undefined = AtomicValue.load(buckets[i]); node; node = AtomicValue.load(node.next)) { + yield [node.key, node.value]; + } + } + } + + private static growTable, V extends NonNullable>(self: ConcurrentMap, tables: Tables, resizeDesired: boolean, forceRehashIfNonRandomized: boolean) { + using _first = new UniqueLock(tables.locks[0]); + if (tables !== AtomicValue.load(self._tables)) { + return; + } + + let newLength = tables.buckets.length; + let newSeed: number | undefined; + if (forceRehashIfNonRandomized && tables.seed === undefined) { + newSeed = generateHashSeed(); + } + + if (resizeDesired) { + if (newSeed === undefined && ConcurrentMap.getSizeNoLocks(self) < tables.buckets.length / 4) { + self._budget *= 2; + if (self._budget > (self._budget | 0)) { + self._budget = MAX_INT32; + } + return; + } + + if ((newLength = tables.buckets.length * 2) < 0 || + (newLength = getPrime(newLength)) > SHARED_ARRAY_MAX_LENGTH) { + newLength = SHARED_ARRAY_MAX_LENGTH; + self._budget = MAX_INT32; + } + } + + let newLocks = tables.locks; + if (self._growLockArray && tables.locks.length < MaxLockNumber) { + newLocks = new SharedArray(tables.locks.length * 2); + for (let i = 0; i < tables.locks.length; i++) { + newLocks[i] = tables.locks[i]; + } + for (let i = tables.locks.length; i < newLocks.length; i++) { + newLocks[i] = new Mutex(); + } + } + + const newBuckets = new SharedArray | undefined>>(newLength); + for (let i = 0; i < newLength; i++) { + newBuckets[i] = new AtomicValue | undefined>(/*value*/ undefined); + } + + const newCountsPerLock = new SharedArray(newLocks.length); + Array.prototype.fill.call(newCountsPerLock, 0); + + const newTables = new Tables(newBuckets, newLocks, newCountsPerLock, newSeed ?? tables.seed); + + using _rest = new ScopedLock(Array.prototype.slice.call(tables.locks, 1)); + for (const bucket of iterateValues(tables.buckets)) { + let current: Node | undefined = AtomicValue.load(bucket); + while (current) { + let hashCode = newSeed === undefined ? current.hashCode : identityHash(current.key, newSeed); + const next: Node | undefined = AtomicValue.load(current.next); + let { lockNo: newLockNo, bucket: newBucket } = ConcurrentMap.getBucketAndLock(newTables, hashCode); + AtomicValue.store(newBucket, new Node(current.key, current.value, hashCode, AtomicValue.load(newBucket))); + newCountsPerLock[newLockNo]++; + Debug.assert(newCountsPerLock[newLockNo] <= MAX_INT32); + current = next; + } + } + + self._budget = Math.max(1, (newBuckets.length / newLocks.length) | 0); + AtomicValue.store(self._tables, newTables); + } + + private static getSizeNoLocks, V extends NonNullable>(self: ConcurrentMap) { + let count = 0; + const tables = AtomicValue.load(self._tables); + const countsPerLock = tables.countsPerLock; + for (let i = 0; i < countsPerLock.length; i++) { + count += countsPerLock[i]; + } + return count; + } + + private static getBucket, V extends NonNullable>(tables: Tables, hashCode: number) { + const buckets = tables.buckets; + const bucketNo = (hashCode >>> 0) % buckets.length; + const bucket = buckets[bucketNo]; + return AtomicValue.load(bucket); + } + + private static getBucketAndLock, V extends NonNullable>(tables: Tables, hashCode: number) { + const buckets = tables.buckets; + const bucketNo = (hashCode >>> 0) % buckets.length; + const lockNo = bucketNo % tables.locks.length; + const bucket = buckets[bucketNo]; + return { bucket, lockNo }; + } + + private static allBucketsAreEmpty, V extends NonNullable>(self: ConcurrentMap) { + return Array.prototype.some.call(AtomicValue.load(self._tables).countsPerLock, x => x !== 0); + } +} + +function isLockFree(value: Shareable) { + if (Atomics.isLockFree(8)) return true; + if (typeof value === "number") return isFinite(value) && (value === (value >>> 0) || value === (value >> 0)); + return true; +} diff --git a/src/compiler/sharing/collections/deque.ts b/src/compiler/sharing/collections/deque.ts new file mode 100644 index 00000000000..56350d3bb03 --- /dev/null +++ b/src/compiler/sharing/collections/deque.ts @@ -0,0 +1,126 @@ +import { Shared, SharedStructBase } from "../structs/sharedStruct"; + +@Shared() +class Ring extends SharedStructBase { + @Shared() readonly size: number; + @Shared() readonly mask: number; + @Shared() readonly segment: SharedArray; + + constructor(size: number) { + super(); + const mask = size - 1; + if (size & mask) throw new RangeError("Must be a power of 2"); + + this.size = size; + this.mask = mask; + this.segment = new SharedArray(size); + } + + static size(self: Ring) { + return Atomics.load(self, "size"); + } + + static get(self: Ring, i: number) { + return Atomics.load(self.segment, i & Atomics.load(self, "mask")); + } + + static put(self: Ring, i: number, value: T) { + Atomics.store(self.segment, i & Atomics.load(self, "mask"), value); + } + + static grow(self: Ring, bottom: number, top: number) { + const size = Atomics.load(self, "size"); + const newSize = (size << 1) >>> 0; + if (newSize < size) throw new RangeError(); + const a: Ring = new Ring(newSize); + for (let i = top; i < bottom; i++) { + Ring.put(a, i, Ring.get(self, i)); + } + return a; + } + + static shrink(self: Ring, bottom: number, top: number) { + const size = Atomics.load(self, "size"); + if (size <= 1) return self; + const a: Ring = new Ring(size >>> 1); + for (let i = top; i < bottom; i++) { + Ring.put(a, i, Ring.get(self, i)); + } + return a; + } +} + +const kDequeInitialCapacity = 1 << 5; +const kDequeTrimFactor = 3; + +/** + * Chase-Lev Deque based on "Dynamic Circular Work-Stealing Deque" + * @see {@link https://dl.acm.org/doi/10.1145/1073970.1073974} + * @template {Shareable} T + */ +@Shared() +export class Deque extends SharedStructBase { + @Shared() readonly top: number; + @Shared() readonly bottom: number; + @Shared() readonly array: Ring; + + constructor() { + super(); + this.top = 0; + this.bottom = 0; + this.array = new Ring(kDequeInitialCapacity); + } + + static pushBottom(self: Deque, value: T) { + const bottom = Atomics.load(self, "bottom"); + const top = Atomics.load(self, "top"); + let array = Atomics.load(self, "array"); + if (bottom - top > Ring.size(array) - 1) { + array = Ring.grow(array, bottom, top); + Atomics.store(self, "array", array); + } + Ring.put(array, bottom, value); + Atomics.store(self, "bottom", bottom + 1); + } + + static popBottom(self: Deque) { + const bottom = Atomics.load(self, "bottom") - 1; + const array = Atomics.load(self, "array"); + Atomics.store(self, "bottom", bottom); + const top = Atomics.load(self, "top"); + const size = bottom - top; + if (size < 0) { + Atomics.store(self, "bottom", top); + return undefined; + } + let value = Ring.get(array, bottom); + if (size > 0) { + Deque.trim(self, bottom, top); + return value; + } + const result = top === Atomics.compareExchange(self, "top", top, top + 1); + Atomics.store(self, "bottom", top + 1); + return result ? value : undefined; + } + + static steal(self: Deque) { + const top = Atomics.load(self, "top"); + const bottom = Atomics.load(self, "bottom"); + const array = Atomics.load(self, "array"); + if (bottom - top <= 0) { + return undefined; + } + const value = Ring.get(array, top); + if (top !== Atomics.compareExchange(self, "top", top, top + 1)) { + return undefined; + } + return value; + } + + private static trim(self: Deque, bottom: number, top: number) { + const array = Atomics.load(self, "array"); + if (bottom - top < Ring.size(array) / kDequeTrimFactor) { + Atomics.store(self, "array", Ring.shrink(array, bottom, top)); + } + } +} diff --git a/src/compiler/sharing/collections/hash.ts b/src/compiler/sharing/collections/hash.ts new file mode 100644 index 00000000000..e69301507d3 --- /dev/null +++ b/src/compiler/sharing/collections/hash.ts @@ -0,0 +1,37 @@ +import { hasProperty } from "../../core"; +import { Debug } from "../../debug"; +import { sys } from "../../sys"; +import { IdentifiableStruct } from "../structs/identifiableStruct"; +import { xxh32string } from "./xxhash32"; + +const defaultStringSeed = sys.stringSeed ?? generateHashSeed(); + +/** @internal */ +export function generateHashSeed() { + return Math.floor(Math.random() * 0xffffffff) >>> 0; +} + +/** + * Get a hashcode for a value that is consistent across multiple threads. + * @internal + */ +export function identityHash(value: Shareable, seed?: number): number { + if (value === undefined || value === null) { // eslint-disable-line no-null/no-null -- necessary comparison + return 0; + } + switch (typeof value) { + case "number": + return value >> 0; + case "boolean": + return value ? 1 : 0; + case "string": + return xxh32string(value, seed ?? defaultStringSeed) >> 0; + case "object": + if (hasProperty(value, "__hash__")) { + return (value as IdentifiableStruct).__hash__ >> 0; + } + return 0; + default: + Debug.assertNever(value); + } +} diff --git a/src/compiler/sharing/collections/hashData.ts b/src/compiler/sharing/collections/hashData.ts index e91106131d8..532ad125bdf 100644 --- a/src/compiler/sharing/collections/hashData.ts +++ b/src/compiler/sharing/collections/hashData.ts @@ -1,32 +1,6 @@ -import { hasProperty } from "../../core"; -import { Debug } from "../../debug"; -import { sys } from "../../sys"; -import { IdentifiableStruct } from "../structs/identifiableStruct"; import { Shared, SharedStructBase } from "../structs/sharedStruct"; -import { xxh32string } from "./xxhash32"; +import { identityHash } from "./hash"; -const seed = sys.stringSeed ?? Math.floor(Math.random() * 0xffffffff) >>> 0; - -function hash(value: Shareable) { - if (value === undefined || value === null) { // eslint-disable-line no-null/no-null -- necessary comparison - return 0; - } - switch (typeof value) { - case "number": - return value >> 0; - case "boolean": - return value ? 1 : 0; - case "string": - return xxh32string(value, seed); - case "object": - if (hasProperty(value, "__hash__")) { - return (value as IdentifiableStruct).__hash__ >> 0; - } - return 0; - default: - Debug.assertNever(value); - } -} // Portions of the following are derived from esfx and .NET Core. See ThirdPartyNoticeText.txt in the root of this // repository for their respective license notices. @@ -80,7 +54,8 @@ function isPrime(candidate: number) { return candidate === 2; } -function getPrime(min: number) { +/** @internal */ +export function getPrime(min: number) { if (min < 0) throw new RangeError(); for (const prime of primes) { if (prime >= min) return prime; @@ -171,7 +146,7 @@ export class HashData extends SharedSt } static findEntryIndex(hashData: HashData, key: K) { - const hashCode = hash(key) & MAX_INT32; + const hashCode = identityHash(key); // Value in _buckets is 1-based let i = hashData.buckets[hashCode % hashData.buckets.length] - 1; const length = hashData.entries.length; @@ -191,7 +166,7 @@ export class HashData extends SharedSt } static insertEntry(hashData: HashData, key: K, value: V) { - const hashCode = hash(key) & MAX_INT32; + const hashCode = identityHash(key) & MAX_INT32; let bucket = hashCode % hashData.buckets.length; // Value in _buckets is 1-based let i = hashData.buckets[bucket] - 1; @@ -236,7 +211,7 @@ export class HashData extends SharedSt } static deleteEntry(hashData: HashData, key: K) { - const hashCode = hash(key) & MAX_INT32; + const hashCode = identityHash(key) & MAX_INT32; const bucket = hashCode % hashData.buckets.length; let last = -1; let entry: HashEntry | undefined; diff --git a/src/compiler/sharing/sharedNode.ts b/src/compiler/sharing/sharedNode.ts index 0bf9c4a2320..95569e49c0b 100644 --- a/src/compiler/sharing/sharedNode.ts +++ b/src/compiler/sharing/sharedNode.ts @@ -42,7 +42,7 @@ export class SharedTextRange extends Tagged(SharedStructBase, Tag.TextRange) { /** @internal */ @Shared({ abstract: true }) -export abstract class SharedNodeBase extends Identifiable(Tagged(SharedTextRange, Tag.Node)) { +export abstract class SharedNode extends Identifiable(Tagged(SharedTextRange, Tag.Node)) { @Shared() kind!: Kind; @Shared() flags = NodeFlags.None; @Shared() transformFlags = TransformFlags.None; @@ -55,11 +55,11 @@ export abstract class SharedNodeBase exten /** @internal */ @Shared() -export class SharedToken extends SharedNodeBase { +export class SharedToken extends SharedNode { declare kind: Kind; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && isTokenKind(value.kind); + return value instanceof SharedNode && isTokenKind(value.kind); } } @@ -114,22 +114,22 @@ export type SharedModifierLike = /** @internal */ @Shared() -export class SharedIdentifier extends HasFlowNode(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedIdentifier extends HasFlowNode(HasSymbol(HasJSDoc(SharedNode))) { @Shared() escapedText!: __String; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.Identifier; + return value instanceof SharedNode && value.kind === SyntaxKind.Identifier; } } /** @internal */ @Shared() -export class SharedQualifiedName extends HasFlowNode(SharedNodeBase) { +export class SharedQualifiedName extends HasFlowNode(SharedNode) { @Shared() left!: SharedEntityName; @Shared() right!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.QualifiedName; + return value instanceof SharedNode && value.kind === SyntaxKind.QualifiedName; } } @@ -162,27 +162,27 @@ export type SharedMemberName = /** @internal */ @Shared() -export class SharedComputedPropertyName extends SharedNodeBase { +export class SharedComputedPropertyName extends SharedNode { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ComputedPropertyName; + return value instanceof SharedNode && value.kind === SyntaxKind.ComputedPropertyName; } } /** @internal */ @Shared() -export class SharedPrivateIdentifier extends SharedNodeBase { +export class SharedPrivateIdentifier extends SharedNode { @Shared() escapedText!: __String; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PrivateIdentifier; + return value instanceof SharedNode && value.kind === SyntaxKind.PrivateIdentifier; } } /** @internal */ @Shared() -export class SharedTypeParameterDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedTypeParameterDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier; @Shared() constraint: SharedTypeNode | undefined; @@ -190,13 +190,13 @@ export class SharedTypeParameterDeclaration extends HasSymbol(HasJSDoc(SharedNod @Shared() expression: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeParameter; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeParameter; } } /** @internal */ @Shared() -export class SharedParameterDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedParameterDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() dotDotDotToken!: SharedToken | undefined; @Shared() name!: SharedBindingName; @@ -205,23 +205,23 @@ export class SharedParameterDeclaration extends HasSymbol(HasJSDoc(SharedNodeBas @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.Parameter; + return value instanceof SharedNode && value.kind === SyntaxKind.Parameter; } } /** @internal */ @Shared() -export class SharedDecorator extends SharedNodeBase { +export class SharedDecorator extends SharedNode { @Shared() expression!: SharedLeftHandSideExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.Decorator; + return value instanceof SharedNode && value.kind === SyntaxKind.Decorator; } } /** @internal */ @Shared() -export class SharedPropertySignature extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedPropertySignature extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedPropertyName; @Shared() questionToken!: SharedToken | undefined; @@ -229,75 +229,75 @@ export class SharedPropertySignature extends HasSymbol(HasJSDoc(SharedNodeBase)) @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PropertySignature; + return value instanceof SharedNode && value.kind === SyntaxKind.PropertySignature; } } /** @internal */ @Shared() -export class SharedCallSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedCallSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @Shared() type!: SharedTypeNode | undefined; @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.CallSignature; + return value instanceof SharedNode && value.kind === SyntaxKind.CallSignature; } } /** @internal */ @Shared() -export class SharedConstructSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedConstructSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @Shared() type!: SharedTypeNode | undefined; @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ConstructSignature; + return value instanceof SharedNode && value.kind === SyntaxKind.ConstructSignature; } } /** @internal */ @Shared() -export class SharedVariableDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedVariableDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedBindingName; @Shared() exclamationToken!: SharedToken | undefined; @Shared() type!: SharedTypeNode | undefined; @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.VariableDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.VariableDeclaration; } } /** @internal */ @Shared() -export class SharedVariableDeclarationList extends SharedNodeBase { +export class SharedVariableDeclarationList extends SharedNode { @Shared() declarations!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.VariableDeclarationList; + return value instanceof SharedNode && value.kind === SyntaxKind.VariableDeclarationList; } } /** @internal */ @Shared() -export class SharedBindingElement extends HasFlowNode(HasSymbol(SharedNodeBase)) { +export class SharedBindingElement extends HasFlowNode(HasSymbol(SharedNode)) { @Shared() propertyName!: SharedPropertyName | undefined; @Shared() dotDotDotToken!: SharedToken | undefined; @Shared() name!: SharedBindingName; @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.BindingElement; + return value instanceof SharedNode && value.kind === SyntaxKind.BindingElement; } } /** @internal */ @Shared() -export class SharedPropertyDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedPropertyDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedPropertyName; @Shared() questionToken!: SharedToken | undefined; @@ -306,13 +306,13 @@ export class SharedPropertyDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PropertyDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.PropertyDeclaration; } } /** @internal */ @Shared() -export class SharedPropertyAssignment extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedPropertyAssignment extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedPropertyName; @Shared() initializer!: SharedExpression; @Shared() modifiers!: SharedNodeArray | undefined; @@ -320,13 +320,13 @@ export class SharedPropertyAssignment extends HasSymbol(HasJSDoc(SharedNodeBase) @Shared() exclamationToken!: SharedToken | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PropertyAssignment; + return value instanceof SharedNode && value.kind === SyntaxKind.PropertyAssignment; } } /** @internal */ @Shared() -export class SharedShorthandPropertyAssignment extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedShorthandPropertyAssignment extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedIdentifier; @Shared() equalsToken!: SharedToken | undefined; @Shared() objectAssignmentInitializer!: SharedExpression | undefined; @@ -335,17 +335,17 @@ export class SharedShorthandPropertyAssignment extends HasSymbol(HasJSDoc(Shared @Shared() exclamationToken!: SharedToken | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ShorthandPropertyAssignment; + return value instanceof SharedNode && value.kind === SyntaxKind.ShorthandPropertyAssignment; } } /** @internal */ @Shared() -export class SharedSpreadAssignment extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedSpreadAssignment extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SpreadAssignment; + return value instanceof SharedNode && value.kind === SyntaxKind.SpreadAssignment; } } @@ -363,27 +363,27 @@ export type SharedArrayBindingElement = /** @internal */ @Shared() -export class SharedObjectBindingPattern extends SharedNodeBase { +export class SharedObjectBindingPattern extends SharedNode { @Shared() elements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ObjectBindingPattern; + return value instanceof SharedNode && value.kind === SyntaxKind.ObjectBindingPattern; } } /** @internal */ @Shared() -export class SharedArrayBindingPattern extends SharedNodeBase { +export class SharedArrayBindingPattern extends SharedNode { @Shared() elements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ArrayBindingPattern; + return value instanceof SharedNode && value.kind === SyntaxKind.ArrayBindingPattern; } } /** @internal */ @Shared() -export class SharedFunctionDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase)))) { +export class SharedFunctionDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNode)))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() asteriskToken!: SharedToken | undefined; @Shared() name!: SharedIdentifier | undefined; @@ -394,13 +394,13 @@ export class SharedFunctionDeclaration extends HasFunctionFlow(HasLocals(HasSymb @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.FunctionDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.FunctionDeclaration; } } /** @internal */ @Shared() -export class SharedMethodSignature extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedMethodSignature extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedPropertyName; @Shared() questionToken!: SharedToken | undefined; @@ -410,13 +410,13 @@ export class SharedMethodSignature extends HasLocals(HasSymbol(HasJSDoc(SharedNo @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.MethodSignature; + return value instanceof SharedNode && value.kind === SyntaxKind.MethodSignature; } } /** @internal */ @Shared() -export class SharedMethodDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))))) { +export class SharedMethodDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNode))))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() asteriskToken!: SharedToken | undefined; @Shared() name!: SharedPropertyName; @@ -429,13 +429,13 @@ export class SharedMethodDeclaration extends HasFunctionFlow(HasFlowNode(HasLoca @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.MethodDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.MethodDeclaration; } } /** @internal */ @Shared() -export class SharedConstructorDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase)))) { +export class SharedConstructorDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNode)))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() body!: SharedFunctionBody | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @@ -444,21 +444,21 @@ export class SharedConstructorDeclaration extends HasFunctionFlow(HasLocals(HasS @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.Constructor; + return value instanceof SharedNode && value.kind === SyntaxKind.Constructor; } } /** @internal */ @Shared() -export class SharedSemicolonClassElement extends HasJSDoc(SharedNodeBase) { +export class SharedSemicolonClassElement extends HasJSDoc(SharedNode) { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SemicolonClassElement; + return value instanceof SharedNode && value.kind === SyntaxKind.SemicolonClassElement; } } /** @internal */ @Shared() -export class SharedGetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))))) { +export class SharedGetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNode))))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedPropertyName; @Shared() body!: SharedFunctionBody | undefined; @@ -468,13 +468,13 @@ export class SharedGetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(Ha @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.GetAccessor; + return value instanceof SharedNode && value.kind === SyntaxKind.GetAccessor; } } /** @internal */ @Shared() -export class SharedSetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))))) { +export class SharedSetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNode))))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedPropertyName; @Shared() body!: SharedFunctionBody | undefined; @@ -484,7 +484,7 @@ export class SharedSetAccessorDeclaration extends HasFunctionFlow(HasFlowNode(Ha @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SetAccessor; + return value instanceof SharedNode && value.kind === SyntaxKind.SetAccessor; } } @@ -496,7 +496,7 @@ export type SharedAccessorDeclaration = /** @internal */ @Shared() -export class SharedIndexSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedIndexSignatureDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @@ -504,18 +504,18 @@ export class SharedIndexSignatureDeclaration extends HasLocals(HasSymbol(HasJSDo @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.IndexSignature; + return value instanceof SharedNode && value.kind === SyntaxKind.IndexSignature; } } /** @internal */ @Shared() -export class SharedClassStaticBlockDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase)))) { +export class SharedClassStaticBlockDeclaration extends HasFunctionFlow(HasLocals(HasSymbol(HasJSDoc(SharedNode)))) { @Shared() body!: SharedBlock; @Shared() modifiers!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ClassStaticBlockDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ClassStaticBlockDeclaration; } } @@ -552,18 +552,18 @@ export type SharedTypeNode = /** @internal */ @Shared() -export class SharedImportTypeAssertionContainer extends SharedNodeBase { +export class SharedImportTypeAssertionContainer extends SharedNode { @Shared() assertClause!: SharedAssertClause; @Shared() multiLine!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportTypeAssertionContainer; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportTypeAssertionContainer; } } /** @internal */ @Shared() -export class SharedImportTypeNode extends SharedNodeBase { +export class SharedImportTypeNode extends SharedNode { @Shared() isTypeOf!: boolean; @Shared() argument!: SharedTypeNode; @Shared() assertions!: SharedImportTypeAssertionContainer | undefined; @@ -571,22 +571,22 @@ export class SharedImportTypeNode extends SharedNodeBase @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportType; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportType; } } /** @internal */ @Shared() -export class SharedThisTypeNode extends SharedNodeBase { +export class SharedThisTypeNode extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ThisType; + return value instanceof SharedNode && value.kind === SyntaxKind.ThisType; } } /** @internal */ @Shared() -export class SharedFunctionTypeNode extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedFunctionTypeNode extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: undefined | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @@ -594,13 +594,13 @@ export class SharedFunctionTypeNode extends HasLocals(HasSymbol(HasJSDoc(SharedN @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.FunctionType; + return value instanceof SharedNode && value.kind === SyntaxKind.FunctionType; } } /** @internal */ @Shared() -export class SharedConstructorTypeNode extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedConstructorTypeNode extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @@ -608,185 +608,185 @@ export class SharedConstructorTypeNode extends HasLocals(HasSymbol(HasJSDoc(Shar @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ConstructorType; + return value instanceof SharedNode && value.kind === SyntaxKind.ConstructorType; } } /** @internal */ @Shared() -export class SharedTypeReferenceNode extends SharedNodeBase { +export class SharedTypeReferenceNode extends SharedNode { @Shared() typeName!: SharedEntityName; @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeReference; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeReference; } } /** @internal */ @Shared() -export class SharedTypePredicateNode extends SharedNodeBase { +export class SharedTypePredicateNode extends SharedNode { @Shared() assertsModifier!: SharedToken | undefined; @Shared() parameterName!: SharedIdentifier | SharedThisTypeNode; @Shared() type!: SharedTypeNode | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypePredicate; + return value instanceof SharedNode && value.kind === SyntaxKind.TypePredicate; } } /** @internal */ @Shared() -export class SharedTypeQueryNode extends SharedNodeBase { +export class SharedTypeQueryNode extends SharedNode { @Shared() exprName!: SharedEntityName; @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeQuery; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeQuery; } } /** @internal */ @Shared() -export class SharedTypeLiteralNode extends HasSymbol(SharedNodeBase) { +export class SharedTypeLiteralNode extends HasSymbol(SharedNode) { @Shared() members!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeLiteral; } } /** @internal */ @Shared() -export class SharedArrayTypeNode extends SharedNodeBase { +export class SharedArrayTypeNode extends SharedNode { @Shared() elementType!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ArrayType; + return value instanceof SharedNode && value.kind === SyntaxKind.ArrayType; } } /** @internal */ @Shared() -export class SharedTupleTypeNode extends SharedNodeBase { +export class SharedTupleTypeNode extends SharedNode { @Shared() elements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TupleType; + return value instanceof SharedNode && value.kind === SyntaxKind.TupleType; } } /** @internal */ @Shared() -export class SharedNamedTupleMember extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedNamedTupleMember extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() dotDotDotToken!: SharedToken | undefined; @Shared() name!: SharedIdentifier; @Shared() questionToken!: SharedToken | undefined; @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamedTupleMember; + return value instanceof SharedNode && value.kind === SyntaxKind.NamedTupleMember; } } /** @internal */ @Shared() -export class SharedOptionalTypeNode extends SharedNodeBase { +export class SharedOptionalTypeNode extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.OptionalType; + return value instanceof SharedNode && value.kind === SyntaxKind.OptionalType; } } /** @internal */ @Shared() -export class SharedRestTypeNode extends SharedNodeBase { +export class SharedRestTypeNode extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.RestType; + return value instanceof SharedNode && value.kind === SyntaxKind.RestType; } } /** @internal */ @Shared() -export class SharedUnionTypeNode extends SharedNodeBase { +export class SharedUnionTypeNode extends SharedNode { @Shared() types!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.UnionType; + return value instanceof SharedNode && value.kind === SyntaxKind.UnionType; } } /** @internal */ @Shared() -export class SharedIntersectionTypeNode extends SharedNodeBase { +export class SharedIntersectionTypeNode extends SharedNode { @Shared() types!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.IntersectionType; + return value instanceof SharedNode && value.kind === SyntaxKind.IntersectionType; } } /** @internal */ @Shared() -export class SharedConditionalTypeNode extends HasLocals(SharedNodeBase) { +export class SharedConditionalTypeNode extends HasLocals(SharedNode) { @Shared() checkType!: SharedTypeNode; @Shared() extendsType!: SharedTypeNode; @Shared() trueType!: SharedTypeNode; @Shared() falseType!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ConditionalType; + return value instanceof SharedNode && value.kind === SyntaxKind.ConditionalType; } } /** @internal */ @Shared() -export class SharedInferTypeNode extends SharedNodeBase { +export class SharedInferTypeNode extends SharedNode { @Shared() typeParameter!: SharedTypeParameterDeclaration; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.InferType; + return value instanceof SharedNode && value.kind === SyntaxKind.InferType; } } /** @internal */ @Shared() -export class SharedParenthesizedTypeNode extends SharedNodeBase { +export class SharedParenthesizedTypeNode extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ParenthesizedType; + return value instanceof SharedNode && value.kind === SyntaxKind.ParenthesizedType; } } /** @internal */ @Shared() -export class SharedTypeOperatorNode extends SharedNodeBase { +export class SharedTypeOperatorNode extends SharedNode { @Shared() operator!: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeOperator; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeOperator; } } /** @internal */ @Shared() -export class SharedIndexedAccessTypeNode extends SharedNodeBase { +export class SharedIndexedAccessTypeNode extends SharedNode { @Shared() objectType!: SharedTypeNode; @Shared() indexType!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.IndexedAccessType; + return value instanceof SharedNode && value.kind === SyntaxKind.IndexedAccessType; } } /** @internal */ @Shared() -export class SharedMappedTypeNode extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedMappedTypeNode extends HasLocals(HasSymbol(SharedNode)) { @Shared() readonlyToken!: SharedToken | SharedToken | SharedToken | undefined; @Shared() typeParameter!: SharedTypeParameterDeclaration; @Shared() nameType!: SharedTypeNode | undefined; @@ -795,52 +795,52 @@ export class SharedMappedTypeNode extends HasLocals(HasSymbol(SharedNodeBase)) | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.MappedType; + return value instanceof SharedNode && value.kind === SyntaxKind.MappedType; } } /** @internal */ @Shared() -export class SharedLiteralTypeNode extends SharedNodeBase { +export class SharedLiteralTypeNode extends SharedNode { @Shared() literal!: SharedToken | SharedToken | SharedToken | SharedStringLiteral | SharedNumericLiteral | SharedBigIntLiteral | SharedPrefixUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.LiteralType; + return value instanceof SharedNode && value.kind === SyntaxKind.LiteralType; } } /** @internal */ @Shared() -export class SharedStringLiteral extends HasSymbol(SharedNodeBase) { +export class SharedStringLiteral extends HasSymbol(SharedNode) { @Shared() text!: string; @Shared() singleQuote!: boolean | undefined; @Shared() isUnterminated!: boolean; @Shared() hasExtendedUnicodeEscape!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.StringLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.StringLiteral; } } /** @internal */ @Shared() -export class SharedTemplateLiteralTypeNode extends SharedNodeBase { +export class SharedTemplateLiteralTypeNode extends SharedNode { @Shared() head!: SharedTemplateHead; @Shared() templateSpans!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateLiteralType; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateLiteralType; } } /** @internal */ @Shared() -export class SharedTemplateLiteralTypeSpan extends SharedNodeBase { +export class SharedTemplateLiteralTypeSpan extends SharedNode { @Shared() type!: SharedTypeNode; @Shared() literal!: SharedTemplateMiddle | SharedTemplateTail; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateLiteralTypeSpan; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateLiteralTypeSpan; } } @@ -937,100 +937,100 @@ export type SharedPrimaryExpression = /** @internal */ @Shared() -export class SharedOmittedExpression extends SharedNodeBase { +export class SharedOmittedExpression extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.OmittedExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.OmittedExpression; } } /** @internal */ @Shared() -export class SharedPrefixUnaryExpression extends SharedNodeBase { +export class SharedPrefixUnaryExpression extends SharedNode { @Shared() operator!: PrefixUnaryOperator; @Shared() operand!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PrefixUnaryExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.PrefixUnaryExpression; } } /** @internal */ @Shared() -export class SharedPostfixUnaryExpression extends SharedNodeBase { +export class SharedPostfixUnaryExpression extends SharedNode { @Shared() operand!: SharedLeftHandSideExpression; @Shared() operator!: PostfixUnaryOperator; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PostfixUnaryExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.PostfixUnaryExpression; } } /** @internal */ @Shared() -export class SharedDeleteExpression extends SharedNodeBase { +export class SharedDeleteExpression extends SharedNode { @Shared() expression!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.DeleteExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.DeleteExpression; } } /** @internal */ @Shared() -export class SharedTypeOfExpression extends SharedNodeBase { +export class SharedTypeOfExpression extends SharedNode { @Shared() expression!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeOfExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeOfExpression; } } /** @internal */ @Shared() -export class SharedVoidExpression extends SharedNodeBase { +export class SharedVoidExpression extends SharedNode { @Shared() expression!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.VoidExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.VoidExpression; } } /** @internal */ @Shared() -export class SharedAwaitExpression extends SharedNodeBase { +export class SharedAwaitExpression extends SharedNode { @Shared() expression!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.AwaitExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.AwaitExpression; } } /** @internal */ @Shared() -export class SharedYieldExpression extends SharedNodeBase { +export class SharedYieldExpression extends SharedNode { @Shared() asteriskToken!: SharedToken | undefined; @Shared() expression!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.YieldExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.YieldExpression; } } /** @internal */ @Shared() -export class SharedBinaryExpression extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedBinaryExpression extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() left!: SharedExpression; @Shared() operatorToken!: SharedToken; @Shared() right!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.BinaryExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.BinaryExpression; } } /** @internal */ @Shared() -export class SharedConditionalExpression extends SharedNodeBase { +export class SharedConditionalExpression extends SharedNode { @Shared() condition!: SharedExpression; @Shared() questionToken!: SharedToken; @Shared() whenTrue!: SharedExpression; @@ -1038,7 +1038,7 @@ export class SharedConditionalExpression extends SharedNodeBase { +export class SharedFunctionExpression extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNode))))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() asteriskToken!: SharedToken | undefined; @Shared() name!: SharedIdentifier | undefined; @@ -1062,13 +1062,13 @@ export class SharedFunctionExpression extends HasFunctionFlow(HasFlowNode(HasLoc @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.FunctionExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.FunctionExpression; } } /** @internal */ @Shared() -export class SharedArrowFunction extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))))) { +export class SharedArrowFunction extends HasFunctionFlow(HasFlowNode(HasLocals(HasSymbol(HasJSDoc(SharedNode))))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() equalsGreaterThanToken!: SharedToken; @Shared() typeParameters!: SharedNodeArray | undefined; @@ -1078,25 +1078,25 @@ export class SharedArrowFunction extends HasFunctionFlow(HasFlowNode(HasLocals(H @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ArrowFunction; + return value instanceof SharedNode && value.kind === SyntaxKind.ArrowFunction; } } /** @internal */ @Shared() -export class SharedRegularExpressionLiteral extends SharedNodeBase { +export class SharedRegularExpressionLiteral extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.RegularExpressionLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.RegularExpressionLiteral; } } /** @internal */ @Shared() -export class SharedNoSubstitutionTemplateLiteral extends HasSymbol(SharedNodeBase) { +export class SharedNoSubstitutionTemplateLiteral extends HasSymbol(SharedNode) { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @@ -1104,38 +1104,38 @@ export class SharedNoSubstitutionTemplateLiteral extends HasSymbol(SharedNodeBas @Shared() templateFlags!: TokenFlags | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NoSubstitutionTemplateLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.NoSubstitutionTemplateLiteral; } } /** @internal */ @Shared() -export class SharedNumericLiteral extends HasSymbol(SharedNodeBase) { +export class SharedNumericLiteral extends HasSymbol(SharedNode) { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @Shared() numericLiteralFlags!: TokenFlags; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NumericLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.NumericLiteral; } } /** @internal */ @Shared() -export class SharedBigIntLiteral extends SharedNodeBase { +export class SharedBigIntLiteral extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.BigIntLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.BigIntLiteral; } } /** @internal */ @Shared() -export class SharedTemplateHead extends SharedNodeBase { +export class SharedTemplateHead extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @@ -1143,13 +1143,13 @@ export class SharedTemplateHead extends SharedNodeBase @Shared() templateFlags!: TokenFlags | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateHead; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateHead; } } /** @internal */ @Shared() -export class SharedTemplateMiddle extends SharedNodeBase { +export class SharedTemplateMiddle extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @@ -1157,13 +1157,13 @@ export class SharedTemplateMiddle extends SharedNodeBase { +export class SharedTemplateTail extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @@ -1171,60 +1171,60 @@ export class SharedTemplateTail extends SharedNodeBase @Shared() templateFlags!: TokenFlags | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateTail; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateTail; } } /** @internal */ @Shared() -export class SharedTemplateExpression extends SharedNodeBase { +export class SharedTemplateExpression extends SharedNode { @Shared() head!: SharedTemplateHead; @Shared() templateSpans!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateExpression; } } /** @internal */ @Shared() -export class SharedTemplateSpan extends SharedNodeBase { +export class SharedTemplateSpan extends SharedNode { @Shared() expression!: SharedExpression; @Shared() literal!: SharedTemplateMiddle | SharedTemplateTail; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TemplateSpan; + return value instanceof SharedNode && value.kind === SyntaxKind.TemplateSpan; } } /** @internal */ @Shared() -export class SharedParenthesizedExpression extends HasJSDoc(SharedNodeBase) { +export class SharedParenthesizedExpression extends HasJSDoc(SharedNode) { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ParenthesizedExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.ParenthesizedExpression; } } /** @internal */ @Shared() -export class SharedArrayLiteralExpression extends SharedNodeBase { +export class SharedArrayLiteralExpression extends SharedNode { @Shared() elements!: SharedNodeArray; @Shared() multiLine!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ArrayLiteralExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.ArrayLiteralExpression; } } /** @internal */ @Shared() -export class SharedSpreadElement extends SharedNodeBase { +export class SharedSpreadElement extends SharedNode { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SpreadElement; + return value instanceof SharedNode && value.kind === SyntaxKind.SpreadElement; } } @@ -1239,72 +1239,72 @@ export type SharedObjectLiteralElement = /** @internal */ @Shared() -export class SharedObjectLiteralExpression extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedObjectLiteralExpression extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() properties!: SharedNodeArray; @Shared() multiLine!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ObjectLiteralExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.ObjectLiteralExpression; } } /** @internal */ @Shared() -export class SharedPropertyAccessExpression extends HasFlowNode(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedPropertyAccessExpression extends HasFlowNode(HasSymbol(HasJSDoc(SharedNode))) { @Shared() expression!: SharedLeftHandSideExpression; @Shared() questionDotToken!: SharedToken | undefined; @Shared() name!: SharedMemberName; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.PropertyAccessExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.PropertyAccessExpression; } } /** @internal */ @Shared() -export class SharedElementAccessExpression extends HasFlowNode(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedElementAccessExpression extends HasFlowNode(HasSymbol(HasJSDoc(SharedNode))) { @Shared() expression!: SharedLeftHandSideExpression; @Shared() questionDotToken!: SharedToken | undefined; @Shared() argumentExpression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ElementAccessExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.ElementAccessExpression; } } /** @internal */ @Shared() -export class SharedCallExpression extends HasSymbol(SharedNodeBase) { +export class SharedCallExpression extends HasSymbol(SharedNode) { @Shared() expression!: SharedLeftHandSideExpression; @Shared() questionDotToken!: SharedToken | undefined; @Shared() typeArguments!: SharedNodeArray | undefined; @Shared() arguments!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.CallExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.CallExpression; } } /** @internal */ @Shared() -export class SharedExpressionWithTypeArguments extends SharedNodeBase { +export class SharedExpressionWithTypeArguments extends SharedNode { @Shared() expression!: SharedLeftHandSideExpression; @Shared() typeArguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExpressionWithTypeArguments; + return value instanceof SharedNode && value.kind === SyntaxKind.ExpressionWithTypeArguments; } } /** @internal */ @Shared() -export class SharedNewExpression extends HasSymbol(SharedNodeBase) { +export class SharedNewExpression extends HasSymbol(SharedNode) { @Shared() expression!: SharedLeftHandSideExpression; @Shared() typeArguments!: SharedNodeArray | undefined; @Shared() arguments!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NewExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.NewExpression; } } @@ -1316,80 +1316,80 @@ export type SharedTemplateLiteral = /** @internal */ @Shared() -export class SharedTaggedTemplateExpression extends SharedNodeBase { +export class SharedTaggedTemplateExpression extends SharedNode { @Shared() tag!: SharedLeftHandSideExpression; @Shared() typeArguments!: SharedNodeArray | undefined; @Shared() template!: SharedTemplateLiteral; @Shared() questionDotToken!: SharedToken | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TaggedTemplateExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.TaggedTemplateExpression; } } /** @internal */ @Shared() -export class SharedAsExpression extends SharedNodeBase { +export class SharedAsExpression extends SharedNode { @Shared() expression!: SharedExpression; @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.AsExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.AsExpression; } } /** @internal */ @Shared() -export class SharedTypeAssertion extends SharedNodeBase { +export class SharedTypeAssertion extends SharedNode { @Shared() type!: SharedTypeNode; @Shared() expression!: SharedUnaryExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeAssertionExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeAssertionExpression; } } /** @internal */ @Shared() -export class SharedSatisfiesExpression extends SharedNodeBase { +export class SharedSatisfiesExpression extends SharedNode { @Shared() expression!: SharedExpression; @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SatisfiesExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.SatisfiesExpression; } } /** @internal */ @Shared() -export class SharedNonNullExpression extends SharedNodeBase { +export class SharedNonNullExpression extends SharedNode { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NonNullExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.NonNullExpression; } } /** @internal */ @Shared() -export class SharedMetaProperty extends HasFlowNode(SharedNodeBase) { +export class SharedMetaProperty extends HasFlowNode(SharedNode) { @Shared() keywordToken!: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword; @Shared() name!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.MetaProperty; + return value instanceof SharedNode && value.kind === SyntaxKind.MetaProperty; } } /** @internal */ @Shared() -export class SharedJsxElement extends SharedNodeBase { +export class SharedJsxElement extends SharedNode { @Shared() openingElement!: SharedJsxOpeningElement; @Shared() children!: SharedNodeArray; @Shared() closingElement!: SharedJsxClosingElement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxElement; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxElement; } } @@ -1421,85 +1421,85 @@ export type SharedJsxTagNameExpression = /** @internal */ @Shared() -export class SharedJsxAttributes extends HasSymbol(SharedNodeBase) { +export class SharedJsxAttributes extends HasSymbol(SharedNode) { @Shared() properties!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxAttributes; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxAttributes; } } /** @internal */ @Shared() -export class SharedJsxNamespacedName extends SharedNodeBase { +export class SharedJsxNamespacedName extends SharedNode { @Shared() name!: SharedIdentifier; @Shared() namespace!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxNamespacedName; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxNamespacedName; } } /** @internal */ @Shared() -export class SharedJsxOpeningElement extends SharedNodeBase { +export class SharedJsxOpeningElement extends SharedNode { @Shared() tagName!: SharedJsxTagNameExpression; @Shared() typeArguments!: SharedNodeArray | undefined; @Shared() attributes!: SharedJsxAttributes; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxOpeningElement; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxOpeningElement; } } /** @internal */ @Shared() -export class SharedJsxSelfClosingElement extends SharedNodeBase { +export class SharedJsxSelfClosingElement extends SharedNode { @Shared() tagName!: SharedJsxTagNameExpression; @Shared() typeArguments!: SharedNodeArray | undefined; @Shared() attributes!: SharedJsxAttributes; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxSelfClosingElement; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxSelfClosingElement; } } /** @internal */ @Shared() -export class SharedJsxFragment extends SharedNodeBase { +export class SharedJsxFragment extends SharedNode { @Shared() openingFragment!: SharedJsxOpeningFragment; @Shared() children!: SharedNodeArray; @Shared() closingFragment!: SharedJsxClosingFragment; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxFragment; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxFragment; } } /** @internal */ @Shared() -export class SharedJsxOpeningFragment extends SharedNodeBase { +export class SharedJsxOpeningFragment extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxOpeningFragment; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxOpeningFragment; } } /** @internal */ @Shared() -export class SharedJsxClosingFragment extends SharedNodeBase { +export class SharedJsxClosingFragment extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxClosingFragment; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxClosingFragment; } } /** @internal */ @Shared() -export class SharedJsxAttribute extends HasSymbol(SharedNodeBase) { +export class SharedJsxAttribute extends HasSymbol(SharedNode) { @Shared() name!: SharedJsxAttributeName; @Shared() initializer!: SharedJsxAttributeValue | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxAttribute; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxAttribute; } } @@ -1513,45 +1513,45 @@ export type SharedJsxAttributeValue = /** @internal */ @Shared() -export class SharedJsxSpreadAttribute extends SharedNodeBase { +export class SharedJsxSpreadAttribute extends SharedNode { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxSpreadAttribute; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxSpreadAttribute; } } /** @internal */ @Shared() -export class SharedJsxClosingElement extends SharedNodeBase { +export class SharedJsxClosingElement extends SharedNode { @Shared() tagName!: SharedJsxTagNameExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxClosingElement; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxClosingElement; } } /** @internal */ @Shared() -export class SharedJsxExpression extends SharedNodeBase { +export class SharedJsxExpression extends SharedNode { @Shared() dotDotDotToken!: SharedToken | undefined; @Shared() expression!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxExpression; } } /** @internal */ @Shared() -export class SharedJsxText extends SharedNodeBase { +export class SharedJsxText extends SharedNode { @Shared() text!: string; @Shared() isUnterminated!: boolean | undefined; @Shared() hasExtendedUnicodeEscape!: boolean | undefined; @Shared() containsOnlyTriviaWhiteSpaces!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JsxText; + return value instanceof SharedNode && value.kind === SyntaxKind.JsxText; } } @@ -1611,94 +1611,94 @@ export type SharedIterationStatement = /** @internal */ @Shared() -export class SharedEmptyStatement extends HasJSDoc(SharedNodeBase) { +export class SharedEmptyStatement extends HasJSDoc(SharedNode) { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.EmptyStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.EmptyStatement; } } /** @internal */ @Shared() -export class SharedDebuggerStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedDebuggerStatement extends HasFlowNode(HasJSDoc(SharedNode)) { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.DebuggerStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.DebuggerStatement; } } /** @internal */ @Shared() -export class SharedMissingDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedMissingDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedIdentifier | undefined; @Shared() modifiers!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.MissingDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.MissingDeclaration; } } /** @internal */ @Shared() -export class SharedBlock extends HasLocals(HasJSDoc(SharedNodeBase)) { +export class SharedBlock extends HasLocals(HasJSDoc(SharedNode)) { @Shared() statements!: SharedNodeArray; @Shared() multiLine!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.Block; + return value instanceof SharedNode && value.kind === SyntaxKind.Block; } } /** @internal */ @Shared() -export class SharedVariableStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedVariableStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() declarationList!: SharedVariableDeclarationList; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.VariableStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.VariableStatement; } } /** @internal */ @Shared() -export class SharedExpressionStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedExpressionStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExpressionStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ExpressionStatement; } } /** @internal */ @Shared() -export class SharedIfStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedIfStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; @Shared() thenStatement!: SharedStatement; @Shared() elseStatement!: SharedStatement | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.IfStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.IfStatement; } } /** @internal */ @Shared() -export class SharedDoStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedDoStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() statement!: SharedStatement; @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.DoStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.DoStatement; } } /** @internal */ @Shared() -export class SharedWhileStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedWhileStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.WhileStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.WhileStatement; } } @@ -1710,14 +1710,14 @@ export type SharedForInitializer = /** @internal */ @Shared() -export class SharedForStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNodeBase))) { +export class SharedForStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNode))) { @Shared() initializer!: SharedForInitializer | undefined; @Shared() condition!: SharedExpression | undefined; @Shared() incrementor!: SharedExpression | undefined; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ForStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ForStatement; } } @@ -1729,110 +1729,110 @@ export type SharedForInOrOfStatement = /** @internal */ @Shared() -export class SharedForInStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNodeBase))) { +export class SharedForInStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNode))) { @Shared() initializer!: SharedForInitializer; @Shared() expression!: SharedExpression; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ForInStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ForInStatement; } } /** @internal */ @Shared() -export class SharedForOfStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNodeBase))) { +export class SharedForOfStatement extends HasFlowNode(HasLocals(HasJSDoc(SharedNode))) { @Shared() awaitModifier!: SharedToken | undefined; @Shared() initializer!: SharedForInitializer; @Shared() expression!: SharedExpression; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ForOfStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ForOfStatement; } } /** @internal */ @Shared() -export class SharedBreakStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedBreakStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() label!: SharedIdentifier | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.BreakStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.BreakStatement; } } /** @internal */ @Shared() -export class SharedContinueStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedContinueStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() label!: SharedIdentifier | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ContinueStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ContinueStatement; } } /** @internal */ @Shared() -export class SharedReturnStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedReturnStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ReturnStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ReturnStatement; } } /** @internal */ @Shared() -export class SharedWithStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedWithStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.WithStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.WithStatement; } } /** @internal */ @Shared() -export class SharedSwitchStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedSwitchStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; @Shared() caseBlock!: SharedCaseBlock; @Shared() possiblyExhaustive!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SwitchStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.SwitchStatement; } } /** @internal */ @Shared() -export class SharedCaseBlock extends HasLocals(SharedNodeBase) { +export class SharedCaseBlock extends HasLocals(SharedNode) { @Shared() clauses!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.CaseBlock; + return value instanceof SharedNode && value.kind === SyntaxKind.CaseBlock; } } /** @internal */ @Shared() -export class SharedCaseClause extends HasJSDoc(SharedNodeBase) { +export class SharedCaseClause extends HasJSDoc(SharedNode) { @Shared() expression!: SharedExpression; @Shared() statements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.CaseClause; + return value instanceof SharedNode && value.kind === SyntaxKind.CaseClause; } } /** @internal */ @Shared() -export class SharedDefaultClause extends SharedNodeBase { +export class SharedDefaultClause extends SharedNode { @Shared() statements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.DefaultClause; + return value instanceof SharedNode && value.kind === SyntaxKind.DefaultClause; } } @@ -1844,45 +1844,45 @@ export type SharedCaseOrDefaultClause = /** @internal */ @Shared() -export class SharedLabeledStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedLabeledStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() label!: SharedIdentifier; @Shared() statement!: SharedStatement; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.LabeledStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.LabeledStatement; } } /** @internal */ @Shared() -export class SharedThrowStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedThrowStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ThrowStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.ThrowStatement; } } /** @internal */ @Shared() -export class SharedTryStatement extends HasFlowNode(HasJSDoc(SharedNodeBase)) { +export class SharedTryStatement extends HasFlowNode(HasJSDoc(SharedNode)) { @Shared() tryBlock!: SharedBlock; @Shared() catchClause!: SharedCatchClause | undefined; @Shared() finallyBlock!: SharedBlock | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TryStatement; + return value instanceof SharedNode && value.kind === SyntaxKind.TryStatement; } } /** @internal */ @Shared() -export class SharedCatchClause extends HasLocals(SharedNodeBase) { +export class SharedCatchClause extends HasLocals(SharedNode) { @Shared() variableDeclaration!: SharedVariableDeclaration | undefined; @Shared() block!: SharedBlock; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.CatchClause; + return value instanceof SharedNode && value.kind === SyntaxKind.CatchClause; } } @@ -1899,7 +1899,7 @@ export type SharedClassElement = /** @internal */ @Shared() -export class SharedClassDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedClassDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @@ -1907,13 +1907,13 @@ export class SharedClassDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase))< @Shared() members!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ClassDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ClassDeclaration; } } /** @internal */ @Shared() -export class SharedClassExpression extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedClassExpression extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier | undefined; @Shared() typeParameters!: SharedNodeArray | undefined; @@ -1921,7 +1921,7 @@ export class SharedClassExpression extends HasSymbol(HasJSDoc(SharedNodeBase)); static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ClassExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.ClassExpression; } } @@ -1937,7 +1937,7 @@ export type SharedTypeElement = /** @internal */ @Shared() -export class SharedInterfaceDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedInterfaceDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier; @Shared() typeParameters!: SharedNodeArray | undefined; @@ -1945,54 +1945,54 @@ export class SharedInterfaceDeclaration extends HasSymbol(HasJSDoc(SharedNodeBas @Shared() members!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.InterfaceDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.InterfaceDeclaration; } } /** @internal */ @Shared() -export class SharedHeritageClause extends SharedNodeBase { +export class SharedHeritageClause extends SharedNode { @Shared() token!: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword; @Shared() types!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.HeritageClause; + return value instanceof SharedNode && value.kind === SyntaxKind.HeritageClause; } } /** @internal */ @Shared() -export class SharedTypeAliasDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedTypeAliasDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier; @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.TypeAliasDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.TypeAliasDeclaration; } } /** @internal */ @Shared() -export class SharedEnumMember extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedEnumMember extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedPropertyName; @Shared() initializer!: SharedExpression | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.EnumMember; + return value instanceof SharedNode && value.kind === SyntaxKind.EnumMember; } } /** @internal */ @Shared() -export class SharedEnumDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedEnumDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier; @Shared() members!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.EnumDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.EnumDeclaration; } } @@ -2010,13 +2010,13 @@ export type SharedModuleBody = /** @internal */ @Shared() -export class SharedModuleDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNodeBase))) { +export class SharedModuleDeclaration extends HasLocals(HasSymbol(HasJSDoc(SharedNode))) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedModuleName; @Shared() body!: SharedModuleBody | SharedJSDocNamespaceDeclaration | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ModuleDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ModuleDeclaration; } } @@ -2046,11 +2046,11 @@ export interface SharedJSDocNamespaceDeclaration extends SharedModuleDeclaration /** @internal */ @Shared() -export class SharedModuleBlock extends HasJSDoc(SharedNodeBase) { +export class SharedModuleBlock extends HasJSDoc(SharedNode) { @Shared() statements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ModuleBlock; + return value instanceof SharedNode && value.kind === SyntaxKind.ModuleBlock; } } @@ -2062,37 +2062,37 @@ export type SharedModuleReference = /** @internal */ @Shared() -export class SharedImportEqualsDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedImportEqualsDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() name!: SharedIdentifier; @Shared() isTypeOnly!: boolean; @Shared() moduleReference!: SharedModuleReference; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportEqualsDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportEqualsDeclaration; } } /** @internal */ @Shared() -export class SharedExternalModuleReference extends SharedNodeBase { +export class SharedExternalModuleReference extends SharedNode { @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExternalModuleReference; + return value instanceof SharedNode && value.kind === SyntaxKind.ExternalModuleReference; } } /** @internal */ @Shared() -export class SharedImportDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedImportDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() importClause!: SharedImportClause | undefined; @Shared() moduleSpecifier!: SharedExpression; @Shared() assertClause!: SharedAssertClause | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportDeclaration; } } @@ -2110,13 +2110,13 @@ export type SharedNamedExportBindings = /** @internal */ @Shared() -export class SharedImportClause extends HasSymbol(SharedNodeBase) { +export class SharedImportClause extends HasSymbol(SharedNode) { @Shared() isTypeOnly!: boolean; @Shared() name!: SharedIdentifier | undefined; @Shared() namedBindings!: SharedNamedImportBindings | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportClause; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportClause; } } @@ -2128,60 +2128,60 @@ export type SharedAssertionKey = /** @internal */ @Shared() -export class SharedAssertEntry extends SharedNodeBase { +export class SharedAssertEntry extends SharedNode { @Shared() name!: SharedAssertionKey; @Shared() value!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.AssertEntry; + return value instanceof SharedNode && value.kind === SyntaxKind.AssertEntry; } } /** @internal */ @Shared() -export class SharedAssertClause extends SharedNodeBase { +export class SharedAssertClause extends SharedNode { @Shared() elements!: SharedNodeArray; @Shared() multiLine!: boolean | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.AssertClause; + return value instanceof SharedNode && value.kind === SyntaxKind.AssertClause; } } /** @internal */ @Shared() -export class SharedNamespaceImport extends HasSymbol(SharedNodeBase) { +export class SharedNamespaceImport extends HasSymbol(SharedNode) { @Shared() name!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamespaceImport; + return value instanceof SharedNode && value.kind === SyntaxKind.NamespaceImport; } } /** @internal */ @Shared() -export class SharedNamespaceExport extends HasSymbol(SharedNodeBase) { +export class SharedNamespaceExport extends HasSymbol(SharedNode) { @Shared() name!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamespaceExport; + return value instanceof SharedNode && value.kind === SyntaxKind.NamespaceExport; } } /** @internal */ @Shared() -export class SharedNamespaceExportDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedNamespaceExportDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() name!: SharedIdentifier; @Shared() modifiers!: SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamespaceExportDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.NamespaceExportDeclaration; } } /** @internal */ @Shared() -export class SharedExportDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedExportDeclaration extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() isTypeOnly!: boolean; @Shared() exportClause!: SharedNamedExportBindings | undefined; @@ -2189,94 +2189,94 @@ export class SharedExportDeclaration extends HasSymbol(HasJSDoc(SharedNodeBase)) @Shared() assertClause!: SharedAssertClause | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExportDeclaration; + return value instanceof SharedNode && value.kind === SyntaxKind.ExportDeclaration; } } /** @internal */ @Shared() -export class SharedNamedImports extends SharedNodeBase { +export class SharedNamedImports extends SharedNode { @Shared() elements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamedImports; + return value instanceof SharedNode && value.kind === SyntaxKind.NamedImports; } } /** @internal */ @Shared() -export class SharedNamedExports extends SharedNodeBase { +export class SharedNamedExports extends SharedNode { @Shared() elements!: SharedNodeArray; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.NamedExports; + return value instanceof SharedNode && value.kind === SyntaxKind.NamedExports; } } /** @internal */ @Shared() -export class SharedImportSpecifier extends HasSymbol(SharedNodeBase) { +export class SharedImportSpecifier extends HasSymbol(SharedNode) { @Shared() propertyName!: SharedIdentifier | undefined; @Shared() name!: SharedIdentifier; @Shared() isTypeOnly!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ImportSpecifier; + return value instanceof SharedNode && value.kind === SyntaxKind.ImportSpecifier; } } /** @internal */ @Shared() -export class SharedExportSpecifier extends HasJSDoc(SharedNodeBase) { +export class SharedExportSpecifier extends HasJSDoc(SharedNode) { @Shared() isTypeOnly!: boolean; @Shared() propertyName!: SharedIdentifier | undefined; @Shared() name!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExportSpecifier; + return value instanceof SharedNode && value.kind === SyntaxKind.ExportSpecifier; } } /** @internal */ @Shared() -export class SharedExportAssignment extends HasSymbol(HasJSDoc(SharedNodeBase)) { +export class SharedExportAssignment extends HasSymbol(HasJSDoc(SharedNode)) { @Shared() modifiers!: SharedNodeArray | undefined; @Shared() isExportEquals!: boolean | undefined; @Shared() expression!: SharedExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.ExportAssignment; + return value instanceof SharedNode && value.kind === SyntaxKind.ExportAssignment; } } /** @internal */ @Shared() -export class SharedJSDocTypeExpression extends SharedNodeBase { +export class SharedJSDocTypeExpression extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTypeExpression; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTypeExpression; } } /** @internal */ @Shared() -export class SharedJSDocNameReference extends SharedNodeBase { +export class SharedJSDocNameReference extends SharedNode { @Shared() name!: SharedEntityName | SharedJSDocMemberName; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocNameReference; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocNameReference; } } /** @internal */ @Shared() -export class SharedJSDocMemberName extends SharedNodeBase { +export class SharedJSDocMemberName extends SharedNode { @Shared() left!: SharedEntityName | SharedJSDocMemberName; @Shared() right!: SharedIdentifier; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocMemberName; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocMemberName; } } @@ -2294,94 +2294,94 @@ export type SharedJSDocType = /** @internal */ @Shared() -export class SharedJSDocAllType extends SharedNodeBase { +export class SharedJSDocAllType extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocAllType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocAllType; } } /** @internal */ @Shared() -export class SharedJSDocUnknownType extends SharedNodeBase { +export class SharedJSDocUnknownType extends SharedNode { static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocUnknownType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocUnknownType; } } /** @internal */ @Shared() -export class SharedJSDocNonNullableType extends SharedNodeBase { +export class SharedJSDocNonNullableType extends SharedNode { @Shared() type!: SharedTypeNode; @Shared() postfix!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocNonNullableType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocNonNullableType; } } /** @internal */ @Shared() -export class SharedJSDocNullableType extends SharedNodeBase { +export class SharedJSDocNullableType extends SharedNode { @Shared() type!: SharedTypeNode; @Shared() postfix!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocNullableType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocNullableType; } } /** @internal */ @Shared() -export class SharedJSDocOptionalType extends SharedNodeBase { +export class SharedJSDocOptionalType extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocOptionalType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocOptionalType; } } /** @internal */ @Shared() -export class SharedJSDocFunctionType extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedJSDocFunctionType extends HasLocals(HasSymbol(SharedNode)) { @Shared() typeParameters!: SharedNodeArray | undefined; @Shared() parameters!: SharedNodeArray; @Shared() type!: SharedTypeNode | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocFunctionType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocFunctionType; } } /** @internal */ @Shared() -export class SharedJSDocVariadicType extends SharedNodeBase { +export class SharedJSDocVariadicType extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocVariadicType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocVariadicType; } } /** @internal */ @Shared() -export class SharedJSDocNamepathType extends SharedNodeBase { +export class SharedJSDocNamepathType extends SharedNode { @Shared() type!: SharedTypeNode; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocNamepathType; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocNamepathType; } } /** @internal */ @Shared() -export class SharedJSDocNode extends SharedNodeBase { +export class SharedJSDocNode extends SharedNode { @Shared() tags!: SharedNodeArray | undefined; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDoc; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDoc; } } @@ -2415,34 +2415,34 @@ export type SharedJSDocTag = /** @internal */ @Shared() -export class SharedJSDocLink extends SharedNodeBase { +export class SharedJSDocLink extends SharedNode { @Shared() name!: SharedEntityName | SharedJSDocMemberName | undefined; @Shared() text!: string; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocLink; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocLink; } } /** @internal */ @Shared() -export class SharedJSDocLinkCode extends SharedNodeBase { +export class SharedJSDocLinkCode extends SharedNode { @Shared() name!: SharedEntityName | SharedJSDocMemberName | undefined; @Shared() text!: string; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocLinkCode; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocLinkCode; } } /** @internal */ @Shared() -export class SharedJSDocLinkPlain extends SharedNodeBase { +export class SharedJSDocLinkPlain extends SharedNode { @Shared() name!: SharedEntityName | SharedJSDocMemberName | undefined; @Shared() text!: string; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocLinkPlain; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocLinkPlain; } } @@ -2456,213 +2456,213 @@ export type SharedJSDocComment = /** @internal */ @Shared() -export class SharedJSDocText extends SharedNodeBase { +export class SharedJSDocText extends SharedNode { @Shared() text!: string; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocText; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocText; } } /** @internal */ @Shared() -export class SharedJSDocUnknownTag extends SharedNodeBase { +export class SharedJSDocUnknownTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTag; } } /** @internal */ @Shared() -export class SharedJSDocAugmentsTag extends SharedNodeBase { +export class SharedJSDocAugmentsTag extends SharedNode { @Shared() class!: SharedExpressionWithTypeArguments & { readonly expression: SharedIdentifier | SharedPropertyAccessExpression }; @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocAugmentsTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocAugmentsTag; } } /** @internal */ @Shared() -export class SharedJSDocImplementsTag extends SharedNodeBase { +export class SharedJSDocImplementsTag extends SharedNode { @Shared() class!: SharedExpressionWithTypeArguments & { readonly expression: SharedIdentifier | SharedPropertyAccessExpression }; @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocImplementsTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocImplementsTag; } } /** @internal */ @Shared() -export class SharedJSDocAuthorTag extends SharedNodeBase { +export class SharedJSDocAuthorTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocAuthorTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocAuthorTag; } } /** @internal */ @Shared() -export class SharedJSDocDeprecatedTag extends SharedNodeBase { +export class SharedJSDocDeprecatedTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocDeprecatedTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocDeprecatedTag; } } /** @internal */ @Shared() -export class SharedJSDocClassTag extends SharedNodeBase { +export class SharedJSDocClassTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocClassTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocClassTag; } } /** @internal */ @Shared() -export class SharedJSDocPublicTag extends SharedNodeBase { +export class SharedJSDocPublicTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocPublicTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocPublicTag; } } /** @internal */ @Shared() -export class SharedJSDocPrivateTag extends SharedNodeBase { +export class SharedJSDocPrivateTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocPrivateTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocPrivateTag; } } /** @internal */ @Shared() -export class SharedJSDocProtectedTag extends SharedNodeBase { +export class SharedJSDocProtectedTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocProtectedTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocProtectedTag; } } /** @internal */ @Shared() -export class SharedJSDocReadonlyTag extends SharedNodeBase { +export class SharedJSDocReadonlyTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocReadonlyTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocReadonlyTag; } } /** @internal */ @Shared() -export class SharedJSDocOverrideTag extends SharedNodeBase { +export class SharedJSDocOverrideTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocOverrideTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocOverrideTag; } } /** @internal */ @Shared() -export class SharedJSDocEnumTag extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedJSDocEnumTag extends HasLocals(HasSymbol(SharedNode)) { @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; @Shared() typeExpression!: SharedJSDocTypeExpression; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocEnumTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocEnumTag; } } /** @internal */ @Shared() -export class SharedJSDocThisTag extends SharedNodeBase { +export class SharedJSDocThisTag extends SharedNode { @Shared() typeExpression!: SharedJSDocTypeExpression; @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocThisTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocThisTag; } } /** @internal */ @Shared() -export class SharedJSDocTemplateTag extends SharedNodeBase { +export class SharedJSDocTemplateTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() constraint!: SharedJSDocTypeExpression | undefined; @Shared() typeParameters!: SharedNodeArray; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTemplateTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTemplateTag; } } /** @internal */ @Shared() -export class SharedJSDocSeeTag extends SharedNodeBase { +export class SharedJSDocSeeTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() name!: SharedJSDocNameReference | undefined; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocSeeTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocSeeTag; } } /** @internal */ @Shared() -export class SharedJSDocReturnTag extends SharedNodeBase { +export class SharedJSDocReturnTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() typeExpression!: SharedJSDocTypeExpression | undefined; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocReturnTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocReturnTag; } } /** @internal */ @Shared() -export class SharedJSDocTypeTag extends SharedNodeBase { +export class SharedJSDocTypeTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() typeExpression!: SharedJSDocTypeExpression; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTypeTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTypeTag; } } /** @internal */ @Shared() -export class SharedJSDocTypedefTag extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedJSDocTypedefTag extends HasLocals(HasSymbol(SharedNode)) { @Shared() tagName!: SharedIdentifier; @Shared() fullName!: SharedJSDocNamespaceDeclaration | SharedIdentifier | undefined; @Shared() name!: SharedIdentifier | undefined; @@ -2670,13 +2670,13 @@ export class SharedJSDocTypedefTag extends HasLocals(HasSymbol(SharedNodeBase))< @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTypedefTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTypedefTag; } } /** @internal */ @Shared() -export class SharedJSDocCallbackTag extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedJSDocCallbackTag extends HasLocals(HasSymbol(SharedNode)) { @Shared() tagName!: SharedIdentifier; @Shared() fullName!: SharedJSDocNamespaceDeclaration | SharedIdentifier | undefined; @Shared() name!: SharedIdentifier | undefined; @@ -2684,49 +2684,49 @@ export class SharedJSDocCallbackTag extends HasLocals(HasSymbol(SharedNodeBase)) @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocCallbackTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocCallbackTag; } } /** @internal */ @Shared() -export class SharedJSDocOverloadTag extends SharedNodeBase { +export class SharedJSDocOverloadTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() typeExpression!: SharedJSDocSignature; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocOverloadTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocOverloadTag; } } /** @internal */ @Shared() -export class SharedJSDocThrowsTag extends SharedNodeBase { +export class SharedJSDocThrowsTag extends SharedNode { @Shared() tagName!: SharedIdentifier; @Shared() typeExpression!: SharedJSDocTypeExpression | undefined; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocThrowsTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocThrowsTag; } } /** @internal */ @Shared() -export class SharedJSDocSignature extends HasLocals(HasSymbol(SharedNodeBase)) { +export class SharedJSDocSignature extends HasLocals(HasSymbol(SharedNode)) { @Shared() typeParameters!: ReadonlySharedArray | undefined; @Shared() parameters!: ReadonlySharedArray; @Shared() type!: SharedJSDocReturnTag | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocSignature; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocSignature; } } /** @internal */ @Shared() -export class SharedJSDocPropertyTag extends HasSymbol(SharedNodeBase) { +export class SharedJSDocPropertyTag extends HasSymbol(SharedNode) { @Shared() tagName!: SharedIdentifier; @Shared() name!: SharedEntityName; @Shared() typeExpression!: SharedJSDocTypeExpression | undefined; @@ -2735,13 +2735,13 @@ export class SharedJSDocPropertyTag extends HasSymbol(SharedNodeBase) | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocPropertyTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocPropertyTag; } } /** @internal */ @Shared() -export class SharedJSDocParameterTag extends HasSymbol(SharedNodeBase) { +export class SharedJSDocParameterTag extends HasSymbol(SharedNode) { @Shared() tagName!: SharedIdentifier; @Shared() name!: SharedEntityName; @Shared() typeExpression!: SharedJSDocTypeExpression | undefined; @@ -2750,7 +2750,7 @@ export class SharedJSDocParameterTag extends HasSymbol(SharedNodeBase) | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocParameterTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocParameterTag; } } @@ -2762,24 +2762,24 @@ export type SharedJSDocPropertyLikeTag = /** @internal */ @Shared() -export class SharedJSDocTypeLiteral extends HasSymbol(SharedNodeBase) { +export class SharedJSDocTypeLiteral extends HasSymbol(SharedNode) { @Shared() jsDocPropertyTags!: ReadonlySharedArray | undefined; @Shared() isArrayType!: boolean; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocTypeLiteral; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocTypeLiteral; } } /** @internal */ @Shared() -export class SharedJSDocSatisfiesTag extends SharedNodeBase { +export class SharedJSDocSatisfiesTag extends SharedNode { @Shared() typeExpression!: SharedJSDocTypeExpression; @Shared() tagName!: SharedIdentifier; @Shared() comment!: string | SharedNodeArray | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.JSDocSatisfiesTag; + return value instanceof SharedNode && value.kind === SyntaxKind.JSDocSatisfiesTag; } } @@ -2827,7 +2827,7 @@ export class SharedCheckJsDirective extends Tagged(SharedStructBase, Tag.CheckJs /** @internal */ @Shared() -export class SharedCommentRange extends SharedNodeBase { +export class SharedCommentRange extends SharedNode { @Shared() hasTrailingNewLine: boolean | undefined; } @@ -2883,7 +2883,7 @@ export class SharedPragmaSpan extends Tagged(SharedStructBase, Tag.PragmaSpan) { /** @internal */ @Shared() -export class SharedSourceFile extends HasEndFlow(HasLocals(HasSymbol(SharedNodeBase))) { +export class SharedSourceFile extends HasEndFlow(HasLocals(HasSymbol(SharedNode))) { @Shared() statements!: SharedNodeArray; @Shared() endOfFileToken!: SharedEndOfFileToken; @Shared() fileName!: string; @@ -2920,211 +2920,10 @@ export class SharedSourceFile extends HasEndFlow(HasLocals(HasSymbol(SharedNodeB @Shared() version: string | undefined; static [Symbol.hasInstance](value: unknown) { - return value instanceof SharedNodeBase && value.kind === SyntaxKind.SourceFile; + return value instanceof SharedNode && value.kind === SyntaxKind.SourceFile; } } -/** @internal */ -export type SharedNode = - | SharedToken - | SharedIdentifier - | SharedQualifiedName - | SharedComputedPropertyName - | SharedPrivateIdentifier - | SharedDecorator - | SharedTypeParameterDeclaration - | SharedCallSignatureDeclaration - | SharedConstructSignatureDeclaration - | SharedVariableDeclaration - | SharedVariableDeclarationList - | SharedParameterDeclaration - | SharedBindingElement - | SharedPropertySignature - | SharedPropertyDeclaration - | SharedPropertyAssignment - | SharedShorthandPropertyAssignment - | SharedSpreadAssignment - | SharedObjectBindingPattern - | SharedArrayBindingPattern - | SharedFunctionDeclaration - | SharedMethodSignature - | SharedMethodDeclaration - | SharedConstructorDeclaration - | SharedSemicolonClassElement - | SharedGetAccessorDeclaration - | SharedSetAccessorDeclaration - | SharedIndexSignatureDeclaration - | SharedClassStaticBlockDeclaration - | SharedImportTypeAssertionContainer - | SharedImportTypeNode - | SharedThisTypeNode - | SharedFunctionTypeNode - | SharedConstructorTypeNode - | SharedTypeReferenceNode - | SharedTypePredicateNode - | SharedTypeQueryNode - | SharedTypeLiteralNode - | SharedArrayTypeNode - | SharedTupleTypeNode - | SharedNamedTupleMember - | SharedOptionalTypeNode - | SharedRestTypeNode - | SharedUnionTypeNode - | SharedIntersectionTypeNode - | SharedConditionalTypeNode - | SharedInferTypeNode - | SharedParenthesizedTypeNode - | SharedTypeOperatorNode - | SharedIndexedAccessTypeNode - | SharedMappedTypeNode - | SharedLiteralTypeNode - | SharedStringLiteral - | SharedTemplateLiteralTypeNode - | SharedTemplateLiteralTypeSpan - | SharedOmittedExpression - | SharedPrefixUnaryExpression - | SharedPostfixUnaryExpression - | SharedDeleteExpression - | SharedTypeOfExpression - | SharedVoidExpression - | SharedAwaitExpression - | SharedYieldExpression - | SharedBinaryExpression - | SharedConditionalExpression - | SharedFunctionExpression - | SharedArrowFunction - | SharedRegularExpressionLiteral - | SharedNoSubstitutionTemplateLiteral - | SharedNumericLiteral - | SharedBigIntLiteral - | SharedTemplateHead - | SharedTemplateMiddle - | SharedTemplateTail - | SharedTemplateExpression - | SharedTemplateSpan - | SharedParenthesizedExpression - | SharedArrayLiteralExpression - | SharedSpreadElement - | SharedObjectLiteralExpression - | SharedPropertyAccessExpression - | SharedElementAccessExpression - | SharedCallExpression - | SharedExpressionWithTypeArguments - | SharedNewExpression - | SharedTaggedTemplateExpression - | SharedAsExpression - | SharedTypeAssertion - | SharedSatisfiesExpression - | SharedNonNullExpression - | SharedMetaProperty - | SharedJsxElement - | SharedJsxAttributes - | SharedJsxNamespacedName - | SharedJsxOpeningElement - | SharedJsxSelfClosingElement - | SharedJsxFragment - | SharedJsxOpeningFragment - | SharedJsxClosingFragment - | SharedJsxAttribute - | SharedJsxSpreadAttribute - | SharedJsxClosingElement - | SharedJsxExpression - | SharedJsxText - | SharedEmptyStatement - | SharedDebuggerStatement - | SharedMissingDeclaration - | SharedBlock - | SharedVariableStatement - | SharedExpressionStatement - | SharedIfStatement - | SharedDoStatement - | SharedWhileStatement - | SharedForStatement - | SharedForInStatement - | SharedForOfStatement - | SharedBreakStatement - | SharedContinueStatement - | SharedReturnStatement - | SharedWithStatement - | SharedSwitchStatement - | SharedCaseBlock - | SharedCaseClause - | SharedDefaultClause - | SharedLabeledStatement - | SharedThrowStatement - | SharedTryStatement - | SharedCatchClause - | SharedClassDeclaration - | SharedClassExpression - | SharedInterfaceDeclaration - | SharedHeritageClause - | SharedTypeAliasDeclaration - | SharedEnumMember - | SharedEnumDeclaration - | SharedModuleDeclaration - | SharedNamespaceDeclaration - | SharedJSDocNamespaceDeclaration - | SharedModuleBlock - | SharedImportEqualsDeclaration - | SharedExternalModuleReference - | SharedImportDeclaration - | SharedImportClause - | SharedAssertEntry - | SharedAssertClause - | SharedNamespaceImport - | SharedNamespaceExport - | SharedNamespaceExportDeclaration - | SharedExportDeclaration - | SharedNamedImports - | SharedNamedExports - | SharedImportSpecifier - | SharedExportSpecifier - | SharedExportAssignment - | SharedJSDocTypeExpression - | SharedJSDocNameReference - | SharedJSDocMemberName - | SharedJSDocAllType - | SharedJSDocUnknownType - | SharedJSDocNonNullableType - | SharedJSDocNullableType - | SharedJSDocOptionalType - | SharedJSDocFunctionType - | SharedJSDocVariadicType - | SharedJSDocNamepathType - | SharedJSDocNode - | SharedJSDocLink - | SharedJSDocLinkCode - | SharedJSDocLinkPlain - | SharedJSDocText - | SharedJSDocUnknownTag - | SharedJSDocAugmentsTag - | SharedJSDocImplementsTag - | SharedJSDocAuthorTag - | SharedJSDocDeprecatedTag - | SharedJSDocClassTag - | SharedJSDocPublicTag - | SharedJSDocPrivateTag - | SharedJSDocProtectedTag - | SharedJSDocReadonlyTag - | SharedJSDocOverrideTag - | SharedJSDocEnumTag - | SharedJSDocThisTag - | SharedJSDocTemplateTag - | SharedJSDocSeeTag - | SharedJSDocReturnTag - | SharedJSDocTypeTag - | SharedJSDocTypedefTag - | SharedJSDocCallbackTag - | SharedJSDocOverloadTag - | SharedJSDocThrowsTag - | SharedJSDocSignature - | SharedJSDocPropertyTag - | SharedJSDocParameterTag - | SharedJSDocTypeLiteral - | SharedJSDocSatisfiesTag - | SharedSourceFile - ; - const sharedNodeTypes = { // [TokenSyntaxKind]: SharedToken, [SyntaxKind.EndOfFileToken]: SharedEndOfFileToken, @@ -3338,11 +3137,11 @@ export function getSharedConstructorForKind(kind: SyntaxKind): new () => SharedN // Mixins /** @internal */ -export interface SharedJSDocContainer extends SharedNodeBase { +export interface SharedJSDocContainer extends SharedNode { jsDoc: SharedArray | undefined; } -function HasJSDoc SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedJSDocContainer) { +function HasJSDoc SharedNode>(base: F): F & (abstract new (...args: any) => SharedJSDocContainer) { @Shared({ abstract: true }) abstract class HasJSDoc extends base { @Shared() jsDoc: SharedArray | undefined; @@ -3351,12 +3150,12 @@ function HasJSDoc SharedNodeBase>(base: } /** @internal */ -export interface SharedLocalsContainer extends SharedNodeBase { +export interface SharedLocalsContainer extends SharedNode { locals: undefined; nextContainer: undefined; } -function HasLocals SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedLocalsContainer) { +function HasLocals SharedNode>(base: F): F & (abstract new (...args: any) => SharedLocalsContainer) { @Shared({ abstract: true }) abstract class HasLocals extends base { @Shared() locals: undefined; @@ -3366,11 +3165,11 @@ function HasLocals SharedNodeBase>(base } /** @internal */ -export interface SharedFlowNodeContainer extends SharedNodeBase { +export interface SharedFlowNodeContainer extends SharedNode { flowNode: undefined; } -function HasFlowNode SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedFlowNodeContainer) { +function HasFlowNode SharedNode>(base: F): F & (abstract new (...args: any) => SharedFlowNodeContainer) { @Shared({ abstract: true }) abstract class HasFlowNode extends base { @Shared() flowNode: undefined; @@ -3379,12 +3178,12 @@ function HasFlowNode SharedNodeBase>(ba } /** @internal */ -export interface SharedSymbolContainer extends SharedNodeBase { +export interface SharedSymbolContainer extends SharedNode { symbol: undefined; localSymbol: undefined; } -function HasSymbol SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedSymbolContainer) { +function HasSymbol SharedNode>(base: F): F & (abstract new (...args: any) => SharedSymbolContainer) { @Shared({ abstract: true }) abstract class HasSymbol extends base { @Shared() symbol: undefined; @@ -3394,11 +3193,11 @@ function HasSymbol SharedNodeBase>(base } /** @internal */ -export interface SharedEndFlowContainer extends SharedNodeBase { +export interface SharedEndFlowContainer extends SharedNode { endFlowNode: undefined; } -function HasEndFlow SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedEndFlowContainer) { +function HasEndFlow SharedNode>(base: F): F & (abstract new (...args: any) => SharedEndFlowContainer) { @Shared({ abstract: true }) abstract class HasEndFlow extends base { @Shared() endFlowNode: undefined; @@ -3411,7 +3210,7 @@ export interface SharedFunctionFlowContainer extends SharedEndFlowContainer { returnFlowNode: undefined; } -function HasFunctionFlow SharedNodeBase>(base: F): F & (abstract new (...args: any) => SharedFunctionFlowContainer) { +function HasFunctionFlow SharedNode>(base: F): F & (abstract new (...args: any) => SharedFunctionFlowContainer) { @Shared({ abstract: true }) abstract class HasFunctionFlow extends HasEndFlow(base) { @Shared() returnFlowNode: undefined; diff --git a/src/compiler/sharing/sharedNodeAdapter.ts b/src/compiler/sharing/sharedNodeAdapter.ts index 9ea4d81bc79..4ca71a837f1 100644 --- a/src/compiler/sharing/sharedNodeAdapter.ts +++ b/src/compiler/sharing/sharedNodeAdapter.ts @@ -1,17 +1,19 @@ import { AmdDependency, CommentDirective, Debug, Diagnostic, DiagnosticMessageChain, DiagnosticRelatedInformation, DiagnosticWithLocation, FileReference, getJSDocTypeAliasName, hasProperty, JSDocPropertyLikeTag, ReadonlyPragmaMap, setParent, SharedMap } from "../_namespaces/ts"; import { identity } from "../core"; +import { measureActivity } from "../performance"; import { ArrayBindingElement, ArrayBindingPattern, ArrayLiteralExpression, ArrayTypeNode, ArrowFunction, AsExpression, AssertClause, AssertEntry, AssertionKey, AwaitExpression, BigIntLiteral, BinaryExpression, BindingElement, BindingName, BindingPattern, Block, BreakStatement, CallExpression, CallSignatureDeclaration, CaseBlock, CaseClause, CaseOrDefaultClause, CatchClause, ClassDeclaration, ClassElement, ClassExpression, ClassStaticBlockDeclaration, ComputedPropertyName, ConciseBody, ConditionalExpression, ConditionalTypeNode, ConstructorDeclaration, ConstructorTypeNode, ConstructSignatureDeclaration, ContinueStatement, DebuggerStatement, Decorator, DefaultClause, DeleteExpression, DoStatement, ElementAccessExpression, EmptyStatement, EndOfFileToken, EntityName, EnumDeclaration, EnumMember, ExportAssignment, ExportDeclaration, ExportSpecifier, Expression, ExpressionStatement, ExpressionWithTypeArguments, ExternalModuleReference, FalseLiteral, ForInitializer, ForInStatement, ForOfStatement, ForStatement, FunctionDeclaration, FunctionExpression, FunctionTypeNode, GetAccessorDeclaration, HeritageClause, Identifier, IfStatement, ImportClause, ImportDeclaration, ImportEqualsDeclaration, ImportExpression, ImportSpecifier, ImportTypeAssertionContainer, ImportTypeNode, IndexedAccessTypeNode, IndexSignatureDeclaration, InferTypeNode, InterfaceDeclaration, IntersectionTypeNode, JSDoc, JSDocAllType, JSDocAugmentsTag, JSDocAuthorTag, JSDocCallbackTag, JSDocClassTag, JSDocComment, JSDocContainer, JSDocDeprecatedTag, JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, JSDocMemberName, JSDocNamepathType, JSDocNameReference, JSDocNamespaceDeclaration, JSDocNonNullableType, JSDocNullableType, JSDocOptionalType, JSDocOverloadTag, JSDocOverrideTag, JSDocParameterTag, JSDocPrivateTag, JSDocPropertyTag, JSDocProtectedTag, JSDocPublicTag, JSDocReadonlyTag, JSDocReturnTag, JSDocSatisfiesTag, JSDocSeeTag, JSDocSignature, JSDocTag, JSDocTemplateTag, JSDocText, JSDocThisTag, JSDocThrowsTag, JSDocTypedefTag, JSDocTypeExpression, JSDocTypeLiteral, JSDocTypeTag, JSDocUnknownTag, JSDocUnknownType, JSDocVariadicType, JsxAttribute, JsxAttributeLike, JsxAttributeName, JsxAttributes, JsxAttributeValue, JsxChild, JsxClosingElement, JsxClosingFragment, JsxElement, JsxExpression, JsxFragment, JsxNamespacedName, JsxOpeningElement, JsxOpeningFragment, JsxSelfClosingElement, JsxSpreadAttribute, JsxTagNameExpression, JsxTagNamePropertyAccess, JsxText, KeywordTypeNode, LabeledStatement, LeftHandSideExpression, LiteralTypeNode, MappedTypeNode, MemberExpression, MemberName, MetaProperty, MethodDeclaration, MethodSignature, MissingDeclaration, Modifier, ModifierLike, ModuleBlock, ModuleBody, ModuleDeclaration, ModuleName, ModuleReference, MutableNodeArray, NamedExportBindings, NamedExports, NamedImportBindings, NamedImports, NamedTupleMember, NamespaceDeclaration, NamespaceExport, NamespaceExportDeclaration, NamespaceImport, NewExpression, Node, NodeArray, NodeFactory, NonNullExpression, NoSubstitutionTemplateLiteral, NullLiteral, NumericLiteral, ObjectBindingPattern, ObjectLiteralElementLike, ObjectLiteralExpression, OmittedExpression, OptionalTypeNode, ParameterDeclaration, ParenthesizedExpression, ParenthesizedTypeNode, PostfixUnaryExpression, PrefixUnaryExpression, PrimaryExpression, PrivateIdentifier, PropertyAccessEntityNameExpression, PropertyAccessExpression, PropertyAssignment, PropertyDeclaration, PropertyName, PropertySignature, QualifiedName, RegularExpressionLiteral, RestTypeNode, ReturnStatement, SatisfiesExpression, SemicolonClassElement, SetAccessorDeclaration, ShorthandPropertyAssignment, SourceFile, SpreadAssignment, SpreadElement, Statement, StringLiteral, SuperExpression, SwitchStatement, SyntaxKind, TaggedTemplateExpression, TemplateExpression, TemplateHead, TemplateLiteral, TemplateLiteralTypeNode, TemplateLiteralTypeSpan, TemplateMiddle, TemplateSpan, TemplateTail, ThisExpression, ThisTypeNode, ThrowStatement, Token, TokenSyntaxKind, TrueLiteral, TryStatement, TupleTypeNode, TypeAliasDeclaration, TypeAssertion, TypeElement, TypeLiteralNode, TypeNode, TypeOfExpression, TypeOperatorNode, TypeParameterDeclaration, TypePredicateNode, TypeQueryNode, TypeReferenceNode, UnaryExpression, UnionTypeNode, VariableDeclaration, VariableDeclarationList, VariableStatement, VoidExpression, WhileStatement, WithStatement, YieldExpression } from "../types"; import { Mutable } from "../utilities"; import { SharedDiagnostic, SharedDiagnosticMessageChain, SharedDiagnosticRelatedInformation, SharedDiagnosticWithLocation } from "./sharedDiagnostics"; -import { SharedArrayBindingElement, SharedArrayBindingPattern, SharedArrayLiteralExpression, SharedArrayTypeNode, SharedArrowFunction, SharedAsExpression, SharedAssertClause, SharedAssertEntry, SharedAssertionKey, SharedAwaitExpression, SharedBigIntLiteral, SharedBinaryExpression, SharedBindingElement, SharedBindingName, SharedBindingPattern, SharedBlock, SharedBreakStatement, SharedCallExpression, SharedCallSignatureDeclaration, SharedCaseBlock, SharedCaseClause, SharedCaseOrDefaultClause, SharedCatchClause, SharedClassDeclaration, SharedClassElement, SharedClassExpression, SharedClassStaticBlockDeclaration, SharedComputedPropertyName, SharedConciseBody, SharedConditionalExpression, SharedConditionalTypeNode, SharedConstructorDeclaration, SharedConstructorTypeNode, SharedConstructSignatureDeclaration, SharedContinueStatement, SharedDebuggerStatement, SharedDecorator, SharedDefaultClause, SharedDeleteExpression, SharedDoStatement, SharedElementAccessExpression, SharedEmptyStatement, SharedEndOfFileToken, SharedEntityName, SharedEnumDeclaration, SharedEnumMember, SharedExportAssignment, SharedExportDeclaration, SharedExportSpecifier, SharedExpression, SharedExpressionStatement, SharedExpressionWithTypeArguments, SharedExternalModuleReference, SharedForInitializer, SharedForInStatement, SharedForOfStatement, SharedForStatement, SharedFunctionDeclaration, SharedFunctionExpression, SharedFunctionTypeNode, SharedGetAccessorDeclaration, SharedHeritageClause, SharedIdentifier, SharedIfStatement, SharedImportClause, SharedImportDeclaration, SharedImportEqualsDeclaration, SharedImportSpecifier, SharedImportTypeAssertionContainer, SharedImportTypeNode, SharedIndexedAccessTypeNode, SharedIndexSignatureDeclaration, SharedInferTypeNode, SharedInterfaceDeclaration, SharedIntersectionTypeNode, SharedJSDocAllType, SharedJSDocAugmentsTag, SharedJSDocAuthorTag, SharedJSDocCallbackTag, SharedJSDocClassTag, SharedJSDocComment, SharedJSDocContainer, SharedJSDocDeprecatedTag, SharedJSDocEnumTag, SharedJSDocFunctionType, SharedJSDocImplementsTag, SharedJSDocLink, SharedJSDocLinkCode, SharedJSDocLinkPlain, SharedJSDocMemberName, SharedJSDocNamepathType, SharedJSDocNameReference, SharedJSDocNamespaceDeclaration, SharedJSDocNode, SharedJSDocNonNullableType, SharedJSDocNullableType, SharedJSDocOptionalType, SharedJSDocOverloadTag, SharedJSDocOverrideTag, SharedJSDocParameterTag, SharedJSDocPrivateTag, SharedJSDocPropertyLikeTag, SharedJSDocPropertyTag, SharedJSDocProtectedTag, SharedJSDocPublicTag, SharedJSDocReadonlyTag, SharedJSDocReturnTag, SharedJSDocSatisfiesTag, SharedJSDocSeeTag, SharedJSDocSignature, SharedJSDocTag, SharedJSDocTemplateTag, SharedJSDocText, SharedJSDocThisTag, SharedJSDocThrowsTag, SharedJSDocTypedefTag, SharedJSDocTypeExpression, SharedJSDocTypeLiteral, SharedJSDocTypeTag, SharedJSDocUnknownTag, SharedJSDocUnknownType, SharedJSDocVariadicType, SharedJsxAttribute, SharedJsxAttributeLike, SharedJsxAttributeName, SharedJsxAttributes, SharedJsxAttributeValue, SharedJsxChild, SharedJsxClosingElement, SharedJsxClosingFragment, SharedJsxElement, SharedJsxExpression, SharedJsxFragment, SharedJsxNamespacedName, SharedJsxOpeningElement, SharedJsxOpeningFragment, SharedJsxSelfClosingElement, SharedJsxSpreadAttribute, SharedJsxTagNameExpression, SharedJsxText, SharedLabeledStatement, SharedLeftHandSideExpression, SharedLiteralTypeNode, SharedMappedTypeNode, SharedMemberExpression, SharedMemberName, SharedMetaProperty, SharedMethodDeclaration, SharedMethodSignature, SharedMissingDeclaration, SharedModifier, SharedModifierLike, SharedModuleBlock, SharedModuleBody, SharedModuleDeclaration, SharedModuleName, SharedModuleReference, SharedNamedExportBindings, SharedNamedExports, SharedNamedImportBindings, SharedNamedImports, SharedNamedTupleMember, SharedNamespaceExport, SharedNamespaceExportDeclaration, SharedNamespaceImport, SharedNewExpression, SharedNodeBase, SharedNonNullExpression, SharedNoSubstitutionTemplateLiteral, SharedNumericLiteral, SharedObjectBindingPattern, SharedObjectLiteralElement, SharedObjectLiteralExpression, SharedOmittedExpression, SharedOptionalTypeNode, SharedParameterDeclaration, SharedParenthesizedExpression, SharedParenthesizedTypeNode, SharedPostfixUnaryExpression, SharedPrefixUnaryExpression, SharedPrimaryExpression, SharedPrivateIdentifier, SharedPropertyAccessExpression, SharedPropertyAssignment, SharedPropertyDeclaration, SharedPropertyName, SharedPropertySignature, SharedQualifiedName, SharedRegularExpressionLiteral, SharedRestTypeNode, SharedReturnStatement, SharedSatisfiesExpression, SharedSemicolonClassElement, SharedSetAccessorDeclaration, SharedShorthandPropertyAssignment, SharedSourceFile, SharedSpreadAssignment, SharedSpreadElement, SharedStatement, SharedStringLiteral, SharedSwitchStatement, SharedTaggedTemplateExpression, SharedTemplateExpression, SharedTemplateHead, SharedTemplateLiteral, SharedTemplateLiteralTypeNode, SharedTemplateLiteralTypeSpan, SharedTemplateMiddle, SharedTemplateSpan, SharedTemplateTail, SharedThisTypeNode, SharedThrowStatement, SharedToken, SharedTryStatement, SharedTupleTypeNode, SharedTypeAliasDeclaration, SharedTypeAssertion, SharedTypeElement, SharedTypeLiteralNode, SharedTypeNode, SharedTypeOfExpression, SharedTypeOperatorNode, SharedTypeParameterDeclaration, SharedTypePredicateNode, SharedTypeQueryNode, SharedTypeReferenceNode, SharedUnaryExpression, SharedUnionTypeNode, SharedUpdateExpression, SharedVariableDeclaration, SharedVariableDeclarationList, SharedVariableStatement, SharedVoidExpression, SharedWhileStatement, SharedWithStatement, SharedYieldExpression } from "./sharedNode"; +import { SharedArrayBindingElement, SharedArrayBindingPattern, SharedArrayLiteralExpression, SharedArrayTypeNode, SharedArrowFunction, SharedAsExpression, SharedAssertClause, SharedAssertEntry, SharedAssertionKey, SharedAwaitExpression, SharedBigIntLiteral, SharedBinaryExpression, SharedBindingElement, SharedBindingName, SharedBindingPattern, SharedBlock, SharedBreakStatement, SharedCallExpression, SharedCallSignatureDeclaration, SharedCaseBlock, SharedCaseClause, SharedCaseOrDefaultClause, SharedCatchClause, SharedClassDeclaration, SharedClassElement, SharedClassExpression, SharedClassStaticBlockDeclaration, SharedComputedPropertyName, SharedConciseBody, SharedConditionalExpression, SharedConditionalTypeNode, SharedConstructorDeclaration, SharedConstructorTypeNode, SharedConstructSignatureDeclaration, SharedContinueStatement, SharedDebuggerStatement, SharedDecorator, SharedDefaultClause, SharedDeleteExpression, SharedDoStatement, SharedElementAccessExpression, SharedEmptyStatement, SharedEndOfFileToken, SharedEntityName, SharedEnumDeclaration, SharedEnumMember, SharedExportAssignment, SharedExportDeclaration, SharedExportSpecifier, SharedExpression, SharedExpressionStatement, SharedExpressionWithTypeArguments, SharedExternalModuleReference, SharedForInitializer, SharedForInStatement, SharedForOfStatement, SharedForStatement, SharedFunctionDeclaration, SharedFunctionExpression, SharedFunctionTypeNode, SharedGetAccessorDeclaration, SharedHeritageClause, SharedIdentifier, SharedIfStatement, SharedImportClause, SharedImportDeclaration, SharedImportEqualsDeclaration, SharedImportSpecifier, SharedImportTypeAssertionContainer, SharedImportTypeNode, SharedIndexedAccessTypeNode, SharedIndexSignatureDeclaration, SharedInferTypeNode, SharedInterfaceDeclaration, SharedIntersectionTypeNode, SharedJSDocAllType, SharedJSDocAugmentsTag, SharedJSDocAuthorTag, SharedJSDocCallbackTag, SharedJSDocClassTag, SharedJSDocComment, SharedJSDocContainer, SharedJSDocDeprecatedTag, SharedJSDocEnumTag, SharedJSDocFunctionType, SharedJSDocImplementsTag, SharedJSDocLink, SharedJSDocLinkCode, SharedJSDocLinkPlain, SharedJSDocMemberName, SharedJSDocNamepathType, SharedJSDocNameReference, SharedJSDocNamespaceDeclaration, SharedJSDocNode, SharedJSDocNonNullableType, SharedJSDocNullableType, SharedJSDocOptionalType, SharedJSDocOverloadTag, SharedJSDocOverrideTag, SharedJSDocParameterTag, SharedJSDocPrivateTag, SharedJSDocPropertyLikeTag, SharedJSDocPropertyTag, SharedJSDocProtectedTag, SharedJSDocPublicTag, SharedJSDocReadonlyTag, SharedJSDocReturnTag, SharedJSDocSatisfiesTag, SharedJSDocSeeTag, SharedJSDocSignature, SharedJSDocTag, SharedJSDocTemplateTag, SharedJSDocText, SharedJSDocThisTag, SharedJSDocThrowsTag, SharedJSDocTypedefTag, SharedJSDocTypeExpression, SharedJSDocTypeLiteral, SharedJSDocTypeTag, SharedJSDocUnknownTag, SharedJSDocUnknownType, SharedJSDocVariadicType, SharedJsxAttribute, SharedJsxAttributeLike, SharedJsxAttributeName, SharedJsxAttributes, SharedJsxAttributeValue, SharedJsxChild, SharedJsxClosingElement, SharedJsxClosingFragment, SharedJsxElement, SharedJsxExpression, SharedJsxFragment, SharedJsxNamespacedName, SharedJsxOpeningElement, SharedJsxOpeningFragment, SharedJsxSelfClosingElement, SharedJsxSpreadAttribute, SharedJsxTagNameExpression, SharedJsxText, SharedLabeledStatement, SharedLeftHandSideExpression, SharedLiteralTypeNode, SharedMappedTypeNode, SharedMemberExpression, SharedMemberName, SharedMetaProperty, SharedMethodDeclaration, SharedMethodSignature, SharedMissingDeclaration, SharedModifier, SharedModifierLike, SharedModuleBlock, SharedModuleBody, SharedModuleDeclaration, SharedModuleName, SharedModuleReference, SharedNamedExportBindings, SharedNamedExports, SharedNamedImportBindings, SharedNamedImports, SharedNamedTupleMember, SharedNamespaceExport, SharedNamespaceExportDeclaration, SharedNamespaceImport, SharedNewExpression, SharedNode, SharedNonNullExpression, SharedNoSubstitutionTemplateLiteral, SharedNumericLiteral, SharedObjectBindingPattern, SharedObjectLiteralElement, SharedObjectLiteralExpression, SharedOmittedExpression, SharedOptionalTypeNode, SharedParameterDeclaration, SharedParenthesizedExpression, SharedParenthesizedTypeNode, SharedPostfixUnaryExpression, SharedPrefixUnaryExpression, SharedPrimaryExpression, SharedPrivateIdentifier, SharedPropertyAccessExpression, SharedPropertyAssignment, SharedPropertyDeclaration, SharedPropertyName, SharedPropertySignature, SharedQualifiedName, SharedRegularExpressionLiteral, SharedRestTypeNode, SharedReturnStatement, SharedSatisfiesExpression, SharedSemicolonClassElement, SharedSetAccessorDeclaration, SharedShorthandPropertyAssignment, SharedSourceFile, SharedSpreadAssignment, SharedSpreadElement, SharedStatement, SharedStringLiteral, SharedSwitchStatement, SharedTaggedTemplateExpression, SharedTemplateExpression, SharedTemplateHead, SharedTemplateLiteral, SharedTemplateLiteralTypeNode, SharedTemplateLiteralTypeSpan, SharedTemplateMiddle, SharedTemplateSpan, SharedTemplateTail, SharedThisTypeNode, SharedThrowStatement, SharedToken, SharedTryStatement, SharedTupleTypeNode, SharedTypeAliasDeclaration, SharedTypeAssertion, SharedTypeElement, SharedTypeLiteralNode, SharedTypeNode, SharedTypeOfExpression, SharedTypeOperatorNode, SharedTypeParameterDeclaration, SharedTypePredicateNode, SharedTypeQueryNode, SharedTypeReferenceNode, SharedUnaryExpression, SharedUnionTypeNode, SharedUpdateExpression, SharedVariableDeclaration, SharedVariableDeclarationList, SharedVariableStatement, SharedVoidExpression, SharedWhileStatement, SharedWithStatement, SharedYieldExpression } from "./sharedNode"; import { SharedNodeArray } from "./sharedNodeArray"; import { isSharedArray } from "./structs/shareable"; /** @internal */ export function adoptSharedSourceFile(sharedFile: SharedSourceFile, factory: NodeFactory, sharedCache?: ReadonlyMap): SourceFile { + using _ = measureActivity("Parallel: Struct to Object conversion", "beginStructToObject", "endStructToObject"); let file = sharedCache?.get(sharedFile) as SourceFile | undefined; let cache: Map; - let needsParent: [SharedNodeBase, Node][]; + let needsParent: [SharedNode, Node][]; if (!file) { cache = new Map(sharedCache); needsParent = []; @@ -2506,7 +2508,7 @@ export function adoptSharedSourceFile(sharedFile: SharedSourceFile, factory: Nod return cache.get(shared) as U ?? visit(shared); } - function visitNodes(sharedNodes: SharedNodeArray, visit: (value: T) => U): NodeArray { + function visitNodes(sharedNodes: SharedNodeArray, visit: (value: T) => U): NodeArray { const nodes = factory.createNodeArray(visitArray(sharedNodes.items, visit), sharedNodes.hasTrailingComma) as MutableNodeArray; nodes.pos = sharedNodes.pos; nodes.end = sharedNodes.end; @@ -2530,7 +2532,7 @@ export function adoptSharedSourceFile(sharedFile: SharedSourceFile, factory: Nod node.jsDoc = shared.jsDoc && visitArray(shared.jsDoc, visitJSDocNode); } - function finishNode(node: Mutable, shared: SharedNodeBase): T { + function finishNode(node: Mutable, shared: SharedNode): T { node.pos = shared.pos; node.end = shared.end; node.flags = shared.flags; diff --git a/src/compiler/sharing/sharedNodeArray.ts b/src/compiler/sharing/sharedNodeArray.ts index fdba28abcfb..4db167494e6 100644 --- a/src/compiler/sharing/sharedNodeArray.ts +++ b/src/compiler/sharing/sharedNodeArray.ts @@ -1,13 +1,12 @@ import { TransformFlags } from "../types"; -import type { SharedNodeBase } from "./sharedNode"; +import type { SharedNode } from "./sharedNode"; import { Identifiable } from "./structs/identifiableStruct"; -import { isShareableNonPrimitive } from "./structs/shareable"; import { Shared, SharedStructBase } from "./structs/sharedStruct"; import { isTaggedStruct, Tag, Tagged } from "./structs/taggedStruct"; /** @internal */ @Shared() -export class SharedNodeArray extends Identifiable(Tagged(SharedStructBase, Tag.NodeArray)) { +export class SharedNodeArray extends Identifiable(Tagged(SharedStructBase, Tag.NodeArray)) { @Shared() items!: SharedArray; @Shared() pos = -1; @Shared() end = -1; @@ -15,15 +14,13 @@ export class SharedNodeArray extends Identifiable(Tagg @Shared() transformFlags = TransformFlags.None; @Shared() isMissingList = false; - static * values(self: SharedNodeArray): IterableIterator { + static * values(self: SharedNodeArray): IterableIterator { for (let i = 0; i < self.items.length; i++) { yield self.items[i]; } } - static [Symbol.hasInstance](value: unknown): value is SharedNodeArray { - return isShareableNonPrimitive(value) && - isTaggedStruct(value) && - value.__tag__ === Tag.NodeArray; + static [Symbol.hasInstance](value: unknown): value is SharedNodeArray { + return isTaggedStruct(value, Tag.NodeArray); } } diff --git a/src/compiler/sharing/sharedObjectAllocator.ts b/src/compiler/sharing/sharedObjectAllocator.ts index d9ec2e254b4..9e8a659446e 100644 --- a/src/compiler/sharing/sharedObjectAllocator.ts +++ b/src/compiler/sharing/sharedObjectAllocator.ts @@ -1,6 +1,6 @@ import { Identifier, Node, NodeArray, PrivateIdentifier, SourceFile, SyntaxKind, Token } from "../types"; import { ObjectAllocator, objectAllocator } from "../utilities"; -import { getSharedConstructorForKind, SharedNodeBase } from "./sharedNode"; +import { getSharedConstructorForKind } from "./sharedNode"; import { SharedNodeArray } from "./sharedNodeArray"; function NodeArray(items: readonly any[], hasTrailingComma?: boolean) { @@ -15,7 +15,7 @@ function NodeArray(items: readonly any[], hasTrailingComma?: boolean) { function Node(kind: SyntaxKind, pos: number, end: number) { const SharedNode = getSharedConstructorForKind(kind); - const node = new SharedNode() as SharedNodeBase; + const node = new SharedNode(); node.kind = kind; node.pos = pos; node.end = end; diff --git a/src/compiler/sharing/sharedParserState.ts b/src/compiler/sharing/sharedParserState.ts index 6ca12aa8bfb..9261c5ee1eb 100644 --- a/src/compiler/sharing/sharedParserState.ts +++ b/src/compiler/sharing/sharedParserState.ts @@ -1,16 +1,16 @@ import { Condition } from "../threading/condition"; import { Mutex } from "../threading/mutex"; -import { SharedMutex } from "../threading/sharedMutex"; import { ResolutionMode, ScriptTarget } from "../types"; -import { SharedMap } from "./collections/sharedMap"; +import { ConcurrentMap } from "./collections/concurrentMap"; import { SharedSourceFile } from "./sharedNode"; import { Shared, SharedStructBase } from "./structs/sharedStruct"; /** @internal */ @Shared() export class SharedParserState extends SharedStructBase { - @Shared() sharedMutex = new SharedMutex(); - @Shared() files = new SharedMap(); + // @Shared() sharedMutex = new SharedMutex(); + // @Shared() files = new SharedMap(); + @Shared() files = new ConcurrentMap(); } /** @internal */ diff --git a/src/compiler/sharing/structs/sharedStructsGlobals.ts b/src/compiler/sharing/structs/sharedStructsGlobals.ts index 57c4d96640c..b0b28cefa8e 100644 --- a/src/compiler/sharing/structs/sharedStructsGlobals.ts +++ b/src/compiler/sharing/structs/sharedStructsGlobals.ts @@ -44,7 +44,9 @@ declare global { interface SharedStructTypeConstructor { new (fields: readonly (keyof T & string)[]): SharedStructType; - new (fields: readonly string[]): SharedStructType; + new (fields: readonly K[]): SharedStructType & Record; + (fields: readonly (keyof T & string)[]): SharedStructType; + (fields: readonly K[]): SharedStructType & Record; isSharedStruct(value: unknown): value is SharedStruct; } @@ -56,6 +58,11 @@ declare global { readonly length: number; } + type SharedTuple = + & SharedArray + & { readonly length: T["length"] } + & { [P in keyof T as P extends `${bigint}` ? P : never]: T[P] }; + interface ReadonlySharedArray extends SharedArray { readonly [index: number]: T; } @@ -120,5 +127,13 @@ declare global { interface Atomics { readonly Mutex: Atomics.MutexConstructor; readonly Condition: Atomics.ConditionConstructor; + compareExchange(sharedArray: SharedArray, index: number, expectedValue: T, replacementValue: T): T; + compareExchange(sharedStruct: T, key: K, expectedValue: T[K], replacementValue: T[K]): T[K]; + exchange(sharedArray: SharedArray, index: number, value: T): T; + exchange(sharedStruct: T, key: K, value: T[K]): T[K]; + load(sharedArray: SharedArray, index: number): T; + load(sharedStruct: T, key: K): T[K]; + store(sharedArray: SharedArray, index: number, value: T): T; + store(sharedStruct: T, key: K, value: V): V; } } diff --git a/src/compiler/sharing/structs/taggedStruct.ts b/src/compiler/sharing/structs/taggedStruct.ts index 1e53482a53c..e08f0e57922 100644 --- a/src/compiler/sharing/structs/taggedStruct.ts +++ b/src/compiler/sharing/structs/taggedStruct.ts @@ -9,9 +9,12 @@ export const enum Tag { Condition, ManualResetEvent, CountdownEvent, + Thread, Map, Set, ResizableArray, + ConcurrentMap, + Semaphore, NodeArray, Node, Symbol, @@ -53,6 +56,10 @@ export function Tagged SharedStruct, TT abstract class TaggedStruct extends base { static readonly __tag__ = tag; @Shared() readonly __tag__ = tag; + + static [Symbol.hasInstance](value: unknown): boolean { + return isTaggedStruct(value, tag); + } } return TaggedStruct as Tagged; } diff --git a/src/compiler/sharing/structs/wrapper.ts b/src/compiler/sharing/structs/wrapper.ts new file mode 100644 index 00000000000..f561a44d0ea --- /dev/null +++ b/src/compiler/sharing/structs/wrapper.ts @@ -0,0 +1,65 @@ +import { Debug } from "../../debug"; + +/** + * Used in a `declare` instance field of a struct type to override the type we use for a wrapper object generated for + * the struct. We do this because we cannot properly infer correct generic instantiations from generic static methods. + * This declaration intentionally does not produce an actual value as it should only be used in an ambient context. + * @internal + */ +export declare const StructWrapperTypes: unique symbol; + +/** @internal */ +export type StructWrapper = + TInstance extends { [StructWrapperTypes]: infer T extends [any, any][] } ? + T[number] extends [TStatics, infer U] ? U : + SynthesizedStructWrapper : + SynthesizedStructWrapper; + +type SynthesizedStructInstanceFields = { + [P in keyof TInstance & string as Exclude]: TInstance[P]; +}; + +type SynthesizedStructInstanceMethods = { + [P in keyof TStatics & string as TStatics[P] extends (self: TInstance, ...args: any) => any ? Exclude : never]: + TStatics[P] extends (self: TInstance, ...args: infer A) => infer R ? (...args: A) => R : never; +}; + +type SynthesizedStructWrapper = + & SynthesizedStructInstanceFields + & SynthesizedStructInstanceMethods + ; + +/** + * Generates a simple, shallow proxy for a shared struct that treats static methods as instance methods with the first + * parameter bound to the instance. + * @internal + */ +export function wrapStruct(instance: TInstance, statics: TStatics): StructWrapper { + const wrapper = {} as any; + for (const key of Reflect.ownKeys(instance) as Iterable) { + if (typeof key !== "string") continue; + if (key === "__tag__" || key == "__hash__") continue; + Object.defineProperty(wrapper, key, { + enumerable: true, + configurable: false, + get: () => instance[key], + set: (value: TInstance[typeof key]) => instance[key] = value + }); + } + + for (const key of Reflect.ownKeys(statics) as Iterable) { + if (typeof key !== "string") continue; + if (key.startsWith("_")) continue; + const value = statics[key]; + if (typeof value !== "function") continue; + if (Object.prototype.hasOwnProperty.call(value, key)) Debug.fail(`static method name '${key}' conflicts with same named instance field`); + Object.defineProperty(wrapper, key, { + enumerable: false, + configurable: false, + writable: false, + value: value.bind(/*thisArg*/ undefined, instance) + }); + } + + return wrapper as StructWrapper; +} diff --git a/src/compiler/symbolDisposeShim.ts b/src/compiler/symbolDisposeShim.ts index 29e9f95b0dd..68bb1773e97 100644 --- a/src/compiler/symbolDisposeShim.ts +++ b/src/compiler/symbolDisposeShim.ts @@ -1,5 +1,8 @@ /// -export {}; + +import { Debug } from "./debug"; + +export { }; // Shim `Symbol.dispose` so that we can can use `using`. if (!Symbol.dispose) { @@ -10,3 +13,105 @@ if (!Symbol.dispose) { // do nothing } } + +/** @internal */ +export function createSuppressedError(error: unknown, suppressed: unknown) { + if (typeof SuppressedError === "function") { + return Debug.captureStackTrace(new SuppressedError(error, suppressed), createSuppressedError); + } + + const e = new Error("An error suppression occurred.") as SuppressedError; + e.error = error; + e.suppressed = suppressed; + e.name = "SuppressedError"; + return Debug.captureStackTrace(e, createSuppressedError); +} + +/** @internal */ +export function createDisposableStack() { + return new disposableStackConstructor(); +} + +const disposableStackConstructor = typeof DisposableStack === "function" ? DisposableStack : createDisposableStackShim(); + +function createDisposableStackShim(): new () => DisposableStack { + class DisposableStack implements globalThis.DisposableStack { + private _stack: { resource: unknown, dispose: (this: unknown) => void }[] = []; + private _disposed = false; + + get disposed(): boolean { + return this._disposed; + } + + dispose(): void { + if (this._disposed) { + return; + } + + this._disposed = true; + + let error: unknown; + let hasError = false; + let entry; + while (entry = this._stack.pop()) { + try { + const { resource, dispose } = entry; + dispose.call(resource); + } + catch (e) { + error = hasError ? createSuppressedError(e, error) : e; + hasError = true; + } + } + + if (hasError) { + throw error; + } + } + + use(value: T): T { + if (this._disposed) throw new ReferenceError("Object is disposed"); + if (value === undefined) return value; + Debug.assert(typeof value === "object"); + if (!value) return value; + const dispose = value[Symbol.dispose]; + Debug.assert(typeof dispose === "function"); + this._stack.push({ resource: value, dispose }); + return value; + } + + adopt(value: T, onDispose: (value: T) => void): T { + if (this._disposed) throw new ReferenceError("Object is disposed"); + Debug.assert(typeof onDispose === "function"); + this._stack.push({ resource: undefined, dispose: () => { onDispose(value); } }); + return value; + } + + defer(onDispose: () => void): void { + if (this._disposed) throw new ReferenceError("Object is disposed"); + Debug.assert(typeof onDispose === "function"); + this._stack.push({ resource: undefined, dispose: onDispose }); + } + + move(): globalThis.DisposableStack { + if (this._disposed) throw new ReferenceError("Object is disposed"); + const stack = new DisposableStack(); + stack._stack = this._stack; + this._stack = []; + this._disposed = true; + return stack; + } + + [Symbol.dispose](): void { + this.dispose(); + } + + [Symbol.toStringTag]!: string; + + static { + this.prototype[Symbol.dispose] = this.prototype.dispose; + Object.defineProperty(this.prototype, Symbol.toStringTag, { configurable: true, writable: true, value: "DisposableStack" }); + } + } + return DisposableStack; +} diff --git a/src/compiler/threading/condition.ts b/src/compiler/threading/condition.ts index c53e08dfeb3..f16007fdd00 100644 --- a/src/compiler/threading/condition.ts +++ b/src/compiler/threading/condition.ts @@ -25,10 +25,10 @@ export class Condition extends Tagged(SharedStructBase, Tag.Condition) { * @param self The condition to wait for. * @param lock A {@link UniqueLock} taken for a {@link Mutex}. * @param timeout The number of milliseconds to wait before returning. - * @returns `"no-timeout"` if the condition was notified before the timeout elapsed, or `"timeout"` to indicate the + * @returns `"ok"` if the condition was notified before the timeout elapsed, or `"timed-out"` to indicate the * timeout elapsed before the condition was notified. */ - static waitFor(self: Condition, lock: UniqueLock, timeout: number): "no-timeout" | "timeout"; + static waitFor(self: Condition, lock: UniqueLock, timeout: number): "ok" | "timed-out"; /** * Waits until a Condition is signaled via a call to {@link notify|`Condition.notify`}, or until a timeout period * has elapsed. @@ -40,7 +40,7 @@ export class Condition extends Tagged(SharedStructBase, Tag.Condition) { * `false` to indicate that the timeout elapsed before the condition was ready. */ static waitFor(self: Condition, lock: UniqueLock, timeout: number, stopWaiting: () => boolean): boolean; - static waitFor(self: Condition, lock: UniqueLock, timeout: number, stopWaiting?: () => boolean): "no-timeout" | "timeout" | boolean { + static waitFor(self: Condition, lock: UniqueLock, timeout: number, stopWaiting?: () => boolean): "ok" | "timed-out" | boolean { return Condition.waitUntil(self, lock, Date.now() + timeout, stopWaiting!); } @@ -49,10 +49,10 @@ export class Condition extends Tagged(SharedStructBase, Tag.Condition) { * @param self The condition to wait for. * @param lock A {@link UniqueLock} taken for a {@link Mutex}. * @param absoluteTimeout The number of milliseconds since the UNIX epoch. - * @returns `"no-timeout"` if the condition was notified before the timeout elapsed, or `"timeout"` to indicate the + * @returns `"ok"` if the condition was notified before the timeout elapsed, or `"timed-out"` to indicate the * timeout elapsed before the condition was notified. */ - static waitUntil(self: Condition, lock: UniqueLock, absoluteTimeout: number): "no-timeout" | "timeout"; + static waitUntil(self: Condition, lock: UniqueLock, absoluteTimeout: number): "ok" | "timed-out"; /** * Waits until a Condition is signaled via a call to {@link notify|`Condition.notify`}, or until a specific time has been reached. * @param self The condition to wait for. @@ -63,7 +63,7 @@ export class Condition extends Tagged(SharedStructBase, Tag.Condition) { * `false` to indicate that the timeout elapsed before the condition was ready. */ static waitUntil(self: Condition, lock: UniqueLock, absoluteTimeout: number, stopWaiting: () => boolean): boolean; - static waitUntil(self: Condition, lock: UniqueLock, absoluteTimeout: number, stopWaiting?: () => boolean): "no-timeout" | "timeout" | boolean { + static waitUntil(self: Condition, lock: UniqueLock, absoluteTimeout: number, stopWaiting?: () => boolean): "ok" | "timed-out" | boolean { const mutex = lock.mutex; Debug.assert(mutex); Debug.assert(mutex["_locked"]); // eslint-disable-line dot-notation -- declared `private` @@ -75,12 +75,12 @@ export class Condition extends Tagged(SharedStructBase, Tag.Condition) { Atomics.Condition.notify(nativeCondition); try { const remainingTimeout = isFinite(absoluteTimeout) ? Date.now() - absoluteTimeout : undefined; - const result = Atomics.Condition.wait(self._condition, nativeMutex, remainingTimeout) ? "no-timeout" : "timeout"; - if (result === "timeout") { + const result = Atomics.Condition.wait(self._condition, nativeMutex, remainingTimeout) ? "ok" : "timed-out"; + if (result === "timed-out") { return stopWaiting ? stopWaiting() : result; } if (!stopWaiting) { - return "no-timeout"; + return "ok"; } } finally { diff --git a/src/compiler/threading/countdownEvent.ts b/src/compiler/threading/countdownEvent.ts index 1026caf2cad..58fd2162f5e 100644 --- a/src/compiler/threading/countdownEvent.ts +++ b/src/compiler/threading/countdownEvent.ts @@ -99,7 +99,7 @@ export class CountdownEvent extends Tagged(SharedStructBase, Tag.CountdownEvent) using lck = new UniqueLock(self._mutex); if (timeout !== undefined) { - return Condition.waitFor(self._condition, lck, timeout) !== "timeout"; + return Condition.waitFor(self._condition, lck, timeout) !== "timed-out"; } else { Condition.wait(self._condition, lck); diff --git a/src/compiler/threading/lockable.ts b/src/compiler/threading/lockable.ts index a8151997211..8fd6b093b1f 100644 --- a/src/compiler/threading/lockable.ts +++ b/src/compiler/threading/lockable.ts @@ -1,10 +1,6 @@ /** @internal */ -export interface BasicLockable { +export interface Lockable { + tryLock(): boolean; lock(): void; unlock(): void; } - -/** @internal */ -export interface Lockable extends BasicLockable { - tryLock(): boolean; -} diff --git a/src/compiler/threading/manualResetEvent.ts b/src/compiler/threading/manualResetEvent.ts index 4158bb2df1a..fdd5f7fcd46 100644 --- a/src/compiler/threading/manualResetEvent.ts +++ b/src/compiler/threading/manualResetEvent.ts @@ -1,5 +1,5 @@ import { Shared, SharedStructBase } from "../sharing/structs/sharedStruct"; -import { Tag, Tagged } from "../sharing/structs/taggedStruct"; +import { isTaggedStruct, Tag, Tagged } from "../sharing/structs/taggedStruct"; /** @internal */ @Shared() @@ -38,4 +38,8 @@ export class ManualResetEvent extends Tagged(SharedStructBase, Tag.ManualResetEv static wait(self: ManualResetEvent, timeout?: number) { return Atomics.Mutex.lock(self.mutex, () => Atomics.Condition.wait(self.condition, self.mutex, timeout)); } + + static [Symbol.hasInstance](value: unknown): value is ManualResetEvent { + return isTaggedStruct(value, Tag.ManualResetEvent); + } } \ No newline at end of file diff --git a/src/compiler/threading/mutex.ts b/src/compiler/threading/mutex.ts index c39a9b03fbf..8063f77876d 100644 --- a/src/compiler/threading/mutex.ts +++ b/src/compiler/threading/mutex.ts @@ -1,8 +1,7 @@ -import { hasProperty } from "../core"; import { Debug } from "../debug"; import { Identifiable } from "../sharing/structs/identifiableStruct"; import { Shared, SharedStructBase } from "../sharing/structs/sharedStruct"; -import { Tag, Tagged, TaggedStruct } from "../sharing/structs/taggedStruct"; +import { isTaggedStruct, Tag, Tagged } from "../sharing/structs/taggedStruct"; import { Lockable } from "./lockable"; let tryLock: (self: Mutex, cacheKey?: object) => boolean; @@ -120,9 +119,7 @@ export class Mutex extends Identifiable(Tagged(SharedStructBase, Tag.Mutex)) { } static [Symbol.hasInstance](value: unknown): value is Mutex { - return typeof value === "object" && value !== null && // eslint-disable-line no-null/no-null -- necessary for comparison - hasProperty(value, "__tag__") && - (value as TaggedStruct).__tag__ === Tag.Mutex; + return isTaggedStruct(value, Tag.Mutex); } } @@ -135,19 +132,19 @@ class LockableMutex implements Lockable { } tryLock(): boolean { - Debug.assert(!this._ownsLock); + Debug.assert(!this._ownsLock, "cannot take a lock you aleady own."); this._ownsLock = tryLock(this._mutex, this); return this._ownsLock; } lock(): void { - Debug.assert(!this._ownsLock); + Debug.assert(!this._ownsLock, "cannot take a lock you aleady own."); lock(this._mutex, this); this._ownsLock = true; } unlock(): void { - Debug.assert(this._ownsLock); + Debug.assert(this._ownsLock, "cannot release a lock you do not own."); unlock(this._mutex, this); this._ownsLock = false; } diff --git a/src/compiler/threading/scopedLock.ts b/src/compiler/threading/scopedLock.ts index a0f3efe29ef..658c31c5d95 100644 --- a/src/compiler/threading/scopedLock.ts +++ b/src/compiler/threading/scopedLock.ts @@ -1,5 +1,5 @@ -import { Debug } from "../debug"; import "../symbolDisposeShim"; +import { createSuppressedError } from "../symbolDisposeShim"; import { Lockable } from "./lockable"; import { Mutex } from "./mutex"; @@ -9,13 +9,13 @@ import { SharedMutex } from "./sharedMutex"; export class ScopedLock { private _mutexes: readonly Lockable[] | undefined; - constructor(mutexes: Iterable) { + constructor(mutexes: ArrayLike | Iterable) { const array: Lockable[] = []; - for (const mutex of mutexes) { + for (const mutex of Array.from(mutexes)) { array.push( mutex instanceof Mutex ? Mutex.asLockable(mutex) : - mutex instanceof SharedMutex ? SharedMutex.asLockable(mutex) : - mutex); + mutex instanceof SharedMutex ? SharedMutex.asLockable(mutex) : + mutex); } let remaining = array.length; @@ -36,30 +36,28 @@ export class ScopedLock { // always wait for the first lock lockable.lock(); } - else { - if (lockable.tryLock()) { - // this lock was taken. move to the next lock - index = (index + 1) % array.length; - remaining--; - } - else { - // if we fail to take a lock, unlock each lock taken so far so that we start over at the current - // index. - let i = (index + array.length - 1) % array.length; - while (remaining < array.length) { - // always unlock all locks taken, even if one unlock fails for some reason. - try { - array[i].unlock(); - } - catch (e) { - error = error ? createSuppressedError(e, error) : e; - hasError = true; - } - i = (index + array.length - 1) % array.length; - remaining++; + else if (!lockable.tryLock()) { + // if we fail to take a lock, unlock each lock taken so far so that we start over at the current + // index. + let i = (index + array.length - 1) % array.length; + while (remaining < array.length) { + // always unlock all locks taken, even if one unlock fails for some reason. + try { + array[i].unlock(); } + catch (e) { + error = error ? createSuppressedError(e, error) : e; + hasError = true; + } + i = (index + array.length - 1) % array.length; + remaining++; } + continue; } + + // this lock was taken. move to the next lock + index = (index + 1) % array.length; + remaining--; } catch (e) { error = error ? createSuppressedError(e, error) : e; @@ -94,15 +92,3 @@ export class ScopedLock { } } } - -function createSuppressedError(error: unknown, suppressed: unknown) { - if (typeof SuppressedError === "function") { - return Debug.captureStackTrace(new SuppressedError(error, suppressed), createSuppressedError); - } - - const e = new Error("An error suppression occurred.") as SuppressedError; - e.error = error; - e.suppressed = suppressed; - e.name = "SuppressedError"; - return Debug.captureStackTrace(e, createSuppressedError); -} diff --git a/src/compiler/threading/semaphore.ts b/src/compiler/threading/semaphore.ts new file mode 100644 index 00000000000..ffa9116a73c --- /dev/null +++ b/src/compiler/threading/semaphore.ts @@ -0,0 +1,93 @@ +import { Condition, Debug, Mutex, Shared, SharedStructBase, Tag, Tagged, UniqueLock } from "../_namespaces/ts"; +import { AtomicValue } from "../sharing/atomicValue"; + +/** @internal */ +@Shared() +export class Semaphore extends Tagged(SharedStructBase, Tag.Semaphore) { + @Shared() private readonly _maxCount: number; + @Shared() private readonly _currentCount: AtomicValue; + @Shared() private readonly _waitCount = new AtomicValue(0); + @Shared() private readonly _mutex = new Mutex(); + @Shared() private readonly _condition = new Condition(); + + constructor(initialCount: number, maxCount: number = 2 ** 31 - 1) { + Debug.assert(initialCount === (initialCount | 0) && initialCount >= 0); + Debug.assert(maxCount >= 0 && maxCount >= initialCount); + super(); + this._maxCount = maxCount; + this._currentCount = new AtomicValue(initialCount); + } + + static count(self: Semaphore) { + return AtomicValue.load(self._currentCount); + } + + static tryAcquire(self: Semaphore, timeout?: number) { + if (timeout !== undefined) { + if (isNaN(timeout) || isFinite(timeout)) timeout |= 0; + if (timeout < 0) timeout = 0; + } + + // first, try to acquire a count lock-free + let count = AtomicValue.load(self._currentCount); + if (count > 0 && count === (count = AtomicValue.compareExchange(self._currentCount, count, count - 1))) { + return true; + } + if (timeout === undefined) { + return false; + } + + const start = Date.now(); + let remaining: number; + + // if that fails, take a lock and wait for a spot to open up + using lck = new UniqueLock(self._mutex); + using _waiter = waitScope(self._waitCount); + do { + remaining = timeout - (Date.now() - start); + if (count <= 0) { + if (Condition.waitFor(self._condition, lck, remaining) === "timed-out") { + return false; + } + count = AtomicValue.load(self._currentCount); + } + else if (count === (count = AtomicValue.compareExchange(self._currentCount, count, count - 1))) { + return true; + } + } + while (remaining >= 0); + return false; + } + + static acquire(self: Semaphore) { + Semaphore.tryAcquire(self, Infinity); + } + + static release(self: Semaphore, count = 1) { + let previousCount = AtomicValue.load(self._currentCount); + let nextCount: number; + let waitCount: number; + do { + Debug.assert(self._maxCount - previousCount >= count); + nextCount = previousCount + count; + waitCount = AtomicValue.load(self._waitCount); + } + while (previousCount !== (previousCount = AtomicValue.compareExchange(self._currentCount, previousCount, nextCount))); + if (nextCount === 1 && waitCount === 1) { + Condition.notify(self._condition, 1); + } + else if (waitCount > 1) { + Condition.notify(self._condition); + } + return previousCount; + } +} + +function waitScope(count: AtomicValue) { + AtomicValue.increment(count); + return { + [Symbol.dispose]() { + AtomicValue.decrement(count); + } + }; +} \ No newline at end of file diff --git a/src/compiler/threading/sharedGuard.ts b/src/compiler/threading/sharedGuard.ts new file mode 100644 index 00000000000..00a2a3d9cf3 --- /dev/null +++ b/src/compiler/threading/sharedGuard.ts @@ -0,0 +1,102 @@ +// import { Shared, SharedStructBase } from "../_namespaces/ts"; +// import { AtomicValue } from "../sharing/atomicValue"; + +// @Shared() +// class DataStruct extends SharedStructBase { +// @Shared() internalCounter = new AtomicValue(0); +// @Shared() object: T; + +// constructor(object: T) { +// super(); +// this.object = object; +// } + +// static releaseRef(self: DataStruct) { +// if (AtomicValue.add(self.internalCounter, 1) == -1) { +// DataStruct.destroy(self); +// } +// } + +// static destroy(self: DataStruct) { +// self.internalCounter = undefined!; +// self.object = undefined!; +// } +// } + +// @Shared() +// class DataPtrStruct extends SharedStructBase { +// @Shared() externalCounter: number; +// @Shared() ptr: DataStruct | undefined; +// constructor(ptr: DataStruct | undefined, externalCounter = 0) { +// super(); +// this.ptr = ptr; +// this.externalCounter = externalCounter; +// } +// } + +// class DataGuard { +// private _ptr: DataStruct | undefined; + +// constructor(ptr: DataStruct | undefined) { +// this._ptr = ptr; +// } + +// get isValid() { return !!this._ptr; } + +// get object() { +// if (!this._ptr) throw new ReferenceError("Object is disposed"); +// return this._ptr.object; +// } + +// replaceWith(other: DataGuard) { +// if (this._ptr) { +// DataStruct.releaseRef(this._ptr); +// } +// this._ptr = other._ptr; +// other._ptr = undefined; +// return this; +// } + +// move() { +// const obj = new DataGuard(this._ptr); +// this._ptr = undefined; +// return obj; +// } + +// [Symbol.dispose]() { +// if (this._ptr) { +// DataStruct.releaseRef(this._ptr); +// this._ptr = undefined; +// } +// } +// } + +// @Shared() +// class SharedGuard extends SharedStructBase { +// @Shared() private data_ptr = new AtomicValue>(new DataPtrStruct(undefined)); + +// private static release(old_data_ptr: DataPtrStruct) { +// if (!old_data_ptr.ptr) return; +// const external = old_data_ptr.externalCounter; +// if (AtomicValue.sub(old_data_ptr.ptr.internalCounter, external) === external - 1) { +// DataStruct.destroy(old_data_ptr.ptr); +// } +// else { +// DataStruct.releaseRef(old_data_ptr.ptr); +// } +// } + +// static destroy(self: SharedGuard) { +// const old_data_ptr = AtomicValue.load(self.data_ptr); +// SharedGuard.release(old_data_ptr); +// } + +// static acquire(self: SharedGuard) { +// let new_data_ptr: DataPtrStruct; +// const old_data_ptr = AtomicValue.load(self.data_ptr); +// do { +// new_data_ptr = new DataPtrStruct(old_data_ptr.ptr, old_data_ptr.externalCounter + 1); +// } +// while (!AtomicValue.compareAndSwap(self.data_ptr, old_data_ptr, new_data_ptr)); +// } +// } \ No newline at end of file diff --git a/src/compiler/threading/sharedLock.ts b/src/compiler/threading/sharedLock.ts index df067f3f595..3aa1fcae927 100644 --- a/src/compiler/threading/sharedLock.ts +++ b/src/compiler/threading/sharedLock.ts @@ -10,9 +10,7 @@ export class SharedLock { private _lockable: SharedLockable | undefined; private _ownsLock = false; - constructor(); - constructor(mutex: T, t?: "defer-lock" | "try-to-lock" | "adopt-lock"); - constructor(mutex?: T, t?: "defer-lock" | "try-to-lock" | "adopt-lock") { + constructor(mutex?: T, t?: "lock" | "defer-lock" | "try-to-lock" | "adopt-lock") { this._mutex = mutex; this._lockable = mutex instanceof SharedMutex ? SharedMutex.asSharedLockable(mutex) : @@ -27,6 +25,7 @@ export class SharedLock { case "adopt-lock": this._ownsLock = true; break; + case "lock": case undefined: this._lockable.lockShared(); this._ownsLock = true; @@ -72,10 +71,10 @@ export class SharedLock { swap(other: SharedLock) { const mutex = other._mutex; - other._mutex = this._mutex; const lockable = other._lockable; - other._lockable = this._lockable; const ownsLock = other._ownsLock; + other._mutex = this._mutex; + other._lockable = this._lockable; other._ownsLock = this._ownsLock; this._mutex = mutex; this._lockable = lockable; @@ -84,12 +83,7 @@ export class SharedLock { move() { const other = new SharedLock(); - other._mutex = this._mutex; - other._lockable = this._lockable; - other._ownsLock = this._ownsLock; - this._mutex = undefined; - this._lockable = undefined; - this._ownsLock = false; + this.swap(other); return other; } diff --git a/src/compiler/threading/sharedMutex.ts b/src/compiler/threading/sharedMutex.ts index 03c21a8a43f..18381ff9546 100644 --- a/src/compiler/threading/sharedMutex.ts +++ b/src/compiler/threading/sharedMutex.ts @@ -1,10 +1,9 @@ import "../symbolDisposeShim"; -import { hasProperty } from "../core"; import { Debug } from "../debug"; import { Identifiable } from "../sharing/structs/identifiableStruct"; import { Shared, SharedStructBase } from "../sharing/structs/sharedStruct"; -import { Tag, Tagged, TaggedStruct } from "../sharing/structs/taggedStruct"; +import { isTaggedStruct, Tag, Tagged } from "../sharing/structs/taggedStruct"; import { Lockable } from "./lockable"; import { SharedLockable } from "./sharedLockable"; @@ -216,9 +215,7 @@ export class SharedMutex extends Identifiable(Tagged(SharedStructBase, Tag.Share } static [Symbol.hasInstance](value: unknown): value is SharedMutex { - return typeof value === "object" && value !== null && // eslint-disable-line no-null/no-null -- necessary for comparision - hasProperty(value, "__tag__") && - (value as TaggedStruct).__tag__ === Tag.SharedMutex; + return isTaggedStruct(value, Tag.SharedMutex); } } diff --git a/src/compiler/threading/sleep.ts b/src/compiler/threading/sleep.ts new file mode 100644 index 00000000000..55e98c1e783 --- /dev/null +++ b/src/compiler/threading/sleep.ts @@ -0,0 +1,15 @@ +let mutex: Atomics.Mutex; +let condition: Atomics.Condition; +let timeout: number; + +/** @internal */ +export function sleep(ms: number) { + mutex ??= new Atomics.Mutex(); + condition ??= new Atomics.Condition(); + timeout = ms; + Atomics.Mutex.lock(mutex, sleepWorker); +} + +function sleepWorker() { + Atomics.Condition.wait(condition, mutex, timeout | 0); +} diff --git a/src/compiler/threading/spinWait.ts b/src/compiler/threading/spinWait.ts new file mode 100644 index 00000000000..0315f3ed68c --- /dev/null +++ b/src/compiler/threading/spinWait.ts @@ -0,0 +1,31 @@ +import { sys } from "../sys"; +import { sleep } from "./sleep"; + +const cpuCount = sys.cpuCount?.() ?? 1; + +export class SpinWait { + private _count = 0; + + reset() { + this._count = 0; + } + + spinOnce() { + const count = this._count; + if (cpuCount > 0 && count < 10) { + for (let i = 0; i < count; i++) { + // busy loop, do nothing + } + } + else if ((count - 10) % 20 === 19) { + sleep(1); + } + // else if ((count - 10) % 5 === 4) { + // sleep(1); + // } + else { + sleep(0); + } + this._count = (count + 1) >>> 0; + } +} diff --git a/src/compiler/threading/threadPool.ts b/src/compiler/threading/threadPool.ts index 8a8eafe7a84..85aa9631d77 100644 --- a/src/compiler/threading/threadPool.ts +++ b/src/compiler/threading/threadPool.ts @@ -1,15 +1,19 @@ -import { WorkerThreadsHost, Worker, workerThreads } from "../workerThreads"; -import { SharedLinkedList } from "../sharing/collections/sharedLinkedList"; -import { Shared, SharedStructBase } from "../sharing/structs/sharedStruct"; -import { Mutex } from "./mutex"; -import { Condition } from "./condition"; -import { UniqueLock } from "./uniqueLock"; +import { combinePaths, getAnyExtensionFromPath, getBaseFileName, getDirectoryPath, isTaggedStruct, removeExtension, sys, Tag, Tagged } from "../_namespaces/ts"; +import { isNodeLikeSystem, noop } from "../core"; import { Debug } from "../debug"; -import { isNodeLikeSystem } from "../core"; -import { CountdownEvent } from "./countdownEvent"; +import { Deque } from "../sharing/collections/deque"; +import { Shared, SharedStructBase } from "../sharing/structs/sharedStruct"; +import { Worker, workerThreads, WorkerThreadsHost } from "../workerThreads"; +import { Condition } from "./condition"; +import { Mutex } from "./mutex"; +import { SpinWait } from "./spinWait"; +import { UniqueLock } from "./uniqueLock"; + +const WORK_STEALING = true; +const PER_THREAD_QUEUE = true; @Shared() -class ThreadPoolWorkItem extends SharedStructBase { +class Task extends SharedStructBase { @Shared() readonly name: string; @Shared() readonly arg: Shareable; @@ -20,40 +24,145 @@ class ThreadPoolWorkItem extends SharedStructBase { } } -/** @internal */ @Shared() -export class ThreadPoolState extends SharedStructBase { - @Shared() mutex = new Mutex(); - @Shared() condition = new Condition(); - @Shared() countdown = new CountdownEvent(1); - @Shared() queue = new SharedLinkedList(); - @Shared() active = 0; +class TaskQueue extends SharedStructBase { + @Shared() private mutex = new Mutex(); + @Shared() private condition = new Condition(); + @Shared() private dequeue = new Deque(); @Shared() done = false; - @Shared() error: string | undefined; + + static tryDequeue(self: TaskQueue) { + return Deque.popBottom(self.dequeue); + } + + static dequeue(self: TaskQueue) { + const done = self.done; + const task = TaskQueue.tryDequeue(self); + if (task || done) { + return task; + } + + using lck = new UniqueLock(self.mutex); + while (true) { + const done = self.done; + const task = TaskQueue.tryDequeue(self); + if (task || done) { + return task; + } + Condition.wait(self.condition, lck); + } + } + + static steal(self: TaskQueue) { + return Deque.steal(self.dequeue); + } + + static enqueue(self: TaskQueue, task: Task) { + Debug.assert(!self.done); + Deque.pushBottom(self.dequeue, task); + Condition.notify(self.condition, 1); + } + + static done(self: TaskQueue) { + self.done = true; + Condition.notify(self.condition); + } +} + +@Shared() +class TaskScheduler extends SharedStructBase { + @Shared() queues: SharedArray; + @Shared() nextTaskId = 0; + @Shared() mutex = new Mutex(); + + constructor(poolSize: number) { + super(); + this.queues = new SharedArray(PER_THREAD_QUEUE ? poolSize : 1); + const queueCount = this.queues.length; + for (let i = 0; i < queueCount; i++) { + this.queues[i] = new TaskQueue(); + } + } + + static shutdown(self: TaskScheduler) { + const queueCount = self.queues.length; + for (let i = 0; i < queueCount; i++) { + TaskQueue.done(self.queues[i]); + } + } + + static scheduleTask(self: TaskScheduler, task: Task) { + const queueCount = self.queues.length; + const spin = new SpinWait(); + + let queueId: number; + while (true) { + const previousValue = Atomics.load(self, "nextTaskId"); + const nextValue = (previousValue + 1) >>> 0; + if (Atomics.compareExchange(self, "nextTaskId", previousValue, nextValue) === previousValue) { + queueId = previousValue % queueCount; + break; + } + spin.spinOnce(); + } + + TaskQueue.enqueue(self.queues[queueId], task); + // TODO: wake all queues to steal work? + } + + static takeTask(self: TaskScheduler, queueId: number) { + const queues = self.queues; + + // first, try to take work from our queue + const done = queues[queueId].done; + const task = TaskQueue.tryDequeue(queues[queueId]); + if (task || done) { + return task; + } + + if (WORK_STEALING && PER_THREAD_QUEUE) { + // next, try to steal work from an open queue + const queueCount = queues.length; + for (let i = 1; i < queueCount; i++) { + const queue = queues[(queueId + i) % queueCount]; + const task = TaskQueue.steal(queue); + if (task) { + return task; + } + } + } + + // finally, if that fails, perform a blocking dequeue on our queue + return TaskQueue.dequeue(queues[queueId]); + } } /** * Creates a thread pool of one or more worker threads. A {@link ThreadPool} can only be created on the main thread. * @internal */ -export class ThreadPool { +export class ThreadPool implements Disposable { readonly poolSize: number; private readonly _host: WorkerThreadsHost; + private readonly _generateCpuProfile: string | undefined; private _workers: Worker[] = []; - private _state = new ThreadPoolState(); + private _threads: Thread[] = []; + private _scheduler: TaskScheduler | undefined; private _listening = false; private _onUncaughtException = () => { - if (!this._state.done) { + if (this._scheduler) { this.abort(); } }; - constructor(poolSize: number, host = workerThreads ?? Debug.fail("Worker threads not available.")) { + constructor(poolSize: number, host = workerThreads ?? Debug.fail("Worker threads not available."), generateCpuProfile?: string) { Debug.assert(poolSize >= 1); Debug.assert(host.isMainThread(), "A new thread pool can only be created on the main thread."); this.poolSize = poolSize; + this._generateCpuProfile = generateCpuProfile; + this._scheduler = new TaskScheduler(poolSize); this._host = host; } @@ -61,31 +170,71 @@ export class ThreadPool { * Starts all threads in the thread pool. */ start(): void { + Debug.assert(this._scheduler, "Object is disposed"); + if (this._workers.length < this.poolSize) { this._startListening(); } + + const queueCount = this._scheduler.queues.length; for (let i = this._workers.length; i < this.poolSize; i++) { - this._workers.push(this._host.createWorker({ - name: "ThreadPool Thread", - workerData: { type: "ThreadPoolThread", state: this._state } - })); + const thread = new Thread(this._scheduler, i % queueCount, this._generateCpuProfile); + this._threads[i] = thread; + + const worker = this._host.createWorker({ name: "ThreadPool Thread", workerData: thread }); + this._workers[i] = worker; } } /** * Disable the addition of new work items in the thread pool and wait for threads to terminate gracefully. */ - stop(timeout?: number) { - this._shutdown(); - return CountdownEvent.wait(this._state.countdown, timeout); + shutdown() { + if (!this._scheduler) { + return; + } + + this._stopListening(); + + const scheduler = this._scheduler; + const threads = this._threads.slice(); + + this._scheduler = undefined; + this._threads.length = 0; + this._workers.length = 0; + + // mark all queues as done + TaskScheduler.shutdown(scheduler); + + // join all threads + for (const thread of threads) { + Thread.join(thread); + } + + Debug.log.trace("Thread pool shut down."); } /** * Immediately stop all threads in the thread pool and wait for them to terminate. */ async abort() { - this._shutdown(); - const workers = this._workers.splice(0, this._workers.length); + if (!this._scheduler) { + return; + } + + this._stopListening(); + + const scheduler = this._scheduler; + const workers = this._workers.slice(); + + this._scheduler = undefined; + this._threads.length = 0; + this._workers.length = 0; + + // mark all queues as done + TaskScheduler.shutdown(scheduler); + + // terminate all workers await Promise.all(workers.map(worker => worker.terminate())); } @@ -96,24 +245,8 @@ export class ThreadPool { * thread. */ queueWorkItem(name: string, arg?: Shareable) { - { - using _ = new UniqueLock(this._state.mutex); - SharedLinkedList.push(this._state.queue, new ThreadPoolWorkItem(name, arg)); - } - - Condition.notify(this._state.condition, 1); - } - - private _shutdown() { - this._stopListening(); - - Debug.log.trace("Shutting down thread pool"); - if (!this._state.done) { - using _ = new UniqueLock(this._state.mutex); - this._state.done = true; - Condition.notify(this._state.condition); - CountdownEvent.signal(this._state.countdown, 1); - } + Debug.assert(this._scheduler, "Object is disposed"); + TaskScheduler.scheduleTask(this._scheduler, new Task(name, arg)); } private _startListening() { @@ -134,98 +267,102 @@ export class ThreadPool { process.off("uncaughtExceptionMonitor", this._onUncaughtException); } } + + [Symbol.dispose]() { + this.shutdown(); + } } /** - * Represents a thread in a {@link ThreadPool} and can be used to process work items. A {@link ThreadPoolThread} should - * only be used in a worker thread. - * @internal + * Entrypoint method for a thread pool thread, invoking the `processTask` callback whenever a task is available. This + * function only exits once its associated queue is done adding new tasks and is empty. This function is only available + * from a worker thread. */ -export class ThreadPoolThread { - private _state: ThreadPoolState; - private _processWorkItem: (name: string, arg: Shareable) => void; +export let runThread: (processTask: (name: string, arg: Shareable) => void) => void; - constructor(state: ThreadPoolState, processWorkItem: (name: string, arg: Shareable) => void) { - this._state = state; - this._processWorkItem = processWorkItem; +/** + * Queue a new task in a background thread in the thread pool. This function is only available from a worker thread. + */ +export let queueWorkItem: (name: string, arg?: Shareable) => void; + +const enum ThreadState { + NotStarted, + Running, + Exited, +} + +@Shared() +class Thread extends Tagged(SharedStructBase, Tag.Thread) { + @Shared() private mutex = new Mutex(); + @Shared() private condition = new Condition(); + @Shared() private scheduler: TaskScheduler; + @Shared() private queueId: number; + @Shared() private generateCpuProfile: string | undefined; + @Shared() state = ThreadState.NotStarted; + + constructor(scheduler: TaskScheduler, queueId: number, generateCpuProfile?: string) { + super(); + this.scheduler = scheduler; + this.queueId = queueId; + this.generateCpuProfile = generateCpuProfile; } - /** - * Runs the thread pool thread until the {@link ThreadPool} signals the thread should shut down. - */ - run() { - let running = true; - let started = false; - try { - const processWorkItem = this._processWorkItem; - if (!CountdownEvent.tryAdd(this._state.countdown, 1)) { - Debug.log.trace("thread pool is already shut down"); - return; + static join(self: Thread) { + using lck = new UniqueLock(self.mutex); + Condition.wait(self.condition, lck, () => self.state === ThreadState.Exited); + } + + static [Symbol.hasInstance](value: unknown) { + return isTaggedStruct(value, Tag.Thread); + } + + static { + function runLoop(thread: Thread, processTask: (name: string, arg: Shareable) => void) { + let task: Task | undefined; + while (task = TaskScheduler.takeTask(thread.scheduler, thread.queueId)) { + processTask(task.name, task.arg); } + } - while (running) { - let workItem: ThreadPoolWorkItem | undefined; - { - using lck = new UniqueLock(this._state.mutex); + runThread = function (processTask) { + Debug.assert(workerThreads?.isWorkerThread() && workerThreads.workerData instanceof Thread, "This function may only be called from a thread pool thread."); + const thread = workerThreads.workerData; - // decrement the active thread counter before we start waiting for work - if (started) { - this._state.active--; - } - - // wait until we have work to do - Condition.wait(this._state.condition, lck, () => this._state.queue.size > 0 || this._state.done); - - // stop the thread if the thread pool is closed - if (this._state.done) { - if (started) { - this._state.active--; - } - running = false; - break; - } - - // increment the active thread counter before we start processing a work item - this._state.active++; - started = true; - workItem = SharedLinkedList.shift(this._state.queue); - } - - // process the workitem - if (workItem) { + const state = thread.state; + Debug.assert(state === ThreadState.NotStarted); + Debug.assert(state === Atomics.compareExchange(thread, "state", state, ThreadState.Running)); + try { + if (thread.generateCpuProfile && sys.enableCPUProfiler && sys.disableCPUProfiler) { + const dirname = getDirectoryPath(thread.generateCpuProfile); + const basename = getBaseFileName(thread.generateCpuProfile); + const extname = getAnyExtensionFromPath(basename); + const basenameNoExtension = removeExtension(basename, extname); + const cpuProfilePath = combinePaths(dirname, `${basenameNoExtension}-${workerThreads.threadId}${extname}`); + sys.enableCPUProfiler(cpuProfilePath, noop); try { - processWorkItem(workItem.name, workItem.arg); + runLoop(thread, processTask); } - catch (e) { - Debug.log.trace(e); - running = false; - using _ = new UniqueLock(this._state.mutex); - this._state.active--; - break; + finally { + sys.disableCPUProfiler(noop); } } + else { + runLoop(thread, processTask); + } } - } - catch (e) { - Debug.log.trace(e); - } + catch (e) { + Debug.log.trace(e); + } + finally { + thread.state = ThreadState.Exited; + Condition.notify(thread.condition); + } + }; - // Debug.log.trace(`shutting down.`); - CountdownEvent.signal(this._state.countdown); - } - - /** - * Queue additional work to be performed in another thread. - */ - queueWorkItem(name: string, arg?: Shareable) { - Debug.assert(!this._state.done); - - { - using _ = new UniqueLock(this._state.mutex); - Debug.assert(!this._state.done); - SharedLinkedList.push(this._state.queue, new ThreadPoolWorkItem(name, arg)); - } - - Condition.notify(this._state.condition, 1); + queueWorkItem = function (name, arg) { + Debug.assert(workerThreads?.isWorkerThread() && workerThreads.workerData instanceof Thread, "This function may only be called from a thread pool thread."); + const thread = workerThreads.workerData; + TaskScheduler.scheduleTask(thread.scheduler, new Task(name, arg)); + }; } } diff --git a/src/compiler/threading/uniqueLock.ts b/src/compiler/threading/uniqueLock.ts index 3f95db5f4ab..dedf717037d 100644 --- a/src/compiler/threading/uniqueLock.ts +++ b/src/compiler/threading/uniqueLock.ts @@ -1,25 +1,17 @@ import "../symbolDisposeShim"; -import { hasProperty } from "../core"; import { Debug } from "../debug"; -import { BasicLockable, Lockable } from "./lockable"; +import { Lockable } from "./lockable"; import { Mutex } from "./mutex"; import { SharedMutex } from "./sharedMutex"; -function isLockable(x: BasicLockable): x is Lockable { - return x instanceof UniqueLock ? !!x.mutex && isLockable(x.mutex) : hasProperty(x, "tryLock") && typeof (x as Lockable).tryLock === "function"; -} - /** @internal */ -export class UniqueLock { +export class UniqueLock { private _mutex: T | undefined; - private _lockable: BasicLockable | undefined; + private _lockable: Lockable | undefined; private _ownsLock = false; - constructor(mutex?: T); - constructor(mutex: Extract, t?: "defer-lock" | "try-to-lock" | "adopt-lock"); - constructor(mutex: T, t?: "defer-lock" | "adopt-lock"); - constructor(mutex?: T, t?: "defer-lock" | "try-to-lock" | "adopt-lock") { + constructor(mutex?: T, t?: "lock" | "defer-lock" | "try-to-lock" | "adopt-lock") { this._mutex = mutex; this._lockable = mutex instanceof Mutex ? Mutex.asLockable(mutex) : @@ -30,12 +22,12 @@ export class UniqueLock { case "defer-lock": break; case "try-to-lock": - Debug.assert(isLockable(this._lockable)); this._ownsLock = this._lockable.tryLock(); break; case "adopt-lock": this._ownsLock = true; break; + case "lock": case undefined: this._lockable.lock(); this._ownsLock = true; @@ -55,7 +47,6 @@ export class UniqueLock { tryLock(this: UniqueLock>): boolean { Debug.assert(this._lockable); Debug.assert(!this._ownsLock); - Debug.assert(isLockable(this._lockable)); this._ownsLock = this._lockable.tryLock(); return this._ownsLock; } @@ -94,12 +85,7 @@ export class UniqueLock { move() { const other = new UniqueLock(); - other._mutex = this._mutex; - other._lockable = this._lockable; - other._ownsLock = this._ownsLock; - this._mutex = undefined; - this._lockable = undefined; - this._ownsLock = false; + this.swap(other); return other; } diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts index 4f091195827..ffad910f2dc 100644 --- a/src/compiler/tracing.ts +++ b/src/compiler/tracing.ts @@ -170,6 +170,18 @@ export namespace tracingEnabled { } eventStack.length = 0; } + + const popActivity = { + [Symbol.dispose]() { + pop(); + } + }; + + export function traceActivity(phase: Phase, name: string, args?: Args, separateBeginAndEnd?: boolean): Disposable { + push(phase, name, args, separateBeginAndEnd); + return popActivity; + } + // sample every 10ms const sampleInterval = 1000 * 10; function writeStackEvent(index: number, endTime: number, results?: Args) { diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 07a1f205bd9..8437485e1f6 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -347,8 +347,10 @@ export function createSolutionBuilder(host: SolutionBu return createSolutionBuilderWorker(/*watch*/ false, host, rootNames, defaultOptions); } -export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { - return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions, baseWatchOptions); +export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder; +/** @internal */ export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions, threadPoolLifetime?: DisposableStack): SolutionBuilder; +export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions, threadPoolLifetime?: DisposableStack): SolutionBuilder { + return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions, baseWatchOptions, threadPoolLifetime); } type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic; @@ -430,9 +432,11 @@ interface SolutionBuilderState extends WatchFactory void; + + readonly threadPoolLifetime: DisposableStack | undefined; } -function createSolutionBuilderState(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions: WatchOptions | undefined): SolutionBuilderState { +function createSolutionBuilderState(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions: WatchOptions | undefined, threadPoolLifetime: DisposableStack | undefined): SolutionBuilderState { const host = hostOrHostWithWatch as SolutionBuilderHost; const hostWithWatch = hostOrHostWithWatch as SolutionBuilderWithWatchHost; @@ -546,6 +550,9 @@ function createSolutionBuilderState(watch: boolean, ho watchFile, watchDirectory, writeLog, + + // once we've reached this point we can take ownership of the threadPool's lifetime + threadPoolLifetime: threadPoolLifetime?.move(), }; return state; @@ -2455,6 +2462,7 @@ function startWatching(state: SolutionBuilderState, } function stopWatching(state: SolutionBuilderState) { + using _ = state.threadPoolLifetime; clearMap(state.allWatchedConfigFiles, closeFileWatcher); clearMap(state.allWatchedExtendedConfigFiles, closeFileWatcherOf); clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf)); @@ -2467,9 +2475,9 @@ function stopWatching(state: SolutionBuilderState) * can dynamically add/remove other projects based on changes on the rootNames' references */ function createSolutionBuilderWorker(watch: false, host: SolutionBuilderHost, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder; -function createSolutionBuilderWorker(watch: true, host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder; -function createSolutionBuilderWorker(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { - const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options, baseWatchOptions); +function createSolutionBuilderWorker(watch: true, host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions, threadPoolLifetime?: DisposableStack): SolutionBuilder; +function createSolutionBuilderWorker(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions?: WatchOptions, threadPoolLifetime?: DisposableStack): SolutionBuilder { + const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options, baseWatchOptions, threadPoolLifetime); return { build: (project, cancellationToken, writeFile, getCustomTransformers) => build(state, project, cancellationToken, writeFile, getCustomTransformers), clean: project => clean(state, project), diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 31eb10b026d..b3da29d42d3 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig-base", "compilerOptions": { "types": ["node"], - "experimentalDecorators": true + "experimentalDecorators": true, + "strictBindCallApply": true }, "references": [ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index df3e00d76e1..1132f38aab6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -20,8 +20,7 @@ import { ThreadPool, WorkerThreadsHost, } from "./_namespaces/ts"; -import { SharedNodeBase } from "./sharing/sharedNode"; -import { SharedParserState } from "./sharing/sharedParserState"; +import { SharedNode } from "./sharing/sharedNode"; // branded string type used to store absolute, normalized and canonicalized paths // arbitrary file name can be converted to Path via toPath function @@ -931,7 +930,7 @@ export interface Node extends ReadonlyTextRange { // `locals` and `nextContainer` have been moved to `LocalsContainer` // `flowNode` has been moved to `FlowContainer` // see: https://github.com/microsoft/TypeScript/pull/51682 - /** @internal */ __shared__?: SharedNodeBase; + /** @internal */ __shared__?: SharedNode; } export interface JSDocContainer extends Node { @@ -7772,7 +7771,7 @@ export type HasInvalidatedLibResolutions = (libFileName: string) => boolean; export type HasChangedAutomaticTypeDirectiveNames = () => boolean; export interface CompilerHost extends ModuleResolutionHost { - /** @internal */ requestSourceFile?(parserState: SharedParserState, fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, shouldCreateNewSourceFile?: boolean, setFileVersion?: boolean): void; + /** @internal */ requestSourceFile?(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, shouldCreateNewSourceFile?: boolean, setFileVersion?: boolean): void; getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; getCancellationToken?(): CancellationToken; diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index a1715dbc519..f46bf8459ab 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -18,7 +18,6 @@ import { createIncrementalCompilerHost, createIncrementalProgram, CreateProgram, - createRequestSourceFile, createWriteFileMeasuringIO, CustomTransformers, Debug, @@ -73,6 +72,7 @@ import { isReferenceFileLocation, isString, last, + makeCompilerHostParallel, maybeBind, memoize, ModuleKind, @@ -108,7 +108,7 @@ import { WatchStatusReporter, whitespaceOrMapCommentRegExp, WorkerThreadsHost, - WriteFileCallback, + WriteFileCallback } from "./_namespaces/ts"; const sysFormatDiagnosticsHost: FormatDiagnosticsHost | undefined = sys ? { @@ -744,7 +744,6 @@ export function createWatchFactory(host: WatchFactoryHost & { tra export function createCompilerHostFromProgramHost(host: ProgramHost, getCompilerOptions: () => CompilerOptions, directoryStructureHost: DirectoryStructureHost = host): CompilerHost { const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); const compilerHost: CompilerHost = { - requestSourceFile: host.threadPool && createRequestSourceFile(host.threadPool, /*setParentNodes*/ undefined), getSourceFile: createGetSourceFile( (fileName, encoding) => !encoding ? compilerHost.readFile(fileName) : host.readFile(fileName, encoding), getCompilerOptions, @@ -773,8 +772,10 @@ export function createCompilerHostFromProgramHost(host: ProgramHost, getCom readDirectory: maybeBind(host, host.readDirectory), storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit, workerThreads: host.workerThreads, - threadPool: host.threadPool, }; + if (host.threadPool) { + makeCompilerHostParallel(compilerHost, host.threadPool, /*setParentNodes*/ undefined); + } return compilerHost; } @@ -821,18 +822,12 @@ export function getSourceFileVersionAsHashFromText(host: Pick { - const result = originalGetSourceFile.call(compilerHost, ...args); + const result = originalGetSourceFile.call(compilerHost, ...args) as SourceFile | undefined; if (result) { - result.version = getSourceFileVersionAsHashFromText(compilerHost, result.text); + result.version ??= getSourceFileVersionAsHashFromText(compilerHost, result.text); } return result; }; - const originalRequestSourceFile = compilerHost.requestSourceFile; - if (originalRequestSourceFile) { - compilerHost.requestSourceFile = (parserState, fileName, languageVersionOrOptions, shouldCreateNewSourceFile) => { - originalRequestSourceFile.call(compilerHost, parserState, fileName, languageVersionOrOptions, shouldCreateNewSourceFile, /*setFileVersion*/ true); - }; - } } /** diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 24457865607..9e55a8ccf5d 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -410,9 +410,11 @@ type WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile(host: WatchCompilerHostOfFilesAndCompilerOptions): WatchOfFilesAndCompilerOptions; /** * Creates the watch from the host for config file - */ +*/ export function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; -export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { +/** @internal */ export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions, threadPoolLifetime?: DisposableStack): WatchOfFilesAndCompilerOptions; +/** @internal */ export function createWatchProgram(host: WatchCompilerHostOfConfigFile, threadPoolLifetime?: DisposableStack): WatchOfConfigFile; +export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile, _threadPoolLifetime?: DisposableStack): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { interface FilePresentOnHost { version: string; sourceFile: SourceFile; @@ -549,11 +551,15 @@ export function createWatchProgram(host: WatchCompiler // Update extended config file watch if (configFileName) updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); + // once we've reached this point we can take ownership of the thread pool's lifetime + const threadPoolLifetime = _threadPoolLifetime?.move(); + return configFileName ? { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } : { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; function close() { + using _ = threadPoolLifetime; clearInvalidateResolutionsOfFailedLookupLocations(); resolutionCache.clear(); clearMap(sourceFilesCache, value => { diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 1c7eb04b119..9f597de468b 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -689,20 +689,17 @@ export function getWatchFactory(host: WatchFactoryHost, watchL return { watchFile: createExcludeHandlingAddWatch("watchFile"), - watchDirectory: createExcludeHandlingAddWatch("watchDirectory") + watchDirectory: createExcludeHandlingAddWatch("watchDirectory"), }; - function createExcludeHandlingAddWatch>(key: T): WatchFactory[T] { - return ( - file: string, - cb: FileWatcherCallback | DirectoryWatcherCallback, - flags: PollingInterval | WatchDirectoryFlags, - options: WatchOptions | undefined, - detailInfo1: X, - detailInfo2?: Y - ) => !matchesExclude(file, key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, useCaseSensitiveFileNames(), host.getCurrentDirectory?.() || "") ? - factory[key].call(/*thisArgs*/ undefined, file, cb, flags, options, detailInfo1, detailInfo2) : + function createExcludeHandlingAddWatch>(key: K): WatchCallback { + return (...args) => { + const [file, , flags, options, detailInfo1, detailInfo2] = args; + const f = factory[key] as WatchCallback; + return !matchesExclude(file, key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, useCaseSensitiveFileNames(), host.getCurrentDirectory?.() || "") ? + f(...args) : excludeWatcherFactory(file, flags, options, detailInfo1, detailInfo2); + }; } function useCaseSensitiveFileNames() { @@ -768,22 +765,26 @@ export function getWatchFactory(host: WatchFactoryHost, watchL }; } - function createTriggerLoggingAddWatch>(key: T): WatchFactory[T] { - return ( - file: string, - cb: FileWatcherCallback | DirectoryWatcherCallback, - flags: PollingInterval | WatchDirectoryFlags, - options: WatchOptions | undefined, - detailInfo1: X, - detailInfo2?: Y - ) => plainInvokeFactory[key].call(/*thisArgs*/ undefined, file, (...args: any[]) => { + type WatchCallback> = (...args: Parameters[K]>) => FileWatcher; + + function addTriggerLoggingToCallback(cb: (...args: A) => void, key: keyof WatchFactory, file: string, flags: PollingInterval | WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, detailInfo2: Y | undefined): (...args: A) => void { + return (...args: A) => { const triggerredInfo = `${key === "watchFile" ? "FileWatcher" : "DirectoryWatcher"}:: Triggered with ${args[0]} ${args[1] !== undefined ? args[1] : ""}:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; log(triggerredInfo); const start = timestamp(); - cb.call(/*thisArg*/ undefined, ...args); + cb(...args); const elapsed = timestamp() - start; log(`Elapsed:: ${elapsed}ms ${triggerredInfo}`); - }, flags, options, detailInfo1, detailInfo2); + }; + } + + function createTriggerLoggingAddWatch>(key: K): WatchCallback { + return (...args) => { + const [file, cb, flags, options, detailInfo1, detailInfo2] = args; + const f = plainInvokeFactory[key] as WatchCallback; + args[1] = addTriggerLoggingToCallback(cb, key, file, flags, options, detailInfo1, detailInfo2); + return f(...args); + }; } function getWatchInfo(file: string, flags: T, options: WatchOptions | undefined, detailInfo1: X, detailInfo2: Y | undefined, getDetailWatchInfo: GetDetailWatchInfo | undefined) { diff --git a/src/compiler/worker.ts b/src/compiler/worker.ts index c5d05d825ed..05f3d63fb4a 100644 --- a/src/compiler/worker.ts +++ b/src/compiler/worker.ts @@ -1,4 +1,4 @@ -import { createCompilerHostWorker, Debug, isNodeLikeSystem, setGetSourceFileAsHashVersioned, sys, System, ThreadPoolState, ThreadPoolThread, workerThreads, WorkerThreadWorkerThreadsHost } from "./_namespaces/ts"; +import { createCompilerHostWorker, Debug, isNodeLikeSystem, runThread, setGetSourceFileAsHashVersioned, setSys, setWorkerThreadsHost, System, workerThreads, WorkerThreadWorkerThreadsHost } from "./_namespaces/ts"; import { SharedSourceFile } from "./sharing/sharedNode"; import { getSharedObjectAllocator } from "./sharing/sharedObjectAllocator"; import { SharedSourceFileEntry } from "./sharing/sharedParserState"; @@ -6,19 +6,21 @@ import { Condition } from "./threading/condition"; import { UniqueLock } from "./threading/uniqueLock"; /** @internal */ -export function executeWorker(_system: System, host: WorkerThreadWorkerThreadsHost) { +export function executeWorker(system: System, host: WorkerThreadWorkerThreadsHost) { // if (process.execArgv.includes("--inspect-brk")) { // const inspector = require("node:inspector") as typeof import("node:inspector"); // inspector.open(); // inspector.waitForDebugger(); // } + setSys(system); + setWorkerThreadsHost(host); if (isNodeLikeSystem()) { const fs: typeof import("fs") = require("fs"); const util: typeof import("util") = require("util"); Debug.loggingHost = { log(_level, s) { - fs.writeSync(2, `[worker#${host.threadId}] ${s || ""}${sys.newLine}`); + fs.writeSync(2, `[worker#${host.threadId}] ${s || ""}${system.newLine}`); }, format(...args) { return util.formatWithOptions({ colors: true }, ...args); @@ -26,26 +28,13 @@ export function executeWorker(_system: System, host: WorkerThreadWorkerThreadsHo }; } - const { workerData } = host; - Debug.assert(workerData); - const { type } = workerData as { type: string }; - switch (type) { - case "ThreadPoolThread": { - const { state } = workerData as { state: ThreadPoolState }; - const thread = new ThreadPoolThread(state, (name, arg) => { - switch (name) { - case "Program.requestSourceFile": - programRequestSourceFile(arg as SharedSourceFileEntry); - break; - } - }); - thread.run(); - break; + runThread((name, arg) => { + switch (name) { + case "Program.requestSourceFile": + programRequestSourceFile(arg as SharedSourceFileEntry); + break; } - default: - Debug.fail(`Unsupported worker type: '${type}'.`); - break; - } + }); function programRequestSourceFile(entry: SharedSourceFileEntry) { let ok = false; @@ -53,7 +42,7 @@ export function executeWorker(_system: System, host: WorkerThreadWorkerThreadsHo try { // Debug.log.trace(`parsing: ${entry.fileName}`); const overideObjectAllocator = getSharedObjectAllocator(); - const host = createCompilerHostWorker({}, entry.setParentNodes, sys, workerThreads, /*threadPool*/ undefined, overideObjectAllocator); + const host = createCompilerHostWorker({}, entry.setParentNodes, system, workerThreads, /*threadPool*/ undefined, overideObjectAllocator); if (entry.setFileVersion) { setGetSourceFileAsHashVersioned(host); } diff --git a/src/executeCommandLine/executeCommandLine.ts b/src/executeCommandLine/executeCommandLine.ts index 5bbcd398b33..100706afe80 100644 --- a/src/executeCommandLine/executeCommandLine.ts +++ b/src/executeCommandLine/executeCommandLine.ts @@ -1,4 +1,5 @@ import * as performance from "../compiler/performance"; +import { createDisposableStack } from "../compiler/symbolDisposeShim"; import { arrayFrom, BuilderProgram, @@ -34,6 +35,7 @@ import { DiagnosticMessage, DiagnosticReporter, Diagnostics, + dispose, dumpTracingLegend, EmitAndSemanticDiagnosticsBuilderProgram, emitFilesAndReportErrorsAndGetExitStatus, @@ -638,12 +640,8 @@ function executeCommandLineWorker( return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } - let threadPool: ThreadPool | undefined; - const maxCpuCount = getMaxCpuCount(commandLine.options); - if (maxCpuCount > 1 && workerThreads?.isMainThread()) { - threadPool = new ThreadPool(maxCpuCount, workerThreads); - threadPool.start(); - } + using threadPoolLifetime = createDisposableStack(); + const threadPool = threadPoolLifetime.use(tryCreateThreadPool(commandLine.options, workerThreads)); const currentDirectory = sys.getCurrentDirectory(); const commandLineOptions = convertToOptionsWithAbsolutePaths( @@ -661,10 +659,12 @@ function executeCommandLineWorker( configParseResult.options ); configParseResult.errors.forEach(reportDiagnostic); + dispose(threadPoolLifetime); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } // eslint-disable-next-line no-null/no-null sys.write(JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine); + dispose(threadPoolLifetime); return sys.exit(ExitStatus.Success); } reportDiagnostic = updateReportDiagnostic( @@ -684,6 +684,7 @@ function executeCommandLineWorker( extendedConfigCache, workerThreads, threadPool, + threadPoolLifetime, // hand off the lifetime of the thread pool ); } else if (isIncrementalCompilation(configParseResult.options)) { @@ -694,6 +695,7 @@ function executeCommandLineWorker( configParseResult, workerThreads, threadPool, + threadPoolLifetime, ); } else { @@ -704,6 +706,7 @@ function executeCommandLineWorker( configParseResult, workerThreads, threadPool, + threadPoolLifetime, ); } } @@ -711,6 +714,7 @@ function executeCommandLineWorker( if (commandLineOptions.showConfig) { // eslint-disable-next-line no-null/no-null sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine); + dispose(threadPoolLifetime); return sys.exit(ExitStatus.Success); } reportDiagnostic = updateReportDiagnostic( @@ -729,6 +733,7 @@ function executeCommandLineWorker( commandLine.watchOptions, workerThreads, threadPool, + threadPoolLifetime // hand off the lifetime of the thread pool ); } else if (isIncrementalCompilation(commandLineOptions)) { @@ -739,6 +744,7 @@ function executeCommandLineWorker( { ...commandLine, options: commandLineOptions }, workerThreads, threadPool, + threadPoolLifetime, ); } else { @@ -749,6 +755,7 @@ function executeCommandLineWorker( { ...commandLine, options: commandLineOptions }, workerThreads, threadPool, + threadPoolLifetime, ); } } @@ -818,6 +825,15 @@ function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: Diagnos return false; } +function tryCreateThreadPool(options: BuildOptions | CompilerOptions, workerThreads: WorkerThreadsHost | undefined) { + const maxCpuCount = getMaxCpuCount(options); + if (maxCpuCount > 1 && workerThreads?.isMainThread()) { + const threadPool = new ThreadPool(maxCpuCount, workerThreads, options.generateCpuProfile); + threadPool.start(); + return threadPool; + } +} + function performBuild( sys: System, cb: ExecuteCommandLineCallbacks, @@ -860,15 +876,10 @@ function performBuild( return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } - let threadPool: ThreadPool | undefined; - const maxCpuCount = getMaxCpuCount(buildOptions); - if (maxCpuCount > 1 && workerThreads?.isMainThread()) { - threadPool = new ThreadPool(maxCpuCount, workerThreads); - } - if (buildOptions.watch) { if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; - threadPool?.start(); + using threadPoolLifetime = createDisposableStack(); + const threadPool = threadPoolLifetime.use(tryCreateThreadPool(buildOptions, workerThreads)); const buildHost = createSolutionBuilderWithWatchHost( sys, /*createProgram*/ undefined, @@ -891,14 +902,15 @@ function performBuild( reportSolutionBuilderTimes(builder, solutionPerformance); } }; - const builder = createSolutionBuilderWithWatch(buildHost, projects, buildOptions, watchOptions); + const builder = createSolutionBuilderWithWatch(buildHost, projects, buildOptions, watchOptions, threadPoolLifetime); builder.build(); reportSolutionBuilderTimes(builder, solutionPerformance); reportBuildStatistics = true; return builder; } - threadPool?.start(); + using threadPoolLifetime = createDisposableStack(); + const threadPool = threadPoolLifetime.use(tryCreateThreadPool(buildOptions, workerThreads)); const buildHost = createSolutionBuilderHost( sys, /*createProgram*/ undefined, @@ -914,7 +926,7 @@ function performBuild( const exitStatus = buildOptions.clean ? builder.clean() : builder.build(); reportSolutionBuilderTimes(builder, solutionPerformance); dumpTracingLegend(); // Will no-op if there hasn't been any tracing - threadPool?.stop(); + dispose(threadPoolLifetime); return sys.exit(exitStatus); } @@ -931,6 +943,7 @@ function performCompilation( config: ParsedCommandLine, workerThreads: WorkerThreadsHost | undefined, threadPool: ThreadPool | undefined, + threadPoolLifetime: DisposableStack | undefined, ) { const { fileNames, options, projectReferences } = config; const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, sys, workerThreads, threadPool); @@ -955,7 +968,7 @@ function performCompilation( ); reportStatistics(sys, program, /*solutionPerformance*/ undefined); cb(program); - threadPool?.stop(); + dispose(threadPoolLifetime); return sys.exit(exitStatus); } @@ -966,6 +979,7 @@ function performIncrementalCompilation( config: ParsedCommandLine, workerThreads: WorkerThreadsHost | undefined, threadPool: ThreadPool | undefined, + threadPoolLifetime: DisposableStack | undefined, ) { const { options, fileNames, projectReferences } = config; enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false); @@ -984,7 +998,7 @@ function performIncrementalCompilation( cb(builderProgram); } }); - threadPool?.stop(); + dispose(threadPoolLifetime); return sys.exit(exitStatus); } @@ -1045,6 +1059,7 @@ function createWatchOfConfigFile( extendedConfigCache: Map, workerThreads: WorkerThreadsHost | undefined, threadPool: ThreadPool | undefined, + threadPoolLifetime: DisposableStack | undefined, ) { const watchCompilerHost = createWatchCompilerHostOfConfigFile({ configFileName: configParseResult.options.configFilePath!, @@ -1059,7 +1074,7 @@ function createWatchOfConfigFile( updateWatchCompilationHost(system, cb, watchCompilerHost); watchCompilerHost.configFileParsingResult = configParseResult; watchCompilerHost.extendedConfigCache = extendedConfigCache; - return createWatchProgram(watchCompilerHost); + return createWatchProgram(watchCompilerHost, threadPoolLifetime); } function createWatchOfFilesAndCompilerOptions( @@ -1071,6 +1086,7 @@ function createWatchOfFilesAndCompilerOptions( watchOptions: WatchOptions | undefined, workerThreads: WorkerThreadsHost | undefined, threadPool: ThreadPool | undefined, + threadPoolLifetime: DisposableStack | undefined, ) { const watchCompilerHost = createWatchCompilerHostOfFilesAndCompilerOptions({ rootFiles, @@ -1083,7 +1099,7 @@ function createWatchOfFilesAndCompilerOptions( threadPool, }); updateWatchCompilationHost(system, cb, watchCompilerHost); - return createWatchProgram(watchCompilerHost); + return createWatchProgram(watchCompilerHost, threadPoolLifetime); } interface SolutionPerformance { diff --git a/src/harness/fakesHosts.ts b/src/harness/fakesHosts.ts index abf12f60a0e..187a2b2af05 100644 --- a/src/harness/fakesHosts.ts +++ b/src/harness/fakesHosts.ts @@ -556,7 +556,6 @@ export function patchHostForBuildInfoWrite(sys: T, version: export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost { /** @internal */ declare workerThreads: ts.WorkerThreadsHost | undefined; /** @internal */ declare threadPool: ts.ThreadPool | undefined; - /** @internal */ declare membrane: ts.Membrane | undefined; createProgram: ts.CreateProgram; diff --git a/src/services/services.ts b/src/services/services.ts index efd133b5cce..6a4896661fa 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -603,7 +603,7 @@ class TokenOrIdentifierObject implements Node { } public getChildren(): Node[] { - return this.kind === SyntaxKind.EndOfFileToken ? (this as Node as EndOfFileToken).jsDoc || emptyArray : emptyArray; + return this.kind === SyntaxKind.EndOfFileToken ? (this as Node as EndOfFileToken).jsDoc?.slice() || [] : []; } public getFirstToken(): Node | undefined { diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index ba61cdf07d5..fe07bb0997b 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -20,7 +20,7 @@ import "./unittests/publicApi"; import "./unittests/reuseProgramStructure"; import "./unittests/semver"; import "./unittests/sharing/hashData"; -import "./unittests/sharing/resizableArray"; +import "./unittests/sharing/concurrentMap"; import "./unittests/transform"; import "./unittests/typeParameterIsPossiblyReferenced"; import "./unittests/config/commandLineParsing"; diff --git a/src/testRunner/unittests/sharing/concurrentMap.ts b/src/testRunner/unittests/sharing/concurrentMap.ts new file mode 100644 index 00000000000..f98b87d0787 --- /dev/null +++ b/src/testRunner/unittests/sharing/concurrentMap.ts @@ -0,0 +1,145 @@ +import { ConcurrentMap, wrapStruct } from "../../_namespaces/ts"; + +describe("unittests:: sharing:: concurrentMap", () => { + it("round trip", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + assert.equal(map.size(), 0); + assert.isFalse(map.has(1)); + map.set(1, "a"); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + map.delete(1); + assert.equal(map.size(), 0); + assert.isFalse(map.has(1)); + }); + it("large inserts", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + for (let i = 0; i < 10_000; i++) { + map.insert(i, i); + } + assert.equal(map.size(), 10_000); + }); + it("large deletes", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + for (let i = 0; i < 10_000; i++) { + map.insert(i, i); + } + for (let i = 0; i < 10_000; i++) { + map.delete(i); + } + assert.equal(map.size(), 0); + }); + describe("exchange", () => { + it("sets key to value if missing", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.exchange(1, 2); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 2); + }); + it("overwrites key if present and value is not undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.exchange(1, 3); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 3); + }); + it("deletes key if present and value is undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.exchange(1, /*value*/ undefined); + assert.equal(map.size(), 0); + assert.isFalse(map.has(1)); + assert.equal(map.get(1), /*expected*/ undefined); + }); + it("returns undefined if key was not present", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + const result = map.exchange(1, 2); + assert.isUndefined(result); + }); + it("returns previous value if key was present", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + const result1 = map.exchange(1, 3); + const result2 = map.exchange(1, /*value*/ undefined); + assert.equal(result1, 2); + assert.equal(result2, 3); + }); + }); + describe("compareExchange", () => { + it("sets key to value if expecting undefined and key not present", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.compareExchange(1, /*expectedValue*/ undefined, 2); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 2); + }); + it("does not set key to value if expecting undefined and key is present", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.compareExchange(1, /*expectedValue*/ undefined, 3); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 2); + }); + it("overwrites key if present, expected value matches, and replacement value is not undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.compareExchange(1, 2, 3); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 3); + }); + it("does not overwrite key if present, expected value does not match, and replacement value is not undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.compareExchange(1, 4, 3); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 2); + }); + it("deletes key if present, expected value matches, and value is undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.compareExchange(1, 2, /*replacementValue*/ undefined); + assert.equal(map.size(), 0); + assert.isFalse(map.has(1)); + assert.equal(map.get(1), /*expected*/ undefined); + }); + it("does not delete key if present, expected value does not match, and value is undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + map.compareExchange(1, 3, /*replacementValue*/ undefined); + assert.equal(map.size(), 1); + assert.isTrue(map.has(1)); + assert.equal(map.get(1), 2); + }); + it("returns undefined if key was not present and expected value is undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + const result = map.compareExchange(1, /*expectedValue*/ undefined, 2); + assert.isUndefined(result); + }); + it("returns undefined if key was not present and expected value was not undefined", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + const result = map.compareExchange(1, 2, 3); + assert.isUndefined(result); + }); + it("returns previous value if key was present and expected value matches", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + const result1 = map.compareExchange(1, 2, 3); + const result2 = map.compareExchange(1, 3, /*value*/ undefined); + assert.equal(result1, 2); + assert.equal(result2, 3); + }); + it("returns previous value if key was present and expected value did not match", () => { + const map = wrapStruct(new ConcurrentMap(), ConcurrentMap); + map.set(1, 2); + const result1 = map.compareExchange(1, 3, 4); + const result2 = map.compareExchange(1, 4, /*value*/ undefined); + assert.equal(result1, 2); + assert.equal(result2, 2); + }); + }); +}); \ No newline at end of file diff --git a/src/testRunner/unittests/sharing/hashData.ts b/src/testRunner/unittests/sharing/hashData.ts index 275e6754ada..4acbe7dede2 100644 --- a/src/testRunner/unittests/sharing/hashData.ts +++ b/src/testRunner/unittests/sharing/hashData.ts @@ -1,6 +1,6 @@ import { HashData } from "../../../compiler/sharing/collections/hashData"; -describe("unittests:: hashData", () => { +describe("unittests:: sharing:: hashData", () => { describe("findEntryIndex", () => { it("when empty", () => { const hashData = new HashData(0); diff --git a/src/testRunner/unittests/sharing/resizableArray.ts b/src/testRunner/unittests/sharing/resizableArray.ts deleted file mode 100644 index 347a59f1cb7..00000000000 --- a/src/testRunner/unittests/sharing/resizableArray.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Membrane, ProxyResizableArray } from "../../_namespaces/ts"; - -describe("unittests:: resizableArray", () => { - it("push", () => { - const membrane = new Membrane(); - const array = new ProxyResizableArray(membrane); - array.push(1); - }); -}); \ No newline at end of file