Skip to content

Try some optimizations #4448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -837,17 +837,16 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma

/**
* All interfaces implemented by a class, except for those inherited through the superclass.
* Redundant interfaces are removed unless there is a super call to them.
* Redundant* interfaces are removed unless there is a super call to them.
* An interface is redudundant if some other interface in the set derives from it.
* TODO: write a clearer and more efficient algorithm.
*/
def superInterfaces: List[Symbol] = {
val directlyInheritedTraits = decorateSymbol(sym).directlyInheritedTraits
val directlyInheritedTraitsSet = directlyInheritedTraits.toSet
val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.symbol.asClass.baseClasses.drop(1)).toSet
val directlyInheritedTraits = sym.directlyInheritedTraits
def isRedundant(cls: Symbol) = directlyInheritedTraits.exists(t => (t `ne` cls) && t.derivesFrom(cls))
val superCalls = superCallsMap.getOrElse(sym, Set.empty)
val additional = (superCalls -- directlyInheritedTraitsSet).filter(_.is(Flags.Trait))
// if (additional.nonEmpty)
// println(s"$fullName: adding supertraits $additional")
directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) ++ additional
directlyInheritedTraits.filter(t => !isRedundant(t) || superCalls.contains(t)).toList ++
superCalls.filter(cls => cls.is(Flags.Trait) && !directlyInheritedTraits.contains(cls))
}

/**
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import StdNames._
import Annotations._
import collection.mutable
import ast.tpd._
import util.Lst

/** Realizability status */
object CheckRealizable {
Expand Down Expand Up @@ -142,7 +143,7 @@ class CheckRealizable(implicit ctx: Context) {
}
}
val baseProblems =
tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems)
tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(x => Lst.fromIterable(baseTypeProblems(x)))

