From 25e1fb85021f95d54e39269aeaa6a7cebfd3d404 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 24 Apr 2020 11:47:13 +0200 Subject: [PATCH] JVM: map synthetic line numbers through the SMAP This is necessary so that IDEA does not ignore the line number. --- .../kotlin/codegen/inline/MethodInliner.kt | 2 +- .../jetbrains/kotlin/codegen/inline/SMAP.kt | 22 +++++++++++++------ .../codegen/inline/inlineCodegenUtils.kt | 4 ++-- .../smap/inlineOnly/stdlibInlineOnly.kt | 2 ++ .../inlineOnly/stdlibInlineOnlyOneLine.kt | 14 ++++++++++++ .../lineNumbers/stdlibInlineOnly.kt | 15 ------------- .../lineNumbers/stdlibInlineOnlyOneLine.kt | 11 ---------- .../debug/stepping/voidLambdaStepInline.kt | 2 ++ .../codegen/BytecodeTextTestGenerated.java | 10 --------- .../ir/IrBytecodeTextTestGenerated.java | 10 --------- 10 files changed, 36 insertions(+), 56 deletions(-) delete mode 100644 compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt delete mode 100644 compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 3a16cb8a5a2..efcde89170e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -278,7 +278,7 @@ class MethodInliner( visitInsn(Opcodes.NOP) } - inlineOnlySmapSkipper?.onInlineLambdaStart(remappingMethodAdapter, info) + inlineOnlySmapSkipper?.onInlineLambdaStart(remappingMethodAdapter, info, sourceMapper.parent) addInlineMarker(this, true) val lambdaParameters = info.addAllParameters(nodeRemapper) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt index c54bc69c99d..62ca36aa424 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt @@ -62,19 +62,22 @@ class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, val call private var lastVisitedRange: RangeMapping? = null fun mapLineNumber(lineNumber: Int): Int { - if (lineNumber in JvmAbi.SYNTHETIC_MARKER_LINE_NUMBERS) { - return lineNumber - } - val mappedLineNumber = visitedLines.get(lineNumber) if (mappedLineNumber > 0) { return mappedLineNumber } - val range = lastVisitedRange?.takeIf { lineNumber in it } ?: smap.findRange(lineNumber) ?: return -1 - val newLineNumber = parent.mapLineNumber(range.mapDestToSource(lineNumber), callSite ?: range.callSite) + val newLineNumber = if (lineNumber in JvmAbi.SYNTHETIC_MARKER_LINE_NUMBERS) { + // This is a compatibility hack for reading bytecode generated by 1.4-M1. Once the bootstrap + // compiler is updated to a newer version, it can be removed (as newer bytecode explicitly lists + // this range in the SMAP). + parent.mapSyntheticLineNumber(lineNumber) + } else { + val range = lastVisitedRange?.takeIf { lineNumber in it } ?: smap.findRange(lineNumber) ?: return -1 + lastVisitedRange = range + parent.mapLineNumber(range.mapDestToSource(lineNumber), callSite ?: range.callSite) + } visitedLines.put(lineNumber, newLineNumber) - lastVisitedRange = range return newLineNumber } } @@ -107,6 +110,11 @@ class SourceMapper(val sourceInfo: SourceInfo?) { maxUsedValue = max(maxUsedValue, mappedLineIndex) return mappedLineIndex } + + fun mapSyntheticLineNumber(id: Int): Int { + assert(id in JvmAbi.SYNTHETIC_MARKER_LINE_NUMBERS) { "$id is not a synthetic line number" } + return mapLineNumber(SourcePosition(id, "fake.kt", "kotlin/jvm/internal/FakeKt"), null) + } } class SMAP(val fileMappings: List) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 374079ed483..ad1edfde591 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -541,7 +541,7 @@ internal fun isThis0(name: String): Boolean = AsmUtil.CAPTURED_THIS_FIELD == nam class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) { private val callLineNumber = codegen.lastLineNumber - fun onInlineLambdaStart(mv: MethodVisitor, info: LambdaInfo) { + fun onInlineLambdaStart(mv: MethodVisitor, info: LambdaInfo, smap: SourceMapper) { val firstLine = info.node.node.instructions.asSequence().mapNotNull { it as? LineNumberNode }.firstOrNull()?.line ?: -1 if (callLineNumber >= 0 && firstLine == callLineNumber) { // We want the debugger to be able to break both on the inline call itself, plus on each @@ -552,7 +552,7 @@ class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) { // number that is remapped by the SMAP to a line that does not exist. val label = Label() mv.visitLabel(label) - mv.visitLineNumber(JvmAbi.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER, label) + mv.visitLineNumber(smap.mapSyntheticLineNumber(JvmAbi.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER), label) } } diff --git a/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnly.kt b/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnly.kt index 64c53bd8bb0..476266b4e50 100644 --- a/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnly.kt +++ b/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnly.kt @@ -19,3 +19,5 @@ fun box(): String { } // FILE: 2.smap +// See KT-23064 for the problem, InlineOnlySmapSkipper for an explanation, and +// `stdlibInlineOnlyOneLine.kt` for the case where something should actually happen. diff --git a/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnlyOneLine.kt b/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnlyOneLine.kt index b6af5b5c9f7..245fe06fce7 100644 --- a/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnlyOneLine.kt +++ b/compiler/testData/codegen/boxInline/smap/inlineOnly/stdlibInlineOnlyOneLine.kt @@ -14,3 +14,17 @@ fun box(): String { } // FILE: 2.smap +// See KT-23064 for the problem and InlineOnlySmapSkipper for an explanation. +SMAP +2.kt +Kotlin +*S Kotlin +*F ++ 1 2.kt +_2Kt ++ 2 fake.kt +kotlin/jvm/internal/FakeKt +*L +1#1,9:1 +65100#2:10 +*E diff --git a/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt b/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt deleted file mode 100644 index 6084e5aaf54..00000000000 --- a/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt +++ /dev/null @@ -1,15 +0,0 @@ -@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") -@kotlin.internal.InlineOnly -inline fun T.myLet(block: (T) -> R) = block(this) - -fun box(): String { - val k = "".myLet { - it + "K" - } - return "O".myLet(fun (it: String): String { - return it + k - }) -} - -// See KT-23064 for the problem and InlineOnlySmapSkipper for an explanation. -// 0 LINENUMBER 65100 diff --git a/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt b/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt deleted file mode 100644 index 35358c61461..00000000000 --- a/compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt +++ /dev/null @@ -1,11 +0,0 @@ -@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") -@kotlin.internal.InlineOnly -inline fun T.myLet(block: (T) -> R) = block(this) - -fun box(): String { - val k = "".myLet { it + "K" } - return "O".myLet(fun (it: String): String { return it + k }) -} - -// See KT-23064 for the problem and InlineOnlySmapSkipper for an explanation. -// 2 LINENUMBER 65100 diff --git a/compiler/testData/debug/stepping/voidLambdaStepInline.kt b/compiler/testData/debug/stepping/voidLambdaStepInline.kt index d03d8235f44..2a350c003a2 100644 --- a/compiler/testData/debug/stepping/voidLambdaStepInline.kt +++ b/compiler/testData/debug/stepping/voidLambdaStepInline.kt @@ -10,6 +10,8 @@ fun box(): String { // LINENUMBERS // test.kt:4 +// fake.kt:65100 +// test.kt:4 // test.kt:5 // test.kt:6 // test.kt:5 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index ff7ff1bfab7..a85cbd64fce 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -3467,16 +3467,6 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/singleThen.kt"); } - @TestMetadata("stdlibInlineOnly.kt") - public void testStdlibInlineOnly() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt"); - } - - @TestMetadata("stdlibInlineOnlyOneLine.kt") - public void testStdlibInlineOnlyOneLine() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt"); - } - @TestMetadata("tryCatch.kt") public void testTryCatch() throws Exception { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryCatch.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index f893c315ddc..6c199b997ab 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -3552,16 +3552,6 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/singleThen.kt"); } - @TestMetadata("stdlibInlineOnly.kt") - public void testStdlibInlineOnly() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnly.kt"); - } - - @TestMetadata("stdlibInlineOnlyOneLine.kt") - public void testStdlibInlineOnlyOneLine() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/lineNumbers/stdlibInlineOnlyOneLine.kt"); - } - @TestMetadata("tryCatch.kt") public void testTryCatch() throws Exception { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/tryCatch.kt");