KotlinCacheServiceImpl: create new locks when creating caches that delegate to other caches

Remove single globalContext that was passed around to every configurations
Correctly create exception trackers when delegating caches
Delegate builtIns instance when delegating caches
Create specialized JvmBuiltIns only if Sdk is specified
This commit is contained in:
Pavel V. Talanov
2016-06-27 18:56:38 +03:00
parent d53c53a900
commit cbf78c7298
4 changed files with 117 additions and 113 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.context.GlobalContext
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider
@@ -65,55 +66,69 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
}
private val globalContext = GlobalContext(logProcessCanceled = true)
// TODO: soft reference?
// TODO: cache by script definition?
private val facadeForScriptDependencies by lazy {
ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
"dependencies of scripts",
project,
JvmPlatform, // TODO: Js scripts?
null, // TODO: provide sdk via dependencies
commonGlobalContext = globalContext,
allModules = listOf(ScriptDependenciesModuleInfo(project)),
dependencies = listOf(
LibraryModificationTracker.getInstance(project), //TODO: provide correct trackers
ProjectRootModificationTracker.getInstance(project)
),
moduleFilter = { true }
)
}
val globalContext = GlobalContext()
ProjectResolutionFacade(
project, globalContext,
globalResolveSessionProvider(
"dependencies of scripts",
JvmPlatform, // TODO: Js scripts?
null, // TODO: provide sdk via dependencies
allModules = listOf(ScriptDependenciesModuleInfo(project)),
dependencies = listOf(
LibraryModificationTracker.getInstance(project), //TODO: provide correct trackers
ProjectRootModificationTracker.getInstance(project)
),
moduleFilter = { true }
)
)
}
private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) {
val facadeForLibraries = ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
"project libraries for platform $platform",
project,
platform,
sdk,
commonGlobalContext = globalContext,
moduleFilter = { it.isLibraryClasses() },
dependencies = listOf(
LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project)
)
)
}
private val sdkContext = GlobalContext()
val facadeForSdk = ProjectResolutionFacade(
project, sdkContext,
globalResolveSessionProvider(
"sdk $sdk",
platform,
sdk,
moduleFilter = { it is SdkInfo },
dependencies = listOf(
LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project)
)
))
val facadeForModules = ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
"project source roots and libraries for platform $platform",
project,
platform,
sdk,
commonGlobalContext = globalContext,
reuseDataFrom = facadeForLibraries,
moduleFilter = { !it.isLibraryClasses() },
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT))
}
private val librariesContext = sdkContext.contextWithNewLockAndCompositeExceptionTracker()
val facadeForLibraries = ProjectResolutionFacade(
project, librariesContext,
globalResolveSessionProvider(
"project libraries for platform $platform",
platform,
sdk,
reuseDataFrom = facadeForSdk,
moduleFilter = { it is LibraryInfo },
dependencies = listOf(
LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project)
)
)
)
private val modulesContext = librariesContext.contextWithNewLockAndCompositeExceptionTracker()
val facadeForModules = ProjectResolutionFacade(
project, modulesContext,
globalResolveSessionProvider(
"project source roots and libraries for platform $platform",
platform,
sdk,
reuseDataFrom = facadeForLibraries,
moduleFilter = { !it.isLibraryClasses() },
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT))
)
}
@Deprecated("Use JetElement.getResolutionFacade(), please avoid introducing new usages")
@@ -146,13 +161,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
fun makeGlobalResolveSessionProvider(reuseDataFrom: ProjectResolutionFacade? = null,
moduleFilter: (IdeaModuleInfo) -> Boolean = { true },
allModules: Collection<IdeaModuleInfo>? = null
): CachedValueProvider.Result<ModuleResolverProvider> {
): (GlobalContextImpl, Project) -> CachedValueProvider.Result<ModuleResolverProvider> {
return globalResolveSessionProvider(
debugName,
project,
targetPlatform,
sdk,
commonGlobalContext = globalContext,
syntheticFiles = files,
reuseDataFrom = reuseDataFrom,
moduleFilter = moduleFilter,
@@ -164,30 +177,38 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
return when {
syntheticFileModule is ModuleSourceInfo -> {
val dependentModules = syntheticFileModule.getDependentModules()
ProjectResolutionFacade(project, globalContext.storageManager) {
makeGlobalResolveSessionProvider(
reuseDataFrom = globalFacade(targetPlatform, sdk),
moduleFilter = { it in dependentModules })
}
val modulesFacade = globalFacade(targetPlatform, sdk)
val globalContext = modulesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade(
project, globalContext,
makeGlobalResolveSessionProvider(
reuseDataFrom = modulesFacade,
moduleFilter = { it in dependentModules })
)
}
syntheticFileModule is ScriptModuleInfo || syntheticFileModule is ScriptDependenciesModuleInfo -> {
ProjectResolutionFacade(project, globalContext.storageManager) {
makeGlobalResolveSessionProvider(
reuseDataFrom = facadeForScriptDependencies,
allModules = listOf(syntheticFileModule) + syntheticFileModule.dependencies(),
moduleFilter = { it == syntheticFileModule }
)
}
val globalContext = facadeForScriptDependencies.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade(
project, globalContext,
makeGlobalResolveSessionProvider(
reuseDataFrom = facadeForScriptDependencies,
moduleFilter = { it == syntheticFileModule },
allModules = syntheticFileModule.dependencies()
)
)
}
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
ProjectResolutionFacade(project, globalContext.storageManager) {
makeGlobalResolveSessionProvider(
reuseDataFrom = librariesFacade(targetPlatform, sdk),
moduleFilter = { it == syntheticFileModule }
)
}
val librariesFacade = librariesFacade(targetPlatform, sdk)
val globalContext = librariesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade(
project, globalContext,
makeGlobalResolveSessionProvider(
reuseDataFrom = librariesFacade,
moduleFilter = { it == syntheticFileModule }
)
)
}
syntheticFileModule.isLibraryClasses() -> {
@@ -195,9 +216,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
// currently the only known scenario is when we cannot determine that file is a library source
// (file under both classes and sources root)
LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule")
ProjectResolutionFacade(project, globalContext.storageManager) {
makeGlobalResolveSessionProvider()
}
val globalContext = GlobalContext()
ProjectResolutionFacade(
project, globalContext,
makeGlobalResolveSessionProvider()
)
}
else -> throw IllegalStateException("Unknown IdeaModuleInfo ${syntheticFileModule.javaClass}")
@@ -278,40 +301,40 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private fun globalResolveSessionProvider(
debugName: String,
project: Project,
platform: TargetPlatform,
sdk: Sdk?,
dependencies: Collection<Any>,
moduleFilter: (IdeaModuleInfo) -> Boolean,
commonGlobalContext: GlobalContextImpl,
reuseDataFrom: ProjectResolutionFacade? = null,
syntheticFiles: Collection<KtFile> = listOf(),
allModules: Collection<IdeaModuleInfo>? = null // null means create resolvers for modules from idea model
): CachedValueProvider.Result<ModuleResolverProvider> {
): (GlobalContextImpl, Project) -> CachedValueProvider.Result<ModuleResolverProvider> = { globalContext, project ->
val delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
val globalContext = commonGlobalContext.withCompositeExceptionTrackerUnderSameLock()
val builtIns: KotlinBuiltIns = when (platform) {
is JsPlatform -> JsPlatform.builtIns
is JvmPlatform -> JvmBuiltIns(globalContext.storageManager)
val reusedBuiltIns = delegateResolverProvider?.builtIns
val newBuiltIns: KotlinBuiltIns? = when {
reusedBuiltIns != null -> null
platform is JsPlatform -> JsPlatform.builtIns
platform is JvmPlatform && sdk != null -> JvmBuiltIns(globalContext.storageManager)
else -> DefaultBuiltIns.Instance
}
val builtIns = reusedBuiltIns ?: newBuiltIns!!
val moduleResolverProvider = createModuleResolverProvider(
debugName, project, globalContext, sdk,
AnalyzerFacadeProvider.getAnalyzerFacade(platform),
syntheticFiles, delegateResolverForProject, moduleFilter,
allModules, builtIns
allModules,
builtIns
)
if (builtIns is JvmBuiltIns) {
val moduleInfoToUse = sdk?.let { SdkInfo(project, it) } ?: moduleResolverProvider.resolverForProject.allModules.firstOrNull()
if (moduleInfoToUse != null) {
builtIns.setOwnerModuleDescriptor(moduleResolverProvider.resolverForProject.descriptorForModule(moduleInfoToUse))
}
if (newBuiltIns is JvmBuiltIns) {
val sdkInfo = SdkInfo(project, sdk!!)
newBuiltIns.setOwnerModuleDescriptor(moduleResolverProvider.resolverForProject.descriptorForModule(sdkInfo))
}
val allDependencies = dependencies + listOf(moduleResolverProvider.exceptionTracker)
return CachedValueProvider.Result.create(moduleResolverProvider, allDependencies)
CachedValueProvider.Result.create(moduleResolverProvider, allDependencies)
}
@@ -80,6 +80,7 @@ fun createModuleResolverProvider(
return ModuleResolverProviderImpl(
resolverForProject,
builtIns,
globalContext
)
}
@@ -112,11 +113,13 @@ private fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModul
interface ModuleResolverProvider {
val exceptionTracker: ExceptionTracker
val resolverForProject: ResolverForProject<IdeaModuleInfo>
val builtIns: KotlinBuiltIns
}
class ModuleResolverProviderImpl(
override val resolverForProject: ResolverForProject<IdeaModuleInfo>,
val globalContext: GlobalContextImpl
override val builtIns: KotlinBuiltIns,
globalContext: GlobalContextImpl
) : ModuleResolverProvider {
override val exceptionTracker: ExceptionTracker = globalContext.exceptionTracker
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.project.ResolveElementCache
@@ -36,20 +37,19 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompositeBindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.storage.StorageManager
internal class ProjectResolutionFacade(
val project: Project,
private val storageManager: StorageManager,
computeModuleResolverProvider: () -> CachedValueProvider.Result<ModuleResolverProvider>
val globalContext: GlobalContextImpl,
computeModuleResolverProvider: (GlobalContextImpl, Project) -> CachedValueProvider.Result<ModuleResolverProvider>
) {
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
computeModuleResolverProvider,
{ computeModuleResolverProvider(globalContext, project) },
/* trackValue = */ false
)
val moduleResolverProvider: ModuleResolverProvider
get() = storageManager.compute { cachedValue.value }
get() = globalContext.storageManager.compute { cachedValue.value }
fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = moduleResolverProvider.resolverForProject.resolverForModule(moduleInfo)
fun resolverForDescriptor(moduleDescriptor: ModuleDescriptor) = moduleResolverProvider.resolverForProject.resolverForModuleDescriptor(moduleDescriptor)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,12 @@
package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.ExceptionTracker
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.storage.LockBasedStorageManager
fun GlobalContextImpl.withCompositeExceptionTrackerUnderSameLock(): GlobalContextImpl {
internal fun GlobalContextImpl.contextWithNewLockAndCompositeExceptionTracker(): GlobalContextImpl {
val newExceptionTracker = CompositeExceptionTracker(this.exceptionTracker)
val newStorageManager = LockBasedStorageManager.createDelegatingWithSameLock(this.storageManager, newExceptionTracker)
return GlobalContextImpl(newStorageManager, newExceptionTracker)
return GlobalContextImpl(LockBasedStorageManager.createWithExceptionHandling(newExceptionTracker), newExceptionTracker)
}
private class CompositeExceptionTracker(val delegate: ExceptionTracker) : ExceptionTracker() {
@@ -33,22 +30,3 @@ private class CompositeExceptionTracker(val delegate: ExceptionTracker) : Except
return super.getModificationCount() + delegate.modificationCount
}
}
private class ExceptionTrackerWithProcessCanceledReport() : ExceptionTracker() {
override fun handleException(throwable: Throwable): RuntimeException {
if (throwable is ProcessCanceledException) {
LOG.info("ProcessCancelException was thrown while analyzing libraries. Cache has to be rebuilt.")
}
throw super.handleException(throwable)
}
companion object {
val LOG = Logger.getInstance(ExceptionTrackerWithProcessCanceledReport::class.java)
}
}
fun GlobalContext(logProcessCanceled: Boolean): GlobalContextImpl {
val tracker = if (logProcessCanceled) ExceptionTrackerWithProcessCanceledReport() else ExceptionTracker()
return GlobalContextImpl(LockBasedStorageManager.createWithExceptionHandling(tracker), tracker)
}