summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-11-30 14:44:35 +1000
committerGitHub <noreply@github.com>2016-11-30 14:44:35 +1000
commitd0da258116109272e5f76ea1722af5458bd588e3 (patch)
tree52f954103f891b0bcaf58f5503ba45f6a9148d89
parent50d46c12766228155a6d52cf7b33add4fa24a86e (diff)
parentde25e861249826658663a6d40f13b9b91d1146fc (diff)
downloadscala-d0da258116109272e5f76ea1722af5458bd588e3.tar.gz
scala-d0da258116109272e5f76ea1722af5458bd588e3.tar.bz2
scala-d0da258116109272e5f76ea1722af5458bd588e3.zip
Merge pull request #5563 from lrytz/sd259b
Don't exclude super calls to trait methods from inlining
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala12
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala15
2 files changed, 23 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
index 929e8b5ca4..4744cb9ab1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
@@ -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))
}
@@ -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 = {
@@ -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)
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 90a938be35..7be88816d5 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -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$")
+ }
}