Skip to content

Commit f3cca47

Browse files
authored
Merge pull request #14878 from dotty-staging/tailrec-avoid-useless-reassignment-to-this
Two more small improvements to the codegen of tailrec methods
2 parents d673b97 + 18b3deb commit f3cca47

File tree

3 files changed

+60
-56
lines changed

3 files changed

+60
-56
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
113113
}
114114
}
115115

116-
def genThrow(expr: Tree): BType = {
116+
def genThrow(expr: Tree): Unit = {
117117
val thrownKind = tpeTK(expr)
118118
// `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable.
119119
// Similarly for scala.Nothing (again, as defined in src/libray-aux).
120120
assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(ThrowableReference))
121121
genLoad(expr, thrownKind)
122122
lineNumber(expr)
123123
emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level.
124-
125-
RT_NOTHING // always returns the same, the invoker should know :)
126124
}
127125

128126
/* Generate code for primitive arithmetic operations. */
@@ -319,13 +317,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
319317
generatedType = expectedType
320318

321319
case t @ WhileDo(_, _) =>
322-
generatedType = genWhileDo(t)
320+
generatedType = genWhileDo(t, expectedType)
323321

324322
case t @ Try(_, _, _) =>
325323
generatedType = genLoadTry(t)
326324

327325
case t: Apply if t.fun.symbol eq defn.throwMethod =>
328-
generatedType = genThrow(t.args.head)
326+
genThrow(t.args.head)
327+
generatedType = expectedType
329328

330329
case New(tpt) =>
331330
abort(s"Unexpected New(${tpt.tpe.showSummary()}/$tpt) reached GenBCode.\n" +
@@ -586,41 +585,47 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
586585
}
587586
} // end of genReturn()
588587

