FIR IDE: reuse up-to-date fir sessions

This commit is contained in:
Ilya Kirillov
2020-09-14 19:15:20 +03:00
parent 22c2d34b14
commit a743b80d17
5 changed files with 61 additions and 18 deletions
@@ -16,8 +16,8 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
*/ */
@OptIn(PrivateSessionConstructor::class) @OptIn(PrivateSessionConstructor::class)
internal class FirIdeLibrariesSession @PrivateSessionConstructor constructor( internal class FirIdeLibrariesSession @PrivateSessionConstructor constructor(
moduleInfo: ModuleInfo, override val moduleInfo: ModuleInfo,
override val project: Project, override val project: Project,
override val scope: GlobalSearchScope, override val scope: GlobalSearchScope,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : FirIdeModuleSession(moduleInfo, builtinTypes) ) : FirIdeModuleSession(builtinTypes)
@@ -19,6 +19,7 @@ abstract class FirIdeSession(override val builtinTypes: BuiltinTypes) : FirSessi
} }
@OptIn(PrivateSessionConstructor::class) @OptIn(PrivateSessionConstructor::class)
abstract class FirIdeModuleSession(override val moduleInfo: ModuleInfo, builtinTypes: BuiltinTypes) : FirIdeSession(builtinTypes) { abstract class FirIdeModuleSession(builtinTypes: BuiltinTypes) : FirIdeSession(builtinTypes) {
abstract override val moduleInfo: ModuleInfo
abstract val scope: GlobalSearchScope abstract val scope: GlobalSearchScope
} }
@@ -57,10 +57,11 @@ internal object FirIdeSessionFactory {
val scopeProvider = KotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = KotlinScopeProvider(::wrapScopeWithJvmMapped)
val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner) val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner)
val searchScope = ModuleProductionSourceScope(moduleInfo.module) val searchScope = ModuleProductionSourceScope(moduleInfo.module)
val session = FirIdeSourcesSession(moduleInfo, project, searchScope, firBuilder, builtinTypes)
sessionsCache[moduleInfo] = session
val dependentModules = moduleInfo.dependenciesWithoutSelf() val dependentModules = moduleInfo.dependenciesWithoutSelf()
.filterIsInstanceTo<ModuleSourceInfo, MutableList<ModuleSourceInfo>>(mutableListOf()) .filterIsInstanceTo<ModuleSourceInfo, MutableList<ModuleSourceInfo>>(mutableListOf())
val session = FirIdeSourcesSession(moduleInfo, dependentModules, project, searchScope, firBuilder, builtinTypes)
sessionsCache[moduleInfo] = session
return session.apply { return session.apply {
val cache = ModuleFileCacheImpl(this) val cache = ModuleFileCacheImpl(this)
@@ -8,29 +8,67 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.sessions
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.trackers.KotlinModuleOutOfCodeBlockModificationTracker
import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner
import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE
import java.util.concurrent.ConcurrentHashMap
internal class FirIdeSessionProviderStorage(private val project: Project) { internal class FirIdeSessionProviderStorage(private val project: Project) {
private val sessionsCache = ConcurrentHashMap<ModuleSourceInfo, FromModuleViewSessionCache>()
fun getSessionProvider(rootModule: ModuleSourceInfo): FirIdeSessionProvider { fun getSessionProvider(rootModule: ModuleSourceInfo): FirIdeSessionProvider {
val transformerProvider = FirTransformerProvider() val transformerProvider = FirTransformerProvider()
val firPhaseRunner = FirPhaseRunner(transformerProvider) val firPhaseRunner = FirPhaseRunner(transformerProvider)
val builtinTypes = BuiltinTypes() val builtinTypes = BuiltinTypes()
val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, builtinTypes) val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, builtinTypes)
val sessions = mutableMapOf<ModuleSourceInfo, FirIdeSourcesSession>() val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache(rootModule) }
val session = executeWithoutPCE { val (sessions, session) = cache.withMappings { mappings ->
FirIdeSessionFactory.createSourcesSession( val sessions = mutableMapOf<ModuleSourceInfo, FirIdeSourcesSession>().apply { putAll(mappings) }
project, val session = executeWithoutPCE {
rootModule, FirIdeSessionFactory.createSourcesSession(
builtinsAndCloneableSession, project,
firPhaseRunner, rootModule,
builtinTypes, builtinsAndCloneableSession,
sessions, firPhaseRunner,
isRootModule = true builtinTypes,
) sessions,
isRootModule = true
)
}
sessions to session
} }
return FirIdeSessionProvider(project, session, sessions) return FirIdeSessionProvider(project, session, sessions)
} }
}
private class FromModuleViewSessionCache(
val root: ModuleSourceInfo
) {
@Volatile
private var mappings: Map<ModuleSourceInfo, FirSessionWithModificationTracker> = emptyMap()
inline fun <R> withMappings(
action: (Map<ModuleSourceInfo, FirIdeSourcesSession>) -> Pair<Map<ModuleSourceInfo, FirIdeSourcesSession>, R>
): Pair<Map<ModuleSourceInfo, FirIdeSourcesSession>, R> {
val (newMappings, result) = action(getSessions().mapValues { it.value })
mappings = newMappings.mapValues { FirSessionWithModificationTracker(it.value) }
return newMappings to result
}
@OptIn(ExperimentalStdlibApi::class)
private fun getSessions(): Map<ModuleSourceInfo, FirIdeSourcesSession> = buildMap {
mappings.forEach { (module, session) -> if (session.isValid) put(module, session.firSession) }
}
}
private class FirSessionWithModificationTracker(
val firSession: FirIdeSourcesSession,
) {
private val modificationTracker = KotlinModuleOutOfCodeBlockModificationTracker(firSession.moduleInfo.module)
private val timeStamp = modificationTracker.modificationCount
val isValid: Boolean get() = modificationTracker.modificationCount == timeStamp
} }
@@ -10,17 +10,20 @@ import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
@OptIn(PrivateSessionConstructor::class) @OptIn(PrivateSessionConstructor::class)
internal class FirIdeSourcesSession @PrivateSessionConstructor constructor( internal class FirIdeSourcesSession @PrivateSessionConstructor constructor(
moduleInfo: ModuleInfo, override val moduleInfo: ModuleSourceInfo,
val dependencies: List<ModuleSourceInfo>,
override val project: Project, override val project: Project,
override val scope: GlobalSearchScope, override val scope: GlobalSearchScope,
val firFileBuilder: FirFileBuilder, val firFileBuilder: FirFileBuilder,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : FirIdeModuleSession(moduleInfo, builtinTypes) { ) : FirIdeModuleSession( builtinTypes) {
val cache get() = firIdeProvider.cache val cache get() = firIdeProvider.cache
} }