Skip to content

Commit 4b9d75c

Browse files
committed
Reduce number of calls to Type#equals
When compiling dotc/typer/*.scala we observe a reduction of the number of calls from ~3.7m to ~1.0m.
1 parent a87540a commit 4b9d75c

File tree

8 files changed

+59
-57
lines changed

8 files changed

+59
-57
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
306306

307307
def prefixIsElidable(tp: NamedType)(implicit ctx: Context) = {
308308
val typeIsElidable = tp.prefix match {
309-
case NoPrefix =>
310-
true
311309
case pre: ThisType =>
312310
pre.cls.isStaticOwner ||
313311
tp.symbol.isParamOrAccessor && !pre.cls.is(Trait) && ctx.owner.enclosingClass == pre.cls
@@ -316,8 +314,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
316314
// eg anonymous TypeMap inside TypeMap.andThen
317315
case pre: TermRef =>
318316
pre.symbol.is(Module) && pre.symbol.isStatic
319-
case _ =>
320-
false
317+
case pre =>
318+
pre `eq` NoPrefix
321319
}
322320
typeIsElidable ||
323321
tp.symbol.is(JavaStatic) ||

compiler/src/dotty/tools/dotc/core/Substituters.scala

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ trait Substituters { this: Context =>
1212
case tp: BoundType =>
1313
if (tp.binder eq from) tp.copyBoundType(to.asInstanceOf[tp.BT]) else tp
1414
case tp: NamedType =>
15-
if (tp.currentSymbol.isStatic) tp
15+
if (tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
1616
else tp.derivedSelect(subst(tp.prefix, from, to, theMap))
17-
case _: ThisType | NoPrefix =>
17+
case _: ThisType =>
1818
tp
1919
case _ =>
2020
(if (theMap != null) theMap else new SubstBindingMap(from, to))
@@ -26,9 +26,9 @@ trait Substituters { this: Context =>
2626
case tp: NamedType =>
2727
val sym = tp.symbol
2828
if (sym eq from) return to
29-
if (sym.isStatic && !from.isStatic) tp
29+
if (sym.isStatic && !from.isStatic || (tp.prefix `eq` NoPrefix)) tp
3030
else tp.derivedSelect(subst1(tp.prefix, from, to, theMap))
31-
case _: ThisType | _: BoundType | NoPrefix =>
31+
case _: ThisType | _: BoundType =>
3232
tp
3333
case _ =>
3434
(if (theMap != null) theMap else new Subst1Map(from, to))
@@ -42,9 +42,9 @@ trait Substituters { this: Context =>
4242
val sym = tp.symbol
4343
if (sym eq from1) return to1
4444
if (sym eq from2) return to2
45-
if (sym.isStatic && !from1.isStatic && !from2.isStatic) tp
45+
if (sym.isStatic && !from1.isStatic && !from2.isStatic || (tp.prefix `eq` NoPrefix)) tp
4646
else tp.derivedSelect(subst2(tp.prefix, from1, to1, from2, to2, theMap))
47-
case _: ThisType | _: BoundType | NoPrefix =>
47+
case _: ThisType | _: BoundType =>
4848
tp
4949
case _ =>
5050
(if (theMap != null) theMap else new Subst2Map(from1, to1, from2, to2))
@@ -63,9 +63,9 @@ trait Substituters { this: Context =>
6363
fs = fs.tail
6464
ts = ts.tail
6565
}
66-
if (sym.isStatic && !existsStatic(from)) tp
66+
if (sym.isStatic && !existsStatic(from) || (tp.prefix `eq` NoPrefix)) tp
6767
else tp.derivedSelect(subst(tp.prefix, from, to, theMap))
68-
case _: ThisType | _: BoundType | NoPrefix =>
68+
case _: ThisType | _: BoundType =>
6969
tp
7070
case _ =>
7171
(if (theMap != null) theMap else new SubstMap(from, to))
@@ -84,7 +84,7 @@ trait Substituters { this: Context =>
8484
fs = fs.tail
8585
ts = ts.tail
8686
}
87-
if (sym.isStatic && !existsStatic(from)) tp
87+
if (sym.isStatic && !existsStatic(from) || (tp.prefix `eq` NoPrefix)) tp
8888
else {
8989
tp.info match {
9090
case TypeAlias(alias) =>
@@ -94,7 +94,7 @@ trait Substituters { this: Context =>
9494
}
9595
tp.derivedSelect(substDealias(tp.prefix, from, to, theMap))
9696
}
97-
case _: ThisType | _: BoundType | NoPrefix =>
97+
case _: ThisType | _: BoundType =>
9898
tp
9999
case _ =>
100100
(if (theMap != null) theMap else new SubstDealiasMap(from, to))
@@ -114,7 +114,7 @@ trait Substituters { this: Context =>
114114
fs = fs.tail
115115
ts = ts.tail
116116
}
117-
if (sym.isStatic && !existsStatic(from)) tp
117+
if (sym.isStatic && !existsStatic(from) || (tp.prefix `eq` NoPrefix)) tp
118118
else tp.derivedSelect(substSym(tp.prefix, from, to, theMap))
119119
case tp: ThisType =>
120120
val sym = tp.cls
@@ -126,7 +126,7 @@ trait Substituters { this: Context =>
126126
ts = ts.tail
127127
}
128128
tp
129-
case _: ThisType | _: BoundType | NoPrefix =>
129+
case _: ThisType | _: BoundType =>
130130
tp
131131
case _ =>
132132
(if (theMap != null) theMap else new SubstSymMap(from, to))
@@ -138,9 +138,9 @@ trait Substituters { this: Context =>
138138
case tp: ThisType =>
139139
if (tp.cls eq from) to else tp
140140
case tp: NamedType =>
141-
if (tp.currentSymbol.isStaticOwner) tp
141+
if (tp.currentSymbol.isStaticOwner || (tp.prefix `eq` NoPrefix)) tp
142142
else tp.derivedSelect(substThis(tp.prefix, from, to, theMap))
143-
case _: BoundType | NoPrefix =>
143+
case _: BoundType =>
144144
tp
145145
case _ =>
146146
(if (theMap != null) theMap else new SubstThisMap(from, to))
@@ -152,9 +152,9 @@ trait Substituters { this: Context =>
152152
case tp @ RecThis(binder) =>
153153
if (binder eq from) to else tp
154154
case tp: NamedType =>
155-
if (tp.currentSymbol.isStatic) tp
155+
if (tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
156156
else tp.derivedSelect(substRecThis(tp.prefix, from, to, theMap))
157-
case _: ThisType | _: BoundType | NoPrefix =>
157+
case _: ThisType | _: BoundType =>
158158
tp
159159
case _ =>
160160
(if (theMap != null) theMap else new SubstRecThisMap(from, to))
@@ -166,9 +166,9 @@ trait Substituters { this: Context =>
166166
case tp: BoundType =>
167167
if (tp == from) to else tp
168168
case tp: NamedType =>
169-
if (tp.currentSymbol.isStatic) tp
169+
if (tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
170170
else tp.derivedSelect(substParam(tp.prefix, from, to, theMap))
171-
case _: ThisType | NoPrefix =>
171+
case _: ThisType =>
172172
tp
173173
case _ =>
174174
(if (theMap != null) theMap else new SubstParamMap(from, to))
@@ -180,9 +180,9 @@ trait Substituters { this: Context =>
180180
case tp: ParamRef =>
181181
if (tp.binder == from) to(tp.paramNum) else tp
182182
case tp: NamedType =>
183-
if (tp.currentSymbol.isStatic) tp
183+
if (tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
184184
else tp.derivedSelect(substParams(tp.prefix, from, to, theMap))
185-
case _: ThisType | NoPrefix =>
185+
case _: ThisType =>
186186
tp
187187
case _ =>
188188
(if (theMap != null) theMap else new SubstParamsMap(from, to))

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ object SymDenotations {
461461
/** Is symbol known to not exist? */
462462
final def isAbsent(implicit ctx: Context): Boolean = {
463463
ensureCompleted()
464-
myInfo == NoType ||
464+
(myInfo `eq` NoType) ||
465465
(this is (ModuleVal, butNot = Package)) && moduleClass.isAbsent
466466
}
467467

