]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: move constants from map header to map type
authorKeith Randall <khr@golang.org>
Fri, 1 Aug 2014 21:38:56 +0000 (14:38 -0700)
committerKeith Randall <khr@golang.org>
Fri, 1 Aug 2014 21:38:56 +0000 (14:38 -0700)
A good cleanup anyway, and it makes some room for an additional
field needed for issue 8412.

Update #8412

LGTM=iant
R=iant, khr
CC=golang-codereviews
https://golang.org/cl/112700043

src/cmd/gc/reflect.c
src/pkg/reflect/type.go
src/pkg/runtime/hashmap.go
src/pkg/runtime/hashmap_fast.go
src/pkg/runtime/type.h

index 984b507826f5160eef90114939d0e353f51618f2..8170c15b62e2b6898a67e1cfe117674d7543688c 100644 (file)
@@ -192,7 +192,7 @@ mapbucket(Type *t)
 // the given map type.  This type is not visible to users -
 // we include only enough information to generate a correct GC
 // program for it.
-// Make sure this stays in sync with ../../pkg/runtime/hashmap.c!
+// Make sure this stays in sync with ../../pkg/runtime/hashmap.go!
 static Type*
 hmap(Type *t)
 {
@@ -211,10 +211,6 @@ hmap(Type *t)
        offset += 4;       // flags
        offset += 4;       // hash0
        offset += 1;       // B
-       offset += 1;       // keysize
-       offset += 1;       // valuesize
-       offset = (offset + 1) / 2 * 2;
-       offset += 2;       // bucketsize
        offset = (offset + widthptr - 1) / widthptr * widthptr;
        
        bucketsfield = typ(TFIELD);
@@ -568,6 +564,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
                return off;
 
        // fill in *extraType pointer in header
+       off = rnd(off, widthptr);
        dsymptr(sym, ptroff, sym, off);
 
        n = 0;
@@ -1090,6 +1087,21 @@ ok:
                ot = dsymptr(s, ot, s2, 0);
                ot = dsymptr(s, ot, s3, 0);
                ot = dsymptr(s, ot, s4, 0);
+               if(t->down->width > MAXKEYSIZE) {
+                       ot = duint8(s, ot, widthptr);
+                       ot = duint8(s, ot, 1); // indirect
+               } else {
+                       ot = duint8(s, ot, t->down->width);
+                       ot = duint8(s, ot, 0); // not indirect
+               }
+               if(t->type->width > MAXVALSIZE) {
+                       ot = duint8(s, ot, widthptr);
+                       ot = duint8(s, ot, 1); // indirect
+               } else {
+                       ot = duint8(s, ot, t->type->width);
+                       ot = duint8(s, ot, 0); // not indirect
+               }
+               ot = duint16(s, ot, mapbucket(t)->width);
                break;
 
        case TPTR32:
index 5fb95906588fe5f8826e8aa31fd3c42bcc9abee2..d7d4974597a2ddb7520299e90588e2de9dc2903c 100644 (file)
@@ -323,11 +323,16 @@ type interfaceType struct {
 
 // mapType represents a map type.
 type mapType struct {
-       rtype  `reflect:"map"`
-       key    *rtype // map key type
-       elem   *rtype // map element (value) type
-       bucket *rtype // internal bucket structure
-       hmap   *rtype // internal map header
+       rtype         `reflect:"map"`
+       key           *rtype // map key type
+       elem          *rtype // map element (value) type
+       bucket        *rtype // internal bucket structure
+       hmap          *rtype // internal map header
+       keysize       uint8  // size of key slot
+       indirectkey   uint8  // store ptr to key instead of key itself
+       valuesize     uint8  // size of value slot
+       indirectvalue uint8  // store ptr to value instead of value itself
+       bucketsize    uint16 // size of bucket
 }
 
 // ptrType represents a pointer type.
@@ -1454,6 +1459,21 @@ func MapOf(key, elem Type) Type {
        mt.key = ktyp
        mt.elem = etyp
        mt.bucket = bucketOf(ktyp, etyp)
+       if ktyp.size > maxKeySize {
+               mt.keysize = uint8(ptrSize)
+               mt.indirectkey = 1
+       } else {
+               mt.keysize = uint8(ktyp.size)
+               mt.indirectkey = 0
+       }
+       if etyp.size > maxValSize {
+               mt.valuesize = uint8(ptrSize)
+               mt.indirectvalue = 1
+       } else {
+               mt.valuesize = uint8(etyp.size)
+               mt.indirectvalue = 0
+       }
+       mt.bucketsize = uint16(mt.bucket.size)
        mt.uncommonType = nil
        mt.ptrToThis = nil
        mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
@@ -1543,7 +1563,7 @@ const (
        bitsPointer = 2
 )
 
-// Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c!
+// Make sure these routines stay in sync with ../../pkg/runtime/hashmap.go!
 // These types exist only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in string
 // for possible debugging use.
index 0b4bb7d71cd405332649c6fd0265622523cc367c..6706290974db55ed1300f045234f22188712b21c 100644 (file)
@@ -90,10 +90,8 @@ const (
        minTopHash     = 4 // minimum tophash for a normal filled cell.
 
        // flags
-       indirectKey   = 1 // storing pointers to keys
-       indirectValue = 2 // storing pointers to values
-       iterator      = 4 // there may be an iterator using buckets
-       oldIterator   = 8 // there may be an iterator using oldbuckets
+       iterator    = 1 // there may be an iterator using buckets
+       oldIterator = 2 // there may be an iterator using oldbuckets
 
        // sentinel bucket ID for iterator checks
        noCheck = 1<<(8*ptrSize) - 1
@@ -106,13 +104,10 @@ const (
 type hmap struct {
        // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
        // ../reflect/type.go.  Don't change this structure without also changing that code!
-       count      int // # live cells == size of map.  Must be first (used by len() builtin)
-       flags      uint32
-       hash0      uint32 // hash seed
-       B          uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
-       keysize    uint8  // key size in bytes
-       valuesize  uint8  // value size in bytes
-       bucketsize uint16 // bucket size in bytes
+       count int // # live cells == size of map.  Must be first (used by len() builtin)
+       flags uint32
+       hash0 uint32 // hash seed
+       B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
 
        buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
        oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
@@ -166,22 +161,14 @@ func makemap(t *maptype, hint int64) *hmap {
                gothrow("runtime.makemap: unsupported map key type")
        }
 
-       flags := uint32(0)
-
-       // figure out how big we have to make everything
-       keysize := uintptr(t.key.size)
-       if keysize > maxKeySize {
-               flags |= indirectKey
-               keysize = ptrSize
-       }
-       valuesize := uintptr(t.elem.size)
-       if valuesize > maxValueSize {
-               flags |= indirectValue
-               valuesize = ptrSize
+       // check compiler's and reflect's math
+       if t.key.size > maxKeySize && (t.indirectkey == 0 || t.keysize != uint8(ptrSize)) ||
+               t.key.size <= maxKeySize && (t.indirectkey == 1 || t.keysize != uint8(t.key.size)) {
+               gothrow("key size wrong")
        }
-       bucketsize := dataOffset + bucketCnt*(keysize+valuesize)
-       if bucketsize != uintptr(t.bucket.size) {
-               gothrow("bucketsize wrong")
+       if t.elem.size > maxValueSize && (t.indirectvalue == 0 || t.valuesize != uint8(ptrSize)) ||
+               t.elem.size <= maxValueSize && (t.indirectvalue == 1 || t.valuesize != uint8(t.elem.size)) {
+               gothrow("value size wrong")
        }
 
        // invariants we depend on.  We should probably check these at compile time
@@ -231,10 +218,7 @@ func makemap(t *maptype, hint int64) *hmap {
        h := (*hmap)(newobject(t.hmap))
        h.count = 0
        h.B = B
-       h.flags = flags
-       h.keysize = uint8(keysize)
-       h.valuesize = uint8(valuesize)
-       h.bucketsize = uint16(bucketsize)
+       h.flags = 0
        h.hash0 = fastrand2()
        h.buckets = buckets
        h.oldbuckets = nil
@@ -261,9 +245,9 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        }
        hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
        m := uintptr(1)<<h.B - 1
-       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
        if c := h.oldbuckets; c != nil {
-               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                if !evacuated(oldb) {
                        b = oldb
                }
@@ -277,13 +261,13 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
                        if b.tophash[i] != top {
                                continue
                        }
-                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
-                       if h.flags&indirectKey != 0 {
+                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+                       if t.indirectkey != 0 {
                                k = *((*unsafe.Pointer)(k))
                        }
                        if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
-                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
-                               if h.flags&indirectValue != 0 {
+                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+                               if t.indirectvalue != 0 {
                                        v = *((*unsafe.Pointer)(v))
                                }
                                return v
@@ -309,9 +293,9 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
        }
        hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
        m := uintptr(1)<<h.B - 1
-       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
+       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
        if c := h.oldbuckets; c != nil {
-               oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(h.bucketsize)))
+               oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
                if !evacuated(oldb) {
                        b = oldb
                }
@@ -325,13 +309,13 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
                        if b.tophash[i] != top {
                                continue
                        }
-                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
-                       if h.flags&indirectKey != 0 {
+                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+                       if t.indirectkey != 0 {
                                k = *((*unsafe.Pointer)(k))
                        }
                        if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
-                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
-                               if h.flags&indirectValue != 0 {
+                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+                               if t.indirectvalue != 0 {
                                        v = *((*unsafe.Pointer)(v))
                                }
                                return v, true
@@ -351,9 +335,9 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
        }
        hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
        m := uintptr(1)<<h.B - 1
-       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
+       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
        if c := h.oldbuckets; c != nil {
-               oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(h.bucketsize)))
+               oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
                if !evacuated(oldb) {
                        b = oldb
                }
@@ -367,13 +351,13 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
                        if b.tophash[i] != top {
                                continue
                        }
-                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
-                       if h.flags&indirectKey != 0 {
+                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+                       if t.indirectkey != 0 {
                                k = *((*unsafe.Pointer)(k))
                        }
                        if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
-                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
-                               if h.flags&indirectValue != 0 {
+                               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+                               if t.indirectvalue != 0 {
                                        v = *((*unsafe.Pointer)(v))
                                }
                                return k, v
@@ -413,7 +397,7 @@ again:
        if h.oldbuckets != nil {
                growWork(t, h, bucket)
        }
-       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(h.bucketsize)))
+       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
        top := uint8(hash >> (ptrSize*8 - 8))
        if top < minTopHash {
                top += minTopHash
@@ -427,14 +411,14 @@ again:
                        if b.tophash[i] != top {
                                if b.tophash[i] == empty && inserti == nil {
                                        inserti = &b.tophash[i]
-                                       insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
-                                       insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
+                                       insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+                                       insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
                                }
                                continue
                        }
-                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
+                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
                        k2 := k
-                       if h.flags&indirectKey != 0 {
+                       if t.indirectkey != 0 {
                                k2 = *((*unsafe.Pointer)(k2))
                        }
                        if !goeq(t.key.alg, key, k2, uintptr(t.key.size)) {
@@ -442,9 +426,9 @@ again:
                        }
                        // already have a mapping for key.  Update it.
                        memmove(k2, key, uintptr(t.key.size))
-                       v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
+                       v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
                        v2 := v
-                       if h.flags&indirectValue != 0 {
+                       if t.indirectvalue != 0 {
                                v2 = *((*unsafe.Pointer)(v2))
                        }
                        memmove(v2, val, uintptr(t.elem.size))
@@ -471,11 +455,11 @@ again:
                b.overflow = newb
                inserti = &newb.tophash[0]
                insertk = add(unsafe.Pointer(newb), dataOffset)
-               insertv = add(insertk, bucketCnt*uintptr(h.keysize))
+               insertv = add(insertk, bucketCnt*uintptr(t.keysize))
        }
 
        // store new key/value at insert position
-       if h.flags&indirectKey != 0 {
+       if t.indirectkey != 0 {
                if checkgc {
                        memstats.next_gc = memstats.heap_alloc
                }
@@ -483,7 +467,7 @@ again:
                *(*unsafe.Pointer)(insertk) = kmem
                insertk = kmem
        }
-       if h.flags&indirectValue != 0 {
+       if t.indirectvalue != 0 {
                if checkgc {
                        memstats.next_gc = memstats.heap_alloc
                }
@@ -513,7 +497,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
        if h.oldbuckets != nil {
                growWork(t, h, bucket)
        }
-       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(h.bucketsize)))
+       b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
        top := uint8(hash >> (ptrSize*8 - 8))
        if top < minTopHash {
                top += minTopHash
@@ -523,17 +507,17 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
                        if b.tophash[i] != top {
                                continue
                        }
-                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
+                       k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
                        k2 := k
-                       if h.flags&indirectKey != 0 {
+                       if t.indirectkey != 0 {
                                k2 = *((*unsafe.Pointer)(k2))
                        }
                        if !goeq(t.key.alg, key, k2, uintptr(t.key.size)) {
                                continue
                        }
-                       memclr(k, uintptr(h.keysize))
-                       v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(h.keysize) + i*uintptr(h.valuesize))
-                       memclr(v, uintptr(h.valuesize))
+                       memclr(k, uintptr(t.keysize))
+                       v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
+                       memclr(v, uintptr(t.valuesize))
                        b.tophash[i] = empty
                        h.count--
                        return
@@ -626,15 +610,15 @@ next:
                        // bucket hasn't been evacuated) then we need to iterate through the old
                        // bucket and only return the ones that will be migrated to this bucket.
                        oldbucket := bucket & (uintptr(1)<<(it.B-1) - 1)
-                       b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+                       b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
                        if !evacuated(b) {
                                checkBucket = bucket
                        } else {
-                               b = (*bmap)(add(it.buckets, bucket*uintptr(h.bucketsize)))
+                               b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
                                checkBucket = noCheck
                        }
                } else {
-                       b = (*bmap)(add(it.buckets, bucket*uintptr(h.bucketsize)))
+                       b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
                        checkBucket = noCheck
                }
                bucket++
@@ -646,8 +630,8 @@ next:
        }
        for ; i < bucketCnt; i++ {
                offi := (i + uintptr(it.offset)) & (bucketCnt - 1)
-               k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(h.keysize))
-               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+offi*uintptr(h.valuesize))
+               k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.keysize))
+               v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+offi*uintptr(t.valuesize))
                if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
                        if checkBucket != noCheck {
                                // Special case: iterator was started during a grow and the
@@ -658,7 +642,7 @@ next:
                                // to the other new bucket (each oldbucket expands to two
                                // buckets during a grow).
                                k2 := k
-                               if h.flags&indirectKey != 0 {
+                               if t.indirectkey != 0 {
                                        k2 = *((*unsafe.Pointer)(k2))
                                }
                                if goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
@@ -683,11 +667,11 @@ next:
                        }
                        if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY {
                                // this is the golden data, we can return it.
-                               if h.flags&indirectKey != 0 {
+                               if t.indirectkey != 0 {
                                        k = *((*unsafe.Pointer)(k))
                                }
                                it.key = k
-                               if h.flags&indirectValue != 0 {
+                               if t.indirectvalue != 0 {
                                        v = *((*unsafe.Pointer)(v))
                                }
                                it.value = v
@@ -695,7 +679,7 @@ next:
                                // The hash table has grown since the iterator was started.
                                // The golden data for this key is now somewhere else.
                                k2 := k
-                               if h.flags&indirectKey != 0 {
+                               if t.indirectkey != 0 {
                                        k2 = *((*unsafe.Pointer)(k2))
                                }
                                if goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
@@ -716,7 +700,7 @@ next:
                                        // us because when key!=key we can't look it up
                                        // successfully in the current table.
                                        it.key = k2
-                                       if h.flags&indirectValue != 0 {
+                                       if t.indirectvalue != 0 {
                                                v = *((*unsafe.Pointer)(v))
                                        }
                                        it.value = v
@@ -772,24 +756,24 @@ func growWork(t *maptype, h *hmap, bucket uintptr) {
 }
 
 func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
-       b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+       b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
        newbit := uintptr(1) << (h.B - 1)
        if !evacuated(b) {
                // TODO: reuse overflow buckets instead of using new ones, if there
                // is no iterator using the old buckets.  (If !oldIterator.)
 
-               x := (*bmap)(add(h.buckets, oldbucket*uintptr(h.bucketsize)))
-               y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(h.bucketsize)))
+               x := (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
+               y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
                xi := 0
                yi := 0
                xk := add(unsafe.Pointer(x), dataOffset)
                yk := add(unsafe.Pointer(y), dataOffset)
-               xv := add(xk, bucketCnt*uintptr(h.keysize))
-               yv := add(yk, bucketCnt*uintptr(h.keysize))
+               xv := add(xk, bucketCnt*uintptr(t.keysize))
+               yv := add(yk, bucketCnt*uintptr(t.keysize))
                for ; b != nil; b = b.overflow {
                        k := add(unsafe.Pointer(b), dataOffset)
-                       v := add(k, bucketCnt*uintptr(h.keysize))
-                       for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(h.keysize)), add(v, uintptr(h.valuesize)) {
+                       v := add(k, bucketCnt*uintptr(t.keysize))
+                       for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) {
                                top := b.tophash[i]
                                if top == empty {
                                        b.tophash[i] = evacuatedEmpty
@@ -799,7 +783,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                                        gothrow("bad map state")
                                }
                                k2 := k
-                               if h.flags&indirectKey != 0 {
+                               if t.indirectkey != 0 {
                                        k2 = *((*unsafe.Pointer)(k2))
                                }
                                // Compute hash to make our evacuation decision (whether we need
@@ -840,22 +824,22 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                                                x = newx
                                                xi = 0
                                                xk = add(unsafe.Pointer(x), dataOffset)
-                                               xv = add(xk, bucketCnt*uintptr(h.keysize))
+                                               xv = add(xk, bucketCnt*uintptr(t.keysize))
                                        }
                                        x.tophash[xi] = top
-                                       if h.flags&indirectKey != 0 {
+                                       if t.indirectkey != 0 {
                                                *(*unsafe.Pointer)(xk) = k2 // copy pointer
                                        } else {
                                                memmove(xk, k, uintptr(t.key.size)) // copy value
                                        }
-                                       if h.flags&indirectValue != 0 {
+                                       if t.indirectvalue != 0 {
                                                *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
                                        } else {
                                                memmove(xv, v, uintptr(t.elem.size))
                                        }
                                        xi++
-                                       xk = add(xk, uintptr(h.keysize))
-                                       xv = add(xv, uintptr(h.valuesize))
+                                       xk = add(xk, uintptr(t.keysize))
+                                       xv = add(xv, uintptr(t.valuesize))
                                } else {
                                        b.tophash[i] = evacuatedY
                                        if yi == bucketCnt {
@@ -867,30 +851,30 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
                                                y = newy
                                                yi = 0
                                                yk = add(unsafe.Pointer(y), dataOffset)
-                                               yv = add(yk, bucketCnt*uintptr(h.keysize))
+                                               yv = add(yk, bucketCnt*uintptr(t.keysize))
                                        }
                                        y.tophash[yi] = top
-                                       if h.flags&indirectKey != 0 {
+                                       if t.indirectkey != 0 {
                                                *(*unsafe.Pointer)(yk) = k2
                                        } else {
                                                memmove(yk, k, uintptr(t.key.size))
                                        }
-                                       if h.flags&indirectValue != 0 {
+                                       if t.indirectvalue != 0 {
                                                *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
                                        } else {
                                                memmove(yv, v, uintptr(t.elem.size))
                                        }
                                        yi++
-                                       yk = add(yk, uintptr(h.keysize))
-                                       yv = add(yv, uintptr(h.valuesize))
+                                       yk = add(yk, uintptr(t.keysize))
+                                       yv = add(yv, uintptr(t.valuesize))
                                }
                        }
                }
                // Unlink the overflow buckets & clear key/value to help GC.
                if h.flags&oldIterator == 0 {
-                       b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+                       b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
                        b.overflow = nil
-                       memclr(add(unsafe.Pointer(b), dataOffset), uintptr(h.bucketsize)-dataOffset)
+                       memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
                }
        }
 
index 6176c842dd3b3112e59e9dc005f03c0a537eafe2..989ae032bdf6db746540fafaae58f5ae332ef16f 100644 (file)
@@ -25,9 +25,9 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
        } else {
                hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
                m := uintptr(1)<<h.B - 1
-               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
                if c := h.oldbuckets; c != nil {
-                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                        if !evacuated(oldb) {
                                b = oldb
                        }
@@ -39,11 +39,11 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
                        if k != key {
                                continue
                        }
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
-                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(h.valuesize))
+                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
                }
                b = b.overflow
                if b == nil {
@@ -69,9 +69,9 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
        } else {
                hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
                m := uintptr(1)<<h.B - 1
-               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
                if c := h.oldbuckets; c != nil {
-                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                        if !evacuated(oldb) {
                                b = oldb
                        }
@@ -83,11 +83,11 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
                        if k != key {
                                continue
                        }
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
-                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(h.valuesize)), true
+                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true
                }
                b = b.overflow
                if b == nil {
@@ -113,9 +113,9 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
        } else {
                hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
                m := uintptr(1)<<h.B - 1
-               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
                if c := h.oldbuckets; c != nil {
-                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                        if !evacuated(oldb) {
                                b = oldb
                        }
@@ -127,11 +127,11 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
                        if k != key {
                                continue
                        }
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
-                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(h.valuesize))
+                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
                }
                b = b.overflow
                if b == nil {
@@ -157,9 +157,9 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
        } else {
                hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
                m := uintptr(1)<<h.B - 1
-               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+               b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
                if c := h.oldbuckets; c != nil {
-                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+                       oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                        if !evacuated(oldb) {
                                b = oldb
                        }
@@ -171,11 +171,11 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
                        if k != key {
                                continue
                        }
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
-                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(h.valuesize)), true
+                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true
                }
                b = b.overflow
                if b == nil {
@@ -201,8 +201,8 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
                if key.len < 32 {
                        // short key, doing lots of comparisons is ok
                        for i := uintptr(0); i < bucketCnt; i++ {
-                               t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                               if t == empty {
+                               x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                               if x == empty {
                                        continue
                                }
                                k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -210,7 +210,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
                                        continue
                                }
                                if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
-                                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+                                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
                                }
                        }
                        return unsafe.Pointer(t.elem.zero)
@@ -218,8 +218,8 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
                // long key, try not to do more comparisons than necessary
                keymaybe := uintptr(bucketCnt)
                for i := uintptr(0); i < bucketCnt; i++ {
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -227,7 +227,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
                                continue
                        }
                        if k.str == key.str {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
                        }
                        // check first 4 bytes
                        // TODO: on amd64/386 at least, make this compile to one 4-byte comparison instead of
@@ -248,7 +248,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
                if keymaybe != bucketCnt {
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize))
                        if gomemeq(k.str, key.str, uintptr(key.len)) {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(h.valuesize))
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize))
                        }
                }
                return unsafe.Pointer(t.elem.zero)
@@ -256,9 +256,9 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 dohash:
        hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
        m := uintptr(1)<<h.B - 1
-       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
        if c := h.oldbuckets; c != nil {
-               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                if !evacuated(oldb) {
                        b = oldb
                }
@@ -269,8 +269,8 @@ dohash:
        }
        for {
                for i := uintptr(0); i < bucketCnt; i++ {
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t != top {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x != top {
                                continue
                        }
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -278,7 +278,7 @@ dohash:
                                continue
                        }
                        if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
                        }
                }
                b = b.overflow
@@ -305,8 +305,8 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
                if key.len < 32 {
                        // short key, doing lots of comparisons is ok
                        for i := uintptr(0); i < bucketCnt; i++ {
-                               t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                               if t == empty {
+                               x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                               if x == empty {
                                        continue
                                }
                                k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -314,7 +314,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
                                        continue
                                }
                                if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
-                                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+                                       return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
                                }
                        }
                        return unsafe.Pointer(t.elem.zero), false
@@ -322,8 +322,8 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
                // long key, try not to do more comparisons than necessary
                keymaybe := uintptr(bucketCnt)
                for i := uintptr(0); i < bucketCnt; i++ {
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t == empty {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x == empty {
                                continue
                        }
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -331,7 +331,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
                                continue
                        }
                        if k.str == key.str {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
                        }
                        // check first 4 bytes
                        if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
@@ -350,7 +350,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
                if keymaybe != bucketCnt {
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize))
                        if gomemeq(k.str, key.str, uintptr(key.len)) {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(h.valuesize)), true
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize)), true
                        }
                }
                return unsafe.Pointer(t.elem.zero), false
@@ -358,9 +358,9 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 dohash:
        hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
        m := uintptr(1)<<h.B - 1
-       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+       b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
        if c := h.oldbuckets; c != nil {
-               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+               oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
                if !evacuated(oldb) {
                        b = oldb
                }
@@ -371,8 +371,8 @@ dohash:
        }
        for {
                for i := uintptr(0); i < bucketCnt; i++ {
-                       t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
-                       if t != top {
+                       x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+                       if x != top {
                                continue
                        }
                        k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
@@ -380,7 +380,7 @@ dohash:
                                continue
                        }
                        if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
-                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+                               return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
                        }
                }
                b = b.overflow
index a9de837094debc472f91d0f6365ecc92d59ae186..8de0ccba2c5398e802935ca2e5aa9a7551ffca26 100644 (file)
@@ -81,8 +81,13 @@ struct MapType
        Type;
        Type *key;
        Type *elem;
-       Type *bucket; // internal type representing a hash bucket
-       Type *hmap;   // internal type representing a Hmap
+       Type *bucket;           // internal type representing a hash bucket
+       Type *hmap;             // internal type representing a Hmap
+       uint8 keysize;          // size of key slot
+       bool indirectkey;       // store ptr to key instead of key itself
+       uint8 valuesize;        // size of value slot
+       bool indirectvalue;     // store ptr to value instead of value itself
+       uint16 bucketsize;      // size of bucket
 };
 
 struct ChanType