@@ -18,8 +18,6 @@ namespace ts {
1818 const names : string [ ] = [ ] ;
1919 let nameToNameIndexMap : ESMap < string , number > | undefined ;
2020 const mappingCharCodes : number [ ] = [ ] ;
21- // We will create a string from the char code buffer whenever it exceeds this length
22- const mappingCommitThreshold = 1000 ;
2321 let mappings = "" ;
2422
2523 // Last recorded and encoded mappings
@@ -213,6 +211,15 @@ namespace ts {
213211 || lastNameIndex !== pendingNameIndex ;
214212 }
215213
214+ function appendMappingCharCode ( charCode : number ) {
215+ mappingCharCodes . push ( charCode ) ;
216+ // String.fromCharCode accepts its arguments on the stack, so we have to chunk the input,
217+ // otherwise we can get stack overflows for large source maps
218+ if ( mappingCharCodes . length >= 1024 ) {
219+ flushMappingBuffer ( ) ;
220+ }
221+ }
222+
216223 function commitPendingMapping ( ) {
217224 if ( ! hasPending || ! shouldCommitMapping ( ) ) {
218225 return ;
@@ -223,9 +230,8 @@ namespace ts {
223230 // Line/Comma delimiters
224231 if ( lastGeneratedLine < pendingGeneratedLine ) {
225232 // Emit line delimiters
226- // This loop can potentially overflow the stack on the char code conversion if it were a single operation
227233 do {
228- mappingCharCodes . push ( CharacterCodes . semicolon ) ; // ';'
234+ appendMappingCharCode ( CharacterCodes . semicolon ) ;
229235 lastGeneratedLine ++ ;
230236 }
231237 while ( lastGeneratedLine < pendingGeneratedLine ) ;
@@ -236,7 +242,7 @@ namespace ts {
236242 Debug . assertEqual ( lastGeneratedLine , pendingGeneratedLine , "generatedLine cannot backtrack" ) ;
237243 // Emit comma to separate the entry
238244 if ( hasLast ) {
239- mappingCharCodes . push ( CharacterCodes . comma ) ; // ','
245+ appendMappingCharCode ( CharacterCodes . comma ) ;
240246 }
241247 }
242248
@@ -264,22 +270,13 @@ namespace ts {
264270 }
265271 }
266272
267- if ( mappings . length > mappingCommitThreshold ) {
268- flushMappingBuffer ( ) ;
269- }
270-
271273 hasLast = true ;
272274 exit ( ) ;
273275 }
274276
275277 function flushMappingBuffer ( ) : void {
276- const len = mappingCharCodes . length ;
277- if ( len > 0 ) {
278- // If there are a very large number of skipped lines in the source mapping, this loop can iterate multiple times
279- // Otherwise it should always have 1 iteration
280- for ( let i = 0 ; i < len ; i += 1024 ) {
281- mappings += String . fromCharCode . apply ( undefined , mappingCharCodes . slice ( i , i + 1024 ) ) ;
282- }
278+ if ( mappingCharCodes . length > 0 ) {
279+ mappings += String . fromCharCode . apply ( undefined , mappingCharCodes ) ;
283280 mappingCharCodes . length = 0 ;
284281 }
285282 }
@@ -319,7 +316,7 @@ namespace ts {
319316 // There are still more digits to decode, set the msb (6th bit)
320317 currentDigit = currentDigit | 32 ;
321318 }
322- mappingCharCodes . push ( base64FormatEncode ( currentDigit ) ) ;
319+ appendMappingCharCode ( base64FormatEncode ( currentDigit ) ) ;
323320 } while ( inValue > 0 ) ;
324321 }
325322 }
0 commit comments