diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-11-29 14:00:46 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-11-29 14:46:07 +0100 |
commit | de25e861249826658663a6d40f13b9b91d1146fc (patch) | |
tree | 96ef6ae3a85ab104ec964aa294139e1849c04704 /src/compiler/scala | |
parent | b02e3914b6dee6b7da1c3da1864343ccdce5ca3c (diff) | |
download | scala-de25e861249826658663a6d40f13b9b91d1146fc.tar.gz scala-de25e861249826658663a6d40f13b9b91d1146fc.tar.bz2 scala-de25e861249826658663a6d40f13b9b91d1146fc.zip |
Don't exclude super calls to trait methods from inlining
In 8020cd6, the inliner was changed to make sure trait methods bodies
are not duplicated into the static super accessors, and from there into
mixin forwarders.
The check for mixin forwarders was too wide. In `def t = super.m`, where
`m` is a trait method annotated `@inline`, we want to inline `m`. Note
that `super.m` is translated to an `invokestatic T.m$`. The current
check incorrectly identifies `t` as a mixin forwarder, and skip
inlining.
Diffstat (limited to 'src/compiler/scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala | 12 |
1 files changed, 8 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) |