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.PsiFile
import com.intellij.psi.impl.compiled.ClsFileImpl import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.search.searches.ReferencesSearch 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.util.ThreeState
import com.intellij.xdebugger.frame.XStackFrame import com.intellij.xdebugger.frame.XStackFrame
import com.sun.jdi.AbsentInformationException import com.sun.jdi.AbsentInformationException
import com.sun.jdi.Location import com.sun.jdi.Location
import com.sun.jdi.ReferenceType import com.sun.jdi.ReferenceType
import com.sun.jdi.request.ClassPrepareRequest 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.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil 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.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor 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.NoResolveFileClassesProvider
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses 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.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory 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() { 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? { override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? {
return ThreeState.UNSURE return ThreeState.UNSURE
} }
@@ -167,10 +160,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
if (literalsOrFunctions.isEmpty()) return null; if (literalsOrFunctions.isEmpty()) return null;
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
val typeMapper = if (!isInLibrary) val elementAt = file.findElementAt(start) ?: return null
prepareTypeMapper(file) val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
else
createTypeMapperForLibraryFile(file.findElementAt(start), file)
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
for (literal in literalsOrFunctions) { for (literal in literalsOrFunctions) {
@@ -274,7 +265,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
val file = sourcePosition.file.containingFile as KtFile val file = sourcePosition.file.containingFile as KtFile
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
lambdas.flatMap { lambdas.flatMap {
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(it, file) val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(it)
getInternalClassNameForElement(it, typeMapper, file, isInLibrary) getInternalClassNameForElement(it, typeMapper, file, isInLibrary)
} }
} }
@@ -295,30 +286,14 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
element -> element ->
val file = element.containingFile as KtFile val file = element.containingFile as KtFile
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null 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) 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> { override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
if (position.file !is KtFile) { if (position.file !is KtFile) {
throw NoDataException.INSTANCE 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( private fun getInternalClassNameForElement(
notPositionedElement: PsiElement?, notPositionedElement: PsiElement?,
typeMapper: JetTypeMapper, typeMapper: JetTypeMapper,
@@ -458,9 +426,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
element is KtPropertyAccessor || element is KtPropertyAccessor ||
PsiTreeUtil.getParentOfType(element, KtProperty::class.java, KtPropertyAccessor::class.java) 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? { private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, ktClass: KtClassOrObject): String? {
val classDescriptor = typeMapper.bindingContext.get<PsiElement, ClassDescriptor>(BindingContext.CLASS, ktClass) ?: return null 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 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> { private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Set<String> {
return runReadAction { return runReadAction {
val result = hashSetOf<String>() val result = hashSetOf<String>()
@@ -589,22 +538,4 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin") private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
private fun String?.toSet() = if (this == null) emptySet() else setOf(this) 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.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.LibraryUtil
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker 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.* import java.util.*
class KotlinPositionManagerCache(private val project: Project) { class KotlinPositionManagerCache(private val project: Project) {
@@ -32,6 +44,12 @@ class KotlinPositionManagerCache(private val project: Project) {
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false) }, false)
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<String, JetTypeMapper>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
companion object { companion object {
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> { fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> {
val cache = getInstance(psiElement.project) 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 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 { private fun lambdaOrdinalIndex(elementAt: KtFunction): Int {
val typeMapper = KotlinPositionManager.createTypeMapper(elementAt.getContainingKtFile()) val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt) val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt)
return type.className.substringAfterLast("$").toInt() return type.className.substringAfterLast("$").toInt()
@@ -93,7 +93,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight
assertNotNull(positionManager); assertNotNull(positionManager);
for (KtFile file : files) { for (KtFile file : files) {
positionManager.addTypeMapper(file, state.getTypeMapper()); KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper());
} }
return positionManager; return positionManager;