mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-16 05:58:32 -06:00
Transient node properties for transformations.
This commit is contained in:
parent
fb48731afa
commit
e64724ea35
@ -1059,6 +1059,7 @@ namespace ts {
|
||||
this.excludeTransformFlags = TransformFlags.None;
|
||||
this.parent = undefined;
|
||||
this.original = undefined;
|
||||
this.transformId = 0;
|
||||
}
|
||||
|
||||
export let objectAllocator: ObjectAllocator = {
|
||||
@ -1181,16 +1182,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all marks.
|
||||
*/
|
||||
export function getMarkNames() {
|
||||
return getKeys(markCounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of marks with the specified name.
|
||||
*
|
||||
* @param markName The name of the marks that should be counted.
|
||||
*/
|
||||
export function getCount(markName: string) {
|
||||
if (enabled) {
|
||||
return getProperty(markCounts, markName) || 0;
|
||||
}
|
||||
return 0;
|
||||
return enabled && getProperty(markCounts, markName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1199,10 +1204,7 @@ namespace ts {
|
||||
* @param markName The name of the mark.
|
||||
*/
|
||||
export function getTimestamp(markName: string) {
|
||||
if (enabled) {
|
||||
return getProperty(markTimestamps, markName) || 0;
|
||||
}
|
||||
return 0;
|
||||
return enabled && getProperty(markTimestamps, markName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1221,8 +1223,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function clearMark(markName: string) {
|
||||
markTimestamps[markName] = 0;
|
||||
markCounts[markName] = 0;
|
||||
if (delete markTimestamps[markName]) {
|
||||
delete markCounts[markName];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1246,13 +1249,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all recorded measures.
|
||||
*/
|
||||
export function getMeasureNames() {
|
||||
return getKeys(measureDurations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total duration of all measurements with the supplied name.
|
||||
*
|
||||
* @param measureName The name of the measure whose durations should be accumulated.
|
||||
*/
|
||||
export function getDuration(measureName: string) {
|
||||
return getProperty(measureDurations, measureName) || 0;
|
||||
return enabled && getProperty(measureDurations, measureName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1271,7 +1281,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function clearMeasure(measureName: string) {
|
||||
measureDurations[measureName] = 0;
|
||||
delete measureDurations[measureName];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -45,6 +45,14 @@ namespace ts {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a monotonically increasing transformation id used to associate a node with a specific
|
||||
* transformation. This ensures transient properties related to transformations can be safely
|
||||
* stored on source tree nodes that may be reused across multiple transformations (such as
|
||||
* with compile-on-save).
|
||||
*/
|
||||
let nextTransformId = 1;
|
||||
|
||||
/**
|
||||
* Transforms an array of SourceFiles by passing them through each transformer.
|
||||
*
|
||||
@ -54,12 +62,13 @@ namespace ts {
|
||||
* @param transforms An array of Transformers.
|
||||
*/
|
||||
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]) {
|
||||
const nodeEmitFlags: Map<NodeEmitFlags> = {};
|
||||
const sourceMapRanges: Map<TextRange> = {};
|
||||
const commentRanges: Map<TextRange> = {};
|
||||
const transformId = nextTransformId++;
|
||||
const tokenSourceMapRanges: Map<TextRange> = { };
|
||||
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
|
||||
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
|
||||
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
|
||||
const sourceTreeNodesWithAnnotations: Node[] = [];
|
||||
|
||||
let lastNodeEmitFlagsNode: Node;
|
||||
let lastNodeEmitFlags: NodeEmitFlags;
|
||||
let lastSourceMapRangeNode: Node;
|
||||
@ -118,7 +127,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = sourceFile;
|
||||
return transformation(sourceFile);
|
||||
sourceFile = transformation(sourceFile);
|
||||
|
||||
// Cleanup source tree nodes with annotations
|
||||
for (const node of sourceTreeNodesWithAnnotations) {
|
||||
if (node.transformId === transformId) {
|
||||
node.transformId = 0;
|
||||
node.emitFlags = 0;
|
||||
node.commentRange = undefined;
|
||||
node.sourceMapRange = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
sourceTreeNodesWithAnnotations.length = 0;
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,6 +203,28 @@ namespace ts {
|
||||
emit(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a node with the current transformation, initializing
|
||||
* various transient transformation properties.
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function beforeSetAnnotation(node: Node) {
|
||||
if (node.transformId !== transformId) {
|
||||
node.transformId = transformId;
|
||||
if ((node.flags & NodeFlags.Synthesized) === 0) {
|
||||
node.emitFlags = 0;
|
||||
node.sourceMapRange = undefined;
|
||||
node.commentRange = undefined;
|
||||
|
||||
// To avoid holding onto transformation artifacts, we keep track of any
|
||||
// source tree node we are annotating. This allows us to clean them up after
|
||||
// all transformations have completed.
|
||||
sourceTreeNodesWithAnnotations.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets flags that control emit behavior of a node.
|
||||
*
|
||||
@ -196,15 +240,19 @@ namespace ts {
|
||||
return lastNodeEmitFlags;
|
||||
}
|
||||
|
||||
|
||||
// Get the emit flags for a node or from one of its original nodes.
|
||||
let flags: NodeEmitFlags;
|
||||
while (node) {
|
||||
let flags = node.id ? nodeEmitFlags[node.id] : undefined;
|
||||
if (flags !== undefined) {
|
||||
break;
|
||||
let current = node;
|
||||
while (current) {
|
||||
if (current.transformId === transformId) {
|
||||
const nodeEmitFlags = current.emitFlags;
|
||||
if (nodeEmitFlags) {
|
||||
flags = nodeEmitFlags & ~NodeEmitFlags.HasNodeEmitFlags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node = node.original;
|
||||
current = current.original;
|
||||
}
|
||||
|
||||
// Cache the most recently requested value.
|
||||
@ -220,14 +268,17 @@ namespace ts {
|
||||
* @param emitFlags The NodeEmitFlags for the node.
|
||||
*/
|
||||
function setNodeEmitFlags<T extends Node>(node: T, emitFlags: NodeEmitFlags) {
|
||||
// Merge existing flags.
|
||||
if (emitFlags & NodeEmitFlags.Merge) {
|
||||
emitFlags = getNodeEmitFlags(node) | (emitFlags & ~NodeEmitFlags.Merge);
|
||||
}
|
||||
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastNodeEmitFlagsNode = node;
|
||||
lastNodeEmitFlags = emitFlags;
|
||||
nodeEmitFlags[getNodeId(node)] = emitFlags;
|
||||
node.emitFlags = emitFlags | NodeEmitFlags.HasNodeEmitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -246,12 +297,15 @@ namespace ts {
|
||||
return lastSourceMapRange || node;
|
||||
}
|
||||
|
||||
// Get the custom source map range for a node or from one of its original nodes.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
range = current.id ? sourceMapRanges[current.id] : undefined;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
if (current.transformId === transformId) {
|
||||
range = current.sourceMapRange;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
@ -270,10 +324,12 @@ namespace ts {
|
||||
* @param range The text range.
|
||||
*/
|
||||
function setSourceMapRange<T extends Node>(node: T, range: TextRange) {
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastSourceMapRangeNode = node;
|
||||
lastSourceMapRange = range;
|
||||
sourceMapRanges[getNodeId(node)] = range;
|
||||
node.sourceMapRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -290,13 +346,15 @@ namespace ts {
|
||||
// As a performance optimization, use the cached value of the most recent node.
|
||||
// This helps for cases where this function is called repeatedly for the same node.
|
||||
if (lastTokenSourceMapRangeNode === node && lastTokenSourceMapRangeToken === token) {
|
||||
return lastSourceMapRange;
|
||||
return lastTokenSourceMapRange;
|
||||
}
|
||||
|
||||
// Get the custom token source map range for a node or from one of its original nodes.
|
||||
// Custom token ranges are not stored on the node to avoid the GC burden.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
range = current.id ? sourceMapRanges[current.id + "-" + token] : undefined;
|
||||
range = current.id ? tokenSourceMapRanges[current.id + "-" + token] : undefined;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
@ -323,7 +381,7 @@ namespace ts {
|
||||
lastTokenSourceMapRangeNode = node;
|
||||
lastTokenSourceMapRangeToken = token;
|
||||
lastTokenSourceMapRange = range;
|
||||
sourceMapRanges[getNodeId(node) + "-" + token] = range;
|
||||
tokenSourceMapRanges[getNodeId(node) + "-" + token] = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -342,12 +400,15 @@ namespace ts {
|
||||
return lastCommentMapRange || node;
|
||||
}
|
||||
|
||||
// Get the custom comment range for a node or from one of its original nodes.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
range = current.id ? commentRanges[current.id] : undefined;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
if (current.transformId === transformId) {
|
||||
range = current.commentRange;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
@ -363,10 +424,12 @@ namespace ts {
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*/
|
||||
function setCommentRange<T extends Node>(node: T, range: TextRange) {
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastCommentMapRangeNode = node;
|
||||
lastCommentMapRange = range;
|
||||
commentRanges[getNodeId(node)] = range;
|
||||
node.commentRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@ -544,7 +544,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) {
|
||||
if (compilerOptions.diagnostics) {
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
performance.enable();
|
||||
performance.reset();
|
||||
}
|
||||
@ -558,7 +558,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
if (compilerOptions.diagnostics) {
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
|
||||
reportCountStatistic("Files", program.getSourceFiles().length);
|
||||
reportCountStatistic("Lines", countLines(program));
|
||||
@ -577,9 +577,6 @@ namespace ts {
|
||||
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
|
||||
reportTimeStatistic("I/O read", performance.getDuration("ioReadTime"));
|
||||
reportTimeStatistic("I/O write", performance.getDuration("ioWriteTime"));
|
||||
reportTimeStatistic("Print time", performance.getDuration("printTime"));
|
||||
reportTimeStatistic("Comment time", performance.getDuration("commentTime"));
|
||||
reportTimeStatistic("Sourcemap time", performance.getDuration("sourcemapTime"));
|
||||
const programTime = performance.getDuration("programTime");
|
||||
const bindTime = performance.getDuration("bindTime");
|
||||
const checkTime = performance.getDuration("checkTime");
|
||||
@ -590,6 +587,27 @@ namespace ts {
|
||||
reportTimeStatistic("Emit time", emitTime);
|
||||
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
|
||||
|
||||
if (compilerOptions.extendedDiagnostics) {
|
||||
sys.write("Extended Diagnostics:" + sys.newLine);
|
||||
sys.write("Marks:" + sys.newLine);
|
||||
for (const markName of performance.getMarkNames()) {
|
||||
if (/^(ioReadStart|ioWriteStart|programStart|bindStart|checkStart|emitStart)$/.test(markName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reportCountStatistic(" " + markName, performance.getCount(markName));
|
||||
}
|
||||
|
||||
sys.write("Measures:" + sys.newLine);
|
||||
for (const measureName of performance.getMeasureNames()) {
|
||||
if (/^(ioReadTime|ioWriteTime|programTime|bindTime|checkTime|emitTime)$/.test(measureName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reportTimeStatistic(" " + measureName, performance.getDuration(measureName));
|
||||
}
|
||||
}
|
||||
|
||||
performance.disable();
|
||||
performance.reset();
|
||||
}
|
||||
|
||||
@ -470,6 +470,10 @@ namespace ts {
|
||||
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
|
||||
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
|
||||
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
|
||||
/* @internal */ transformId?: number; // Associates transient transformation properties with a specific transformation (initialized by transformation).
|
||||
/* @internal */ emitFlags?: NodeEmitFlags; // Transient emit flags for a synthesized node (initialized by transformation).
|
||||
/* @internal */ sourceMapRange?: TextRange; // Transient custom sourcemap range for a synthesized node (initialized by transformation).
|
||||
/* @internal */ commentRange?: TextRange; // Transient custom comment range for a synthesized node (initialized by transformation).
|
||||
}
|
||||
|
||||
export interface NodeArray<T extends Node> extends Array<T>, TextRange {
|
||||
@ -2957,6 +2961,8 @@ namespace ts {
|
||||
// align with the old emitter.
|
||||
SourceMapEmitOpenBraceAsToken = 1 << 21, // Emits the open brace of a block function body as a source mapped token.
|
||||
SourceMapAdjustRestParameterLoop = 1 << 22, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
|
||||
|
||||
HasNodeEmitFlags = 1 << 31, // Indicates the node has emit flags set.
|
||||
}
|
||||
|
||||
/** Additional context provided to `visitEachChild` */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user