Skip to content

Commit 5b50238

Browse files
committed
Cache repeated mapper instantiations only within a single instantiation call
1 parent a6a728f commit 5b50238

File tree

101 files changed

+160
-111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+160
-111
lines changed

Diff for: src/compiler/checker.ts

+46-16
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ import {
164164
EmitResolver,
165165
EmitTextWriter,
166166
emptyArray,
167-
emptyMap,
168167
EntityName,
169168
EntityNameExpression,
170169
EntityNameOrEntityNameExpression,
@@ -2111,14 +2110,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21112110
}
21122111
return t;
21132112
}, () => "(unmeasurable reporter)");
2114-
reportUnreliableMapper.instantiations = emptyMap;
21152113
var reportUnmeasurableMapper = makeFunctionTypeMapper(t => {
21162114
if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) {
21172115
outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false);
21182116
}
21192117
return t;
21202118
}, () => "(unreliable reporter)");
2121-
reportUnmeasurableMapper.instantiations = emptyMap;
21222119

21232120
var emptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
21242121
var emptyJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
@@ -2319,6 +2316,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
23192316
var inferenceContexts: (InferenceContext | undefined)[] = [];
23202317
var inferenceContextCount = 0;
23212318

2319+
var activeTypeMappers: TypeMapper[] = [];
2320+
var activeTypeMappersCaches: Map<string, Type>[] = [];
2321+
var activeTypeMappersCount = 0;
2322+
23222323
var emptyStringType = getStringLiteralType("");
23232324
var zeroType = getNumberLiteralType(0);
23242325
var zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" });
@@ -20374,22 +20375,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2037420375
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
2037520376
return errorType;
2037620377
}
20377-
let key: string;
20378-
if (mapper.instantiations !== emptyMap) {
20379-
key = type.id + getAliasId(aliasSymbol, aliasTypeArguments);
20380-
const cached = (mapper.instantiations ??= new Map()).get(key);
20381-
if (cached) {
20382-
return cached;
20383-
}
20378+
const index = findActiveMapper(mapper);
20379+
if (index === -1) {
20380+
pushActiveMapper(mapper);
20381+
}
20382+
const key = type.id + getAliasId(aliasSymbol, aliasTypeArguments);
20383+
const mapperCache = activeTypeMappersCaches[index !== -1 ? index : activeTypeMappersCount - 1];
20384+
const cached = mapperCache.get(key);
20385+
if (cached) {
20386+
return cached;
2038420387
}
2038520388
totalInstantiationCount++;
2038620389
instantiationCount++;
2038720390
instantiationDepth++;
2038820391
const result = instantiateTypeWorker(type, mapper, aliasSymbol, aliasTypeArguments);
20389-
if (mapper.instantiations !== emptyMap) {
20390-
// volatile caches (like on `nonFixingMapper`) could have been cleared by the above `instantiateTypeWorker`
20391-
// if so, we don't want to cache the result as it likely won't be valid anymore anyway
20392-
mapper.instantiations?.set(key!, result);
20392+
if (index === -1) {
20393+
popActiveMapper();
20394+
}
20395+
else {
20396+
mapperCache.set(key, result);
2039320397
}
2039420398
instantiationDepth--;
2039520399
return result;
@@ -25594,7 +25598,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2559425598

2559525599
function clearCachedInferences(context: InferenceContext | undefined, inferences: InferenceInfo[]) {
2559625600
if (context) {
25597-
context.nonFixingMapper.instantiations = undefined;
25601+
clearActiveMapperCache(context.nonFixingMapper);
2559825602
}
2559925603
for (const inference of inferences) {
2560025604
if (!inference.isFixed) {
@@ -26967,7 +26971,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2696726971
// instantiating the constraint could reenter this function if the type parameter's constraint depends on that parameter
2696826972
// in such a case the reentering call just returns the preemptively set `.inferredType`
2696926973
// but given the `.inferredType` gets changed changed above, the cached instantiations have to be cleared because they were cached for the wrong type
26970-
context.nonFixingMapper.instantiations = undefined;
26974+
clearActiveMapperCache(context.nonFixingMapper);
2697126975
}
2697226976
}
2697326977
}
@@ -32186,6 +32190,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3218632190
}
3218732191
}
3218832192

