Skip to content

Commit 0af375e

Browse files
committed
Merge pull request #8906 from Microsoft/transforms-commentsPerf
[Transforms] Performance improvements in the comment emitter.
2 parents 5853aad + bf9d2c4 commit 0af375e

File tree

13 files changed

+828
-683
lines changed

13 files changed

+828
-683
lines changed

Jakefile.js

Lines changed: 245 additions & 100 deletions
Large diffs are not rendered by default.

src/compiler/comments.ts

Lines changed: 251 additions & 265 deletions
Large diffs are not rendered by default.

src/compiler/emitter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8238,10 +8238,10 @@ const _super = (function (geti, seti) {
82388238
}
82398239
}
82408240

8241-
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) {
8242-
emitPos(comment.pos);
8243-
writeCommentRange(text, lineMap, writer, comment, newLine);
8244-
emitPos(comment.end);
8241+
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
8242+
emitPos(commentPos);
8243+
writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
8244+
emitPos(commentEnd);
82458245
}
82468246

82478247
function emitShebang() {

src/compiler/factory.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,12 @@ namespace ts {
2020
return node;
2121
}
2222

23-
function updateNode<T extends Node>(updated: T, original: T): T {
24-
updated.original = original;
25-
if (original.transformId) {
26-
updated.transformId = original.transformId;
27-
updated.emitFlags = original.emitFlags;
28-
updated.commentRange = original.commentRange;
29-
updated.sourceMapRange = original.sourceMapRange;
30-
}
23+
export function updateNode<T extends Node>(updated: T, original: T): T {
24+
setOriginalNode(updated, original);
3125
if (original.startsOnNewLine) {
3226
updated.startsOnNewLine = true;
3327
}
28+
3429
return updated;
3530
}
3631

@@ -1887,6 +1882,12 @@ namespace ts {
18871882

18881883
export function setOriginalNode<T extends Node>(node: T, original: Node): T {
18891884
node.original = original;
1885+
if (original) {
1886+
const { emitFlags, commentRange, sourceMapRange } = original;
1887+
if (emitFlags) node.emitFlags = emitFlags;
1888+
if (commentRange) node.commentRange = commentRange;
1889+
if (sourceMapRange) node.sourceMapRange = sourceMapRange;
1890+
}
18901891
return node;
18911892
}
18921893

src/compiler/printer.ts

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,16 @@ const _super = (function (geti, seti) {
161161

162162
const comments = createCommentWriter(host, writer, sourceMap);
163163
const {
164-
getLeadingComments,
165-
getTrailingComments,
166-
getTrailingCommentsOfPosition,
167-
emitLeadingComments,
168-
emitTrailingComments,
169-
emitLeadingDetachedComments,
170-
emitTrailingDetachedComments
164+
emitNodeWithComments,
165+
emitBodyWithDetachedComments,
166+
emitTrailingCommentsOfPosition
171167
} = comments;
172168

173169
let context: TransformationContext;
174170
let getNodeEmitFlags: (node: Node) => NodeEmitFlags;
175171
let setNodeEmitFlags: (node: Node, flags: NodeEmitFlags) => void;
176172
let getSourceMapRange: (node: Node) => TextRange;
177173
let getTokenSourceMapRange: (node: Node, token: SyntaxKind) => TextRange;
178-
let getCommentRange: (node: Node) => TextRange;
179174
let isSubstitutionEnabled: (node: Node) => boolean;
180175
let isEmitNotificationEnabled: (node: Node) => boolean;
181176
let onSubstituteNode: (node: Node, isExpression: boolean) => Node;
@@ -240,7 +235,6 @@ const _super = (function (geti, seti) {
240235
setNodeEmitFlags = undefined;
241236
getSourceMapRange = undefined;
242237
getTokenSourceMapRange = undefined;
243-
getCommentRange = undefined;
244238
isSubstitutionEnabled = undefined;
245239
isEmitNotificationEnabled = undefined;
246240
onSubstituteNode = undefined;
@@ -262,7 +256,6 @@ const _super = (function (geti, seti) {
262256
setNodeEmitFlags = context.setNodeEmitFlags;
263257
getSourceMapRange = context.getSourceMapRange;
264258
getTokenSourceMapRange = context.getTokenSourceMapRange;
265-
getCommentRange = context.getCommentRange;
266259
isSubstitutionEnabled = context.isSubstitutionEnabled;
267260
isEmitNotificationEnabled = context.isEmitNotificationEnabled;
268261
onSubstituteNode = context.onSubstituteNode;
@@ -276,7 +269,7 @@ const _super = (function (geti, seti) {
276269
currentFileIdentifiers = node.identifiers;
277270
sourceMap.setSourceFile(node);
278271
comments.setSourceFile(node);
279-
emitNodeWithNotificationOption(node, emitWorker);
272+
emitNodeWithNotification(node, emitWorker);
280273
return node;
281274
}
282275

@@ -291,7 +284,7 @@ const _super = (function (geti, seti) {
291284
* Emits a node.
292285
*/
293286
function emit(node: Node) {
294-
emitNodeWithNotificationOption(node, emitWithoutNotificationOption);
287+
emitNodeWithNotification(node, emitWithComments);
295288
}
296289

297290
/**
@@ -315,51 +308,71 @@ const _super = (function (geti, seti) {
315308
}
316309

317310
/**
318-
* Emits a node without calling onEmitNode.
319-
* NOTE: Do not call this method directly.
311+
* Emits a node with comments.
312+
*
313+
* NOTE: Do not call this method directly. It is part of the emit pipeline
314+
* and should only be called indirectly from emit.
320315
*/
321-
function emitWithoutNotificationOption(node: Node) {
322-
emitNodeWithWorker(node, emitWorker);
316+
function emitWithComments(node: Node) {
317+
emitNodeWithComments(node, emitWithSourceMap);
318+
}
319+
320+
/**
321+
* Emits a node with source maps.
322+
*
323+
* NOTE: Do not call this method directly. It is part of the emit pipeline
324+
* and should only be called indirectly from emitWithComments.
325+
*/
326+
function emitWithSourceMap(node: Node) {
327+
emitNodeWithSourceMap(node, emitWorker);
323328
}
324329

325330
/**
326331
* Emits an expression node.
327332
*/
328333
function emitExpression(node: Expression) {
329-
emitNodeWithNotificationOption(node, emitExpressionWithoutNotificationOption);
334+
emitNodeWithNotification(node, emitExpressionWithComments);
335+
}
336+
337+
/**
338+
* Emits an expression with comments.
339+
*
340+
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
341+
* and should only be called indirectly from emitExpression.
342+
*/
343+
function emitExpressionWithComments(node: Expression) {
344+
emitNodeWithComments(node, emitExpressionWithSourceMap);
330345
}
331346

332347
/**
333-
* Emits an expression without calling onEmitNode.
334-
* NOTE: Do not call this method directly.
348+
* Emits an expression with source maps.
349+
*
350+
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
351+
* and should only be called indirectly from emitExpressionWithComments.
335352
*/
336-
function emitExpressionWithoutNotificationOption(node: Expression) {
337-
emitNodeWithWorker(node, emitExpressionWorker);
353+
function emitExpressionWithSourceMap(node: Expression) {
354+
emitNodeWithSourceMap(node, emitExpressionWorker);
338355
}
339356

340357
/**
341358
* Emits a node with emit notification if available.
342359
*/
343-
function emitNodeWithNotificationOption(node: Node, emit: (node: Node) => void) {
360+
function emitNodeWithNotification(node: Node, emitCallback: (node: Node) => void) {
344361
if (node) {
345362
if (isEmitNotificationEnabled(node)) {
346-
onEmitNode(node, emit);
363+
onEmitNode(node, emitCallback);
347364
}
348365
else {
349-
emit(node);
366+
emitCallback(node);
350367
}
351368
}
352369
}
353370

354-
function emitNodeWithWorker(node: Node, emitWorker: (node: Node) => void) {
371+
function emitNodeWithSourceMap(node: Node, emitCallback: (node: Node) => void) {
355372
if (node) {
356-
const leadingComments = getLeadingComments(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingCommentsForNode, getCommentRange);
357-
const trailingComments = getTrailingComments(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingCommentsForNode, getCommentRange);
358-
emitLeadingComments(/*range*/ node, leadingComments, /*contextNode*/ node, getCommentRange);
359373
emitStart(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
360-
emitWorker(node);
374+
emitCallback(node);
361375
emitEnd(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
362-
emitTrailingComments(node, trailingComments);
363376
}
364377
}
365378

@@ -1642,24 +1655,33 @@ const _super = (function (geti, seti) {
16421655
}
16431656

16441657
increaseIndent();
1645-
emitLeadingDetachedComments(body.statements, body, shouldSkipLeadingCommentsForNode);
16461658

1659+
emitBodyWithDetachedComments(body, body.statements,
1660+
shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)
1661+
? emitBlockFunctionBodyOnSingleLine
1662+
: emitBlockFunctionBodyWorker);
1663+
1664+
decreaseIndent();
1665+
writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body);
1666+
}
1667+
1668+
function emitBlockFunctionBodyOnSingleLine(body: Block) {
1669+
emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true);
1670+
}
1671+
1672+
function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) {
16471673
// Emit all the prologue directives (like "use strict").
16481674
const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true);
16491675
const helpersEmitted = emitHelpers(body);
16501676

1651-
if (statementOffset === 0 && !helpersEmitted && shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)) {
1677+
if (statementOffset === 0 && !helpersEmitted && emitBlockFunctionBodyOnSingleLine) {
16521678
decreaseIndent();
16531679
emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements);
16541680
increaseIndent();
16551681
}
16561682
else {
16571683
emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset);
16581684
}
1659-
1660-
emitTrailingDetachedComments(body.statements, body, shouldSkipTrailingCommentsForNode);
1661-
decreaseIndent();
1662-
writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body);
16631685
}
16641686

16651687
function emitClassDeclaration(node: ClassDeclaration) {
@@ -2004,9 +2026,12 @@ const _super = (function (geti, seti) {
20042026
// }
20052027
// "comment1" is not considered to be leading comment for node.initializer
20062028
// but rather a trailing comment on the previous node.
2007-
if (!shouldSkipLeadingCommentsForNode(node.initializer)) {
2008-
emitLeadingComments(/*range*/ node.initializer, getTrailingComments(collapseRangeToStart(node.initializer)), /*contextNode*/ node.initializer, getCommentRange);
2029+
const initializer = node.initializer;
2030+
if (!shouldSkipLeadingCommentsForNode(initializer)) {
2031+
const commentRange = initializer.commentRange || initializer;
2032+
emitTrailingCommentsOfPosition(commentRange.pos);
20092033
}
2034+
20102035
emitExpression(node.initializer);
20112036
}
20122037

@@ -2034,23 +2059,17 @@ const _super = (function (geti, seti) {
20342059
function emitSourceFile(node: SourceFile) {
20352060
writeLine();
20362061
emitShebang();
2037-
emitLeadingDetachedComments(node);
2062+
emitBodyWithDetachedComments(node, node.statements, emitSourceFileWorker);
2063+
}
20382064

2065+
function emitSourceFileWorker(node: SourceFile) {
20392066
const statements = node.statements;
20402067
const statementOffset = emitPrologueDirectives(statements);
2041-
if (getNodeEmitFlags(node) & NodeEmitFlags.NoLexicalEnvironment) {
2042-
emitHelpers(node);
2043-
emitList(node, statements, ListFormat.MultiLine, statementOffset);
2044-
}
2045-
else {
2046-
const savedTempFlags = tempFlags;
2047-
tempFlags = 0;
2048-
emitHelpers(node);
2049-
emitList(node, statements, ListFormat.MultiLine, statementOffset);
2050-
tempFlags = savedTempFlags;
2051-
}
2052-
2053-
emitTrailingDetachedComments(node.statements);
2068+
const savedTempFlags = tempFlags;
2069+
tempFlags = 0;
2070+
emitHelpers(node);
2071+
emitList(node, statements, ListFormat.MultiLine, statementOffset);
2072+
tempFlags = savedTempFlags;
20542073
}
20552074

20562075
// Transformation nodes
@@ -2326,7 +2345,8 @@ const _super = (function (geti, seti) {
23262345
}
23272346
else {
23282347
// Write the opening line terminator or leading whitespace.
2329-
let shouldEmitInterveningComments = true;
2348+
const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0;
2349+
let shouldEmitInterveningComments = mayEmitInterveningComments;
23302350
if (shouldWriteLeadingLineTerminator(parentNode, children, format)) {
23312351
writeLine();
23322352
shouldEmitInterveningComments = false;
@@ -2369,10 +2389,11 @@ const _super = (function (geti, seti) {
23692389
}
23702390

23712391
if (shouldEmitInterveningComments) {
2372-
emitLeadingComments(/*node*/ child, getTrailingCommentsOfPosition(child.pos), /*contextNode*/ child, getCommentRange);
2392+
const commentRange = child.commentRange || child;
2393+
emitTrailingCommentsOfPosition(commentRange.pos);
23732394
}
23742395
else {
2375-
shouldEmitInterveningComments = true;
2396+
shouldEmitInterveningComments = mayEmitInterveningComments;
23762397
}
23772398

23782399
// Emit this child.
@@ -2876,6 +2897,7 @@ const _super = (function (geti, seti) {
28762897
// Other
28772898
PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes.
28782899
NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list.
2900+
NoInterveningComments = 1 << 17,// Do not emit comments between each node
28792901

28802902
// Precomputed Formats
28812903
Modifiers = SingleLine | SpaceBetweenSiblings,
@@ -2890,7 +2912,7 @@ const _super = (function (geti, seti) {
28902912
ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,
28912913
CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
28922914
NewExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis | OptionalIfUndefined,
2893-
TemplateExpressionSpans = SingleLine,
2915+
TemplateExpressionSpans = SingleLine | NoInterveningComments,
28942916
SingleLineBlockStatements = SpaceBetweenBraces | SpaceBetweenSiblings | SingleLine,
28952917
MultiLineBlockStatements = Indented | MultiLine,
28962918
VariableDeclarationList = CommaDelimited | SpaceBetweenSiblings | SingleLine,
@@ -2902,8 +2924,8 @@ const _super = (function (geti, seti) {
29022924
EnumMembers = CommaDelimited | Indented | MultiLine,
29032925
CaseBlockClauses = Indented | MultiLine,
29042926
NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces,
2905-
JsxElementChildren = SingleLine,
2906-
JsxElementAttributes = SingleLine | SpaceBetweenSiblings,
2927+
JsxElementChildren = SingleLine | NoInterveningComments,
2928+
JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
29072929
CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty,
29082930
HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine,
29092931
SourceFileStatements = MultiLine | NoTrailingNewLine,

0 commit comments

Comments
 (0)