[LL FIR] reuse source sessions

This commit is contained in:
Ilya Kirillov
2022-07-19 18:45:10 +02:00
parent a43ed57be5
commit 51cd5fb5d8
4 changed files with 36 additions and 21 deletions
@@ -9,9 +9,7 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
@Suppress("unused")
internal class LLFirGlobalResolveComponents( internal class LLFirGlobalResolveComponents(
val useSiteKtModule: KtModule,
val project: Project, val project: Project,
) { ) {
val phaseRunner: LLFirPhaseRunner = LLFirPhaseRunner() val phaseRunner: LLFirPhaseRunner = LLFirPhaseRunner()
@@ -10,16 +10,17 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker import com.intellij.openapi.roots.ProjectRootModificationTracker
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.* import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProviderStorage import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProviderStorage
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibrarySourceResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibrarySourceResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession
import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.withLock
internal class LLFirResolveSessionService(project: Project) { internal class LLFirResolveSessionService(project: Project) {
private val sessionProviderStorage = LLFirSessionProviderStorage(project) private val sessionProviderStorage = LLFirSessionProviderStorage(project)
@@ -28,11 +29,22 @@ internal class LLFirResolveSessionService(project: Project) {
project.createProjectWideOutOfBlockModificationTracker(), project.createProjectWideOutOfBlockModificationTracker(),
ProjectRootModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project),
) { ) {
ConcurrentHashMap<KtModule, LLFirResolvableResolveSession>() mutableMapOf<KtModule, LLFirResolvableResolveSession>()
} }
fun getFirResolveSession(module: KtModule): LLFirResolvableResolveSession = private val cacheLock = ReentrantReadWriteLock()
stateCache.computeIfAbsent(module) { createFirResolveSessionFor(module, sessionProviderStorage) }
fun getFirResolveSession(module: KtModule): LLFirResolvableResolveSession {
cacheLock.readLock().withLock {
stateCache[module]?.let { return it }
}
cacheLock.writeLock().withLock {
stateCache[module]?.let { return it }
val session = createFirResolveSessionFor(module, sessionProviderStorage)
stateCache[module] = session
return session
}
}
companion object { companion object {
fun getInstance(project: Project): LLFirResolveSessionService = fun getInstance(project: Project): LLFirResolveSessionService =
@@ -54,6 +66,7 @@ internal class LLFirResolveSessionService(project: Project) {
sessionProvider, sessionProvider,
) )
} }
is KtLibraryModule, is KtLibrarySourceModule -> { is KtLibraryModule, is KtLibrarySourceModule -> {
LLFirLibraryOrLibrarySourceResolvableResolveSession( LLFirLibraryOrLibrarySourceResolvableResolveSession(
useSiteSession.moduleComponents.globalResolveComponents, useSiteSession.moduleComponents.globalResolveComponents,
@@ -62,6 +75,7 @@ internal class LLFirResolveSessionService(project: Project) {
sessionProvider, sessionProvider,
) )
} }
is KtNotUnderContentRootModule -> { is KtNotUnderContentRootModule -> {
LLFirNotUnderContentRootResolvableResolveSession( LLFirNotUnderContentRootResolvableResolveSession(
useSiteSession.moduleComponents.globalResolveComponents, useSiteSession.moduleComponents.globalResolveComponents,
@@ -70,6 +84,7 @@ internal class LLFirResolveSessionService(project: Project) {
sessionProvider, sessionProvider,
) )
} }
else -> { else -> {
error("Unexpected $useSiteKtModule") error("Unexpected $useSiteKtModule")
} }
@@ -54,7 +54,7 @@ internal class LLFirNonUnderContentRootSessionFactory(private val project: Proje
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform) val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val globalResolveComponents = LLFirGlobalResolveComponents(module, project) val globalResolveComponents = LLFirGlobalResolveComponents(project)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope val contentScope = module.contentScope
val session = LLFirNonUnderContentRootSession(module, project, components, builtinsSession.builtinTypes) val session = LLFirNonUnderContentRootSession(module, project, components, builtinsSession.builtinTypes)
@@ -11,30 +11,29 @@ import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentMap import kotlinx.collections.immutable.toPersistentMap
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirNonUnderContentRootSessionFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.firKtModuleBasedModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.firKtModuleBasedModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE
import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirNonUnderContentRootSessionFactory
class LLFirSessionProviderStorage(val project: Project) { class LLFirSessionProviderStorage(val project: Project) {
private val sessionsCache = ConcurrentHashMap<KtModule, FromModuleViewSessionCache>() private val sessionsCache = LLFirSessionsCache()
private val librariesSessionFactory = LLFirLibrarySessionFactory.getInstance(project) private val librariesSessionFactory = LLFirLibrarySessionFactory.getInstance(project)
private val builtInsSessionFactopry = LLFirBuiltinsSessionFactory.getInstance(project) private val builtInsSessionFactory = LLFirBuiltinsSessionFactory.getInstance(project)
private val globalComponents = LLFirGlobalResolveComponents(project)
fun getSessionProvider( fun getSessionProvider(
useSiteKtModule: KtModule, useSiteKtModule: KtModule,
configureSession: (LLFirSession.() -> Unit)? = null configureSession: (LLFirSession.() -> Unit)? = null
): LLFirSessionProvider { ): LLFirSessionProvider {
val globalComponents = LLFirGlobalResolveComponents(useSiteKtModule, project) val (sessions, session) = sessionsCache.withMappings(project) { mappings ->
val cache = sessionsCache.getOrPut(useSiteKtModule) { FromModuleViewSessionCache() }
val (sessions, session) = cache.withMappings(project) { mappings ->
val sessions = mutableMapOf<KtModule, LLFirResolvableModuleSession>().apply { putAll(mappings) } val sessions = mutableMapOf<KtModule, LLFirResolvableModuleSession>().apply { putAll(mappings) }
val session = executeWithoutPCE { val session = executeWithoutPCE {
when (useSiteKtModule) { when (useSiteKtModule) {
@@ -43,26 +42,29 @@ class LLFirSessionProviderStorage(val project: Project) {
project, project,
useSiteKtModule, useSiteKtModule,
globalComponents, globalComponents,
cache.sessionInvalidator, sessionsCache.sessionInvalidator,
sessions, sessions,
librariesSessionFactory, librariesSessionFactory,
configureSession = configureSession, configureSession = configureSession,
) )
} }
is KtLibraryModule, is KtLibrarySourceModule -> { is KtLibraryModule, is KtLibrarySourceModule -> {
LLFirSessionFactory.createLibraryOrLibrarySourceResolvableSession( LLFirSessionFactory.createLibraryOrLibrarySourceResolvableSession(
project, project,
useSiteKtModule, useSiteKtModule,
globalComponents, globalComponents,
cache.sessionInvalidator, sessionsCache.sessionInvalidator,
builtInsSessionFactopry.getBuiltinsSession(useSiteKtModule.platform), builtInsSessionFactory.getBuiltinsSession(useSiteKtModule.platform),
sessions, sessions,
configureSession = configureSession, configureSession = configureSession,
) )
} }
is KtNotUnderContentRootModule -> is KtNotUnderContentRootModule ->
LLFirNonUnderContentRootSessionFactory.getInstance(project) LLFirNonUnderContentRootSessionFactory.getInstance(project)
.getNonUnderContentRootSession(useSiteKtModule, sessions) .getNonUnderContentRootSession(useSiteKtModule, sessions)
else -> error("Unexpected ${useSiteKtModule::class.simpleName}") else -> error("Unexpected ${useSiteKtModule::class.simpleName}")
} }
@@ -74,7 +76,7 @@ class LLFirSessionProviderStorage(val project: Project) {
} }
} }
private class FromModuleViewSessionCache { private class LLFirSessionsCache {
@Volatile @Volatile
private var mappings: PersistentMap<KtModule, FirSessionWithModificationTracker> = persistentMapOf() private var mappings: PersistentMap<KtModule, FirSessionWithModificationTracker> = persistentMapOf()