From 3264b64f08cd3a946fecf9b9ebd9d741190b5543 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 23 Apr 2019 15:32:02 -0700 Subject: [PATCH 1/3] Reuse map if module resolution is same for redirected and own files --- src/compiler/moduleNameResolver.ts | 11 ++++++----- src/compiler/program.ts | 2 +- src/compiler/utilities.ts | 7 ++++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index b8aa9fa2df465..090abfa978e7d 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -436,10 +436,10 @@ namespace ts { set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void; } - export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache { + export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string, options?: CompilerOptions): ModuleResolutionCache { return createModuleResolutionCacheWithMaps( - createCacheWithRedirects(), - createCacheWithRedirects(), + createCacheWithRedirects(options), + createCacheWithRedirects(options), currentDirectory, getCanonicalFileName ); @@ -454,7 +454,7 @@ namespace ts { } /*@internal*/ - export function createCacheWithRedirects(): CacheWithRedirects { + export function createCacheWithRedirects(options?: CompilerOptions): CacheWithRedirects { const ownMap: Map = createMap(); const redirectsMap: Map> = createMap(); return { @@ -471,7 +471,8 @@ namespace ts { const path = redirectedReference.sourceFile.path; let redirects = redirectsMap.get(path); if (!redirects) { - redirects = createMap(); + // Reuse map if redirected reference map uses same resolution + redirects = !options || optionsHaveModuleResolutionChanges(options, redirectedReference.commandLine.options) ? createMap() : ownMap; redirectsMap.set(path, redirects); } return redirects; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 4f50aa3ab1f59..c6c592b0e7381 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -773,7 +773,7 @@ namespace ts { }); } else { - moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x)); + moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x), options); const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache, redirectedReference).resolvedModule!; // TODO: GH#18217 resolveModuleNamesWorker = (moduleNames, containingFile, _reusedNames, redirectedReference) => loadWithLocalCache(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2e6c3ae4f866e..5e7474920fd27 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -101,7 +101,12 @@ namespace ts { } export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean { - return oldOptions.configFilePath !== newOptions.configFilePath || moduleResolutionOptionDeclarations.some(o => + return oldOptions.configFilePath !== newOptions.configFilePath || + optionsHaveModuleResolutionChanges(oldOptions, newOptions); + } + + export function optionsHaveModuleResolutionChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions) { + return moduleResolutionOptionDeclarations.some(o => !isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o))); } From 93b958e0ea1f61565802fa47df75176e4b38aa47 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 24 Apr 2019 12:38:25 -0700 Subject: [PATCH 2/3] Share module resolution cache among different program --- src/compiler/moduleNameResolver.ts | 21 ++++++++++++++--- src/compiler/program.ts | 3 ++- src/compiler/tsbuild.ts | 37 ++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 090abfa978e7d..c8b32fa6010d2 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -421,6 +421,7 @@ namespace ts { */ export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache { getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): Map; + /*@internal*/ directoryToModuleNameMap: CacheWithRedirects>; } /** @@ -429,6 +430,7 @@ namespace ts { */ export interface NonRelativeModuleNameResolutionCache { getOrCreateCacheForModuleName(nonRelativeModuleName: string, redirectedReference?: ResolvedProjectReference): PerModuleNameCache; + /*@internal*/ moduleNameToDirectoryMap: CacheWithRedirects; } export interface PerModuleNameCache { @@ -445,25 +447,38 @@ namespace ts { ); } + /*@internal*/ export interface CacheWithRedirects { ownMap: Map; redirectsMap: Map>; getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map; clear(): void; + setOwnOptions(newOptions: CompilerOptions): void; + setOwnMap(newOwnMap: Map): void; } /*@internal*/ export function createCacheWithRedirects(options?: CompilerOptions): CacheWithRedirects { - const ownMap: Map = createMap(); + let ownMap: Map = createMap(); const redirectsMap: Map> = createMap(); return { ownMap, redirectsMap, getOrCreateMapOfCacheRedirects, - clear + clear, + setOwnOptions, + setOwnMap }; + function setOwnOptions(newOptions: CompilerOptions) { + options = newOptions; + } + + function setOwnMap(newOwnMap: Map) { + ownMap = newOwnMap; + } + function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined) { if (!redirectedReference) { return ownMap; @@ -491,7 +506,7 @@ namespace ts { currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): ModuleResolutionCache { - return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName }; + return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName, directoryToModuleNameMap, moduleNameToDirectoryMap }; function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) { const path = toPath(directoryName, currentDirectory, getCanonicalFileName); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c6c592b0e7381..e8b2ba39b13a7 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -528,7 +528,8 @@ namespace ts { } } - function loadWithLocalCache(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] { + /* @internal */ + export function loadWithLocalCache(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] { if (names.length === 0) { return []; } diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index f60641fe0cfe7..8bc66e95edc45 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -400,6 +400,10 @@ namespace ts { const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions); setGetSourceFileAsHashVersioned(compilerHost, host); + compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames); + compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); + let moduleResolutionCache = !compilerHost.resolveModuleNames ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined; + const buildInfoChecked = createFileMap(toPath); // Watch state @@ -1097,6 +1101,30 @@ namespace ts { // TODO: handle resolve module name to cache result in project reference redirect projectCompilerOptions = configFile.options; + // Update module resolution cache if needed + if (moduleResolutionCache) { + const projPath = toPath(proj); + if (moduleResolutionCache.directoryToModuleNameMap.redirectsMap.size === 0) { + // The own map will be for projectCompilerOptions + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size === 0); + moduleResolutionCache.directoryToModuleNameMap.redirectsMap.set(projPath, moduleResolutionCache.directoryToModuleNameMap.ownMap); + moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.set(projPath, moduleResolutionCache.moduleNameToDirectoryMap.ownMap); + } + else { + // Set correct own map + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size > 0); + + const ref: ResolvedProjectReference = { + sourceFile: projectCompilerOptions.configFile!, + commandLine: configFile + }; + moduleResolutionCache.directoryToModuleNameMap.setOwnMap(moduleResolutionCache.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref)); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnMap(moduleResolutionCache.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref)); + } + moduleResolutionCache.directoryToModuleNameMap.setOwnOptions(projectCompilerOptions); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnOptions(projectCompilerOptions); + } + const program = host.createProgram( configFile.fileNames, configFile.options, @@ -1368,6 +1396,13 @@ namespace ts { readFileWithCache = newReadFileWithCache; compilerHost.getSourceFile = getSourceFileWithCache!; + const originalResolveModuleNames = compilerHost.resolveModuleNames; + if (!compilerHost.resolveModuleNames) { + const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference).resolvedModule!; + compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference) => + loadWithLocalCache(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader); + } + const graph = getGlobalDependencyGraph(); reportBuildQueue(graph); let anyFailed = false; @@ -1428,6 +1463,8 @@ namespace ts { host.writeFile = originalWriteFile; compilerHost.getSourceFile = savedGetSourceFile; readFileWithCache = savedReadFileWithCache; + compilerHost.resolveModuleNames = originalResolveModuleNames; + moduleResolutionCache = undefined; return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success; } From 9bb837332774ae60356382f5ca5adce3d8137b78 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 25 Apr 2019 14:06:49 -0700 Subject: [PATCH 3/3] Accept API changes --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 5d5472e840592..93c49f699e75f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3718,7 +3718,7 @@ declare namespace ts { get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined; set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void; } - function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache; + function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string, options?: CompilerOptions): ModuleResolutionCache; function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations | undefined; function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e8e2bed3bb8f9..6a3c992bdb513 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3718,7 +3718,7 @@ declare namespace ts { get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined; set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void; } - function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache; + function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string, options?: CompilerOptions): ModuleResolutionCache; function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations | undefined; function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;