From b9b3ed5a12a13f1852fd32ca5e3dce7995870e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 2 Feb 2023 16:47:59 +0100 Subject: [PATCH] Fix #15107: Avoid re-emitting a LineNumber after only LabelNodes. There was already some deduplication code to avoid consecutive `LineNumber` nodes. However, it can happen that `LabelNode`s appear in-between. In that case, we also want to deduplicate the `LineNumber`s, since labels do not actually contribute to the final bytecode. --- .../tools/backend/jvm/BCodeSkelBuilder.scala | 8 +++- .../backend/jvm/DottyBytecodeTests.scala | 2 - .../backend/jvm/InlineBytecodeTests.scala | 48 +++++++++---------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index 1885210a6687..b9f0d4ee302d 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -556,11 +556,17 @@ trait BCodeSkelBuilder extends BCodeHelpers { case _ => false } ) } def lineNumber(tree: Tree): Unit = { + @tailrec + def getNonLabelNode(a: asm.tree.AbstractInsnNode): asm.tree.AbstractInsnNode = a match { + case a: asm.tree.LabelNode => getNonLabelNode(a.getPrevious) + case _ => a + } + if (!emitLines || !tree.span.exists) return; val nr = ctx.source.offsetToLine(tree.span.point) + 1 if (nr != lastEmittedLineNr) { lastEmittedLineNr = nr - lastInsn match { + getNonLabelNode(lastInsn) match { case lnn: asm.tree.LineNumberNode => // overwrite previous landmark as no instructions have been emitted for it lnn.line = nr diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index 71bf530fcda5..ac4ba3ee0e75 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -1622,7 +1622,6 @@ class DottyBytecodeTests extends DottyBytecodeTest { val instructions = instructionsFromMethod(method).filter(_.isInstanceOf[LineNumber]) val expected = List( - LineNumber(2, Label(0)), LineNumber(3, Label(0)), LineNumber(4, Label(5)), // case y => LineNumber(5, Label(9)), @@ -1664,7 +1663,6 @@ class DottyBytecodeTests extends DottyBytecodeTest { val instructions = instructionsFromMethod(method).filter(_.isInstanceOf[LineNumber]) val expected = List( - LineNumber(2, Label(0)), LineNumber(3, Label(0)), LineNumber(4, Label(5)), // case a if a == 3 => LineNumber(5, Label(15)), diff --git a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala index 33e898718b33..d55d1343ea7e 100644 --- a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala @@ -163,28 +163,27 @@ class InlineBytecodeTests extends DottyBytecodeTest { val expected = List( Label(0), - LineNumber(6, Label(0)), LineNumber(3, Label(0)), VarOp(ALOAD, 0), Ldc(LDC, "tracking"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(6), - LineNumber(8, Label(6)), + Label(5), + LineNumber(8, Label(5)), VarOp(ALOAD, 0), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(11), - LineNumber(3, Label(11)), + Label(10), + LineNumber(3, Label(10)), VarOp(ALOAD, 0), Ldc(LDC, "tracking"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(16), - LineNumber(10, Label(16)), + Label(15), + LineNumber(10, Label(15)), VarOp(ALOAD, 0), Ldc(LDC, "inner"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), Op(RETURN), - Label(22) + Label(21) ) assert(instructions == expected, "`track` was not properly inlined in `main`\n" + diffInstructions(instructions, expected)) @@ -228,23 +227,22 @@ class InlineBytecodeTests extends DottyBytecodeTest { val expected = List( Label(0), - LineNumber(12, Label(0)), LineNumber(7, Label(0)), VarOp(ALOAD, 0), Ldc(LDC, "tracking"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(6), - LineNumber(3, Label(6)), + Label(5), + LineNumber(3, Label(5)), VarOp(ALOAD, 0), Ldc(LDC, "tracking2"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(11), - LineNumber(14, Label(11)), + Label(10), + LineNumber(14, Label(10)), VarOp(ALOAD, 0), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), Op(RETURN), - Label(17) + Label(16) ) assert(instructions == expected, "`track` was not properly inlined in `main`\n" + diffInstructions(instructions, expected)) @@ -288,23 +286,22 @@ class InlineBytecodeTests extends DottyBytecodeTest { val expected = List( Label(0), - LineNumber(12, Label(0)), LineNumber(3, Label(0)), VarOp(ALOAD, 0), Ldc(LDC, "tracking2"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(6), - LineNumber(8, Label(6)), + Label(5), + LineNumber(8, Label(5)), VarOp(ALOAD, 0), Ldc(LDC, "fgh"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(11), - LineNumber(14, Label(11)), + Label(10), + LineNumber(14, Label(10)), VarOp(ALOAD, 0), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), Op(RETURN), - Label(17) + Label(16) ) assert(instructions == expected, "`track` was not properly inlined in `main`\n" + diffInstructions(instructions, expected)) @@ -349,23 +346,22 @@ class InlineBytecodeTests extends DottyBytecodeTest { val expected = List( Label(0), - LineNumber(13, Label(0)), LineNumber(3, Label(0)), VarOp(ALOAD, 0), Ldc(LDC, "tracking2"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(6), - LineNumber(3, Label(6)), + Label(5), + LineNumber(3, Label(5)), VarOp(ALOAD, 0), Ldc(LDC, "tracking2"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), - Label(11), - LineNumber(15, Label(11)), + Label(10), + LineNumber(15, Label(10)), VarOp(ALOAD, 0), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "Foo", "foo", "(Ljava/lang/String;)V", false), Op(RETURN), - Label(17) + Label(16) ) assert(instructions == expected, "`track` was not properly inlined in `main`\n" + diffInstructions(instructions, expected))