Skip to content

Commit eb6bd31

Browse files
committed
Break out dual maps in Names#derived into its own LinearMap data type.
The reason for using a linear map instead of a mutable.Map here is that most derived instances are very small.
1 parent e64c4c1 commit eb6bd31

File tree

2 files changed

+52
-31
lines changed

2 files changed

+52
-31
lines changed

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

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import StdNames.str
1010
import scala.internal.Chars.isIdentifierStart
1111
import collection.immutable
1212
import config.Config
13-
import java.util.HashMap
13+
import util.LinearMap
1414

1515
import scala.annotation.internal.sharable
1616

@@ -182,38 +182,16 @@ object Names {
182182
def underlying: TermName = unsupported("underlying")
183183

184184
@sharable // because of synchronized block in `and`
185-
private var derivedNames: immutable.Map[NameInfo, DerivedName] | HashMap[NameInfo, DerivedName] =
186-
immutable.Map.empty[NameInfo, DerivedName]
187-
188-
private def getDerived(info: NameInfo): DerivedName /* | Null */ = (derivedNames: @unchecked) match {
189-
case derivedNames: immutable.AbstractMap[NameInfo, DerivedName] @unchecked =>
190-
if (derivedNames.contains(info)) derivedNames(info) else null
191-
case derivedNames: HashMap[NameInfo, DerivedName] @unchecked =>
192-
derivedNames.get(info)
193-
}
194-
195-
private def putDerived(info: NameInfo, name: DerivedName): name.type = {
196-
derivedNames match {
197-
case derivedNames: immutable.Map[NameInfo, DerivedName] @unchecked =>
198-
if (derivedNames.size < 4)
199-
this.derivedNames = derivedNames.updated(info, name)
200-
else {
201-
val newMap = new HashMap[NameInfo, DerivedName]
202-
derivedNames.foreach { case (k, v) => newMap.put(k, v) }
203-
newMap.put(info, name)
204-
this.derivedNames = newMap
205-
}
206-
case derivedNames: HashMap[NameInfo, DerivedName] @unchecked =>
207-
derivedNames.put(info, name)
208-
}
209-
name
210-
}
185+
private var derivedNames: LinearMap[NameInfo, DerivedName] = LinearMap.Empty
211186

212187
private def add(info: NameInfo): TermName = synchronized {
213-
getDerived(info) match {
214-
case null => putDerived(info, new DerivedName(this, info))
215-
case derivedName => derivedName
216-
}
188+
derivedNames(info) match
189+
case null =>
190+
val derivedName = new DerivedName(this, info)
191+
derivedNames = derivedNames.updated(info, derivedName)
192+
derivedName
193+
case derivedName =>
194+
derivedName
217195
}
218196

219197
private def rewrap(underlying: TermName) =
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dotty.tools.dotc.util
2+
3+
import collection.immutable
4+
5+
/** A linear map is a map where after an `updated` the previous map
6+
* value cannot be used anymore. The map is implemented as an immutable
7+
* map for sizes <= 4 (where immutable maps have specialized, compact
8+
* representations) and as a HashMap for larger sizes.
9+
*/
10+
opaque type LinearMap[K <: AnyRef, V >: Null <: AnyRef] =
11+
immutable.Map[K, V] | HashMap[K, V]
12+
13+
object LinearMap:
14+
15+
def Empty[K <: AnyRef, V >: Null <: AnyRef]: LinearMap[K, V] =
16+
immutable.Map.empty[K, V]
17+
18+
extension [K <: AnyRef, V >: Null <: AnyRef](m: LinearMap[K, V]):
19+
20+
def apply(key: K): V /*| Null*/ = m match
21+
case m: immutable.Map[K, V] @unchecked =>
22+
if m.contains(key) then m(key) else null
23+
case m: HashMap[K, V] @unchecked =>
24+
m.get(key)
25+
26+
def updated(key: K, value: V): LinearMap[K, V] = m match
27+
case m: immutable.Map[K, V] @unchecked =>
28+
if m.size < 4 then
29+
m.updated(key, value)
30+
else
31+
val m1 = HashMap[K, V]()
32+
m.foreach(m1.put(_, _))
33+
m1.put(key, value)
34+
m1
35+
case m: HashMap[K, V] @unchecked =>
36+
m.put(key, value)
37+
m
38+
39+
def size = m match
40+
case m: immutable.Map[K, V] @unchecked => m.size
41+
case m: HashMap[K, V] @unchecked => m.size
42+
43+
end LinearMap

0 commit comments

Comments
 (0)