Skip to content

Commit de8d0f7

Browse files
Shrink the top "hot method too big"
I used the following to filter and sort the output of bootstrapping with -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining $ cat out.log | grep "hot method too big" | grep -oe "@.*" | grep dotty | sort | uniq -c | sort -nr | tac
1 parent 759daf2 commit de8d0f7

File tree

9 files changed

+247
-185
lines changed

9 files changed

+247
-185
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,10 +1235,8 @@ object Trees {
12351235

12361236
def apply(x: X, trees: Traversable[Tree])(implicit ctx: Context): X = (x /: trees)(apply)
12371237
def foldOver(x: X, tree: Tree)(implicit ctx: Context): X = {
1238-
Stats.record(s"TreeAccumulator.foldOver $getClass")
1239-
Stats.record("TreeAccumulator.foldOver total")
1240-
def localCtx =
1241-
if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx
1238+
// Stats.record(s"TreeAccumulator.foldOver $getClass")
1239+
// Stats.record("TreeAccumulator.foldOver total")
12421240
tree match {
12431241
case Ident(name) =>
12441242
x
@@ -1252,6 +1250,13 @@ object Trees {
12521250
this(this(x, fun), args)
12531251
case TypeApply(fun, args) =>
12541252
this(this(x, fun), args)
1253+
case _ => foldOver0(x, tree)
1254+
}
1255+
}
1256+
def foldOver0(x: X, tree: Tree)(implicit ctx: Context): X = {
1257+
def localCtx =
1258+
if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx
1259+
tree match {
12551260
case Literal(const) =>
12561261
x
12571262
case New(tpt) =>

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

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,10 @@ object Constants {
2323
final val EnumTag = 13
2424
final val ScalaSymbolTag = 14
2525

26-
case class Constant(value: Any) extends printing.Showable {
26+
class Constant(val value: Any, val tag: Int) extends printing.Showable {
2727
import java.lang.Double.doubleToRawLongBits
2828
import java.lang.Float.floatToRawIntBits
2929

30-
val tag: Int = value match {
31-
case null => NullTag
32-
case x: Unit => UnitTag
33-
case x: Boolean => BooleanTag
34-
case x: Byte => ByteTag
35-
case x: Short => ShortTag
36-
case x: Int => IntTag
37-
case x: Long => LongTag
38-
case x: Float => FloatTag
39-
case x: Double => DoubleTag
40-
case x: String => StringTag
41-
case x: Char => CharTag
42-
case x: Type => ClazzTag
43-
case x: Symbol => EnumTag
44-
case x: scala.Symbol => ScalaSymbolTag
45-
case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
46-
}
47-
4830
def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
4931
def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue
5032
def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue
@@ -235,5 +217,47 @@ object Constants {
235217
h = mix(h, equalHashValue.##)
236218
finalizeHash(h, length = 2)
237219
}
220+
221+
def get = value
222+
def isEmpty = false
223+
def _1 = value
224+
}
225+
226+
object Constant {
227+
def apply(x: Null) = new Constant(x, NullTag)
228+
def apply(x: Unit) = new Constant(x, UnitTag)
229+
def apply(x: Boolean) = new Constant(x, BooleanTag)
230+
def apply(x: Byte) = new Constant(x, ByteTag)
231+
def apply(x: Short) = new Constant(x, ShortTag)
232+
def apply(x: Int) = new Constant(x, IntTag)
233+
def apply(x: Long) = new Constant(x, LongTag)
234+
def apply(x: Float) = new Constant(x, FloatTag)
235+
def apply(x: Double) = new Constant(x, DoubleTag)
236+
def apply(x: String) = new Constant(x, StringTag)
237+
def apply(x: Char) = new Constant(x, CharTag)
238+
def apply(x: Type) = new Constant(x, ClazzTag)
239+
def apply(x: Symbol) = new Constant(x, EnumTag)
240+
def apply(x: scala.Symbol) = new Constant(x, ScalaSymbolTag)
241+
def apply(value: Any) =
242+
new Constant(value,
243+
value match {
244+
case null => NullTag
245+
case x: Unit => UnitTag
246+
case x: Boolean => BooleanTag
247+
case x: Byte => ByteTag
248+
case x: Short => ShortTag
249+
case x: Int => IntTag
250+
case x: Long => LongTag
251+
case x: Float => FloatTag
252+
case x: Double => DoubleTag
253+
case x: String => StringTag
254+
case x: Char => CharTag
255+
case x: Type => ClazzTag
256+
case x: Symbol => EnumTag
257+
case x: scala.Symbol => ScalaSymbolTag
258+
}
259+
)
260+
261+
def unapply(c: Constant) = c
238262
}
239263
}

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

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ object Denotations {
839839
// denotation and try again.
840840
val nxt = nextDefined
841841
if (nxt.validFor != Nowhere) return nxt
842-
assert(false, this)
842+
// assert(false, this)
843843
}
844844

845845
if (valid.runId != currentPeriod.runId)
@@ -859,55 +859,61 @@ object Denotations {
859859
cur = next
860860
cur
861861
} else {
862-
//println(s"might need new denot for $cur, valid for ${cur.validFor} at $currentPeriod")
863-
// not found, cur points to highest existing variant
864-
val nextTransformerId = ctx.nextDenotTransformerId(cur.validFor.lastPhaseId)
865-
if (currentPeriod.lastPhaseId <= nextTransformerId)
866-
cur.validFor = Period(currentPeriod.runId, cur.validFor.firstPhaseId, nextTransformerId)
867-
else {
868-
var startPid = nextTransformerId + 1
869-
val transformer = ctx.denotTransformers(nextTransformerId)
870-
//println(s"transforming $this with $transformer")
871-
try {
872-
next = transformer.transform(cur)(ctx.withPhase(transformer))
873-
} catch {
874-
case ex: CyclicReference =>
875-
println(s"error while transforming $this") // DEBUG
876-
throw ex
877-
}
878-
if (next eq cur)
879-
startPid = cur.validFor.firstPhaseId
862+
def compute = {
863+
//println(s"might need new denot for $cur, valid for ${cur.validFor} at $currentPeriod")
864+
// not found, cur points to highest existing variant
865+
val nextTransformerId = ctx.nextDenotTransformerId(cur.validFor.lastPhaseId)
866+
if (currentPeriod.lastPhaseId <= nextTransformerId)
867+
cur.validFor = Period(currentPeriod.runId, cur.validFor.firstPhaseId, nextTransformerId)
880868
else {
881-
next match {
882-
case next: ClassDenotation =>
883-
assert(!next.is(Package), s"illegal transformation of package denotation by transformer ${ctx.withPhase(transformer).phase}")
884-
case _ =>
869+
var startPid = nextTransformerId + 1
870+
val transformer = ctx.denotTransformers(nextTransformerId)
871+
// println(s"transforming $this with $transformer")
872+
// try {
873+
next = transformer.transform(cur)(ctx.withPhase(transformer))
874+
// } catch {
875+
// case ex: CyclicReference =>
876+
// // println(s"error while transforming $this") // DEBUG
877+
// throw ex
878+
// }
879+
if (next eq cur)
880+
startPid = cur.validFor.firstPhaseId
881+
else {
882+
// next match {
883+
// case next: ClassDenotation =>
884+
// assert(!next.is(Package), s"illegal transformation of package denotation by transformer ${ctx.withPhase(transformer).phase}")
885+
// case _ =>
886+
// }
887+
next.insertAfter(cur)
888+
cur = next
885889
}
886-
next.insertAfter(cur)
887-
cur = next
890+
cur.validFor = Period(currentPeriod.runId, startPid, transformer.lastPhaseId)
891+
//printPeriods(cur)
892+
//println(s"new denot: $cur, valid for ${cur.validFor}")
888893
}
889-
cur.validFor = Period(currentPeriod.runId, startPid, transformer.lastPhaseId)
890-
//printPeriods(cur)
891-
//println(s"new denot: $cur, valid for ${cur.validFor}")
894+
cur.current // multiple transformations could be required
892895
}
893-
cur.current // multiple transformations could be required
896+
compute
894897
}
895898
} else {
896899
// currentPeriod < end of valid; in this case a version must exist
897900
// but to be defensive we check for infinite loop anyway
898901
var cnt = 0
899-
while (!(cur.validFor contains currentPeriod)) {
900-
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
901-
cur = cur.nextInRun
902-
// Note: One might be tempted to add a `prev` field to get to the new denotation
903-
// more directly here. I tried that, but it degrades rather than improves
904-
// performance: Test setup: Compile everything in dotc and immediate subdirectories
905-
// 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
906-
cnt += 1
907-
if (cnt > MaxPossiblePhaseId)
908-
return current(ctx.withPhase(coveredInterval.firstPhaseId))
902+
def checkForInfinitLoop: SingleDenotation = {
903+
while (!(cur.validFor contains currentPeriod)) {
904+
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
905+
cur = cur.nextInRun
906+
// Note: One might be tempted to add a `prev` field to get to the new denotation
907+
// more directly here. I tried that, but it degrades rather than improves
908+
// performance: Test setup: Compile everything in dotc and immediate subdirectories
909+
// 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
910+
cnt += 1
911+
if (cnt > MaxPossiblePhaseId)
912+
return current(ctx.withPhase(coveredInterval.firstPhaseId))
913+
}
914+
cur
909915
}
910-
cur
916+
checkForInfinitLoop
911917
}
912918
}
913919
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ class TypeApplications(val self: Type) extends AnyVal {
217217
if (self.tycon.typeSymbol.isClass) NoType else self.superType.hkResult
218218
case self: HKTypeLambda => self.resultType
219219
case _: SingletonType | _: RefinedType | _: RecType => NoType
220-
case self: WildcardType => self.optBounds.hkResult
221220
case self: TypeVar =>
222221
// Using `origin` instead of `underlying`, as is done for typeParams,
223222
// avoids having to set ephemeral in some cases.

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

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
212212
}
213213
}
214214
compareNamed(tp1, tp2)
215+
case _ => firtry0
216+
}
217+
218+
def firtry0: Boolean = tp2 match {
215219
case tp2: ProtoType =>
216220
isMatchedByProto(tp2, tp1)
217221
case tp2: BoundType =>
@@ -247,6 +251,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
247251
}
248252
}
249253
compareThis
254+
case _ => firstTry1
255+
}
256+
257+
def firstTry1: Boolean = tp2 match {
250258
case tp2: SuperType =>
251259
def compareSuper = tp1 match {
252260
case tp1: SuperType =>
@@ -261,21 +269,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
261269
case OrType(tp21, tp22) =>
262270
if (tp21.stripTypeVar eq tp22.stripTypeVar) recur(tp1, tp21)
263271
else secondTry
264-
case TypeErasure.ErasedValueType(tycon1, underlying2) =>
265-
def compareErasedValueType = tp1 match {
266-
case TypeErasure.ErasedValueType(tycon2, underlying1) =>
267-
(tycon1.symbol eq tycon2.symbol) && isSameType(underlying1, underlying2)
268-
case _ =>
269-
secondTry
270-
}
271-
compareErasedValueType
272-
case ConstantType(v2) =>
273-
tp1 match {
274-
case ConstantType(v1) => v1.value == v2.value
275-
case _ => secondTry
276-
}
277-
case _: FlexType =>
278-
true
272+
case TypeErasure.ErasedValueType(tycon2, underlying2) if tp1.isInstanceOf[TypeErasure.ErasedValueType] =>
273+
val tp1_ = tp1.asInstanceOf[TypeErasure.ErasedValueType]
274+
tp1_.tycon.symbol.eq(tycon2.symbol) && isSameType(tp1_.erasedUnderlying, underlying2)
275+
case ConstantType(v2) if tp1.isInstanceOf[ConstantType] =>
276+
tp1.asInstanceOf[ConstantType].value == v2.value
279277
case _ =>
280278
secondTry
281279
}

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,9 @@ object Types {
998998
val tycon1 = tycon.dealias(keepAnnots)
999999
if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec
10001000
else this
1001+
case _ => dealias0(keepAnnots)
1002+
}
1003+
private def dealias0(keepAnnots: Boolean)(implicit ctx: Context): Type = this match {
10011004
case tp: TypeVar =>
10021005
val tp1 = tp.instanceOpt
10031006
if (tp1.exists) tp1.dealias(keepAnnots): @tailrec else tp
@@ -2704,20 +2707,20 @@ object Types {
27042707
val depStatusAcc = new TypeAccumulator[DependencyStatus] {
27052708
def apply(status: DependencyStatus, tp: Type) =
27062709
if (status == TrueDeps) status
2707-
else
2708-
tp match {
2709-
case TermParamRef(`thisLambdaType`, _) => TrueDeps
2710-
case tp: TypeRef =>
2711-
val status1 = foldOver(status, tp)
2712-
tp.info match { // follow type alias to avoid dependency
2713-
case TypeAlias(alias) if status1 == TrueDeps && status != TrueDeps =>
2714-
combine(apply(status, alias), FalseDeps)
2715-
case _ =>
2716-
status1
2717-
}
2718-
case tp: TypeVar if !tp.isInstantiated => combine(status, Provisional)
2719-
case _ => foldOver(status, tp)
2720-
}
2710+
else {
2711+
if (tp.isInstanceOf[TermParamRef] && tp.asInstanceOf[TermParamRef].binder == thisLambdaType) TrueDeps
2712+
else if (tp.isInstanceOf[TypeRef]) {
2713+
val status1 = foldOver(status, tp)
2714+
tp.asInstanceOf[TypeRef].info match { // follow type alias to avoid dependency
2715+
case TypeAlias(alias) if status1 == TrueDeps && status != TrueDeps =>
2716+
combine(apply(status, alias), FalseDeps)
2717+
case _ =>
2718+
status1
2719+
}
2720+
} else if (tp.isInstanceOf[TypeVar] && !tp.asInstanceOf[TypeVar].isInstantiated) {
2721+
combine(status, Provisional)
2722+
} else foldOver(status, tp)
2723+
}
27212724
}
27222725
depStatusAcc(initial, tp)
27232726
}

compiler/src/dotty/tools/dotc/transform/MegaPhase.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,19 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
175175
case tree: TypeApply => goTypeApply(tree, start)
176176
case tree: If => goIf(tree, start)
177177
case tree: New => goNew(tree, start)
178+
case _ => goUnnamed1(tree, start)
179+
}
180+
def goUnnamed1(tree: Tree, start: Int) = tree match {
178181
case tree: Typed => goTyped(tree, start)
179182
case tree: CaseDef => goCaseDef(tree, start)
180183
case tree: Closure => goClosure(tree, start)
181184
case tree: Assign => goAssign(tree, start)
182185
case tree: SeqLiteral => goSeqLiteral(tree, start)
183186
case tree: Super => goSuper(tree, start)
184187
case tree: Template => goTemplate(tree, start)
188+
case _ => goUnnamed2(tree, start)
189+
}
190+
def goUnnamed2(tree: Tree, start: Int) = tree match {
185191
case tree: Match => goMatch(tree, start)
186192
case tree: UnApply => goUnApply(tree, start)
187193
case tree: PackageDef => goPackageDef(tree, start)
@@ -219,6 +225,9 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
219225
}
220226
if (tree.isEmpty) tree
221227
else goValDef(mapValDef(if (tree.symbol.exists) localContext else ctx), start)
228+
case _ => transformNamed1(tree, start, outerCtx)
229+
}
230+
def transformNamed1(tree: Tree, start: Int, outerCtx: Context): Tree = tree match {
222231
case tree: DefDef =>
223232
implicit val ctx = prepDefDef(tree, start)(outerCtx)
224233
def mapDefDef(implicit ctx: Context) = {
@@ -259,6 +268,9 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
259268
case tree: Literal =>
260269
implicit val ctx = prepLiteral(tree, start)(outerCtx)
261270
goLiteral(tree, start)
271+
case _ => transformUnnamed1(tree, start, outerCtx)
272+
}
273+
def transformUnnamed1(tree: Tree, start: Int, outerCtx: Context): Tree = tree match {
262274
case tree: Block =>
263275
implicit val ctx = prepBlock(tree, start)(outerCtx)
264276
val stats = transformStats(tree.stats, ctx.owner, start)

0 commit comments

Comments
 (0)