589-
def genWhileDo(tree: WhileDo): BType = tree match{
588+
def genWhileDo(tree: WhileDo, expectedType: BType): BType = tree match{
590589
case WhileDo(cond, body) =>
591590

592591
val isInfinite = cond == tpd.EmptyTree
593592

594-
val loop = new asm.Label
595-
markProgramPoint(loop)
596-
597-
if (isInfinite) {
598-
genLoad(body, UNIT)
599-
bc goTo loop
600-
RT_NOTHING
601-
} else {
602-
val hasBody = cond match {
603-
case Literal(value) if value.tag == UnitTag => false
604-
case _ => true
605-
}
606-
607-
if (hasBody) {
608-
val success = new asm.Label
609-
val failure = new asm.Label
610-
genCond(cond, success, failure, targetIfNoJump = success)
611-
markProgramPoint(success)
612-
genLoad(body, UNIT)
613-
bc goTo loop
614-
markProgramPoint(failure)
615-
} else {
616-
// this is the shape of do..while loops, so do something smart about them
617-
val failure = new asm.Label
618-
genCond(cond, loop, failure, targetIfNoJump = failure)
619-
markProgramPoint(failure)
620-
}
621-
593+
if isInfinite then
594+
body match
595+
case Labeled(bind, expr) if tpeTK(body) == UNIT =>
596+
// this is the shape of tailrec methods
597+
val loop = programPoint(bind.symbol)
598+
markProgramPoint(loop)
599+
genLoad(expr, UNIT)
600+
bc goTo loop
601+
case _ =>
602+
val loop = new asm.Label
603+
markProgramPoint(loop)
604+
genLoad(body, UNIT)
605+
bc goTo loop
606+
end match
607+
expectedType
608+
else
609+
body match
610+
case Literal(value) if value.tag == UnitTag =>
611+
// this is the shape of do..while loops
612+
val loop = new asm.Label
613+
markProgramPoint(loop)
614+
val exitLoop = new asm.Label
615+
genCond(cond, loop, exitLoop, targetIfNoJump = exitLoop)
616+
markProgramPoint(exitLoop)
617+
case _ =>
618+
val loop = new asm.Label
619+
val success = new asm.Label
620+
val failure = new asm.Label
621+
markProgramPoint(loop)
622+
genCond(cond, success, failure, targetIfNoJump = success)
623+
markProgramPoint(success)
624+
genLoad(body, UNIT)
625+
bc goTo loop
626+
markProgramPoint(failure)
627+
end match
622628
UNIT
623-
}
624629
}
625630

626631
def genTypeApply(t: TypeApply): BType = (t: @unchecked) match {

compiler/src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,13 @@ class TailRec extends MiniPhase {
349349
yield
350350
(getVarForRewrittenParam(param), arg)
351351

352-
val assignThisAndParamPairs =
353-
if (prefix eq EmptyTree) assignParamPairs
354-
else
355-
// TODO Opt: also avoid assigning `this` if the prefix is `this.`
352+
val assignThisAndParamPairs = prefix match
353+
case EmptyTree =>
354+
assignParamPairs
355+
case prefix: This if prefix.symbol == enclosingClass =>
356+
// Avoid assigning `this = this`
357+
assignParamPairs
358+
case _ =>
356359
(getVarForRewrittenThis(), noTailTransform(prefix)) :: assignParamPairs
357360

358361
val assignments = assignThisAndParamPairs match {

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

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ class TestBCode extends DottyBytecodeTest {
597597
val clsIn = dir.lookupName("Test.class", directory = false).input
598598
val clsNode = loadClassNode(clsIn)
599599
val method = getMethod(clsNode, "test")
600-
assertEquals(94, instructionsFromMethod(method).size)
600+
assertEquals(93, instructionsFromMethod(method).size)
601601
}
602602
}
603603

@@ -976,29 +976,25 @@ class TestBCode extends DottyBytecodeTest {
976976
Op(ICONST_0),
977977
Jump(IF_ICMPNE, Label(7)),
978978
VarOp(ILOAD, 2),
979-
Jump(GOTO, Label(26)),
979+
Jump(GOTO, Label(22)),
980980
Label(7),
981-
VarOp(ALOAD, 0),
982-
VarOp(ASTORE, 3),
983981
VarOp(ILOAD, 1),
984982
Op(ICONST_1),
985983
Op(ISUB),
986-
VarOp(ISTORE, 4),
984+
VarOp(ISTORE, 3),
987985
VarOp(ILOAD, 2),
988986
VarOp(ILOAD, 1),
989987
Op(IMUL),
990-
VarOp(ISTORE, 5),
991-
VarOp(ALOAD, 3),
992-
VarOp(ASTORE, 0),
993-
VarOp(ILOAD, 4),
988+
VarOp(ISTORE, 4),
989+
VarOp(ILOAD, 3),
994990
VarOp(ISTORE, 1),
995-
VarOp(ILOAD, 5),
991+
VarOp(ILOAD, 4),
996992
VarOp(ISTORE, 2),
997-
Jump(GOTO, Label(29)),
998-
Label(26),
999-
Op(IRETURN),
1000-
Label(29),
1001993
Jump(GOTO, Label(0)),
994+
Label(22),
995+
Op(IRETURN),
996+
Op(NOP),
997+
Op(NOP),
1002998
Op(NOP),
1003999
Op(ATHROW),
10041000
))
@@ -1032,12 +1028,12 @@ class TestBCode extends DottyBytecodeTest {
10321028
VarOp(ASTORE, 0),
10331029
VarOp(ILOAD, 4),
10341030
VarOp(ISTORE, 1),
1035-
Jump(GOTO, Label(29)),
1031+
Jump(GOTO, Label(0)),
10361032
Label(26),
10371033
Op(IRETURN),
1038-
Label(29),
1039-
Jump(GOTO, Label(0)),
10401034
Op(NOP),
1035+
Op(NOP),
1036+
Op(ATHROW),
10411037
Op(ATHROW),
10421038
))
10431039
}

0 commit comments

Comments
 (0)