1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package dotty.tools.dotc
package core
import Types._, Contexts._, util.Stats._, Hashable._, Names._
import config.Config
import util.HashSet
/** Defines operation `unique` for hash-consing types.
* Also defines specialized hash sets for hash consing uniques of a specific type.
* All sets offer a `enterIfNew` method which checks whether a type
* with the given parts exists already and creates a new one if not.
*/
object Uniques {
private def recordCaching(tp: Type): Unit = recordCaching(tp.hash, tp.getClass)
private def recordCaching(h: Int, clazz: Class[_]): Unit =
if (h == NotCached) {
record("uncached-types")
record(s"uncached: $clazz")
} else {
record("cached-types")
record(s"cached: $clazz")
}
def unique[T <: Type](tp: T)(implicit ctx: Context): T = {
if (monitored) recordCaching(tp)
if (tp.hash == NotCached) tp
else if (monitored) {
val size = ctx.uniques.size
val result = ctx.uniques.findEntryOrUpdate(tp).asInstanceOf[T]
if (ctx.uniques.size > size) record(s"fresh unique ${tp.getClass}")
result
} else ctx.uniques.findEntryOrUpdate(tp).asInstanceOf[T]
} /* !!! DEBUG
ensuring (
result => tp.toString == result.toString || {
println(s"cache mismatch; tp = $tp, cached = $result")
false
}
)
*/
final class NamedTypeUniques extends HashSet[NamedType](Config.initialUniquesCapacity) with Hashable {
override def hash(x: NamedType): Int = x.hash
private def findPrevious(h: Int, prefix: Type, name: Name): NamedType = {
var e = findEntryByHash(h)
while (e != null) {
if ((e.prefix eq prefix) && (e.name eq name)) return e
e = nextEntryByHash(h)
}
e
}
def enterIfNew(prefix: Type, name: Name): NamedType = {
val h = doHash(name, prefix)
if (monitored) recordCaching(h, classOf[CachedTermRef])
def newType =
if (name.isTypeName) new CachedTypeRef(prefix, name.asTypeName, h)
else new CachedTermRef(prefix, name.asTermName, h)
if (h == NotCached) newType
else {
val r = findPrevious(h, prefix, name)
if (r ne null) r else addEntryAfterScan(newType)
}
}
}
final class TypeAliasUniques extends HashSet[TypeAlias](Config.initialUniquesCapacity) with Hashable {
override def hash(x: TypeAlias): Int = x.hash
private def findPrevious(h: Int, alias: Type, variance: Int): TypeAlias = {
var e = findEntryByHash(h)
while (e != null) {
if ((e.alias eq alias) && (e.variance == variance)) return e
e = nextEntryByHash(h)
}
e
}
def enterIfNew(alias: Type, variance: Int): TypeAlias = {
val h = doHash(variance, alias)
if (monitored) recordCaching(h, classOf[TypeAlias])
def newAlias = new CachedTypeAlias(alias, variance, h)
if (h == NotCached) newAlias
else {
val r = findPrevious(h, alias, variance)
if (r ne null) r
else addEntryAfterScan(newAlias)
}
}
}
final class RefinedUniques extends HashSet[RefinedType](Config.initialUniquesCapacity) with Hashable {
override val hashSeed = classOf[CachedRefinedType].hashCode // some types start life as CachedRefinedTypes, need to have same hash seed
override def hash(x: RefinedType): Int = x.hash
private def findPrevious(h: Int, parent: Type, refinedName: Name, refinedInfo: Type): RefinedType = {
var e = findEntryByHash(h)
while (e != null) {
if ((e.parent eq parent) && (e.refinedName eq refinedName) && (e.refinedInfo eq refinedInfo))
return e
e = nextEntryByHash(h)
}
e
}
def enterIfNew(parent: Type, refinedName: Name, refinedInfo: Type): RefinedType = {
val h = doHash(refinedName, refinedInfo, parent)
def newType = new CachedRefinedType(parent, refinedName, refinedInfo, h)
if (monitored) recordCaching(h, classOf[CachedRefinedType])
if (h == NotCached) newType
else {
val r = findPrevious(h, parent, refinedName, refinedInfo)
if (r ne null) r else addEntryAfterScan(newType)
}
}
def enterIfNew(rt: RefinedType) = {
if (monitored) recordCaching(rt)
if (rt.hash == NotCached) rt
else {
val r = findPrevious(rt.hash, rt.parent, rt.refinedName, rt.refinedInfo)
if (r ne null) r else addEntryAfterScan(rt)
}
}
}
}
|