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.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.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
|
||||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
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?) {
|
private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) {
|
||||||
val facadeForLibraries = ProjectResolutionFacade(project) {
|
val facadeForLibraries = ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||||
globalResolveSessionProvider(
|
globalResolveSessionProvider(
|
||||||
"project libraries for platform $platform",
|
"project libraries for platform $platform",
|
||||||
project,
|
project,
|
||||||
platform,
|
platform,
|
||||||
sdk,
|
sdk,
|
||||||
logProcessCanceled = true,
|
commonGlobalContext = globalContext,
|
||||||
moduleFilter = { it.isLibraryClasses() },
|
moduleFilter = { it.isLibraryClasses() },
|
||||||
dependencies = listOf(
|
dependencies = listOf(
|
||||||
LibraryModificationTracker.getInstance(project),
|
LibraryModificationTracker.getInstance(project),
|
||||||
@@ -80,12 +83,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val facadeForModules = ProjectResolutionFacade(project) {
|
val facadeForModules = ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||||
globalResolveSessionProvider(
|
globalResolveSessionProvider(
|
||||||
"project source roots and libraries for platform $platform",
|
"project source roots and libraries for platform $platform",
|
||||||
project,
|
project,
|
||||||
platform,
|
platform,
|
||||||
sdk,
|
sdk,
|
||||||
|
commonGlobalContext = globalContext,
|
||||||
reuseDataFrom = facadeForLibraries,
|
reuseDataFrom = facadeForLibraries,
|
||||||
moduleFilter = { !it.isLibraryClasses() },
|
moduleFilter = { !it.isLibraryClasses() },
|
||||||
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT))
|
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT))
|
||||||
@@ -120,12 +124,13 @@ 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) {
|
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||||
globalResolveSessionProvider(
|
globalResolveSessionProvider(
|
||||||
debugName,
|
debugName,
|
||||||
project,
|
project,
|
||||||
targetPlatform,
|
targetPlatform,
|
||||||
sdk,
|
sdk,
|
||||||
|
commonGlobalContext = globalContext,
|
||||||
syntheticFiles = files,
|
syntheticFiles = files,
|
||||||
reuseDataFrom = globalFacade(targetPlatform, sdk),
|
reuseDataFrom = globalFacade(targetPlatform, sdk),
|
||||||
moduleFilter = { it in dependentModules },
|
moduleFilter = { it in dependentModules },
|
||||||
@@ -135,12 +140,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
|
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
|
||||||
ProjectResolutionFacade(project) {
|
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||||
globalResolveSessionProvider(
|
globalResolveSessionProvider(
|
||||||
debugName,
|
debugName,
|
||||||
project,
|
project,
|
||||||
targetPlatform,
|
targetPlatform,
|
||||||
sdk,
|
sdk,
|
||||||
|
commonGlobalContext = globalContext,
|
||||||
syntheticFiles = files,
|
syntheticFiles = files,
|
||||||
reuseDataFrom = librariesFacade(targetPlatform, sdk),
|
reuseDataFrom = librariesFacade(targetPlatform, sdk),
|
||||||
moduleFilter = { it == syntheticFileModule },
|
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
|
// 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) {
|
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||||
globalResolveSessionProvider(
|
globalResolveSessionProvider(
|
||||||
debugName,
|
debugName,
|
||||||
project,
|
project,
|
||||||
targetPlatform,
|
targetPlatform,
|
||||||
sdk,
|
sdk,
|
||||||
|
commonGlobalContext = globalContext,
|
||||||
syntheticFiles = files,
|
syntheticFiles = files,
|
||||||
moduleFilter = { true },
|
moduleFilter = { true },
|
||||||
dependencies = dependenciesForSyntheticFileCache
|
dependencies = dependenciesForSyntheticFileCache
|
||||||
@@ -250,15 +257,13 @@ private fun globalResolveSessionProvider(
|
|||||||
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()
|
||||||
logProcessCanceled: Boolean = false
|
|
||||||
): CachedValueProvider.Result<ModuleResolverProvider> {
|
): CachedValueProvider.Result<ModuleResolverProvider> {
|
||||||
val delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
|
val delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
|
||||||
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
|
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
|
||||||
val globalContext = (delegateResolverProvider as? ModuleResolverProviderImpl)?.globalContext
|
val globalContext = commonGlobalContext.withCompositeExceptionTrackerUnderSameLock()
|
||||||
?.withCompositeExceptionTrackerUnderSameLock()
|
|
||||||
?: GlobalContext(logProcessCanceled)
|
|
||||||
|
|
||||||
val builtIns: KotlinBuiltIns = when (platform) {
|
val builtIns: KotlinBuiltIns = when (platform) {
|
||||||
is JsPlatform -> JsPlatform.builtIns
|
is JsPlatform -> JsPlatform.builtIns
|
||||||
|
|||||||
+7
-2
@@ -36,15 +36,20 @@ 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,
|
||||||
computeModuleResolverProvider: () -> CachedValueProvider.Result<ModuleResolverProvider>
|
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
|
val moduleResolverProvider: ModuleResolverProvider
|
||||||
get() = resolverCache.getValue()
|
get() = 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,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