diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt index 65768611305..96855f599ac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt @@ -206,11 +206,13 @@ abstract class AnalyzerFacade { addFriends() + val cache = WeakReferenceSLRUCache(storageManager) + fun initializeResolverForProject() { modules.forEach { module -> val descriptor = resolverForProject.descriptorForModule(module) - val computeResolverForModule = storageManager.createLazyValue { + val computeResolverForModule = cache.prepareValueComputation(module) { val content = modulesContent(module) createResolverForModule( module, descriptor, projectContext.withModule(descriptor), modulesContent(module), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/WeakReferenceSLRUCache.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/WeakReferenceSLRUCache.kt new file mode 100644 index 00000000000..27513774513 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/WeakReferenceSLRUCache.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2016 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.analyzer + +import com.intellij.util.containers.ContainerUtil +import com.intellij.util.containers.SLRUMap +import org.jetbrains.kotlin.storage.StorageManager + +class WeakReferenceSLRUCache(private val storageManager: StorageManager) { + private val weakValueMap = ContainerUtil.createConcurrentWeakValueMap() + // Store most recently used values in SLRU cache to make them available even if no other references to them exist + private val recentlyUsed = SLRUMap(20, 20) + + fun prepareValueComputation(module: K, computation: () -> V): () -> V = { + getOrCompute(module, computation) + } + + private fun getOrCompute(module: K, computation: () -> V): V { + getFromWeakValueMap(module)?.let { + return it + } + + return storageManager.compute { + getFromWeakValueMap(module)?.let { + return@compute it + } + + val result = computation() + weakValueMap[module] = result + + recentlyUsed.put(result, STUB_OBJECT) + + result + } + } + + private fun getFromWeakValueMap(module: K) = + weakValueMap[module]?.let { + recordAccess(it) + it + } + + private fun recordAccess(resolver: V) { + storageManager.compute { + recentlyUsed.get(resolver) + } + } +} + +private val STUB_OBJECT = Any()