FIR: remove extra layers of caching above JavaSymbolProvider
There needs to be exactly one postcompute-aware cache in order to avoid breaking recursive calls to getClassLikeSymbolByFqName.
This commit is contained in:
-89
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.fir.low.level.api.providers
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.PrivateForInline
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.util.concurrent.locks.ReadWriteLock
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
internal class FirThreadSafeSymbolProviderWrapper(private val provider: FirSymbolProvider) : FirSymbolProvider(provider.session) {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private val classesCache = ThreadSafeCache<ClassId, FirClassLikeSymbol<*>>(lock)
|
||||
private val topLevelCache = ThreadSafeCache<CallableId, List<FirCallableSymbol<*>>>(lock)
|
||||
private val packages = ThreadSafeCache<FqName, FqName>(lock)
|
||||
|
||||
override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? =
|
||||
classesCache.getOrCompute(classId) {
|
||||
provider.getClassLikeSymbolByFqName(classId)
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> =
|
||||
topLevelCache.getOrCompute(CallableId(packageFqName, name)) {
|
||||
provider.getTopLevelCallableSymbols(packageFqName, name)
|
||||
} ?: emptyList()
|
||||
|
||||
override fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> {
|
||||
return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance<FirNamedFunctionSymbol>()
|
||||
}
|
||||
|
||||
override fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List<FirPropertySymbol> {
|
||||
return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance<FirPropertySymbol>()
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
|
||||
error("Should not be called for wrapper")
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += getTopLevelFunctionSymbols(packageFqName, name)
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += getTopLevelPropertySymbols(packageFqName, name)
|
||||
}
|
||||
|
||||
override fun getPackage(fqName: FqName): FqName? =
|
||||
packages.getOrCompute(fqName) { provider.getPackage(fqName) }
|
||||
}
|
||||
|
||||
private class ThreadSafeCache<KEY, VALUE : Any>(private val lock: ReadWriteLock) {
|
||||
private val map = HashMap<KEY, Any>()
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
inline fun getOrCompute(key: KEY, compute: () -> VALUE?): VALUE? {
|
||||
var value = lock.readLock().withLock { map[key] }
|
||||
if (value == null) {
|
||||
lock.writeLock().withLock {
|
||||
value = compute() ?: NULLABLE_VALUE
|
||||
map[key] = value!!
|
||||
}
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (value) {
|
||||
NULLABLE_VALUE -> null
|
||||
null -> error("We should not read null from map here")
|
||||
else -> value as VALUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ClassName")
|
||||
@PrivateForInline
|
||||
internal object NULLABLE_VALUE
|
||||
+9
-16
@@ -46,7 +46,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeBuiltinsAndCl
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeLibrariesSessionProvider
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirModuleWithDependenciesSymbolProvider
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirThreadSafeSymbolProviderWrapper
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.util.checkCanceled
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl
|
||||
@@ -197,8 +196,6 @@ internal object FirIdeSessionFactory {
|
||||
registerCommonJavaComponents()
|
||||
registerJavaSpecificResolveComponents()
|
||||
|
||||
val javaSymbolProvider = JavaSymbolProvider(this, mainModuleData, project, searchScope)
|
||||
|
||||
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
|
||||
|
||||
val moduleDataProvider = project.stateConfigurator.createModuleDataProvider(mainModuleInfo)
|
||||
@@ -210,19 +207,16 @@ internal object FirIdeSessionFactory {
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
buildList {
|
||||
add(
|
||||
FirThreadSafeSymbolProviderWrapper(
|
||||
KotlinDeserializedJvmSymbolsProviderForIde(
|
||||
this@session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
packagePartProvider,
|
||||
kotlinClassFinder,
|
||||
javaSymbolProvider,
|
||||
javaClassFinder
|
||||
)
|
||||
KotlinDeserializedJvmSymbolsProviderForIde(
|
||||
this@session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
packagePartProvider,
|
||||
kotlinClassFinder,
|
||||
javaClassFinder
|
||||
)
|
||||
)
|
||||
add(javaSymbolProvider)
|
||||
add(JavaSymbolProvider(this@session, mainModuleData, project, searchScope))
|
||||
addAll((builtinsAndCloneableSession.symbolProvider as FirCompositeSymbolProvider).providers)
|
||||
}
|
||||
)
|
||||
@@ -244,11 +238,10 @@ internal object FirIdeSessionFactory {
|
||||
kotlinScopeProvider: FirKotlinScopeProvider,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
kotlinClassFinder: KotlinClassFinder,
|
||||
javaSymbolProvider: JavaSymbolProvider,
|
||||
javaClassFinder: JavaClassFinder
|
||||
) : KotlinDeserializedJvmSymbolsProvider(
|
||||
session, moduleDataProvider, kotlinScopeProvider, packagePartProvider, kotlinClassFinder,
|
||||
javaSymbolProvider, javaClassFinder
|
||||
javaClassFinder
|
||||
) {
|
||||
override fun getClass(
|
||||
classId: ClassId,
|
||||
|
||||
Reference in New Issue
Block a user