Skip to content

Commit 8c94870

Browse files
authored
Merge pull request #9721 from dotty-staging/optimize-computations
Optimize some computation-intensive code
2 parents 1ab71c1 + 5d550c5 commit 8c94870

13 files changed

+87
-54
lines changed

compiler/src/dotty/tools/backend/jvm/BTypes.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ abstract class BTypes {
5858
case DOUBLE => "D"
5959
case ClassBType(internalName) => "L" + internalName + ";"
6060
case ArrayBType(component) => "[" + component
61-
case MethodBType(args, res) => "(" + args.mkString + ")" + res
61+
case MethodBType(args, res) => args.mkString("(", "", ")" + res)
6262
}
6363

6464
/**

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

+30-16
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ object Decorators {
7070
NoSymbol
7171
}
7272

73-
final val MaxFilterRecursions = 1000
73+
final val MaxFilterRecursions = 10
7474

7575
/** Implements filterConserve, zipWithConserve methods
7676
* on lists that avoid duplication of list nodes where feasible.
@@ -105,24 +105,38 @@ object Decorators {
105105
}
106106

107107
/** Like `xs filter p` but returns list `xs` itself - instead of a copy -
108-
* if `p` is true for all elements and `xs` is not longer
109-
* than `MaxFilterRecursions`.
108+
* if `p` is true for all elements.
110109
*/
111-
def filterConserve(p: T => Boolean): List[T] = {
112-
def loop(xs: List[T], nrec: Int): List[T] = xs match {
113-
case Nil => xs
110+
def filterConserve(p: T => Boolean): List[T] =
111+
112+
def addAll(buf: ListBuffer[T], from: List[T], until: List[T]): ListBuffer[T] =
113+
if from eq until then buf else addAll(buf += from.head, from.tail, until)
114+
115+
def loopWithBuffer(buf: ListBuffer[T], xs: List[T]): List[T] = xs match
114116
case x :: xs1 =>
115-
if (nrec < MaxFilterRecursions) {
116-
val ys1 = loop(xs1, nrec + 1)
117-
if (p(x))
118-
if (ys1 eq xs1) xs else x :: ys1
117+
if p(x) then buf += x
118+
loopWithBuffer(buf, xs1)
119+
case nil => buf.toList
120+
121+
def loop(keep: List[T], explore: List[T], keepCount: Int, recCount: Int): List[T] =
122+
explore match
123+
case x :: rest =>
124+
if p(x) then
125+
loop(keep, rest, keepCount + 1, recCount)
126+
else if keepCount <= 3 && recCount <= MaxFilterRecursions then
127+
val rest1 = loop(rest, rest, 0, recCount + 1)
128+
keepCount match
129+
case 0 => rest1
130+
case 1 => keep.head :: rest1
131+
case 2 => keep.head :: keep.tail.head :: rest1
132+
case 3 => val tl = keep.tail; keep.head :: tl.head :: tl.tail.head :: rest1
119133
else
120-
ys1
121-
}
122-
else xs filter p
123-
}
124-
loop(xs, 0)
125-
}
134+
loopWithBuffer(addAll(new ListBuffer[T], keep, explore), rest)
135+
case nil =>
136+
keep
137+
138+
loop(xs, xs, 0, 0)
139+
end filterConserve
126140

127141
/** Like `xs.lazyZip(ys).map(f)`, but returns list `xs` itself
128142
* - instead of a copy - if function `f` maps all elements of

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

+13-9
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package core
33

44
import java.security.MessageDigest
55
import scala.io.Codec
6+
import Int.MaxValue
67
import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._, Types._
7-
import scala.internal.Chars
8-
import Chars.isOperatorPart
8+
import scala.internal.Chars.{isOperatorPart, digit2int}
99
import Definitions._
1010
import nme._
1111
import Decorators.concat
@@ -207,14 +207,18 @@ object NameOps {
207207

208208
/** Parsed function arity for function with some specific prefix */
209209
private def functionArityFor(prefix: String): Int =
210-
if (name.startsWith(prefix)) {
211-
val suffix = name.toString.substring(prefix.length)
212-
if (suffix.matches("\\d+"))
213-
suffix.toInt
210+
inline val MaxSafeInt = MaxValue / 10
211+
val first = name.firstPart
212+
def collectDigits(acc: Int, idx: Int): Int =
213+
if idx == first.length then acc
214214
else
215-
-1
216-
}
217-
else -1
215+
val d = digit2int(first(idx), 10)
216+
if d < 0 || acc > MaxSafeInt then -1
217+
else collectDigits(acc * 10 + d, idx + 1)
218+
if first.startsWith(prefix) && prefix.length < first.length then
219+
collectDigits(0, prefix.length)
220+
else
221+
-1
218222

