]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/reflectdata: share hmap and hiter types
authorMatthew Dempsky <mdempsky@google.com>
Mon, 21 Aug 2023 18:26:15 +0000 (11:26 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 21 Aug 2023 23:29:33 +0000 (23:29 +0000)
There's no need for distinct hmap and hiter types for each map.

Shaves 9kB off cmd/go binary size.

Change-Id: I7bc3b2d8ec82e7fcd78c1cb17733ebd8b615990a
Reviewed-on: https://go-review.googlesource.com/c/go/+/521615
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>

12 files changed:
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/typecheck/subr.go
src/cmd/compile/internal/types/fmt.go
src/cmd/compile/internal/types/sizeof_test.go
src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/walk/builtin.go
src/cmd/compile/internal/walk/order.go
src/cmd/compile/internal/walk/range.go
test/live.go
test/live2.go
test/live_regabi.go

index ba8c0b2af62267a6d85cab648fc0f63eacc85499..d593a312bd96a9ec51bd6deca399e142e3932137 100644 (file)
@@ -195,15 +195,15 @@ func MapBucketType(t *types.Type) *types.Type {
        return bucket
 }
 
-// MapType builds a type representing a Hmap structure for the given map type.
+var hmapType *types.Type
+
+// MapType returns a type interchangeable with runtime.hmap.
 // Make sure this stays in sync with runtime/map.go.
-func MapType(t *types.Type) *types.Type {
-       if t.MapType().Hmap != nil {
-               return t.MapType().Hmap
+func MapType() *types.Type {
+       if hmapType != nil {
+               return hmapType
        }
 
-       bmap := MapBucketType(t)
-
        // build a struct:
        // type hmap struct {
        //    count      int
@@ -211,8 +211,8 @@ func MapType(t *types.Type) *types.Type {
        //    B          uint8
        //    noverflow  uint16
        //    hash0      uint32
-       //    buckets    *bmap
-       //    oldbuckets *bmap
+       //    buckets    unsafe.Pointer
+       //    oldbuckets unsafe.Pointer
        //    nevacuate  uintptr
        //    extra      unsafe.Pointer // *mapextra
        // }
@@ -222,15 +222,19 @@ func MapType(t *types.Type) *types.Type {
                makefield("flags", types.Types[types.TUINT8]),
                makefield("B", types.Types[types.TUINT8]),
                makefield("noverflow", types.Types[types.TUINT16]),
-               makefield("hash0", types.Types[types.TUINT32]), // Used in walk.go for OMAKEMAP.
-               makefield("buckets", types.NewPtr(bmap)),       // Used in walk.go for OMAKEMAP.
-               makefield("oldbuckets", types.NewPtr(bmap)),
+               makefield("hash0", types.Types[types.TUINT32]),      // Used in walk.go for OMAKEMAP.
+               makefield("buckets", types.Types[types.TUNSAFEPTR]), // Used in walk.go for OMAKEMAP.
+               makefield("oldbuckets", types.Types[types.TUNSAFEPTR]),
                makefield("nevacuate", types.Types[types.TUINTPTR]),
                makefield("extra", types.Types[types.TUNSAFEPTR]),
        }
 
-       hmap := types.NewStruct(fields)
-       hmap.SetNoalg(true)
+       n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("hmap"))
+       hmap := types.NewNamed(n)
+       n.SetType(hmap)
+       n.SetTypecheck(1)
+
+       hmap.SetUnderlying(types.NewStruct(fields))
        types.CalcSize(hmap)
 
        // The size of hmap should be 48 bytes on 64 bit
@@ -239,29 +243,29 @@ func MapType(t *types.Type) *types.Type {
                base.Fatalf("hmap size not correct: got %d, want %d", hmap.Size(), size)
        }
 
-       t.MapType().Hmap = hmap
-       hmap.StructType().Map = t
+       hmapType = hmap
        return hmap
 }
 
-// MapIterType builds a type representing an Hiter structure for the given map type.
+var hiterType *types.Type
+
+// MapIterType returns a type interchangeable with runtime.hiter.
 // Make sure this stays in sync with runtime/map.go.
-func MapIterType(t *types.Type) *types.Type {
-       if t.MapType().Hiter != nil {
-               return t.MapType().Hiter
+func MapIterType() *types.Type {
+       if hiterType != nil {
+               return hiterType
        }
 
-       hmap := MapType(t)
-       bmap := MapBucketType(t)
+       hmap := MapType()
 
        // build a struct:
        // type hiter struct {
-       //    key         *Key
-       //    elem        *Elem
+       //    key         unsafe.Pointer // *Key
+       //    elem        unsafe.Pointer // *Elem
        //    t           unsafe.Pointer // *MapType
        //    h           *hmap
-       //    buckets     *bmap
-       //    bptr        *bmap
+       //    buckets     unsafe.Pointer
+       //    bptr        unsafe.Pointer // *bmap
        //    overflow    unsafe.Pointer // *[]*bmap
        //    oldoverflow unsafe.Pointer // *[]*bmap
        //    startBucket uintptr
@@ -274,12 +278,12 @@ func MapIterType(t *types.Type) *types.Type {
        // }
        // must match runtime/map.go:hiter.
        fields := []*types.Field{
-               makefield("key", types.NewPtr(t.Key())),   // Used in range.go for TMAP.
-               makefield("elem", types.NewPtr(t.Elem())), // Used in range.go for TMAP.
+               makefield("key", types.Types[types.TUNSAFEPTR]),  // Used in range.go for TMAP.
+               makefield("elem", types.Types[types.TUNSAFEPTR]), // Used in range.go for TMAP.
                makefield("t", types.Types[types.TUNSAFEPTR]),
                makefield("h", types.NewPtr(hmap)),
-               makefield("buckets", types.NewPtr(bmap)),
-               makefield("bptr", types.NewPtr(bmap)),
+               makefield("buckets", types.Types[types.TUNSAFEPTR]),
+               makefield("bptr", types.Types[types.TUNSAFEPTR]),
                makefield("overflow", types.Types[types.TUNSAFEPTR]),
                makefield("oldoverflow", types.Types[types.TUNSAFEPTR]),
                makefield("startBucket", types.Types[types.TUINTPTR]),
@@ -292,14 +296,18 @@ func MapIterType(t *types.Type) *types.Type {
        }
 
        // build iterator struct holding the above fields
-       hiter := types.NewStruct(fields)
-       hiter.SetNoalg(true)
+       n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.Runtime.Lookup("hiter"))
+       hiter := types.NewNamed(n)
+       n.SetType(hiter)
+       n.SetTypecheck(1)
+
+       hiter.SetUnderlying(types.NewStruct(fields))
        types.CalcSize(hiter)
        if hiter.Size() != int64(12*types.PtrSize) {
                base.Fatalf("hash_iter size not correct %d %d", hiter.Size(), 12*types.PtrSize)
        }
-       t.MapType().Hiter = hiter
-       hiter.StructType().Map = t
+
+       hiterType = hiter
        return hiter
 }
 
@@ -947,16 +955,11 @@ func writeType(t *types.Type) *obj.LSym {
 
        s := types.TypeSym(t)
        lsym := s.Linksym()
-       if s.Siggen() {
-               return lsym
-       }
-       s.SetSiggen(true)
 
        // special case (look for runtime below):
        // when compiling package runtime,
        // emit the type structures for int, float, etc.
        tbase := t
-
        if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
                tbase = t.Elem()
        }
@@ -964,6 +967,19 @@ func writeType(t *types.Type) *obj.LSym {
                base.Fatalf("unresolved defined type: %v", tbase)
        }
 
+       // This is a fake type we generated for our builtin pseudo-runtime
+       // package. We'll emit a description for the real type while
+       // compiling package runtime, so we don't need or want to emit one
+       // from this fake type.
+       if sym := tbase.Sym(); sym != nil && sym.Pkg == ir.Pkgs.Runtime {
+               return lsym
+       }
+
+       if s.Siggen() {
+               return lsym
+       }
+       s.SetSiggen(true)
+
        if !NeedEmit(tbase) {
                if i := typecheck.BaseTypeIndex(t); i >= 0 {
                        lsym.Pkg = tbase.Sym().Pkg.Prefix
index 28f68e01bc83444970cc612067986fc429e58cc8..864bd4f9d0f7fb859c4b1eb8a30384bd829f42cc 100644 (file)
@@ -86,6 +86,7 @@ func InitConfig() {
        _ = types.NewPtr(types.Types[types.TINT16])                             // *int16
        _ = types.NewPtr(types.Types[types.TINT64])                             // *int64
        _ = types.NewPtr(types.ErrorType)                                       // *error
+       _ = types.NewPtr(reflectdata.MapType())                                 // *runtime.hmap
        types.NewPtrCacheEnabled = false
        ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0, Arch.SoftFloat)
        ssaConfig.Race = base.Flag.Race
@@ -2802,8 +2803,7 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
                }
 
                // map <--> *hmap
-               if to.Kind() == types.TMAP && from.IsPtr() &&
-                       to.MapType().Hmap == from.Elem() {
+               if to.Kind() == types.TMAP && from == types.NewPtr(reflectdata.MapType()) {
                        return v
                }
 
index 56ff7a73179051c86ef2ba7d8743769491a7e5db..0583635013b82dfd3deb1bde16100b2487cb7674 100644 (file)
@@ -537,15 +537,7 @@ func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
                return ir.OCONVNOP, ""
        }
 
-       // 10. src is map and dst is a pointer to corresponding hmap.
-       // This rule is needed for the implementation detail that
-       // go gc maps are implemented as a pointer to a hmap struct.
-       if src.Kind() == types.TMAP && dst.IsPtr() &&
-               src.MapType().Hmap == dst.Elem() {
-               return ir.OCONVNOP, ""
-       }
-
-       // 11. src is a slice and dst is an array or pointer-to-array.
+       // 10. src is a slice and dst is an array or pointer-to-array.
        // They must have same element type.
        if src.IsSlice() {
                if dst.IsArray() && types.Identical(src.Elem(), dst.Elem()) {
index 0016fb960620148cc5a0d6353e27bc5381e7150e..0646f4375478a1a3cf9ff43c3c459e842d8ec61a 100644 (file)
@@ -511,10 +511,6 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                        switch t {
                        case mt.Bucket:
                                b.WriteString("map.bucket[")
-                       case mt.Hmap:
-                               b.WriteString("map.hdr[")
-                       case mt.Hiter:
-                               b.WriteString("map.iter[")
                        default:
                                base.Fatalf("unknown internal map type")
                        }
index 76ccbd54a506ead84cd8d86f91994c2ff27c8d46..cec12834358f6c364b713100216823997edcb897 100644 (file)
@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
        }{
                {Sym{}, 32, 64},
                {Type{}, 56, 96},
-               {Map{}, 20, 40},
+               {Map{}, 12, 24},
                {Forward{}, 20, 32},
                {Func{}, 20, 32},
                {Struct{}, 12, 24},
index 7a69aaabc133a830cb19b4978a41cb1f8b012c97..5f7e6e131dd1bf3cdf6543d03720a1bb901a4355 100644 (file)
@@ -276,8 +276,6 @@ type Map struct {
        Elem *Type // Val (elem) type
 
        Bucket *Type // internal struct type representing a hash bucket
-       Hmap   *Type // internal struct type representing the Hmap (map header object)
-       Hiter  *Type // internal struct type representing hash iterator state
 }
 
 // MapType returns t's extra map-specific fields.
index f9360224337befa3a118b67a16af6d1459c0f5a0..9f3102cf30bb756358dd0c381bf281be3c454bf6 100644 (file)
@@ -302,7 +302,7 @@ func walkMakeChan(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
 // walkMakeMap walks an OMAKEMAP node.
 func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
        t := n.Type()
-       hmapType := reflectdata.MapType(t)
+       hmapType := reflectdata.MapType()
        hint := n.Len
 
        // var h *hmap
@@ -340,7 +340,7 @@ func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
 
                        // h.buckets = b
                        bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
-                       na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, bsym), b)
+                       na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, bsym), typecheck.ConvNop(b, types.Types[types.TUNSAFEPTR]))
                        nif.Body.Append(na)
                        appendWalkStmt(init, nif)
                }
index 80dd12093494b8d8f5eeac0b8e7cb3420d3171db..f8b755c946c504179fdfd1b260ca3f770483d9ac 100644 (file)
@@ -872,7 +872,7 @@ func (o *orderState) stmt(n ir.Node) {
 
                        // n.Prealloc is the temp for the iterator.
                        // MapIterType contains pointers and needs to be zeroed.
-                       n.Prealloc = o.newTemp(reflectdata.MapIterType(xt), true)
+                       n.Prealloc = o.newTemp(reflectdata.MapIterType(), true)
                }
                n.Key = o.exprInPlace(n.Key)
                n.Value = o.exprInPlace(n.Value)
index ed1a9c402fdebbbcc74ac1464c443351ac7635c3..dd2f346c5ff18d0007b5062e0b78ee465f386385 100644 (file)
@@ -241,13 +241,13 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
                fn = typecheck.SubstArgTypes(fn, th)
                nfor.Post = mkcallstmt1(fn, typecheck.NodAddr(hit))
 
-               key := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym))
+               key := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), types.NewPtr(t.Key())))
                if v1 == nil {
                        body = nil
                } else if v2 == nil {
                        body = []ir.Node{rangeAssign(nrange, key)}
                } else {
-                       elem := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, elemsym))
+                       elem := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, elemsym), types.NewPtr(t.Elem())))
                        body = []ir.Node{rangeAssign2(nrange, key, elem)}
                }
 
