summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala11
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala48
-rw-r--r--test/junit/scala/tools/testing/BytecodeTesting.scala2
3 files changed, 58 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index d18963ec8b..7b4cfe2a18 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -253,7 +253,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
def inlineCallsite(callsite: Callsite): Unit = {
import callsite.{callsiteClass, callsiteMethod, callsiteInstruction, receiverKnownNotNull, callsiteStackHeight}
val Right(callsiteCallee) = callsite.callee
- import callsiteCallee.{callee, calleeDeclarationClass}
+ import callsiteCallee.{callee, calleeDeclarationClass, sourceFilePath}
// Inlining requires the callee not to have unreachable code, the analyzer used below should not
// return any `null` frames. Note that inlining a method can create unreachable code. Example:
@@ -268,7 +268,14 @@ class Inliner[BT <: BTypes](val btypes: BT) {
// New labels for the cloned instructions
val labelsMap = cloneLabels(callee)
- val (clonedInstructions, instructionMap, hasSerializableClosureInstantiation) = cloneInstructions(callee, labelsMap, keepLineNumbers = callsiteClass == calleeDeclarationClass)
+ val sameSourceFile = sourceFilePath match {
+ case Some(calleeSource) => byteCodeRepository.compilingClasses.get(callsiteClass.internalName) match {
+ case Some((_, `calleeSource`)) => true
+ case _ => false
+ }
+ case _ => false
+ }
+ val (clonedInstructions, instructionMap, hasSerializableClosureInstantiation) = cloneInstructions(callee, labelsMap, keepLineNumbers = sameSourceFile)
// local vars in the callee are shifted by the number of locals at the callsite
val localVarShift = callsiteMethod.maxLocals
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 9b538573dc..9173a1d189 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -1526,4 +1526,52 @@ class InlinerTest extends BytecodeTesting {
val c :: _ = compileClassesSeparately(codes, extraArgs = compilerArgs)
assertInvoke(getMethod(c, "t"), "p1/Implicits$RichFunction1$", "toRx$extension")
}
+
+ @Test
+ def keepLineNumbersPerCompilationUnit(): Unit = {
+ val code1 =
+ """class A {
+ | def fx(): Unit = ()
+ | @inline final def ma = {
+ | fx()
+ | 1
+ | }
+ |}
+ """.stripMargin
+ val code2 =
+ """class B extends A {
+ | @inline final def mb = {
+ | fx()
+ | 1
+ | }
+ |}
+ |class C extends B {
+ | @inline final def mc = {
+ | fx()
+ | 1
+ | }
+ | def t1 = ma // no lines, not the same source file
+ | def t2 = mb // lines
+ | def t3 = mc // lines
+ |}
+ """.stripMargin
+ notPerRun.foreach(_.clear())
+ val run = compiler.newRun
+ run.compileSources(List(makeSourceFile(code1, "A.scala"), makeSourceFile(code2, "B.scala")))
+ val List(_, _, c) = readAsmClasses(getGeneratedClassfiles(global.settings.outputDirs.getSingleOutput.get))
+ def is(name: String) = getMethod(c, name).instructions.filterNot(_.isInstanceOf[FrameEntry])
+
+ assertSameCode(is("t1"), List(
+ Label(0), LineNumber(12, Label(0)),
+ VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "A", "fx", "()V", false),
+ Op(ICONST_1), Op(IRETURN), Label(6)))
+
+ assertSameCode(is("t2"), List(
+ Label(0), LineNumber(3, Label(0)), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "B", "fx", "()V", false),
+ Label(4), LineNumber(4, Label(4)), Op(ICONST_1), Op(IRETURN), Label(8)))
+
+ assertSameCode(is("t3"), List(
+ Label(0), LineNumber(9, Label(0)), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "fx", "()V", false),
+ Label(4), LineNumber(10, Label(4)), Op(ICONST_1), Op(IRETURN), Label(8)))
+ }
}
diff --git a/test/junit/scala/tools/testing/BytecodeTesting.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala
index 1a0c1e210a..4ddb6580df 100644
--- a/test/junit/scala/tools/testing/BytecodeTesting.scala
+++ b/test/junit/scala/tools/testing/BytecodeTesting.scala
@@ -29,7 +29,7 @@ class Compiler(val global: Global) {
global.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None))
}
- private def newRun: global.Run = {
+ def newRun: global.Run = {
global.reporter.reset()
resetOutput()
new global.Run()