Skip to content

Commit 5f0ed19

Browse files
committed
Optimize util.HashSet
Using "%" to find the index of an entry in the backing array is expensive, by restricting our backing array size to be a power of two we can use "&" instead. This is similar to what we do in the implementation of MutableScope (note: should we try to avoid code duplication between util.HashSet and MutableScope?).
1 parent 4bb0a1f commit 5f0ed19

File tree

3 files changed

+9
-7
lines changed

3 files changed

+9
-7
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,10 @@ object Config {
147147
/** Initial size of superId table */
148148
final val InitialSuperIdsSize = 4096
149149

150-
/** Initial capacity of uniques HashMap */
151-
final val initialUniquesCapacity = 40000
150+
/** Initial capacity of uniques HashMap.
151+
* Note: This MUST BE a power of two to work with util.HashSet
152+
*/
153+
final val initialUniquesCapacity = 65536
152154

153155
/** How many recursive calls to NamedType#underlying are performed before logging starts. */
154156
final val LogPendingUnderlyingThreshold = 50

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
131131

132132
/** a faster version of cs1 intersect cs2 */
133133
def intersect(cs1: List[ClassSymbol], cs2: List[ClassSymbol]): List[ClassSymbol] = {
134-
val cs2AsSet = new util.HashSet[ClassSymbol](100)
134+
val cs2AsSet = new util.HashSet[ClassSymbol](128)
135135
cs2.foreach(cs2AsSet.addEntry)
136136
cs1.filter(cs2AsSet.contains)
137137
}

compiler/src/dotty/tools/dotc/util/HashSet.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools.dotc.util
22

33
/** A hash set that allows some privileged protected access to its internals
44
*/
5-
class HashSet[T >: Null <: AnyRef](initialCapacity: Int, loadFactor: Float = 0.25f) extends Set[T] {
5+
class HashSet[T >: Null <: AnyRef](powerOfTwoInitialCapacity: Int, loadFactor: Float = 0.25f) extends Set[T] {
66
private var used: Int = _
77
private var limit: Int = _
88
private var table: Array[AnyRef] = _
@@ -20,11 +20,11 @@ class HashSet[T >: Null <: AnyRef](initialCapacity: Int, loadFactor: Float = 0.2
2020
/** Remove all elements from this set and set back to initial configuration */
2121
def clear(): Unit = {
2222
used = 0
23-
allocate(initialCapacity)
23+
allocate(powerOfTwoInitialCapacity)
2424
}
2525

26-
/** Turn hashode `x` into a table index */
27-
private def index(x: Int): Int = math.abs(x % table.length)
26+
/** Turn hashcode `x` into a table index */
27+
private def index(x: Int): Int = x & (table.length - 1)
2828

2929
/** Hashcode, can be overridden */
3030
def hash(x: T): Int = x.hashCode

0 commit comments

Comments
 (0)