diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 984b507826f..8170c15b62e 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -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: diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go index 5fb95906588..d7d4974597a 100644 --- a/src/pkg/reflect/type.go +++ b/src/pkg/reflect/type.go @@ -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. diff --git a/src/pkg/runtime/hashmap.go b/src/pkg/runtime/hashmap.go index 0b4bb7d71cd..6706290974d 100644 --- a/src/pkg/runtime/hashmap.go +++ b/src/pkg/runtime/hashmap.go @@ -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 + // 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") } - valuesize := uintptr(t.elem.size) - if valuesize > maxValueSize { - flags |= indirectValue - valuesize = ptrSize - } - 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)<>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)<>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)<>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) } } diff --git a/src/pkg/runtime/hashmap_fast.go b/src/pkg/runtime/hashmap_fast.go index 6176c842dd3..989ae032bdf 100644 --- a/src/pkg/runtime/hashmap_fast.go +++ b/src/pkg/runtime/hashmap_fast.go @@ -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)<>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)<>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)<>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)<>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)<>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)<>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 diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h index a9de837094d..8de0ccba2c5 100644 --- a/src/pkg/runtime/type.h +++ b/src/pkg/runtime/type.h @@ -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