JVM: preserve call site markers when inlining lambdas

and default functions into their own stubs.

Fixes #KT-35006
This commit is contained in:
pyos
2020-03-25 16:41:47 +01:00
committed by max-kammerer
parent 9d21800d8f
commit e98bdc6f8e
18 changed files with 250 additions and 81 deletions
@@ -42,7 +42,7 @@ class InlineCodegenForDefaultBody(
val nodeAndSmap = InlineCodegen.createInlineMethodNode( val nodeAndSmap = InlineCodegen.createInlineMethodNode(
function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline
) )
val childSourceMapper = NestedSourceMapper(sourceMapper, nodeAndSmap.classSMAP) val childSourceMapper = NestedSourceMapper(sourceMapper, nodeAndSmap.classSMAP, sameFile = true)
val node = nodeAndSmap.node val node = nodeAndSmap.node
val transformedMethod = MethodNode( val transformedMethod = MethodNode(
@@ -285,10 +285,8 @@ class MethodInliner(
val childSourceMapper = val childSourceMapper =
if (inliningContext.classRegeneration && !inliningContext.isInliningLambda) if (inliningContext.classRegeneration && !inliningContext.isInliningLambda)
NestedSourceMapper(sourceMapper, lambdaSMAP) NestedSourceMapper(sourceMapper, lambdaSMAP)
else if (info is DefaultLambda)
NestedSourceMapper(sourceMapper.parent!!, lambdaSMAP)
else else
SameFileNestedSourceMapper(sourceMapper.parent!!, info.node.classSMAP) NestedSourceMapper(sourceMapper.parent!!, lambdaSMAP, sameFile = info !is DefaultLambda)
val inliner = MethodInliner( val inliner = MethodInliner(
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info), info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
@@ -85,8 +85,8 @@ class SMAPBuilder(
} }
} }
open class NestedSourceMapper( class NestedSourceMapper(
override val parent: SourceMapper, protected val smap: SMAP override val parent: SourceMapper, private val smap: SMAP, private val sameFile: Boolean = false
) : DefaultSourceMapper(smap.sourceInfo) { ) : DefaultSourceMapper(smap.sourceInfo) {
private val visitedLines = TIntIntHashMap() private val visitedLines = TIntIntHashMap()
@@ -98,32 +98,29 @@ open class NestedSourceMapper(
return lineNumber return lineNumber
} }
val mappedLineNumber = visitedLines.get(lineNumber) if (sameFile && lineNumber <= smap.sourceInfo.linesInFile) {
return if (mappedLineNumber > 0) {
mappedLineNumber
} else {
val rangeForMapping =
(if (lastVisitedRange?.contains(lineNumber) == true) lastVisitedRange!! else smap.findRange(lineNumber))
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}: ${sourceInfo.pathOrCleanFQN}")
val sourceLineNumber = rangeForMapping.mapDestToSource(lineNumber)
val newLineNumber = parent.mapLineNumber(sourceLineNumber, rangeForMapping.parent!!.name, rangeForMapping.parent!!.path)
if (newLineNumber > 0) {
visitedLines.put(lineNumber, newLineNumber)
}
lastVisitedRange = rangeForMapping
newLineNumber
}
}
}
open class SameFileNestedSourceMapper(parent: SourceMapper, smap: SMAP) : NestedSourceMapper(parent, smap) {
override fun mapLineNumber(lineNumber: Int): Int {
if (lineNumber <= smap.sourceInfo.linesInFile) {
// assuming the parent source mapper is for the same file, this line number does not need remapping // assuming the parent source mapper is for the same file, this line number does not need remapping
return lineNumber return lineNumber
} }
return super.mapLineNumber(lineNumber)
val mappedLineNumber = visitedLines.get(lineNumber)
if (mappedLineNumber > 0) {
return mappedLineNumber
}
val range = lastVisitedRange?.takeIf { lineNumber in it }
?: smap.findRange(lineNumber)
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}: ${sourceInfo.pathOrCleanFQN}")
val sourceLineNumber = range.mapDestToSource(lineNumber)
val newLineNumber = if (sameFile)
parent.mapLineNumber(sourceLineNumber, range.parent!!.name, range.parent!!.path, range.callSiteMarker)
else
parent.mapLineNumber(sourceLineNumber, range.parent!!.name, range.parent!!.path)
if (newLineNumber > 0) {
visitedLines.put(lineNumber, newLineNumber)
}
lastVisitedRange = range
return newLineNumber
} }
} }
@@ -132,13 +129,12 @@ interface SourceMapper {
val parent: SourceMapper? val parent: SourceMapper?
get() = null get() = null
fun mapLineNumber(lineNumber: Int): Int { fun mapLineNumber(lineNumber: Int): Int
throw UnsupportedOperationException("fail")
}
fun mapLineNumber(source: Int, sourceName: String, sourcePath: String): Int { fun mapLineNumber(source: Int, sourceName: String, sourcePath: String): Int =
throw UnsupportedOperationException("fail") mapLineNumber(source, sourceName, sourcePath, null)
}
fun mapLineNumber(source: Int, sourceName: String, sourcePath: String, callSiteMarker: CallSiteMarker?): Int
fun endMapping() { fun endMapping() {
} }
@@ -159,13 +155,12 @@ object IdenticalSourceMapper : SourceMapper {
override fun mapLineNumber(lineNumber: Int) = lineNumber override fun mapLineNumber(lineNumber: Int) = lineNumber
override fun mapLineNumber(source: Int, sourceName: String, sourcePath: String): Int { override fun mapLineNumber(source: Int, sourceName: String, sourcePath: String, callSiteMarker: CallSiteMarker?): Int =
throw UnsupportedOperationException( throw UnsupportedOperationException(
"IdenticalSourceMapper#mapLineNumber($source, $sourceName, $sourcePath)\n" "IdenticalSourceMapper#mapLineNumber($source, $sourceName, $sourcePath)\n"
+ "This mapper should not encounter a line number out of range of the current file.\n" + "This mapper should not encounter a line number out of range of the current file.\n"
+ "This indicates that SMAP generation is missed somewhere." + "This indicates that SMAP generation is missed somewhere."
) )
}
} }
data class CallSiteMarker(val lineNumber: Int) data class CallSiteMarker(val lineNumber: Int)
@@ -209,7 +204,10 @@ open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
return lineNumber return lineNumber
} }
override fun mapLineNumber(source: Int, sourceName: String, sourcePath: String): Int { override fun mapLineNumber(source: Int, sourceName: String, sourcePath: String): Int =
mapLineNumber(source, sourceName, sourcePath, callSiteMarker)
override fun mapLineNumber(source: Int, sourceName: String, sourcePath: String, callSiteMarker: CallSiteMarker?): Int {
if (source < 0) { if (source < 0) {
//no source information, so just skip this linenumber //no source information, so just skip this linenumber
return -1 return -1
@@ -0,0 +1,63 @@
// FILE: 1.kt
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
package test
inline fun inlineFun2(param: String): String {
return param
}
inline fun inlineFun(param: String = "OK"): String {
// The Kotlin stratum should only contain 1 out-of-range line, and
// KotlinDebug should point it to this line:
return inlineFun2(param)
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
// FILE: 1.smap
SMAP
1.kt
Kotlin
*S Kotlin
*F
+ 1 1.kt
test/_1Kt
*L
1#1,14:1
5#1:15
*E
*S KotlinDebug
*F
+ 1 1.kt
test/_1Kt
*L
11#1:15
*E
// FILE: 2.smap
SMAP
2.kt
Kotlin
*S Kotlin
*F
+ 1 2.kt
_2Kt
+ 2 1.kt
test/_1Kt
*L
1#1,8:1
8#2,4:9
5#2:13
*E
*S KotlinDebug
*F
+ 1 2.kt
_2Kt
*L
5#1,4:9
5#1:13
*E
@@ -102,7 +102,7 @@ test/_1Kt$lParams$1
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
5#1,5:11 6#1,5:11
5#1:17 6#1:17
5#1:16 6#1:16
*E *E
@@ -140,9 +140,9 @@ test/_1Kt$lParams$1
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
5#1:11 6#1:11
5#1,2:12 6#1,2:12
5#1:15 6#1:15
5#1:14 6#1:14
5#1:16 6#1:16
*E *E
@@ -128,9 +128,9 @@ test/_1Kt$lParams$1
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
5#1,5:11 6#1,5:11
5#1:17 6#1:17
5#1:16 6#1:16
*E *E
// FILE: 2.smap-separate-compilation // FILE: 2.smap-separate-compilation
@@ -156,9 +156,9 @@ test/_1Kt$lParams$1
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
5#1,5:11 6#1,5:11
5#1:17 6#1:17
5#1:16 6#1:16
*E *E
SMAP SMAP
@@ -90,6 +90,6 @@ test/_1Kt$lParams$1
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
5#1,5:11 6#1,5:11
5#1:16 6#1:16
*E *E
+44
View File
@@ -0,0 +1,44 @@
// FILE: 1.kt
package test
inline fun f() {}
inline fun g(x: () -> String) = x()
// FILE: 2.kt
import test.*
fun box(): String { // KotlinDebug:
return g { // 2.kt:N -> 2.kt:5
f() // 2.kt:N+1 -> 2.kt:6, NOT 2.kt:5
f() // 2.kt:N+2 -> 2.kt:7, NOT 2.kt:N+1 or 2.kt:5
"OK"
}
}
// FILE: 1.smap
// FILE: 2.smap
SMAP
2.kt
Kotlin
*S Kotlin
*F
+ 1 2.kt
_2Kt
+ 2 1.kt
test/_1Kt
*L
1#1,12:1
5#2:13
4#2:14
4#2:15
*E
*S KotlinDebug
*F
+ 1 2.kt
_2Kt
*L
5#1:13
6#1:14
7#1:15
*E
+30 -24
View File
@@ -80,36 +80,42 @@ _2Kt
builders/_1Kt builders/_1Kt
*L *L
1#1,25:1 1#1,25:1
7#1,3:36 7#1,3:33
10#1:41 10#1:38
11#1,2:45 11#1,2:42
13#1:48 13#1:45
15#1:50 15#1:47
19#2:26 19#2:26
7#2,9:27 7#2:27
19#2:39 15#2:28
7#2:40 11#2,3:29
15#2:42 8#2:32
11#2,2:43 19#2:36
13#2:47 7#2:37
8#2:49 15#2:39
11#2,2:40
13#2:44
8#2:46
*E *E
*S KotlinDebug *S KotlinDebug
*F *F
+ 1 2.kt + 1 2.kt
_2Kt _2Kt
*L *L
20#1,3:36 20#1,3:33
20#1:41 20#1:38
20#1,2:45 20#1,2:42
20#1:48 20#1:45
20#1:50
9#1:26
9#1,9:27
20#1:39
20#1:40
20#1:42
20#1,2:43
20#1:47 20#1:47
20#1:49 9#1:26
9#1:27
10#1:28
10#1,3:29
9#1:32
20#1:36
20#1:37
20#1:39
20#1,2:40
20#1:44
20#1:46
*E *E
@@ -8,5 +8,5 @@ fun foo(i: Int = 1) {
inline fun bar(i: Int = 1) { inline fun bar(i: Int = 1) {
} }
// IGNORE_BACKEND: JVM_IR
// 2 3 13 14 4 7 6 10 9 15 // 2 3 13 14 4 7 6 10 9 10
@@ -16,4 +16,4 @@ inline fun baz() {
fun nop() {} fun nop() {}
// 2 20 21 3 4 25 26 5 22 6 9 10 11 14 15 17 // 2 20 21 3 4 22 23 5 24 6 9 10 11 14 15 17
@@ -3280,6 +3280,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -3300,6 +3305,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");
@@ -3280,6 +3280,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -3300,6 +3305,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");
@@ -3280,6 +3280,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -3300,6 +3305,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");
@@ -3280,6 +3280,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -3300,6 +3305,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");
@@ -2895,6 +2895,11 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -2915,6 +2920,11 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");
@@ -2895,6 +2895,11 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt"); runTest("compiler/testData/codegen/boxInline/smap/defaultFunction.kt");
} }
@TestMetadata("defaultFunctionWithInlineCall.kt")
public void testDefaultFunctionWithInlineCall() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/defaultFunctionWithInlineCall.kt");
}
@TestMetadata("interleavedFiles.kt") @TestMetadata("interleavedFiles.kt")
public void testInterleavedFiles() throws Exception { public void testInterleavedFiles() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt"); runTest("compiler/testData/codegen/boxInline/smap/interleavedFiles.kt");
@@ -2915,6 +2920,11 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt"); runTest("compiler/testData/codegen/boxInline/smap/kt23369_3.kt");
} }
@TestMetadata("kt35006.kt")
public void testKt35006() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/kt35006.kt");
}
@TestMetadata("oneFile.kt") @TestMetadata("oneFile.kt")
public void testOneFile() throws Exception { public void testOneFile() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt"); runTest("compiler/testData/codegen/boxInline/smap/oneFile.kt");