@@ -73,29 +73,10 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
73
73
override def initContext (ctx : FreshContext ) =
74
74
DirectMeth = ctx.addLocation[MutableSymbolMap [Symbol ]]()
75
75
76
- /** If this option is true, we don't specialize symbols that are known to be only
77
- * targets of monomorphic calls.
78
- * The reason for this option is that benchmarks show that on the JVM for monomorphic dispatch
79
- * scenarios inlining and escape analysis can often remove all calling overhead, so we might as
80
- * well not duplicate the code. We need more experience to decide on the best setting of this option.
81
- */
82
- final val specializeMonoTargets = true
83
76
84
77
override def prepareForUnit (tree : Tree )(implicit ctx : Context ) =
85
78
ctx.fresh.updateStore(DirectMeth , newMutableSymbolMap[Symbol ])
86
79
87
- /** Should `sym` get a ..$direct companion?
88
- * This is the case if `sym` is a method with a non-nullary implicit function type as final result type.
89
- * However if `specializeMonoTargets` is false, we exclude symbols that are known
90
- * to be only targets of monomorphic calls because they are effectively
91
- * final and don't override anything.
92
- */
93
- private def shouldBeSpecialized (sym : Symbol )(implicit ctx : Context ) =
94
- sym.is(Method , butNot = Accessor ) &&
95
- defn.isImplicitFunctionType(sym.info.finalResultType) &&
96
- defn.functionArity(sym.info.finalResultType) > 0 &&
97
- ! sym.isAnonymousFunction &&
98
- (specializeMonoTargets || ! sym.isEffectivelyFinal || sym.allOverriddenSymbols.nonEmpty)
99
80
100
81
/** The direct method `m$direct` that accompanies the given method `m`.
101
82
* Create one if it does not exist already.
@@ -108,7 +89,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
108
89
override def transformSelect (tree : Select )(implicit ctx : Context ) =
109
90
if (tree.name == nme.apply &&
110
91
defn.isImplicitFunctionType(tree.qualifier.tpe.widen) &&
111
- shouldBeSpecialized (tree.qualifier.symbol)) {
92
+ needsImplicitShortcut (tree.qualifier.symbol)) {
112
93
def directQual (tree : Tree ): Tree = tree match {
113
94
case Apply (fn, args) => cpy.Apply (tree)(directQual(fn), args)
114
95
case TypeApply (fn, args) => cpy.TypeApply (tree)(directQual(fn), args)
@@ -127,7 +108,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
127
108
/** Transform methods with implicit function type result according to rewrite rule (1) above */
128
109
override def transformDefDef (mdef : DefDef )(implicit ctx : Context ): Tree = {
129
110
val original = mdef.symbol
130
- if (shouldBeSpecialized (original)) {
111
+ if (needsImplicitShortcut (original)) {
131
112
val direct = directMethod(original)
132
113
133
114
// Move @tailrec to the direct method
@@ -171,6 +152,27 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh
171
152
object ShortcutImplicits {
172
153
val name = " shortcutImplicits"
173
154
155
+ /** If this option is true, we don't specialize symbols that are known to be only
156
+ * targets of monomorphic calls.
157
+ * The reason for this option is that benchmarks show that on the JVM for monomorphic dispatch
158
+ * scenarios inlining and escape analysis can often remove all calling overhead, so we might as
159
+ * well not duplicate the code. We need more experience to decide on the best setting of this option.
160
+ */
161
+ final val specializeMonoTargets = true
162
+
163
+ /** Should `sym` get a ..$direct companion?
164
+ * This is the case if `sym` is a method with a non-nullary implicit function type as final result type.
165
+ * However if `specializeMonoTargets` is false, we exclude symbols that are known
166
+ * to be only targets of monomorphic calls because they are effectively
167
+ * final and don't override anything.
168
+ */
169
+ def needsImplicitShortcut (sym : Symbol )(implicit ctx : Context ) =
170
+ sym.is(Method , butNot = Accessor ) &&
171
+ defn.isImplicitFunctionType(sym.info.finalResultType) &&
172
+ defn.functionArity(sym.info.finalResultType) > 0 &&
173
+ ! sym.isAnonymousFunction &&
174
+ (specializeMonoTargets || ! sym.isEffectivelyFinal || sym.allOverriddenSymbols.nonEmpty)
175
+
174
176
/** @pre The type's final result type is an implicit function type `implicit Ts => R`.
175
177
* @return The type of the `apply` member of `implicit Ts => R`.
176
178
*/
@@ -181,8 +183,6 @@ object ShortcutImplicits {
181
183
case info => info.member(nme.apply).info
182
184
}
183
185
184
- def isImplicitShortcut (sym : Symbol )(implicit ctx : Context ) = sym.name.is(DirectMethodName )
185
-
186
186
/** A new `m$direct` method to accompany the given method `m` */
187
187
private def newShortcutMethod (sym : Symbol )(implicit ctx : Context ): Symbol =
188
188
sym.copy(
@@ -195,6 +195,8 @@ object ShortcutImplicits {
195
195
sym.owner.info.decl(DirectMethodName (sym.name.asTermName))
196
196
.suchThat(_.info matches directInfo(sym.info)).symbol
197
197
.orElse(newShortcutMethod(sym).enteredAfter(phase))
198
+
199
+ def isImplicitShortcut (sym : Symbol )(implicit ctx : Context ) = sym.name.is(DirectMethodName )
198
200
}
199
201
200
202
0 commit comments