From 24bd7e5eefb47946de6702d927817789a20a0261 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 13 Dec 2022 16:45:41 +0100 Subject: [PATCH] K2: Optimize use-site member and intersection scopes Avoid creating cache keys for names that are definitely absent --- .../impl/AbstractFirUseSiteMemberScope.kt | 11 ++++-- .../scopes/impl/FirTypeIntersectionScope.kt | 34 ++++++++----------- .../impl/FirTypeIntersectionScopeContext.kt | 9 +---- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt index 0ee86b27582..bde476a1fc2 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt @@ -36,8 +36,6 @@ abstract class AbstractFirUseSiteMemberScope( protected val propertiesFromSupertypes: MutableMap>> = mutableMapOf() protected val fieldsFromSupertypes: MutableMap> = mutableMapOf() - private val absentClassifiersFromSupertypes = mutableSetOf() - private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) { buildSet { addAll(declaredMemberScope.getCallableNames()) @@ -53,6 +51,8 @@ abstract class AbstractFirUseSiteMemberScope( } final override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getCallableNames()) return functions.getOrPut(name) { collectFunctions(name) }.forEach { @@ -102,6 +102,8 @@ abstract class AbstractFirUseSiteMemberScope( } final override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getCallableNames()) return properties.getOrPut(name) { collectProperties(name) }.forEach { @@ -198,13 +200,16 @@ abstract class AbstractFirUseSiteMemberScope( } override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getClassifierNames()) return + var shadowed = false declaredMemberScope.processClassifiersByNameWithSubstitution(name) { classifier, substitutor -> shadowed = true processor(classifier, substitutor) } if (!shadowed) { - supertypeScopeContext.processClassifiersByNameWithSubstitution(name, absentClassifiersFromSupertypes, processor) + supertypeScopeContext.processClassifiersByNameWithSubstitution(name, processor) } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt index 450a28ace59..0a88cc0aa06 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt @@ -21,41 +21,35 @@ class FirTypeIntersectionScope private constructor( private val intersectionContext = FirTypeIntersectionScopeContext(session, overrideChecker, scopes, dispatchReceiverType, forClassUseSiteScope = false) - private val absentFunctions: MutableSet = mutableSetOf() - private val absentProperties: MutableSet = mutableSetOf() - private val absentClassifiers: MutableSet = mutableSetOf() - private val overriddenSymbols: MutableMap, Collection>>> = mutableMapOf() private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) { scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() } } + private val classifiersNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) { + scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() } + } + override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { - processCallablesByName(name, processor, absentFunctions, FirScope::processFunctionsByName) + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getCallableNames()) return + processCallablesByName(name, processor, FirScope::processFunctionsByName) } override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { - processCallablesByName(name, processor, absentProperties, FirScope::processPropertiesByName) + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getCallableNames()) return + processCallablesByName(name, processor, FirScope::processPropertiesByName) } private inline fun > processCallablesByName( name: Name, noinline processor: (D) -> Unit, - absentNames: MutableSet, processCallables: FirScope.(Name, (D) -> Unit) -> Unit ) { - if (name in absentNames) { - return - } - val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(name, processCallables) - if (callablesWithOverridden.isEmpty()) { - absentNames.add(name) - return - } - for (resultOfIntersection in callablesWithOverridden) { val symbol = resultOfIntersection.chosenSymbol overriddenSymbols[symbol] = resultOfIntersection.overriddenMembers @@ -64,7 +58,9 @@ class FirTypeIntersectionScope private constructor( } override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { - intersectionContext.processClassifiersByNameWithSubstitution(name, absentClassifiers, processor) + // Important optimization: avoid creating cache keys for names that are definitely absent + if (name !in getClassifierNames()) return + intersectionContext.processClassifiersByNameWithSubstitution(name, processor) } @Suppress("UNCHECKED_CAST") @@ -112,9 +108,7 @@ class FirTypeIntersectionScope private constructor( override fun getCallableNames(): Set = callableNamesCached - override fun getClassifierNames(): Set { - return scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() } - } + override fun getClassifierNames(): Set = classifiersNamesCached override fun toString(): String { return "Intersection of [${scopes.joinToString(", ")}]" diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt index 190ef498887..aa5f2372372 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt @@ -76,16 +76,9 @@ class FirTypeIntersectionScopeContext( fun processClassifiersByNameWithSubstitution( name: Name, - absentClassifierNames: MutableSet, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit ) { - if (name in absentClassifierNames) return - val classifiers = collectClassifiers(name) - if (classifiers.isEmpty()) { - absentClassifierNames += name - return - } - for ((symbol, substitution) in classifiers) { + for ((symbol, substitution) in collectClassifiers(name)) { processor(symbol, substitution) } }