219223
/** The name of the generic runtime operation corresponding to an array operation */
220224
def genericArrayOp: TermName = name match {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
409409
if isRemovable(param.binder) then remove(param.binder)
410410
else updateEntry(this, param, replacement)
411411

412-
def removeParam(ps: List[TypeParamRef]) = ps.filter(param ne _)
412+
def removeParam(ps: List[TypeParamRef]) = ps.filterConserve(param ne _)
413413

414414
def replaceParam(tp: Type, atPoly: TypeLambda, atIdx: Int): Type =
415415
current.ensureNonCyclic(atPoly.paramRefs(atIdx), tp.substParam(param, replacement))

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

-1
Original file line numberDiff line numberDiff line change
@@ -2501,7 +2501,6 @@ object TypeComparer {
25012501
case _ => String.valueOf(res)
25022502
}
25032503

2504-
25052504
/** The approximation state indicates how the pair of types currently compared
25062505
* relates to the types compared originally.
25072506
* - `None` : They are still the same types

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -829,8 +829,8 @@ object Types {
829829
*/
830830
final def possibleSamMethods(using Context): Seq[SingleDenotation] = {
831831
record("possibleSamMethods")
832-
abstractTermMembers
833-
.filterNot(m => m.symbol.matchingMember(defn.ObjectType).exists || m.symbol.isSuperAccessor)
832+
abstractTermMembers.toList.filterConserve(m =>
833+
!m.symbol.matchingMember(defn.ObjectType).exists && !m.symbol.isSuperAccessor)
834834
}
835835

836836
/** The set of abstract type members of this type. */
@@ -3180,7 +3180,12 @@ object Types {
31803180
private var myParamRefs: List[ParamRefType] = null
31813181

31823182
def paramRefs: List[ParamRefType] = {
3183-
if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef)
3183+
if myParamRefs == null then
3184+
def recur(paramNames: List[ThisName], i: Int): List[ParamRefType] =
3185+
paramNames match
3186+
case _ :: rest => newParamRef(i) :: recur(rest, i + 1)
3187+
case _ => Nil
3188+
myParamRefs = recur(paramNames, 0)
31843189
myParamRefs
31853190
}
31863191

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ object Erasure {
977977
if (takesBridges(ctx.owner)) new Bridges(ctx.owner.asClass, erasurePhase).add(stats0)
978978
else stats0
979979
val (stats2, finalCtx) = super.typedStats(stats1, exprOwner)
980-
(stats2.filter(!_.isEmpty), finalCtx)
980+
(stats2.filterConserve(!_.isEmpty), finalCtx)
981981
}
982982

983983
override def adapt(tree: Tree, pt: Type, locked: TypeVars, tryGadtHealing: Boolean)(using Context): Tree =

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ object OverridingPairs {
3333
* pair has already been treated in a parent class.
3434
* This may be refined in subclasses. @see Bridges for a use case.
3535
*/
36-
protected def parents: Array[Symbol] = base.info.parents.toArray map (_.typeSymbol)
36+
protected def parents: Array[Symbol] = base.info.parents.toArray.map(_.typeSymbol)
3737

3838
/** Does `sym1` match `sym2` so that it qualifies as overriding.
3939
* Types always match. Term symbols match if their membertypes
@@ -64,11 +64,12 @@ object OverridingPairs {
6464
decls
6565
}
6666

67-
private val subParents =
68-
val subParents = MutableSymbolMap[BitSet]()
69-
for (bc <- base.info.baseClasses)
70-
subParents(bc) = BitSet(parents.indices.filter(parents(_).derivesFrom(bc)): _*)
71-
subParents
67+
private val subParents = MutableSymbolMap[BitSet]()
68+
for bc <- base.info.baseClasses do
69+
var bits = BitSet.empty
70+
for i <- 0 until parents.length do
71+
if parents(i).derivesFrom(bc) then bits += i
72+
subParents(bc) = bits
7273

7374
private def hasCommonParentAsSubclass(cls1: Symbol, cls2: Symbol): Boolean =
7475
(subParents(cls1) intersect subParents(cls2)).nonEmpty

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

+8-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import reporting._
2222
import config.Printers.{exhaustivity => debug}
2323
import util.SrcPos
2424
import NullOpsDecorator._
25+
import collection.mutable
2526

2627
/** Space logic for checking exhaustivity and unreachability of pattern matching
2728
*
@@ -123,10 +124,13 @@ trait SpaceLogic {
123124
else if (canDecompose(tp) && decompose(tp).isEmpty) Empty
124125
else sp
125126
case Or(spaces) =>
126-
val set = spaces.map(simplify(_)).flatMap {
127-
case Or(ss) => ss
128-
case s => Seq(s)
129-
} filter (_ != Empty)
127+
val buf = new mutable.ListBuffer[Space]
128+
def include(s: Space) = if s != Empty then buf += s
129+
for space <- spaces do
130+
simplify(space) match
131+
case Or(ss) => ss.foreach(include)
132+
case s => include(s)
133+
val set = buf.toList
130134

131135
if (set.isEmpty) Empty
132136
else if (set.size == 1) set.toList(0)

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ trait Applications extends Compatibility {
18321832
}
18331833

18341834
def narrowBySize(alts: List[TermRef]): List[TermRef] =
1835-
alts.filter(sizeFits(_))
1835+
alts.filterConserve(sizeFits(_))
18361836

18371837
def narrowByShapes(alts: List[TermRef]): List[TermRef] =
18381838
val normArgs = args.mapWithIndexConserve(normArg(alts, _, _))
@@ -1843,11 +1843,11 @@ trait Applications extends Compatibility {
18431843
alts
18441844

18451845
def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] = {
1846-
val alts2 = alts.filter(alt =>
1846+
val alts2 = alts.filterConserve(alt =>
18471847
isDirectlyApplicableMethodRef(alt, args, resultType)
18481848
)
18491849
if (alts2.isEmpty && !ctx.isAfterTyper)
1850-
alts.filter(alt =>
1850+
alts.filterConserve(alt =>
18511851
isApplicableMethodRef(alt, args, resultType, keepConstraint = false)
18521852
)
18531853
else

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1205,7 +1205,7 @@ trait Implicits:
12051205
case retained: SearchSuccess =>
12061206
val newPending =
12071207
if (retained eq found) || remaining.isEmpty then remaining
1208-
else remaining.filter(cand =>
1208+
else remaining.filterConserve(cand =>
12091209
compareCandidate(retained, cand.ref, cand.level) <= 0)
12101210
rank(newPending, retained, rfailures)
12111211
case fail: SearchFailure =>

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,20 @@ object Nullables:
399399
tree match
400400
case Block(stats, expr) =>
401401
var shadowed: Set[(Name, List[Span])] = Set.empty
402-
for case (stat: ValDef) <- stats if stat.mods.is(Mutable) do
403-
for prevSpans <- candidates.put(stat.name, Nil) do
404-
shadowed += (stat.name -> prevSpans)
405-
reachable += stat.name
402+
for stat <- stats do
403+
stat match
404+
case stat: ValDef if stat.mods.is(Mutable) =>
405+
for prevSpans <- candidates.put(stat.name, Nil) do
406+
shadowed += (stat.name -> prevSpans)
407+
reachable += stat.name
408+
case _ =>
406409
traverseChildren(tree)
407-
for case (stat: ValDef) <- stats if stat.mods.is(Mutable) do
408-
for spans <- candidates.remove(stat.name) do
409-
tracked += (stat.nameSpan.start -> spans) // candidates that survive until here are tracked
410+
for stat <- stats do
411+
stat match
412+
case stat: ValDef if stat.mods.is(Mutable) =>
413+
for spans <- candidates.remove(stat.name) do
414+
tracked += (stat.nameSpan.start -> spans) // candidates that survive until here are tracked
415+
case _ =>
410416
candidates ++= shadowed
411417
case Assign(Ident(name), rhs) =>
412418
candidates.get(name) match

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ trait TypeAssigner {
4040
}
4141

4242
def avoidingType(expr: Tree, bindings: List[Tree])(using Context): Type =
43-
TypeOps.avoid(expr.tpe, localSyms(bindings).filter(_.isTerm))
43+
TypeOps.avoid(expr.tpe, localSyms(bindings).filterConserve(_.isTerm))
4444

4545
def avoidPrivateLeaks(sym: Symbol)(using Context): Type =
4646
if sym.owner.isClass && !sym.isOneOf(JavaOrPrivateOrSynthetic)

0 commit comments

Comments
 (0)