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