Compute cached-value under common storage manager

Before this commit it was calculated under separate lock, so it could turn into dead-lock

 #KT-12396 Fixed
This commit is contained in:
Denis Zharkov
2016-05-19 10:59:33 +03:00
parent a25ba5baf1
commit 4cbd2fbe62
3 changed files with 24 additions and 48 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.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
@@ -64,14 +65,16 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
}
private val globalContext = GlobalContext(logProcessCanceled = true)
private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) {
val facadeForLibraries = ProjectResolutionFacade(project) {
val facadeForLibraries = ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
"project libraries for platform $platform",
project,
platform,
sdk,
logProcessCanceled = true,
commonGlobalContext = globalContext,
moduleFilter = { it.isLibraryClasses() },
dependencies = listOf(
LibraryModificationTracker.getInstance(project),
@@ -80,12 +83,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
)
}
val facadeForModules = ProjectResolutionFacade(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))
@@ -120,12 +124,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
return when {
syntheticFileModule is ModuleSourceInfo -> {
val dependentModules = syntheticFileModule.getDependentModules()
ProjectResolutionFacade(project) {
ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
debugName,
project,
targetPlatform,
sdk,
commonGlobalContext = globalContext,
syntheticFiles = files,
reuseDataFrom = globalFacade(targetPlatform, sdk),
moduleFilter = { it in dependentModules },
@@ -135,12 +140,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
ProjectResolutionFacade(project) {
ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
debugName,
project,
targetPlatform,
sdk,
commonGlobalContext = globalContext,
syntheticFiles = files,
reuseDataFrom = librariesFacade(targetPlatform, sdk),
moduleFilter = { it == syntheticFileModule },
@@ -154,12 +160,13 @@ 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) {
ProjectResolutionFacade(project, globalContext.storageManager) {
globalResolveSessionProvider(
debugName,
project,
targetPlatform,
sdk,
commonGlobalContext = globalContext,
syntheticFiles = files,
moduleFilter = { true },
dependencies = dependenciesForSyntheticFileCache
@@ -250,15 +257,13 @@ private fun globalResolveSessionProvider(
sdk: Sdk?,
dependencies: Collection<Any>,
moduleFilter: (IdeaModuleInfo) -> Boolean,
commonGlobalContext: GlobalContextImpl,
reuseDataFrom: ProjectResolutionFacade? = null,
syntheticFiles: Collection<KtFile> = listOf(),
logProcessCanceled: Boolean = false
syntheticFiles: Collection<KtFile> = listOf()
): CachedValueProvider.Result<ModuleResolverProvider> {
val delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
val globalContext = (delegateResolverProvider as? ModuleResolverProviderImpl)?.globalContext
?.withCompositeExceptionTrackerUnderSameLock()
?: GlobalContext(logProcessCanceled)
val globalContext = commonGlobalContext.withCompositeExceptionTrackerUnderSameLock()
val builtIns: KotlinBuiltIns = when (platform) {
is JsPlatform -> JsPlatform.builtIns
@@ -36,15 +36,20 @@ 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>
) {
private val resolverCache = SynchronizedCachedValue(project, computeModuleResolverProvider, trackValue = false)
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
computeModuleResolverProvider,
/* trackValue = */ false
)
val moduleResolverProvider: ModuleResolverProvider
get() = resolverCache.getValue()
get() = storageManager.compute { cachedValue.value }
fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = moduleResolverProvider.resolverForProject.resolverForModule(moduleInfo)
fun resolverForDescriptor(moduleDescriptor: ModuleDescriptor) = moduleResolverProvider.resolverForProject.resolverForModuleDescriptor(moduleDescriptor)
@@ -134,4 +139,4 @@ internal class ResolutionFacadeImpl(
fun ResolutionFacade.findModuleDescriptor(ideaModuleInfo: IdeaModuleInfo): ModuleDescriptor? {
return (this as? ResolutionFacadeImpl)?.findModuleDescriptor(ideaModuleInfo)
}
}
@@ -1,34 +0,0 @@
/*
* Copyright 2010-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValueProvider
class SynchronizedCachedValue<out V>(project: Project, provider: () -> CachedValueProvider.Result<V>, trackValue: Boolean = true) {
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
provider,
trackValue
)
fun getValue(): V {
return synchronized(cachedValue) {
cachedValue.value
}
}
}