1
2
3
4
5 package maps
6
7 import (
8 "internal/abi"
9 "internal/goexperiment"
10 "internal/race"
11 "internal/runtime/sys"
12 "unsafe"
13 )
14
15
16 func runtime_mapaccess1_fast64(typ *abi.MapType, m *Map, key uint64) unsafe.Pointer {
17 p, _ := runtime_mapaccess2_fast64(typ, m, key)
18 return p
19 }
20
21
22 func runtime_mapaccess2_fast64(typ *abi.MapType, m *Map, key uint64) (unsafe.Pointer, bool) {
23 if race.Enabled && m != nil {
24 callerpc := sys.GetCallerPC()
25 pc := abi.FuncPCABIInternal(runtime_mapaccess2_fast64)
26 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
27 }
28
29 if m == nil || m.Used() == 0 {
30 return unsafe.Pointer(&zeroVal[0]), false
31 }
32
33 if m.writing != 0 {
34 fatal("concurrent map read and map write")
35 return nil, false
36 }
37
38 if m.dirLen == 0 {
39 g := groupReference{
40 data: m.dirPtr,
41 }
42 full := g.ctrls().matchFull()
43 slotKey := g.key(typ, 0)
44 var keyStride uintptr
45 if goexperiment.MapSplitGroup {
46 keyStride = 8
47 } else {
48 keyStride = typ.KeyStride
49 }
50 var i uintptr
51 for full != 0 {
52 if key == *(*uint64)(slotKey) && full.lowestSet() {
53 if goexperiment.MapSplitGroup {
54 return g.elem(typ, i), true
55 } else {
56 return unsafe.Pointer(uintptr(slotKey) + 8), true
57 }
58 }
59 slotKey = unsafe.Pointer(uintptr(slotKey) + keyStride)
60 full = full.shiftOutLowest()
61 i++
62 }
63 return unsafe.Pointer(&zeroVal[0]), false
64 }
65
66 var hash uintptr
67
68 if memHashAESImplemented && UseAeshash {
69 hash = memHash64AES(key, m.seed)
70 } else {
71 hash = memHash64Fallback(key, m.seed)
72 }
73
74
75 idx := m.directoryIndex(hash)
76 t := m.directoryAt(idx)
77
78
79 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
80
81 h2Hash := h2(hash)
82 for ; ; seq = seq.next() {
83 g := t.groups.group(typ, seq.offset)
84
85 match := g.ctrls().matchH2(h2Hash)
86
87 for match != 0 {
88 i := match.first()
89
90 slotKey := g.key(typ, i)
91 if key == *(*uint64)(slotKey) {
92 if goexperiment.MapSplitGroup {
93 return g.elem(typ, i), true
94 } else {
95 return unsafe.Pointer(uintptr(slotKey) + 8), true
96 }
97 }
98 match = match.removeFirst()
99 }
100
101 match = g.ctrls().matchEmpty()
102 if match != 0 {
103
104
105 return unsafe.Pointer(&zeroVal[0]), false
106 }
107 }
108 }
109
110 func (m *Map) putSlotSmallFast64(typ *abi.MapType, hash uintptr, key uint64) unsafe.Pointer {
111 g := groupReference{
112 data: m.dirPtr,
113 }
114
115 match := g.ctrls().matchH2(h2(hash))
116
117
118 for match != 0 {
119 i := match.first()
120
121 slotKey := g.key(typ, i)
122 if key == *(*uint64)(slotKey) {
123 slotElem := g.elem(typ, i)
124 return slotElem
125 }
126 match = match.removeFirst()
127 }
128
129
130
131
132 match = g.ctrls().matchEmptyOrDeleted()
133 if match == 0 {
134
135 return nil
136 }
137
138 i := match.first()
139
140 slotKey := g.key(typ, i)
141 *(*uint64)(slotKey) = key
142
143 slotElem := g.elem(typ, i)
144
145 g.ctrls().set(i, ctrl(h2(hash)))
146 m.used++
147
148 return slotElem
149 }
150
151 func (t *table) uncheckedPutSlotForAssignFast64(typ *abi.MapType, hash uintptr, key uint64) unsafe.Pointer {
152 if t.growthLeft == 0 {
153 panic("invariant failed: growthLeft is unexpectedly 0")
154 }
155
156
157
158
159
160 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
161 for ; ; seq = seq.next() {
162 g := t.groups.group(typ, seq.offset)
163
164 match := g.ctrls().matchEmptyOrDeleted()
165 if match != 0 {
166 i := match.first()
167
168 slotKey := g.key(typ, i)
169 *(*uint64)(slotKey) = key
170
171 slotElem := g.elem(typ, i)
172
173 t.growthLeft--
174 t.used++
175 g.ctrls().set(i, ctrl(h2(hash)))
176 return slotElem
177 }
178 }
179 }
180
181
182 func runtime_mapassign_fast64(typ *abi.MapType, m *Map, key uint64) unsafe.Pointer {
183 if m == nil {
184 panic(errNilAssign)
185 }
186 if race.Enabled {
187 callerpc := sys.GetCallerPC()
188 pc := abi.FuncPCABIInternal(runtime_mapassign_fast64)
189 race.WritePC(unsafe.Pointer(m), callerpc, pc)
190 }
191 if m.writing != 0 {
192 fatal("concurrent map writes")
193 }
194
195 var hash uintptr
196
197 if memHashAESImplemented && UseAeshash {
198 hash = memHash64AES(key, m.seed)
199 } else {
200 hash = memHash64Fallback(key, m.seed)
201 }
202
203
204
205 m.writing ^= 1
206
207 if m.dirPtr == nil {
208 m.growToSmall(typ)
209 }
210
211 if m.dirLen == 0 {
212 elem := m.putSlotSmallFast64(typ, hash, key)
213 if elem == nil {
214
215 tab := m.growToTable(typ)
216
217 elem = tab.uncheckedPutSlotForAssignFast64(typ, hash, key)
218 m.used++
219
220 tab.checkInvariants(typ, m)
221 }
222
223 if m.writing == 0 {
224 fatal("concurrent map writes")
225 }
226 m.writing ^= 1
227
228 return elem
229 }
230
231 var slotElem unsafe.Pointer
232 outer:
233 for {
234
235 idx := m.directoryIndex(hash)
236 t := m.directoryAt(idx)
237
238 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
239
240
241
242
243 var firstDeletedGroup groupReference
244 var firstDeletedSlot uintptr
245
246 h2Hash := h2(hash)
247 for ; ; seq = seq.next() {
248 g := t.groups.group(typ, seq.offset)
249 match := g.ctrls().matchH2(h2Hash)
250
251
252 for match != 0 {
253 i := match.first()
254
255 slotKey := g.key(typ, i)
256 if key == *(*uint64)(slotKey) {
257 slotElem = g.elem(typ, i)
258
259 t.checkInvariants(typ, m)
260 break outer
261 }
262 match = match.removeFirst()
263 }
264
265
266
267 match = g.ctrls().matchEmptyOrDeleted()
268 if match == 0 {
269 continue
270 }
271 i := match.first()
272 if g.ctrls().get(i) == ctrlDeleted {
273
274
275 if firstDeletedGroup.data == nil {
276 firstDeletedGroup = g
277 firstDeletedSlot = i
278 }
279 continue
280 }
281
282
283
284
285
286 if firstDeletedGroup.data != nil {
287 g = firstDeletedGroup
288 i = firstDeletedSlot
289 t.growthLeft++
290 }
291
292
293 if t.growthLeft == 0 {
294 t.pruneTombstones(typ, m)
295 }
296
297
298 if t.growthLeft > 0 {
299 slotKey := g.key(typ, i)
300 *(*uint64)(slotKey) = key
301
302 slotElem = g.elem(typ, i)
303
304 g.ctrls().set(i, ctrl(h2Hash))
305 t.growthLeft--
306 t.used++
307 m.used++
308
309 t.checkInvariants(typ, m)
310 break outer
311 }
312
313 t.rehash(typ, m)
314 continue outer
315 }
316 }
317
318 if m.writing == 0 {
319 fatal("concurrent map writes")
320 }
321 m.writing ^= 1
322
323 return slotElem
324 }
325
326 func (m *Map) putSlotSmallFastPtr(typ *abi.MapType, hash uintptr, key unsafe.Pointer) unsafe.Pointer {
327 g := groupReference{
328 data: m.dirPtr,
329 }
330
331 match := g.ctrls().matchH2(h2(hash))
332
333
334 for match != 0 {
335 i := match.first()
336
337 slotKey := g.key(typ, i)
338 if key == *(*unsafe.Pointer)(slotKey) {
339 slotElem := g.elem(typ, i)
340 return slotElem
341 }
342 match = match.removeFirst()
343 }
344
345
346
347
348 match = g.ctrls().matchEmptyOrDeleted()
349 if match == 0 {
350
351 return nil
352 }
353
354 i := match.first()
355
356 slotKey := g.key(typ, i)
357 *(*unsafe.Pointer)(slotKey) = key
358
359 slotElem := g.elem(typ, i)
360
361 g.ctrls().set(i, ctrl(h2(hash)))
362 m.used++
363
364 return slotElem
365 }
366
367 func (t *table) uncheckedPutSlotForAssignFastPtr(typ *abi.MapType, hash uintptr, key unsafe.Pointer) unsafe.Pointer {
368 if t.growthLeft == 0 {
369 panic("invariant failed: growthLeft is unexpectedly 0")
370 }
371
372
373
374
375
376 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
377 for ; ; seq = seq.next() {
378 g := t.groups.group(typ, seq.offset)
379
380 match := g.ctrls().matchEmptyOrDeleted()
381 if match != 0 {
382 i := match.first()
383
384 slotKey := g.key(typ, i)
385 *(*unsafe.Pointer)(slotKey) = key
386
387 slotElem := g.elem(typ, i)
388
389 t.growthLeft--
390 t.used++
391 g.ctrls().set(i, ctrl(h2(hash)))
392 return slotElem
393 }
394 }
395 }
396
397
398
399
400 func runtime_mapassign_fast64ptr(typ *abi.MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
401 if m == nil {
402 panic(errNilAssign)
403 }
404 if race.Enabled {
405 callerpc := sys.GetCallerPC()
406 pc := abi.FuncPCABIInternal(runtime_mapassign_fast64ptr)
407 race.WritePC(unsafe.Pointer(m), callerpc, pc)
408 }
409 if m.writing != 0 {
410 fatal("concurrent map writes")
411 }
412
413 var hash uintptr
414
415 if memHashAESImplemented && UseAeshash {
416 hash = memHash64AES(uint64((uintptr)(key)), m.seed)
417 } else {
418 hash = memHash64Fallback(uint64((uintptr)(key)), m.seed)
419 }
420
421
422
423 m.writing ^= 1
424
425 if m.dirPtr == nil {
426 m.growToSmall(typ)
427 }
428
429 if m.dirLen == 0 {
430 elem := m.putSlotSmallFastPtr(typ, hash, key)
431 if elem == nil {
432
433 tab := m.growToTable(typ)
434
435 elem = tab.uncheckedPutSlotForAssignFastPtr(typ, hash, key)
436 m.used++
437
438 tab.checkInvariants(typ, m)
439 }
440
441 if m.writing == 0 {
442 fatal("concurrent map writes")
443 }
444 m.writing ^= 1
445
446 return elem
447 }
448
449 var slotElem unsafe.Pointer
450 outer:
451 for {
452
453 idx := m.directoryIndex(hash)
454 t := m.directoryAt(idx)
455
456 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
457
458
459
460
461 var firstDeletedGroup groupReference
462 var firstDeletedSlot uintptr
463
464 h2Hash := h2(hash)
465 for ; ; seq = seq.next() {
466 g := t.groups.group(typ, seq.offset)
467 match := g.ctrls().matchH2(h2Hash)
468
469
470 for match != 0 {
471 i := match.first()
472
473 slotKey := g.key(typ, i)
474 if key == *(*unsafe.Pointer)(slotKey) {
475 slotElem = g.elem(typ, i)
476
477 t.checkInvariants(typ, m)
478 break outer
479 }
480 match = match.removeFirst()
481 }
482
483
484
485 match = g.ctrls().matchEmptyOrDeleted()
486 if match == 0 {
487 continue
488 }
489 i := match.first()
490 if g.ctrls().get(i) == ctrlDeleted {
491
492
493 if firstDeletedGroup.data == nil {
494 firstDeletedGroup = g
495 firstDeletedSlot = i
496 }
497 continue
498 }
499
500
501
502
503
504 if firstDeletedGroup.data != nil {
505 g = firstDeletedGroup
506 i = firstDeletedSlot
507 t.growthLeft++
508 }
509
510 if t.growthLeft == 0 {
511 t.pruneTombstones(typ, m)
512 }
513
514
515 if t.growthLeft > 0 {
516 slotKey := g.key(typ, i)
517 *(*unsafe.Pointer)(slotKey) = key
518
519 slotElem = g.elem(typ, i)
520
521 g.ctrls().set(i, ctrl(h2Hash))
522 t.growthLeft--
523 t.used++
524 m.used++
525
526 t.checkInvariants(typ, m)
527 break outer
528 }
529
530 t.rehash(typ, m)
531 continue outer
532 }
533 }
534
535 if m.writing == 0 {
536 fatal("concurrent map writes")
537 }
538 m.writing ^= 1
539
540 return slotElem
541 }
542
543
544 func runtime_mapdelete_fast64(typ *abi.MapType, m *Map, key uint64) {
545 if race.Enabled {
546 callerpc := sys.GetCallerPC()
547 pc := abi.FuncPCABIInternal(runtime_mapdelete_fast64)
548 race.WritePC(unsafe.Pointer(m), callerpc, pc)
549 }
550
551 if m == nil || m.Used() == 0 {
552 return
553 }
554
555 m.Delete(typ, abi.NoEscape(unsafe.Pointer(&key)))
556 }
557
View as plain text