((((Realizable: Realizability)
/: memberProblems)(_ andAlso _)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Comments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,8 @@ object Comments {
case NoSymbol => None
case _ =>
val searchList =
if (site.flags.is(Flags.Module)) site :: site.info.baseClasses
else site.info.baseClasses
if (site.flags.is(Flags.Module)) site :: site.info.baseClasses.toList
else site.info.baseClasses.toList

searchList collectFirst { case x if defs(x) contains vble => defs(x)(vble) } match {
case Some(str) if str startsWith "$" => lookupVariable(str.tail, site)
Expand Down
16 changes: 12 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import printing.Printer
import io.AbstractFile
import config.Config
import util.common._
import util.Lst
import collection.mutable.ListBuffer
import Decorators.SymbolIteratorDecorator

Expand Down Expand Up @@ -461,10 +462,17 @@ object Denotations {
val sym2Accessible = sym2.isAccessibleFrom(pre)

/** Does `sym1` come before `sym2` in the linearization of `pre`? */
def precedes(sym1: Symbol, sym2: Symbol) = {
def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match {
case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1)
case Nil => true
def precedes(sym1: Symbol, sym2: Symbol): Boolean = {
def precedesIn(bcs: Lst[ClassSymbol]): Boolean = {
var i = 0
val len = bcs.length
while (i < len) {
val bc = bcs(i)
if (bc `eq` sym1) return true
else if (bc `eq` sym2) return false
i += 1
}
true
}
(sym1 ne sym2) &&
(sym1.derivesFrom(sym2) ||
Expand Down
92 changes: 28 additions & 64 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import ast.Trees._
import annotation.tailrec
import CheckRealizable._
import util.SimpleIdentityMap
import util.Stats
import util.{Lst, Stats}
import java.util.WeakHashMap
import config.Config
import config.Printers.noPrinter
Expand Down Expand Up @@ -1077,10 +1077,7 @@ object SymDenotations {
else overriddenFromType(owner.asClass.classInfo.selfType)

private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
tp.baseClasses match {
case _ :: inherited => inherited.iterator map overriddenSymbol filter (_.exists)
case Nil => Iterator.empty
}
tp.baseClasses.iterator().drop(1).map(overriddenSymbol).filter(_.exists)

/** The symbol overriding this symbol in given subclass `ofclazz`.
*
Expand All @@ -1095,15 +1092,16 @@ object SymDenotations {
* pre: `this.owner` is in the base class sequence of `base`.
*/
final def superSymbolIn(base: Symbol)(implicit ctx: Context): Symbol = {
@tailrec def loop(bcs: List[ClassSymbol]): Symbol = bcs match {
case bc :: bcs1 =>
val sym = matchingDecl(bcs.head, base.thisType)
val bcs = base.info.baseClasses
val len = bcs.length
@tailrec def loop(i: Int): Symbol =
if (i < len) {
val sym = matchingDecl(bcs(i), base.thisType)
.suchThat(alt => !(alt is Deferred)).symbol
if (sym.exists) sym else loop(bcs.tail)
case _ =>
NoSymbol
}
loop(base.info.baseClasses.dropWhile(owner != _).tail)
if (sym.exists) sym else loop(i + 1)
}
else NoSymbol
loop(bcs.firstIndexWhere(owner == _) + 1)
}

/** A member of class `base` is incomplete if
Expand Down Expand Up @@ -1445,33 +1443,39 @@ object SymDenotations {

override def appliedRef(implicit ctx: Context): Type = classInfo.appliedRef

private def baseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = {
private def baseData(implicit onBehalf: BaseData, ctx: Context): (Lst[ClassSymbol], BaseClassSet) = {
if (!baseDataCache.isValid) baseDataCache = BaseData.newCache()
baseDataCache(this)
}

/** The base classes of this class in linearization order,
* with the class itself as first element.
*/
def baseClasses(implicit onBehalf: BaseData, ctx: Context): List[ClassSymbol] =
def baseClasses(implicit onBehalf: BaseData, ctx: Context): Lst[ClassSymbol] =
baseData._1

/** A bitset that contains the superId's of all base classes */
private def baseClassSet(implicit onBehalf: BaseData, ctx: Context): BaseClassSet =
baseData._2

def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = {
def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (Lst[ClassSymbol], BaseClassSet) = {
def emptyParentsExpected =
is(Package) || (symbol == defn.AnyClass) || ctx.erasedTypes && (symbol == defn.ObjectClass)
if (classParents.isEmpty && !emptyParentsExpected)
onBehalf.signalProvisional()
val builder = new BaseDataBuilder
val builder = new Lst.Buffer[ClassSymbol]
for (p <- classParents)
p.classSymbol match {
case pcls: ClassSymbol => builder.addAll(pcls.baseClasses)
case _ => assert(isRefinementClass || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
case pcls: ClassSymbol =>
pcls.baseClasses.foreachReversed { bc =>
if (!builder.contains(bc)) builder += bc
}
case _ =>
assert(isRefinementClass || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
}
(classSymbol :: builder.baseClasses, builder.baseClassSet)
val bcs = BaseClassSet(builder.toLst)
builder += classSymbol
(builder.toLst.reverse, bcs)
}

final override def derivesFrom(base: Symbol)(implicit ctx: Context): Boolean =
Expand Down Expand Up @@ -2038,7 +2042,7 @@ object SymDenotations {
*/
trait BaseData extends InheritedCache {
def apply(clsd: ClassDenotation)
(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet)
(implicit onBehalf: BaseData, ctx: Context): (Lst[ClassSymbol], BaseClassSet)
def signalProvisional(): Unit
}

Expand Down Expand Up @@ -2123,7 +2127,7 @@ object SymDenotations {
}

private class BaseDataImpl(createdAt: Period) extends InheritedCacheImpl(createdAt) with BaseData {
private[this] var cache: (List[ClassSymbol], BaseClassSet) = null
private[this] var cache: (Lst[ClassSymbol], BaseClassSet) = null

private[this] var valid = true
private[this] var locked = false
Expand All @@ -2141,7 +2145,7 @@ object SymDenotations {
def signalProvisional() = provisional = true

def apply(clsd: ClassDenotation)(implicit onBehalf: BaseData, ctx: Context)
: (List[ClassSymbol], BaseClassSet) = {
: (Lst[ClassSymbol], BaseClassSet) = {
assert(isValid)
try {
if (cache != null) cache
Expand Down Expand Up @@ -2181,49 +2185,9 @@ object SymDenotations {
}

object BaseClassSet {
def apply(bcs: List[ClassSymbol]): BaseClassSet =
def apply(bcs: Lst[ClassSymbol]): BaseClassSet =
new BaseClassSet(bcs.toArray.map(_.id))
}

/** A class to combine base data from parent types */
class BaseDataBuilder {
private[this] var classes: List[ClassSymbol] = Nil
private[this] var classIds = new Array[Int](32)
private[this] var length = 0

private def resize(size: Int) = {
val classIds1 = new Array[Int](size)
Array.copy(classIds, 0, classIds1, 0, classIds.length min size)
classIds = classIds1
}

private def add(sym: Symbol): Unit = {
if (length == classIds.length) resize(length * 2)
classIds(length) = sym.id
length += 1
}

def addAll(bcs: List[ClassSymbol]): this.type = {
val len = length
bcs match {
case bc :: bcs1 =>
addAll(bcs1)
if (!new BaseClassSet(classIds).contains(bc, len)) {
add(bc)
classes = bc :: classes
}
case nil =>
}
this
}

def baseClassSet = {
if (length != classIds.length) resize(length)
new BaseClassSet(classIds)
}

def baseClasses: List[ClassSymbol] = classes
}

@sharable private[this] var indent = 0 // for completions printing
}
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import printing.Printer
import Types._
import Annotations._
import util.Positions._
import util.Stats
import DenotTransformers._
import StdNames._
import NameOps._
Expand Down Expand Up @@ -416,6 +417,8 @@ object Symbols {

//assert(id != 723)

Stats.record("symbol")

def coord: Coord = myCoord
/** Set the coordinate of this class, this is only useful when the coordinate is
* not known at symbol creation. This is the case for root symbols
Expand Down
28 changes: 9 additions & 19 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import config.Config
import config.Printers.{typr, constr, subtyping, gadts, noPrinter}
import TypeErasure.{erasedLub, erasedGlb}
import TypeApplications._
import util.Lst
import scala.util.control.NonFatal
import reporting.trace

Expand Down Expand Up @@ -751,14 +752,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp1w =>
tp1w.typeSymbol.isClass && {
val classBounds = tycon2.classSymbols
def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match {
case bc :: bcs1 =>
classBounds.exists(bc.derivesFrom) && appOK(tp1w.baseType(bc)) ||
liftToBase(bcs1)
case _ =>
false
}
liftToBase(tp1w.baseClasses)
// TODO: Try to use testLifted
tp1w.baseClasses.exists(bc =>
classBounds.exists(bc.derivesFrom) && appOK(tp1w.baseType(bc)))
} ||
fourthTry
}
Expand Down Expand Up @@ -924,17 +920,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
*/
private def testLifted(tp1: Type, tp2: Type, tparams: List[TypeParamInfo], p: Type => Boolean): Boolean = {
val classBounds = tp2.classSymbols
def recur(bcs: List[ClassSymbol]): Boolean = bcs match {
case bc :: bcs1 =>
(classBounds.exists(bc.derivesFrom) &&
variancesConform(bc.typeParams, tparams) &&
p(tp1.baseType(bc))
||
recur(bcs1))
case nil =>
false
}
recur(tp1.baseClasses)
tp1.baseClasses.exists(bc =>
classBounds.exists(bc.derivesFrom) &&
variancesConform(bc.typeParams, tparams) &&
p(tp1.baseType(bc))
)
}

/** Replace any top-level recursive type `{ z => T }` in `tp` with
Expand Down
14 changes: 6 additions & 8 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -268,22 +268,20 @@ object TypeErasure {

// From the spec, "Linearization also satisfies the property that a
// linearization of a class always contains the linearization of its
// direct superclass as a suffix"; it's enought to consider every
// direct superclass as a suffix"; it's enough to consider every
// candidate up to the first class.
val candidates = takeUntil(tp2superclasses)(!_.is(Trait))
val firstRealClassIdx = tp2superclasses.firstIndexWhere(!_.is(Trait))
val candidates = tp2superclasses.take(firstRealClassIdx + 1)

// Candidates st "no other common superclass or trait derives from S"
val minimums = candidates.filter { cand =>
candidates.forall(x => !x.derivesFrom(cand) || x.eq(cand))
}

// Pick the last minimum to prioritise classes over traits
minimums.lastOption match {
case Some(lub) if lub != defn.AnyClass && lub != defn.AnyValClass =>
lub.typeRef
case _ => // Any/AnyVal only exist before erasure
defn.ObjectType
}
val lub = if (minimums.isEmpty) defn.ObjectClass else minimums.last
if (lub == defn.AnyClass || lub == defn.AnyValClass) defn.ObjectType
else lub.typeRef
}
}

Expand Down
17 changes: 4 additions & 13 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import StdNames._
import Annotations._
import annotation.tailrec
import config.Config
import util.Property
import util.{Property, Lst}
import transform.SymUtils.dominators
import collection.mutable
import ast.tpd._
import reporting.trace
Expand Down Expand Up @@ -128,22 +129,12 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
def orDominator(tp: Type): Type = {

/** a faster version of cs1 intersect cs2 */
def intersect(cs1: List[ClassSymbol], cs2: List[ClassSymbol]): List[ClassSymbol] = {
def intersect(cs1: Lst[ClassSymbol], cs2: Lst[ClassSymbol]): Lst[ClassSymbol] = {
val cs2AsSet = new util.HashSet[ClassSymbol](128)
cs2.foreach(cs2AsSet.addEntry)
cs1.filter(cs2AsSet.contains)
}

/** The minimal set of classes in `cs` which derive all other classes in `cs` */
def dominators(cs: List[ClassSymbol], accu: List[ClassSymbol]): List[ClassSymbol] = (cs: @unchecked) match {
case c :: rest =>
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
case Nil => // this case can happen because after erasure we do not have a top class anymore
assert(ctx.erasedTypes || ctx.reporter.errorsReported)
defn.ObjectClass :: Nil
}

def mergeRefinedOrApplied(tp1: Type, tp2: Type): Type = {
def fail = throw new AssertionError(i"Failure to join alternatives $tp1 and $tp2")
tp1 match {
Expand Down Expand Up @@ -197,7 +188,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
err
case _ =>
val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
val doms = dominators(commonBaseClasses, Nil)
val doms = dominators(commonBaseClasses)
def baseTp(cls: ClassSymbol): Type =
tp.baseType(cls).mapReduceOr(identity)(mergeRefinedOrApplied)
doms.map(baseTp).reduceLeft(AndType.apply)
Expand Down
Loading