diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8ed8edf927a..2ce3bbfaf3b 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -785,7 +785,8 @@ namespace ts { }; export interface ObjectAllocator { - getNodeConstructor(kind: SyntaxKind): new (pos?: number, end?: number) => Node; + getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node; + getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile; getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; getSignatureConstructor(): new (checker: TypeChecker) => Signature; @@ -804,7 +805,7 @@ namespace ts { function Signature(checker: TypeChecker) { } - function Node(pos: number, end: number, kind: SyntaxKind) { + function Node(kind: SyntaxKind, pos: number, end: number) { this.kind = kind; this.pos = pos; this.end = end; @@ -813,7 +814,8 @@ namespace ts { } export let objectAllocator: ObjectAllocator = { - getNodeConstructor: _ => Node, + getNodeConstructor: () => Node, + getSourceFileConstructor: () => Node, getSymbolConstructor: () => Symbol, getTypeConstructor: () => Type, getSignatureConstructor: () => Signature diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5ec56496ff3..ec2aeb25af9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2,15 +2,18 @@ /// namespace ts { - const nodeConstructors = new Array Node>(SyntaxKind.Count); /* @internal */ export let parseTime = 0; - export function getNodeConstructor(kind: SyntaxKind): new (pos?: number, end?: number, kind?: SyntaxKind) => Node { - return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); - } + let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { - return new (getNodeConstructor(kind))(pos, end, kind); + if (kind === SyntaxKind.SourceFile) { + return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); + } + else { + return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); + } } function visitNode(cbNode: (node: Node) => T, node: Node): T { @@ -437,6 +440,10 @@ namespace ts { const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); const disallowInAndDecoratorContext = ParserContextFlags.DisallowIn | ParserContextFlags.Decorator; + // capture constructors in 'initializeState' to avoid null checks + let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let sourceFile: SourceFile; let parseDiagnostics: Diagnostic[]; let syntaxCursor: IncrementalParser.SyntaxCursor; @@ -537,6 +544,9 @@ namespace ts { } function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor) { + NodeConstructor = objectAllocator.getNodeConstructor(); + SourceFileConstructor = objectAllocator.getSourceFileConstructor(); + sourceText = _sourceText; syntaxCursor = _syntaxCursor; @@ -657,10 +667,11 @@ namespace ts { } function createSourceFile(fileName: string, languageVersion: ScriptTarget): SourceFile { - const sourceFile = createNode(SyntaxKind.SourceFile, /*pos*/ 0); + // code from createNode is inlined here so createNode won't have to deal with special case of creating source files + // this is quite rare comparing to other nodes and createNode should be as fast as possible + const sourceFile = new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length); + nodeCount++; - sourceFile.pos = 0; - sourceFile.end = sourceText.length; sourceFile.text = sourceText; sourceFile.bindDiagnostics = []; sourceFile.languageVersion = languageVersion; @@ -991,12 +1002,14 @@ namespace ts { } } + // note: this function creates only node function createNode(kind: SyntaxKind, pos?: number): Node { nodeCount++; if (!(pos >= 0)) { pos = scanner.getStartPos(); } - return new (nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)))(pos, pos, kind); + + return new NodeConstructor(kind, pos, pos); } function finishNode(node: T, end?: number): T { diff --git a/src/services/services.ts b/src/services/services.ts index 1672e4ad4ff..113a52459e9 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -174,7 +174,7 @@ namespace ts { let jsDocCompletionEntries: CompletionEntry[]; function createNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags, parent?: Node): NodeObject { - let node = new (getNodeConstructor(kind))(pos, end); + let node = new NodeObject(kind, pos, end); node.flags = flags; node.parent = parent; return node; @@ -188,6 +188,14 @@ namespace ts { public parent: Node; private _children: Node[]; + constructor(kind: SyntaxKind, pos: number, end: number) { + this.kind = kind; + this.pos = pos; + this.end = end; + this.flags = NodeFlags.None; + this.parent = undefined; + } + public getSourceFile(): SourceFile { return getSourceFileOfNode(this); } @@ -805,6 +813,10 @@ namespace ts { public imports: LiteralExpression[]; private namedDeclarations: Map; + constructor(kind: SyntaxKind, pos: number, end: number) { + super(kind, pos, end) + } + public update(newText: string, textChangeRange: TextChangeRange): SourceFile { return updateSourceFile(this, newText, textChangeRange); } @@ -7970,18 +7982,8 @@ namespace ts { function initializeServices() { objectAllocator = { - getNodeConstructor: kind => { - function Node(pos: number, end: number) { - this.pos = pos; - this.end = end; - this.flags = NodeFlags.None; - this.parent = undefined; - } - let proto = kind === SyntaxKind.SourceFile ? new SourceFileObject() : new NodeObject(); - proto.kind = kind; - Node.prototype = proto; - return Node; - }, + getNodeConstructor: () => NodeObject, + getSourceFileConstructor: () => SourceFileObject, getSymbolConstructor: () => SymbolObject, getTypeConstructor: () => TypeObject, getSignatureConstructor: () => SignatureObject,