github.com/goplus/llgo@v0.8.3/internal/runtime/map.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/elem 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 elems) 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/elem 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 "unsafe" 58 59 "github.com/goplus/llgo/internal/abi" 60 ) 61 62 const ( 63 // Maximum number of key/elem pairs a bucket can hold. 64 bucketCntBits = abi.MapBucketCountBits 65 bucketCnt = abi.MapBucketCount 66 67 // Maximum average load of a bucket that triggers growth is bucketCnt*13/16 (about 80% full) 68 // Because of minimum alignment rules, bucketCnt is known to be at least 8. 69 // Represent as loadFactorNum/loadFactorDen, to allow integer math. 70 loadFactorDen = 2 71 loadFactorNum = (bucketCnt * 13 / 16) * loadFactorDen 72 73 // Maximum key or elem size to keep inline (instead of mallocing per element). 74 // Must fit in a uint8. 75 // Fast versions cannot handle big elems - the cutoff size for 76 // fast versions in cmd/compile/internal/gc/walk.go must be at most this elem. 77 maxKeySize = abi.MapMaxKeyBytes 78 maxElemSize = abi.MapMaxElemBytes 79 80 // data offset should be the size of the bmap struct, but needs to be 81 // aligned correctly. For amd64p32 this means 64-bit alignment 82 // even though pointers are 32 bit. 83 dataOffset = unsafe.Offsetof(struct { 84 b bmap 85 v int64 86 }{}.v) 87 88 // Possible tophash values. We reserve a few possibilities for special marks. 89 // Each bucket (including its overflow buckets, if any) will have either all or none of its 90 // entries in the evacuated* states (except during the evacuate() method, which only happens 91 // during map writes and thus no one else can observe the map during that time). 92 emptyRest = 0 // this cell is empty, and there are no more non-empty cells at higher indexes or overflows. 93 emptyOne = 1 // this cell is empty 94 evacuatedX = 2 // key/elem is valid. Entry has been evacuated to first half of larger table. 95 evacuatedY = 3 // same as above, but evacuated to second half of larger table. 96 evacuatedEmpty = 4 // cell is empty, bucket is evacuated. 97 minTopHash = 5 // minimum tophash for a normal filled cell. 98 99 // flags 100 iterator = 1 // there may be an iterator using buckets 101 oldIterator = 2 // there may be an iterator using oldbuckets 102 hashWriting = 4 // a goroutine is writing to the map 103 sameSizeGrow = 8 // the current map growth is to a new map of the same size 104 105 // sentinel bucket ID for iterator checks 106 // noCheck = 1<<(8*goarch.PtrSize) - 1 107 ) 108 109 // isEmpty reports whether the given tophash array entry represents an empty bucket entry. 110 func isEmpty(x uint8) bool { 111 return x <= emptyOne 112 } 113 114 // A header for a Go map. 115 type hmap struct { 116 // Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go. 117 // Make sure this stays in sync with the compiler's definition. 118 count int // # live cells == size of map. Must be first (used by len() builtin) 119 flags uint8 120 B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) 121 noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details 122 hash0 uint32 // hash seed 123 124 buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. 125 oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing 126 nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) 127 128 extra *mapextra // optional fields 129 } 130 131 // mapextra holds fields that are not present on all maps. 132 type mapextra struct { 133 // If both key and elem do not contain pointers and are inline, then we mark bucket 134 // type as containing no pointers. This avoids scanning such maps. 135 // However, bmap.overflow is a pointer. In order to keep overflow buckets 136 // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow. 137 // overflow and oldoverflow are only used if key and elem do not contain pointers. 138 // overflow contains overflow buckets for hmap.buckets. 139 // oldoverflow contains overflow buckets for hmap.oldbuckets. 140 // The indirection allows to store a pointer to the slice in hiter. 141 overflow *[]*bmap 142 oldoverflow *[]*bmap 143 144 // nextOverflow holds a pointer to a free overflow bucket. 145 nextOverflow *bmap 146 } 147 148 // A bucket for a Go map. 149 type bmap struct { 150 // tophash generally contains the top byte of the hash value 151 // for each key in this bucket. If tophash[0] < minTopHash, 152 // tophash[0] is a bucket evacuation state instead. 153 tophash [bucketCnt]uint8 154 // Followed by bucketCnt keys and then bucketCnt elems. 155 // NOTE: packing all the keys together and then all the elems together makes the 156 // code a bit more complicated than alternating key/elem/key/elem/... but it allows 157 // us to eliminate padding which would be needed for, e.g., map[int64]int8. 158 // Followed by an overflow pointer. 159 } 160 161 /* 162 // A hash iteration structure. 163 // If you modify hiter, also change cmd/compile/internal/reflectdata/reflect.go 164 // and reflect/value.go to match the layout of this structure. 165 type hiter struct { 166 key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/compile/internal/walk/range.go). 167 elem unsafe.Pointer // Must be in second position (see cmd/compile/internal/walk/range.go). 168 t *maptype 169 h *hmap 170 buckets unsafe.Pointer // bucket ptr at hash_iter initialization time 171 bptr *bmap // current bucket 172 overflow *[]*bmap // keeps overflow buckets of hmap.buckets alive 173 oldoverflow *[]*bmap // keeps overflow buckets of hmap.oldbuckets alive 174 startBucket uintptr // bucket iteration started at 175 offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) 176 wrapped bool // already wrapped around from end of bucket array to beginning 177 B uint8 178 i uint8 179 bucket uintptr 180 checkBucket uintptr 181 } 182 183 // bucketShift returns 1<<b, optimized for code generation. 184 func bucketShift(b uint8) uintptr { 185 // Masking the shift amount allows overflow checks to be elided. 186 return uintptr(1) << (b & (goarch.PtrSize*8 - 1)) 187 } 188 189 // bucketMask returns 1<<b - 1, optimized for code generation. 190 func bucketMask(b uint8) uintptr { 191 return bucketShift(b) - 1 192 } 193 194 // tophash calculates the tophash value for hash. 195 func tophash(hash uintptr) uint8 { 196 top := uint8(hash >> (goarch.PtrSize*8 - 8)) 197 if top < minTopHash { 198 top += minTopHash 199 } 200 return top 201 } 202 203 func evacuated(b *bmap) bool { 204 h := b.tophash[0] 205 return h > emptyOne && h < minTopHash 206 } 207 208 func (b *bmap) overflow(t *maptype) *bmap { 209 return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) 210 } 211 212 func (b *bmap) setoverflow(t *maptype, ovf *bmap) { 213 *(**bmap)(add(unsafe.Pointer(b), uintptr(t.BucketSize)-goarch.PtrSize)) = ovf 214 } 215 216 func (b *bmap) keys() unsafe.Pointer { 217 return add(unsafe.Pointer(b), dataOffset) 218 } 219 220 // incrnoverflow increments h.noverflow. 221 // noverflow counts the number of overflow buckets. 222 // This is used to trigger same-size map growth. 223 // See also tooManyOverflowBuckets. 224 // To keep hmap small, noverflow is a uint16. 225 // When there are few buckets, noverflow is an exact count. 226 // When there are many buckets, noverflow is an approximate count. 227 func (h *hmap) incrnoverflow() { 228 // We trigger same-size map growth if there are 229 // as many overflow buckets as buckets. 230 // We need to be able to count to 1<<h.B. 231 if h.B < 16 { 232 h.noverflow++ 233 return 234 } 235 // Increment with probability 1/(1<<(h.B-15)). 236 // When we reach 1<<15 - 1, we will have approximately 237 // as many overflow buckets as buckets. 238 mask := uint32(1)<<(h.B-15) - 1 239 // Example: if h.B == 18, then mask == 7, 240 // and fastrand & 7 == 0 with probability 1/8. 241 if fastrand()&mask == 0 { 242 h.noverflow++ 243 } 244 } 245 246 func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap { 247 var ovf *bmap 248 if h.extra != nil && h.extra.nextOverflow != nil { 249 // We have preallocated overflow buckets available. 250 // See makeBucketArray for more details. 251 ovf = h.extra.nextOverflow 252 if ovf.overflow(t) == nil { 253 // We're not at the end of the preallocated overflow buckets. Bump the pointer. 254 h.extra.nextOverflow = (*bmap)(add(unsafe.Pointer(ovf), uintptr(t.BucketSize))) 255 } else { 256 // This is the last preallocated overflow bucket. 257 // Reset the overflow pointer on this bucket, 258 // which was set to a non-nil sentinel value. 259 ovf.setoverflow(t, nil) 260 h.extra.nextOverflow = nil 261 } 262 } else { 263 ovf = (*bmap)(newobject(t.Bucket)) 264 } 265 h.incrnoverflow() 266 if t.Bucket.PtrBytes == 0 { 267 h.createOverflow() 268 *h.extra.overflow = append(*h.extra.overflow, ovf) 269 } 270 b.setoverflow(t, ovf) 271 return ovf 272 } 273 274 func (h *hmap) createOverflow() { 275 if h.extra == nil { 276 h.extra = new(mapextra) 277 } 278 if h.extra.overflow == nil { 279 h.extra.overflow = new([]*bmap) 280 } 281 } 282 283 func makemap64(t *maptype, hint int64, h *hmap) *hmap { 284 if int64(int(hint)) != hint { 285 hint = 0 286 } 287 return makemap(t, int(hint), h) 288 } 289 */ 290 291 // makemap_small implements Go map creation for make(map[k]v) and 292 // make(map[k]v, hint) when hint is known to be at most bucketCnt 293 // at compile time and the map needs to be allocated on the heap. 294 func makemap_small() *hmap { 295 h := new(hmap) 296 h.hash0 = fastrand() 297 return h 298 } 299 300 /* 301 // makemap implements Go map creation for make(map[k]v, hint). 302 // If the compiler has determined that the map or the first bucket 303 // can be created on the stack, h and/or bucket may be non-nil. 304 // If h != nil, the map can be created directly in h. 305 // If h.buckets != nil, bucket pointed to can be used as the first bucket. 306 func makemap(t *maptype, hint int, h *hmap) *hmap { 307 mem, overflow := math.MulUintptr(uintptr(hint), t.Bucket.Size_) 308 if overflow || mem > maxAlloc { 309 hint = 0 310 } 311 312 // initialize Hmap 313 if h == nil { 314 h = new(hmap) 315 } 316 h.hash0 = fastrand() 317 318 // Find the size parameter B which will hold the requested # of elements. 319 // For hint < 0 overLoadFactor returns false since hint < bucketCnt. 320 B := uint8(0) 321 for overLoadFactor(hint, B) { 322 B++ 323 } 324 h.B = B 325 326 // allocate initial hash table 327 // if B == 0, the buckets field is allocated lazily later (in mapassign) 328 // If hint is large zeroing this memory could take a while. 329 if h.B != 0 { 330 var nextOverflow *bmap 331 h.buckets, nextOverflow = makeBucketArray(t, h.B, nil) 332 if nextOverflow != nil { 333 h.extra = new(mapextra) 334 h.extra.nextOverflow = nextOverflow 335 } 336 } 337 338 return h 339 } 340 341 // makeBucketArray initializes a backing array for map buckets. 342 // 1<<b is the minimum number of buckets to allocate. 343 // dirtyalloc should either be nil or a bucket array previously 344 // allocated by makeBucketArray with the same t and b parameters. 345 // If dirtyalloc is nil a new backing array will be alloced and 346 // otherwise dirtyalloc will be cleared and reused as backing array. 347 func makeBucketArray(t *maptype, b uint8, dirtyalloc unsafe.Pointer) (buckets unsafe.Pointer, nextOverflow *bmap) { 348 base := bucketShift(b) 349 nbuckets := base 350 // For small b, overflow buckets are unlikely. 351 // Avoid the overhead of the calculation. 352 if b >= 4 { 353 // Add on the estimated number of overflow buckets 354 // required to insert the median number of elements 355 // used with this value of b. 356 nbuckets += bucketShift(b - 4) 357 sz := t.Bucket.Size_ * nbuckets 358 up := roundupsize(sz) 359 if up != sz { 360 nbuckets = up / t.Bucket.Size_ 361 } 362 } 363 364 if dirtyalloc == nil { 365 buckets = newarray(t.Bucket, int(nbuckets)) 366 } else { 367 // dirtyalloc was previously generated by 368 // the above newarray(t.Bucket, int(nbuckets)) 369 // but may not be empty. 370 buckets = dirtyalloc 371 size := t.Bucket.Size_ * nbuckets 372 if t.Bucket.PtrBytes != 0 { 373 memclrHasPointers(buckets, size) 374 } else { 375 memclrNoHeapPointers(buckets, size) 376 } 377 } 378 379 if base != nbuckets { 380 // We preallocated some overflow buckets. 381 // To keep the overhead of tracking these overflow buckets to a minimum, 382 // we use the convention that if a preallocated overflow bucket's overflow 383 // pointer is nil, then there are more available by bumping the pointer. 384 // We need a safe non-nil pointer for the last overflow bucket; just use buckets. 385 nextOverflow = (*bmap)(add(buckets, base*uintptr(t.BucketSize))) 386 last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.BucketSize))) 387 last.setoverflow(t, (*bmap)(buckets)) 388 } 389 return buckets, nextOverflow 390 } 391 392 // mapaccess1 returns a pointer to h[key]. Never returns nil, instead 393 // it will return a reference to the zero object for the elem type if 394 // the key is not in the map. 395 // NOTE: The returned pointer may keep the whole map live, so don't 396 // hold onto it for very long. 397 func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 398 if raceenabled && h != nil { 399 callerpc := getcallerpc() 400 pc := abi.FuncPCABIInternal(mapaccess1) 401 racereadpc(unsafe.Pointer(h), callerpc, pc) 402 raceReadObjectPC(t.Key, key, callerpc, pc) 403 } 404 if msanenabled && h != nil { 405 msanread(key, t.Key.Size_) 406 } 407 if asanenabled && h != nil { 408 asanread(key, t.Key.Size_) 409 } 410 if h == nil || h.count == 0 { 411 if t.HashMightPanic() { 412 t.Hasher(key, 0) // see issue 23734 413 } 414 return unsafe.Pointer(&zeroVal[0]) 415 } 416 if h.flags&hashWriting != 0 { 417 fatal("concurrent map read and map write") 418 } 419 hash := t.Hasher(key, uintptr(h.hash0)) 420 m := bucketMask(h.B) 421 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) 422 if c := h.oldbuckets; c != nil { 423 if !h.sameSizeGrow() { 424 // There used to be half as many buckets; mask down one more power of two. 425 m >>= 1 426 } 427 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) 428 if !evacuated(oldb) { 429 b = oldb 430 } 431 } 432 top := tophash(hash) 433 bucketloop: 434 for ; b != nil; b = b.overflow(t) { 435 for i := uintptr(0); i < bucketCnt; i++ { 436 if b.tophash[i] != top { 437 if b.tophash[i] == emptyRest { 438 break bucketloop 439 } 440 continue 441 } 442 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 443 if t.IndirectKey() { 444 k = *((*unsafe.Pointer)(k)) 445 } 446 if t.Key.Equal(key, k) { 447 e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 448 if t.IndirectElem() { 449 e = *((*unsafe.Pointer)(e)) 450 } 451 return e 452 } 453 } 454 } 455 return unsafe.Pointer(&zeroVal[0]) 456 } 457 458 func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { 459 if raceenabled && h != nil { 460 callerpc := getcallerpc() 461 pc := abi.FuncPCABIInternal(mapaccess2) 462 racereadpc(unsafe.Pointer(h), callerpc, pc) 463 raceReadObjectPC(t.Key, key, callerpc, pc) 464 } 465 if msanenabled && h != nil { 466 msanread(key, t.Key.Size_) 467 } 468 if asanenabled && h != nil { 469 asanread(key, t.Key.Size_) 470 } 471 if h == nil || h.count == 0 { 472 if t.HashMightPanic() { 473 t.Hasher(key, 0) // see issue 23734 474 } 475 return unsafe.Pointer(&zeroVal[0]), false 476 } 477 if h.flags&hashWriting != 0 { 478 fatal("concurrent map read and map write") 479 } 480 hash := t.Hasher(key, uintptr(h.hash0)) 481 m := bucketMask(h.B) 482 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) 483 if c := h.oldbuckets; c != nil { 484 if !h.sameSizeGrow() { 485 // There used to be half as many buckets; mask down one more power of two. 486 m >>= 1 487 } 488 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) 489 if !evacuated(oldb) { 490 b = oldb 491 } 492 } 493 top := tophash(hash) 494 bucketloop: 495 for ; b != nil; b = b.overflow(t) { 496 for i := uintptr(0); i < bucketCnt; i++ { 497 if b.tophash[i] != top { 498 if b.tophash[i] == emptyRest { 499 break bucketloop 500 } 501 continue 502 } 503 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 504 if t.IndirectKey() { 505 k = *((*unsafe.Pointer)(k)) 506 } 507 if t.Key.Equal(key, k) { 508 e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 509 if t.IndirectElem() { 510 e = *((*unsafe.Pointer)(e)) 511 } 512 return e, true 513 } 514 } 515 } 516 return unsafe.Pointer(&zeroVal[0]), false 517 } 518 519 // returns both key and elem. Used by map iterator. 520 func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) { 521 if h == nil || h.count == 0 { 522 return nil, nil 523 } 524 hash := t.Hasher(key, uintptr(h.hash0)) 525 m := bucketMask(h.B) 526 b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.BucketSize))) 527 if c := h.oldbuckets; c != nil { 528 if !h.sameSizeGrow() { 529 // There used to be half as many buckets; mask down one more power of two. 530 m >>= 1 531 } 532 oldb := (*bmap)(add(c, (hash&m)*uintptr(t.BucketSize))) 533 if !evacuated(oldb) { 534 b = oldb 535 } 536 } 537 top := tophash(hash) 538 bucketloop: 539 for ; b != nil; b = b.overflow(t) { 540 for i := uintptr(0); i < bucketCnt; i++ { 541 if b.tophash[i] != top { 542 if b.tophash[i] == emptyRest { 543 break bucketloop 544 } 545 continue 546 } 547 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 548 if t.IndirectKey() { 549 k = *((*unsafe.Pointer)(k)) 550 } 551 if t.Key.Equal(key, k) { 552 e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 553 if t.IndirectElem() { 554 e = *((*unsafe.Pointer)(e)) 555 } 556 return k, e 557 } 558 } 559 } 560 return nil, nil 561 } 562 563 func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer { 564 e := mapaccess1(t, h, key) 565 if e == unsafe.Pointer(&zeroVal[0]) { 566 return zero 567 } 568 return e 569 } 570 571 func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) { 572 e := mapaccess1(t, h, key) 573 if e == unsafe.Pointer(&zeroVal[0]) { 574 return zero, false 575 } 576 return e, true 577 } 578 579 // Like mapaccess, but allocates a slot for the key if it is not present in the map. 580 func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 581 if h == nil { 582 panic(plainError("assignment to entry in nil map")) 583 } 584 if raceenabled { 585 callerpc := getcallerpc() 586 pc := abi.FuncPCABIInternal(mapassign) 587 racewritepc(unsafe.Pointer(h), callerpc, pc) 588 raceReadObjectPC(t.Key, key, callerpc, pc) 589 } 590 if msanenabled { 591 msanread(key, t.Key.Size_) 592 } 593 if asanenabled { 594 asanread(key, t.Key.Size_) 595 } 596 if h.flags&hashWriting != 0 { 597 fatal("concurrent map writes") 598 } 599 hash := t.Hasher(key, uintptr(h.hash0)) 600 601 // Set hashWriting after calling t.hasher, since t.hasher may panic, 602 // in which case we have not actually done a write. 603 h.flags ^= hashWriting 604 605 if h.buckets == nil { 606 h.buckets = newobject(t.Bucket) // newarray(t.Bucket, 1) 607 } 608 609 again: 610 bucket := hash & bucketMask(h.B) 611 if h.growing() { 612 growWork(t, h, bucket) 613 } 614 b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) 615 top := tophash(hash) 616 617 var inserti *uint8 618 var insertk unsafe.Pointer 619 var elem unsafe.Pointer 620 bucketloop: 621 for { 622 for i := uintptr(0); i < bucketCnt; i++ { 623 if b.tophash[i] != top { 624 if isEmpty(b.tophash[i]) && inserti == nil { 625 inserti = &b.tophash[i] 626 insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 627 elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 628 } 629 if b.tophash[i] == emptyRest { 630 break bucketloop 631 } 632 continue 633 } 634 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 635 if t.IndirectKey() { 636 k = *((*unsafe.Pointer)(k)) 637 } 638 if !t.Key.Equal(key, k) { 639 continue 640 } 641 // already have a mapping for key. Update it. 642 if t.NeedKeyUpdate() { 643 typedmemmove(t.Key, k, key) 644 } 645 elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 646 goto done 647 } 648 ovf := b.overflow(t) 649 if ovf == nil { 650 break 651 } 652 b = ovf 653 } 654 655 // Did not find mapping for key. Allocate new cell & add entry. 656 657 // If we hit the max load factor or we have too many overflow buckets, 658 // and we're not already in the middle of growing, start growing. 659 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { 660 hashGrow(t, h) 661 goto again // Growing the table invalidates everything, so try again 662 } 663 664 if inserti == nil { 665 // The current bucket and all the overflow buckets connected to it are full, allocate a new one. 666 newb := h.newoverflow(t, b) 667 inserti = &newb.tophash[0] 668 insertk = add(unsafe.Pointer(newb), dataOffset) 669 elem = add(insertk, bucketCnt*uintptr(t.KeySize)) 670 } 671 672 // store new key/elem at insert position 673 if t.IndirectKey() { 674 kmem := newobject(t.Key) 675 *(*unsafe.Pointer)(insertk) = kmem 676 insertk = kmem 677 } 678 if t.IndirectElem() { 679 vmem := newobject(t.Elem) 680 *(*unsafe.Pointer)(elem) = vmem 681 } 682 typedmemmove(t.Key, insertk, key) 683 *inserti = top 684 h.count++ 685 686 done: 687 if h.flags&hashWriting == 0 { 688 fatal("concurrent map writes") 689 } 690 h.flags &^= hashWriting 691 if t.IndirectElem() { 692 elem = *((*unsafe.Pointer)(elem)) 693 } 694 return elem 695 } 696 697 func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { 698 if raceenabled && h != nil { 699 callerpc := getcallerpc() 700 pc := abi.FuncPCABIInternal(mapdelete) 701 racewritepc(unsafe.Pointer(h), callerpc, pc) 702 raceReadObjectPC(t.Key, key, callerpc, pc) 703 } 704 if msanenabled && h != nil { 705 msanread(key, t.Key.Size_) 706 } 707 if asanenabled && h != nil { 708 asanread(key, t.Key.Size_) 709 } 710 if h == nil || h.count == 0 { 711 if t.HashMightPanic() { 712 t.Hasher(key, 0) // see issue 23734 713 } 714 return 715 } 716 if h.flags&hashWriting != 0 { 717 fatal("concurrent map writes") 718 } 719 720 hash := t.Hasher(key, uintptr(h.hash0)) 721 722 // Set hashWriting after calling t.hasher, since t.hasher may panic, 723 // in which case we have not actually done a write (delete). 724 h.flags ^= hashWriting 725 726 bucket := hash & bucketMask(h.B) 727 if h.growing() { 728 growWork(t, h, bucket) 729 } 730 b := (*bmap)(add(h.buckets, bucket*uintptr(t.BucketSize))) 731 bOrig := b 732 top := tophash(hash) 733 search: 734 for ; b != nil; b = b.overflow(t) { 735 for i := uintptr(0); i < bucketCnt; i++ { 736 if b.tophash[i] != top { 737 if b.tophash[i] == emptyRest { 738 break search 739 } 740 continue 741 } 742 k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) 743 k2 := k 744 if t.IndirectKey() { 745 k2 = *((*unsafe.Pointer)(k2)) 746 } 747 if !t.Key.Equal(key, k2) { 748 continue 749 } 750 // Only clear key if there are pointers in it. 751 if t.IndirectKey() { 752 *(*unsafe.Pointer)(k) = nil 753 } else if t.Key.PtrBytes != 0 { 754 memclrHasPointers(k, t.Key.Size_) 755 } 756 e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 757 if t.IndirectElem() { 758 *(*unsafe.Pointer)(e) = nil 759 } else if t.Elem.PtrBytes != 0 { 760 memclrHasPointers(e, t.Elem.Size_) 761 } else { 762 memclrNoHeapPointers(e, t.Elem.Size_) 763 } 764 b.tophash[i] = emptyOne 765 // If the bucket now ends in a bunch of emptyOne states, 766 // change those to emptyRest states. 767 // It would be nice to make this a separate function, but 768 // for loops are not currently inlineable. 769 if i == bucketCnt-1 { 770 if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { 771 goto notLast 772 } 773 } else { 774 if b.tophash[i+1] != emptyRest { 775 goto notLast 776 } 777 } 778 for { 779 b.tophash[i] = emptyRest 780 if i == 0 { 781 if b == bOrig { 782 break // beginning of initial bucket, we're done. 783 } 784 // Find previous bucket, continue at its last entry. 785 c := b 786 for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { 787 } 788 i = bucketCnt - 1 789 } else { 790 i-- 791 } 792 if b.tophash[i] != emptyOne { 793 break 794 } 795 } 796 notLast: 797 h.count-- 798 // Reset the hash seed to make it more difficult for attackers to 799 // repeatedly trigger hash collisions. See issue 25237. 800 if h.count == 0 { 801 h.hash0 = fastrand() 802 } 803 break search 804 } 805 } 806 807 if h.flags&hashWriting == 0 { 808 fatal("concurrent map writes") 809 } 810 h.flags &^= hashWriting 811 } 812 813 // mapiterinit initializes the hiter struct used for ranging over maps. 814 // The hiter struct pointed to by 'it' is allocated on the stack 815 // by the compilers order pass or on the heap by reflect_mapiterinit. 816 // Both need to have zeroed hiter since the struct contains pointers. 817 func mapiterinit(t *maptype, h *hmap, it *hiter) { 818 if raceenabled && h != nil { 819 callerpc := getcallerpc() 820 racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiterinit)) 821 } 822 823 it.t = t 824 if h == nil || h.count == 0 { 825 return 826 } 827 828 if unsafe.Sizeof(hiter{})/goarch.PtrSize != 12 { 829 throw("hash_iter size incorrect") // see cmd/compile/internal/reflectdata/reflect.go 830 } 831 it.h = h 832 833 // grab snapshot of bucket state 834 it.B = h.B 835 it.buckets = h.buckets 836 if t.Bucket.PtrBytes == 0 { 837 // Allocate the current slice and remember pointers to both current and old. 838 // This preserves all relevant overflow buckets alive even if 839 // the table grows and/or overflow buckets are added to the table 840 // while we are iterating. 841 h.createOverflow() 842 it.overflow = h.extra.overflow 843 it.oldoverflow = h.extra.oldoverflow 844 } 845 846 // decide where to start 847 var r uintptr 848 if h.B > 31-bucketCntBits { 849 r = uintptr(fastrand64()) 850 } else { 851 r = uintptr(fastrand()) 852 } 853 it.startBucket = r & bucketMask(h.B) 854 it.offset = uint8(r >> h.B & (bucketCnt - 1)) 855 856 // iterator state 857 it.bucket = it.startBucket 858 859 // Remember we have an iterator. 860 // Can run concurrently with another mapiterinit(). 861 if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator { 862 atomic.Or8(&h.flags, iterator|oldIterator) 863 } 864 865 mapiternext(it) 866 } 867 868 func mapiternext(it *hiter) { 869 h := it.h 870 if raceenabled { 871 callerpc := getcallerpc() 872 racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiternext)) 873 } 874 if h.flags&hashWriting != 0 { 875 fatal("concurrent map iteration and map write") 876 } 877 t := it.t 878 bucket := it.bucket 879 b := it.bptr 880 i := it.i 881 checkBucket := it.checkBucket 882 883 next: 884 if b == nil { 885 if bucket == it.startBucket && it.wrapped { 886 // end of iteration 887 it.key = nil 888 it.elem = nil 889 return 890 } 891 if h.growing() && it.B == h.B { 892 // Iterator was started in the middle of a grow, and the grow isn't done yet. 893 // If the bucket we're looking at hasn't been filled in yet (i.e. the old 894 // bucket hasn't been evacuated) then we need to iterate through the old 895 // bucket and only return the ones that will be migrated to this bucket. 896 oldbucket := bucket & it.h.oldbucketmask() 897 b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) 898 if !evacuated(b) { 899 checkBucket = bucket 900 } else { 901 b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) 902 checkBucket = noCheck 903 } 904 } else { 905 b = (*bmap)(add(it.buckets, bucket*uintptr(t.BucketSize))) 906 checkBucket = noCheck 907 } 908 bucket++ 909 if bucket == bucketShift(it.B) { 910 bucket = 0 911 it.wrapped = true 912 } 913 i = 0 914 } 915 for ; i < bucketCnt; i++ { 916 offi := (i + it.offset) & (bucketCnt - 1) 917 if isEmpty(b.tophash[offi]) || b.tophash[offi] == evacuatedEmpty { 918 // TODO: emptyRest is hard to use here, as we start iterating 919 // in the middle of a bucket. It's feasible, just tricky. 920 continue 921 } 922 k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.KeySize)) 923 if t.IndirectKey() { 924 k = *((*unsafe.Pointer)(k)) 925 } 926 e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(offi)*uintptr(t.ValueSize)) 927 if checkBucket != noCheck && !h.sameSizeGrow() { 928 // Special case: iterator was started during a grow to a larger size 929 // and the grow is not done yet. We're working on a bucket whose 930 // oldbucket has not been evacuated yet. Or at least, it wasn't 931 // evacuated when we started the bucket. So we're iterating 932 // through the oldbucket, skipping any keys that will go 933 // to the other new bucket (each oldbucket expands to two 934 // buckets during a grow). 935 if t.ReflexiveKey() || t.Key.Equal(k, k) { 936 // If the item in the oldbucket is not destined for 937 // the current new bucket in the iteration, skip it. 938 hash := t.Hasher(k, uintptr(h.hash0)) 939 if hash&bucketMask(it.B) != checkBucket { 940 continue 941 } 942 } else { 943 // Hash isn't repeatable if k != k (NaNs). We need a 944 // repeatable and randomish choice of which direction 945 // to send NaNs during evacuation. We'll use the low 946 // bit of tophash to decide which way NaNs go. 947 // NOTE: this case is why we need two evacuate tophash 948 // values, evacuatedX and evacuatedY, that differ in 949 // their low bit. 950 if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) { 951 continue 952 } 953 } 954 } 955 if (b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY) || 956 !(t.ReflexiveKey() || t.Key.Equal(k, k)) { 957 // This is the golden data, we can return it. 958 // OR 959 // key!=key, so the entry can't be deleted or updated, so we can just return it. 960 // That's lucky for us because when key!=key we can't look it up successfully. 961 it.key = k 962 if t.IndirectElem() { 963 e = *((*unsafe.Pointer)(e)) 964 } 965 it.elem = e 966 } else { 967 // The hash table has grown since the iterator was started. 968 // The golden data for this key is now somewhere else. 969 // Check the current hash table for the data. 970 // This code handles the case where the key 971 // has been deleted, updated, or deleted and reinserted. 972 // NOTE: we need to regrab the key as it has potentially been 973 // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). 974 rk, re := mapaccessK(t, h, k) 975 if rk == nil { 976 continue // key has been deleted 977 } 978 it.key = rk 979 it.elem = re 980 } 981 it.bucket = bucket 982 if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 983 it.bptr = b 984 } 985 it.i = i + 1 986 it.checkBucket = checkBucket 987 return 988 } 989 b = b.overflow(t) 990 i = 0 991 goto next 992 } 993 994 // mapclear deletes all keys from a map. 995 func mapclear(t *maptype, h *hmap) { 996 if raceenabled && h != nil { 997 callerpc := getcallerpc() 998 pc := abi.FuncPCABIInternal(mapclear) 999 racewritepc(unsafe.Pointer(h), callerpc, pc) 1000 } 1001 1002 if h == nil || h.count == 0 { 1003 return 1004 } 1005 1006 if h.flags&hashWriting != 0 { 1007 fatal("concurrent map writes") 1008 } 1009 1010 h.flags ^= hashWriting 1011 1012 // Mark buckets empty, so existing iterators can be terminated, see issue #59411. 1013 markBucketsEmpty := func(bucket unsafe.Pointer, mask uintptr) { 1014 for i := uintptr(0); i <= mask; i++ { 1015 b := (*bmap)(add(bucket, i*uintptr(t.BucketSize))) 1016 for ; b != nil; b = b.overflow(t) { 1017 for i := uintptr(0); i < bucketCnt; i++ { 1018 b.tophash[i] = emptyRest 1019 } 1020 } 1021 } 1022 } 1023 markBucketsEmpty(h.buckets, bucketMask(h.B)) 1024 if oldBuckets := h.oldbuckets; oldBuckets != nil { 1025 markBucketsEmpty(oldBuckets, h.oldbucketmask()) 1026 } 1027 1028 h.flags &^= sameSizeGrow 1029 h.oldbuckets = nil 1030 h.nevacuate = 0 1031 h.noverflow = 0 1032 h.count = 0 1033 1034 // Reset the hash seed to make it more difficult for attackers to 1035 // repeatedly trigger hash collisions. See issue 25237. 1036 h.hash0 = fastrand() 1037 1038 // Keep the mapextra allocation but clear any extra information. 1039 if h.extra != nil { 1040 *h.extra = mapextra{} 1041 } 1042 1043 // makeBucketArray clears the memory pointed to by h.buckets 1044 // and recovers any overflow buckets by generating them 1045 // as if h.buckets was newly alloced. 1046 _, nextOverflow := makeBucketArray(t, h.B, h.buckets) 1047 if nextOverflow != nil { 1048 // If overflow buckets are created then h.extra 1049 // will have been allocated during initial bucket creation. 1050 h.extra.nextOverflow = nextOverflow 1051 } 1052 1053 if h.flags&hashWriting == 0 { 1054 fatal("concurrent map writes") 1055 } 1056 h.flags &^= hashWriting 1057 } 1058 1059 func hashGrow(t *maptype, h *hmap) { 1060 // If we've hit the load factor, get bigger. 1061 // Otherwise, there are too many overflow buckets, 1062 // so keep the same number of buckets and "grow" laterally. 1063 bigger := uint8(1) 1064 if !overLoadFactor(h.count+1, h.B) { 1065 bigger = 0 1066 h.flags |= sameSizeGrow 1067 } 1068 oldbuckets := h.buckets 1069 newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger, nil) 1070 1071 flags := h.flags &^ (iterator | oldIterator) 1072 if h.flags&iterator != 0 { 1073 flags |= oldIterator 1074 } 1075 // commit the grow (atomic wrt gc) 1076 h.B += bigger 1077 h.flags = flags 1078 h.oldbuckets = oldbuckets 1079 h.buckets = newbuckets 1080 h.nevacuate = 0 1081 h.noverflow = 0 1082 1083 if h.extra != nil && h.extra.overflow != nil { 1084 // Promote current overflow buckets to the old generation. 1085 if h.extra.oldoverflow != nil { 1086 throw("oldoverflow is not nil") 1087 } 1088 h.extra.oldoverflow = h.extra.overflow 1089 h.extra.overflow = nil 1090 } 1091 if nextOverflow != nil { 1092 if h.extra == nil { 1093 h.extra = new(mapextra) 1094 } 1095 h.extra.nextOverflow = nextOverflow 1096 } 1097 1098 // the actual copying of the hash table data is done incrementally 1099 // by growWork() and evacuate(). 1100 } 1101 1102 // overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor. 1103 func overLoadFactor(count int, B uint8) bool { 1104 return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) 1105 } 1106 1107 // tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<<B buckets. 1108 // Note that most of these overflow buckets must be in sparse use; 1109 // if use was dense, then we'd have already triggered regular map growth. 1110 func tooManyOverflowBuckets(noverflow uint16, B uint8) bool { 1111 // If the threshold is too low, we do extraneous work. 1112 // If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory. 1113 // "too many" means (approximately) as many overflow buckets as regular buckets. 1114 // See incrnoverflow for more details. 1115 if B > 15 { 1116 B = 15 1117 } 1118 // The compiler doesn't see here that B < 16; mask B to generate shorter shift code. 1119 return noverflow >= uint16(1)<<(B&15) 1120 } 1121 1122 // growing reports whether h is growing. The growth may be to the same size or bigger. 1123 func (h *hmap) growing() bool { 1124 return h.oldbuckets != nil 1125 } 1126 1127 // sameSizeGrow reports whether the current growth is to a map of the same size. 1128 func (h *hmap) sameSizeGrow() bool { 1129 return h.flags&sameSizeGrow != 0 1130 } 1131 1132 // noldbuckets calculates the number of buckets prior to the current map growth. 1133 func (h *hmap) noldbuckets() uintptr { 1134 oldB := h.B 1135 if !h.sameSizeGrow() { 1136 oldB-- 1137 } 1138 return bucketShift(oldB) 1139 } 1140 1141 // oldbucketmask provides a mask that can be applied to calculate n % noldbuckets(). 1142 func (h *hmap) oldbucketmask() uintptr { 1143 return h.noldbuckets() - 1 1144 } 1145 1146 func growWork(t *maptype, h *hmap, bucket uintptr) { 1147 // make sure we evacuate the oldbucket corresponding 1148 // to the bucket we're about to use 1149 evacuate(t, h, bucket&h.oldbucketmask()) 1150 1151 // evacuate one more oldbucket to make progress on growing 1152 if h.growing() { 1153 evacuate(t, h, h.nevacuate) 1154 } 1155 } 1156 1157 func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool { 1158 b := (*bmap)(add(h.oldbuckets, bucket*uintptr(t.BucketSize))) 1159 return evacuated(b) 1160 } 1161 1162 // evacDst is an evacuation destination. 1163 type evacDst struct { 1164 b *bmap // current destination bucket 1165 i int // key/elem index into b 1166 k unsafe.Pointer // pointer to current key storage 1167 e unsafe.Pointer // pointer to current elem storage 1168 } 1169 1170 func evacuate(t *maptype, h *hmap, oldbucket uintptr) { 1171 b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.BucketSize))) 1172 newbit := h.noldbuckets() 1173 if !evacuated(b) { 1174 // TODO: reuse overflow buckets instead of using new ones, if there 1175 // is no iterator using the old buckets. (If !oldIterator.) 1176 1177 // xy contains the x and y (low and high) evacuation destinations. 1178 var xy [2]evacDst 1179 x := &xy[0] 1180 x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) 1181 x.k = add(unsafe.Pointer(x.b), dataOffset) 1182 x.e = add(x.k, bucketCnt*uintptr(t.KeySize)) 1183 1184 if !h.sameSizeGrow() { 1185 // Only calculate y pointers if we're growing bigger. 1186 // Otherwise GC can see bad pointers. 1187 y := &xy[1] 1188 y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) 1189 y.k = add(unsafe.Pointer(y.b), dataOffset) 1190 y.e = add(y.k, bucketCnt*uintptr(t.KeySize)) 1191 } 1192 1193 for ; b != nil; b = b.overflow(t) { 1194 k := add(unsafe.Pointer(b), dataOffset) 1195 e := add(k, bucketCnt*uintptr(t.KeySize)) 1196 for i := 0; i < bucketCnt; i, k, e = i+1, add(k, uintptr(t.KeySize)), add(e, uintptr(t.ValueSize)) { 1197 top := b.tophash[i] 1198 if isEmpty(top) { 1199 b.tophash[i] = evacuatedEmpty 1200 continue 1201 } 1202 if top < minTopHash { 1203 throw("bad map state") 1204 } 1205 k2 := k 1206 if t.IndirectKey() { 1207 k2 = *((*unsafe.Pointer)(k2)) 1208 } 1209 var useY uint8 1210 if !h.sameSizeGrow() { 1211 // Compute hash to make our evacuation decision (whether we need 1212 // to send this key/elem to bucket x or bucket y). 1213 hash := t.Hasher(k2, uintptr(h.hash0)) 1214 if h.flags&iterator != 0 && !t.ReflexiveKey() && !t.Key.Equal(k2, k2) { 1215 // If key != key (NaNs), then the hash could be (and probably 1216 // will be) entirely different from the old hash. Moreover, 1217 // it isn't reproducible. Reproducibility is required in the 1218 // presence of iterators, as our evacuation decision must 1219 // match whatever decision the iterator made. 1220 // Fortunately, we have the freedom to send these keys either 1221 // way. Also, tophash is meaningless for these kinds of keys. 1222 // We let the low bit of tophash drive the evacuation decision. 1223 // We recompute a new random tophash for the next level so 1224 // these keys will get evenly distributed across all buckets 1225 // after multiple grows. 1226 useY = top & 1 1227 top = tophash(hash) 1228 } else { 1229 if hash&newbit != 0 { 1230 useY = 1 1231 } 1232 } 1233 } 1234 1235 if evacuatedX+1 != evacuatedY || evacuatedX^1 != evacuatedY { 1236 throw("bad evacuatedN") 1237 } 1238 1239 b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY 1240 dst := &xy[useY] // evacuation destination 1241 1242 if dst.i == bucketCnt { 1243 dst.b = h.newoverflow(t, dst.b) 1244 dst.i = 0 1245 dst.k = add(unsafe.Pointer(dst.b), dataOffset) 1246 dst.e = add(dst.k, bucketCnt*uintptr(t.KeySize)) 1247 } 1248 dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check 1249 if t.IndirectKey() { 1250 *(*unsafe.Pointer)(dst.k) = k2 // copy pointer 1251 } else { 1252 typedmemmove(t.Key, dst.k, k) // copy elem 1253 } 1254 if t.IndirectElem() { 1255 *(*unsafe.Pointer)(dst.e) = *(*unsafe.Pointer)(e) 1256 } else { 1257 typedmemmove(t.Elem, dst.e, e) 1258 } 1259 dst.i++ 1260 // These updates might push these pointers past the end of the 1261 // key or elem arrays. That's ok, as we have the overflow pointer 1262 // at the end of the bucket to protect against pointing past the 1263 // end of the bucket. 1264 dst.k = add(dst.k, uintptr(t.KeySize)) 1265 dst.e = add(dst.e, uintptr(t.ValueSize)) 1266 } 1267 } 1268 // Unlink the overflow buckets & clear key/elem to help GC. 1269 if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { 1270 b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) 1271 // Preserve b.tophash because the evacuation 1272 // state is maintained there. 1273 ptr := add(b, dataOffset) 1274 n := uintptr(t.BucketSize) - dataOffset 1275 memclrHasPointers(ptr, n) 1276 } 1277 } 1278 1279 if oldbucket == h.nevacuate { 1280 advanceEvacuationMark(h, t, newbit) 1281 } 1282 } 1283 1284 func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) { 1285 h.nevacuate++ 1286 // Experiments suggest that 1024 is overkill by at least an order of magnitude. 1287 // Put it in there as a safeguard anyway, to ensure O(1) behavior. 1288 stop := h.nevacuate + 1024 1289 if stop > newbit { 1290 stop = newbit 1291 } 1292 for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { 1293 h.nevacuate++ 1294 } 1295 if h.nevacuate == newbit { // newbit == # of oldbuckets 1296 // Growing is all done. Free old main bucket array. 1297 h.oldbuckets = nil 1298 // Can discard old overflow buckets as well. 1299 // If they are still referenced by an iterator, 1300 // then the iterator holds a pointers to the slice. 1301 if h.extra != nil { 1302 h.extra.oldoverflow = nil 1303 } 1304 h.flags &^= sameSizeGrow 1305 } 1306 } 1307 1308 // Reflect stubs. Called from ../reflect/asm_*.s 1309 1310 //go:linkname reflect_makemap reflect.makemap 1311 func reflect_makemap(t *maptype, cap int) *hmap { 1312 // Check invariants and reflects math. 1313 if t.Key.Equal == nil { 1314 throw("runtime.reflect_makemap: unsupported map key type") 1315 } 1316 if t.Key.Size_ > maxKeySize && (!t.IndirectKey() || t.KeySize != uint8(goarch.PtrSize)) || 1317 t.Key.Size_ <= maxKeySize && (t.IndirectKey() || t.KeySize != uint8(t.Key.Size_)) { 1318 throw("key size wrong") 1319 } 1320 if t.Elem.Size_ > maxElemSize && (!t.IndirectElem() || t.ValueSize != uint8(goarch.PtrSize)) || 1321 t.Elem.Size_ <= maxElemSize && (t.IndirectElem() || t.ValueSize != uint8(t.Elem.Size_)) { 1322 throw("elem size wrong") 1323 } 1324 if t.Key.Align_ > bucketCnt { 1325 throw("key align too big") 1326 } 1327 if t.Elem.Align_ > bucketCnt { 1328 throw("elem align too big") 1329 } 1330 if t.Key.Size_%uintptr(t.Key.Align_) != 0 { 1331 throw("key size not a multiple of key align") 1332 } 1333 if t.Elem.Size_%uintptr(t.Elem.Align_) != 0 { 1334 throw("elem size not a multiple of elem align") 1335 } 1336 if bucketCnt < 8 { 1337 throw("bucketsize too small for proper alignment") 1338 } 1339 if dataOffset%uintptr(t.Key.Align_) != 0 { 1340 throw("need padding in bucket (key)") 1341 } 1342 if dataOffset%uintptr(t.Elem.Align_) != 0 { 1343 throw("need padding in bucket (elem)") 1344 } 1345 1346 return makemap(t, cap, nil) 1347 } 1348 1349 //go:linkname reflect_mapaccess reflect.mapaccess 1350 func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { 1351 elem, ok := mapaccess2(t, h, key) 1352 if !ok { 1353 // reflect wants nil for a missing element 1354 elem = nil 1355 } 1356 return elem 1357 } 1358 1359 //go:linkname reflect_mapaccess_faststr reflect.mapaccess_faststr 1360 func reflect_mapaccess_faststr(t *maptype, h *hmap, key string) unsafe.Pointer { 1361 elem, ok := mapaccess2_faststr(t, h, key) 1362 if !ok { 1363 // reflect wants nil for a missing element 1364 elem = nil 1365 } 1366 return elem 1367 } 1368 1369 //go:linkname reflect_mapassign reflect.mapassign0 1370 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, elem unsafe.Pointer) { 1371 p := mapassign(t, h, key) 1372 typedmemmove(t.Elem, p, elem) 1373 } 1374 1375 //go:linkname reflect_mapassign_faststr reflect.mapassign_faststr0 1376 func reflect_mapassign_faststr(t *maptype, h *hmap, key string, elem unsafe.Pointer) { 1377 p := mapassign_faststr(t, h, key) 1378 typedmemmove(t.Elem, p, elem) 1379 } 1380 1381 //go:linkname reflect_mapdelete reflect.mapdelete 1382 func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { 1383 mapdelete(t, h, key) 1384 } 1385 1386 //go:linkname reflect_mapdelete_faststr reflect.mapdelete_faststr 1387 func reflect_mapdelete_faststr(t *maptype, h *hmap, key string) { 1388 mapdelete_faststr(t, h, key) 1389 } 1390 1391 //go:linkname reflect_mapiterinit reflect.mapiterinit 1392 func reflect_mapiterinit(t *maptype, h *hmap, it *hiter) { 1393 mapiterinit(t, h, it) 1394 } 1395 1396 //go:linkname reflect_mapiternext reflect.mapiternext 1397 func reflect_mapiternext(it *hiter) { 1398 mapiternext(it) 1399 } 1400 1401 //go:linkname reflect_mapiterkey reflect.mapiterkey 1402 func reflect_mapiterkey(it *hiter) unsafe.Pointer { 1403 return it.key 1404 } 1405 1406 //go:linkname reflect_mapiterelem reflect.mapiterelem 1407 func reflect_mapiterelem(it *hiter) unsafe.Pointer { 1408 return it.elem 1409 } 1410 1411 //go:linkname reflect_maplen reflect.maplen 1412 func reflect_maplen(h *hmap) int { 1413 if h == nil { 1414 return 0 1415 } 1416 if raceenabled { 1417 callerpc := getcallerpc() 1418 racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) 1419 } 1420 return h.count 1421 } 1422 1423 //go:linkname reflect_mapclear reflect.mapclear 1424 func reflect_mapclear(t *maptype, h *hmap) { 1425 mapclear(t, h) 1426 } 1427 1428 //go:linkname reflectlite_maplen internal/reflectlite.maplen 1429 func reflectlite_maplen(h *hmap) int { 1430 if h == nil { 1431 return 0 1432 } 1433 if raceenabled { 1434 callerpc := getcallerpc() 1435 racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(reflect_maplen)) 1436 } 1437 return h.count 1438 } 1439 1440 const maxZero = 1024 // must match value in reflect/value.go:maxZero cmd/compile/internal/gc/walk.go:zeroValSize 1441 var zeroVal [maxZero]byte 1442 1443 // mapinitnoop is a no-op function known the Go linker; if a given global 1444 // map (of the right size) is determined to be dead, the linker will 1445 // rewrite the relocation (from the package init func) from the outlined 1446 // map init function to this symbol. Defined in assembly so as to avoid 1447 // complications with instrumentation (coverage, etc). 1448 func mapinitnoop() 1449 1450 // mapclone for implementing maps.Clone 1451 // 1452 //go:linkname mapclone maps.clone 1453 func mapclone(m any) any { 1454 e := efaceOf(&m) 1455 e.data = unsafe.Pointer(mapclone2((*maptype)(unsafe.Pointer(e._type)), (*hmap)(e.data))) 1456 return m 1457 } 1458 1459 // moveToBmap moves a bucket from src to dst. It returns the destination bucket or new destination bucket if it overflows 1460 // and the pos that the next key/value will be written, if pos == bucketCnt means needs to written in overflow bucket. 1461 func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) { 1462 for i := 0; i < bucketCnt; i++ { 1463 if isEmpty(src.tophash[i]) { 1464 continue 1465 } 1466 1467 for ; pos < bucketCnt; pos++ { 1468 if isEmpty(dst.tophash[pos]) { 1469 break 1470 } 1471 } 1472 1473 if pos == bucketCnt { 1474 dst = h.newoverflow(t, dst) 1475 pos = 0 1476 } 1477 1478 srcK := add(unsafe.Pointer(src), dataOffset+uintptr(i)*uintptr(t.KeySize)) 1479 srcEle := add(unsafe.Pointer(src), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(i)*uintptr(t.ValueSize)) 1480 dstK := add(unsafe.Pointer(dst), dataOffset+uintptr(pos)*uintptr(t.KeySize)) 1481 dstEle := add(unsafe.Pointer(dst), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(pos)*uintptr(t.ValueSize)) 1482 1483 dst.tophash[pos] = src.tophash[i] 1484 if t.IndirectKey() { 1485 *(*unsafe.Pointer)(dstK) = *(*unsafe.Pointer)(srcK) 1486 } else { 1487 typedmemmove(t.Key, dstK, srcK) 1488 } 1489 if t.IndirectElem() { 1490 *(*unsafe.Pointer)(dstEle) = *(*unsafe.Pointer)(srcEle) 1491 } else { 1492 typedmemmove(t.Elem, dstEle, srcEle) 1493 } 1494 pos++ 1495 h.count++ 1496 } 1497 return dst, pos 1498 } 1499 1500 func mapclone2(t *maptype, src *hmap) *hmap { 1501 dst := makemap(t, src.count, nil) 1502 dst.hash0 = src.hash0 1503 dst.nevacuate = 0 1504 //flags do not need to be copied here, just like a new map has no flags. 1505 1506 if src.count == 0 { 1507 return dst 1508 } 1509 1510 if src.flags&hashWriting != 0 { 1511 fatal("concurrent map clone and map write") 1512 } 1513 1514 if src.B == 0 { 1515 dst.buckets = newobject(t.Bucket) 1516 dst.count = src.count 1517 typedmemmove(t.Bucket, dst.buckets, src.buckets) 1518 return dst 1519 } 1520 1521 //src.B != 0 1522 if dst.B == 0 { 1523 dst.buckets = newobject(t.Bucket) 1524 } 1525 dstArraySize := int(bucketShift(dst.B)) 1526 srcArraySize := int(bucketShift(src.B)) 1527 for i := 0; i < dstArraySize; i++ { 1528 dstBmap := (*bmap)(add(dst.buckets, uintptr(i*int(t.BucketSize)))) 1529 pos := 0 1530 for j := 0; j < srcArraySize; j += dstArraySize { 1531 srcBmap := (*bmap)(add(src.buckets, uintptr((i+j)*int(t.BucketSize)))) 1532 for srcBmap != nil { 1533 dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) 1534 srcBmap = srcBmap.overflow(t) 1535 } 1536 } 1537 } 1538 1539 if src.oldbuckets == nil { 1540 return dst 1541 } 1542 1543 oldB := src.B 1544 srcOldbuckets := src.oldbuckets 1545 if !src.sameSizeGrow() { 1546 oldB-- 1547 } 1548 oldSrcArraySize := int(bucketShift(oldB)) 1549 1550 for i := 0; i < oldSrcArraySize; i++ { 1551 srcBmap := (*bmap)(add(srcOldbuckets, uintptr(i*int(t.BucketSize)))) 1552 if evacuated(srcBmap) { 1553 continue 1554 } 1555 1556 if oldB >= dst.B { // main bucket bits in dst is less than oldB bits in src 1557 dstBmap := (*bmap)(add(dst.buckets, (uintptr(i)&bucketMask(dst.B))*uintptr(t.BucketSize))) 1558 for dstBmap.overflow(t) != nil { 1559 dstBmap = dstBmap.overflow(t) 1560 } 1561 pos := 0 1562 for srcBmap != nil { 1563 dstBmap, pos = moveToBmap(t, dst, dstBmap, pos, srcBmap) 1564 srcBmap = srcBmap.overflow(t) 1565 } 1566 continue 1567 } 1568 1569 for srcBmap != nil { 1570 // move from oldBlucket to new bucket 1571 for i := uintptr(0); i < bucketCnt; i++ { 1572 if isEmpty(srcBmap.tophash[i]) { 1573 continue 1574 } 1575 1576 if src.flags&hashWriting != 0 { 1577 fatal("concurrent map clone and map write") 1578 } 1579 1580 srcK := add(unsafe.Pointer(srcBmap), dataOffset+i*uintptr(t.KeySize)) 1581 if t.IndirectKey() { 1582 srcK = *((*unsafe.Pointer)(srcK)) 1583 } 1584 1585 srcEle := add(unsafe.Pointer(srcBmap), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) 1586 if t.IndirectElem() { 1587 srcEle = *((*unsafe.Pointer)(srcEle)) 1588 } 1589 dstEle := mapassign(t, dst, srcK) 1590 typedmemmove(t.Elem, dstEle, srcEle) 1591 } 1592 srcBmap = srcBmap.overflow(t) 1593 } 1594 } 1595 return dst 1596 } 1597 1598 // keys for implementing maps.keys 1599 // 1600 //go:linkname keys maps.keys 1601 func keys(m any, p unsafe.Pointer) { 1602 e := efaceOf(&m) 1603 t := (*maptype)(unsafe.Pointer(e._type)) 1604 h := (*hmap)(e.data) 1605 1606 if h == nil || h.count == 0 { 1607 return 1608 } 1609 s := (*slice)(p) 1610 r := int(fastrand()) 1611 offset := uint8(r >> h.B & (bucketCnt - 1)) 1612 if h.B == 0 { 1613 copyKeys(t, h, (*bmap)(h.buckets), s, offset) 1614 return 1615 } 1616 arraySize := int(bucketShift(h.B)) 1617 buckets := h.buckets 1618 for i := 0; i < arraySize; i++ { 1619 bucket := (i + r) & (arraySize - 1) 1620 b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) 1621 copyKeys(t, h, b, s, offset) 1622 } 1623 1624 if h.growing() { 1625 oldArraySize := int(h.noldbuckets()) 1626 for i := 0; i < oldArraySize; i++ { 1627 bucket := (i + r) & (oldArraySize - 1) 1628 b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) 1629 if evacuated(b) { 1630 continue 1631 } 1632 copyKeys(t, h, b, s, offset) 1633 } 1634 } 1635 return 1636 } 1637 1638 func copyKeys(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { 1639 for b != nil { 1640 for i := uintptr(0); i < bucketCnt; i++ { 1641 offi := (i + uintptr(offset)) & (bucketCnt - 1) 1642 if isEmpty(b.tophash[offi]) { 1643 continue 1644 } 1645 if h.flags&hashWriting != 0 { 1646 fatal("concurrent map read and map write") 1647 } 1648 k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.KeySize)) 1649 if t.IndirectKey() { 1650 k = *((*unsafe.Pointer)(k)) 1651 } 1652 if s.len >= s.cap { 1653 fatal("concurrent map read and map write") 1654 } 1655 typedmemmove(t.Key, add(s.array, uintptr(s.len)*uintptr(t.KeySize)), k) 1656 s.len++ 1657 } 1658 b = b.overflow(t) 1659 } 1660 } 1661 1662 // values for implementing maps.values 1663 // 1664 //go:linkname values maps.values 1665 func values(m any, p unsafe.Pointer) { 1666 e := efaceOf(&m) 1667 t := (*maptype)(unsafe.Pointer(e._type)) 1668 h := (*hmap)(e.data) 1669 if h == nil || h.count == 0 { 1670 return 1671 } 1672 s := (*slice)(p) 1673 r := int(fastrand()) 1674 offset := uint8(r >> h.B & (bucketCnt - 1)) 1675 if h.B == 0 { 1676 copyValues(t, h, (*bmap)(h.buckets), s, offset) 1677 return 1678 } 1679 arraySize := int(bucketShift(h.B)) 1680 buckets := h.buckets 1681 for i := 0; i < arraySize; i++ { 1682 bucket := (i + r) & (arraySize - 1) 1683 b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize))) 1684 copyValues(t, h, b, s, offset) 1685 } 1686 1687 if h.growing() { 1688 oldArraySize := int(h.noldbuckets()) 1689 for i := 0; i < oldArraySize; i++ { 1690 bucket := (i + r) & (oldArraySize - 1) 1691 b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize))) 1692 if evacuated(b) { 1693 continue 1694 } 1695 copyValues(t, h, b, s, offset) 1696 } 1697 } 1698 return 1699 } 1700 1701 func copyValues(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { 1702 for b != nil { 1703 for i := uintptr(0); i < bucketCnt; i++ { 1704 offi := (i + uintptr(offset)) & (bucketCnt - 1) 1705 if isEmpty(b.tophash[offi]) { 1706 continue 1707 } 1708 1709 if h.flags&hashWriting != 0 { 1710 fatal("concurrent map read and map write") 1711 } 1712 1713 ele := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+offi*uintptr(t.ValueSize)) 1714 if t.IndirectElem() { 1715 ele = *((*unsafe.Pointer)(ele)) 1716 } 1717 if s.len >= s.cap { 1718 fatal("concurrent map read and map write") 1719 } 1720 typedmemmove(t.Elem, add(s.array, uintptr(s.len)*uintptr(t.ValueSize)), ele) 1721 s.len++ 1722 } 1723 b = b.overflow(t) 1724 } 1725 } 1726 */