summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-09-17 20:15:36 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-09-18 10:32:28 +0200
commit41e5ef4396a1526cd8c58157912ffed830a96f1e (patch)
treed406ff22f3588ac9c47ff0067a002efa30ca5cef
parent59a5d3b8fd036d36afcf6349bc3cc527344981a1 (diff)
downloadscala-41e5ef4396a1526cd8c58157912ffed830a96f1e.tar.gz
scala-41e5ef4396a1526cd8c58157912ffed830a96f1e.tar.bz2
scala-41e5ef4396a1526cd8c58157912ffed830a96f1e.zip
First version of inliningh heuristics that prefer higher-order methos
When invoking a higher-order method and the value passed for the SAM type is either a function literal or a parameter of the callsite method, inline the higher-order method into the callee. This is a first version, the heuristics will be refined further.
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala12
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala4
-rw-r--r--test/files/run/mapConserve.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala33
4 files changed, 46 insertions, 5 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 cd10094204..e559b63c09 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
@@ -84,8 +84,16 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
if (callee.safeToInline && callee.annotatedInline) Some(InlineRequest(callsite, Nil))
else None
-// case "default" =>
-
+ case "default" =>
+ val callee = callsite.callee.get
+ if (callee.safeToInline && !callee.annotatedNoInline) {
+ val shouldInlineHO = callee.samParamTypes.nonEmpty && (callee.samParamTypes exists {
+ case (index, _) => callsite.argInfos.contains(index)
+ })
+
+ if (shouldInlineHO || callee.annotatedInline) Some(InlineRequest(callsite, Nil))
+ else None
+ } else None
}
/*
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index ea9ad1d909..74d152a4cf 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -276,8 +276,8 @@ trait ScalaSettings extends AbsScalaSettings
name = "-Yopt-inline-heuristics",
helpArg = "strategy",
descr = "Set the heuristics for inlining decisions.",
- choices = List("at-inline-annotated", "everything"),
- default = "at-inline-annotated")
+ choices = List("at-inline-annotated", "everything", "default"),
+ default = "default")
object YoptWarningsChoices extends MultiChoiceEnumeration {
val none = Choice("none" , "No optimizer warnings.")
diff --git a/test/files/run/mapConserve.scala b/test/files/run/mapConserve.scala
index c17754283a..95cad69954 100644
--- a/test/files/run/mapConserve.scala
+++ b/test/files/run/mapConserve.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with
+ * filter: inliner warning
*/
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
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 622715ab3a..8429a583b5 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -1101,4 +1101,37 @@ class InlinerTest extends ClearAfterClass {
assertInvoke(getSingleMethod(c, "g"), "C", "f") // g itself still has the call to f
assert(r.isEmpty, r)
}
+
+ /**
+ * NOTE: if this test fails for you when running within the IDE, it's probably because you're
+ * using 2.12.0-M2 for compilining within the IDE, which doesn't add SAM information to the
+ * InlineInfo attribute. So the InlineInfo in the classfile for Function1 doesn't say that
+ * it's a SAM type. The test passes when running with ant (which does a full bootstrap).
+ */
+ @Test
+ def inlineHigherOrder(): Unit = {
+ val code =
+ """class C {
+ | final def h(f: Int => Int): Int = f(0)
+ | def t1 = h(x => x + 1)
+ | def t2 = {
+ | val fun = (x: Int) => x + 1
+ | h(fun)
+ | }
+ | def t3(f: Int => Int) = h(f)
+ | def t4(f: Int => Int) = {
+ | val fun = f
+ | h(fun)
+ | }
+ | def t5 = h(Map(0 -> 10)) // not currently inlined
+ |}
+ """.stripMargin
+
+ val List(c) = compile(code)
+ assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1")
+ assertInvoke(getSingleMethod(c, "t2"), "C", "C$$$anonfun$2")
+ assertInvoke(getSingleMethod(c, "t3"), "scala/Function1", "apply$mcII$sp")
+ assertInvoke(getSingleMethod(c, "t4"), "scala/Function1", "apply$mcII$sp")
+ assertInvoke(getSingleMethod(c, "t5"), "C", "h")
+ }
}