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
45
46
47 var zeroVal [abi.ZeroValSize]byte
48
49
50
51
52
53
54
55
56 func runtime_mapaccess1(typ *abi.MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
57 if race.Enabled && m != nil {
58 callerpc := sys.GetCallerPC()
59 pc := abi.FuncPCABIInternal(runtime_mapaccess1)
60 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
61 race.ReadObjectPC(typ.Key, key, callerpc, pc)
62 }
63 if msan.Enabled && m != nil {
64 msan.Read(key, typ.Key.Size_)
65 }
66 if asan.Enabled && m != nil {
67 asan.Read(key, typ.Key.Size_)
68 }
69
70 if m == nil || m.Used() == 0 {
71 if err := mapKeyError(typ, key); err != nil {
72 panic(err)
73 }
74 return unsafe.Pointer(&zeroVal[0])
75 }
76
77 if m.writing != 0 {
78 fatal("concurrent map read and map write")
79 }
80
81 hash := typ.Hasher(key, m.seed)
82
83 if m.dirLen <= 0 {
84 _, elem, ok := m.getWithKeySmall(typ, hash, key)
85 if !ok {
86 return unsafe.Pointer(&zeroVal[0])
87 }
88 return elem
89 }
90
91
92 idx := m.directoryIndex(hash)
93 t := m.directoryAt(idx)
94
95
96 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
97 h2Hash := h2(hash)
98 for ; ; seq = seq.next() {
99 g := t.groups.group(typ, seq.offset)
100
101 match := g.ctrls().matchH2(h2Hash)
102
103 for match != 0 {
104 i := match.first()
105
106 slotKey := g.key(typ, i)
107 slotKeyOrig := slotKey
108 if typ.IndirectKey() {
109 slotKey = *((*unsafe.Pointer)(slotKey))
110 }
111 if typ.Key.Equal(key, slotKey) {
112 slotElem := unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
113 if typ.IndirectElem() {
114 slotElem = *((*unsafe.Pointer)(slotElem))
115 }
116 return slotElem
117 }
118 match = match.removeFirst()
119 }
120
121 match = g.ctrls().matchEmpty()
122 if match != 0 {
123
124
125 return unsafe.Pointer(&zeroVal[0])
126 }
127 }
128 }
129
130
131 func runtime_mapaccess2(typ *abi.MapType, m *Map, key unsafe.Pointer) (unsafe.Pointer, bool) {
132 if race.Enabled && m != nil {
133 callerpc := sys.GetCallerPC()
134 pc := abi.FuncPCABIInternal(runtime_mapaccess1)
135 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
136 race.ReadObjectPC(typ.Key, key, callerpc, pc)
137 }
138 if msan.Enabled && m != nil {
139 msan.Read(key, typ.Key.Size_)
140 }
141 if asan.Enabled && m != nil {
142 asan.Read(key, typ.Key.Size_)
143 }
144
145 if m == nil || m.Used() == 0 {
146 if err := mapKeyError(typ, key); err != nil {
147 panic(err)
148 }
149 return unsafe.Pointer(&zeroVal[0]), false
150 }
151
152 if m.writing != 0 {
153 fatal("concurrent map read and map write")
154 }
155
156 hash := typ.Hasher(key, m.seed)
157
158 if m.dirLen == 0 {
159 _, elem, ok := m.getWithKeySmall(typ, hash, key)
160 if !ok {
161 return unsafe.Pointer(&zeroVal[0]), false
162 }
163 return elem, true
164 }
165
166
167 idx := m.directoryIndex(hash)
168 t := m.directoryAt(idx)
169
170
171 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
172 h2Hash := h2(hash)
173 for ; ; seq = seq.next() {
174 g := t.groups.group(typ, seq.offset)
175
176 match := g.ctrls().matchH2(h2Hash)
177
178 for match != 0 {
179 i := match.first()
180
181 slotKey := g.key(typ, i)
182 slotKeyOrig := slotKey
183 if typ.IndirectKey() {
184 slotKey = *((*unsafe.Pointer)(slotKey))
185 }
186 if typ.Key.Equal(key, slotKey) {
187 slotElem := unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
188 if typ.IndirectElem() {
189 slotElem = *((*unsafe.Pointer)(slotElem))
190 }
191 return slotElem, true
192 }
193 match = match.removeFirst()
194 }
195
196 match = g.ctrls().matchEmpty()
197 if match != 0 {
198
199
200 return unsafe.Pointer(&zeroVal[0]), false
201 }
202 }
203 }
204
205
206 func runtime_mapassign(typ *abi.MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
207 if m == nil {
208 panic(errNilAssign)
209 }
210 if race.Enabled {
211 callerpc := sys.GetCallerPC()
212 pc := abi.FuncPCABIInternal(runtime_mapassign)
213 race.WritePC(unsafe.Pointer(m), callerpc, pc)
214 race.ReadObjectPC(typ.Key, key, callerpc, pc)
215 }
216 if msan.Enabled {
217 msan.Read(key, typ.Key.Size_)
218 }
219 if asan.Enabled {
220 asan.Read(key, typ.Key.Size_)
221 }
222 if m.writing != 0 {
223 fatal("concurrent map writes")
224 }
225
226 hash := typ.Hasher(key, m.seed)
227
228
229
230 m.writing ^= 1
231
232 if m.dirPtr == nil {
233 m.growToSmall(typ)
234 }
235
236 if m.dirLen == 0 {
237 if m.used < abi.MapGroupSlots {
238 elem := m.putSlotSmall(typ, hash, key)
239
240 if m.writing == 0 {
241 fatal("concurrent map writes")
242 }
243 m.writing ^= 1
244
245 return elem
246 }
247
248
249 m.growToTable(typ)
250 }
251
252 var slotElem unsafe.Pointer
253 outer:
254 for {
255
256 idx := m.directoryIndex(hash)
257 t := m.directoryAt(idx)
258
259 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
260
261
262
263
264 var firstDeletedGroup groupReference
265 var firstDeletedSlot uintptr
266
267 h2Hash := h2(hash)
268 for ; ; seq = seq.next() {
269 g := t.groups.group(typ, seq.offset)
270 match := g.ctrls().matchH2(h2Hash)
271
272
273 for match != 0 {
274 i := match.first()
275
276 slotKey := g.key(typ, i)
277 slotKeyOrig := slotKey
278 if typ.IndirectKey() {
279 slotKey = *((*unsafe.Pointer)(slotKey))
280 }
281 if typ.Key.Equal(key, slotKey) {
282 if typ.NeedKeyUpdate() {
283 typedmemmove(typ.Key, slotKey, key)
284 }
285
286 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
287 if typ.IndirectElem() {
288 slotElem = *((*unsafe.Pointer)(slotElem))
289 }
290
291 t.checkInvariants(typ, m)
292 break outer
293 }
294 match = match.removeFirst()
295 }
296
297
298
299 match = g.ctrls().matchEmpty()
300 if match != 0 {
301
302
303
304 var i uintptr
305
306
307
308 if firstDeletedGroup.data != nil {
309 g = firstDeletedGroup
310 i = firstDeletedSlot
311 t.growthLeft++
312 } else {
313
314 i = match.first()
315 }
316
317
318 if t.growthLeft > 0 {
319 slotKey := g.key(typ, i)
320 slotKeyOrig := slotKey
321 if typ.IndirectKey() {
322 kmem := newobject(typ.Key)
323 *(*unsafe.Pointer)(slotKey) = kmem
324 slotKey = kmem
325 }
326 typedmemmove(typ.Key, slotKey, key)
327
328 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
329 if typ.IndirectElem() {
330 emem := newobject(typ.Elem)
331 *(*unsafe.Pointer)(slotElem) = emem
332 slotElem = emem
333 }
334
335 g.ctrls().set(i, ctrl(h2Hash))
336 t.growthLeft--
337 t.used++
338 m.used++
339
340 t.checkInvariants(typ, m)
341 break outer
342 }
343
344 t.rehash(typ, m)
345 continue outer
346 }
347
348
349
350
351
352
353 if firstDeletedGroup.data == nil {
354
355
356 match = g.ctrls().matchEmptyOrDeleted()
357 if match != 0 {
358 firstDeletedGroup = g
359 firstDeletedSlot = match.first()
360 }
361 }
362 }
363 }
364
365 if m.writing == 0 {
366 fatal("concurrent map writes")
367 }
368 m.writing ^= 1
369
370 return slotElem
371 }
372
View as plain text