Skip to content

Commit

Permalink
Merge pull request #8188 from lrytz/sd618
Browse files Browse the repository at this point in the history
 Inline calls to static trait super accessors if trait method is trivial
  • Loading branch information
lrytz committed Jul 2, 2019
2 parents 26f34d0 + 2d66bd0 commit e89bdde
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ intellij := {
}

def moduleDep(name: String, jars: Seq[File]) = {
val entries = jars.map(f => s""" <root url="jar://${f.toURI.getRawPath}!/" />""").mkString("\n")
val entries = jars.map(f => s""" <root url="jar://${f.toURI.getPath}!/" />""").mkString("\n")
s"""| <library name="$name-deps">
| <CLASSES>
|$entries
Expand All @@ -1166,7 +1166,7 @@ intellij := {
}

def starrDep(jars: Seq[File]) = {
val entries = jars.map(f => s""" <root url="file://${f.toURI.getRawPath}" />""").mkString("\n")
val entries = jars.map(f => s""" <root url="file://${f.toURI.getPath}" />""").mkString("\n")
s"""| <library name="starr" type="Scala">
| <properties>
| <option name="languageLevel" value="Scala_2_12" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,21 @@ abstract class InlinerHeuristics extends PerRunInit {
// inlined in turn (chosen by the same heuristic), or the code is rolled back. but we don't inline them just because
// they are forwarders.
val isTraitSuperAccessor = backendUtils.isTraitSuperAccessor(callee.callee, callee.calleeDeclarationClass)
if (isTraitSuperAccessor) null
if (isTraitSuperAccessor) {
// inline static trait super accessors if the corresponding trait method is a forwarder or trivial (scala-dev#618)
{
val css = callGraph.callsites(callee.callee)
if (css.sizeIs == 1) css.head._2 else null
} match {
case null => null
case traitMethodCallsite =>
val tmCallee = traitMethodCallsite.callee.get
val traitMethodForwarderKind = backendUtils.looksLikeForwarderOrFactoryOrTrivial(
tmCallee.callee, tmCallee.calleeDeclarationClass.internalName, allowPrivateCalls = false)
if (traitMethodForwarderKind > 0) GenericForwarder
else null
}
}
else {
val forwarderKind = backendUtils.looksLikeForwarderOrFactoryOrTrivial(callee.callee, callee.calleeDeclarationClass.internalName, allowPrivateCalls = false)
if (forwarderKind < 0)
Expand Down
29 changes: 27 additions & 2 deletions test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1642,8 +1642,8 @@ class InlinerTest extends BytecodeTesting {
assertInvoke(getMethod(c, "t5"), "T", "m3a") // could not inline
assertNoInvoke(getMethod(c, "t6")) // both forwarders inlined, closure eliminated

assertInvoke(getMethod(c, "t7"), "T", "m1a$")
assertInvoke(getMethod(c, "t8"), "T", "m1b$")
assertNoInvoke(getMethod(c, "t7"))
assertNoInvoke(getMethod(c, "t8"))

assertNoInvoke(getMethod(c, "t9"))
assertNoInvoke(getMethod(c, "t10"))
Expand Down Expand Up @@ -2208,4 +2208,29 @@ class InlinerTest extends BytecodeTesting {
}
assertEquals(List("A", "$anonfun$f$1"), args.head)
}

@Test
def sd618(): Unit = {
val code =
"""trait T {
| final def m1 = 1 // trivial
| final def m2 = p // forwarder
| @noinline def p = 42
|}
|
|object TT extends T // gets mixin forwarders m1 / m2 which call the static T.m1$ / T.m2$
|
|class C {
| def t1a(t: T) = t.m1 // inlined, so we get 1
| def t1b = TT.m1 // mixin forwarder is inlined, static forwarder then as well because the final method is trivial
| def t2a(t: T) = t.m2 // inlined, so we get T.p
| def t2b = TT.m2 // mixin forwarder is inlined, static forwarder then as well because the final method is forwarder
|}
""".stripMargin
val c :: _ = compileClasses(code)
assertNoInvoke(getMethod(c, "t1a"))
assertNoInvoke(getMethod(c, "t1b"))
assertInvoke(getMethod(c, "t2a"), "T", "p")
assertInvoke(getMethod(c, "t2b"), "T", "p")
}
}

0 comments on commit e89bdde

Please sign in to comment.