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