Skip to content

Commit 1b6c9a8

Browse files
committed
Mark the caches as readonly after program construction so there are no changes to them
1 parent a49de0e commit 1b6c9a8

File tree

3 files changed

+50
-13
lines changed

3 files changed

+50
-13
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ function createResolvedModuleWithFailedLookupLocationsHandlingSymlink(
225225
affectingLocations: string[],
226226
diagnostics: Diagnostic[],
227227
state: ModuleResolutionState,
228+
cache: ModuleResolutionCache | NonRelativeModuleNameResolutionCache | undefined,
228229
legacyResult?: string,
229230
): ResolvedModuleWithFailedLookupLocations {
230231
// If this is from node_modules for non relative name, always respect preserveSymlinks
@@ -246,6 +247,7 @@ function createResolvedModuleWithFailedLookupLocationsHandlingSymlink(
246247
affectingLocations,
247248
diagnostics,
248249
state.resultFromCache,
250+
cache,
249251
legacyResult,
250252
);
251253
}
@@ -257,13 +259,24 @@ function createResolvedModuleWithFailedLookupLocations(
257259
affectingLocations: string[],
258260
diagnostics: Diagnostic[],
259261
resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined,
262+
cache: ModuleResolutionCache | NonRelativeModuleNameResolutionCache | undefined,
260263
legacyResult?: string,
261264
): ResolvedModuleWithFailedLookupLocations {
262265
if (resultFromCache) {
263-
resultFromCache.failedLookupLocations = updateResolutionField(resultFromCache.failedLookupLocations, failedLookupLocations);
264-
resultFromCache.affectingLocations = updateResolutionField(resultFromCache.affectingLocations, affectingLocations);
265-
resultFromCache.resolutionDiagnostics = updateResolutionField(resultFromCache.resolutionDiagnostics, diagnostics);
266-
return resultFromCache;
266+
if (!cache?.isReadonly) {
267+
resultFromCache.failedLookupLocations = updateResolutionField(resultFromCache.failedLookupLocations, failedLookupLocations);
268+
resultFromCache.affectingLocations = updateResolutionField(resultFromCache.affectingLocations, affectingLocations);
269+
resultFromCache.resolutionDiagnostics = updateResolutionField(resultFromCache.resolutionDiagnostics, diagnostics);
270+
return resultFromCache;
271+
}
272+
else {
273+
return {
274+
...resultFromCache,
275+
failedLookupLocations: initializeResolutionFieldForReadonlyCache(resultFromCache.failedLookupLocations, failedLookupLocations),
276+
affectingLocations: initializeResolutionFieldForReadonlyCache(resultFromCache.affectingLocations, affectingLocations),
277+
resolutionDiagnostics: initializeResolutionFieldForReadonlyCache(resultFromCache.resolutionDiagnostics, diagnostics),
278+
};
279+
}
267280
}
268281
return {
269282
resolvedModule: resolved && {
@@ -291,6 +304,12 @@ export function updateResolutionField<T>(to: T[] | undefined, value: T[] | undef
291304
return to;
292305
}
293306

307+
function initializeResolutionFieldForReadonlyCache<T>(fromCache: T[] | undefined, value: T[]): T[] | undefined {
308+
if (!fromCache?.length) return initializeResolutionField(value);
309+
if (!value.length) return fromCache.slice();
310+
return [...fromCache, ...value];
311+
}
312+
294313
/** @internal */
295314
export interface ModuleResolutionState {
296315
host: ModuleResolutionHost;
@@ -612,10 +631,10 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
612631
affectingLocations: initializeResolutionField(affectingLocations),
613632
resolutionDiagnostics: initializeResolutionField(diagnostics),
614633
};
615-
if (containingDirectory) {
616-
cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result);
634+
if (containingDirectory && cache && !cache.isReadonly) {
635+
cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result);
617636
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
618-
cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result);
637+
cache.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result);
619638
}
620639
}
621640
if (traceEnabled) traceResult(result);
@@ -851,6 +870,7 @@ export interface PerDirectoryResolutionCache<T> {
851870
*/
852871
update(options: CompilerOptions): void;
853872
/** @internal */ directoryToModuleNameMap: CacheWithRedirects<Path, ModeAwareCache<T>>;
873+
/** @internal */ isReadonly?: boolean;
854874
}
855875

