Move typeMappers cache to KotlinPositionManagerCache

This commit is contained in:
Natalia Ukhorskaya
2016-01-20 15:05:00 +03:00
parent c808f4ec2a
commit e89638f937
4 changed files with 88 additions and 77 deletions
@@ -31,18 +31,15 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.*
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.ThreeState
import com.intellij.xdebugger.frame.XStackFrame
import com.sun.jdi.AbsentInformationException
import com.sun.jdi.Location
import com.sun.jdi.ReferenceType
import com.sun.jdi.request.ClassPrepareRequest
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -51,8 +48,6 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
@@ -78,8 +73,6 @@ import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiRequestPositionManager, PositionManagerEx() {
private val myTypeMappers = WeakHashMap<String, CachedValue<JetTypeMapper>>()
override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? {
return ThreeState.UNSURE
}
@@ -167,10 +160,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
if (literalsOrFunctions.isEmpty()) return null;
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
val typeMapper = if (!isInLibrary)
prepareTypeMapper(file)
else
createTypeMapperForLibraryFile(file.findElementAt(start), file)
val elementAt = file.findElementAt(start) ?: return null
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
for (literal in literalsOrFunctions) {
@@ -274,7 +265,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
val file = sourcePosition.file.containingFile as KtFile
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
lambdas.flatMap {
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(it, file)
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(it)
getInternalClassNameForElement(it, typeMapper, file, isInLibrary)
}
}
@@ -295,30 +286,14 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
element ->
val file = element.containingFile as KtFile
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(element, file)
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(element)
getInternalClassNameForElement(element, typeMapper, file, isInLibrary)
}
}
}
}
private fun prepareTypeMapper(file: KtFile): JetTypeMapper {
val key = createKeyForTypeMapper(file)
var value: CachedValue<JetTypeMapper>? = myTypeMappers.get(key)
if (value == null) {
value = CachedValuesManager.getManager(file.project).createCachedValue<JetTypeMapper>(
{
val typeMapper = createTypeMapper(file)
CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT)
}, false)
myTypeMappers.put(key, value)
}
return value.value
}
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
if (position.file !is KtFile) {
throw NoDataException.INSTANCE
@@ -352,13 +327,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
}
}
@TestOnly fun addTypeMapper(file: KtFile, typeMapper: JetTypeMapper) {
val value = CachedValuesManager.getManager(file.project).createCachedValue<JetTypeMapper>(
{ CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) }, false)
val key = createKeyForTypeMapper(file)
myTypeMappers.put(key, value)
}
private fun getInternalClassNameForElement(
notPositionedElement: PsiElement?,
typeMapper: JetTypeMapper,
@@ -458,9 +426,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
element is KtPropertyAccessor ||
PsiTreeUtil.getParentOfType(element, KtProperty::class.java, KtPropertyAccessor::class.java) is KtPropertyAccessor
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =
if (element is KtElement) element else PsiTreeUtil.getParentOfType(element, KtElement::class.java)
private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, ktClass: KtClassOrObject): String? {
val classDescriptor = typeMapper.bindingContext.get<PsiElement, ClassDescriptor>(BindingContext.CLASS, ktClass) ?: return null
@@ -471,22 +436,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
return typeMapper.mapClass(classDescriptor).internalName
}
private fun createTypeMapperForLibraryFile(notPositionedElement: PsiElement?, file: KtFile): JetTypeMapper {
val element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement)
val analysisResult = element!!.analyzeAndGetResult()
val state = GenerationState(file.project, ClassBuilderFactories.THROW_EXCEPTION,
analysisResult.moduleDescriptor, analysisResult.bindingContext, listOf(file))
state.beforeCompile()
return state.typeMapper
}
fun isInlinedLambda(functionLiteral: KtFunction, context: BindingContext): Boolean {
return InlineUtil.isInlinedArgument(functionLiteral, context, false)
}
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Set<String> {
return runReadAction {
val result = hashSetOf<String>()
@@ -589,22 +538,4 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
private fun String?.toSet() = if (this == null) emptySet() else setOf(this)
companion object {
fun createTypeMapper(file: KtFile): JetTypeMapper {
val project = file.project
val analysisResult = file.analyzeFullyAndGetResult()
analysisResult.throwIfError()
val state = GenerationState(
project,
ClassBuilderFactories.THROW_EXCEPTION,
analysisResult.moduleDescriptor,
analysisResult.bindingContext,
listOf(file))
state.beforeCompile()
return state.typeMapper
}
}
}
@@ -18,10 +18,22 @@ package org.jetbrains.kotlin.idea.debugger
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.LibraryUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import java.util.*
class KotlinPositionManagerCache(private val project: Project) {
@@ -32,6 +44,12 @@ class KotlinPositionManagerCache(private val project: Project) {
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<String, JetTypeMapper>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
companion object {
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> {
val cache = getInstance(psiElement.project)
@@ -48,6 +66,68 @@ class KotlinPositionManagerCache(private val project: Project) {
}
}
fun getOrCreateTypeMapper(psiElement: PsiElement): JetTypeMapper {
val cache = getInstance(psiElement.project)
synchronized(cache.cachedTypeMappers) {
val typeMappersCache = cache.cachedTypeMappers.value
val file = psiElement.containingFile as KtFile
val key = createKeyForTypeMapper(file)
val cachedValue = typeMappersCache[key]
if (cachedValue != null) return cachedValue
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
if (!isInLibrary) {
val newValue = createTypeMapperForSourceFile(file)
typeMappersCache[key] = newValue
return newValue
}
else {
return createTypeMapperForLibraryFile(psiElement, file)
}
}
}
private fun getInstance(project: Project) = ServiceManager.getService(project, KotlinPositionManagerCache::class.java)!!
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
private fun createTypeMapperForLibraryFile(notPositionedElement: PsiElement?, file: KtFile): JetTypeMapper {
val element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement)
val analysisResult = element.analyzeAndGetResult()
val state = GenerationState(
file.project,
ClassBuilderFactories.THROW_EXCEPTION,
analysisResult.moduleDescriptor,
analysisResult.bindingContext,
listOf(file))
state.beforeCompile()
return state.typeMapper
}
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =
if (element is KtElement) element else PsiTreeUtil.getParentOfType(element, KtElement::class.java)!!
private fun createTypeMapperForSourceFile(file: KtFile): JetTypeMapper {
val analysisResult = file.analyzeFullyAndGetResult()
analysisResult.throwIfError()
val state = GenerationState(
file.project,
ClassBuilderFactories.THROW_EXCEPTION,
analysisResult.moduleDescriptor,
analysisResult.bindingContext,
listOf(file))
state.beforeCompile()
return state.typeMapper
}
@TestOnly fun addTypeMapper(file: KtFile, typeMapper: JetTypeMapper) {
val cache = getInstance(file.project)
val key = createKeyForTypeMapper(file)
cache.cachedTypeMappers.value[key] = typeMapper
}
}
}
@@ -41,7 +41,7 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug
}
private fun lambdaOrdinalIndex(elementAt: KtFunction): Int {
val typeMapper = KotlinPositionManager.createTypeMapper(elementAt.getContainingKtFile())
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt)
return type.className.substringAfterLast("$").toInt()
@@ -93,7 +93,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight
assertNotNull(positionManager);
for (KtFile file : files) {
positionManager.addTypeMapper(file, state.getTypeMapper());
KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper());
}
return positionManager;