Skip to content

Commit 5256eb4

Browse files
committed
Add a bytecode test with the status quo of tailrec methods.
1 parent 2fa2663 commit 5256eb4

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTest.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ trait DottyBytecodeTest {
122122
def assertSameCode(method: MethodNode, expected: List[Instruction]): Unit =
123123
assertSameCode(instructionsFromMethod(method).dropNonOp, expected)
124124
def assertSameCode(actual: List[Instruction], expected: List[Instruction]): Unit = {
125-
assert(actual === expected, s"\nExpected: $expected\nActual : $actual")
125+
assert(actual === expected, "\n" + diffInstructions(actual, expected))
126126
}
127127

128128
def assertInvoke(m: MethodNode, receiver: String, method: String): Unit =
@@ -296,4 +296,3 @@ trait DottyBytecodeTest {
296296
object DottyBytecodeTest {
297297
extension [T](l: List[T]) def stringLines = l.mkString("\n")
298298
}
299-

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

+107
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,113 @@ class TestBCode extends DottyBytecodeTest {
946946
}
947947
}
948948

949+
@Test def i14773TailRecReuseParamSlots(): Unit = {
950+
val source =
951+
s"""class Foo {
952+
| @scala.annotation.tailrec // explicit @tailrec here
953+
| final def fact(n: Int, acc: Int): Int =
954+
| if n == 0 then acc
955+
| else fact(n - 1, acc * n)
956+
|}
957+
|
958+
|class IntList(head: Int, tail: IntList | Null) {
959+
| // implicit @tailrec
960+
| final def sum(acc: Int): Int =
961+
| val t = tail
962+
| if t == null then acc + head
963+
| else t.sum(acc + head)
964+
|}
965+
""".stripMargin
966+
967+
checkBCode(source) { dir =>
968+
// The mutable local vars for n and acc reuse the slots of the params n and acc
969+
970+
val fooClass = loadClassNode(dir.lookupName("Foo.class", directory = false).input)
971+
val factMeth = getMethod(fooClass, "fact")
972+
973+
assertSameCode(factMeth, List(
974+
VarOp(ALOAD, 0),
975+
VarOp(ASTORE, 3),
976+
VarOp(ILOAD, 2),
977+
VarOp(ISTORE, 4),
978+
VarOp(ILOAD, 1),
979+
VarOp(ISTORE, 5),
980+
Label(6),
981+
VarOp(ILOAD, 5),
982+
Op(ICONST_0),
983+
Jump(IF_ICMPNE, Label(13)),
984+
VarOp(ILOAD, 4),
985+
Jump(GOTO, Label(32)),
986+
Label(13),
987+
VarOp(ALOAD, 3),
988+
VarOp(ASTORE, 6),
989+
VarOp(ILOAD, 5),
990+
Op(ICONST_1),
991+
Op(ISUB),
992+
VarOp(ISTORE, 7),
993+
VarOp(ILOAD, 4),
994+
VarOp(ILOAD, 5),
995+
Op(IMUL),
996+
VarOp(ISTORE, 8),
997+
VarOp(ALOAD, 6),
998+
VarOp(ASTORE, 3),
999+
VarOp(ILOAD, 7),
1000+
VarOp(ISTORE, 5),
1001+
VarOp(ILOAD, 8),
1002+
VarOp(ISTORE, 4),
1003+
Jump(GOTO, Label(35)),
1004+
Label(32),
1005+
Op(IRETURN),
1006+
Label(35),
1007+
Jump(GOTO, Label(6)),
1008+
Op(ATHROW),
1009+
Op(ATHROW),
1010+
))
1011+
1012+
// The mutable local vars for this and acc reuse the slots of `this` and of the param acc
1013+
1014+
val intListClass = loadClassNode(dir.lookupName("IntList.class", directory = false).input)
1015+
val sumMeth = getMethod(intListClass, "sum")
1016+
1017+
assertSameCode(sumMeth, List(
1018+
VarOp(ALOAD, 0),
1019+
VarOp(ASTORE, 2),
1020+
VarOp(ILOAD, 1),
1021+
VarOp(ISTORE, 3),
1022+
Label(4),
1023+
VarOp(ALOAD, 2),
1024+
Field(GETFIELD, "IntList", "tail", "LIntList;"),
1025+
VarOp(ASTORE, 4),
1026+
VarOp(ALOAD, 4),
1027+
Jump(IFNONNULL, Label(16)),
1028+
VarOp(ILOAD, 3),
1029+
VarOp(ALOAD, 2),
1030+
Field(GETFIELD, "IntList", "head", "I"),
1031+
Op(IADD),
1032+
Jump(GOTO, Label(30)),
1033+
Label(16),
1034+
VarOp(ALOAD, 4),
1035+
VarOp(ASTORE, 5),
1036+
VarOp(ILOAD, 3),
1037+
VarOp(ALOAD, 2),
1038+
Field(GETFIELD, "IntList", "head", "I"),
1039+
Op(IADD),
1040+
VarOp(ISTORE, 6),
1041+
VarOp(ALOAD, 5),
1042+
VarOp(ASTORE, 2),
1043+
VarOp(ILOAD, 6),
1044+
VarOp(ISTORE, 3),
1045+
Jump(GOTO, Label(33)),
1046+
Label(30),
1047+
Op(IRETURN),
1048+
Label(33),
1049+
Jump(GOTO, Label(4)),
1050+
Op(ATHROW),
1051+
Op(ATHROW),
1052+
))
1053+
}
1054+
}
1055+
9491056
@Test
9501057
def getClazz: Unit = {
9511058
val source = """

0 commit comments

Comments
 (0)