1
2
3
4
5 package maps
6
7 import (
8 "internal/abi"
9 "internal/asan"
10 "internal/msan"
11 "internal/race"
12 "internal/runtime/sys"
13 "unsafe"
14 )
15
16
17
18
19 func fatal(s string)
20
21
22 func rand() uint64
23
24
25 func typedmemmove(typ *abi.Type, dst, src unsafe.Pointer)
26
27
28 func typedmemclr(typ *abi.Type, ptr unsafe.Pointer)
29
30
31 func newarray(typ *abi.Type, n int) unsafe.Pointer
32
33
34 func newobject(typ *abi.Type) unsafe.Pointer
35
36
37
38
39 var errNilAssign error
40
41
42
43
44 var zeroVal [abi.ZeroValSize]byte
45
46
47
48
49
50
51
52
53 func runtime_mapaccess1(typ *abi.MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
54 p, _ := runtime_mapaccess2(typ, m, key)
55 return p
56 }
57
58
59 func runtime_mapaccess2(typ *abi.MapType, m *Map, key unsafe.Pointer) (unsafe.Pointer, bool) {
60 if race.Enabled && m != nil {
61 callerpc := sys.GetCallerPC()
62 pc := abi.FuncPCABIInternal(runtime_mapaccess2)
63 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
64 race.ReadObjectPC(typ.Key, key, callerpc, pc)
65 }
66 if msan.Enabled && m != nil {
67 msan.Read(key, typ.Key.Size_)
68 }
69 if asan.Enabled && m != nil {
70 asan.Read(key, typ.Key.Size_)
71 }
72
73 if m == nil || m.Used() == 0 {
74 if err := mapKeyError(typ, key); err != nil {
75 panic(err)
76 }
77 return unsafe.Pointer(&zeroVal[0]), false
78 }
79
80 if m.writing != 0 {
81 fatal("concurrent map read and map write")
82 }
83
84 hash := typ.Hasher(key, m.seed)
85
86 if m.dirLen == 0 {
87 _, elem, ok := m.getWithKeySmall(typ, hash, key)
88 if !ok {
89 return unsafe.Pointer(&zeroVal[0]), false
90 }
91 return elem, true
92 }
93
94
95 idx := m.directoryIndex(hash)
96 t := m.directoryAt(idx)
97
98
99 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
100 h2Hash := h2(hash)
101 for ; ; seq = seq.next() {
102 g := t.groups.group(typ, seq.offset)
103
104 match := g.ctrls().matchH2(h2Hash)
105
106 for match != 0 {
107 i := match.first()
108
109 slotKey := g.key(typ, i)
110 slotKeyOrig := slotKey
111 if typ.IndirectKey() {
112 slotKey = *((*unsafe.Pointer)(slotKey))
113 }
114 if typ.Key.Equal(key, slotKey) {
115 slotElem := unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
116 if typ.IndirectElem() {
117 slotElem = *((*unsafe.Pointer)(slotElem))
118 }
119 return slotElem, true
120 }
121 match = match.removeFirst()
122 }
123
124 match = g.ctrls().matchEmpty()
125 if match != 0 {
126
127
128 return unsafe.Pointer(&zeroVal[0]), false
129 }
130 }
131 }
132
133
134 func runtime_mapassign(typ *abi.MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
135 if m == nil {
136 panic(errNilAssign)
137 }
138 if race.Enabled {
139 callerpc := sys.GetCallerPC()
140 pc := abi.FuncPCABIInternal(runtime_mapassign)
141 race.WritePC(unsafe.Pointer(m), callerpc, pc)
142 race.ReadObjectPC(typ.Key, key, callerpc, pc)
143 }
144 if msan.Enabled {
145 msan.Read(key, typ.Key.Size_)
146 }
147 if asan.Enabled {
148 asan.Read(key, typ.Key.Size_)
149 }
150 if m.writing != 0 {
151 fatal("concurrent map writes")
152 }
153
154 hash := typ.Hasher(key, m.seed)
155
156
157
158 m.writing ^= 1
159
160 if m.dirPtr == nil {
161 m.growToSmall(typ)
162 }
163
164 if m.dirLen == 0 {
165 if m.used < abi.MapGroupSlots {
166 elem := m.putSlotSmall(typ, hash, key)
167
168 if m.writing == 0 {
169 fatal("concurrent map writes")
170 }
171 m.writing ^= 1
172
173 return elem
174 }
175
176
177 m.growToTable(typ)
178 }
179
180 var slotElem unsafe.Pointer
181 outer:
182 for {
183
184 idx := m.directoryIndex(hash)
185 t := m.directoryAt(idx)
186
187 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
188
189
190
191
192 var firstDeletedGroup groupReference
193 var firstDeletedSlot uintptr
194
195 h2Hash := h2(hash)
196 for ; ; seq = seq.next() {
197 g := t.groups.group(typ, seq.offset)
198 match := g.ctrls().matchH2(h2Hash)
199
200
201 for match != 0 {
202 i := match.first()
203
204 slotKey := g.key(typ, i)
205 slotKeyOrig := slotKey
206 if typ.IndirectKey() {
207 slotKey = *((*unsafe.Pointer)(slotKey))
208 }
209 if typ.Key.Equal(key, slotKey) {
210 if typ.NeedKeyUpdate() {
211 typedmemmove(typ.Key, slotKey, key)
212 }
213
214 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
215 if typ.IndirectElem() {
216 slotElem = *((*unsafe.Pointer)(slotElem))
217 }
218
219 t.checkInvariants(typ, m)
220 break outer
221 }
222 match = match.removeFirst()
223 }
224
225
226
227 match = g.ctrls().matchEmpty()
228 if match != 0 {
229
230
231
232 var i uintptr
233
234
235
236 if firstDeletedGroup.data != nil {
237 g = firstDeletedGroup
238 i = firstDeletedSlot
239 t.growthLeft++
240 } else {
241
242 i = match.first()
243 }
244
245
246 if t.growthLeft > 0 {
247 slotKey := g.key(typ, i)
248 slotKeyOrig := slotKey
249 if typ.IndirectKey() {
250 kmem := newobject(typ.Key)
251 *(*unsafe.Pointer)(slotKey) = kmem
252 slotKey = kmem
253 }
254 typedmemmove(typ.Key, slotKey, key)
255
256 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
257 if typ.IndirectElem() {
258 emem := newobject(typ.Elem)
259 *(*unsafe.Pointer)(slotElem) = emem
260 slotElem = emem
261 }
262
263 g.ctrls().set(i, ctrl(h2Hash))
264 t.growthLeft--
265 t.used++
266 m.used++
267
268 t.checkInvariants(typ, m)
269 break outer
270 }
271
272 t.rehash(typ, m)
273 continue outer
274 }
275
276
277
278
279
280
281 if firstDeletedGroup.data == nil {
282
283
284 match = g.ctrls().matchEmptyOrDeleted()
285 if match != 0 {
286 firstDeletedGroup = g
287 firstDeletedSlot = match.first()
288 }
289 }
290 }
291 }
292
293 if m.writing == 0 {
294 fatal("concurrent map writes")
295 }
296 m.writing ^= 1
297
298 return slotElem
299 }
300
View as plain text