From 6f563b7af9241a0b55d88f1f19f109687c0e6ceb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 5 Aug 2014 18:27:04 -0700 Subject: [PATCH 1/3] Fixed memory leak from '--watch' flag. As I initially feared, we were actually nesting closure environments with each new `getSourceFile`. Fixes #366. --- src/compiler/core.ts | 8 ++++++++ src/compiler/tc.ts | 20 ++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 581a1672f29..24ce47333bb 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -156,6 +156,14 @@ module ts { return result; } + export function arrayToMap(array: T[], f: (value: T) => string): Map { + var result: Map = {}; + + forEach(array, value => { result[f(value)] = value }); + + return result; + } + function formatStringFromArgs(text: string, args: { [index: number]: any; }, baseIndex?: number): string { baseIndex = baseIndex || 0; diff --git a/src/compiler/tc.ts b/src/compiler/tc.ts index cbe9bcee6df..cae7d64f0e5 100644 --- a/src/compiler/tc.ts +++ b/src/compiler/tc.ts @@ -238,14 +238,14 @@ module ts { function addWatchers(program: Program) { forEach(program.getSourceFiles(), f => { - var filename = f.filename; + var filename = getCanonicalName(f.filename); watchers[filename] = sys.watchFile(filename, fileUpdated); }); } function removeWatchers(program: Program) { forEach(program.getSourceFiles(), f => { - var filename = f.filename; + var filename = getCanonicalName(f.filename); if (hasProperty(watchers, filename)) { watchers[filename].close(); } @@ -257,8 +257,7 @@ module ts { // Fired off whenever a file is changed. function fileUpdated(filename: string) { var firstNotification = isEmpty(updatedFiles); - - updatedFiles[filename] = true; + updatedFiles[getCanonicalName(filename)] = true; // Only start this off when the first file change comes in, // so that we can batch up all further changes. @@ -279,7 +278,10 @@ module ts { removeWatchers(program); // Gets us syntactically correct files from the last compilation. - var getUnmodifiedSourceFile = program.getSourceFile; + var oldSourceFiles = arrayToMap(program.getSourceFiles(), file => getCanonicalName(file.filename)); + + // No longer using the old program. + program = undefined; // We create a new compiler host for this compilation cycle. // This new host is effectively the same except that 'getSourceFile' @@ -287,8 +289,10 @@ module ts { // so long as they were not modified. var newCompilerHost = clone(compilerHost); newCompilerHost.getSourceFile = (fileName, languageVersion, onError) => { + fileName = getCanonicalName(fileName); + if (!hasProperty(changedFiles, fileName)) { - var sourceFile = getUnmodifiedSourceFile(fileName); + var sourceFile = lookUp(oldSourceFiles, fileName); if (sourceFile) { return sourceFile; } @@ -301,6 +305,10 @@ module ts { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); addWatchers(program); } + + function getCanonicalName(fileName: string) { + return compilerHost.getCanonicalFileName(fileName); + } } function compile(commandLine: ParsedCommandLine, compilerHost: CompilerHost) { From bd06e77b18915b7bd1fb37594e32c7e8e9244d3e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 6 Aug 2014 13:22:18 -0700 Subject: [PATCH 2/3] Addressed code review feedback. --- src/compiler/tc.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/compiler/tc.ts b/src/compiler/tc.ts index cae7d64f0e5..1d09f793a19 100644 --- a/src/compiler/tc.ts +++ b/src/compiler/tc.ts @@ -277,11 +277,10 @@ module ts { // specified since the last compilation cycle. removeWatchers(program); - // Gets us syntactically correct files from the last compilation. - var oldSourceFiles = arrayToMap(program.getSourceFiles(), file => getCanonicalName(file.filename)); - - // No longer using the old program. - program = undefined; + // Reuse source files from the last compilation so long as they weren't changed. + var oldSourceFiles = arrayToMap( + filter(program.getSourceFiles(), file => !hasProperty(changedFiles, getCanonicalName(file.filename))), + file => getCanonicalName(file.filename)); // We create a new compiler host for this compilation cycle. // This new host is effectively the same except that 'getSourceFile' @@ -291,11 +290,9 @@ module ts { newCompilerHost.getSourceFile = (fileName, languageVersion, onError) => { fileName = getCanonicalName(fileName); - if (!hasProperty(changedFiles, fileName)) { - var sourceFile = lookUp(oldSourceFiles, fileName); - if (sourceFile) { - return sourceFile; - } + var sourceFile = lookUp(oldSourceFiles, fileName); + if (sourceFile) { + return sourceFile; } return compilerHost.getSourceFile(fileName, languageVersion, onError); From eaa28feefd95875919d92401fffb95a9b3ab9342 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 6 Aug 2014 14:29:43 -0700 Subject: [PATCH 3/3] Style and comments. --- src/compiler/core.ts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 24ce47333bb..7f43b726d16 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -152,14 +152,30 @@ module ts { export function mapToArray(map: Map): T[] { var result: T[] = []; - for (var id in map) result.push(map[id]); + + for (var id in map) { + result.push(map[id]); + } + return result; } - export function arrayToMap(array: T[], f: (value: T) => string): Map { + /** + * Creates a map from the elements of an array. + * + * @param array the array of input elements. + * @param makeKey a function that produces a key for a given element. + * + * This function makes no effort to avoid collisions; if any two elements produce + * the same key with the given 'makeKey' function, then the element with the higher + * index in the array will be the one associated with the produced key. + */ + export function arrayToMap(array: T[], makeKey: (value: T) => string): Map { var result: Map = {}; - forEach(array, value => { result[f(value)] = value }); + forEach(array, value => { + result[makeKey(value)] = value + }); return result; }