@@ -60,6 +60,15 @@ namespace ts {
6060 const lexicalEnvironmentVariableDeclarationsStack : VariableDeclaration [ ] [ ] = [ ] ;
6161 const lexicalEnvironmentFunctionDeclarationsStack : FunctionDeclaration [ ] [ ] = [ ] ;
6262 const enabledSyntaxKindFeatures = new Array < SyntaxKindFeatureFlags > ( SyntaxKind . Count ) ;
63+ let lastNodeEmitFlagsNode : Node ;
64+ let lastNodeEmitFlags : NodeEmitFlags ;
65+ let lastSourceMapRangeNode : Node ;
66+ let lastSourceMapRange : TextRange ;
67+ let lastTokenSourceMapRangeNode : Node ;
68+ let lastTokenSourceMapRangeToken : SyntaxKind ;
69+ let lastTokenSourceMapRange : TextRange ;
70+ let lastCommentMapRangeNode : Node ;
71+ let lastCommentMapRange : TextRange ;
6372 let lexicalEnvironmentStackOffset = 0 ;
6473 let hoistedVariableDeclarations : VariableDeclaration [ ] ;
6574 let hoistedFunctionDeclarations : FunctionDeclaration [ ] ;
@@ -174,103 +183,189 @@ namespace ts {
174183
175184 /**
176185 * Gets flags that control emit behavior of a node.
186+ *
187+ * If the node does not have its own NodeEmitFlags set, the node emit flags of its
188+ * original pointer are used.
189+ *
190+ * @param node The node.
177191 */
178192 function getNodeEmitFlags ( node : Node ) {
193+ // As a performance optimization, use the cached value of the most recent node.
194+ // This helps for cases where this function is called repeatedly for the same node.
195+ if ( lastNodeEmitFlagsNode === node ) {
196+ return lastNodeEmitFlags ;
197+ }
198+
199+
200+ let flags : NodeEmitFlags ;
179201 while ( node ) {
180- let flags = nodeEmitFlags [ getNodeId ( node ) ] ;
202+ let flags = node . id ? nodeEmitFlags [ node . id ] : undefined ;
181203 if ( flags !== undefined ) {
182- return flags ;
204+ break ;
183205 }
184206
185207 node = node . original ;
186208 }
187209
188- return undefined ;
210+ // Cache the most recently requested value.
211+ lastNodeEmitFlagsNode = node ;
212+ lastNodeEmitFlags = flags ;
213+ return flags ;
189214 }
190215
191216 /**
192217 * Sets flags that control emit behavior of a node.
218+ *
219+ * @param node The node.
220+ * @param emitFlags The NodeEmitFlags for the node.
193221 */
194- function setNodeEmitFlags < T extends Node > ( node : T , flags : NodeEmitFlags ) {
195- if ( flags & NodeEmitFlags . Merge ) {
196- flags = getNodeEmitFlags ( node ) | ( flags & ~ NodeEmitFlags . Merge ) ;
222+ function setNodeEmitFlags < T extends Node > ( node : T , emitFlags : NodeEmitFlags ) {
223+ if ( emitFlags & NodeEmitFlags . Merge ) {
224+ emitFlags = getNodeEmitFlags ( node ) | ( emitFlags & ~ NodeEmitFlags . Merge ) ;
197225 }
198226
199- nodeEmitFlags [ getNodeId ( node ) ] = flags ;
227+ // Cache the most recently requested value.
228+ lastNodeEmitFlagsNode = node ;
229+ lastNodeEmitFlags = emitFlags ;
230+ nodeEmitFlags [ getNodeId ( node ) ] = emitFlags ;
200231 return node ;
201232 }
202233
203234 /**
204235 * Gets a custom text range to use when emitting source maps.
236+ *
237+ * If a node does not have its own custom source map text range, the custom source map
238+ * text range of its original pointer is used.
239+ *
240+ * @param node The node.
205241 */
206242 function getSourceMapRange ( node : Node ) {
243+ // As a performance optimization, use the cached value of the most recent node.
244+ // This helps for cases where this function is called repeatedly for the same node.
245+ if ( lastSourceMapRangeNode === node ) {
246+ return lastSourceMapRange || node ;
247+ }
248+
249+ let range : TextRange ;
207250 let current = node ;
208251 while ( current ) {
209- const sourceMapRange = sourceMapRanges [ getNodeId ( current ) ] ;
210- if ( sourceMapRange !== undefined ) {
211- return sourceMapRange ;
252+ range = current . id ? sourceMapRanges [ current . id ] : undefined ;
253+ if ( range !== undefined ) {
254+ break ;
212255 }
213256
214257 current = current . original ;
215258 }
216259
217- return node ;
260+ // Cache the most recently requested value.
261+ lastSourceMapRangeNode = node ;
262+ lastSourceMapRange = range ;
263+ return range || node ;
218264 }
219265
220266 /**
221267 * Sets a custom text range to use when emitting source maps.
268+ *
269+ * @param node The node.
270+ * @param range The text range.
222271 */
223272 function setSourceMapRange < T extends Node > ( node : T , range : TextRange ) {
273+ // Cache the most recently requested value.
274+ lastSourceMapRangeNode = node ;
275+ lastSourceMapRange = range ;
224276 sourceMapRanges [ getNodeId ( node ) ] = range ;
225277 return node ;
226278 }
227279
228280 /**
229281 * Gets the TextRange to use for source maps for a token of a node.
282+ *
283+ * If a node does not have its own custom source map text range for a token, the custom
284+ * source map text range for the token of its original pointer is used.
285+ *
286+ * @param node The node.
287+ * @param token The token.
230288 */
231289 function getTokenSourceMapRange ( node : Node , token : SyntaxKind ) {
290+ // As a performance optimization, use the cached value of the most recent node.
291+ // This helps for cases where this function is called repeatedly for the same node.
292+ if ( lastTokenSourceMapRangeNode === node && lastTokenSourceMapRangeToken === token ) {
293+ return lastSourceMapRange ;
294+ }
295+
296+ let range : TextRange ;
232297 let current = node ;
233298 while ( current ) {
234- const tokenSourceMapRange = sourceMapRanges [ getNodeId ( node ) + "-" + token ] ;
235- if ( tokenSourceMapRange !== undefined ) {
236- return tokenSourceMapRange ;
299+ range = current . id ? sourceMapRanges [ current . id + "-" + token ] : undefined ;
300+ if ( range !== undefined ) {
301+ break ;
237302 }
238303
239304 current = current . original ;
240305 }
241306
242- return undefined ;
307+ // Cache the most recently requested value.
308+ lastTokenSourceMapRangeNode = node ;
309+ lastTokenSourceMapRangeToken = token ;
310+ lastTokenSourceMapRange = range ;
311+ return range ;
243312 }
244313
245314 /**
246315 * Sets the TextRange to use for source maps for a token of a node.
316+ *
317+ * @param node The node.
318+ * @param token The token.
319+ * @param range The text range.
247320 */
248321 function setTokenSourceMapRange < T extends Node > ( node : T , token : SyntaxKind , range : TextRange ) {
322+ // Cache the most recently requested value.
323+ lastTokenSourceMapRangeNode = node ;
324+ lastTokenSourceMapRangeToken = token ;
325+ lastTokenSourceMapRange = range ;
249326 sourceMapRanges [ getNodeId ( node ) + "-" + token ] = range ;
250327 return node ;
251328 }
252329
253330 /**
254331 * Gets a custom text range to use when emitting comments.
332+ *
333+ * If a node does not have its own custom source map text range, the custom source map
334+ * text range of its original pointer is used.
335+ *
336+ * @param node The node.
255337 */
256338 function getCommentRange ( node : Node ) {
339+ // As a performance optimization, use the cached value of the most recent node.
340+ // This helps for cases where this function is called repeatedly for the same node.
341+ if ( lastCommentMapRangeNode === node ) {
342+ return lastCommentMapRange || node ;
343+ }
344+
345+ let range : TextRange ;
257346 let current = node ;
258347 while ( current ) {
259- const commentRange = commentRanges [ getNodeId ( current ) ] ;
260- if ( commentRange !== undefined ) {
261- return commentRange ;
348+ range = current . id ? commentRanges [ current . id ] : undefined ;
349+ if ( range !== undefined ) {
350+ break ;
262351 }
263352
264353 current = current . original ;
265354 }
266355
267- return node ;
356+ // Cache the most recently requested value.
357+ lastCommentMapRangeNode = node ;
358+ lastCommentMapRange = range ;
359+ return range || node ;
268360 }
269361
270362 /**
271363 * Sets a custom text range to use when emitting comments.
272364 */
273365 function setCommentRange < T extends Node > ( node : T , range : TextRange ) {
366+ // Cache the most recently requested value.
367+ lastCommentMapRangeNode = node ;
368+ lastCommentMapRange = range ;
274369 commentRanges [ getNodeId ( node ) ] = range ;
275370 return node ;
276371 }
0 commit comments