32193+
function pushActiveMapper(mapper: TypeMapper) {
32194+
activeTypeMappers[activeTypeMappersCount] = mapper;
32195+
activeTypeMappersCaches[activeTypeMappersCount] = new Map();
32196+
activeTypeMappersCount++;
32197+
}
32198+
32199+
function popActiveMapper() {
32200+
activeTypeMappersCount--;
32201+
}
32202+
32203+
function findActiveMapper(mapper: TypeMapper) {
32204+
for (let i = activeTypeMappersCount - 1; i >= 0; i--) {
32205+
if (mapper === activeTypeMappers[i]) {
32206+
return i;
32207+
}
32208+
}
32209+
return -1;
32210+
}
32211+
32212+
function clearActiveMapperCache(mapper: TypeMapper) {
32213+
const index = findActiveMapper(mapper);
32214+
if (index !== -1) {
32215+
activeTypeMappersCaches[index] = new Map();
32216+
}
32217+
}
32218+
3218932219
function getContextualImportAttributeType(node: ImportAttribute) {
3219032220
return getTypeOfPropertyOfContextualType(getGlobalImportAttributesType(/*reportErrors*/ false), getNameFromImportAttribute(node));
3219132221
}

Diff for: src/compiler/core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
/** @internal */
1717
export const emptyArray: never[] = [] as never[];
1818
/** @internal */
19-
export const emptyMap: Map<never, never> = new Map<never, never>();
19+
export const emptyMap: ReadonlyMap<never, never> = new Map<never, never>();
2020

