Source file
src/runtime/hashmap_fast.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/sys"
9 "unsafe"
10 )
11
12 func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
13 if raceenabled && h != nil {
14 callerpc := getcallerpc()
15 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32))
16 }
17 if h == nil || h.count == 0 {
18 return unsafe.Pointer(&zeroVal[0])
19 }
20 if h.flags&hashWriting != 0 {
21 throw("concurrent map read and map write")
22 }
23 var b *bmap
24 if h.B == 0 {
25
26 b = (*bmap)(h.buckets)
27 } else {
28 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
29 m := bucketMask(h.B)
30 b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
31 if c := h.oldbuckets; c != nil {
32 if !h.sameSizeGrow() {
33
34 m >>= 1
35 }
36 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
37 if !evacuated(oldb) {
38 b = oldb
39 }
40 }
41 }
42 for ; b != nil; b = b.overflow(t) {
43 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) {
44 if *(*uint32)(k) == key && b.tophash[i] != empty {
45 return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
46 }
47 }
48 }
49 return unsafe.Pointer(&zeroVal[0])
50 }
51
52 func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
53 if raceenabled && h != nil {
54 callerpc := getcallerpc()
55 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32))
56 }
57 if h == nil || h.count == 0 {
58 return unsafe.Pointer(&zeroVal[0]), false
59 }
60 if h.flags&hashWriting != 0 {
61 throw("concurrent map read and map write")
62 }
63 var b *bmap
64 if h.B == 0 {
65
66 b = (*bmap)(h.buckets)
67 } else {
68 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
69 m := bucketMask(h.B)
70 b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
71 if c := h.oldbuckets; c != nil {
72 if !h.sameSizeGrow() {
73
74 m >>= 1
75 }
76 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
77 if !evacuated(oldb) {
78 b = oldb
79 }
80 }
81 }
82 for ; b != nil; b = b.overflow(t) {
83 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) {
84 if *(*uint32)(k) == key && b.tophash[i] != empty {
85 return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true
86 }
87 }
88 }
89 return unsafe.Pointer(&zeroVal[0]), false
90 }
91
92 func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
93 if raceenabled && h != nil {
94 callerpc := getcallerpc()
95 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64))
96 }
97 if h == nil || h.count == 0 {
98 return unsafe.Pointer(&zeroVal[0])
99 }
100 if h.flags&hashWriting != 0 {
101 throw("concurrent map read and map write")
102 }
103 var b *bmap
104 if h.B == 0 {
105
106 b = (*bmap)(h.buckets)
107 } else {
108 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
109 m := bucketMask(h.B)
110 b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
111 if c := h.oldbuckets; c != nil {
112 if !h.sameSizeGrow() {
113
114 m >>= 1
115 }
116 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
117 if !evacuated(oldb) {
118 b = oldb
119 }
120 }
121 }
122 for ; b != nil; b = b.overflow(t) {
123 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) {
124 if *(*uint64)(k) == key && b.tophash[i] != empty {
125 return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
126 }
127 }
128 }
129 return unsafe.Pointer(&zeroVal[0])
130 }
131
132 func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
133 if raceenabled && h != nil {
134 callerpc := getcallerpc()
135 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64))
136 }
137 if h == nil || h.count == 0 {
138 return unsafe.Pointer(&zeroVal[0]), false
139 }
140 if h.flags&hashWriting != 0 {
141 throw("concurrent map read and map write")
142 }
143 var b *bmap
144 if h.B == 0 {
145
146 b = (*bmap)(h.buckets)
147 } else {
148 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
149 m := bucketMask(h.B)
150 b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
151 if c := h.oldbuckets; c != nil {
152 if !h.sameSizeGrow() {
153
154 m >>= 1
155 }
156 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
157 if !evacuated(oldb) {
158 b = oldb
159 }
160 }
161 }
162 for ; b != nil; b = b.overflow(t) {
163 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) {
164 if *(*uint64)(k) == key && b.tophash[i] != empty {
165 return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true
166 }
167 }
168 }
169 return unsafe.Pointer(&zeroVal[0]), false
170 }
171
172 func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
173 if raceenabled && h != nil {
174 callerpc := getcallerpc()
175 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr))
176 }
177 if h == nil || h.count == 0 {
178 return unsafe.Pointer(&zeroVal[0])
179 }
180 if h.flags&hashWriting != 0 {
181 throw("concurrent map read and map write")
182 }
183 key := stringStructOf(&ky)
184 if h.B == 0 {
185
186 b := (*bmap)(h.buckets)
187 if key.len < 32 {
188
189 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
190 k := (*stringStruct)(kptr)
191 if k.len != key.len || b.tophash[i] == empty {
192 continue
193 }
194 if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
195 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
196 }
197 }
198 return unsafe.Pointer(&zeroVal[0])
199 }
200
201 keymaybe := uintptr(bucketCnt)
202 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
203 k := (*stringStruct)(kptr)
204 if k.len != key.len || b.tophash[i] == empty {
205 continue
206 }
207 if k.str == key.str {
208 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
209 }
210
211 if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
212 continue
213 }
214
215 if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) {
216 continue
217 }
218 if keymaybe != bucketCnt {
219
220 goto dohash
221 }
222 keymaybe = i
223 }
224 if keymaybe != bucketCnt {
225 k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
226 if memequal(k.str, key.str, uintptr(key.len)) {
227 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize))
228 }
229 }
230 return unsafe.Pointer(&zeroVal[0])
231 }
232 dohash:
233 hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
234 m := bucketMask(h.B)
235 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
236 if c := h.oldbuckets; c != nil {
237 if !h.sameSizeGrow() {
238
239 m >>= 1
240 }
241 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
242 if !evacuated(oldb) {
243 b = oldb
244 }
245 }
246 top := tophash(hash)
247 for ; b != nil; b = b.overflow(t) {
248 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
249 k := (*stringStruct)(kptr)
250 if k.len != key.len || b.tophash[i] != top {
251 continue
252 }
253 if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
254 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
255 }
256 }
257 }
258 return unsafe.Pointer(&zeroVal[0])
259 }
260
261 func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
262 if raceenabled && h != nil {
263 callerpc := getcallerpc()
264 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr))
265 }
266 if h == nil || h.count == 0 {
267 return unsafe.Pointer(&zeroVal[0]), false
268 }
269 if h.flags&hashWriting != 0 {
270 throw("concurrent map read and map write")
271 }
272 key := stringStructOf(&ky)
273 if h.B == 0 {
274
275 b := (*bmap)(h.buckets)
276 if key.len < 32 {
277
278 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
279 k := (*stringStruct)(kptr)
280 if k.len != key.len || b.tophash[i] == empty {
281 continue
282 }
283 if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
284 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
285 }
286 }
287 return unsafe.Pointer(&zeroVal[0]), false
288 }
289
290 keymaybe := uintptr(bucketCnt)
291 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
292 k := (*stringStruct)(kptr)
293 if k.len != key.len || b.tophash[i] == empty {
294 continue
295 }
296 if k.str == key.str {
297 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
298 }
299
300 if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
301 continue
302 }
303
304 if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) {
305 continue
306 }
307 if keymaybe != bucketCnt {
308
309 goto dohash
310 }
311 keymaybe = i
312 }
313 if keymaybe != bucketCnt {
314 k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
315 if memequal(k.str, key.str, uintptr(key.len)) {
316 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true
317 }
318 }
319 return unsafe.Pointer(&zeroVal[0]), false
320 }
321 dohash:
322 hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
323 m := bucketMask(h.B)
324 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
325 if c := h.oldbuckets; c != nil {
326 if !h.sameSizeGrow() {
327
328 m >>= 1
329 }
330 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
331 if !evacuated(oldb) {
332 b = oldb
333 }
334 }
335 top := tophash(hash)
336 for ; b != nil; b = b.overflow(t) {
337 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
338 k := (*stringStruct)(kptr)
339 if k.len != key.len || b.tophash[i] != top {
340 continue
341 }
342 if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
343 return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
344 }
345 }
346 }
347 return unsafe.Pointer(&zeroVal[0]), false
348 }
349
350 func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
351 if h == nil {
352 panic(plainError("assignment to entry in nil map"))
353 }
354 if raceenabled {
355 callerpc := getcallerpc()
356 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32))
357 }
358 if h.flags&hashWriting != 0 {
359 throw("concurrent map writes")
360 }
361 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
362
363
364 h.flags |= hashWriting
365
366 if h.buckets == nil {
367 h.buckets = newobject(t.bucket)
368 }
369
370 again:
371 bucket := hash & bucketMask(h.B)
372 if h.growing() {
373 growWork_fast32(t, h, bucket)
374 }
375 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
376
377 var insertb *bmap
378 var inserti uintptr
379 var insertk unsafe.Pointer
380
381 for {
382 for i := uintptr(0); i < bucketCnt; i++ {
383 if b.tophash[i] == empty {
384 if insertb == nil {
385 inserti = i
386 insertb = b
387 }
388 continue
389 }
390 k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4)))
391 if k != key {
392 continue
393 }
394 inserti = i
395 insertb = b
396 goto done
397 }
398 ovf := b.overflow(t)
399 if ovf == nil {
400 break
401 }
402 b = ovf
403 }
404
405
406
407
408
409 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
410 hashGrow(t, h)
411 goto again
412 }
413
414 if insertb == nil {
415
416 insertb = h.newoverflow(t, b)
417 inserti = 0
418 }
419 insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash)
420
421 insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4)
422
423 *(*uint32)(insertk) = key
424
425 h.count++
426
427 done:
428 val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.valuesize))
429 if h.flags&hashWriting == 0 {
430 throw("concurrent map writes")
431 }
432 h.flags &^= hashWriting
433 return val
434 }
435
436 func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
437 if h == nil {
438 panic(plainError("assignment to entry in nil map"))
439 }
440 if raceenabled {
441 callerpc := getcallerpc()
442 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32))
443 }
444 if h.flags&hashWriting != 0 {
445 throw("concurrent map writes")
446 }
447 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
448
449
450 h.flags |= hashWriting
451
452 if h.buckets == nil {
453 h.buckets = newobject(t.bucket)
454 }
455
456 again:
457 bucket := hash & bucketMask(h.B)
458 if h.growing() {
459 growWork_fast32(t, h, bucket)
460 }
461 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
462
463 var insertb *bmap
464 var inserti uintptr
465 var insertk unsafe.Pointer
466
467 for {
468 for i := uintptr(0); i < bucketCnt; i++ {
469 if b.tophash[i] == empty {
470 if insertb == nil {
471 inserti = i
472 insertb = b
473 }
474 continue
475 }
476 k := *((*unsafe.Pointer)(add(unsafe.Pointer(b), dataOffset+i*4)))
477 if k != key {
478 continue
479 }
480 inserti = i
481 insertb = b
482 goto done
483 }
484 ovf := b.overflow(t)
485 if ovf == nil {
486 break
487 }
488 b = ovf
489 }
490
491
492
493
494
495 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
496 hashGrow(t, h)
497 goto again
498 }
499
500 if insertb == nil {
501
502 insertb = h.newoverflow(t, b)
503 inserti = 0
504 }
505 insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash)
506
507 insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4)
508
509 *(*unsafe.Pointer)(insertk) = key
510
511 h.count++
512
513 done:
514 val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.valuesize))
515 if h.flags&hashWriting == 0 {
516 throw("concurrent map writes")
517 }
518 h.flags &^= hashWriting
519 return val
520 }
521
522 func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
523 if h == nil {
524 panic(plainError("assignment to entry in nil map"))
525 }
526 if raceenabled {
527 callerpc := getcallerpc()
528 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64))
529 }
530 if h.flags&hashWriting != 0 {
531 throw("concurrent map writes")
532 }
533 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
534
535
536 h.flags |= hashWriting
537
538 if h.buckets == nil {
539 h.buckets = newobject(t.bucket)
540 }
541
542 again:
543 bucket := hash & bucketMask(h.B)
544 if h.growing() {
545 growWork_fast64(t, h, bucket)
546 }
547 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
548
549 var insertb *bmap
550 var inserti uintptr
551 var insertk unsafe.Pointer
552
553 for {
554 for i := uintptr(0); i < bucketCnt; i++ {
555 if b.tophash[i] == empty {
556 if insertb == nil {
557 insertb = b
558 inserti = i
559 }
560 continue
561 }
562 k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8)))
563 if k != key {
564 continue
565 }
566 insertb = b
567 inserti = i
568 goto done
569 }
570 ovf := b.overflow(t)
571 if ovf == nil {
572 break
573 }
574 b = ovf
575 }
576
577
578
579
580
581 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
582 hashGrow(t, h)
583 goto again
584 }
585
586 if insertb == nil {
587
588 insertb = h.newoverflow(t, b)
589 inserti = 0
590 }
591 insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash)
592
593 insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8)
594
595 *(*uint64)(insertk) = key
596
597 h.count++
598
599 done:
600 val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.valuesize))
601 if h.flags&hashWriting == 0 {
602 throw("concurrent map writes")
603 }
604 h.flags &^= hashWriting
605 return val
606 }
607
608 func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
609 if h == nil {
610 panic(plainError("assignment to entry in nil map"))
611 }
612 if raceenabled {
613 callerpc := getcallerpc()
614 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64))
615 }
616 if h.flags&hashWriting != 0 {
617 throw("concurrent map writes")
618 }
619 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
620
621
622 h.flags |= hashWriting
623
624 if h.buckets == nil {
625 h.buckets = newobject(t.bucket)
626 }
627
628 again:
629 bucket := hash & bucketMask(h.B)
630 if h.growing() {
631 growWork_fast64(t, h, bucket)
632 }
633 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
634
635 var insertb *bmap
636 var inserti uintptr
637 var insertk unsafe.Pointer
638
639 for {
640 for i := uintptr(0); i < bucketCnt; i++ {
641 if b.tophash[i] == empty {
642 if insertb == nil {
643 insertb = b
644 inserti = i
645 }
646 continue
647 }
648 k := *((*unsafe.Pointer)(add(unsafe.Pointer(b), dataOffset+i*8)))
649 if k != key {
650 continue
651 }
652 insertb = b
653 inserti = i
654 goto done
655 }
656 ovf := b.overflow(t)
657 if ovf == nil {
658 break
659 }
660 b = ovf
661 }
662
663
664
665
666
667 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
668 hashGrow(t, h)
669 goto again
670 }
671
672 if insertb == nil {
673
674 insertb = h.newoverflow(t, b)
675 inserti = 0
676 }
677 insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash)
678
679 insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8)
680
681 *(*unsafe.Pointer)(insertk) = key
682
683 h.count++
684
685 done:
686 val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.valuesize))
687 if h.flags&hashWriting == 0 {
688 throw("concurrent map writes")
689 }
690 h.flags &^= hashWriting
691 return val
692 }
693
694 func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer {
695 if h == nil {
696 panic(plainError("assignment to entry in nil map"))
697 }
698 if raceenabled {
699 callerpc := getcallerpc()
700 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_faststr))
701 }
702 if h.flags&hashWriting != 0 {
703 throw("concurrent map writes")
704 }
705 key := stringStructOf(&s)
706 hash := t.key.alg.hash(noescape(unsafe.Pointer(&s)), uintptr(h.hash0))
707
708
709 h.flags |= hashWriting
710
711 if h.buckets == nil {
712 h.buckets = newobject(t.bucket)
713 }
714
715 again:
716 bucket := hash & bucketMask(h.B)
717 if h.growing() {
718 growWork_faststr(t, h, bucket)
719 }
720 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
721 top := tophash(hash)
722
723 var insertb *bmap
724 var inserti uintptr
725 var insertk unsafe.Pointer
726
727 for {
728 for i := uintptr(0); i < bucketCnt; i++ {
729 if b.tophash[i] != top {
730 if b.tophash[i] == empty && insertb == nil {
731 insertb = b
732 inserti = i
733 }
734 continue
735 }
736 k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
737 if k.len != key.len {
738 continue
739 }
740 if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) {
741 continue
742 }
743
744 inserti = i
745 insertb = b
746 goto done
747 }
748 ovf := b.overflow(t)
749 if ovf == nil {
750 break
751 }
752 b = ovf
753 }
754
755
756
757
758
759 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
760 hashGrow(t, h)
761 goto again
762 }
763
764 if insertb == nil {
765
766 insertb = h.newoverflow(t, b)
767 inserti = 0
768 }
769 insertb.tophash[inserti&(bucketCnt-1)] = top
770
771 insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*sys.PtrSize)
772
773 *((*stringStruct)(insertk)) = *key
774 h.count++
775
776 done:
777 val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*sys.PtrSize+inserti*uintptr(t.valuesize))
778 if h.flags&hashWriting == 0 {
779 throw("concurrent map writes")
780 }
781 h.flags &^= hashWriting
782 return val
783 }
784
785 func mapdelete_fast32(t *maptype, h *hmap, key uint32) {
786 if raceenabled && h != nil {
787 callerpc := getcallerpc()
788 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast32))
789 }
790 if h == nil || h.count == 0 {
791 return
792 }
793 if h.flags&hashWriting != 0 {
794 throw("concurrent map writes")
795 }
796
797 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
798
799
800 h.flags |= hashWriting
801
802 bucket := hash & bucketMask(h.B)
803 if h.growing() {
804 growWork_fast32(t, h, bucket)
805 }
806 b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
807 search:
808 for ; b != nil; b = b.overflow(t) {
809 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) {
810 if key != *(*uint32)(k) || b.tophash[i] == empty {
811 continue
812 }
813
814 if t.key.kind&kindNoPointers == 0 {
815 memclrHasPointers(k, t.key.size)
816 }
817
818 if t.elem.kind&kindNoPointers == 0 {
819 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
820 memclrHasPointers(v, t.elem.size)
821 }
822 b.tophash[i] = empty
823 h.count--
824 break search
825 }
826 }
827
828 if h.flags&hashWriting == 0 {
829 throw("concurrent map writes")
830 }
831 h.flags &^= hashWriting
832 }
833
834 func mapdelete_fast64(t *maptype, h *hmap, key uint64) {
835 if raceenabled && h != nil {
836 callerpc := getcallerpc()
837 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast64))
838 }
839 if h == nil || h.count == 0 {
840 return
841 }
842 if h.flags&hashWriting != 0 {
843 throw("concurrent map writes")
844 }
845
846 hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
847
848
849 h.flags |= hashWriting
850
851 bucket := hash & bucketMask(h.B)
852 if h.growing() {
853 growWork_fast64(t, h, bucket)
854 }
855 b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
856 search:
857 for ; b != nil; b = b.overflow(t) {
858 for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) {
859 if key != *(*uint64)(k) || b.tophash[i] == empty {
860 continue
861 }
862
863 if t.key.kind&kindNoPointers == 0 {
864 memclrHasPointers(k, t.key.size)
865 }
866
867 if t.elem.kind&kindNoPointers == 0 {
868 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
869 memclrHasPointers(v, t.elem.size)
870 }
871 b.tophash[i] = empty
872 h.count--
873 break search
874 }
875 }
876
877 if h.flags&hashWriting == 0 {
878 throw("concurrent map writes")
879 }
880 h.flags &^= hashWriting
881 }
882
883 func mapdelete_faststr(t *maptype, h *hmap, ky string) {
884 if raceenabled && h != nil {
885 callerpc := getcallerpc()
886 racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_faststr))
887 }
888 if h == nil || h.count == 0 {
889 return
890 }
891 if h.flags&hashWriting != 0 {
892 throw("concurrent map writes")
893 }
894
895 key := stringStructOf(&ky)
896 hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
897
898
899 h.flags |= hashWriting
900
901 bucket := hash & bucketMask(h.B)
902 if h.growing() {
903 growWork_faststr(t, h, bucket)
904 }
905 b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
906 top := tophash(hash)
907 search:
908 for ; b != nil; b = b.overflow(t) {
909 for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
910 k := (*stringStruct)(kptr)
911 if k.len != key.len || b.tophash[i] != top {
912 continue
913 }
914 if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) {
915 continue
916 }
917
918 k.str = nil
919
920 if t.elem.kind&kindNoPointers == 0 {
921 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
922 memclrHasPointers(v, t.elem.size)
923 }
924 b.tophash[i] = empty
925 h.count--
926 break search
927 }
928 }
929
930 if h.flags&hashWriting == 0 {
931 throw("concurrent map writes")
932 }
933 h.flags &^= hashWriting
934 }
935
936 func growWork_fast32(t *maptype, h *hmap, bucket uintptr) {
937
938
939 evacuate_fast32(t, h, bucket&h.oldbucketmask())
940
941
942 if h.growing() {
943 evacuate_fast32(t, h, h.nevacuate)
944 }
945 }
946
947 func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) {
948 b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
949 newbit := h.noldbuckets()
950 if !evacuated(b) {
951
952
953
954
955 var xy [2]evacDst
956 x := &xy[0]
957 x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
958 x.k = add(unsafe.Pointer(x.b), dataOffset)
959 x.v = add(x.k, bucketCnt*4)
960
961 if !h.sameSizeGrow() {
962
963
964 y := &xy[1]
965 y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
966 y.k = add(unsafe.Pointer(y.b), dataOffset)
967 y.v = add(y.k, bucketCnt*4)
968 }
969
970 for ; b != nil; b = b.overflow(t) {
971 k := add(unsafe.Pointer(b), dataOffset)
972 v := add(k, bucketCnt*4)
973 for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 4), add(v, uintptr(t.valuesize)) {
974 top := b.tophash[i]
975 if top == empty {
976 b.tophash[i] = evacuatedEmpty
977 continue
978 }
979 if top < minTopHash {
980 throw("bad map state")
981 }
982 var useY uint8
983 if !h.sameSizeGrow() {
984
985
986 hash := t.key.alg.hash(k, uintptr(h.hash0))
987 if hash&newbit != 0 {
988 useY = 1
989 }
990 }
991
992 b.tophash[i] = evacuatedX + useY
993 dst := &xy[useY]
994
995 if dst.i == bucketCnt {
996 dst.b = h.newoverflow(t, dst.b)
997 dst.i = 0
998 dst.k = add(unsafe.Pointer(dst.b), dataOffset)
999 dst.v = add(dst.k, bucketCnt*4)
1000 }
1001 dst.b.tophash[dst.i&(bucketCnt-1)] = top
1002
1003
1004 if sys.PtrSize == 4 && t.key.kind&kindNoPointers == 0 && writeBarrier.enabled {
1005 writebarrierptr((*uintptr)(dst.k), *(*uintptr)(k))
1006 } else {
1007 *(*uint32)(dst.k) = *(*uint32)(k)
1008 }
1009
1010 typedmemmove(t.elem, dst.v, v)
1011 dst.i++
1012
1013
1014
1015
1016 dst.k = add(dst.k, 4)
1017 dst.v = add(dst.v, uintptr(t.valuesize))
1018 }
1019 }
1020
1021 if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 {
1022 b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))
1023
1024
1025 ptr := add(b, dataOffset)
1026 n := uintptr(t.bucketsize) - dataOffset
1027 memclrHasPointers(ptr, n)
1028 }
1029 }
1030
1031 if oldbucket == h.nevacuate {
1032 advanceEvacuationMark(h, t, newbit)
1033 }
1034 }
1035
1036 func growWork_fast64(t *maptype, h *hmap, bucket uintptr) {
1037
1038
1039 evacuate_fast64(t, h, bucket&h.oldbucketmask())
1040
1041
1042 if h.growing() {
1043 evacuate_fast64(t, h, h.nevacuate)
1044 }
1045 }
1046
1047 func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) {
1048 b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
1049 newbit := h.noldbuckets()
1050 if !evacuated(b) {
1051
1052
1053
1054
1055 var xy [2]evacDst
1056 x := &xy[0]
1057 x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
1058 x.k = add(unsafe.Pointer(x.b), dataOffset)
1059 x.v = add(x.k, bucketCnt*8)
1060
1061 if !h.sameSizeGrow() {
1062
1063
1064 y := &xy[1]
1065 y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
1066 y.k = add(unsafe.Pointer(y.b), dataOffset)
1067 y.v = add(y.k, bucketCnt*8)
1068 }
1069
1070 for ; b != nil; b = b.overflow(t) {
1071 k := add(unsafe.Pointer(b), dataOffset)
1072 v := add(k, bucketCnt*8)
1073 for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 8), add(v, uintptr(t.valuesize)) {
1074 top := b.tophash[i]
1075 if top == empty {
1076 b.tophash[i] = evacuatedEmpty
1077 continue
1078 }
1079 if top < minTopHash {
1080 throw("bad map state")
1081 }
1082 var useY uint8
1083 if !h.sameSizeGrow() {
1084
1085
1086 hash := t.key.alg.hash(k, uintptr(h.hash0))
1087 if hash&newbit != 0 {
1088 useY = 1
1089 }
1090 }
1091
1092 b.tophash[i] = evacuatedX + useY
1093 dst := &xy[useY]
1094
1095 if dst.i == bucketCnt {
1096 dst.b = h.newoverflow(t, dst.b)
1097 dst.i = 0
1098 dst.k = add(unsafe.Pointer(dst.b), dataOffset)
1099 dst.v = add(dst.k, bucketCnt*8)
1100 }
1101 dst.b.tophash[dst.i&(bucketCnt-1)] = top
1102
1103
1104 if t.key.kind&kindNoPointers == 0 && writeBarrier.enabled {
1105 if sys.PtrSize == 8 {
1106 writebarrierptr((*uintptr)(dst.k), *(*uintptr)(k))
1107 } else {
1108
1109
1110 typedmemmove(t.key, dst.k, k)
1111 }
1112 } else {
1113 *(*uint64)(dst.k) = *(*uint64)(k)
1114 }
1115
1116 typedmemmove(t.elem, dst.v, v)
1117 dst.i++
1118
1119
1120
1121
1122 dst.k = add(dst.k, 8)
1123 dst.v = add(dst.v, uintptr(t.valuesize))
1124 }
1125 }
1126
1127 if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 {
1128 b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))
1129
1130
1131 ptr := add(b, dataOffset)
1132 n := uintptr(t.bucketsize) - dataOffset
1133 memclrHasPointers(ptr, n)
1134 }
1135 }
1136
1137 if oldbucket == h.nevacuate {
1138 advanceEvacuationMark(h, t, newbit)
1139 }
1140 }
1141
1142 func growWork_faststr(t *maptype, h *hmap, bucket uintptr) {
1143
1144
1145 evacuate_faststr(t, h, bucket&h.oldbucketmask())
1146
1147
1148 if h.growing() {
1149 evacuate_faststr(t, h, h.nevacuate)
1150 }
1151 }
1152
1153 func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) {
1154 b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
1155 newbit := h.noldbuckets()
1156 if !evacuated(b) {
1157
1158
1159
1160
1161 var xy [2]evacDst
1162 x := &xy[0]
1163 x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
1164 x.k = add(unsafe.Pointer(x.b), dataOffset)
1165 x.v = add(x.k, bucketCnt*2*sys.PtrSize)
1166
1167 if !h.sameSizeGrow() {
1168
1169
1170 y := &xy[1]
1171 y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
1172 y.k = add(unsafe.Pointer(y.b), dataOffset)
1173 y.v = add(y.k, bucketCnt*2*sys.PtrSize)
1174 }
1175
1176 for ; b != nil; b = b.overflow(t) {
1177 k := add(unsafe.Pointer(b), dataOffset)
1178 v := add(k, bucketCnt*2*sys.PtrSize)
1179 for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 2*sys.PtrSize), add(v, uintptr(t.valuesize)) {
1180 top := b.tophash[i]
1181 if top == empty {
1182 b.tophash[i] = evacuatedEmpty
1183 continue
1184 }
1185 if top < minTopHash {
1186 throw("bad map state")
1187 }
1188 var useY uint8
1189 if !h.sameSizeGrow() {
1190
1191
1192 hash := t.key.alg.hash(k, uintptr(h.hash0))
1193 if hash&newbit != 0 {
1194 useY = 1
1195 }
1196 }
1197
1198 b.tophash[i] = evacuatedX + useY
1199 dst := &xy[useY]
1200
1201 if dst.i == bucketCnt {
1202 dst.b = h.newoverflow(t, dst.b)
1203 dst.i = 0
1204 dst.k = add(unsafe.Pointer(dst.b), dataOffset)
1205 dst.v = add(dst.k, bucketCnt*2*sys.PtrSize)
1206 }
1207 dst.b.tophash[dst.i&(bucketCnt-1)] = top
1208
1209
1210 *(*string)(dst.k) = *(*string)(k)
1211
1212 typedmemmove(t.elem, dst.v, v)
1213 dst.i++
1214
1215
1216
1217
1218 dst.k = add(dst.k, 2*sys.PtrSize)
1219 dst.v = add(dst.v, uintptr(t.valuesize))
1220 }
1221 }
1222
1223
1224 if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 {
1225 b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))
1226
1227
1228 ptr := add(b, dataOffset)
1229 n := uintptr(t.bucketsize) - dataOffset
1230 memclrHasPointers(ptr, n)
1231 }
1232 }
1233
1234 if oldbucket == h.nevacuate {
1235 advanceEvacuationMark(h, t, newbit)
1236 }
1237 }
1238
View as plain text