JVM: parse KotlinDebug when regenerating anonymous objects

This commit is contained in:
pyos
2020-04-08 13:53:17 +02:00
committed by max-kammerer
parent 1fe7ef6521
commit 5feadd56ef
14 changed files with 167 additions and 158 deletions
@@ -20,6 +20,7 @@ import com.intellij.util.containers.ConcurrentFactoryMap
import com.sun.jdi.Location
import com.sun.jdi.ReferenceType
import com.sun.jdi.VirtualMachine
import org.jetbrains.kotlin.codegen.inline.SMAP
import org.jetbrains.kotlin.idea.caches.project.implementingModules
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.util.getLineCount
@@ -74,7 +75,7 @@ fun createWeakBytecodeDebugInfoStorage(): ConcurrentMap<BinaryCacheKey, Bytecode
}
}
class BytecodeDebugInfo(val smapData: SmapData?, val lineTableMapping: Map<BytecodeMethodKey, Map<String, Set<Int>>>)
class BytecodeDebugInfo(val smapData: SMAP?, val lineTableMapping: Map<BytecodeMethodKey, Map<String, Set<Int>>>)
data class BytecodeMethodKey(val methodName: String, val signature: String)
@@ -259,9 +260,7 @@ private fun inlinedLinesNumbers(
val debugInfo = readBytecodeInfo(project, jvmClassName, virtualFile) ?: return listOf()
val smapData = debugInfo.smapData ?: return listOf()
val smap = smapData.kotlinStrata ?: return listOf()
val mappingsToInlinedFile = smap.fileMappings.filter { it.name == inlineFileName }
val mappingsToInlinedFile = smapData.fileMappings.filter { it.name == inlineFileName }
val mappingIntervals = mappingsToInlinedFile.flatMap { it.lineMappings }
return mappingIntervals.asSequence().filter { rangeMapping -> rangeMapping.hasMappingForSource(inlineLineNumber) }
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.idea.debugger
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.codegen.inline.FileMapping
import org.jetbrains.kotlin.codegen.inline.SMAP
import org.jetbrains.kotlin.codegen.inline.SMAPParser
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.org.objectweb.asm.ClassReader
@@ -22,36 +20,27 @@ enum class SourceLineKind {
}
fun mapStacktraceLineToSource(
smapData: SmapData,
smapData: SMAP,
line: Int,
project: Project,
lineKind: SourceLineKind,
searchScope: GlobalSearchScope
): Pair<KtFile, Int>? {
val smap = when (lineKind) {
SourceLineKind.CALL_LINE -> smapData.kotlinDebugStrata
SourceLineKind.EXECUTED_LINE -> smapData.kotlinStrata
val interval = smapData.findRange(line) ?: return null
val location = when (lineKind) {
SourceLineKind.CALL_LINE -> interval.callSite
SourceLineKind.EXECUTED_LINE -> interval.mapDestToSource(line)
} ?: return null
val mappingInfo = smap.fileMappings.firstOrNull {
it.getIntervalIfContains(line) != null
} ?: return null
val jvmName = JvmClassName.byInternalName(mappingInfo.path)
val jvmName = JvmClassName.byInternalName(location.path)
val sourceFile = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(
project, searchScope, jvmName, mappingInfo.name
project, searchScope, jvmName, location.file
) ?: return null
val interval = mappingInfo.getIntervalIfContains(line)!!
val sourceLine = when (lineKind) {
SourceLineKind.CALL_LINE -> interval.source - 1
SourceLineKind.EXECUTED_LINE -> interval.mapDestToSource(line) - 1
}
return sourceFile to sourceLine
return sourceFile to location.line - 1
}
fun readDebugInfo(bytes: ByteArray): SmapData? {
fun readDebugInfo(bytes: ByteArray): SMAP? {
val cr = ClassReader(bytes)
var debugInfo: String? = null
cr.accept(object : ClassVisitor(Opcodes.API_VERSION) {
@@ -59,30 +48,5 @@ fun readDebugInfo(bytes: ByteArray): SmapData? {
debugInfo = debug
}
}, ClassReader.SKIP_FRAMES and ClassReader.SKIP_CODE)
return debugInfo?.let(::SmapData)
return debugInfo?.let(SMAPParser::parseOrNull)
}
class SmapData(debugInfo: String) {
var kotlinStrata: SMAP?
var kotlinDebugStrata: SMAP?
init {
val intervals = debugInfo.split(SMAP.END).filter(String::isNotBlank)
when (intervals.count()) {
1 -> {
kotlinStrata = SMAPParser.parse(intervals[0] + SMAP.END)
kotlinDebugStrata = null
}
2 -> {
kotlinStrata = SMAPParser.parse(intervals[0] + SMAP.END)
kotlinDebugStrata = SMAPParser.parse(intervals[1] + SMAP.END)
}
else -> {
kotlinStrata = null
kotlinDebugStrata = null
}
}
}
}
private fun FileMapping.getIntervalIfContains(destLine: Int) = lineMappings.firstOrNull { it.contains(destLine) }