@@ -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 }
@@ -2802,13 +2799,12 @@ namespace ts {
28022799 parseOptional ( operator ) ;
28032800 let type = parseConstituentType ( ) ;
28042801 if ( token ( ) === operator ) {
2805- const types = createNodeArray < TypeNode > ( [ type ] , type . pos ) ;
2802+ const types = [ type ] ;
28062803 while ( parseOptional ( operator ) ) {
28072804 types . push ( parseConstituentType ( ) ) ;
28082805 }
2809- types . end = getNodeEnd ( ) ;
28102806 const node = < UnionOrIntersectionTypeNode > createNode ( kind , type . pos ) ;
2811- node . types = types ;
2807+ node . types = createNodeArray ( types , type . pos ) ;
28122808 type = finishNode ( node ) ;
28132809 }
28142810 return type ;
@@ -3174,8 +3170,7 @@ namespace ts {
31743170 parameter . name = identifier ;
31753171 finishNode ( parameter ) ;
31763172
3177- node . parameters = createNodeArray < ParameterDeclaration > ( [ parameter ] , parameter . pos ) ;
3178- node . parameters . end = parameter . end ;
3173+ node . parameters = createNodeArray < ParameterDeclaration > ( [ parameter ] , parameter . pos , parameter . end ) ;
31793174
31803175 node . equalsGreaterThanToken = parseExpectedToken ( SyntaxKind . EqualsGreaterThanToken , /*reportAtCurrentPosition*/ false , Diagnostics . _0_expected , "=>" ) ;
31813176 node . body = parseArrowFunctionExpressionBody ( /*isAsync*/ ! ! asyncModifier ) ;
@@ -4025,7 +4020,8 @@ namespace ts {
40254020 }
40264021
40274022 function parseJsxChildren ( openingTagName : LeftHandSideExpression ) : NodeArray < JsxChild > {
4028- const result = createNodeArray < JsxChild > ( ) ;
4023+ const list = [ ] ;
4024+ const listPos = getNodePos ( ) ;
40294025 const saveParsingContext = parsingContext ;
40304026 parsingContext |= 1 << ParsingContext . JsxChildren ;
40314027
@@ -4046,15 +4042,13 @@ namespace ts {
40464042 }
40474043 const child = parseJsxChild ( ) ;
40484044 if ( child ) {
4049- result . push ( child ) ;
4045+ list . push ( child ) ;
40504046 }
40514047 }
40524048
4053- result . end = scanner . getTokenPos ( ) ;
4054-
40554049 parsingContext = saveParsingContext ;
40564050
4057- return result ;
4051+ return createNodeArray ( list , listPos ) ;
40584052 }
40594053
40604054 function parseJsxAttributes ( ) : JsxAttributes {
@@ -5447,27 +5441,19 @@ namespace ts {
54475441 }
54485442
54495443 function parseDecorators ( ) : NodeArray < Decorator > {
5450- let decorators : NodeArray < Decorator > & Decorator [ ] ;
5444+ let list : Decorator [ ] ;
5445+ const listPos = getNodePos ( ) ;
54515446 while ( true ) {
54525447 const decoratorStart = getNodePos ( ) ;
54535448 if ( ! parseOptional ( SyntaxKind . AtToken ) ) {
54545449 break ;
54555450 }
5456-
54575451 const decorator = < Decorator > createNode ( SyntaxKind . Decorator , decoratorStart ) ;
54585452 decorator . expression = doInDecoratorContext ( parseLeftHandSideExpressionOrHigher ) ;
54595453 finishNode ( decorator ) ;
5460- if ( ! decorators ) {
5461- decorators = createNodeArray < Decorator > ( [ decorator ] , decoratorStart ) ;
5462- }
5463- else {
5464- decorators . push ( decorator ) ;
5465- }
5466- }
5467- if ( decorators ) {
5468- decorators . end = getNodeEnd ( ) ;
5454+ ( list || ( list = [ ] ) ) . push ( decorator ) ;
54695455 }
5470- return decorators ;
5456+ return list && createNodeArray ( list , listPos ) ;
54715457 }
54725458
54735459 /*
@@ -5478,7 +5464,8 @@ namespace ts {
54785464 * In such situations, 'permitInvalidConstAsModifier' should be set to true.
54795465 */
54805466 function parseModifiers ( permitInvalidConstAsModifier ?: boolean ) : NodeArray < Modifier > | undefined {
5481- let modifiers : MutableNodeArray < Modifier > | undefined ;
5467+ let list : Modifier [ ] ;
5468+ const listPos = getNodePos ( ) ;
54825469 while ( true ) {
54835470 const modifierStart = scanner . getStartPos ( ) ;
54845471 const modifierKind = token ( ) ;
@@ -5497,17 +5484,9 @@ namespace ts {
54975484 }
54985485
54995486 const modifier = finishNode ( < Modifier > createNode ( modifierKind , modifierStart ) ) ;
5500- if ( ! modifiers ) {
5501- modifiers = createNodeArray < Modifier > ( [ modifier ] , modifierStart ) ;
5502- }
5503- else {
5504- modifiers . push ( modifier ) ;
5505- }
5506- }
5507- if ( modifiers ) {
5508- modifiers . end = scanner . getStartPos ( ) ;
5487+ ( list || ( list = [ ] ) ) . push ( modifier ) ;
55095488 }
5510- return modifiers ;
5489+ return list && createNodeArray ( list , listPos ) ;
55115490 }
55125491
55135492 function parseModifiersForArrowFunction ( ) : NodeArray < Modifier > {
@@ -5518,9 +5497,7 @@ namespace ts {
55185497 nextToken ( ) ;
55195498 const modifier = finishNode ( < Modifier > createNode ( modifierKind , modifierStart ) ) ;
55205499 modifiers = createNodeArray < Modifier > ( [ modifier ] , modifierStart ) ;
5521- modifiers . end = scanner . getStartPos ( ) ;
55225500 }
5523-
55245501 return modifiers ;
55255502 }
55265503
@@ -6222,7 +6199,9 @@ namespace ts {
62226199 Debug . assert ( start <= end ) ;
62236200 Debug . assert ( end <= content . length ) ;
62246201
6225- let tags : MutableNodeArray < JSDocTag > ;
6202+ let tags : JSDocTag [ ] ;
6203+ let tagsPos : number ;
6204+ let tagsEnd : number ;
62266205 const comments : string [ ] = [ ] ;
62276206 let result : JSDoc ;
62286207
@@ -6355,7 +6334,7 @@ namespace ts {
63556334
63566335 function createJSDocComment ( ) : JSDoc {
63576336 const result = < JSDoc > createNode ( SyntaxKind . JSDocComment , start ) ;
6358- result . tags = tags ;
6337+ result . tags = tags && createNodeArray ( tags , tagsPos , tagsEnd ) ;
63596338 result . comment = comments . length ? comments . join ( "" ) : undefined ;
63606339 return finishNode ( result , end ) ;
63616340 }
@@ -6495,12 +6474,13 @@ namespace ts {
64956474 tag . comment = comments . join ( "" ) ;
64966475
64976476 if ( ! tags ) {
6498- tags = createNodeArray ( [ tag ] , tag . pos ) ;
6477+ tags = [ tag ] ;
6478+ tagsPos = tag . pos ;
64996479 }
65006480 else {
65016481 tags . push ( tag ) ;
65026482 }
6503- tags . end = tag . end ;
6483+ tagsEnd = tag . end ;
65046484 }
65056485
65066486 function tryParseTypeExpression ( ) : JSDocTypeExpression | undefined {
@@ -6800,7 +6780,8 @@ namespace ts {
68006780 }
68016781
68026782 // Type parameter list looks like '@template T,U,V'
6803- const typeParameters = createNodeArray < TypeParameterDeclaration > ( ) ;
6783+ const typeParameters = [ ] ;
6784+ const typeParametersPos = getNodePos ( ) ;
68046785
68056786 while ( true ) {
68066787 const name = parseJSDocIdentifierName ( ) ;
@@ -6828,9 +6809,8 @@ namespace ts {
68286809 const result = < JSDocTemplateTag > createNode ( SyntaxKind . JSDocTemplateTag , atToken . pos ) ;
68296810 result . atToken = atToken ;
68306811 result . tagName = tagName ;
6831- result . typeParameters = typeParameters ;
6812+ result . typeParameters = createNodeArray ( typeParameters , typeParametersPos ) ;
68326813 finishNode ( result ) ;
6833- typeParameters . end = result . end ;
68346814 return result ;
68356815 }
68366816
0 commit comments