K2: Optimize use-site member and intersection scopes

Avoid creating cache keys for names that are definitely absent
This commit is contained in:
Denis.Zharkov
2022-12-13 16:45:41 +01:00
committed by Space Team
parent db3b7c4021
commit 24bd7e5eef
3 changed files with 23 additions and 31 deletions
@@ -36,8 +36,6 @@ abstract class AbstractFirUseSiteMemberScope(
protected val propertiesFromSupertypes: MutableMap<Name, List<ResultOfIntersection<FirPropertySymbol>>> = mutableMapOf() protected val propertiesFromSupertypes: MutableMap<Name, List<ResultOfIntersection<FirPropertySymbol>>> = mutableMapOf()
protected val fieldsFromSupertypes: MutableMap<Name, List<FirFieldSymbol>> = mutableMapOf() protected val fieldsFromSupertypes: MutableMap<Name, List<FirFieldSymbol>> = mutableMapOf()
private val absentClassifiersFromSupertypes = mutableSetOf<Name>()
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) { private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
buildSet { buildSet {
addAll(declaredMemberScope.getCallableNames()) addAll(declaredMemberScope.getCallableNames())
@@ -53,6 +51,8 @@ abstract class AbstractFirUseSiteMemberScope(
} }
final override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { 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) { functions.getOrPut(name) {
collectFunctions(name) collectFunctions(name)
}.forEach { }.forEach {
@@ -102,6 +102,8 @@ abstract class AbstractFirUseSiteMemberScope(
} }
final override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { 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) { properties.getOrPut(name) {
collectProperties(name) collectProperties(name)
}.forEach { }.forEach {
@@ -198,13 +200,16 @@ abstract class AbstractFirUseSiteMemberScope(
} }
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { 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 var shadowed = false
declaredMemberScope.processClassifiersByNameWithSubstitution(name) { classifier, substitutor -> declaredMemberScope.processClassifiersByNameWithSubstitution(name) { classifier, substitutor ->
shadowed = true shadowed = true
processor(classifier, substitutor) processor(classifier, substitutor)
} }
if (!shadowed) { if (!shadowed) {
supertypeScopeContext.processClassifiersByNameWithSubstitution(name, absentClassifiersFromSupertypes, processor) supertypeScopeContext.processClassifiersByNameWithSubstitution(name, processor)
} }
} }
@@ -21,41 +21,35 @@ class FirTypeIntersectionScope private constructor(
private val intersectionContext = private val intersectionContext =
FirTypeIntersectionScopeContext(session, overrideChecker, scopes, dispatchReceiverType, forClassUseSiteScope = false) FirTypeIntersectionScopeContext(session, overrideChecker, scopes, dispatchReceiverType, forClassUseSiteScope = false)
private val absentFunctions: MutableSet<Name> = mutableSetOf()
private val absentProperties: MutableSet<Name> = mutableSetOf()
private val absentClassifiers: MutableSet<Name> = mutableSetOf()
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf() private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<FirCallableSymbol<*>>>> = mutableMapOf()
private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) { private val callableNamesCached by lazy(LazyThreadSafetyMode.PUBLICATION) {
scopes.flatMapTo(mutableSetOf()) { it.getCallableNames() } 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) { 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) { 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 <D : FirCallableSymbol<*>> processCallablesByName( private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
name: Name, name: Name,
noinline processor: (D) -> Unit, noinline processor: (D) -> Unit,
absentNames: MutableSet<Name>,
processCallables: FirScope.(Name, (D) -> Unit) -> Unit processCallables: FirScope.(Name, (D) -> Unit) -> Unit
) { ) {
if (name in absentNames) {
return
}
val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(name, processCallables) val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(name, processCallables)
if (callablesWithOverridden.isEmpty()) {
absentNames.add(name)
return
}
for (resultOfIntersection in callablesWithOverridden) { for (resultOfIntersection in callablesWithOverridden) {
val symbol = resultOfIntersection.chosenSymbol val symbol = resultOfIntersection.chosenSymbol
overriddenSymbols[symbol] = resultOfIntersection.overriddenMembers overriddenSymbols[symbol] = resultOfIntersection.overriddenMembers
@@ -64,7 +58,9 @@ class FirTypeIntersectionScope private constructor(
} }
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { 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") @Suppress("UNCHECKED_CAST")
@@ -112,9 +108,7 @@ class FirTypeIntersectionScope private constructor(
override fun getCallableNames(): Set<Name> = callableNamesCached override fun getCallableNames(): Set<Name> = callableNamesCached
override fun getClassifierNames(): Set<Name> { override fun getClassifierNames(): Set<Name> = classifiersNamesCached
return scopes.flatMapTo(hashSetOf()) { it.getClassifierNames() }
}
override fun toString(): String { override fun toString(): String {
return "Intersection of [${scopes.joinToString(", ")}]" return "Intersection of [${scopes.joinToString(", ")}]"
@@ -76,16 +76,9 @@ class FirTypeIntersectionScopeContext(
fun processClassifiersByNameWithSubstitution( fun processClassifiersByNameWithSubstitution(
name: Name, name: Name,
absentClassifierNames: MutableSet<Name>,
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
) { ) {
if (name in absentClassifierNames) return for ((symbol, substitution) in collectClassifiers(name)) {
val classifiers = collectClassifiers(name)
if (classifiers.isEmpty()) {
absentClassifierNames += name
return
}
for ((symbol, substitution) in classifiers) {
processor(symbol, substitution) processor(symbol, substitution)
} }
} }