From d206f62adb02488ecf693097025d441c7112a673 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 16 Jun 2015 17:55:36 -0700 Subject: [PATCH] Squueze perf in syntactic classification. --- src/compiler/scanner.ts | 23 +++++++++++++++ src/compiler/utilities.ts | 6 ++++ src/services/services.ts | 60 +++++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 27 deletions(-) diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index fd8883045f..fcba1da9dc 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -376,8 +376,31 @@ namespace ts { return ch >= CharacterCodes._0 && ch <= CharacterCodes._7; } + export function couldStartTrivia(text: string, pos: number): boolean { + // Keep in sync with skipTrivia + let ch = text.charCodeAt(pos); + switch (ch) { + case CharacterCodes.carriageReturn: + case CharacterCodes.lineFeed: + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.space: + case CharacterCodes.slash: + // starts of normal trivia + case CharacterCodes.lessThan: + case CharacterCodes.equals: + case CharacterCodes.greaterThan: + // Starts of conflict marker trivia + return true; + default: + return ch > CharacterCodes.maxAsciiCharacter; + } + } + /* @internal */ export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number { + // Keep in sync with couldStartTrivia while (true) { let ch = text.charCodeAt(pos); switch (ch) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7251867f07..6d95e7eac8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2083,6 +2083,12 @@ namespace ts { return start <= textSpanEnd(span) && end >= span.start; } + export function textSpanIntersectsWith2(start1: number, length1: number, start2: number, length2: number) { + let end1 = start1 + length1; + let end2 = start2 + length2; + return start2 <= end1 && end2 >= start1; + } + export function textSpanIntersectsWithPosition(span: TextSpan, position: number) { return position <= textSpanEnd(span) && position >= span.start; } diff --git a/src/services/services.ts b/src/services/services.ts index cebe79630d..2f529ddab7 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -167,7 +167,7 @@ namespace ts { } public getFullWidth(): number { - return this.end - this.getFullStart(); + return this.end - this.pos; } public getLeadingTriviaWidth(sourceFile?: SourceFile): number { @@ -6116,6 +6116,8 @@ namespace ts { function getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications { // doesn't use compiler - no need to synchronize with host let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + let spanStart = span.start; + let spanLength = span.length; // Make a scanner we can get trivia from. let triviaScanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ false, sourceFile.text); @@ -6136,6 +6138,11 @@ namespace ts { triviaScanner.setTextPos(token.pos); while (true) { let start = triviaScanner.getTextPos(); + // only bother scanning if we have something that could be trivia. + if (!couldStartTrivia(sourceFile.text, start)) { + return start; + } + let kind = triviaScanner.scan(); let end = triviaScanner.getTextPos(); let width = end - start; @@ -6151,33 +6158,31 @@ namespace ts { } // Only bother with the trivia if it at least intersects the span of interest. - if (textSpanIntersectsWith(span, start, width)) { - if (isComment(kind)) { - classifyComment(token, kind, start, width); + if (isComment(kind)) { + classifyComment(token, kind, start, width); - // Classifying a comment might cause us to reuse the trivia scanner - // (because of jsdoc comments). So after we classify the comment make - // sure we set the scanner position back to where it needs to be. - triviaScanner.setTextPos(end); + // Classifying a comment might cause us to reuse the trivia scanner + // (because of jsdoc comments). So after we classify the comment make + // sure we set the scanner position back to where it needs to be. + triviaScanner.setTextPos(end); + continue; + } + + if (kind === SyntaxKind.ConflictMarkerTrivia) { + let text = sourceFile.text; + let ch = text.charCodeAt(start); + + // for the <<<<<<< and >>>>>>> markers, we just add them in as comments + // in the classification stream. + if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) { + pushClassification(start, width, ClassificationType.comment); continue; } - if (kind === SyntaxKind.ConflictMarkerTrivia) { - let text = sourceFile.text; - let ch = text.charCodeAt(start); - - // for the <<<<<<< and >>>>>>> markers, we just add them in as comments - // in the classification stream. - if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) { - pushClassification(start, width, ClassificationType.comment); - continue; - } - - // for the ======== add a comment for the first line, and then lex all - // subsequent lines up until the end of the conflict marker. - Debug.assert(ch === CharacterCodes.equals); - classifyDisabledMergeCode(text, start, end); - } + // for the ======== add a comment for the first line, and then lex all + // subsequent lines up until the end of the conflict marker. + Debug.assert(ch === CharacterCodes.equals); + classifyDisabledMergeCode(text, start, end); } } } @@ -6298,7 +6303,7 @@ namespace ts { function classifyToken(token: Node): void { let tokenStart = classifyLeadingTriviaAndGetTokenStart(token); - let tokenWidth = token.getEnd() - tokenStart; + let tokenWidth = token.end - tokenStart; Debug.assert(tokenWidth >= 0); if (tokenWidth > 0) { let type = classifyTokenType(token.kind, token); @@ -6408,9 +6413,10 @@ namespace ts { } // Ignore nodes that don't intersect the original span to classify. - if (textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) { + if (textSpanIntersectsWith2(spanStart, spanLength, element.pos, element.getFullWidth())) { let children = element.getChildren(sourceFile); - for (let child of children) { + for (let i = 0, n = children.length; i < n; i++) { + let child = children[i]; if (isToken(child)) { classifyToken(child); }