2121
/** @internal */
2222
export function length(array: readonly any[] | undefined): number {

Diff for: src/compiler/types.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -7029,11 +7029,11 @@ export const enum TypeMapKind {
70297029

70307030
/** @internal */
70317031
export type TypeMapper =
7032-
| { kind: TypeMapKind.Simple; source: Type; target: Type; instantiations?: Map<string, Type>; }
7033-
| { kind: TypeMapKind.Array; sources: readonly Type[]; targets: readonly Type[] | undefined; instantiations?: Map<string, Type>; }
7034-
| { kind: TypeMapKind.Deferred; sources: readonly Type[]; targets: (() => Type)[]; instantiations?: Map<string, Type>; }
7035-
| { kind: TypeMapKind.Function; func: (t: Type) => Type; debugInfo?: () => string; instantiations?: Map<string, Type>; }
7036-
| { kind: TypeMapKind.Composite | TypeMapKind.Merged; mapper1: TypeMapper; mapper2: TypeMapper; instantiations?: Map<string, Type>; };
7032+
| { kind: TypeMapKind.Simple; source: Type; target: Type; }
7033+
| { kind: TypeMapKind.Array; sources: readonly Type[]; targets: readonly Type[] | undefined; }
7034+
| { kind: TypeMapKind.Deferred; sources: readonly Type[]; targets: (() => Type)[]; }
7035+
| { kind: TypeMapKind.Function; func: (t: Type) => Type; debugInfo?: () => string; }
7036+
| { kind: TypeMapKind.Composite | TypeMapKind.Merged; mapper1: TypeMapper; mapper2: TypeMapper; };
70377037

70387038
// dprint-ignore
70397039
export const enum InferencePriority {

Diff for: tests/baselines/reference/callsOnComplexSignatures.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== callsOnComplexSignatures.tsx ===

Diff for: tests/baselines/reference/checkJsxChildrenCanBeTupleType.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== checkJsxChildrenCanBeTupleType.tsx ===

Diff for: tests/baselines/reference/checkJsxChildrenProperty16.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== checkJsxChildrenProperty16.tsx ===

Diff for: tests/baselines/reference/checkJsxUnionSFXContextualTypeInferredCorrectly.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== checkJsxUnionSFXContextualTypeInferredCorrectly.tsx ===

Diff for: tests/baselines/reference/conditionalTypeDiscriminatingLargeUnionRegularTypeFetchingSpeedReasonable.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Strict subtype cache: 2,500
55
Assignability cache: 10,000
66
Type Count: 10,000
7-
Instantiation count: 25,000
7+
Instantiation count: 50,000
88

99
=== conditionalTypeDiscriminatingLargeUnionRegularTypeFetchingSpeedReasonable.ts ===
1010
type BigUnion =

Diff for: tests/baselines/reference/conditionalTypeVarianceBigArrayConstraintsPerformance.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 1,000
55
Type Count: 5,000
6-
Instantiation count: 5,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== conditionalTypeVarianceBigArrayConstraintsPerformance.ts ===

Diff for: tests/baselines/reference/contextuallyTypedJsxAttribute2.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 5,000
55
Type Count: 10,000
6-
Instantiation count: 100,000
6+
Instantiation count: 250,000
77
Symbol count: 100,000
88

99
=== contextuallyTypedJsxAttribute2.tsx ===

Diff for: tests/baselines/reference/contextuallyTypedJsxChildren.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== contextuallyTypedJsxChildren.tsx ===

Diff for: tests/baselines/reference/declarationEmitRecursiveConditionalAliasPreserved.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 25,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== input.d.ts ===

Diff for: tests/baselines/reference/errorInfoForRelatedIndexTypesNoConstraintElaboration.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 25,000
6+
Instantiation count: 100,000
77
Symbol count: 100,000
88

99
=== errorInfoForRelatedIndexTypesNoConstraintElaboration.ts ===

Diff for: tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 1,000
5-
Instantiation count: 1,000
5+
Instantiation count: 2,500
66

77
=== esNextWeakRefs_IterableWeakMap.ts ===
88
/** `static #cleanup` */

Diff for: tests/baselines/reference/excessiveStackDepthFlatArray.types

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 1,000
5+
Instantiation count: 1,000
56

67
=== index.tsx ===
78
interface MiddlewareArray<T> extends Array<T> {}

Diff for: tests/baselines/reference/genericFunctionInference1.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 1,000
5-
Instantiation count: 1,000 -> 2,500
5+
Instantiation count: 2,500
66

77
=== genericFunctionInference1.ts ===
88
declare function pipe<A extends any[], B>(ab: (...args: A) => B): (...args: A) => B;

Diff for: tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 5,000
55
Type Count: 10,000
6-
Instantiation count: 100,000
6+
Instantiation count: 250,000
77
Symbol count: 100,000
88

99
=== genericInferenceDefaultTypeParameterJsxReact.tsx ===

Diff for: tests/baselines/reference/hugeDeclarationOutputGetsTruncatedWithError.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 100,000
5-
Instantiation count: 250,000
5+
Instantiation count: 500,000
66
Symbol count: 100,000
77

88
=== hugeDeclarationOutputGetsTruncatedWithError.ts ===

Diff for: tests/baselines/reference/ignoredJsxAttributes.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== ignoredJsxAttributes.tsx ===

Diff for: tests/baselines/reference/importTag24.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 1,000
5-
Instantiation count: 1,000
5+
Instantiation count: 2,500
66

77
=== types.d.ts ===
88
export type Foo = string;

Diff for: tests/baselines/reference/infiniteConstraints.types

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//// [tests/cases/compiler/infiniteConstraints.ts] ////
22

3+
=== Performance Stats ===
4+
Instantiation count: 2,500
5+
36
=== infiniteConstraints.ts ===
47
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
58

Diff for: tests/baselines/reference/intraExpressionInferencesJsx.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== intraExpressionInferencesJsx.tsx ===

Diff for: tests/baselines/reference/jsDeclarationsNonIdentifierInferredNames.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 5,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsDeclarationsNonIdentifierInferredNames.jsx ===

Diff for: tests/baselines/reference/jsDeclarationsReactComponents.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsDeclarationsReactComponents1.jsx ===

Diff for: tests/baselines/reference/jsxCallElaborationCheckNoCrash1.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsxCallElaborationCheckNoCrash1.tsx ===

Diff for: tests/baselines/reference/jsxChildrenIndividualErrorElaborations.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== index.tsx ===

Diff for: tests/baselines/reference/jsxComplexSignatureHasApplicabilityError.types

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
=== Performance Stats ===
44
Type Count: 1,000
5+
Instantiation count: 1,000 -> 2,500
56

67
=== jsxComplexSignatureHasApplicabilityError.tsx ===
78
/// <reference path="react16.d.ts" />

Diff for: tests/baselines/reference/jsxDeclarationsWithEsModuleInteropNoCrash.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsxDeclarationsWithEsModuleInteropNoCrash.jsx ===

Diff for: tests/baselines/reference/jsxElementType.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsxElementType.tsx ===

Diff for: tests/baselines/reference/jsxElementTypeLiteral.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsxElementTypeLiteral.tsx ===

Diff for: tests/baselines/reference/jsxElementTypeLiteralWithGeneric.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
=== Performance Stats ===
44
Assignability cache: 2,500
55
Type Count: 10,000
6-
Instantiation count: 10,000
6+
Instantiation count: 50,000
77
Symbol count: 50,000
88

99
=== jsxElementTypeLiteralWithGeneric.tsx ===

0 commit comments

Comments
 (0)