JVM: treat empty SMAP instances as "skip all line numbers"
This commit is contained in:
+1
-1
@@ -118,7 +118,7 @@ class AnonymousObjectTransformer(
|
|||||||
// save time. The result is effectively the same anyway.
|
// save time. The result is effectively the same anyway.
|
||||||
val debugInfoToParse = if (inliningContext.isInliningLambda) null else debugInfo
|
val debugInfoToParse = if (inliningContext.isInliningLambda) null else debugInfo
|
||||||
sourceMap = SMAPParser.parseOrCreateDefault(debugInfoToParse, sourceInfo, oldObjectType.internalName, 1, 65535)
|
sourceMap = SMAPParser.parseOrCreateDefault(debugInfoToParse, sourceInfo, oldObjectType.internalName, 1, 65535)
|
||||||
sourceMapper = SourceMapper(sourceMap.sourceInfo.takeIf { debugInfoToParse?.isEmpty() == false })
|
sourceMapper = SourceMapper(sourceMap.fileMappings.firstOrNull { it.name == sourceInfo }?.toSourceInfo())
|
||||||
|
|
||||||
val allCapturedParamBuilder = ParametersBuilder.newBuilder()
|
val allCapturedParamBuilder = ParametersBuilder.newBuilder()
|
||||||
val constructorParamBuilder = ParametersBuilder.newBuilder()
|
val constructorParamBuilder = ParametersBuilder.newBuilder()
|
||||||
|
|||||||
@@ -614,7 +614,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
callableDescriptor.name.asString() == "arrayOf" -> IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
|
callableDescriptor.name.asString() == "arrayOf" -> IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
|
||||||
else -> throw UnsupportedOperationException("Not an array intrinsic: $callableDescriptor")
|
else -> throw UnsupportedOperationException("Not an array intrinsic: $callableDescriptor")
|
||||||
}
|
}
|
||||||
return SMAPAndMethodNode(body, SMAP(listOf(FileMapping.SKIP)))
|
return SMAPAndMethodNode(body, SMAP(listOf()))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(callableDescriptor is DescriptorWithContainerSource) { "Not a deserialized function or proper: $callableDescriptor" }
|
assert(callableDescriptor is DescriptorWithContainerSource) { "Not a deserialized function or proper: $callableDescriptor" }
|
||||||
|
|||||||
@@ -17,13 +17,12 @@ const val KOTLIN_DEBUG_STRATA_NAME = "KotlinDebug"
|
|||||||
|
|
||||||
object SMAPBuilder {
|
object SMAPBuilder {
|
||||||
fun build(fileMappings: List<FileMapping>, backwardsCompatibleSyntax: Boolean): String? {
|
fun build(fileMappings: List<FileMapping>, backwardsCompatibleSyntax: Boolean): String? {
|
||||||
val realMappings = fileMappings.filter { it.lineMappings.isNotEmpty() && it != FileMapping.SKIP }
|
if (fileMappings.isEmpty()) {
|
||||||
if (realMappings.isEmpty()) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val debugMappings = linkedMapOf<Pair<String, String>, FileMapping>()
|
val debugMappings = linkedMapOf<Pair<String, String>, FileMapping>()
|
||||||
for (fileMapping in realMappings) {
|
for (fileMapping in fileMappings) {
|
||||||
for ((_, dest, range, callSite) in fileMapping.lineMappings) {
|
for ((_, dest, range, callSite) in fileMapping.lineMappings) {
|
||||||
callSite?.let { (line, file, path) ->
|
callSite?.let { (line, file, path) ->
|
||||||
debugMappings.getOrPut(file to path) { FileMapping(file, path) }.mapNewInterval(line, dest, range)
|
debugMappings.getOrPut(file to path) { FileMapping(file, path) }.mapNewInterval(line, dest, range)
|
||||||
@@ -35,7 +34,7 @@ object SMAPBuilder {
|
|||||||
// 1. they require *E between strata, which is not correct syntax according to JSR-045;
|
// 1. they require *E between strata, which is not correct syntax according to JSR-045;
|
||||||
// 2. in KotlinDebug, they use `1#2,3:4` to mean "map lines 4..6 to line 1 of #2", when in reality (and in
|
// 2. in KotlinDebug, they use `1#2,3:4` to mean "map lines 4..6 to line 1 of #2", when in reality (and in
|
||||||
// the non-debug stratum) this maps lines 4..6 to lines 1..3. The correct syntax is `1#2:4,3`.
|
// the non-debug stratum) this maps lines 4..6 to lines 1..3. The correct syntax is `1#2:4,3`.
|
||||||
val defaultStrata = realMappings.toSMAP(KOTLIN_STRATA_NAME, mapToFirstLine = false)
|
val defaultStrata = fileMappings.toSMAP(KOTLIN_STRATA_NAME, mapToFirstLine = false)
|
||||||
val debugStrata = debugMappings.values.toSMAP(KOTLIN_DEBUG_STRATA_NAME, mapToFirstLine = !backwardsCompatibleSyntax)
|
val debugStrata = debugMappings.values.toSMAP(KOTLIN_DEBUG_STRATA_NAME, mapToFirstLine = !backwardsCompatibleSyntax)
|
||||||
if (backwardsCompatibleSyntax && defaultStrata.isNotEmpty() && debugStrata.isNotEmpty()) {
|
if (backwardsCompatibleSyntax && defaultStrata.isNotEmpty() && debugStrata.isNotEmpty()) {
|
||||||
return "SMAP\n${fileMappings[0].name}\n$KOTLIN_STRATA_NAME\n$defaultStrata${SMAP.END}\n$debugStrata${SMAP.END}\n"
|
return "SMAP\n${fileMappings[0].name}\n$KOTLIN_STRATA_NAME\n$defaultStrata${SMAP.END}\n$debugStrata${SMAP.END}\n"
|
||||||
@@ -72,14 +71,8 @@ class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, val call
|
|||||||
return mappedLineNumber
|
return mappedLineNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
val range = lastVisitedRange?.takeIf { lineNumber in it }
|
val range = lastVisitedRange?.takeIf { lineNumber in it } ?: smap.findRange(lineNumber) ?: return -1
|
||||||
?: smap.findRange(lineNumber)
|
val newLineNumber = parent.mapLineNumber(range.mapDestToSource(lineNumber), callSite ?: range.callSite)
|
||||||
?: error("Can't find range to map line $lineNumber in ${smap.sourceInfo.source}: ${smap.sourceInfo.pathOrCleanFQN}")
|
|
||||||
val inlineSource = range.mapDestToSource(lineNumber)
|
|
||||||
if (inlineSource.line < 0) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
val newLineNumber = parent.mapLineNumber(inlineSource, callSite ?: range.callSite)
|
|
||||||
visitedLines.put(lineNumber, newLineNumber)
|
visitedLines.put(lineNumber, newLineNumber)
|
||||||
lastVisitedRange = range
|
lastVisitedRange = range
|
||||||
return newLineNumber
|
return newLineNumber
|
||||||
@@ -113,13 +106,7 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FileMapping.toSourceInfo(): SourceInfo =
|
|
||||||
SourceInfo(name, path, lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) })
|
|
||||||
|
|
||||||
class SMAP(val fileMappings: List<FileMapping>) {
|
class SMAP(val fileMappings: List<FileMapping>) {
|
||||||
val sourceInfo: SourceInfo
|
|
||||||
get() = fileMappings.firstOrNull()?.toSourceInfo() ?: throw AssertionError("no files mapped")
|
|
||||||
|
|
||||||
// assuming disjoint line mappings (otherwise binary search can't be used anyway)
|
// assuming disjoint line mappings (otherwise binary search can't be used anyway)
|
||||||
private val intervals = fileMappings.flatMap { it.lineMappings }.sortedBy { it.dest }
|
private val intervals = fileMappings.flatMap { it.lineMappings }.sortedBy { it.dest }
|
||||||
|
|
||||||
@@ -141,6 +128,9 @@ data class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP)
|
|||||||
class FileMapping(val name: String, val path: String) {
|
class FileMapping(val name: String, val path: String) {
|
||||||
val lineMappings = arrayListOf<RangeMapping>()
|
val lineMappings = arrayListOf<RangeMapping>()
|
||||||
|
|
||||||
|
fun toSourceInfo(): SourceInfo =
|
||||||
|
SourceInfo(name, path, lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) })
|
||||||
|
|
||||||
fun mapNewLineNumber(source: Int, currentIndex: Int, callSite: SourcePosition?): Int {
|
fun mapNewLineNumber(source: Int, currentIndex: Int, callSite: SourcePosition?): Int {
|
||||||
// Save some space in the SMAP by reusing (or extending if it's the last one) the existing range.
|
// Save some space in the SMAP by reusing (or extending if it's the last one) the existing range.
|
||||||
// TODO some *other* range may already cover `source`; probably too slow to check them all though.
|
// TODO some *other* range may already cover `source`; probably too slow to check them all though.
|
||||||
@@ -157,28 +147,20 @@ class FileMapping(val name: String, val path: String) {
|
|||||||
|
|
||||||
fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping =
|
fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping =
|
||||||
RangeMapping(source, dest, range, callSite, parent = this).also { lineMappings.add(it) }
|
RangeMapping(source, dest, range, callSite, parent = this).also { lineMappings.add(it) }
|
||||||
|
|
||||||
companion object {
|
|
||||||
val SKIP = FileMapping("no-source-info", "no-source-info").apply {
|
|
||||||
mapNewInterval(-1, -1, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RangeMapping(val source: Int, val dest: Int, var range: Int, val callSite: SourcePosition?, val parent: FileMapping) {
|
data class RangeMapping(val source: Int, val dest: Int, var range: Int, val callSite: SourcePosition?, val parent: FileMapping) {
|
||||||
private val skip = source == -1 && dest == -1
|
|
||||||
|
|
||||||
operator fun contains(destLine: Int): Boolean =
|
operator fun contains(destLine: Int): Boolean =
|
||||||
skip || (dest <= destLine && destLine < dest + range)
|
dest <= destLine && destLine < dest + range
|
||||||
|
|
||||||
fun hasMappingForSource(sourceLine: Int): Boolean =
|
fun hasMappingForSource(sourceLine: Int): Boolean =
|
||||||
skip || (source <= sourceLine && sourceLine < source + range)
|
source <= sourceLine && sourceLine < source + range
|
||||||
|
|
||||||
fun mapDestToSource(destLine: Int): SourcePosition =
|
fun mapDestToSource(destLine: Int): SourcePosition =
|
||||||
SourcePosition(if (skip) -1 else source + (destLine - dest), parent.name, parent.path)
|
SourcePosition(source + (destLine - dest), parent.name, parent.path)
|
||||||
|
|
||||||
fun mapSourceToDest(sourceLine: Int): Int =
|
fun mapSourceToDest(sourceLine: Int): Int =
|
||||||
if (skip) -1 else dest + (sourceLine - source)
|
dest + (sourceLine - source)
|
||||||
}
|
}
|
||||||
|
|
||||||
val RangeMapping.toRange: IntRange
|
val RangeMapping.toRange: IntRange
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ object SMAPParser {
|
|||||||
parseOrNull(mappingInfo)?.let { return it }
|
parseOrNull(mappingInfo)?.let { return it }
|
||||||
}
|
}
|
||||||
if (source == null || source.isEmpty() || methodStartLine > methodEndLine) {
|
if (source == null || source.isEmpty() || methodStartLine > methodEndLine) {
|
||||||
return SMAP(listOf(FileMapping.SKIP))
|
return SMAP(listOf())
|
||||||
}
|
}
|
||||||
val mapping = FileMapping(source, path).apply {
|
val mapping = FileMapping(source, path).apply {
|
||||||
mapNewInterval(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1)
|
mapNewInterval(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1)
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ class FunctionCodegen(
|
|||||||
val notForInline = irFunction.suspendForInlineToOriginal()
|
val notForInline = irFunction.suspendForInlineToOriginal()
|
||||||
val smap = if (!context.state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) {
|
val smap = if (!context.state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) {
|
||||||
generateAnnotationDefaultValueIfNeeded(methodVisitor)
|
generateAnnotationDefaultValueIfNeeded(methodVisitor)
|
||||||
SMAP(listOf(FileMapping.SKIP))
|
SMAP(listOf())
|
||||||
} else if (notForInline != null) {
|
} else if (notForInline != null) {
|
||||||
val (originalNode, smap) = classCodegen.generateMethodNode(notForInline)
|
val (originalNode, smap) = classCodegen.generateMethodNode(notForInline)
|
||||||
originalNode.accept(MethodBodyVisitor(methodVisitor))
|
originalNode.accept(MethodBodyVisitor(methodVisitor))
|
||||||
|
|||||||
Reference in New Issue
Block a user