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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.context.GlobalContext
import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider 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: soft reference?
// TODO: cache by script definition? // TODO: cache by script definition?
private val facadeForScriptDependencies by lazy { private val facadeForScriptDependencies by lazy {
ProjectResolutionFacade(project, globalContext.storageManager) { val globalContext = GlobalContext()
globalResolveSessionProvider( ProjectResolutionFacade(
"dependencies of scripts", project, globalContext,
project, globalResolveSessionProvider(
JvmPlatform, // TODO: Js scripts? "dependencies of scripts",
null, // TODO: provide sdk via dependencies JvmPlatform, // TODO: Js scripts?
commonGlobalContext = globalContext, null, // TODO: provide sdk via dependencies
allModules = listOf(ScriptDependenciesModuleInfo(project)), allModules = listOf(ScriptDependenciesModuleInfo(project)),
dependencies = listOf( dependencies = listOf(
LibraryModificationTracker.getInstance(project), //TODO: provide correct trackers LibraryModificationTracker.getInstance(project), //TODO: provide correct trackers
ProjectRootModificationTracker.getInstance(project) ProjectRootModificationTracker.getInstance(project)
), ),
moduleFilter = { true } moduleFilter = { true }
) )
} )
} }
private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) { private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) {
val facadeForLibraries = ProjectResolutionFacade(project, globalContext.storageManager) { private val sdkContext = GlobalContext()
globalResolveSessionProvider( val facadeForSdk = ProjectResolutionFacade(
"project libraries for platform $platform", project, sdkContext,
project, globalResolveSessionProvider(
platform, "sdk $sdk",
sdk, platform,
commonGlobalContext = globalContext, sdk,
moduleFilter = { it.isLibraryClasses() }, moduleFilter = { it is SdkInfo },
dependencies = listOf( dependencies = listOf(
LibraryModificationTracker.getInstance(project), LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project) ProjectRootModificationTracker.getInstance(project)
) )
) ))
}
val facadeForModules = ProjectResolutionFacade(project, globalContext.storageManager) { private val librariesContext = sdkContext.contextWithNewLockAndCompositeExceptionTracker()
globalResolveSessionProvider( val facadeForLibraries = ProjectResolutionFacade(
"project source roots and libraries for platform $platform", project, librariesContext,
project, globalResolveSessionProvider(
platform, "project libraries for platform $platform",
sdk, platform,
commonGlobalContext = globalContext, sdk,
reuseDataFrom = facadeForLibraries, reuseDataFrom = facadeForSdk,
moduleFilter = { !it.isLibraryClasses() }, moduleFilter = { it is LibraryInfo },
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)) 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") @Deprecated("Use JetElement.getResolutionFacade(), please avoid introducing new usages")
@@ -146,13 +161,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
fun makeGlobalResolveSessionProvider(reuseDataFrom: ProjectResolutionFacade? = null, fun makeGlobalResolveSessionProvider(reuseDataFrom: ProjectResolutionFacade? = null,
moduleFilter: (IdeaModuleInfo) -> Boolean = { true }, moduleFilter: (IdeaModuleInfo) -> Boolean = { true },
allModules: Collection<IdeaModuleInfo>? = null allModules: Collection<IdeaModuleInfo>? = null
): CachedValueProvider.Result<ModuleResolverProvider> { ): (GlobalContextImpl, Project) -> CachedValueProvider.Result<ModuleResolverProvider> {
return globalResolveSessionProvider( return globalResolveSessionProvider(
debugName, debugName,
project,
targetPlatform, targetPlatform,
sdk, sdk,
commonGlobalContext = globalContext,
syntheticFiles = files, syntheticFiles = files,
reuseDataFrom = reuseDataFrom, reuseDataFrom = reuseDataFrom,
moduleFilter = moduleFilter, moduleFilter = moduleFilter,
@@ -164,30 +177,38 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
return when { return when {
syntheticFileModule is ModuleSourceInfo -> { syntheticFileModule is ModuleSourceInfo -> {
val dependentModules = syntheticFileModule.getDependentModules() val dependentModules = syntheticFileModule.getDependentModules()
ProjectResolutionFacade(project, globalContext.storageManager) { val modulesFacade = globalFacade(targetPlatform, sdk)
makeGlobalResolveSessionProvider( val globalContext = modulesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
reuseDataFrom = globalFacade(targetPlatform, sdk), ProjectResolutionFacade(
moduleFilter = { it in dependentModules }) project, globalContext,
} makeGlobalResolveSessionProvider(
reuseDataFrom = modulesFacade,
moduleFilter = { it in dependentModules })
)
} }
syntheticFileModule is ScriptModuleInfo || syntheticFileModule is ScriptDependenciesModuleInfo -> { syntheticFileModule is ScriptModuleInfo || syntheticFileModule is ScriptDependenciesModuleInfo -> {
ProjectResolutionFacade(project, globalContext.storageManager) { val globalContext = facadeForScriptDependencies.globalContext.contextWithNewLockAndCompositeExceptionTracker()
makeGlobalResolveSessionProvider( ProjectResolutionFacade(
reuseDataFrom = facadeForScriptDependencies, project, globalContext,
allModules = listOf(syntheticFileModule) + syntheticFileModule.dependencies(), makeGlobalResolveSessionProvider(
moduleFilter = { it == syntheticFileModule } reuseDataFrom = facadeForScriptDependencies,
) moduleFilter = { it == syntheticFileModule },
} allModules = syntheticFileModule.dependencies()
)
)
} }
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
ProjectResolutionFacade(project, globalContext.storageManager) { val librariesFacade = librariesFacade(targetPlatform, sdk)
makeGlobalResolveSessionProvider( val globalContext = librariesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
reuseDataFrom = librariesFacade(targetPlatform, sdk), ProjectResolutionFacade(
moduleFilter = { it == syntheticFileModule } project, globalContext,
) makeGlobalResolveSessionProvider(
} reuseDataFrom = librariesFacade,
moduleFilter = { it == syntheticFileModule }
)
)
} }
syntheticFileModule.isLibraryClasses() -> { 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 // currently the only known scenario is when we cannot determine that file is a library source
// (file under both classes and sources root) // (file under both classes and sources root)
LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule") LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule")
ProjectResolutionFacade(project, globalContext.storageManager) { val globalContext = GlobalContext()
makeGlobalResolveSessionProvider() ProjectResolutionFacade(
} project, globalContext,
makeGlobalResolveSessionProvider()
)
} }
else -> throw IllegalStateException("Unknown IdeaModuleInfo ${syntheticFileModule.javaClass}") else -> throw IllegalStateException("Unknown IdeaModuleInfo ${syntheticFileModule.javaClass}")
@@ -278,40 +301,40 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private fun globalResolveSessionProvider( private fun globalResolveSessionProvider(
debugName: String, debugName: String,
project: Project,
platform: TargetPlatform, platform: TargetPlatform,
sdk: Sdk?, sdk: Sdk?,
dependencies: Collection<Any>, dependencies: Collection<Any>,
moduleFilter: (IdeaModuleInfo) -> Boolean, moduleFilter: (IdeaModuleInfo) -> Boolean,
commonGlobalContext: GlobalContextImpl,
reuseDataFrom: ProjectResolutionFacade? = null, reuseDataFrom: ProjectResolutionFacade? = null,
syntheticFiles: Collection<KtFile> = listOf(), syntheticFiles: Collection<KtFile> = listOf(),
allModules: Collection<IdeaModuleInfo>? = null // null means create resolvers for modules from idea model 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 delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject() val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
val globalContext = commonGlobalContext.withCompositeExceptionTrackerUnderSameLock()
val builtIns: KotlinBuiltIns = when (platform) { val reusedBuiltIns = delegateResolverProvider?.builtIns
is JsPlatform -> JsPlatform.builtIns val newBuiltIns: KotlinBuiltIns? = when {
is JvmPlatform -> JvmBuiltIns(globalContext.storageManager) reusedBuiltIns != null -> null
platform is JsPlatform -> JsPlatform.builtIns
platform is JvmPlatform && sdk != null -> JvmBuiltIns(globalContext.storageManager)
else -> DefaultBuiltIns.Instance else -> DefaultBuiltIns.Instance
} }
val builtIns = reusedBuiltIns ?: newBuiltIns!!
val moduleResolverProvider = createModuleResolverProvider( val moduleResolverProvider = createModuleResolverProvider(
debugName, project, globalContext, sdk, debugName, project, globalContext, sdk,
AnalyzerFacadeProvider.getAnalyzerFacade(platform), AnalyzerFacadeProvider.getAnalyzerFacade(platform),
syntheticFiles, delegateResolverForProject, moduleFilter, syntheticFiles, delegateResolverForProject, moduleFilter,
allModules, builtIns allModules,
builtIns
) )
if (builtIns is JvmBuiltIns) { if (newBuiltIns is JvmBuiltIns) {
val moduleInfoToUse = sdk?.let { SdkInfo(project, it) } ?: moduleResolverProvider.resolverForProject.allModules.firstOrNull() val sdkInfo = SdkInfo(project, sdk!!)
if (moduleInfoToUse != null) { newBuiltIns.setOwnerModuleDescriptor(moduleResolverProvider.resolverForProject.descriptorForModule(sdkInfo))
builtIns.setOwnerModuleDescriptor(moduleResolverProvider.resolverForProject.descriptorForModule(moduleInfoToUse))
}
} }
val allDependencies = dependencies + listOf(moduleResolverProvider.exceptionTracker) 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( return ModuleResolverProviderImpl(
resolverForProject, resolverForProject,
builtIns,
globalContext globalContext
) )
} }
@@ -112,11 +113,13 @@ private fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModul
interface ModuleResolverProvider { interface ModuleResolverProvider {
val exceptionTracker: ExceptionTracker val exceptionTracker: ExceptionTracker
val resolverForProject: ResolverForProject<IdeaModuleInfo> val resolverForProject: ResolverForProject<IdeaModuleInfo>
val builtIns: KotlinBuiltIns
} }
class ModuleResolverProviderImpl( class ModuleResolverProviderImpl(
override val resolverForProject: ResolverForProject<IdeaModuleInfo>, override val resolverForProject: ResolverForProject<IdeaModuleInfo>,
val globalContext: GlobalContextImpl override val builtIns: KotlinBuiltIns,
globalContext: GlobalContextImpl
) : ModuleResolverProvider { ) : ModuleResolverProvider {
override val exceptionTracker: ExceptionTracker = globalContext.exceptionTracker 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.analyzer.AnalysisResult
import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.project.ResolveElementCache 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.CompositeBindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.storage.StorageManager
internal class ProjectResolutionFacade( internal class ProjectResolutionFacade(
val project: Project, val project: Project,
private val storageManager: StorageManager, val globalContext: GlobalContextImpl,
computeModuleResolverProvider: () -> CachedValueProvider.Result<ModuleResolverProvider> computeModuleResolverProvider: (GlobalContextImpl, Project) -> CachedValueProvider.Result<ModuleResolverProvider>
) { ) {
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue( private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
computeModuleResolverProvider, { computeModuleResolverProvider(globalContext, project) },
/* trackValue = */ false /* trackValue = */ false
) )
val moduleResolverProvider: ModuleResolverProvider val moduleResolverProvider: ModuleResolverProvider
get() = storageManager.compute { cachedValue.value } get() = globalContext.storageManager.compute { cachedValue.value }
fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = moduleResolverProvider.resolverForProject.resolverForModule(moduleInfo) fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = moduleResolverProvider.resolverForProject.resolverForModule(moduleInfo)
fun resolverForDescriptor(moduleDescriptor: ModuleDescriptor) = moduleResolverProvider.resolverForProject.resolverForModuleDescriptor(moduleDescriptor) 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.ExceptionTracker import org.jetbrains.kotlin.storage.ExceptionTracker
import com.intellij.openapi.progress.ProcessCanceledException import org.jetbrains.kotlin.storage.LockBasedStorageManager
import com.intellij.openapi.diagnostic.Logger
fun GlobalContextImpl.withCompositeExceptionTrackerUnderSameLock(): GlobalContextImpl { internal fun GlobalContextImpl.contextWithNewLockAndCompositeExceptionTracker(): GlobalContextImpl {
val newExceptionTracker = CompositeExceptionTracker(this.exceptionTracker) val newExceptionTracker = CompositeExceptionTracker(this.exceptionTracker)
val newStorageManager = LockBasedStorageManager.createDelegatingWithSameLock(this.storageManager, newExceptionTracker) return GlobalContextImpl(LockBasedStorageManager.createWithExceptionHandling(newExceptionTracker), newExceptionTracker)
return GlobalContextImpl(newStorageManager, newExceptionTracker)
} }
private class CompositeExceptionTracker(val delegate: ExceptionTracker) : ExceptionTracker() { private class CompositeExceptionTracker(val delegate: ExceptionTracker) : ExceptionTracker() {
@@ -33,22 +30,3 @@ private class CompositeExceptionTracker(val delegate: ExceptionTracker) : Except
return super.getModificationCount() + delegate.modificationCount 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)
}