Skip to content

Commit

Permalink
Merge pull request scala#5563 from lrytz/sd259b
Browse files Browse the repository at this point in the history
Don't exclude super calls to trait methods from inlining
  • Loading branch information
retronym authored Nov 30, 2016
2 parents 50d46c1 + de25e86 commit d0da258
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
}

private def isTraitStaticSuperAccessorName(s: String) = s.endsWith("$")
private def traitStaticSuperAccessorName(s: String) = s + "$"

private def isTraitSuperAccessor(method: MethodNode, owner: ClassBType): Boolean = {
owner.isInterface == Right(true) && BytecodeUtils.isStaticMethod(method) && isTraitStaticSuperAccessorName(method.name)
}

private def findCall(method: MethodNode, such: MethodInsnNode => Boolean): Option[MethodInsnNode] = {
private def findSingleCall(method: MethodNode, such: MethodInsnNode => Boolean): Option[MethodInsnNode] = {
@tailrec def noMoreInvoke(insn: AbstractInsnNode): Boolean = {
insn == null || (!insn.isInstanceOf[MethodInsnNode] && noMoreInvoke(insn.getNext))
}
Expand All @@ -87,12 +88,15 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
find(method.instructions.getFirst)
}
private def superAccessorInvocation(method: MethodNode): Option[MethodInsnNode] =
findCall(method, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESTATIC && isTraitStaticSuperAccessorName(mi.name))
findSingleCall(method, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESTATIC && isTraitStaticSuperAccessorName(mi.name))

private def isMixinForwarder(method: MethodNode, owner: ClassBType): Boolean = {
owner.isInterface == Right(false) &&
!BytecodeUtils.isStaticMethod(method) &&
superAccessorInvocation(method).nonEmpty
(superAccessorInvocation(method) match {
case Some(mi) => mi.name == traitStaticSuperAccessorName(method.name)
case _ => false
})
}

private def isTraitSuperAccessorOrMixinForwarder(method: MethodNode, owner: ClassBType): Boolean = {
Expand Down Expand Up @@ -138,7 +142,7 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
if (isTraitSuperAccessor(callee.callee, callee.calleeDeclarationClass)) {
// scala-dev#259: when inlining a trait super accessor, also inline the callsite to the default method
val implName = callee.callee.name.dropRight(1)
findCall(callee.callee, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESPECIAL && mi.name == implName)
findSingleCall(callee.callee, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESPECIAL && mi.name == implName)
} else {
// scala-dev#259: when inlining a mixin forwarder, also inline the callsite to the static super accessor
superAccessorInvocation(callee.callee)
Expand Down
15 changes: 15 additions & 0 deletions test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1738,4 +1738,19 @@ class InlinerTest extends BytecodeTesting {
val List(a, c, t) = compile(code, allowMessage = _.msg contains warn)
assertInvoke(getMethod(c, "t"), "T", "m$")
}

@Test
def sd259d(): Unit = {
val code =
"""trait T {
| @inline final def m = 1
|}
|class C extends T {
| def t = super.m // inline call to T.m$ here, we're not in the mixin forwarder C.m
|}
""".stripMargin
val List(c, t) = compileClasses(code)
assertNoInvoke(getMethod(c, "t"))
assertInvoke(getMethod(c, "m"), "T", "m$")
}
}

0 comments on commit d0da258

Please sign in to comment.