Debugger: merge KotlinPositionManagerCache into KotlinDebuggerCaches

This commit is contained in:
Natalia Ukhorskaya
2016-01-25 15:25:45 +03:00
parent b5b2bbc9ab
commit 9b978377d0
6 changed files with 112 additions and 144 deletions
-3
View File
@@ -258,9 +258,6 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches" <projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/> serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerCache"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerCache"/>
<projectService serviceInterface="org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService" <projectService serviceInterface="org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService"
serviceImplementation="org.jetbrains.kotlin.idea.stubindex.resolve.PluginDeclarationProviderFactoryService"/> serviceImplementation="org.jetbrains.kotlin.idea.stubindex.resolve.PluginDeclarationProviderFactoryService"/>
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses
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
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
@@ -67,7 +68,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.toReadOnlyList
import java.util.* import java.util.*
import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
@@ -160,7 +160,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
if (literalsOrFunctions.isEmpty()) return null; if (literalsOrFunctions.isEmpty()) return null;
val elementAt = file.findElementAt(start) ?: return null val elementAt = file.findElementAt(start) ?: return null
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt) val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(elementAt)
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
for (literal in literalsOrFunctions) { for (literal in literalsOrFunctions) {
@@ -269,11 +269,11 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
emptyList() emptyList()
} }
else { else {
KotlinPositionManagerCache.getOrComputeClassNames(element) { KotlinDebuggerCaches.getOrComputeClassNames(element) {
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 = KotlinPositionManagerCache.getOrCreateTypeMapper(element) val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(element)
getInternalClassNameForElement(element, typeMapper, file, isInLibrary) getInternalClassNameForElement(element, typeMapper, file, isInLibrary)
} }
@@ -1,133 +0,0 @@
/*
* 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.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.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) {
private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<PsiElement, List<String>>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<PsiElement, JetTypeMapper>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
companion object {
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> List<String>): List<String> {
val cache = getInstance(psiElement.project)
synchronized(cache.cachedClassNames) {
val classNamesCache = cache.cachedClassNames.value
val cachedValue = classNamesCache[psiElement]
if (cachedValue != null) return cachedValue
val newValue = create(psiElement)
classNamesCache[psiElement] = newValue
return newValue
}
}
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 isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
if (!isInLibrary) {
// Key = file
val cachedValue = typeMappersCache[file]
if (cachedValue != null) return cachedValue
val newValue = createTypeMapperForSourceFile(file)
typeMappersCache[file] = newValue
return newValue
}
else {
// key = KtElement
val element = getElementToCreateTypeMapperForLibraryFile(psiElement)
val cachedValue = typeMappersCache[psiElement]
if (cachedValue != null) return cachedValue
val newValue = createTypeMapperForLibraryFile(element, file)
typeMappersCache[psiElement] = newValue
return newValue
}
}
}
private fun getInstance(project: Project) = ServiceManager.getService(project, KotlinPositionManagerCache::class.java)!!
private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): JetTypeMapper {
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) {
getInstance(file.project).cachedTypeMappers.value[file] = typeMapper
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.debugger.engine.DebugProcessImpl
import com.sun.jdi.* import com.sun.jdi.*
import com.sun.tools.jdi.LocalVariableImpl import com.sun.tools.jdi.LocalVariableImpl
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
@@ -41,7 +42,7 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug
} }
private fun lambdaOrdinalIndex(elementAt: KtFunction): Int { private fun lambdaOrdinalIndex(elementAt: KtFunction): Int {
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt) val typeMapper = KotlinDebuggerCaches.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()
@@ -20,15 +20,26 @@ import com.intellij.debugger.SourcePosition
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
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.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 com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
import org.apache.log4j.Logger import org.apache.log4j.Logger
import org.jetbrains.annotations.TestOnly
import org.jetbrains.eval4j.Value import org.jetbrains.eval4j.Value
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
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.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
@@ -41,6 +52,18 @@ class KotlinDebuggerCaches(private val project: Project) {
MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT) MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT)
}, false) }, false)
private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<PsiElement, List<String>>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result<HashMap<PsiElement, JetTypeMapper>>(
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
}, false)
companion object { companion object {
private val LOG = Logger.getLogger(KotlinDebuggerCaches::class.java)!! private val LOG = Logger.getLogger(KotlinDebuggerCaches::class.java)!!
@@ -70,6 +93,85 @@ class KotlinDebuggerCaches(private val project: Project) {
return@synchronized newCompiledData return@synchronized newCompiledData
} }
} }
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> List<String>): List<String> {
val cache = getInstance(psiElement.project)
synchronized(cache.cachedClassNames) {
val classNamesCache = cache.cachedClassNames.value
val cachedValue = classNamesCache[psiElement]
if (cachedValue != null) return cachedValue
val newValue = create(psiElement)
classNamesCache[psiElement] = newValue
return newValue
}
}
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 isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
if (!isInLibrary) {
// Key = file
val cachedValue = typeMappersCache[file]
if (cachedValue != null) return cachedValue
val newValue = createTypeMapperForSourceFile(file)
typeMappersCache[file] = newValue
return newValue
}
else {
// key = KtElement
val element = getElementToCreateTypeMapperForLibraryFile(psiElement)
val cachedValue = typeMappersCache[psiElement]
if (cachedValue != null) return cachedValue
val newValue = createTypeMapperForLibraryFile(element, file)
typeMappersCache[psiElement] = newValue
return newValue
}
}
}
private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): JetTypeMapper {
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) {
getInstance(file.project).cachedTypeMappers.value[file] = typeMapper
}
} }
private fun canBeEvaluatedInThisContext(compiledData: CompiledDataDescriptor, context: EvaluationContextImpl): Boolean { private fun canBeEvaluatedInThisContext(compiledData: CompiledDataDescriptor, context: EvaluationContextImpl): Boolean {
@@ -32,16 +32,17 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.LightProjectDescriptor;
import com.sun.jdi.Location; import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType; import com.sun.jdi.ReferenceType;
import kotlin.sequences.SequencesKt;
import kotlin.text.StringsKt;
import kotlin.Unit; import kotlin.Unit;
import kotlin.io.FilesKt; import kotlin.io.FilesKt;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
import kotlin.sequences.SequencesKt;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection; import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches;
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider; import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase; import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor;
@@ -93,7 +94,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight
assertNotNull(positionManager); assertNotNull(positionManager);
for (KtFile file : files) { for (KtFile file : files) {
KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper()); KotlinDebuggerCaches.Companion.addTypeMapper(file, state.getTypeMapper());
} }
return positionManager; return positionManager;