@@ -1281,7 +1281,7 @@ object SymDenotations {
12811281
private[this] var myMemberCachePeriod: Period = Nowhere
12821282

12831283
/** A cache from types T to baseType(T, C) */
1284-
type BaseTypeMap = java.util.HashMap[CachedType, Type]
1284+
type BaseTypeMap = java.util.IdentityHashMap[CachedType, Type]
12851285
private[this] var myBaseTypeCache: BaseTypeMap = null
12861286
private[this] var myBaseTypeCachePeriod: Period = Nowhere
12871287

@@ -1705,7 +1705,7 @@ object SymDenotations {
17051705
btrCache.put(tp, basetp)
17061706
}
17071707
else btrCache.remove(tp)
1708-
} else if (basetp == NoPrefix)
1708+
} else if (basetp `eq` NoPrefix)
17091709
throw CyclicReference(this)
17101710
basetp
17111711
}

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,12 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
429429
tp.derivedClassInfo(NoPrefix, erasedParents, erasedDecls, erasedRef(tp.selfType))
430430
// can't replace selftype by NoType because this would lose the sourceModule link
431431
}
432-
case NoType | NoPrefix | _: ErrorType | JavaArrayType(_) =>
432+
case _: ErrorType | JavaArrayType(_) =>
433433
tp
434434
case tp: WildcardType if wildcardOK =>
435435
tp
436+
case tp if (tp `eq` NoType) || (tp `eq` NoPrefix) =>
437+
tp
436438
}
437439

