diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-10-08 08:53:52 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-10-10 15:23:38 +1000 |
commit | 96f47647381425be5c8c0e771590d6abe0f4d231 (patch) | |
tree | e6e0af0d4c5593b6690a0f1df653f35d69fae693 | |
parent | 22233f40f641815fe7b9304bb386ee27c8422603 (diff) | |
download | scala-96f47647381425be5c8c0e771590d6abe0f4d231.tar.gz scala-96f47647381425be5c8c0e771590d6abe0f4d231.tar.bz2 scala-96f47647381425be5c8c0e771590d6abe0f4d231.zip |
Optimize tail calls to avoid findMember calls
Cache the member symbols for `Boolean.{||, &&}` per-run, rather
than look them up repeatedly.
Based on profiling the tail calls phase in the program below, which
was distilled by @rmacleod2 from the code generated by macros in
https://github.com/paytronix/utils-open/tree/release/2014/ernststavrosgrouper
Wall clock time went from 12s to 6.5s.
```scala
object Test {
def a(): Option[String] = Some("a")
def main(args: Array[String]) {
a() match {
case Some(b1) =>
a() match {
case Some(b2) =>
a() match {
case Some(b3) =>
a() match {
case Some(b4) =>
a() match {
case Some(b5) =>
a() match {
case Some(b6) =>
a() match {
case Some(b7) =>
a() match {
case Some(b8) =>
a() match {
case Some(b9) =>
a() match {
case Some(b10) =>
a() match {
case Some(b11) =>
a() match {
case Some(b12) =>
a() match {
case Some(b13) =>
a() match {
case Some(b14) =>
a() match {
case Some(b15) =>
a() match {
case Some(b16) =>
a() match {
case Some(b17) =>
a() match {
case Some(b18) =>
a() match {
case Some(b19) =>
a() match {
case Some(b20) =>
println("yay")
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
case None => None
}
}
}
```
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/TailCalls.scala | 8 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 4 |
2 files changed, 12 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index ef534f70fd..93a343675b 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -265,6 +265,10 @@ abstract class TailCalls extends Transform { !(sym.hasAccessorFlag || sym.isConstructor) } + // intentionally shadowing imports from definitions for performance + val runDefinitions = currentRun.runDefinitions + import runDefinitions.{Boolean_or, Boolean_and} + tree match { case ValDef(_, _, _, _) => if (tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass)) @@ -421,6 +425,10 @@ abstract class TailCalls extends Transform { def traverseNoTail(tree: Tree) = traverse(tree, maybeTailNew = false) def traverseTreesNoTail(trees: List[Tree]) = trees foreach traverseNoTail + // intentionally shadowing imports from definitions for performance + private val runDefinitions = currentRun.runDefinitions + import runDefinitions.{Boolean_or, Boolean_and} + override def traverse(tree: Tree) = tree match { // we're looking for label(x){x} in tail position, since that means `a` is in tail position in a call `label(a)` case LabelDef(_, List(arg), body@Ident(_)) if arg.symbol == body.symbol => diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 70375d974c..f4f212ac2a 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1437,6 +1437,10 @@ trait Definitions extends api.StandardDefinitions { lazy val isUnbox = unboxMethod.values.toSet[Symbol] lazy val isBox = boxMethod.values.toSet[Symbol] + lazy val Boolean_and = definitions.Boolean_and + lazy val Boolean_or = definitions.Boolean_or + lazy val Boolean_not = definitions.Boolean_not + lazy val Option_apply = getMemberMethod(OptionModule, nme.apply) lazy val List_apply = DefinitionsClass.this.List_apply |