index 0e015db34c4d31d1be6254cd5515f07bf2912bd9..1777a51f2a0494fa18129aff2128a3c4c4984447 100644 (file)
@@ -458,7 +458,7 @@ func f28(b bool) {
 
 func f29(b bool) {
        if b {
-               for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
+               for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hiter$"
                        printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
                }
        }
@@ -667,7 +667,7 @@ func bad40() {
 
 func good40() {
        ret := T40{}              // ERROR "stack object ret T40$"
-       ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
+       ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
        t := &ret
        printnl() // ERROR "live at call to printnl: ret$"
        // Note: ret is live at the printnl because the compiler moves &ret
index 83a6cb7db60759dddff85f8ce4ba9542c19f0981..2beac4f8d2bbe4e70711c209383dc198a47829d5 100644 (file)
@@ -27,14 +27,14 @@ func newT40() *T40 {
 }
 
 func bad40() {
-       t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
+       t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ runtime.hmap$"
        printnl()     // ERROR "live at call to printnl: ret$"
        useT40(t)
 }
 
 func good40() {
        ret := T40{}                  // ERROR "stack object ret T40$"
-       ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
+       ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ runtime.hmap$"
        t := &ret
        printnl() // ERROR "live at call to printnl: ret$"
        useT40(t)
index bae319d2fd70243b7f982960d5d83e575a1bb0a1..7ae84891e4a90a4d972bdc8849b11e2be5b5d8fa 100644 (file)
@@ -455,7 +455,7 @@ func f28(b bool) {
 
 func f29(b bool) {
        if b {
-               for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
+               for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hiter$"
                        printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
                }
        }
@@ -664,7 +664,7 @@ func bad40() {
 
 func good40() {
        ret := T40{}              // ERROR "stack object ret T40$"
-       ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
+       ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
        t := &ret
        printnl() // ERROR "live at call to printnl: ret$"
        // Note: ret is live at the printnl because the compiler moves &ret