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:
+16
-11
@@ -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
|
||||
|
||||
+8
-3
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user