aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-12-14 14:38:45 +0100
committerMartin Odersky <odersky@gmail.com>2016-12-17 18:34:27 +0100
commit86dea77d3b659b48fec0e9d53495009a7bff335d (patch)
treea646109f27f82291d8660a6c1bbe4930d09230c8 /compiler/src/dotty/tools/dotc/transform
parent04adb53b8d079ea114c5432ca3b3f824c80756a7 (diff)
downloaddotty-86dea77d3b659b48fec0e9d53495009a7bff335d.tar.gz
dotty-86dea77d3b659b48fec0e9d53495009a7bff335d.tar.bz2
dotty-86dea77d3b659b48fec0e9d53495009a7bff335d.zip
Make specialization tweakable
Introduce an option to not specialize monomorphic targets of callsites.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/transform')
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala25
1 files changed, 22 insertions, 3 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala
index bf72b89c0..a9fadaa56 100644
--- a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala
@@ -37,7 +37,7 @@ import collection.mutable
* is expanded to:
*
* def m(xs: Ts): IF
- * def m$direct(xs: Ts, ys: Us): R
+ * def m$direct(xs: Ts)(ys: Us): R
*
* (2) A reference `qual.apply` where `qual` has implicit function type and
* `qual` refers to a method `m` is rewritten to a reference to `m$direct`,
@@ -49,6 +49,14 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr
override def phaseName: String = "shortcutImplicits"
val treeTransform = new Transform
+ /** If this option true, we don't specialize symbols that are known to be only
+ * targets of monomorphic calls.
+ * The reason for this option is that benchmarks show that on the JVM for monomorphic dispatch
+ * scenarios inlining and escape analysis can often remove all calling overhead, so we might as
+ * well not duplicate the code. We need more experience to decide on the best setting of this option.
+ */
+ final val specializeMonoTargets = true
+
class Transform extends TreeTransform {
def phase = thisTransform
@@ -59,6 +67,17 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr
*/
private val directMeth = new mutable.HashMap[Symbol, Symbol]
+ /** Should `sym` get a ..$direct companion?
+ * This is the case if (1) `sym` is a method with an implicit function type as final result type.
+ * However if `specializeMonoTargets` is true, we exclude symbols that are known
+ * to be only targets of monomorphic calls because they are effectively
+ * final and don't override anything.
+ */
+ private def shouldBeSpecialized(sym: Symbol)(implicit ctx: Context) =
+ sym.is(Method, butNot = Accessor) &&
+ defn.isImplicitFunctionType(sym.info.finalResultType) &&
+ (specializeMonoTargets || !sym.isEffectivelyFinal || sym.allOverriddenSymbols.nonEmpty)
+
/** @pre The type's final result type is an implicit function type `implicit Ts => R`.
* @return The type of the `apply` member of `implicit Ts => R`.
*/
@@ -93,7 +112,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
if (tree.name == nme.apply &&
defn.isImplicitFunctionType(tree.qualifier.tpe.widen) &&
- tree.qualifier.symbol.is(Method, butNot = Accessor)) {
+ shouldBeSpecialized(tree.qualifier.symbol)) {
def directQual(tree: Tree): Tree = tree match {
case Apply(fn, args) => cpy.Apply(tree)(directQual(fn), args)
case TypeApply(fn, args) => cpy.TypeApply(tree)(directQual(fn), args)
@@ -108,7 +127,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr
/** Transform methods with implicit function type result according to rewrite rule (1) above */
override def transformDefDef(mdef: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val original = mdef.symbol
- if (defn.isImplicitFunctionType(original.info.finalResultType)) {
+ if (shouldBeSpecialized(original)) {
val direct = directMethod(original)
def splitClosure(tree: Tree): (List[Type] => List[List[Tree]] => Tree, Tree) = tree match {