@@ -940,10 +940,6 @@ namespace ts {
940940 return scanner . getStartPos ( ) ;
941941 }
942942
943- function getNodeEnd ( ) : number {
944- return scanner . getStartPos ( ) ;
945- }
946-
947943 // Use this function to access the current token instead of reading the currentToken
948944 // variable. Since function results aren't narrowed in control flow analysis, this ensures
949945 // that the type checker doesn't make wrong assumptions about the type of the current
@@ -1135,13 +1131,14 @@ namespace ts {
11351131 new TokenConstructor ( kind , pos , pos ) ;
11361132 }
11371133
1138- function createNodeArray < T extends Node > ( elements ?: T [ ] , pos ?: number ) : MutableNodeArray < T > {
1139- const array = < MutableNodeArray < T > > ( elements || [ ] ) ;
1140- if ( ! ( pos >= 0 ) ) {
1141- pos = getNodePos ( ) ;
1142- }
1134+ function createNodeArray < T extends Node > ( elements : T [ ] , pos : number , end ?: number ) : NodeArray < T > {
1135+ // Since the element list of a node array is typically created by starting with an empty array and
1136+ // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for
1137+ // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation.
1138+ const length = elements . length ;
1139+ const array = < MutableNodeArray < T > > ( length >= 1 && length <= 4 ? elements . slice ( ) : elements ) ;
11431140 array . pos = pos ;
1144- array . end = pos ;
1141+ array . end = end === undefined ? scanner . getStartPos ( ) : end ;
11451142 return array ;
11461143 }
11471144
@@ -1527,12 +1524,13 @@ namespace ts {
15271524 function parseList < T extends Node > ( kind : ParsingContext , parseElement : ( ) => T ) : NodeArray < T > {
15281525 const saveParsingContext = parsingContext ;
15291526 parsingContext |= 1 << kind ;
1530- const result = createNodeArray < T > ( ) ;
1527+ const list = [ ] ;
1528+ const listPos = getNodePos ( ) ;
15311529
15321530 while ( ! isListTerminator ( kind ) ) {
15331531 if ( isListElement ( kind , /*inErrorRecovery*/ false ) ) {
15341532 const element = parseListElement ( kind , parseElement ) ;
1535- result . push ( element ) ;
1533+ list . push ( element ) ;
15361534
15371535 continue ;
15381536 }
@@ -1542,9 +1540,8 @@ namespace ts {
15421540 }
15431541 }
15441542
1545- result . end = getNodeEnd ( ) ;
15461543 parsingContext = saveParsingContext ;
1547- return result ;
1544+ return createNodeArray ( list , listPos ) ;
15481545 }
15491546
15501547 function parseListElement < T extends Node > ( parsingContext : ParsingContext , parseElement : ( ) => T ) : T {
@@ -1874,13 +1871,14 @@ namespace ts {
18741871 function parseDelimitedList < T extends Node > ( kind : ParsingContext , parseElement : ( ) => T , considerSemicolonAsDelimiter ?: boolean ) : NodeArray < T > {
18751872 const saveParsingContext = parsingContext ;
18761873 parsingContext |= 1 << kind ;
1877- const result = createNodeArray < T > ( ) ;
1874+ const list = [ ] ;
1875+ const listPos = getNodePos ( ) ;
18781876
18791877 let commaStart = - 1 ; // Meaning the previous token was not a comma
18801878 while ( true ) {
18811879 if ( isListElement ( kind , /*inErrorRecovery*/ false ) ) {
18821880 const startPos = scanner . getStartPos ( ) ;
1883- result . push ( parseListElement ( kind , parseElement ) ) ;
1881+ list . push ( parseListElement ( kind , parseElement ) ) ;
18841882 commaStart = scanner . getTokenPos ( ) ;
18851883
18861884 if ( parseOptional ( SyntaxKind . CommaToken ) ) {
@@ -1924,6 +1922,8 @@ namespace ts {
19241922 }
19251923 }
19261924
1925+ parsingContext = saveParsingContext ;
1926+ const result = createNodeArray ( list , listPos ) ;
19271927 // Recording the trailing comma is deliberately done after the previous
19281928 // loop, and not just if we see a list terminator. This is because the list
19291929 // may have ended incorrectly, but it is still important to know if there
@@ -1933,14 +1933,11 @@ namespace ts {
19331933 // Always preserve a trailing comma by marking it on the NodeArray
19341934 result . hasTrailingComma = true ;
19351935 }
1936-
1937- result . end = getNodeEnd ( ) ;
1938- parsingContext = saveParsingContext ;
19391936 return result ;
19401937 }
19411938
19421939 function createMissingList < T extends Node > ( ) : NodeArray < T > {
1943- return createNodeArray < T > ( ) ;
1940+ return createNodeArray < T > ( [ ] , getNodePos ( ) ) ;
19441941 }
19451942
19461943 function parseBracketedList < T extends Node > ( kind : ParsingContext , parseElement : ( ) => T , open : SyntaxKind , close : SyntaxKind ) : NodeArray < T > {
@@ -2015,15 +2012,15 @@ namespace ts {
20152012 template . head = parseTemplateHead ( ) ;
20162013 Debug . assert ( template . head . kind === SyntaxKind . TemplateHead , "Template head has wrong token kind" ) ;
20172014
2018- const templateSpans = createNodeArray < TemplateSpan > ( ) ;
2015+ const list = [ ] ;
2016+ const listPos = getNodePos ( ) ;
20192017
20202018 do {
2021- templateSpans . push ( parseTemplateSpan ( ) ) ;
2019+ list . push ( parseTemplateSpan ( ) ) ;
20222020 }
2023- while ( lastOrUndefined ( templateSpans ) . literal . kind === SyntaxKind . TemplateMiddle ) ;
2021+ while ( lastOrUndefined ( list ) . literal . kind === SyntaxKind . TemplateMiddle ) ;
20242022
2025- templateSpans . end = getNodeEnd ( ) ;
2026- template . templateSpans = templateSpans ;
2023+ template . templateSpans = createNodeArray ( list , listPos ) ;
20272024
20282025 return finishNode ( template ) ;
20292026 }
@@ -2807,13 +2804,12 @@ namespace ts {
28072804 parseOptional ( operator ) ;
28082805 let type = parseConstituentType ( ) ;
28092806 if ( token ( ) === operator ) {
2810- const types = createNodeArray < TypeNode > ( [ type ] , type . pos ) ;
2807+ const types = [ type ] ;
28112808 while ( parseOptional ( operator ) ) {
28122809 types . push ( parseConstituentType ( ) ) ;
28132810 }
2814- types . end = getNodeEnd ( ) ;
28152811 const node = < UnionOrIntersectionTypeNode > createNode ( kind , type . pos ) ;
2816- node . types = types ;
2812+ node . types = createNodeArray ( types , type . pos ) ;
28172813 type = finishNode ( node ) ;
28182814 }
28192815 return type ;
@@ -3179,8 +3175,7 @@ namespace ts {
31793175 parameter . name = identifier ;
31803176 finishNode ( parameter ) ;
31813177
3182- node . parameters = createNodeArray < ParameterDeclaration > ( [ parameter ] , parameter . pos ) ;
3183- node . parameters . end = parameter . end ;
3178+ node . parameters = createNodeArray < ParameterDeclaration > ( [ parameter ] , parameter . pos , parameter . end ) ;
31843179
31853180 node . equalsGreaterThanToken = parseExpectedToken ( SyntaxKind . EqualsGreaterThanToken , /*reportAtCurrentPosition*/ false , Diagnostics . _0_expected , "=>" ) ;
31863181 node . body = parseArrowFunctionExpressionBody ( /*isAsync*/ ! ! asyncModifier ) ;
@@ -4030,7 +4025,8 @@ namespace ts {
40304025 }
40314026
40324027 function parseJsxChildren ( openingTagName : LeftHandSideExpression ) : NodeArray < JsxChild > {
4033- const result = createNodeArray < JsxChild > ( ) ;
4028+ const list = [ ] ;
4029+ const listPos = getNodePos ( ) ;
40344030 const saveParsingContext = parsingContext ;
40354031 parsingContext |= 1 << ParsingContext . JsxChildren ;
40364032
@@ -4051,15 +4047,13 @@ namespace ts {
40514047 }
40524048 const child = parseJsxChild ( ) ;
40534049 if ( child ) {
4054- result . push ( child ) ;
4050+ list . push ( child ) ;
40554051 }
40564052 }
40574053
4058- result . end = scanner . getTokenPos ( ) ;
4059-
40604054 parsingContext = saveParsingContext ;
40614055
4062- return result ;
4056+ return createNodeArray ( list , listPos ) ;
40634057 }
40644058
40654059 function parseJsxAttributes ( ) : JsxAttributes {
@@ -5452,27 +5446,19 @@ namespace ts {
54525446 }
54535447
54545448 function parseDecorators ( ) : NodeArray < Decorator > {
5455- let decorators : NodeArray < Decorator > & Decorator [ ] ;
5449+ let list : Decorator [ ] ;
5450+ const listPos = getNodePos ( ) ;
54565451 while ( true ) {
54575452 const decoratorStart = getNodePos ( ) ;
54585453 if ( ! parseOptional ( SyntaxKind . AtToken ) ) {
54595454 break ;
54605455 }
5461-
54625456 const decorator = < Decorator > createNode ( SyntaxKind . Decorator , decoratorStart ) ;
54635457 decorator . expression = doInDecoratorContext ( parseLeftHandSideExpressionOrHigher ) ;
54645458 finishNode ( decorator ) ;
5465- if ( ! decorators ) {
5466- decorators = createNodeArray < Decorator > ( [ decorator ] , decoratorStart ) ;
5467- }
5468- else {
5469- decorators . push ( decorator ) ;
5470- }
5471- }
5472- if ( decorators ) {
5473- decorators . end = getNodeEnd ( ) ;
5459+ ( list || ( list = [ ] ) ) . push ( decorator ) ;
54745460 }
5475- return decorators ;
5461+ return list && createNodeArray ( list , listPos ) ;
54765462 }
54775463
54785464 /*
@@ -5483,7 +5469,8 @@ namespace ts {
54835469 * In such situations, 'permitInvalidConstAsModifier' should be set to true.
54845470 */
54855471 function parseModifiers ( permitInvalidConstAsModifier ?: boolean ) : NodeArray < Modifier > | undefined {
5486- let modifiers : MutableNodeArray < Modifier > | undefined ;
5472+ let list : Modifier [ ] ;
5473+ const listPos = getNodePos ( ) ;
54875474 while ( true ) {
54885475 const modifierStart = scanner . getStartPos ( ) ;
54895476 const modifierKind = token ( ) ;
@@ -5502,17 +5489,9 @@ namespace ts {
55025489 }
55035490
55045491 const modifier = finishNode ( < Modifier > createNode ( modifierKind , modifierStart ) ) ;
5505- if ( ! modifiers ) {
5506- modifiers = createNodeArray < Modifier > ( [ modifier ] , modifierStart ) ;
5507- }
5508- else {
5509- modifiers . push ( modifier ) ;
5510- }
5511- }
5512- if ( modifiers ) {
5513- modifiers . end = scanner . getStartPos ( ) ;
5492+ ( list || ( list = [ ] ) ) . push ( modifier ) ;
55145493 }
5515- return modifiers ;
5494+ return list && createNodeArray ( list , listPos ) ;
55165495 }
55175496
55185497 function parseModifiersForArrowFunction ( ) : NodeArray < Modifier > {
@@ -5523,9 +5502,7 @@ namespace ts {
55235502 nextToken ( ) ;
55245503 const modifier = finishNode ( < Modifier > createNode ( modifierKind , modifierStart ) ) ;
55255504 modifiers = createNodeArray < Modifier > ( [ modifier ] , modifierStart ) ;
5526- modifiers . end = scanner . getStartPos ( ) ;
55275505 }
5528-
55295506 return modifiers ;
55305507 }
55315508
@@ -6227,7 +6204,9 @@ namespace ts {
62276204 Debug . assert ( start <= end ) ;
62286205 Debug . assert ( end <= content . length ) ;
62296206
6230- let tags : MutableNodeArray < JSDocTag > ;
6207+ let tags : JSDocTag [ ] ;
6208+ let tagsPos : number ;
6209+ let tagsEnd : number ;
62316210 const comments : string [ ] = [ ] ;
62326211 let result : JSDoc ;
62336212
@@ -6360,7 +6339,7 @@ namespace ts {
63606339
63616340 function createJSDocComment ( ) : JSDoc {
63626341 const result = < JSDoc > createNode ( SyntaxKind . JSDocComment , start ) ;
6363- result . tags = tags ;
6342+ result . tags = tags && createNodeArray ( tags , tagsPos , tagsEnd ) ;
63646343 result . comment = comments . length ? comments . join ( "" ) : undefined ;
63656344 return finishNode ( result , end ) ;
63666345 }
@@ -6500,12 +6479,13 @@ namespace ts {
65006479 tag . comment = comments . join ( "" ) ;
65016480
65026481 if ( ! tags ) {
6503- tags = createNodeArray ( [ tag ] , tag . pos ) ;
6482+ tags = [ tag ] ;
6483+ tagsPos = tag . pos ;
65046484 }
65056485 else {
65066486 tags . push ( tag ) ;
65076487 }
6508- tags . end = tag . end ;
6488+ tagsEnd = tag . end ;
65096489 }
65106490
65116491 function tryParseTypeExpression ( ) : JSDocTypeExpression | undefined {
@@ -6805,7 +6785,8 @@ namespace ts {
68056785 }
68066786
68076787 // Type parameter list looks like '@template T,U,V'
6808- const typeParameters = createNodeArray < TypeParameterDeclaration > ( ) ;
6788+ const typeParameters = [ ] ;
6789+ const typeParametersPos = getNodePos ( ) ;
68096790
68106791 while ( true ) {
68116792 const name = parseJSDocIdentifierName ( ) ;
@@ -6833,9 +6814,8 @@ namespace ts {
68336814 const result = < JSDocTemplateTag > createNode ( SyntaxKind . JSDocTemplateTag , atToken . pos ) ;
68346815 result . atToken = atToken ;
68356816 result . tagName = tagName ;
6836- result . typeParameters = typeParameters ;
6817+ result . typeParameters = createNodeArray ( typeParameters , typeParametersPos ) ;
68376818 finishNode ( result ) ;
6838- typeParameters . end = result . end ;
68396819 return result ;
68406820 }
68416821
0 commit comments