From eac645850020a2d204a9becb4e7a694084f3ce2c Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Tue, 28 Mar 2023 21:16:52 +0200 Subject: [PATCH] [LL FIR] KT-57314 Add cache to combined Kotlin symbol providers - This Caffeine cache is limited to classes for now, but may also be tried with callables. - The cache has a small memory footprint, but still avoids most of the unnecessary index accesses. In my local tests, this approach takes 50% of the time compared to no caches. A full cache has no performance advantage over the limited-size cache in my local tests. --- .../fir/providers/LLFirCombinedKotlinSymbolProvider.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt index 742fdf521a0..580341e7814 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.low.level.api.fir.caches.NullableCaffeineCache import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCache import org.jetbrains.kotlin.analysis.project.structure.KtModule @@ -34,7 +35,8 @@ import org.jetbrains.kotlin.psi.KtFile * [LLFirDependenciesSymbolProvider], this check is especially fruitful. * - For a given class or callable ID, indices can be accessed once to get relevant PSI elements. Then the correct symbol provider(s) to * call can be found out via the PSI element's [KtModule]s. This avoids the need to call every single subordinate symbol provider. - * - TODO (marco): Another layer of caching can be provided, perhaps with an LRU cache. + * - A small Caffeine cache can avoid most index accesses for classes, because many names are requested multiple times, with a minor memory + * footprint. * * [declarationProvider] must have a scope which combines the scopes of the individual [providers]. */ @@ -54,10 +56,12 @@ internal class LLFirCombinedKotlinSymbolProvider( } } + private val classifierCache = NullableCaffeineCache> { it.maximumSize(500) } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { if (!symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null - return computeClassLikeSymbolByClassId(classId) + return classifierCache.get(classId) { computeClassLikeSymbolByClassId(it) } } @OptIn(FirSymbolProviderInternals::class)