Skip to content

Commit b3f908d

Browse files
authored
Merge pull request #9680 from dotty-staging/optimize-collections
Use util Collections more widely
2 parents cdfc76e + 5e2d801 commit b3f908d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1120
-763
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Symbols._
2222
import Phases._
2323

2424
import dotty.tools.dotc.util
25-
import dotty.tools.dotc.util.Spans
25+
import dotty.tools.dotc.util.{Spans, ReadOnlyMap}
2626
import dotty.tools.dotc.report
2727

2828
import Decorators._
@@ -36,7 +36,7 @@ import Names.TermName
3636
import Annotations.Annotation
3737
import Names.Name
3838

39-
class DottyBackendInterface(val outputDirectory: AbstractFile, val superCallsMap: Map[Symbol, Set[ClassSymbol]])(using val ctx: Context) {
39+
class DottyBackendInterface(val outputDirectory: AbstractFile, val superCallsMap: ReadOnlyMap[Symbol, Set[ClassSymbol]])(using val ctx: Context) {
4040

4141
private val desugared = new java.util.IdentityHashMap[Type, tpd.Select]
4242

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

+3-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import dotty.tools.io._
3636
class GenBCode extends Phase {
3737
def phaseName: String = GenBCode.name
3838

39-
private val superCallsMap = newMutableSymbolMap[Set[ClassSymbol]]
39+
private val superCallsMap = new MutableSymbolMap[Set[ClassSymbol]]
4040
def registerSuperCall(sym: Symbol, calls: ClassSymbol): Unit = {
4141
val old = superCallsMap.getOrElse(sym, Set.empty)
4242
superCallsMap.update(sym, old + calls)
@@ -51,10 +51,8 @@ class GenBCode extends Phase {
5151
}
5252

5353
def run(using Context): Unit =
54-
new GenBCodePipeline(
55-
new DottyBackendInterface(
56-
outputDir, superCallsMap.toMap
57-
)
54+
GenBCodePipeline(
55+
DottyBackendInterface(outputDir, superCallsMap)
5856
).run(ctx.compilationUnit.tpdTree)
5957

6058

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Names.TermName, StdNames._
99
import Types.{JavaArrayType, UnspecifiedErrorType, Type}
1010
import Symbols.{Symbol, NoSymbol}
1111
import dotc.report
12+
import dotc.util.ReadOnlyMap
1213

1314
import scala.annotation.threadUnsafe
1415
import scala.collection.immutable
@@ -34,7 +35,7 @@ import scala.collection.immutable
3435
class DottyPrimitives(ictx: Context) {
3536
import dotty.tools.backend.ScalaPrimitivesOps._
3637

37-
@threadUnsafe private lazy val primitives: immutable.Map[Symbol, Int] = init
38+
@threadUnsafe private lazy val primitives: ReadOnlyMap[Symbol, Int] = init
3839

3940
/** Return the code for the given symbol. */
4041
def getPrimitive(sym: Symbol): Int = {
@@ -118,12 +119,12 @@ class DottyPrimitives(ictx: Context) {
118119
}
119120

120121
/** Initialize the primitive map */
121-
private def init: immutable.Map[Symbol, Int] = {
122+
private def init: ReadOnlyMap[Symbol, Int] = {
122123

123124
given Context = ictx
124125

125126
import Symbols.defn
126-
val primitives = Symbols.newMutableSymbolMap[Int]
127+
val primitives = Symbols.MutableSymbolMap[Int](512)
127128

128129
/** Add a primitive operation to the map */
129130
def addPrimitive(s: Symbol, code: Int): Unit = {
@@ -394,7 +395,7 @@ class DottyPrimitives(ictx: Context) {
394395
addPrimitives(DoubleClass, nme.UNARY_-, NEG)
395396

396397

397-
primitives.toMap
398+
primitives
398399
}
399400

400401
def isPrimitive(sym: Symbol): Boolean =

compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Symbols._
1010
import dotty.tools.dotc.ast.tpd._
1111
import dotty.tools.backend.jvm.DottyPrimitives
1212
import dotty.tools.dotc.report
13+
import dotty.tools.dotc.util.ReadOnlyMap
1314

1415
import scala.collection.mutable
1516

@@ -55,7 +56,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
5556
import JSPrimitives._
5657
import dotty.tools.backend.ScalaPrimitivesOps._
5758

58-
private lazy val jsPrimitives: Map[Symbol, Int] = initJSPrimitives(using ictx)
59+
private lazy val jsPrimitives: ReadOnlyMap[Symbol, Int] = initJSPrimitives(using ictx)
5960

6061
override def getPrimitive(sym: Symbol): Int =
6162
jsPrimitives.getOrElse(sym, super.getPrimitive(sym))
@@ -70,9 +71,9 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
7071
jsPrimitives.contains(fun.symbol(using ictx)) || super.isPrimitive(fun)
7172

7273
/** Initialize the primitive map */
73-
private def initJSPrimitives(using Context): Map[Symbol, Int] = {
74+
private def initJSPrimitives(using Context): ReadOnlyMap[Symbol, Int] = {
7475

75-
val primitives = newMutableSymbolMap[Int]
76+
val primitives = MutableSymbolMap[Int]()
7677

7778
// !!! Code duplicate with DottyPrimitives
7879
/** Add a primitive operation to the map */
@@ -120,7 +121,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
120121
addPrimitive(jsdefn.ReflectSelectable_selectDynamic, REFLECT_SELECTABLE_SELECTDYN)
121122
addPrimitive(jsdefn.ReflectSelectable_applyDynamic, REFLECT_SELECTABLE_APPLYDYN)
122123

123-
primitives.toMap
124+
primitives
124125
}
125126

126127
}

compiler/src/dotty/tools/dotc/Compiler.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class Compiler {
109109
List(new Constructors, // Collect initialization code in primary constructors
110110
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
111111
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
112-
new Instrumentation) :: // Count closure allocations under -Yinstrument-closures
112+
new Instrumentation) :: // Count calls and allocations under -Yinstrument
113113
List(new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
114114
// Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
115115
new ElimStaticThis, // Replace `this` references to static objects by global identifiers

compiler/src/dotty/tools/dotc/Run.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import Periods._
77
import Symbols._
88
import Types._
99
import Scopes._
10+
import Names.Name
11+
import Denotations.Denotation
1012
import typer.Typer
1113
import typer.ImportInfo._
1214
import Decorators._
1315
import io.{AbstractFile, PlainFile}
1416
import Phases.unfusedPhases
1517

1618
import scala.io.Codec
17-
import util.{Set => _, _}
19+
import util._
1820
import reporting.Reporter
1921
import rewrites.Rewrites
2022
import java.io.{BufferedWriter, OutputStreamWriter}
@@ -116,6 +118,9 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
116118
/** The source files of all late entered symbols, as a set */
117119
private var lateFiles = mutable.Set[AbstractFile]()
118120

121+
/** A cache for static references to packages and classes */
122+
val staticRefs = util.EqHashMap[Name, Denotation](initialCapacity = 1024)
123+
119124
/** Actions that need to be performed at the end of the current compilation run */
120125
private var finalizeActions = mutable.ListBuffer[() => Unit]()
121126

compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package dotc.classpath
77
import java.net.URL
88
import scala.collection.mutable.ArrayBuffer
99
import scala.collection.immutable.ArraySeq
10+
import dotc.util
1011

1112
import dotty.tools.io.{ AbstractFile, ClassPath, ClassRepresentation, EfficientClassPath }
1213

@@ -107,7 +108,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
107108
private def mergeClassesAndSources(entries: scala.collection.Seq[ClassRepresentation]): Seq[ClassRepresentation] = {
108109
// based on the implementation from MergedClassPath
109110
var count = 0
110-
val indices = new collection.mutable.HashMap[String, Int]()
111+
val indices = util.HashMap[String, Int]()
111112
val mergedEntries = new ArrayBuffer[ClassRepresentation](entries.size)
112113
for {
113114
entry <- entries
@@ -132,7 +133,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
132133
}
133134

134135
private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Seq[EntryType]): Seq[EntryType] = {
135-
val seenNames = collection.mutable.HashSet[String]()
136+
val seenNames = util.HashSet[String]()
136137
val entriesBuffer = new ArrayBuffer[EntryType](1024)
137138
for {
138139
cp <- aggregates

compiler/src/dotty/tools/dotc/classpath/ZipAndJarFileLookupFactory.scala

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* Copyright (c) 2014 Contributor. All rights reserved.
33
*/
4-
package dotty.tools.dotc.classpath
4+
package dotty.tools.dotc
5+
package classpath
56

67
import java.io.File
78
import java.net.URL
@@ -12,6 +13,7 @@ import scala.annotation.tailrec
1213
import dotty.tools.io.{AbstractFile, ClassPath, ClassRepresentation, FileZipArchive, ManifestResources}
1314
import dotty.tools.dotc.core.Contexts._
1415
import FileUtils._
16+
import util._
1517

1618
/**
1719
* A trait providing an optional cache for classpath entries obtained from zip and jar files.
@@ -89,8 +91,8 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
8991
* when we need subpackages of a given package or its classes, we traverse once and cache only packages.
9092
* Classes for given package can be then easily loaded when they are needed.
9193
*/
92-
private lazy val cachedPackages: collection.mutable.HashMap[String, PackageFileInfo] = {
93-
val packages = collection.mutable.HashMap[String, PackageFileInfo]()
94+
private lazy val cachedPackages: util.HashMap[String, PackageFileInfo] = {
95+
val packages = util.HashMap[String, PackageFileInfo]()
9496

9597
def getSubpackages(dir: AbstractFile): List[AbstractFile] =
9698
(for (file <- dir if file.isPackage) yield file).toList
@@ -102,7 +104,7 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
102104
case pkgFile :: remainingFiles =>
103105
val subpackages = getSubpackages(pkgFile)
104106
val fullPkgName = packagePrefix + pkgFile.name
105-
packages.put(fullPkgName, PackageFileInfo(pkgFile, subpackages))
107+
packages(fullPkgName) = PackageFileInfo(pkgFile, subpackages)
106108
val newPackagePrefix = fullPkgName + "."
107109
subpackagesQueue.enqueue(PackageInfo(newPackagePrefix, subpackages))
108110
traverse(packagePrefix, remainingFiles, subpackagesQueue)
@@ -113,7 +115,7 @@ object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
113115
}
114116

115117
val subpackages = getSubpackages(file)
116-
packages.put(ClassPath.RootPackage, PackageFileInfo(file, subpackages))
118+
packages(ClassPath.RootPackage) = PackageFileInfo(file, subpackages)
117119
traverse(ClassPath.RootPackage, subpackages, collection.mutable.Queue())
118120
packages
119121
}

compiler/src/dotty/tools/dotc/config/Config.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ object Config {
181181
/** If set, enables tracing */
182182
inline val tracingEnabled = false
183183

184-
/** Initial capacity of uniques HashMap.
185-
* Note: This MUST BE a power of two to work with util.HashSet
184+
/** Initial capacity of the uniques HashMap.
185+
* Note: This should be a power of two to work with util.HashSet
186186
*/
187-
inline val initialUniquesCapacity = 65536
187+
inline val initialUniquesCapacity = 0x8000
188188

189189
/** How many recursive calls to NamedType#underlying are performed before logging starts. */
190190
inline val LogPendingUnderlyingThreshold = 50

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,7 @@ class ScalaSettings extends Settings.SettingGroup {
177177

178178
val YnoDecodeStacktraces: Setting[Boolean] = BooleanSetting("-Yno-decode-stacktraces", "Show raw StackOverflow stacktraces, instead of decoding them into triggering operations.")
179179

180-
val YinstrumentClosures: Setting[Boolean] = BooleanSetting("-Yinstrument-closures", "Add instrumentation code that counts closure creations.")
181-
val YinstrumentAllocations: Setting[Boolean] = BooleanSetting("-Yinstrument-allocations", "Add instrumentation code that counts allocations.")
180+
val Yinstrument: Setting[Boolean] = BooleanSetting("-Yinstrument", "Add instrumentation code that counts allocations and closure creations.")
182181

183182
/** Dottydoc specific settings */
184183
val siteRoot: Setting[String] = StringSetting(

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package core
44

55
import ast.{ untpd, tpd }
66
import Decorators._, Symbols._, Contexts._
7-
import util.SourceFile
7+
import util.{SourceFile, ReadOnlyMap}
88
import util.Spans._
99
import util.CommentParsing._
1010
import util.Property.Key
@@ -23,11 +23,11 @@ object Comments {
2323
*/
2424
class ContextDocstrings {
2525

26-
private val _docstrings: MutableSymbolMap[Comment] = newMutableSymbolMap
26+
private val _docstrings: MutableSymbolMap[Comment] = MutableSymbolMap[Comment](512) // FIXME: 2nd [Comment] needed or "not a class type"
2727

2828
val templateExpander: CommentExpander = new CommentExpander
2929

30-
def docstrings: Map[Symbol, Comment] = _docstrings.toMap
30+
def docstrings: ReadOnlyMap[Symbol, Comment] = _docstrings
3131

3232
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
3333

@@ -180,7 +180,7 @@ object Comments {
180180
protected def superComment(sym: Symbol)(using Context): Option[String] =
181181
allInheritedOverriddenSymbols(sym).iterator map (x => cookedDocComment(x)) find (_ != "")
182182

183-
private val cookedDocComments = newMutableSymbolMap[String]
183+
private val cookedDocComments = MutableSymbolMap[String]()
184184

185185
/** The raw doc comment of symbol `sym`, minus usecase and define sections, augmented by
186186
* missing sections of an inherited doc comment.

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

+13-24
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Uniques._
1414
import ast.Trees._
1515
import ast.untpd
1616
import Flags.GivenOrImplicit
17-
import util.{NoSource, SimpleIdentityMap, SourceFile}
17+
import util.{NoSource, SimpleIdentityMap, SourceFile, HashSet}
1818
import typer.{Implicits, ImportInfo, Inliner, SearchHistory, SearchRoot, TypeAssigner, Typer, Nullables}
1919
import Nullables.{NotNullInfo, given _}
2020
import Implicits.ContextualImplicits
@@ -289,7 +289,7 @@ object Contexts {
289289
private def lookup(key: Phase | SourceFile): Context =
290290
util.Stats.record("Context.related.lookup")
291291
if related == null then
292-
related = SimpleIdentityMap.Empty
292+
related = SimpleIdentityMap.empty
293293
null
294294
else
295295
related(key)
@@ -534,7 +534,7 @@ object Contexts {
534534
def settings: ScalaSettings = base.settings
535535
def definitions: Definitions = base.definitions
536536
def platform: Platform = base.platform
537-
def pendingUnderlying: mutable.HashSet[Type] = base.pendingUnderlying
537+
def pendingUnderlying: util.HashSet[Type] = base.pendingUnderlying
538538
def uniqueNamedTypes: Uniques.NamedTypeUniques = base.uniqueNamedTypes
539539
def uniques: util.HashSet[Type] = base.uniques
540540

@@ -838,30 +838,18 @@ object Contexts {
838838
def nextSymId: Int = { _nextSymId += 1; _nextSymId }
839839

840840
/** Sources that were loaded */
841-
val sources: mutable.HashMap[AbstractFile, SourceFile] = new mutable.HashMap[AbstractFile, SourceFile]
842-
val sourceNamed: mutable.HashMap[TermName, SourceFile] = new mutable.HashMap[TermName, SourceFile]
841+
val sources: util.HashMap[AbstractFile, SourceFile] = util.HashMap[AbstractFile, SourceFile]()
842+
val sourceNamed: util.HashMap[TermName, SourceFile] = util.HashMap[TermName, SourceFile]()
843843

844844
// Types state
845845
/** A table for hash consing unique types */
846-
private[core] val uniques: util.HashSet[Type] = new util.HashSet[Type](Config.initialUniquesCapacity) {
847-
override def hash(x: Type): Int = x.hash
848-
override def isEqual(x: Type, y: Type) = x.eql(y)
849-
}
846+
private[core] val uniques: Uniques = Uniques()
850847

851848
/** A table for hash consing unique applied types */
852-
private[dotc] val uniqueAppliedTypes: AppliedUniques = new AppliedUniques
849+
private[dotc] val uniqueAppliedTypes: AppliedUniques = AppliedUniques()
853850

854851
/** A table for hash consing unique named types */
855-
private[core] val uniqueNamedTypes: NamedTypeUniques = new NamedTypeUniques
856-
857-
private def uniqueSets = Map(
858-
"uniques" -> uniques,
859-
"uniqueAppliedTypes" -> uniqueAppliedTypes,
860-
"uniqueNamedTypes" -> uniqueNamedTypes)
861-
862-
/** A map that associates label and size of all uniques sets */
863-
def uniquesSizes: Map[String, (Int, Int, Int)] =
864-
uniqueSets.transform((_, s) => (s.size, s.accesses, s.misses))
852+
private[core] val uniqueNamedTypes: NamedTypeUniques = NamedTypeUniques()
865853

866854
var emptyTypeBounds: TypeBounds = null
867855
var emptyWildcardBounds: WildcardType = null
@@ -881,7 +869,7 @@ object Contexts {
881869

882870
/** The set of named types on which a currently active invocation
883871
* of underlying during a controlled operation exists. */
884-
private[core] val pendingUnderlying: mutable.HashSet[Type] = new mutable.HashSet[Type]
872+
private[core] val pendingUnderlying: util.HashSet[Type] = util.HashSet[Type]()
885873

886874
/** A map from ErrorType to associated message. We use this map
887875
* instead of storing messages directly in ErrorTypes in order
@@ -925,15 +913,16 @@ object Contexts {
925913
charArray = new Array[Char](charArray.length * 2)
926914
charArray
927915

928-
def reset(): Unit = {
929-
for ((_, set) <- uniqueSets) set.clear()
916+
def reset(): Unit =
917+
uniques.clear()
918+
uniqueAppliedTypes.clear()
919+
uniqueNamedTypes.clear()
930920
emptyTypeBounds = null
931921
emptyWildcardBounds = null
932922
errorTypeMsg.clear()
933923
sources.clear()
934924
sourceNamed.clear()
935925
comparers.clear() // forces re-evaluation of top and bottom classes in TypeComparer
936-
}
937926

938927
// Test that access is single threaded
939928

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@ class Definitions {
16031603
valueTypeEnc(sym2.asClass.name) % valueTypeEnc(sym1.asClass.name) == 0
16041604

16051605
@tu lazy val specialErasure: SimpleIdentityMap[Symbol, ClassSymbol] =
1606-
SimpleIdentityMap.Empty[Symbol]
1606+
SimpleIdentityMap.empty[Symbol]
16071607
.updated(AnyClass, ObjectClass)
16081608
.updated(AnyValClass, ObjectClass)
16091609
.updated(SingletonClass, ObjectClass)

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,8 @@ object Denotations {
12591259
}
12601260
recurSimple(path.length, wrap)
12611261
}
1262-
recur(path)
1262+
if ctx.run == null then recur(path)
1263+
else ctx.run.staticRefs.getOrElseUpdate(path, recur(path))
12631264
}
12641265

12651266

0 commit comments

Comments
 (0)