856876
export interface NonRelativeNameResolutionCache<T> {
@@ -862,11 +882,13 @@ export interface NonRelativeNameResolutionCache<T> {
862882
* This updates the redirects map as well if needed so module resolutions are cached if they can across the projects
863883
*/
864884
update(options: CompilerOptions): void;
885+
/** @internal */ isReadonly?: boolean;
865886
}
866887

867888
export interface PerNonRelativeNameCache<T> {
868889
get(directory: string): T | undefined;
869890
set(directory: string, result: T): void;
891+
/** @internal */ isReadonly?: boolean;
870892
}
871893

872894
export interface ModuleResolutionCache extends PerDirectoryResolutionCache<ResolvedModuleWithFailedLookupLocations>, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache {
@@ -890,6 +912,7 @@ export interface PackageJsonInfoCache {
890912
/** @internal */ entries(): [Path, PackageJsonInfo | boolean][];
891913
/** @internal */ getInternalMap(): Map<Path, PackageJsonInfo | boolean> | undefined;
892914
clear(): void;
915+
/** @internal */ isReadonly?: boolean;
893916
}
894917

895918
export type PerModuleNameCache = PerNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations>;
@@ -1430,10 +1453,12 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
14301453
if (result && result.resolvedModule) perfLogger?.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`);
14311454
perfLogger?.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null");
14321455

1433-
cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result);
1434-
if (!isExternalModuleNameRelative(moduleName)) {
1435-
// put result in per-module name cache
1436-
cache?.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result);
1456+
if (cache && !cache.isReadonly) {
1457+
cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result);
1458+
if (!isExternalModuleNameRelative(moduleName)) {
1459+
// put result in per-module name cache
1460+
cache.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result);
1461+
}
14371462
}
14381463
}
14391464

@@ -1854,6 +1879,7 @@ function nodeModuleNameResolverWorker(
18541879
affectingLocations,
18551880
diagnostics,
18561881
state,
1882+
cache,
18571883
legacyResult,
18581884
);
18591885

@@ -2390,15 +2416,15 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:
23902416
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
23912417
}
23922418
const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined } };
2393-
state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, result);
2419+
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, result);
23942420
state.affectingLocations?.push(packageJsonPath);
23952421
return result;
23962422
}
23972423
else {
23982424
if (directoryExists && traceEnabled) {
23992425
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
24002426
}
2401-
state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, directoryExists);
2427+
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, directoryExists);
24022428
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
24032429
state.failedLookupLocations?.push(packageJsonPath);
24042430
}
@@ -3182,6 +3208,7 @@ export function classicNameResolver(moduleName: string, containingFile: string,
31823208
affectingLocations,
31833209
diagnostics,
31843210
state,
3211+
cache,
31853212
);
31863213

31873214
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
@@ -3277,6 +3304,7 @@ export function loadModuleFromGlobalCache(moduleName: string, projectName: strin
32773304
affectingLocations,
32783305
diagnostics,
32793306
state.resultFromCache,
3307+
/*cache*/ undefined,
32803308
);
32813309
}
32823310

src/compiler/resolutionCache.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
702702
}
703703

704704
function startCachingPerDirectoryResolution() {
705+
moduleResolutionCache.isReadonly = undefined;
706+
typeReferenceDirectiveResolutionCache.isReadonly = undefined;
707+
libraryResolutionCache.isReadonly = undefined;
708+
moduleResolutionCache.getPackageJsonInfoCache().isReadonly = undefined;
705709
moduleResolutionCache.clearAllExceptPackageJsonInfoCache();
706710
typeReferenceDirectiveResolutionCache.clearAllExceptPackageJsonInfoCache();
707711
libraryResolutionCache.clearAllExceptPackageJsonInfoCache();
@@ -756,6 +760,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
756760
directoryWatchesOfFailedLookups.forEach(closeDirectoryWatchesOfFailedLookup);
757761
fileWatchesOfAffectingLocations.forEach(closeFileWatcherOfAffectingLocation);
758762
hasChangedAutomaticTypeDirectiveNames = false;
763+
moduleResolutionCache.isReadonly = true;
764+
typeReferenceDirectiveResolutionCache.isReadonly = true;
765+
libraryResolutionCache.isReadonly = true;
766+
moduleResolutionCache.getPackageJsonInfoCache().isReadonly = true;
759767
}
760768

761769
function closeDirectoryWatchesOfFailedLookup(watcher: DirectoryWatchesOfFailedLookup, path: Path) {

src/harness/incrementalUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ export function verifyResolutionCache(
273273
verifyFileWatchesOfAffectingLocations(expected.fileWatchesOfAffectingLocations, actual.fileWatchesOfAffectingLocations);
274274

275275
// Stop watching resolutions to verify everything gets closed.
276+
expected.startCachingPerDirectoryResolution();
276277
actual.resolvedModuleNames.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path));
277278
actual.resolvedTypeReferenceDirectives.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path));
278279
expected.finishCachingPerDirectoryResolution(/*newProgram*/ undefined, actualProgram);

0 commit comments

Comments
 (0)