438440
private def eraseArray(tp: Type)(implicit ctx: Context) = {

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
5757
tp match {
5858
case tp: NamedType =>
5959
val sym = tp.symbol
60-
if (sym.isStatic) tp
60+
if (sym.isStatic || (tp.prefix `eq` NoPrefix)) tp
6161
else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix)))
6262
case tp: ThisType =>
6363
toPrefix(pre, cls, tp.cls)
64-
case _: BoundType | NoPrefix =>
64+
case _: BoundType =>
6565
tp
6666
case _ =>
6767
mapOver(tp)
@@ -80,7 +80,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
8080
/** Implementation of Types#simplified */
8181
final def simplify(tp: Type, theMap: SimplifyMap): Type = tp match {
8282
case tp: NamedType =>
83-
if (tp.symbol.isStatic) tp
83+
if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
8484
else tp.derivedSelect(simplify(tp.prefix, theMap)) match {
8585
case tp1: NamedType if tp1.denotationIsCurrent =>
8686
val tp2 = tp1.reduceProjection
@@ -97,7 +97,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
9797
val tvar = typerState.constraint.typeVarOfParam(tp)
9898
if (tvar.exists) tvar else tp
9999
}
100-
case _: ThisType | _: BoundType | NoPrefix =>
100+
case _: ThisType | _: BoundType =>
101101
tp
102102
case tp: TypeAlias =>
103103
tp.derivedTypeAlias(simplify(tp.alias, theMap))

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ object Types {
13961396

13971397
/** Equality used for hash-consing; uses `eq` on all recursive invocations.
13981398
*/
1399-
def eql(that: Type): Boolean = this.equals(that)
1399+
def eql(that: Type): Boolean = this.iso(that, null)
14001400

14011401
/** customized hash code of this type.
14021402
* NotCached for uncached types. Cached types
@@ -3773,7 +3773,7 @@ object Types {
37733773
implicit val ctx = this.ctx
37743774
tp match {
37753775
case tp: NamedType =>
3776-
if (stopAtStatic && tp.symbol.isStatic) tp
3776+
if (stopAtStatic && tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
37773777
else {
37783778
val prefix1 = atVariance(variance max 0)(this(tp.prefix))
37793779
// A prefix is never contravariant. Even if say `p.A` is used in a contravariant
@@ -4162,7 +4162,7 @@ object Types {
41624162
record(s"foldOver total")
41634163
tp match {
41644164
case tp: TypeRef =>
4165-
if (stopAtStatic && tp.symbol.isStatic) x
4165+
if (stopAtStatic && tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) x
41664166
else {
41674167
val tp1 = tp.prefix.lookupRefined(tp.name)
41684168
if (tp1.exists) this(x, tp1) else applyToPrefix(x, tp)
@@ -4192,10 +4192,8 @@ object Types {
41924192
variance = -variance
41934193
this(y, tp.resultType)
41944194

4195-
case NoPrefix => x
4196-
41974195
case tp: TermRef =>
4198-
if (stopAtStatic && tp.currentSymbol.isStatic) x
4196+
if (stopAtStatic && tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) x
41994197
else applyToPrefix(x, tp)
42004198

42014199
case tp: TypeVar =>
@@ -4275,11 +4273,14 @@ object Types {
42754273
(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] {
42764274
override def stopAtStatic = false
42774275
def maybeAdd(x: mutable.Set[NamedType], tp: NamedType) = if (p(tp)) x += tp else x
4278-
val seen: mutable.Set[Type] = mutable.Set()
4276+
val seen = new util.HashSet[Type](7) {
4277+
override def hash(x: Type): Int = x.hash
4278+
override def isEqual(x: Type, y: Type) = x.eq(y)
4279+
}
42794280
def apply(x: mutable.Set[NamedType], tp: Type): mutable.Set[NamedType] =
42804281
if (seen contains tp) x
42814282
else {
4282-
seen += tp
4283+
seen.addEntry(tp)
42834284
tp match {
42844285
case tp: TypeRef =>
42854286
foldOver(maybeAdd(x, tp), tp)

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ object Implicits {
186186
* @param outerCtx the next outer context that makes visible further implicits
187187
*/
188188
class ContextualImplicits(val refs: List[ImplicitRef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) {
189-
private val eligibleCache = new mutable.AnyRefMap[Type, List[Candidate]]
189+
private val eligibleCache = new java.util.IdentityHashMap[Type, List[Candidate]]
190190

191191
/** The level increases if current context has a different owner or scope than
192192
* the context of the next-outer ImplicitRefs. This is however disabled under
@@ -211,27 +211,28 @@ object Implicits {
211211
/** The implicit references that are eligible for type `tp`. */
212212
def eligible(tp: Type): List[Candidate] = /*>|>*/ track(s"eligible in ctx") /*<|<*/ {
213213
if (tp.hash == NotCached) computeEligible(tp)
214-
else eligibleCache get tp match {
215-
case Some(eligibles) =>
214+
else {
215+
val eligibles = eligibleCache.get(tp)
216+
if (eligibles != null) {
216217
def elided(ci: ContextualImplicits): Int = {
217218
val n = ci.refs.length
218219
if (ci.isOuterMost) n
219220
else n + elided(ci.outerImplicits)
220221
}
221222
if (monitored) record(s"elided eligible refs", elided(this))
222223
eligibles
223-
case None =>
224-
if (ctx eq NoContext) Nil
225-
else {
226-
val savedEphemeral = ctx.typerState.ephemeral
227-
ctx.typerState.ephemeral = false
228-
try {
229-
val result = computeEligible(tp)
230-
if (ctx.typerState.ephemeral) record("ephemeral cache miss: eligible")
231-
else eligibleCache(tp) = result
232-
result
233-
} finally ctx.typerState.ephemeral |= savedEphemeral
234-
}
224+
}
225+
else if (ctx eq NoContext) Nil
226+
else {
227+
val savedEphemeral = ctx.typerState.ephemeral
228+
ctx.typerState.ephemeral = false
229+
try {
230+
val result = computeEligible(tp)
231+
if (ctx.typerState.ephemeral) record("ephemeral cache miss: eligible")
232+
else eligibleCache.put(tp, result)
233+
result
234+
} finally ctx.typerState.ephemeral |= savedEphemeral
235+
}
235236
}
236237
}
237238

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ object ProtoTypes {
480480
*/
481481
final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[TypeParamRef])(implicit ctx: Context): Type = tp match {
482482
case tp: NamedType => // default case, inlined for speed
483-
if (tp.symbol.isStatic) tp
483+
if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
484484
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
485485
case tp @ AppliedType(tycon, args) =>
486486
wildApprox(tycon, theMap, seen) match {
@@ -540,7 +540,7 @@ object ProtoTypes {
540540
tp.derivedViewProto(
541541
wildApprox(tp.argType, theMap, seen),
542542
wildApprox(tp.resultType, theMap, seen))
543-
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
543+
case _: ThisType | _: BoundType => // default case, inlined for speed
544544
tp
545545
case _ =>
546546
(if (theMap != null && seen.eq(theMap.seen)) theMap else new WildApproxMap(seen))

0 commit comments

Comments
 (0)