Skip to content

Commit f0d913b

Browse files
committed
SI-8062 Fix inliner cycle with recursion, separate compilation
ICodeReaders, which decompiles JVM bytecode to ICode, was not setting the `recursive` attribute of `IMethod`. This meant that the inliner got into a cycle, repeatedly inlining the recursive call. The method name `filter` was needed to trigger this as the inliner heuristically treats that as a more attractive inlining candidate, based on `isMonadicMethod`. This commit: - refactors the checking / setting of `virtual` - adds this to ICodeReaders - tests the case involving `invokevirtual` I'm not sure how to setup a test that fails without the other changes to `ICodeReader` (for invokestatic and invokespecial).
1 parent 7e996c1 commit f0d913b

File tree

6 files changed

+20
-5
lines changed

6 files changed

+20
-5
lines changed

src/compiler/scala/tools/nsc/backend/icode/GenICode.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -954,10 +954,7 @@ abstract class GenICode extends SubComponent {
954954
case _ =>
955955
}
956956
ctx1.bb.emit(cm, tree.pos)
957-
958-
if (sym == ctx1.method.symbol) {
959-
ctx1.method.recursive = true
960-
}
957+
ctx1.method.updateRecursive(sym)
961958
generatedType =
962959
if (sym.isClassConstructor) UNIT
963960
else toTypeKind(sym.info.resultType);

src/compiler/scala/tools/nsc/backend/icode/Members.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ trait Members {
185185
this
186186
}
187187

188+
final def updateRecursive(called: Symbol): Unit = {
189+
recursive ||= (called == symbol)
190+
}
191+
188192
def addLocal(l: Local): Local = findOrElse(locals)(_ == l) { locals ::= l ; l }
189193

190194
def addParam(p: Local): Unit =

src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,23 +489,28 @@ abstract class ICodeReader extends ClassfileParser {
489489
case JVM.invokevirtual =>
490490
val m = pool.getMemberSymbol(in.nextChar, false); size += 2
491491
code.emit(CALL_METHOD(m, Dynamic))
492+
method.updateRecursive(m)
492493
case JVM.invokeinterface =>
493494
val m = pool.getMemberSymbol(in.nextChar, false); size += 4
494495
in.skip(2)
495496
code.emit(CALL_METHOD(m, Dynamic))
497+
// invokeinterface can't be recursive
496498
case JVM.invokespecial =>
497499
val m = pool.getMemberSymbol(in.nextChar, false); size += 2
498500
val style = if (m.name == nme.CONSTRUCTOR || m.isPrivate) Static(true)
499501
else SuperCall(m.owner.name);
500502
code.emit(CALL_METHOD(m, style))
503+
method.updateRecursive(m)
501504
case JVM.invokestatic =>
502505
val m = pool.getMemberSymbol(in.nextChar, true); size += 2
503506
if (isBox(m))
504507
code.emit(BOX(toTypeKind(m.info.paramTypes.head)))
505508
else if (isUnbox(m))
506509
code.emit(UNBOX(toTypeKind(m.info.resultType)))
507-
else
510+
else {
508511
code.emit(CALL_METHOD(m, Static(false)))
512+
method.updateRecursive(m)
513+
}
509514
case JVM.invokedynamic =>
510515
// TODO, this is just a place holder. A real implementation must parse the class constant entry
511516
debuglog("Found JVM invokedynamic instructionm, inserting place holder ICode INVOKE_DYNAMIC.")

test/files/pos/t8062.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-optimize

test/files/pos/t8062/A_1.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package warmup
2+
3+
object Warmup {
4+
def filter[A](p: Any => Boolean): Any = filter[Any](p)
5+
}

test/files/pos/t8062/B_2.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
warmup.Warmup.filter[Any](x => false)
3+
}

0 commit comments

Comments
 (0)