hashmap.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  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. package runtime
  5. // This file contains the implementation of Go's map type.
  6. //
  7. // A map is just a hash table. The data is arranged
  8. // into an array of buckets. Each bucket contains up to
  9. // 8 key/value pairs. The low-order bits of the hash are
  10. // used to select a bucket. Each bucket contains a few
  11. // high-order bits of each hash to distinguish the entries
  12. // within a single bucket.
  13. //
  14. // If more than 8 keys hash to a bucket, we chain on
  15. // extra buckets.
  16. //
  17. // When the hashtable grows, we allocate a new array
  18. // of buckets twice as big. Buckets are incrementally
  19. // copied from the old bucket array to the new bucket array.
  20. //
  21. // Map iterators walk through the array of buckets and
  22. // return the keys in walk order (bucket #, then overflow
  23. // chain order, then bucket index). To maintain iteration
  24. // semantics, we never move keys within their bucket (if
  25. // we did, keys might be returned 0 or 2 times). When
  26. // growing the table, iterators remain iterating through the
  27. // old table and must check the new table if the bucket
  28. // they are iterating through has been moved ("evacuated")
  29. // to the new table.
  30. // Picking loadFactor: too large and we have lots of overflow
  31. // buckets, too small and we waste a lot of space. I wrote
  32. // a simple program to check some stats for different loads:
  33. // (64-bit, 8 byte keys and values)
  34. // loadFactor %overflow bytes/entry hitprobe missprobe
  35. // 4.00 2.13 20.77 3.00 4.00
  36. // 4.50 4.05 17.30 3.25 4.50
  37. // 5.00 6.85 14.77 3.50 5.00
  38. // 5.50 10.55 12.94 3.75 5.50
  39. // 6.00 15.27 11.67 4.00 6.00
  40. // 6.50 20.90 10.79 4.25 6.50
  41. // 7.00 27.14 10.15 4.50 7.00
  42. // 7.50 34.03 9.73 4.75 7.50
  43. // 8.00 41.10 9.40 5.00 8.00
  44. //
  45. // %overflow = percentage of buckets which have an overflow bucket
  46. // bytes/entry = overhead bytes used per key/value pair
  47. // hitprobe = # of entries to check when looking up a present key
  48. // missprobe = # of entries to check when looking up an absent key
  49. //
  50. // Keep in mind this data is for maximally loaded tables, i.e. just
  51. // before the table grows. Typical tables will be somewhat less loaded.
  52. import (
  53. "unsafe"
  54. )
  55. const (
  56. // Maximum number of key/value pairs a bucket can hold.
  57. bucketCntBits = 3
  58. bucketCnt = 1 << bucketCntBits
  59. // Maximum average load of a bucket that triggers growth.
  60. loadFactor = 6.5
  61. // Maximum key or value size to keep inline (instead of mallocing per element).
  62. // Must fit in a uint8.
  63. // Fast versions cannot handle big values - the cutoff size for
  64. // fast versions in ../../cmd/gc/walk.c must be at most this value.
  65. maxKeySize = 128
  66. maxValueSize = 128
  67. // data offset should be the size of the bmap struct, but needs to be
  68. // aligned correctly. For amd64p32 this means 64-bit alignment
  69. // even though pointers are 32 bit.
  70. dataOffset = unsafe.Offsetof(struct {
  71. b bmap
  72. v int64
  73. }{}.v)
  74. // Possible tophash values. We reserve a few possibilities for special marks.
  75. // Each bucket (including its overflow buckets, if any) will have either all or none of its
  76. // entries in the evacuated* states (except during the evacuate() method, which only happens
  77. // during map writes and thus no one else can observe the map during that time).
  78. empty = 0 // cell is empty
  79. evacuatedEmpty = 1 // cell is empty, bucket is evacuated.
  80. evacuatedX = 2 // key/value is valid. Entry has been evacuated to first half of larger table.
  81. evacuatedY = 3 // same as above, but evacuated to second half of larger table.
  82. minTopHash = 4 // minimum tophash for a normal filled cell.
  83. // flags
  84. iterator = 1 // there may be an iterator using buckets
  85. oldIterator = 2 // there may be an iterator using oldbuckets
  86. // sentinel bucket ID for iterator checks
  87. noCheck = 1<<(8*ptrSize) - 1
  88. // trigger a garbage collection at every alloc called from this code
  89. checkgc = false
  90. )
  91. // A header for a Go map.
  92. type hmap struct {
  93. // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
  94. // ../reflect/type.go. Don't change this structure without also changing that code!
  95. count int // # live cells == size of map. Must be first (used by len() builtin)
  96. flags uint32
  97. hash0 uint32 // hash seed
  98. B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  99. buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  100. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  101. nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
  102. }
  103. // A bucket for a Go map.
  104. type bmap struct {
  105. tophash [bucketCnt]uint8
  106. // Followed by bucketCnt keys and then bucketCnt values.
  107. // NOTE: packing all the keys together and then all the values together makes the
  108. // code a bit more complicated than alternating key/value/key/value/... but it allows
  109. // us to eliminate padding which would be needed for, e.g., map[int64]int8.
  110. // Followed by an overflow pointer.
  111. }
  112. // A hash iteration structure.
  113. // If you modify hiter, also change cmd/gc/reflect.c to indicate
  114. // the layout of this structure.
  115. type hiter struct {
  116. key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
  117. value unsafe.Pointer // Must be in second position (see cmd/gc/range.c).
  118. t *maptype
  119. h *hmap
  120. buckets unsafe.Pointer // bucket ptr at hash_iter initialization time
  121. bptr *bmap // current bucket
  122. startBucket uintptr // bucket iteration started at
  123. offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
  124. wrapped bool // already wrapped around from end of bucket array to beginning
  125. B uint8
  126. i uint8
  127. bucket uintptr
  128. checkBucket uintptr
  129. }
  130. func evacuated(b *bmap) bool {
  131. h := b.tophash[0]
  132. return h > empty && h < minTopHash
  133. }
  134. func (b *bmap) overflow(t *maptype) *bmap {
  135. return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize))
  136. }
  137. func (b *bmap) setoverflow(t *maptype, ovf *bmap) {
  138. *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf
  139. }
  140. func makemap(t *maptype, hint int64) *hmap {
  141. if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) {
  142. gothrow("bad hmap size")
  143. }
  144. if hint < 0 || int64(int32(hint)) != hint {
  145. panic("makemap: size out of range")
  146. // TODO: make hint an int, then none of this nonsense
  147. }
  148. if !ismapkey(t.key) {
  149. gothrow("runtime.makemap: unsupported map key type")
  150. }
  151. // check compiler's and reflect's math
  152. if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(ptrSize)) ||
  153. t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) {
  154. gothrow("key size wrong")
  155. }
  156. if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(ptrSize)) ||
  157. t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) {
  158. gothrow("value size wrong")
  159. }
  160. // invariants we depend on. We should probably check these at compile time
  161. // somewhere, but for now we'll do it here.
  162. if t.key.align > bucketCnt {
  163. gothrow("key align too big")
  164. }
  165. if t.elem.align > bucketCnt {
  166. gothrow("value align too big")
  167. }
  168. if uintptr(t.key.size)%uintptr(t.key.align) != 0 {
  169. gothrow("key size not a multiple of key align")
  170. }
  171. if uintptr(t.elem.size)%uintptr(t.elem.align) != 0 {
  172. gothrow("value size not a multiple of value align")
  173. }
  174. if bucketCnt < 8 {
  175. gothrow("bucketsize too small for proper alignment")
  176. }
  177. if dataOffset%uintptr(t.key.align) != 0 {
  178. gothrow("need padding in bucket (key)")
  179. }
  180. if dataOffset%uintptr(t.elem.align) != 0 {
  181. gothrow("need padding in bucket (value)")
  182. }
  183. // find size parameter which will hold the requested # of elements
  184. B := uint8(0)
  185. for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<<B); B++ {
  186. }
  187. // allocate initial hash table
  188. // if B == 0, the buckets field is allocated lazily later (in mapassign)
  189. // If hint is large zeroing this memory could take a while.
  190. var buckets unsafe.Pointer
  191. if B != 0 {
  192. if checkgc {
  193. memstats.next_gc = memstats.heap_alloc
  194. }
  195. buckets = newarray(t.bucket, uintptr(1)<<B)
  196. }
  197. // initialize Hmap
  198. if checkgc {
  199. memstats.next_gc = memstats.heap_alloc
  200. }
  201. h := (*hmap)(newobject(t.hmap))
  202. h.count = 0
  203. h.B = B
  204. h.flags = 0
  205. h.hash0 = fastrand1()
  206. h.buckets = buckets
  207. h.oldbuckets = nil
  208. h.nevacuate = 0
  209. return h
  210. }
  211. // mapaccess1 returns a pointer to h[key]. Never returns nil, instead
  212. // it will return a reference to the zero object for the value type if
  213. // the key is not in the map.
  214. // NOTE: The returned pointer may keep the whole map live, so don't
  215. // hold onto it for very long.
  216. func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
  217. if raceenabled && h != nil {
  218. callerpc := getcallerpc(unsafe.Pointer(&t))
  219. pc := funcPC(mapaccess1)
  220. racereadpc(unsafe.Pointer(h), callerpc, pc)
  221. raceReadObjectPC(t.key, key, callerpc, pc)
  222. }
  223. if h == nil || h.count == 0 {
  224. return unsafe.Pointer(t.elem.zero)
  225. }
  226. alg := goalg(t.key.alg)
  227. hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
  228. m := uintptr(1)<<h.B - 1
  229. b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
  230. if c := h.oldbuckets; c != nil {
  231. oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
  232. if !evacuated(oldb) {
  233. b = oldb
  234. }
  235. }
  236. top := uint8(hash >> (ptrSize*8 - 8))
  237. if top < minTopHash {
  238. top += minTopHash
  239. }
  240. for {
  241. for i := uintptr(0); i < bucketCnt; i++ {
  242. if b.tophash[i] != top {
  243. continue
  244. }
  245. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  246. if t.indirectkey {
  247. k = *((*unsafe.Pointer)(k))
  248. }
  249. if alg.equal(key, k, uintptr(t.key.size)) {
  250. v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
  251. if t.indirectvalue {
  252. v = *((*unsafe.Pointer)(v))
  253. }
  254. return v
  255. }
  256. }
  257. b = b.overflow(t)
  258. if b == nil {
  259. return unsafe.Pointer(t.elem.zero)
  260. }
  261. }
  262. }
  263. func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) {
  264. if raceenabled && h != nil {
  265. callerpc := getcallerpc(unsafe.Pointer(&t))
  266. pc := funcPC(mapaccess2)
  267. racereadpc(unsafe.Pointer(h), callerpc, pc)
  268. raceReadObjectPC(t.key, key, callerpc, pc)
  269. }
  270. if h == nil || h.count == 0 {
  271. return unsafe.Pointer(t.elem.zero), false
  272. }
  273. alg := goalg(t.key.alg)
  274. hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
  275. m := uintptr(1)<<h.B - 1
  276. b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
  277. if c := h.oldbuckets; c != nil {
  278. oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
  279. if !evacuated(oldb) {
  280. b = oldb
  281. }
  282. }
  283. top := uint8(hash >> (ptrSize*8 - 8))
  284. if top < minTopHash {
  285. top += minTopHash
  286. }
  287. for {
  288. for i := uintptr(0); i < bucketCnt; i++ {
  289. if b.tophash[i] != top {
  290. continue
  291. }
  292. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  293. if t.indirectkey {
  294. k = *((*unsafe.Pointer)(k))
  295. }
  296. if alg.equal(key, k, uintptr(t.key.size)) {
  297. v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
  298. if t.indirectvalue {
  299. v = *((*unsafe.Pointer)(v))
  300. }
  301. return v, true
  302. }
  303. }
  304. b = b.overflow(t)
  305. if b == nil {
  306. return unsafe.Pointer(t.elem.zero), false
  307. }
  308. }
  309. }
  310. // returns both key and value. Used by map iterator
  311. func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) {
  312. if h == nil || h.count == 0 {
  313. return nil, nil
  314. }
  315. alg := goalg(t.key.alg)
  316. hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
  317. m := uintptr(1)<<h.B - 1
  318. b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
  319. if c := h.oldbuckets; c != nil {
  320. oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
  321. if !evacuated(oldb) {
  322. b = oldb
  323. }
  324. }
  325. top := uint8(hash >> (ptrSize*8 - 8))
  326. if top < minTopHash {
  327. top += minTopHash
  328. }
  329. for {
  330. for i := uintptr(0); i < bucketCnt; i++ {
  331. if b.tophash[i] != top {
  332. continue
  333. }
  334. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  335. if t.indirectkey {
  336. k = *((*unsafe.Pointer)(k))
  337. }
  338. if alg.equal(key, k, uintptr(t.key.size)) {
  339. v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
  340. if t.indirectvalue {
  341. v = *((*unsafe.Pointer)(v))
  342. }
  343. return k, v
  344. }
  345. }
  346. b = b.overflow(t)
  347. if b == nil {
  348. return nil, nil
  349. }
  350. }
  351. }
  352. func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
  353. if h == nil {
  354. panic("assignment to entry in nil map")
  355. }
  356. if raceenabled {
  357. callerpc := getcallerpc(unsafe.Pointer(&t))
  358. pc := funcPC(mapassign1)
  359. racewritepc(unsafe.Pointer(h), callerpc, pc)
  360. raceReadObjectPC(t.key, key, callerpc, pc)
  361. raceReadObjectPC(t.elem, val, callerpc, pc)
  362. }
  363. alg := goalg(t.key.alg)
  364. hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
  365. if h.buckets == nil {
  366. if checkgc {
  367. memstats.next_gc = memstats.heap_alloc
  368. }
  369. h.buckets = newarray(t.bucket, 1)
  370. }
  371. again:
  372. bucket := hash & (uintptr(1)<<h.B - 1)
  373. if h.oldbuckets != nil {
  374. growWork(t, h, bucket)
  375. }
  376. b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
  377. top := uint8(hash >> (ptrSize*8 - 8))
  378. if top < minTopHash {
  379. top += minTopHash
  380. }
  381. var inserti *uint8
  382. var insertk unsafe.Pointer
  383. var insertv unsafe.Pointer
  384. for {
  385. for i := uintptr(0); i < bucketCnt; i++ {
  386. if b.tophash[i] != top {
  387. if b.tophash[i] == empty && inserti == nil {
  388. inserti = &b.tophash[i]
  389. insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  390. insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
  391. }
  392. continue
  393. }
  394. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  395. k2 := k
  396. if t.indirectkey {
  397. k2 = *((*unsafe.Pointer)(k2))
  398. }
  399. if !alg.equal(key, k2, uintptr(t.key.size)) {
  400. continue
  401. }
  402. // already have a mapping for key. Update it.
  403. memmove(k2, key, uintptr(t.key.size))
  404. v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
  405. v2 := v
  406. if t.indirectvalue {
  407. v2 = *((*unsafe.Pointer)(v2))
  408. }
  409. memmove(v2, val, uintptr(t.elem.size))
  410. return
  411. }
  412. ovf := b.overflow(t)
  413. if ovf == nil {
  414. break
  415. }
  416. b = ovf
  417. }
  418. // did not find mapping for key. Allocate new cell & add entry.
  419. if float32(h.count) >= loadFactor*float32((uintptr(1)<<h.B)) && h.count >= bucketCnt {
  420. hashGrow(t, h)
  421. goto again // Growing the table invalidates everything, so try again
  422. }
  423. if inserti == nil {
  424. // all current buckets are full, allocate a new one.
  425. if checkgc {
  426. memstats.next_gc = memstats.heap_alloc
  427. }
  428. newb := (*bmap)(newobject(t.bucket))
  429. b.setoverflow(t, newb)
  430. inserti = &newb.tophash[0]
  431. insertk = add(unsafe.Pointer(newb), dataOffset)
  432. insertv = add(insertk, bucketCnt*uintptr(t.keysize))
  433. }
  434. // store new key/value at insert position
  435. if t.indirectkey {
  436. if checkgc {
  437. memstats.next_gc = memstats.heap_alloc
  438. }
  439. kmem := newobject(t.key)
  440. *(*unsafe.Pointer)(insertk) = kmem
  441. insertk = kmem
  442. }
  443. if t.indirectvalue {
  444. if checkgc {
  445. memstats.next_gc = memstats.heap_alloc
  446. }
  447. vmem := newobject(t.elem)
  448. *(*unsafe.Pointer)(insertv) = vmem
  449. insertv = vmem
  450. }
  451. memmove(insertk, key, uintptr(t.key.size))
  452. memmove(insertv, val, uintptr(t.elem.size))
  453. *inserti = top
  454. h.count++
  455. }
  456. func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
  457. if raceenabled && h != nil {
  458. callerpc := getcallerpc(unsafe.Pointer(&t))
  459. pc := funcPC(mapdelete)
  460. racewritepc(unsafe.Pointer(h), callerpc, pc)
  461. raceReadObjectPC(t.key, key, callerpc, pc)
  462. }
  463. if h == nil || h.count == 0 {
  464. return
  465. }
  466. alg := goalg(t.key.alg)
  467. hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
  468. bucket := hash & (uintptr(1)<<h.B - 1)
  469. if h.oldbuckets != nil {
  470. growWork(t, h, bucket)
  471. }
  472. b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
  473. top := uint8(hash >> (ptrSize*8 - 8))
  474. if top < minTopHash {
  475. top += minTopHash
  476. }
  477. for {
  478. for i := uintptr(0); i < bucketCnt; i++ {
  479. if b.tophash[i] != top {
  480. continue
  481. }
  482. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
  483. k2 := k
  484. if t.indirectkey {
  485. k2 = *((*unsafe.Pointer)(k2))
  486. }
  487. if !alg.equal(key, k2, uintptr(t.key.size)) {
  488. continue
  489. }
  490. memclr(k, uintptr(t.keysize))
  491. v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
  492. memclr(v, uintptr(t.valuesize))
  493. b.tophash[i] = empty
  494. h.count--
  495. return
  496. }
  497. b = b.overflow(t)
  498. if b == nil {
  499. return
  500. }
  501. }
  502. }
  503. func mapiterinit(t *maptype, h *hmap, it *hiter) {
  504. // Clear pointer fields so garbage collector does not complain.
  505. it.key = nil
  506. it.value = nil
  507. it.t = nil
  508. it.h = nil
  509. it.buckets = nil
  510. it.bptr = nil
  511. if raceenabled && h != nil {
  512. callerpc := getcallerpc(unsafe.Pointer(&t))
  513. racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit))
  514. }
  515. if h == nil || h.count == 0 {
  516. it.key = nil
  517. it.value = nil
  518. return
  519. }
  520. if unsafe.Sizeof(hiter{})/ptrSize != 10 {
  521. gothrow("hash_iter size incorrect") // see ../../cmd/gc/reflect.c
  522. }
  523. it.t = t
  524. it.h = h
  525. // grab snapshot of bucket state
  526. it.B = h.B
  527. it.buckets = h.buckets
  528. // decide where to start
  529. r := uintptr(fastrand1())
  530. if h.B > 31-bucketCntBits {
  531. r += uintptr(fastrand1()) << 31
  532. }
  533. it.startBucket = r & (uintptr(1)<<h.B - 1)
  534. it.offset = uint8(r >> h.B & (bucketCnt - 1))
  535. // iterator state
  536. it.bucket = it.startBucket
  537. it.wrapped = false
  538. it.bptr = nil
  539. // Remember we have an iterator.
  540. // Can run concurrently with another hash_iter_init().
  541. for {
  542. old := h.flags
  543. if old == old|iterator|oldIterator {
  544. break
  545. }
  546. if cas(&h.flags, old, old|iterator|oldIterator) {
  547. break
  548. }
  549. }
  550. mapiternext(it)
  551. }
  552. func mapiternext(it *hiter) {
  553. h := it.h
  554. if raceenabled {
  555. callerpc := getcallerpc(unsafe.Pointer(&it))
  556. racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext))
  557. }
  558. t := it.t
  559. bucket := it.bucket
  560. b := it.bptr
  561. i := it.i
  562. checkBucket := it.checkBucket
  563. alg := goalg(t.key.alg)
  564. next:
  565. if b == nil {
  566. if bucket == it.startBucket && it.wrapped {
  567. // end of iteration
  568. it.key = nil
  569. it.value = nil
  570. return
  571. }
  572. if h.oldbuckets != nil && it.B == h.B {
  573. // Iterator was started in the middle of a grow, and the grow isn't done yet.
  574. // If the bucket we're looking at hasn't been filled in yet (i.e. the old
  575. // bucket hasn't been evacuated) then we need to iterate through the old
  576. // bucket and only return the ones that will be migrated to this bucket.
  577. oldbucket := bucket & (uintptr(1)<<(it.B-1) - 1)
  578. b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
  579. if !evacuated(b) {
  580. checkBucket = bucket
  581. } else {
  582. b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
  583. checkBucket = noCheck
  584. }
  585. } else {
  586. b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
  587. checkBucket = noCheck
  588. }
  589. bucket++
  590. if bucket == uintptr(1)<<it.B {
  591. bucket = 0
  592. it.wrapped = true
  593. }
  594. i = 0
  595. }
  596. for ; i < bucketCnt; i++ {
  597. offi := (i + it.offset) & (bucketCnt - 1)
  598. k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.keysize))
  599. v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+uintptr(offi)*uintptr(t.valuesize))
  600. if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
  601. if checkBucket != noCheck {
  602. // Special case: iterator was started during a grow and the
  603. // grow is not done yet. We're working on a bucket whose
  604. // oldbucket has not been evacuated yet. Or at least, it wasn't
  605. // evacuated when we started the bucket. So we're iterating
  606. // through the oldbucket, skipping any keys that will go
  607. // to the other new bucket (each oldbucket expands to two
  608. // buckets during a grow).
  609. k2 := k
  610. if t.indirectkey {
  611. k2 = *((*unsafe.Pointer)(k2))
  612. }
  613. if alg.equal(k2, k2, uintptr(t.key.size)) {
  614. // If the item in the oldbucket is not destined for
  615. // the current new bucket in the iteration, skip it.
  616. hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
  617. if hash&(uintptr(1)<<it.B-1) != checkBucket {
  618. continue
  619. }
  620. } else {
  621. // Hash isn't repeatable if k != k (NaNs). We need a
  622. // repeatable and randomish choice of which direction
  623. // to send NaNs during evacuation. We'll use the low
  624. // bit of tophash to decide which way NaNs go.
  625. // NOTE: this case is why we need two evacuate tophash
  626. // values, evacuatedX and evacuatedY, that differ in
  627. // their low bit.
  628. if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) {
  629. continue
  630. }
  631. }
  632. }
  633. if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY {
  634. // this is the golden data, we can return it.
  635. if t.indirectkey {
  636. k = *((*unsafe.Pointer)(k))
  637. }
  638. it.key = k
  639. if t.indirectvalue {
  640. v = *((*unsafe.Pointer)(v))
  641. }
  642. it.value = v
  643. } else {
  644. // The hash table has grown since the iterator was started.
  645. // The golden data for this key is now somewhere else.
  646. k2 := k
  647. if t.indirectkey {
  648. k2 = *((*unsafe.Pointer)(k2))
  649. }
  650. if alg.equal(k2, k2, uintptr(t.key.size)) {
  651. // Check the current hash table for the data.
  652. // This code handles the case where the key
  653. // has been deleted, updated, or deleted and reinserted.
  654. // NOTE: we need to regrab the key as it has potentially been
  655. // updated to an equal() but not identical key (e.g. +0.0 vs -0.0).
  656. rk, rv := mapaccessK(t, h, k2)
  657. if rk == nil {
  658. continue // key has been deleted
  659. }
  660. it.key = rk
  661. it.value = rv
  662. } else {
  663. // if key!=key then the entry can't be deleted or
  664. // updated, so we can just return it. That's lucky for
  665. // us because when key!=key we can't look it up
  666. // successfully in the current table.
  667. it.key = k2
  668. if t.indirectvalue {
  669. v = *((*unsafe.Pointer)(v))
  670. }
  671. it.value = v
  672. }
  673. }
  674. it.bucket = bucket
  675. it.bptr = b
  676. it.i = i + 1
  677. it.checkBucket = checkBucket
  678. return
  679. }
  680. }
  681. b = b.overflow(t)
  682. i = 0
  683. goto next
  684. }
  685. func hashGrow(t *maptype, h *hmap) {
  686. if h.oldbuckets != nil {
  687. gothrow("evacuation not done in time")
  688. }
  689. oldbuckets := h.buckets
  690. if checkgc {
  691. memstats.next_gc = memstats.heap_alloc
  692. }
  693. newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1))
  694. flags := h.flags &^ (iterator | oldIterator)
  695. if h.flags&iterator != 0 {
  696. flags |= oldIterator
  697. }
  698. // commit the grow (atomic wrt gc)
  699. h.B++
  700. h.flags = flags
  701. h.oldbuckets = oldbuckets
  702. h.buckets = newbuckets
  703. h.nevacuate = 0
  704. // the actual copying of the hash table data is done incrementally
  705. // by growWork() and evacuate().
  706. }
  707. func growWork(t *maptype, h *hmap, bucket uintptr) {
  708. noldbuckets := uintptr(1) << (h.B - 1)
  709. // make sure we evacuate the oldbucket corresponding
  710. // to the bucket we're about to use
  711. evacuate(t, h, bucket&(noldbuckets-1))
  712. // evacuate one more oldbucket to make progress on growing
  713. if h.oldbuckets != nil {
  714. evacuate(t, h, h.nevacuate)
  715. }
  716. }
  717. func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
  718. b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
  719. newbit := uintptr(1) << (h.B - 1)
  720. alg := goalg(t.key.alg)
  721. if !evacuated(b) {
  722. // TODO: reuse overflow buckets instead of using new ones, if there
  723. // is no iterator using the old buckets. (If !oldIterator.)
  724. x := (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
  725. y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
  726. xi := 0
  727. yi := 0
  728. xk := add(unsafe.Pointer(x), dataOffset)
  729. yk := add(unsafe.Pointer(y), dataOffset)
  730. xv := add(xk, bucketCnt*uintptr(t.keysize))
  731. yv := add(yk, bucketCnt*uintptr(t.keysize))
  732. for ; b != nil; b = b.overflow(t) {
  733. k := add(unsafe.Pointer(b), dataOffset)
  734. v := add(k, bucketCnt*uintptr(t.keysize))
  735. for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) {
  736. top := b.tophash[i]
  737. if top == empty {
  738. b.tophash[i] = evacuatedEmpty
  739. continue
  740. }
  741. if top < minTopHash {
  742. gothrow("bad map state")
  743. }
  744. k2 := k
  745. if t.indirectkey {
  746. k2 = *((*unsafe.Pointer)(k2))
  747. }
  748. // Compute hash to make our evacuation decision (whether we need
  749. // to send this key/value to bucket x or bucket y).
  750. hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
  751. if h.flags&iterator != 0 {
  752. if !alg.equal(k2, k2, uintptr(t.key.size)) {
  753. // If key != key (NaNs), then the hash could be (and probably
  754. // will be) entirely different from the old hash. Moreover,
  755. // it isn't reproducible. Reproducibility is required in the
  756. // presence of iterators, as our evacuation decision must
  757. // match whatever decision the iterator made.
  758. // Fortunately, we have the freedom to send these keys either
  759. // way. Also, tophash is meaningless for these kinds of keys.
  760. // We let the low bit of tophash drive the evacuation decision.
  761. // We recompute a new random tophash for the next level so
  762. // these keys will get evenly distributed across all buckets
  763. // after multiple grows.
  764. if (top & 1) != 0 {
  765. hash |= newbit
  766. } else {
  767. hash &^= newbit
  768. }
  769. top = uint8(hash >> (ptrSize*8 - 8))
  770. if top < minTopHash {
  771. top += minTopHash
  772. }
  773. }
  774. }
  775. if (hash & newbit) == 0 {
  776. b.tophash[i] = evacuatedX
  777. if xi == bucketCnt {
  778. if checkgc {
  779. memstats.next_gc = memstats.heap_alloc
  780. }
  781. newx := (*bmap)(newobject(t.bucket))
  782. x.setoverflow(t, newx)
  783. x = newx
  784. xi = 0
  785. xk = add(unsafe.Pointer(x), dataOffset)
  786. xv = add(xk, bucketCnt*uintptr(t.keysize))
  787. }
  788. x.tophash[xi] = top
  789. if t.indirectkey {
  790. *(*unsafe.Pointer)(xk) = k2 // copy pointer
  791. } else {
  792. memmove(xk, k, uintptr(t.key.size)) // copy value
  793. }
  794. if t.indirectvalue {
  795. *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
  796. } else {
  797. memmove(xv, v, uintptr(t.elem.size))
  798. }
  799. xi++
  800. xk = add(xk, uintptr(t.keysize))
  801. xv = add(xv, uintptr(t.valuesize))
  802. } else {
  803. b.tophash[i] = evacuatedY
  804. if yi == bucketCnt {
  805. if checkgc {
  806. memstats.next_gc = memstats.heap_alloc
  807. }
  808. newy := (*bmap)(newobject(t.bucket))
  809. y.setoverflow(t, newy)
  810. y = newy
  811. yi = 0
  812. yk = add(unsafe.Pointer(y), dataOffset)
  813. yv = add(yk, bucketCnt*uintptr(t.keysize))
  814. }
  815. y.tophash[yi] = top
  816. if t.indirectkey {
  817. *(*unsafe.Pointer)(yk) = k2
  818. } else {
  819. memmove(yk, k, uintptr(t.key.size))
  820. }
  821. if t.indirectvalue {
  822. *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
  823. } else {
  824. memmove(yv, v, uintptr(t.elem.size))
  825. }
  826. yi++
  827. yk = add(yk, uintptr(t.keysize))
  828. yv = add(yv, uintptr(t.valuesize))
  829. }
  830. }
  831. }
  832. // Unlink the overflow buckets & clear key/value to help GC.
  833. if h.flags&oldIterator == 0 {
  834. b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
  835. memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
  836. }
  837. }
  838. // Advance evacuation mark
  839. if oldbucket == h.nevacuate {
  840. h.nevacuate = oldbucket + 1
  841. if oldbucket+1 == newbit { // newbit == # of oldbuckets
  842. // Growing is all done. Free old main bucket array.
  843. h.oldbuckets = nil
  844. }
  845. }
  846. }
  847. func ismapkey(t *_type) bool {
  848. return goalg(t.alg).hash != nil
  849. }
  850. // Reflect stubs. Called from ../reflect/asm_*.s
  851. func reflect_makemap(t *maptype) *hmap {
  852. return makemap(t, 0)
  853. }
  854. func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
  855. val, ok := mapaccess2(t, h, key)
  856. if !ok {
  857. // reflect wants nil for a missing element
  858. val = nil
  859. }
  860. return val
  861. }
  862. func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
  863. mapassign1(t, h, key, val)
  864. }
  865. func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
  866. mapdelete(t, h, key)
  867. }
  868. func reflect_mapiterinit(t *maptype, h *hmap) *hiter {
  869. it := new(hiter)
  870. mapiterinit(t, h, it)
  871. return it
  872. }
  873. func reflect_mapiternext(it *hiter) {
  874. mapiternext(it)
  875. }
  876. func reflect_mapiterkey(it *hiter) unsafe.Pointer {
  877. return it.key
  878. }
  879. func reflect_maplen(h *hmap) int {
  880. if h == nil {
  881. return 0
  882. }
  883. if raceenabled {
  884. callerpc := getcallerpc(unsafe.Pointer(&h))
  885. racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen))
  886. }
  887. return h.count
  888. }
  889. func reflect_ismapkey(t *_type) bool {
  890. return ismapkey(t)
  891. }