github.com/filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/runtime/hashmap.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 // This file contains the implementation of Go's map type. 8 // 9 // A map is just a hash table. The data is arranged 10 // into an array of buckets. Each bucket contains up to 11 // 8 key/value pairs. The low-order bits of the hash are 12 // used to select a bucket. Each bucket contains a few 13 // high-order bits of each hash to distinguish the entries 14 // within a single bucket. 15 // 16 // If more than 8 keys hash to a bucket, we chain on 17 // extra buckets. 18 // 19 // When the hashtable grows, we allocate a new array 20 // of buckets twice as big. Buckets are incrementally 21 // copied from the old bucket array to the new bucket array. 22 // 23 // Map iterators walk through the array of buckets and 24 // return the keys in walk order (bucket #, then overflow 25 // chain order, then bucket index). To maintain iteration 26 // semantics, we never move keys within their bucket (if 27 // we did, keys might be returned 0 or 2 times). When 28 // growing the table, iterators remain iterating through the 29 // old table and must check the new table if the bucket 30 // they are iterating through has been moved ("evacuated") 31 // to the new table. 32 33 // Picking loadFactor: too large and we have lots of overflow 34 // buckets, too small and we waste a lot of space. I wrote 35 // a simple program to check some stats for different loads: 36 // (64-bit, 8 byte keys and values) 37 // loadFactor %overflow bytes/entry hitprobe missprobe 38 // 4.00 2.13 20.77 3.00 4.00 39 // 4.50 4.05 17.30 3.25 4.50 40 // 5.00 6.85 14.77 3.50 5.00 41 // 5.50 10.55 12.94 3.75 5.50 42 // 6.00 15.27 11.67 4.00 6.00 43 // 6.50 20.90 10.79 4.25 6.50 44 // 7.00 27.14 10.15 4.50 7.00 45 // 7.50 34.03 9.73 4.75 7.50 46 // 8.00 41.10 9.40 5.00 8.00 47 // 48 // %overflow = percentage of buckets which have an overflow bucket 49 // bytes/entry = overhead bytes used per key/value pair 50 // hitprobe = # of entries to check when looking up a present key 51 // missprobe = # of entries to check when looking up an absent key 52 // 53 // Keep in mind this data is for maximally loaded tables, i.e. just 54 // before the table grows. Typical tables will be somewhat less loaded. 55 56 import ( 57 "runtime/internal/atomic" 58 "runtime/internal/sys" 59 "unsafe" 60 ) 61 62 const ( 63 // Maximum number of key/value pairs a bucket can hold. 64 bucketCntBits = 3 65 bucketCnt = 1 << bucketCntBits 66 67 // Maximum average load of a bucket that triggers growth is 6.5. 68 // Represent as loadFactorNum/loadFactDen, to allow integer math. 69 loadFactorNum = 13 70 loadFactorDen = 2 71 72 // Maximum key or value size to keep inline (instead of mallocing per element). 73 // Must fit in a uint8. 74 // Fast versions cannot handle big values - the cutoff size for 75 // fast versions in ../../cmd/internal/gc/walk.go must be at most this value. 76 maxKeySize = 128 77 maxValueSize = 128 78 79 // data offset should be the size of the bmap struct, but needs to be 80 // aligned correctly. For amd64p32 this means 64-bit alignment 81 // even though pointers are 32 bit. 82 dataOffset = unsafe.Offsetof(struct { 83 b bmap 84 v int64 85 }{}.v) 86 87 // Possible tophash values. We reserve a few possibilities for special marks. 88 // Each bucket (including its overflow buckets, if any) will have either all or none of its 89 // entries in the evacuated* states (except during the evacuate() method, which only happens 90 // during map writes and thus no one else can observe the map during that time). 91 empty = 0 // cell is empty 92 evacuatedEmpty = 1 // cell is empty, bucket is evacuated. 93 evacuatedX = 2 // key/value is valid. Entry has been evacuated to first half of larger table. 94 evacuatedY = 3 // same as above, but evacuated to second half of larger table. 95 minTopHash = 4 // minimum tophash for a normal filled cell. 96 97 // flags 98 iterator = 1 // there may be an iterator using buckets 99 oldIterator = 2 // there may be an iterator using oldbuckets 100 hashWriting = 4 // a goroutine is writing to the map 101 sameSizeGrow = 8 // the current map growth is to a new map of the same size 102 103 // sentinel bucket ID for iterator checks 104 noCheck = 1<<(8*sys.PtrSize) - 1 105 ) 106 107 // A header for a Go map. 108 type hmap struct { 109 // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and 110 // ../reflect/type.go. Don't change this structure without also changing that code! 111 count int // # live cells == size of map. Must be first (used by len() builtin) 112 flags uint8 113 B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) 114 noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details 115 hash0 uint32 // hash seed 116 117 buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. 118 oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing 119 nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) 120 121 extra *mapextra // optional fields 122 } 123 124 // mapextra holds fields that are not present on all maps. 125 type mapextra struct { 126 // If both key and value do not contain pointers and are inline, then we mark bucket 127 // type as containing no pointers. This avoids scanning such maps. 128 // However, bmap.overflow is a pointer. In order to keep overflow buckets 129 // alive, we store pointers to all overflow buckets in hmap.overflow. 130 // Overflow is used only if key and value do not contain pointers. 131 // overflow[0] contains overflow buckets for hmap.buckets. 132 // overflow[1] contains overflow buckets for hmap.oldbuckets. 133 // The indirection allows to store a pointer to the slice in hiter. 134 overflow [2]*[]*bmap 135 136 // nextOverflow holds a pointer to a free overflow bucket. 137 nextOverflow *bmap 138 } 139 140 // A bucket for a Go map. 141 type bmap struct { 142 // tophash generally contains the top byte of the hash value 143 // for each key in this bucket. If tophash[0] < minTopHash, 144 // tophash[0] is a bucket evacuation state instead. 145 tophash [bucketCnt]uint8 146 // Followed by bucketCnt keys and then bucketCnt values. 147 // NOTE: packing all the keys together and then all the values together makes the 148 // code a bit more complicated than alternating key/value/key/value/... but it allows 149 // us to eliminate padding which would be needed for, e.g., map[int64]int8. 150 // Followed by an overflow pointer. 151 } 152 153 // A hash iteration structure. 154 // If you modify hiter, also change cmd/internal/gc/reflect.go to indicate 155 // the layout of this structure. 156 type hiter struct { 157 key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go). 158 value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go). 159 t *maptype 160 h *hmap 161 buckets unsafe.Pointer // bucket ptr at hash_iter initialization time 162 bptr *bmap // current bucket 163 overflow [2]*[]*bmap // keeps overflow buckets alive 164 startBucket uintptr // bucket iteration started at 165 offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) 166 wrapped bool // already wrapped around from end of bucket array to beginning 167 B uint8 168 i uint8 169 bucket uintptr 170 checkBucket uintptr 171 } 172 173 // bucketShift returns 1<<b, optimized for code generation. 174 func bucketShift(b uint8) uintptr { 175 if sys.GoarchAmd64|sys.GoarchAmd64p32|sys.Goarch386 != 0 { 176 b &= sys.PtrSize*8 - 1 // help x86 archs remove shift overflow checks 177 } 178 return uintptr(1) << b 179 } 180 181 // bucketMask returns 1<<b - 1, optimized for code generation. 182 func bucketMask(b uint8) uintptr { 183 return bucketShift(b) - 1 184 } 185 186 // tophash calculates the tophash value for hash. 187 func tophash(hash uintptr) uint8 { 188 top := uint8(hash >> (sys.PtrSize*8 - 8)) 189 if top < minTopHash { 190 top += minTopHash 191 } 192 return top 193 } 194 195 func evacuated(b *bmap) bool { 196 h := b.tophash[0] 197 return h > empty && h < minTopHash 198 } 199 200 func (b *bmap) overflow(t *maptype) *bmap { 201 return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) 202 } 203 204 func (b *bmap) setoverflow(t *maptype, ovf *bmap) { 205 *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf 206 } 207 208 func (b *bmap) keys() unsafe.Pointer { 209 return add(unsafe.Pointer(b), dataOffset) 210 } 211 212 // incrnoverflow increments h.noverflow. 213 // noverflow counts the number of overflow buckets. 214 // This is used to trigger same-size map growth. 215 // See also tooManyOverflowBuckets. 216 // To keep hmap small, noverflow is a uint16. 217 // When there are few buckets, noverflow is an exact count. 218 // When there are many buckets, noverflow is an approximate count. 219 func (h *hmap) incrnoverflow() { 220 // We trigger same-size map growth if there are 221 // as many overflow buckets as buckets. 222 // We need to be able to count to 1<<h.B. 223 if h.B < 16 { 224 h.noverflow++ 225 return 226 } 227 // Increment with probability 1/(1<<(h.B-15)). 228 // When we reach 1<<15 - 1, we will have approximately 229 // as many overflow buckets as buckets. 230 mask := uint32(1)<<(h.B-15) - 1 231 // Example: if h.B == 18, then mask == 7, 232 // and fastrand & 7 == 0 with probability 1/8. 233 if fastrand()&mask == 0 { 234 h.noverflow++ 235 } 236 } 237 238 func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap { 239 var ovf *bmap 240 if h.extra != nil && h.extra.nextOverflow != nil { 241 // We have preallocated overflow buckets available. 242 // See makeBucketArray for more details. 243 ovf = h.extra.nextOverflow 244 if ovf.overflow(t) == nil { 245 // We're not at the end of the preallocated overflow buckets. Bump the pointer. 246 h.extra.nextOverflow = (*bmap)(add(unsafe.Pointer(ovf), uintptr(t.bucketsize))) 247 } else { 248 // This is the last preallocated overflow bucket. 249 // Reset the overflow pointer on this bucket, 250 // which was set to a non-nil sentinel value. 251 ovf.setoverflow(t, nil) 252 h.extra.nextOverflow = nil 253 } 254 } else { 255 ovf = (*bmap)(newobject(t.bucket)) 256 } 257 h.incrnoverflow() 258 if t.bucket.kind&kindNoPointers != 0 { 259 h.createOverflow() 260 *h.extra.overflow[0] = append(*h.extra.overflow[0], ovf) 261 } 262 b.setoverflow(t, ovf) 263 return ovf 264 } 265 266 func (h *hmap) createOverflow() { 267 if h.extra == nil { 268 h.extra = new(mapextra) 269 } 270 if h.extra.overflow[0] == nil { 271 h.extra.overflow[0] = new([]*bmap) 272 } 273 } 274 275 func makemap64(t *maptype, hint int64, h *hmap) *hmap { 276 if int64(int(hint)) != hint { 277 hint = 0 278 } 279 return makemap(t, int(hint), h) 280 } 281 282 // makemap implements a Go map creation make(map[k]v, hint) 283 // If the compiler has determined that the map or the first bucket 284 // can be created on the stack, h and/or bucket may be non-nil. 285 // If h != nil, the map can be created directly in h. 286 // If h.buckets != nil, bucket pointed to can be used as the first bucket. 287 func makemap(t *maptype, hint int, h *hmap) *hmap { 288 // The size of hmap should be 48 bytes on 64 bit 289 // and 28 bytes on 32 bit platforms. 290 if sz := unsafe.Sizeof(hmap{}); sz != 8+5*sys.PtrSize { 291 println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) 292 throw("bad hmap size") 293 } 294 295 if hint < 0 || hint > int(maxSliceCap(t.bucket.size)) { 296 hint = 0 297 } 298 299 if !ismapkey(t.key) { 300 throw("runtime.makemap: unsupported map key type") 301 } 302 303 if evacuatedX+1 != evacuatedY { 304 // evacuate relies on this relationship 305 throw("bad evacuatedN") 306 } 307 308 // initialize Hmap 309 if h == nil { 310 h = (*hmap)(newobject(t.hmap)) 311 } 312 h.hash0 = fastrand() 313 314 // find size parameter which will hold the requested # of elements 315 B := uint8(0) 316 for overLoadFactor(hint, B) { 317 B++ 318 } 319 h.B = B 320 321 // allocate initial hash table 322 // if B == 0, the buckets field is allocated lazily later (in mapassign) 323 // If hint is large zeroing this memory could take a while. 324 if h.B != 0 { 325 var nextOverflow *bmap 326 h.buckets, nextOverflow = makeBucketArray(t, h.B) 327 if nextOverflow != nil { 328 h.extra = new(mapextra) 329 h.extra.nextOverflow = nextOverflow 330 } 331 } 332 333 return h 334 } 335 336 // mapaccess1 returns a pointer to h[key]. Never returns nil, instead 337 // it will return a reference to the zero object for the value type if 338 // the key is not in the map. 339 // NOTE: The returned pointer may keep the whole map live, so don't 340 // hold onto it for very long. 341 func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 342 if raceenabled && h != nil { 343 callerpc := getcallerpc(unsafe.Pointer(&t)) 344 pc := funcPC(mapaccess1) 345 racereadpc(unsafe.Pointer(h), callerpc, pc) 346 raceReadObjectPC(t.key, key, callerpc, pc) 347 } 348 if msanenabled && h != nil { 349 msanread(key, t.key.size) 350 } 351 if h == nil || h.count == 0 { 352 return unsafe.Pointer(&zeroVal[0]) 353 } 354 if h.flags&hashWriting != 0 { 355 throw("concurrent map read and map write") 356 } 357 alg := t.key.alg 358 hash := alg.hash(key, uintptr(h.hash0)) 359 m := bucketMask(h.B) 360 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) 361 if c := h.oldbuckets; c != nil { 362 if !h.sameSizeGrow() { 363 // There used to be half as many buckets; mask down one more power of two. 364 m >>= 1 365 } 366 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize))) 367 if !evacuated(oldb) { 368 b = oldb 369 } 370 } 371 top := tophash(hash) 372 for ; b != nil; b = b.overflow(t) { 373 for i := uintptr(0); i < bucketCnt; i++ { 374 if b.tophash[i] != top { 375 continue 376 } 377 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 378 if t.indirectkey { 379 k = *((*unsafe.Pointer)(k)) 380 } 381 if alg.equal(key, k) { 382 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 383 if t.indirectvalue { 384 v = *((*unsafe.Pointer)(v)) 385 } 386 return v 387 } 388 } 389 } 390 return unsafe.Pointer(&zeroVal[0]) 391 } 392 393 func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { 394 if raceenabled && h != nil { 395 callerpc := getcallerpc(unsafe.Pointer(&t)) 396 pc := funcPC(mapaccess2) 397 racereadpc(unsafe.Pointer(h), callerpc, pc) 398 raceReadObjectPC(t.key, key, callerpc, pc) 399 } 400 if msanenabled && h != nil { 401 msanread(key, t.key.size) 402 } 403 if h == nil || h.count == 0 { 404 return unsafe.Pointer(&zeroVal[0]), false 405 } 406 if h.flags&hashWriting != 0 { 407 throw("concurrent map read and map write") 408 } 409 alg := t.key.alg 410 hash := alg.hash(key, uintptr(h.hash0)) 411 m := bucketMask(h.B) 412 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize))) 413 if c := h.oldbuckets; c != nil { 414 if !h.sameSizeGrow() { 415 // There used to be half as many buckets; mask down one more power of two. 416 m >>= 1 417 } 418 oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize))) 419 if !evacuated(oldb) { 420 b = oldb 421 } 422 } 423 top := tophash(hash) 424 for ; b != nil; b = b.overflow(t) { 425 for i := uintptr(0); i < bucketCnt; i++ { 426 if b.tophash[i] != top { 427 continue 428 } 429 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 430 if t.indirectkey { 431 k = *((*unsafe.Pointer)(k)) 432 } 433 if alg.equal(key, k) { 434 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 435 if t.indirectvalue { 436 v = *((*unsafe.Pointer)(v)) 437 } 438 return v, true 439 } 440 } 441 } 442 return unsafe.Pointer(&zeroVal[0]), false 443 } 444 445 // returns both key and value. Used by map iterator 446 func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) { 447 if h == nil || h.count == 0 { 448 return nil, nil 449 } 450 alg := t.key.alg 451 hash := alg.hash(key, uintptr(h.hash0)) 452 m := bucketMask(h.B) 453 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize))) 454 if c := h.oldbuckets; c != nil { 455 if !h.sameSizeGrow() { 456 // There used to be half as many buckets; mask down one more power of two. 457 m >>= 1 458 } 459 oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize))) 460 if !evacuated(oldb) { 461 b = oldb 462 } 463 } 464 top := tophash(hash) 465 for ; b != nil; b = b.overflow(t) { 466 for i := uintptr(0); i < bucketCnt; i++ { 467 if b.tophash[i] != top { 468 continue 469 } 470 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 471 if t.indirectkey { 472 k = *((*unsafe.Pointer)(k)) 473 } 474 if alg.equal(key, k) { 475 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 476 if t.indirectvalue { 477 v = *((*unsafe.Pointer)(v)) 478 } 479 return k, v 480 } 481 } 482 } 483 return nil, nil 484 } 485 486 func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer { 487 v := mapaccess1(t, h, key) 488 if v == unsafe.Pointer(&zeroVal[0]) { 489 return zero 490 } 491 return v 492 } 493 494 func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) { 495 v := mapaccess1(t, h, key) 496 if v == unsafe.Pointer(&zeroVal[0]) { 497 return zero, false 498 } 499 return v, true 500 } 501 502 // Like mapaccess, but allocates a slot for the key if it is not present in the map. 503 func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 504 if h == nil { 505 panic(plainError("assignment to entry in nil map")) 506 } 507 if raceenabled { 508 callerpc := getcallerpc(unsafe.Pointer(&t)) 509 pc := funcPC(mapassign) 510 racewritepc(unsafe.Pointer(h), callerpc, pc) 511 raceReadObjectPC(t.key, key, callerpc, pc) 512 } 513 if msanenabled { 514 msanread(key, t.key.size) 515 } 516 if h.flags&hashWriting != 0 { 517 throw("concurrent map writes") 518 } 519 alg := t.key.alg 520 hash := alg.hash(key, uintptr(h.hash0)) 521 522 // Set hashWriting after calling alg.hash, since alg.hash may panic, 523 // in which case we have not actually done a write. 524 h.flags |= hashWriting 525 526 if h.buckets == nil { 527 h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) 528 } 529 530 again: 531 bucket := hash & bucketMask(h.B) 532 if h.growing() { 533 growWork(t, h, bucket) 534 } 535 b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize))) 536 top := tophash(hash) 537 538 var inserti *uint8 539 var insertk unsafe.Pointer 540 var val unsafe.Pointer 541 for { 542 for i := uintptr(0); i < bucketCnt; i++ { 543 if b.tophash[i] != top { 544 if b.tophash[i] == empty && inserti == nil { 545 inserti = &b.tophash[i] 546 insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 547 val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 548 } 549 continue 550 } 551 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 552 if t.indirectkey { 553 k = *((*unsafe.Pointer)(k)) 554 } 555 if !alg.equal(key, k) { 556 continue 557 } 558 // already have a mapping for key. Update it. 559 if t.needkeyupdate { 560 typedmemmove(t.key, k, key) 561 } 562 val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 563 goto done 564 } 565 ovf := b.overflow(t) 566 if ovf == nil { 567 break 568 } 569 b = ovf 570 } 571 572 // Did not find mapping for key. Allocate new cell & add entry. 573 574 // If we hit the max load factor or we have too many overflow buckets, 575 // and we're not already in the middle of growing, start growing. 576 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { 577 hashGrow(t, h) 578 goto again // Growing the table invalidates everything, so try again 579 } 580 581 if inserti == nil { 582 // all current buckets are full, allocate a new one. 583 newb := h.newoverflow(t, b) 584 inserti = &newb.tophash[0] 585 insertk = add(unsafe.Pointer(newb), dataOffset) 586 val = add(insertk, bucketCnt*uintptr(t.keysize)) 587 } 588 589 // store new key/value at insert position 590 if t.indirectkey { 591 kmem := newobject(t.key) 592 *(*unsafe.Pointer)(insertk) = kmem 593 insertk = kmem 594 } 595 if t.indirectvalue { 596 vmem := newobject(t.elem) 597 *(*unsafe.Pointer)(val) = vmem 598 } 599 typedmemmove(t.key, insertk, key) 600 *inserti = top 601 h.count++ 602 603 done: 604 if h.flags&hashWriting == 0 { 605 throw("concurrent map writes") 606 } 607 h.flags &^= hashWriting 608 if t.indirectvalue { 609 val = *((*unsafe.Pointer)(val)) 610 } 611 return val 612 } 613 614 func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { 615 if raceenabled && h != nil { 616 callerpc := getcallerpc(unsafe.Pointer(&t)) 617 pc := funcPC(mapdelete) 618 racewritepc(unsafe.Pointer(h), callerpc, pc) 619 raceReadObjectPC(t.key, key, callerpc, pc) 620 } 621 if msanenabled && h != nil { 622 msanread(key, t.key.size) 623 } 624 if h == nil || h.count == 0 { 625 return 626 } 627 if h.flags&hashWriting != 0 { 628 throw("concurrent map writes") 629 } 630 631 alg := t.key.alg 632 hash := alg.hash(key, uintptr(h.hash0)) 633 634 // Set hashWriting after calling alg.hash, since alg.hash may panic, 635 // in which case we have not actually done a write (delete). 636 h.flags |= hashWriting 637 638 bucket := hash & bucketMask(h.B) 639 if h.growing() { 640 growWork(t, h, bucket) 641 } 642 b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize))) 643 top := tophash(hash) 644 search: 645 for ; b != nil; b = b.overflow(t) { 646 for i := uintptr(0); i < bucketCnt; i++ { 647 if b.tophash[i] != top { 648 continue 649 } 650 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) 651 k2 := k 652 if t.indirectkey { 653 k2 = *((*unsafe.Pointer)(k2)) 654 } 655 if !alg.equal(key, k2) { 656 continue 657 } 658 // Only clear key if there are pointers in it. 659 if t.indirectkey { 660 *(*unsafe.Pointer)(k) = nil 661 } else if t.key.kind&kindNoPointers == 0 { 662 memclrHasPointers(k, t.key.size) 663 } 664 // Only clear value if there are pointers in it. 665 if t.indirectvalue || t.elem.kind&kindNoPointers == 0 { 666 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) 667 if t.indirectvalue { 668 *(*unsafe.Pointer)(v) = nil 669 } else { 670 memclrHasPointers(v, t.elem.size) 671 } 672 } 673 b.tophash[i] = empty 674 h.count-- 675 break search 676 } 677 } 678 679 if h.flags&hashWriting == 0 { 680 throw("concurrent map writes") 681 } 682 h.flags &^= hashWriting 683 } 684 685 func mapiterinit(t *maptype, h *hmap, it *hiter) { 686 // Clear pointer fields so garbage collector does not complain. 687 it.key = nil 688 it.value = nil 689 it.t = nil 690 it.h = nil 691 it.buckets = nil 692 it.bptr = nil 693 it.overflow[0] = nil 694 it.overflow[1] = nil 695 696 if raceenabled && h != nil { 697 callerpc := getcallerpc(unsafe.Pointer(&t)) 698 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit)) 699 } 700 701 if h == nil || h.count == 0 { 702 it.key = nil 703 it.value = nil 704 return 705 } 706 707 if unsafe.Sizeof(hiter{})/sys.PtrSize != 12 { 708 throw("hash_iter size incorrect") // see ../../cmd/internal/gc/reflect.go 709 } 710 it.t = t 711 it.h = h 712 713 // grab snapshot of bucket state 714 it.B = h.B 715 it.buckets = h.buckets 716 if t.bucket.kind&kindNoPointers != 0 { 717 // Allocate the current slice and remember pointers to both current and old. 718 // This preserves all relevant overflow buckets alive even if 719 // the table grows and/or overflow buckets are added to the table 720 // while we are iterating. 721 h.createOverflow() 722 it.overflow = h.extra.overflow 723 } 724 725 // decide where to start 726 r := uintptr(fastrand()) 727 if h.B > 31-bucketCntBits { 728 r += uintptr(fastrand()) << 31 729 } 730 it.startBucket = r & bucketMask(h.B) 731 it.offset = uint8(r >> h.B & (bucketCnt - 1)) 732 733 // iterator state 734 it.bucket = it.startBucket 735 it.wrapped = false 736 it.bptr = nil 737 738 // Remember we have an iterator. 739 // Can run concurrently with another hash_iter_init(). 740 if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator { 741 atomic.Or8(&h.flags, iterator|oldIterator) 742 } 743 744 mapiternext(it) 745 } 746 747 func mapiternext(it *hiter) { 748 h := it.h 749 if raceenabled { 750 callerpc := getcallerpc(unsafe.Pointer(&it)) 751 racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext)) 752 } 753 if h.flags&hashWriting != 0 { 754 throw("concurrent map iteration and map write") 755 } 756 t := it.t 757 bucket := it.bucket 758 b := it.bptr 759 i := it.i 760 checkBucket := it.checkBucket 761 alg := t.key.alg 762 763 next: 764 if b == nil { 765 if bucket == it.startBucket && it.wrapped { 766 // end of iteration 767 it.key = nil 768 it.value = nil 769 return 770 } 771 if h.growing() && it.B == h.B { 772 // Iterator was started in the middle of a grow, and the grow isn't done yet. 773 // If the bucket we're looking at hasn't been filled in yet (i.e. the old 774 // bucket hasn't been evacuated) then we need to iterate through the old 775 // bucket and only return the ones that will be migrated to this bucket. 776 oldbucket := bucket & it.h.oldbucketmask() 777 b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) 778 if !evacuated(b) { 779 checkBucket = bucket 780 } else { 781 b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize))) 782 checkBucket = noCheck 783 } 784 } else { 785 b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize))) 786 checkBucket = noCheck 787 } 788 bucket++ 789 if bucket == bucketShift(it.B) { 790 bucket = 0 791 it.wrapped = true 792 } 793 i = 0 794 } 795 for ; i < bucketCnt; i++ { 796 offi := (i + it.offset) & (bucketCnt - 1) 797 if b.tophash[offi] == empty || b.tophash[offi] == evacuatedEmpty { 798 continue 799 } 800 k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.keysize)) 801 if t.indirectkey { 802 k = *((*unsafe.Pointer)(k)) 803 } 804 v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+uintptr(offi)*uintptr(t.valuesize)) 805 if checkBucket != noCheck && !h.sameSizeGrow() { 806 // Special case: iterator was started during a grow to a larger size 807 // and the grow is not done yet. We're working on a bucket whose 808 // oldbucket has not been evacuated yet. Or at least, it wasn't 809 // evacuated when we started the bucket. So we're iterating 810 // through the oldbucket, skipping any keys that will go 811 // to the other new bucket (each oldbucket expands to two 812 // buckets during a grow). 813 if t.reflexivekey || alg.equal(k, k) { 814 // If the item in the oldbucket is not destined for 815 // the current new bucket in the iteration, skip it. 816 hash := alg.hash(k, uintptr(h.hash0)) 817 if hash&bucketMask(it.B) != checkBucket { 818 continue 819 } 820 } else { 821 // Hash isn't repeatable if k != k (NaNs). We need a 822 // repeatable and randomish choice of which direction 823 // to send NaNs during evacuation. We'll use the low 824 // bit of tophash to decide which way NaNs go. 825 // NOTE: this case is why we need two evacuate tophash 826 // values, evacuatedX and evacuatedY, that differ in 827 // their low bit. 828 if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) { 829 continue 830 } 831 } 832 } 833 if (b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY) || 834 !(t.reflexivekey || alg.equal(k, k)) { 835 // This is the golden data, we can return it. 836 // OR 837 // key!=key, so the entry can't be deleted or updated, so we can just return it. 838 // That's lucky for us because when key!=key we can't look it up successfully. 839 it.key = k 840 if t.indirectvalue { 841 v = *((*unsafe.Pointer)(v)) 842 } 843 it.value = v 844 } else { 845 // The hash table has grown since the iterator was started. 846 // The golden data for this key is now somewhere else. 847 // Check the current hash table for the data. 848 // This code handles the case where the key 849 // has been deleted, updated, or deleted and reinserted. 850 // NOTE: we need to regrab the key as it has potentially been 851 // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). 852 rk, rv := mapaccessK(t, h, k) 853 if rk == nil { 854 continue // key has been deleted 855 } 856 it.key = rk 857 it.value = rv 858 } 859 it.bucket = bucket 860 if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 861 it.bptr = b 862 } 863 it.i = i + 1 864 it.checkBucket = checkBucket 865 return 866 } 867 b = b.overflow(t) 868 i = 0 869 goto next 870 } 871 872 func makeBucketArray(t *maptype, b uint8) (buckets unsafe.Pointer, nextOverflow *bmap) { 873 base := bucketShift(b) 874 nbuckets := base 875 // For small b, overflow buckets are unlikely. 876 // Avoid the overhead of the calculation. 877 if b >= 4 { 878 // Add on the estimated number of overflow buckets 879 // required to insert the median number of elements 880 // used with this value of b. 881 nbuckets += bucketShift(b - 4) 882 sz := t.bucket.size * nbuckets 883 up := roundupsize(sz) 884 if up != sz { 885 nbuckets = up / t.bucket.size 886 } 887 } 888 buckets = newarray(t.bucket, int(nbuckets)) 889 if base != nbuckets { 890 // We preallocated some overflow buckets. 891 // To keep the overhead of tracking these overflow buckets to a minimum, 892 // we use the convention that if a preallocated overflow bucket's overflow 893 // pointer is nil, then there are more available by bumping the pointer. 894 // We need a safe non-nil pointer for the last overflow bucket; just use buckets. 895 nextOverflow = (*bmap)(add(buckets, base*uintptr(t.bucketsize))) 896 last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.bucketsize))) 897 last.setoverflow(t, (*bmap)(buckets)) 898 } 899 return buckets, nextOverflow 900 } 901 902 func hashGrow(t *maptype, h *hmap) { 903 // If we've hit the load factor, get bigger. 904 // Otherwise, there are too many overflow buckets, 905 // so keep the same number of buckets and "grow" laterally. 906 bigger := uint8(1) 907 if !overLoadFactor(h.count+1, h.B) { 908 bigger = 0 909 h.flags |= sameSizeGrow 910 } 911 oldbuckets := h.buckets 912 newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger) 913 914 flags := h.flags &^ (iterator | oldIterator) 915 if h.flags&iterator != 0 { 916 flags |= oldIterator 917 } 918 // commit the grow (atomic wrt gc) 919 h.B += bigger 920 h.flags = flags 921 h.oldbuckets = oldbuckets 922 h.buckets = newbuckets 923 h.nevacuate = 0 924 h.noverflow = 0 925 926 if h.extra != nil && h.extra.overflow[0] != nil { 927 // Promote current overflow buckets to the old generation. 928 if h.extra.overflow[1] != nil { 929 throw("overflow is not nil") 930 } 931 h.extra.overflow[1] = h.extra.overflow[0] 932 h.extra.overflow[0] = nil 933 } 934 if nextOverflow != nil { 935 if h.extra == nil { 936 h.extra = new(mapextra) 937 } 938 h.extra.nextOverflow = nextOverflow 939 } 940 941 // the actual copying of the hash table data is done incrementally 942 // by growWork() and evacuate(). 943 } 944 945 // overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor. 946 func overLoadFactor(count int, B uint8) bool { 947 return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) 948 } 949 950 // tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<<B buckets. 951 // Note that most of these overflow buckets must be in sparse use; 952 // if use was dense, then we'd have already triggered regular map growth. 953 func tooManyOverflowBuckets(noverflow uint16, B uint8) bool { 954 // If the threshold is too low, we do extraneous work. 955 // If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory. 956 // "too many" means (approximately) as many overflow buckets as regular buckets. 957 // See incrnoverflow for more details. 958 if B > 15 { 959 B = 15 960 } 961 // The compiler doesn't see here that B < 16; mask B to generate shorter shift code. 962 return noverflow >= uint16(1)<<(B&15) 963 } 964 965 // growing reports whether h is growing. The growth may be to the same size or bigger. 966 func (h *hmap) growing() bool { 967 return h.oldbuckets != nil 968 } 969 970 // sameSizeGrow reports whether the current growth is to a map of the same size. 971 func (h *hmap) sameSizeGrow() bool { 972 return h.flags&sameSizeGrow != 0 973 } 974 975 // noldbuckets calculates the number of buckets prior to the current map growth. 976 func (h *hmap) noldbuckets() uintptr { 977 oldB := h.B 978 if !h.sameSizeGrow() { 979 oldB-- 980 } 981 return bucketShift(oldB) 982 } 983 984 // oldbucketmask provides a mask that can be applied to calculate n % noldbuckets(). 985 func (h *hmap) oldbucketmask() uintptr { 986 return h.noldbuckets() - 1 987 } 988 989 func growWork(t *maptype, h *hmap, bucket uintptr) { 990 // make sure we evacuate the oldbucket corresponding 991 // to the bucket we're about to use 992 evacuate(t, h, bucket&h.oldbucketmask()) 993 994 // evacuate one more oldbucket to make progress on growing 995 if h.growing() { 996 evacuate(t, h, h.nevacuate) 997 } 998 } 999 1000 func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool { 1001 b := (*bmap)(add(h.oldbuckets, bucket*uintptr(t.bucketsize))) 1002 return evacuated(b) 1003 } 1004 1005 // evacDst is an evacuation destination. 1006 type evacDst struct { 1007 b *bmap // current destination bucket 1008 i int // key/val index into b 1009 k unsafe.Pointer // pointer to current key storage 1010 v unsafe.Pointer // pointer to current value storage 1011 } 1012 1013 func evacuate(t *maptype, h *hmap, oldbucket uintptr) { 1014 b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) 1015 newbit := h.noldbuckets() 1016 if !evacuated(b) { 1017 // TODO: reuse overflow buckets instead of using new ones, if there 1018 // is no iterator using the old buckets. (If !oldIterator.) 1019 1020 // xy contains the x and y (low and high) evacuation destinations. 1021 var xy [2]evacDst 1022 x := &xy[0] 1023 x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) 1024 x.k = add(unsafe.Pointer(x.b), dataOffset) 1025 x.v = add(x.k, bucketCnt*uintptr(t.keysize)) 1026 1027 if !h.sameSizeGrow() { 1028 // Only calculate y pointers if we're growing bigger. 1029 // Otherwise GC can see bad pointers. 1030 y := &xy[1] 1031 y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) 1032 y.k = add(unsafe.Pointer(y.b), dataOffset) 1033 y.v = add(y.k, bucketCnt*uintptr(t.keysize)) 1034 } 1035 1036 for ; b != nil; b = b.overflow(t) { 1037 k := add(unsafe.Pointer(b), dataOffset) 1038 v := add(k, bucketCnt*uintptr(t.keysize)) 1039 for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) { 1040 top := b.tophash[i] 1041 if top == empty { 1042 b.tophash[i] = evacuatedEmpty 1043 continue 1044 } 1045 if top < minTopHash { 1046 throw("bad map state") 1047 } 1048 k2 := k 1049 if t.indirectkey { 1050 k2 = *((*unsafe.Pointer)(k2)) 1051 } 1052 var useY uint8 1053 if !h.sameSizeGrow() { 1054 // Compute hash to make our evacuation decision (whether we need 1055 // to send this key/value to bucket x or bucket y). 1056 hash := t.key.alg.hash(k2, uintptr(h.hash0)) 1057 if h.flags&iterator != 0 && !t.reflexivekey && !t.key.alg.equal(k2, k2) { 1058 // If key != key (NaNs), then the hash could be (and probably 1059 // will be) entirely different from the old hash. Moreover, 1060 // it isn't reproducible. Reproducibility is required in the 1061 // presence of iterators, as our evacuation decision must 1062 // match whatever decision the iterator made. 1063 // Fortunately, we have the freedom to send these keys either 1064 // way. Also, tophash is meaningless for these kinds of keys. 1065 // We let the low bit of tophash drive the evacuation decision. 1066 // We recompute a new random tophash for the next level so 1067 // these keys will get evenly distributed across all buckets 1068 // after multiple grows. 1069 useY = top & 1 1070 top = tophash(hash) 1071 } else { 1072 if hash&newbit != 0 { 1073 useY = 1 1074 } 1075 } 1076 } 1077 1078 b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap 1079 dst := &xy[useY] // evacuation destination 1080 1081 if dst.i == bucketCnt { 1082 dst.b = h.newoverflow(t, dst.b) 1083 dst.i = 0 1084 dst.k = add(unsafe.Pointer(dst.b), dataOffset) 1085 dst.v = add(dst.k, bucketCnt*uintptr(t.keysize)) 1086 } 1087 dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check 1088 if t.indirectkey { 1089 *(*unsafe.Pointer)(dst.k) = k2 // copy pointer 1090 } else { 1091 typedmemmove(t.key, dst.k, k) // copy value 1092 } 1093 if t.indirectvalue { 1094 *(*unsafe.Pointer)(dst.v) = *(*unsafe.Pointer)(v) 1095 } else { 1096 typedmemmove(t.elem, dst.v, v) 1097 } 1098 dst.i++ 1099 // These updates might push these pointers past the end of the 1100 // key or value arrays. That's ok, as we have the overflow pointer 1101 // at the end of the bucket to protect against pointing past the 1102 // end of the bucket. 1103 dst.k = add(dst.k, uintptr(t.keysize)) 1104 dst.v = add(dst.v, uintptr(t.valuesize)) 1105 } 1106 } 1107 // Unlink the overflow buckets & clear key/value to help GC. 1108 if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 { 1109 b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)) 1110 // Preserve b.tophash because the evacuation 1111 // state is maintained there. 1112 ptr := add(b, dataOffset) 1113 n := uintptr(t.bucketsize) - dataOffset 1114 memclrHasPointers(ptr, n) 1115 } 1116 } 1117 1118 if oldbucket == h.nevacuate { 1119 advanceEvacuationMark(h, t, newbit) 1120 } 1121 } 1122 1123 func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) { 1124 h.nevacuate++ 1125 // Experiments suggest that 1024 is overkill by at least an order of magnitude. 1126 // Put it in there as a safeguard anyway, to ensure O(1) behavior. 1127 stop := h.nevacuate + 1024 1128 if stop > newbit { 1129 stop = newbit 1130 } 1131 for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { 1132 h.nevacuate++ 1133 } 1134 if h.nevacuate == newbit { // newbit == # of oldbuckets 1135 // Growing is all done. Free old main bucket array. 1136 h.oldbuckets = nil 1137 // Can discard old overflow buckets as well. 1138 // If they are still referenced by an iterator, 1139 // then the iterator holds a pointers to the slice. 1140 if h.extra != nil { 1141 h.extra.overflow[1] = nil 1142 } 1143 h.flags &^= sameSizeGrow 1144 } 1145 } 1146 1147 func ismapkey(t *_type) bool { 1148 return t.alg.hash != nil 1149 } 1150 1151 // Reflect stubs. Called from ../reflect/asm_*.s 1152 1153 //go:linkname reflect_makemap reflect.makemap 1154 func reflect_makemap(t *maptype, cap int) *hmap { 1155 // Check invariants and reflects math. 1156 if sz := unsafe.Sizeof(hmap{}); sz != t.hmap.size { 1157 println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) 1158 throw("bad hmap size") 1159 } 1160 if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(sys.PtrSize)) || 1161 t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) { 1162 throw("key size wrong") 1163 } 1164 if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(sys.PtrSize)) || 1165 t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) { 1166 throw("value size wrong") 1167 } 1168 if t.key.align > bucketCnt { 1169 throw("key align too big") 1170 } 1171 if t.elem.align > bucketCnt { 1172 throw("value align too big") 1173 } 1174 if t.key.size%uintptr(t.key.align) != 0 { 1175 throw("key size not a multiple of key align") 1176 } 1177 if t.elem.size%uintptr(t.elem.align) != 0 { 1178 throw("value size not a multiple of value align") 1179 } 1180 if bucketCnt < 8 { 1181 throw("bucketsize too small for proper alignment") 1182 } 1183 if dataOffset%uintptr(t.key.align) != 0 { 1184 throw("need padding in bucket (key)") 1185 } 1186 if dataOffset%uintptr(t.elem.align) != 0 { 1187 throw("need padding in bucket (value)") 1188 } 1189 1190 return makemap(t, cap, nil) 1191 } 1192 1193 //go:linkname reflect_mapaccess reflect.mapaccess 1194 func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 1195 val, ok := mapaccess2(t, h, key) 1196 if !ok { 1197 // reflect wants nil for a missing element 1198 val = nil 1199 } 1200 return val 1201 } 1202 1203 //go:linkname reflect_mapassign reflect.mapassign 1204 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { 1205 p := mapassign(t, h, key) 1206 typedmemmove(t.elem, p, val) 1207 } 1208 1209 //go:linkname reflect_mapdelete reflect.mapdelete 1210 func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { 1211 mapdelete(t, h, key) 1212 } 1213 1214 //go:linkname reflect_mapiterinit reflect.mapiterinit 1215 func reflect_mapiterinit(t *maptype, h *hmap) *hiter { 1216 it := new(hiter) 1217 mapiterinit(t, h, it) 1218 return it 1219 } 1220 1221 //go:linkname reflect_mapiternext reflect.mapiternext 1222 func reflect_mapiternext(it *hiter) { 1223 mapiternext(it) 1224 } 1225 1226 //go:linkname reflect_mapiterkey reflect.mapiterkey 1227 func reflect_mapiterkey(it *hiter) unsafe.Pointer { 1228 return it.key 1229 } 1230 1231 //go:linkname reflect_maplen reflect.maplen 1232 func reflect_maplen(h *hmap) int { 1233 if h == nil { 1234 return 0 1235 } 1236 if raceenabled { 1237 callerpc := getcallerpc(unsafe.Pointer(&h)) 1238 racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen)) 1239 } 1240 return h.count 1241 } 1242 1243 //go:linkname reflect_ismapkey reflect.ismapkey 1244 func reflect_ismapkey(t *_type) bool { 1245 return ismapkey(t) 1246 } 1247 1248 const maxZero = 1024 // must match value in ../cmd/compile/internal/gc/walk.go 1249 var zeroVal [maxZero]byte