From c51c53750491036f2ba938bdca89665107ec21e2 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 24 Apr 2020 13:02:21 +0200 Subject: [PATCH] JVM: use precise line bounds when regenerating objects with no SMAPs --- .../inline/AnonymousObjectTransformer.kt | 3 +- .../codegen/inline/inlineCodegenUtils.kt | 33 ++++++++++--------- .../lineNumbers/inlineLambdaObjectInit.kt | 13 ++++++++ .../codegen/BytecodeTextTestGenerated.java | 5 +++ .../ir/IrBytecodeTextTestGenerated.java | 5 +++ 5 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index c29c1388f78..7b72275ddec 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -117,7 +117,8 @@ class AnonymousObjectTransformer( // When regenerating objects in inline lambdas, keep the old SMAP and don't remap the line numbers to // save time. The result is effectively the same anyway. val debugInfoToParse = if (inliningContext.isInliningLambda) null else debugInfo - sourceMap = SMAPParser.parseOrCreateDefault(debugInfoToParse, sourceInfo, oldObjectType.internalName, 1, 65535) + val (firstLine, lastLine) = (methodsToTransform + listOfNotNull(constructor)).lineNumberRange() + sourceMap = SMAPParser.parseOrCreateDefault(debugInfoToParse, sourceInfo, oldObjectType.internalName, firstLine, lastLine) sourceMapper = SourceMapper(sourceMap.fileMappings.firstOrNull { it.name == sourceInfo }?.toSourceInfo()) val allCapturedParamBuilder = ParametersBuilder.newBuilder() 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 d86f0e085fc..f8167fbf636 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -92,12 +92,8 @@ internal fun getMethodNode( val cr = ClassReader(classData) var node: MethodNode? = null val debugInfo = arrayOfNulls(2) - val lines = IntArray(2) - lines[0] = Integer.MAX_VALUE - lines[1] = Integer.MIN_VALUE cr.accept(object : ClassVisitor(Opcodes.API_VERSION) { - override fun visitSource(source: String?, debug: String?) { super.visitSource(source, debug) debugInfo[0] = source @@ -123,16 +119,8 @@ internal fun getMethodNode( node?.let { existing -> throw AssertionError("Can't find proper '$name' method for inline: ambiguity between '${existing.name + existing.desc}' and '${name + desc}'") } - - return object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) { - override fun visitLineNumber(line: Int, start: Label) { - super.visitLineNumber(line, start) - lines[0] = min(lines[0], line) - lines[1] = max(lines[1], line) - } - }.also { - node = it - } + node = MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) + return node!! } }, ClassReader.SKIP_FRAMES or if (GENERATE_SMAP) 0 else ClassReader.SKIP_DEBUG) @@ -140,10 +128,25 @@ internal fun getMethodNode( return null } - val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classType.internalName, lines[0], lines[1]) + val (first, last) = listOfNotNull(node).lineNumberRange() + val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classType.internalName, first, last) return SMAPAndMethodNode(node!!, smap) } +internal fun Collection.lineNumberRange(): Pair { + var minLine = Int.MAX_VALUE + var maxLine = Int.MIN_VALUE + for (node in this) { + for (insn in node.instructions.asSequence()) { + if (insn is LineNumberNode) { + minLine = min(minLine, insn.line) + maxLine = max(maxLine, insn.line) + } + } + } + return minLine to maxLine +} + internal fun findVirtualFile(state: GenerationState, classId: ClassId): VirtualFile? { return VirtualFileFinder.getInstance(state.project, state.module).findVirtualFileWithHeader(classId) } diff --git a/compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt b/compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt new file mode 100644 index 00000000000..e9353bec4ff --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt @@ -0,0 +1,13 @@ +fun box(): String { + var result = "" + run { + object { + init { + result = "OK" + } + } + } + return result +} + +// 1 LINENUMBER 6 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index e9886816e21..b7026364ddb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -3452,6 +3452,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/inlineCondition2.kt"); } + @TestMetadata("inlineLambdaObjectInit.kt") + public void testInlineLambdaObjectInit() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt"); + } + @TestMetadata("singleThen.kt") public void testSingleThen() throws Exception { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/singleThen.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 3bdd692037e..85cb1961229 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -3537,6 +3537,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/inlineCondition2.kt"); } + @TestMetadata("inlineLambdaObjectInit.kt") + public void testInlineLambdaObjectInit() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/lineNumbers/inlineLambdaObjectInit.kt"); + } + @TestMetadata("singleThen.kt") public void testSingleThen() throws Exception { runTest("compiler/testData/codegen/bytecodeText/lineNumbers/singleThen.kt");