From 4cbd2fbe628d5719fcdac17b1f51b0d61cd5f303 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 19 May 2016 10:59:33 +0300 Subject: [PATCH] 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 --- .../caches/resolve/KotlinCacheServiceImpl.kt | 27 +++++++++------ .../caches/resolve/ProjectResolutionFacade.kt | 11 ++++-- .../kotlin/idea/caches/resolve/cacheUtils.kt | 34 ------------------- 3 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/cacheUtils.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index 571a6b734d5..f7a39912a0d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -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, moduleFilter: (IdeaModuleInfo) -> Boolean, + commonGlobalContext: GlobalContextImpl, reuseDataFrom: ProjectResolutionFacade? = null, - syntheticFiles: Collection = listOf(), - logProcessCanceled: Boolean = false + syntheticFiles: Collection = listOf() ): CachedValueProvider.Result { 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 diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt index d6689482d26..a0b636ca955 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt @@ -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 ) { - 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) -} \ No newline at end of file +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/cacheUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/cacheUtils.kt deleted file mode 100644 index 99f918a5f94..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/cacheUtils.kt +++ /dev/null @@ -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(project: Project, provider: () -> CachedValueProvider.Result, trackValue: Boolean = true) { - private val cachedValue = CachedValuesManager.getManager(project).createCachedValue( - provider, - trackValue - ) - - fun getValue(): V { - return synchronized(cachedValue) { - cachedValue.value - } - } -}