@@ -1549,36 +1549,63 @@ func (v Value) MapKeys() []Value {
15491549 if m != nil {
15501550 mlen = maplen (m )
15511551 }
1552- it := mapiterinit (v .typ , m )
1552+ var it hiter
1553+ mapiterinit (v .typ , m , & it )
15531554 a := make ([]Value , mlen )
15541555 var i int
15551556 for i = 0 ; i < len (a ); i ++ {
1556- key := mapiterkey (it )
1557+ key := mapiterkey (& it )
15571558 if key == nil {
15581559 // Someone deleted an entry from the map since we
15591560 // called maplen above. It's a data race, but nothing
15601561 // we can do about it.
15611562 break
15621563 }
15631564 a [i ] = copyVal (keyType , fl , key )
1564- mapiternext (it )
1565+ mapiternext (& it )
15651566 }
15661567 return a [:i ]
15671568}
15681569
1570+ // hiter's structure matches runtime.hiter's structure.
1571+ // Having a clone here allows us to embed a map iterator
1572+ // inside type MapIter so that MapIters can be re-used
1573+ // without doing any allocations.
1574+ type hiter struct {
1575+ key unsafe.Pointer
1576+ elem unsafe.Pointer
1577+ t unsafe.Pointer
1578+ h unsafe.Pointer
1579+ buckets unsafe.Pointer
1580+ bptr unsafe.Pointer
1581+ overflow * []unsafe.Pointer
1582+ oldoverflow * []unsafe.Pointer
1583+ startBucket uintptr
1584+ offset uint8
1585+ wrapped bool
1586+ B uint8
1587+ i uint8
1588+ bucket uintptr
1589+ checkBucket uintptr
1590+ }
1591+
1592+ func (h hiter ) initialized () bool {
1593+ return h .t != nil
1594+ }
1595+
15691596// A MapIter is an iterator for ranging over a map.
15701597// See Value.MapRange.
15711598type MapIter struct {
1572- m Value
1573- it unsafe. Pointer
1599+ m Value
1600+ hiter hiter
15741601}
15751602
15761603// Key returns the key of the iterator's current map entry.
15771604func (it * MapIter ) Key () Value {
1578- if it .it == nil {
1605+ if ! it .hiter . initialized () {
15791606 panic ("MapIter.Key called before Next" )
15801607 }
1581- iterkey := mapiterkey (it .it )
1608+ iterkey := mapiterkey (& it .hiter )
15821609 if iterkey == nil {
15831610 panic ("MapIter.Key called on exhausted iterator" )
15841611 }
@@ -1592,10 +1619,10 @@ func (it *MapIter) Key() Value {
15921619// It is equivalent to dst.Set(it.Key()), but it avoids allocating a new Value.
15931620// As in Go, the key must be assignable to dst's type.
15941621func (it * MapIter ) SetKey (dst Value ) {
1595- if it .it == nil {
1622+ if ! it .hiter . initialized () {
15961623 panic ("MapIter.SetKey called before Next" )
15971624 }
1598- iterkey := mapiterkey (it .it )
1625+ iterkey := mapiterkey (& it .hiter )
15991626 if iterkey == nil {
16001627 panic ("MapIter.SetKey called on exhausted iterator" )
16011628 }
@@ -1616,10 +1643,10 @@ func (it *MapIter) SetKey(dst Value) {
16161643
16171644// Value returns the value of the iterator's current map entry.
16181645func (it * MapIter ) Value () Value {
1619- if it .it == nil {
1646+ if ! it .hiter . initialized () {
16201647 panic ("MapIter.Value called before Next" )
16211648 }
1622- iterelem := mapiterelem (it .it )
1649+ iterelem := mapiterelem (& it .hiter )
16231650 if iterelem == nil {
16241651 panic ("MapIter.Value called on exhausted iterator" )
16251652 }
@@ -1633,10 +1660,10 @@ func (it *MapIter) Value() Value {
16331660// It is equivalent to dst.Set(it.Value()), but it avoids allocating a new Value.
16341661// As in Go, the value must be assignable to dst's type.
16351662func (it * MapIter ) SetValue (dst Value ) {
1636- if it .it == nil {
1663+ if ! it .hiter . initialized () {
16371664 panic ("MapIter.SetValue called before Next" )
16381665 }
1639- iterelem := mapiterelem (it .it )
1666+ iterelem := mapiterelem (& it .hiter )
16401667 if iterelem == nil {
16411668 panic ("MapIter.SetValue called on exhausted iterator" )
16421669 }
@@ -1659,15 +1686,15 @@ func (it *MapIter) SetValue(dst Value) {
16591686// entry. It returns false when the iterator is exhausted; subsequent
16601687// calls to Key, Value, or Next will panic.
16611688func (it * MapIter ) Next () bool {
1662- if it .it == nil {
1663- it . it = mapiterinit (it .m .typ , it .m .pointer ())
1689+ if ! it .hiter . initialized () {
1690+ mapiterinit (it .m .typ , it .m .pointer (), & it . hiter )
16641691 } else {
1665- if mapiterkey (it .it ) == nil {
1692+ if mapiterkey (& it .hiter ) == nil {
16661693 panic ("MapIter.Next called on exhausted iterator" )
16671694 }
1668- mapiternext (it .it )
1695+ mapiternext (& it .hiter )
16691696 }
1670- return mapiterkey (it .it ) != nil
1697+ return mapiterkey (& it .hiter ) != nil
16711698}
16721699
16731700// MapRange returns a range iterator for a map.
@@ -3216,19 +3243,17 @@ func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
32163243//go:noescape
32173244func mapdelete (t * rtype , m unsafe.Pointer , key unsafe.Pointer )
32183245
3219- // m escapes into the return value, but the caller of mapiterinit
3220- // doesn't let the return value escape.
32213246//go:noescape
3222- func mapiterinit (t * rtype , m unsafe.Pointer ) unsafe. Pointer
3247+ func mapiterinit (t * rtype , m unsafe.Pointer , it * hiter )
32233248
32243249//go:noescape
3225- func mapiterkey (it unsafe. Pointer ) (key unsafe.Pointer )
3250+ func mapiterkey (it * hiter ) (key unsafe.Pointer )
32263251
32273252//go:noescape
3228- func mapiterelem (it unsafe. Pointer ) (elem unsafe.Pointer )
3253+ func mapiterelem (it * hiter ) (elem unsafe.Pointer )
32293254
32303255//go:noescape
3231- func mapiternext (it unsafe. Pointer )
3256+ func mapiternext (it * hiter )
32323257
32333258//go:noescape
32343259func maplen (m unsafe.Pointer ) int
0 commit comments