]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: reorganize compiler type descriptor generation
authorKeith Randall <khr@golang.org>
Mon, 9 Oct 2023 20:34:51 +0000 (13:34 -0700)
committerKeith Randall <khr@golang.org>
Tue, 24 Oct 2023 20:24:47 +0000 (20:24 +0000)
Use the new rttype mechanism to share internal/abi types between
the compiler and runtime.

Change-Id: I2bbba4d8090c6f7ff20dca15b7b665f5d04e5bfd
Reviewed-on: https://go-review.googlesource.com/c/go/+/534936
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Run-TryBot: David Chase <drchase@google.com>

src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/rttype/rttype.go
src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/walk/switch.go
src/internal/abi/compiletype.go

index e23d2fb401dddb8b0d6833e77269ccb6d01e5d80..c2407af017e4b3a780454185a24a8475cfbb1179 100644 (file)
@@ -73,15 +73,13 @@ const (
        MAXELEMSIZE = abi.MapMaxElemBytes
 )
 
-func structfieldSize() int { return abi.StructFieldSize(types.PtrSize) } // Sizeof(runtime.structfield{})
-func imethodSize() int     { return abi.IMethodSize(types.PtrSize) }     // Sizeof(runtime.imethod{})
-func commonSize() int      { return int(rttype.Type.Size()) }            // Sizeof(runtime._type{})
+func commonSize() int { return int(rttype.Type.Size()) } // Sizeof(runtime._type{})
 
 func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})
        if t.Sym() == nil && len(methods(t)) == 0 {
                return 0
        }
-       return int(abi.UncommonSize())
+       return int(rttype.UncommonType.Size())
 }
 
 func makefield(name string, t *types.Type) *types.Field {
@@ -432,32 +430,35 @@ func dimportpath(p *types.Pkg) {
        p.Pathsym = s
 }
 
-func dgopkgpath(s *obj.LSym, ot int, pkg *types.Pkg) int {
+func dgopkgpath(c rttype.Cursor, pkg *types.Pkg) {
+       c = c.Field("Bytes")
        if pkg == nil {
-               return objw.Uintptr(s, ot, 0)
+               c.WritePtr(nil)
+               return
        }
 
        dimportpath(pkg)
-       return objw.SymPtr(s, ot, pkg.Pathsym, 0)
+       c.WritePtr(pkg.Pathsym)
 }
 
-// dgopkgpathOff writes an offset relocation in s at offset ot to the pkg path symbol.
-func dgopkgpathOff(s *obj.LSym, ot int, pkg *types.Pkg) int {
+// dgopkgpathOff writes an offset relocation to the pkg path symbol to c.
+func dgopkgpathOff(c rttype.Cursor, pkg *types.Pkg) {
        if pkg == nil {
-               return objw.Uint32(s, ot, 0)
+               c.WriteInt32(0)
+               return
        }
 
        dimportpath(pkg)
-       return objw.SymPtrOff(s, ot, pkg.Pathsym)
+       c.WriteSymPtrOff(pkg.Pathsym, false)
 }
 
 // dnameField dumps a reflect.name for a struct field.
-func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int {
+func dnameField(c rttype.Cursor, spkg *types.Pkg, ft *types.Field) {
        if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg {
                base.Fatalf("package mismatch for %v", ft.Sym)
        }
        nsym := dname(ft.Sym.Name, ft.Note, nil, types.IsExported(ft.Sym.Name), ft.Embedded != 0)
-       return objw.SymPtr(lsym, ot, nsym, 0)
+       c.Field("Bytes").WritePtr(nsym)
 }
 
 // dnameData writes the contents of a reflect.name into s at offset ot.
@@ -502,7 +503,9 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported,
        ot = int(s.WriteBytes(base.Ctxt, int64(ot), b))
 
        if pkg != nil {
-               ot = dgopkgpathOff(s, ot, pkg)
+               c := rttype.NewCursor(s, int64(ot), types.Types[types.TUINT32])
+               dgopkgpathOff(c, pkg)
+               ot += 4
        }
 
        return ot
@@ -553,14 +556,14 @@ func dname(name, tag string, pkg *types.Pkg, exported, embedded bool) *obj.LSym
 
 // dextratype dumps the fields of a runtime.uncommontype.
 // dataAdd is the offset in bytes after the header where the
-// backing array of the []method field is written (by dextratypeData).
-func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
+// backing array of the []method field should be written.
+func dextratype(lsym *obj.LSym, off int64, t *types.Type, dataAdd int) {
        m := methods(t)
        if t.Sym() == nil && len(m) == 0 {
-               return ot
+               base.Fatalf("extra requested of type with no extra info %v", t)
        }
-       noff := int(types.RoundUp(int64(ot), int64(types.PtrSize)))
-       if noff != ot {
+       noff := types.RoundUp(off, int64(types.PtrSize))
+       if noff != off {
                base.Fatalf("unexpected alignment in dextratype for %v", t)
        }
 
@@ -568,7 +571,8 @@ func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
                writeType(a.type_)
        }
 
-       ot = dgopkgpathOff(lsym, ot, typePkg(t))
+       c := rttype.NewCursor(lsym, off, rttype.UncommonType)
+       dgopkgpathOff(c.Field("PkgPath"), typePkg(t))
 
        dataAdd += uncommonSize(t)
        mcount := len(m)
@@ -580,11 +584,27 @@ func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
                base.Fatalf("methods are too far away on %v: %d", t, dataAdd)
        }
 
-       ot = objw.Uint16(lsym, ot, uint16(mcount))
-       ot = objw.Uint16(lsym, ot, uint16(xcount))
-       ot = objw.Uint32(lsym, ot, uint32(dataAdd))
-       ot = objw.Uint32(lsym, ot, 0)
-       return ot
+       c.Field("Mcount").WriteUint16(uint16(mcount))
+       c.Field("Xcount").WriteUint16(uint16(xcount))
+       c.Field("Moff").WriteUint32(uint32(dataAdd))
+       // Note: there is an unused uint32 field here.
+
+       // Write the backing array for the []method field.
+       array := rttype.NewArrayCursor(lsym, off+int64(dataAdd), rttype.Method, mcount)
+       for i, a := range m {
+               exported := types.IsExported(a.name.Name)
+               var pkg *types.Pkg
+               if !exported && a.name.Pkg != typePkg(t) {
+                       pkg = a.name.Pkg
+               }
+               nsym := dname(a.name.Name, "", pkg, exported, false)
+
+               e := array.Elem(i)
+               e.Field("Name").WriteSymPtrOff(nsym, false)
+               dmethodptrOff(e.Field("Mtyp"), writeType(a.mtype))
+               dmethodptrOff(e.Field("Ifn"), a.isym)
+               dmethodptrOff(e.Field("Tfn"), a.tsym)
+       }
 }
 
 func typePkg(t *types.Type) *types.Pkg {
@@ -603,34 +623,11 @@ func typePkg(t *types.Type) *types.Pkg {
        return nil
 }
 
-// dextratypeData dumps the backing array for the []method field of
-// runtime.uncommontype.
-func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
-       for _, a := range methods(t) {
-               // ../../../../runtime/type.go:/method
-               exported := types.IsExported(a.name.Name)
-               var pkg *types.Pkg
-               if !exported && a.name.Pkg != typePkg(t) {
-                       pkg = a.name.Pkg
-               }
-               nsym := dname(a.name.Name, "", pkg, exported, false)
-
-               ot = objw.SymPtrOff(lsym, ot, nsym)
-               ot = dmethodptrOff(lsym, ot, writeType(a.mtype))
-               ot = dmethodptrOff(lsym, ot, a.isym)
-               ot = dmethodptrOff(lsym, ot, a.tsym)
-       }
-       return ot
-}
-
-func dmethodptrOff(s *obj.LSym, ot int, x *obj.LSym) int {
-       objw.Uint32(s, ot, 0)
-       r := obj.Addrel(s)
-       r.Off = int32(ot)
-       r.Siz = 4
+func dmethodptrOff(c rttype.Cursor, x *obj.LSym) {
+       c.WriteInt32(0)
+       r := c.Reloc()
        r.Sym = x
        r.Type = objabi.R_METHODOFF
-       return ot + 4
 }
 
 var kinds = []int{
@@ -667,8 +664,8 @@ var (
        memequalvarlen *obj.LSym
 )
 
-// dcommontype dumps the contents of a reflect.rtype (runtime._type).
-func dcommontype(lsym *obj.LSym, t *types.Type) int {
+// dcommontype dumps the contents of a reflect.rtype (runtime._type) to c.
+func dcommontype(c rttype.Cursor, t *types.Type) {
        types.CalcSize(t)
        eqfunc := geneq(t)
 
@@ -700,10 +697,9 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
        //              str           nameOff
        //              ptrToThis     typeOff
        //      }
-       rt := rttype.Type
-       rt.WriteUintptr(lsym, "Size_", uint64(t.Size()))
-       rt.WriteUintptr(lsym, "PtrBytes", uint64(ptrdata))
-       rt.WriteUint32(lsym, "Hash", types.TypeHash(t))
+       c.Field("Size_").WriteUintptr(uint64(t.Size()))
+       c.Field("PtrBytes").WriteUintptr(uint64(ptrdata))
+       c.Field("Hash").WriteUint32(types.TypeHash(t))
 
        var tflag abi.TFlag
        if uncommonSize(t) != 0 {
@@ -739,7 +735,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
                // this should optimize away completely
                panic("Unexpected change in size of abi.TFlag")
        }
-       rt.WriteUint8(lsym, "TFlag", uint8(tflag))
+       c.Field("TFlag").WriteUint8(uint8(tflag))
 
        // runtime (and common sense) expects alignment to be a power of two.
        i := int(uint8(t.Alignment()))
@@ -750,8 +746,8 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
        if i&(i-1) != 0 {
                base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)
        }
-       rt.WriteUint8(lsym, "Align_", uint8(t.Alignment()))
-       rt.WriteUint8(lsym, "FieldAlign_", uint8(t.Alignment()))
+       c.Field("Align_").WriteUint8(uint8(t.Alignment()))
+       c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))
 
        i = kinds[t.Kind()]
        if types.IsDirectIface(t) {
@@ -760,16 +756,14 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
        if useGCProg {
                i |= objabi.KindGCProg
        }
-       rt.WriteUint8(lsym, "Kind_", uint8(i))
+       c.Field("Kind_").WriteUint8(uint8(i))
 
-       rt.WritePtr(lsym, "Equal", eqfunc)
-       rt.WritePtr(lsym, "GCData", gcsym)
+       c.Field("Equal").WritePtr(eqfunc)
+       c.Field("GCData").WritePtr(gcsym)
 
        nsym := dname(p, "", nil, exported, false)
-       rt.WriteSymPtrOff(lsym, "Str", nsym, false)
-       rt.WriteSymPtrOff(lsym, "PtrToThis", sptr, sptrWeak)
-
-       return int(rt.Size())
+       c.Field("Str").WriteSymPtrOff(nsym, false)
+       c.Field("PtrToThis").WriteSymPtrOff(sptr, sptrWeak)
 }
 
 // TrackSym returns the symbol for tracking use of field/method f, assumed
@@ -973,87 +967,137 @@ func writeType(t *types.Type) *obj.LSym {
                return lsym
        }
 
-       ot := 0
+       // Type layout                          Written by               Marker
+       // +--------------------------------+                            - 0
+       // | abi/internal.Type              |   dcommontype
+       // +--------------------------------+                            - A
+       // | additional type-dependent      |   code in the switch below
+       // | fields, e.g.                   |
+       // | abi/internal.ArrayType.Len     |
+       // +--------------------------------+                            - B
+       // | internal/abi.UncommonType      |   dextratype
+       // | This section is optional,      |
+       // | if type has a name or methods  |
+       // +--------------------------------+                            - C
+       // | variable-length data           |   code in the switch below
+       // | referenced by                  |
+       // | type-dependent fields, e.g.    |
+       // | abi/internal.StructType.Fields |
+       // | dataAdd = size of this section |
+       // +--------------------------------+                            - D
+       // | method list, if any            |   dextratype
+       // +--------------------------------+                            - E
+
+       // UncommonType section is included if we have a name or a method.
+       extra := t.Sym() != nil || len(methods(t)) != 0
+
+       // Decide the underlying type of the descriptor, and remember
+       // the size we need for variable-length data.
+       var rt *types.Type
+       dataAdd := 0
        switch t.Kind() {
        default:
-               ot = dcommontype(lsym, t)
-               ot = dextratype(lsym, ot, t, 0)
+               rt = rttype.Type
+       case types.TARRAY:
+               rt = rttype.ArrayType
+       case types.TSLICE:
+               rt = rttype.SliceType
+       case types.TCHAN:
+               rt = rttype.ChanType
+       case types.TFUNC:
+               rt = rttype.FuncType
+               dataAdd = (t.NumRecvs() + t.NumParams() + t.NumResults()) * types.PtrSize
+       case types.TINTER:
+               rt = rttype.InterfaceType
+               dataAdd = len(imethods(t)) * int(rttype.IMethod.Size())
+       case types.TMAP:
+               rt = rttype.MapType
+       case types.TPTR:
+               rt = rttype.PtrType
+               // TODO: use rttype.Type for Elem() is ANY?
+       case types.TSTRUCT:
+               rt = rttype.StructType
+               dataAdd = t.NumFields() * int(rttype.StructField.Size())
+       }
+
+       // Compute offsets of each section.
+       B := rt.Size()
+       C := B
+       if extra {
+               C = B + rttype.UncommonType.Size()
+       }
+       D := C + int64(dataAdd)
+       E := D + int64(len(methods(t)))*rttype.Method.Size()
 
+       // Write the runtime._type
+       c := rttype.NewCursor(lsym, 0, rt)
+       if rt == rttype.Type {
+               dcommontype(c, t)
+       } else {
+               dcommontype(c.Field("Type"), t)
+       }
+
+       // Write additional type-specific data
+       // (Both the fixed size and variable-sized sections.)
+       switch t.Kind() {
        case types.TARRAY:
-               // ../../../../runtime/type.go:/arrayType
+               // internal/abi.ArrayType
                s1 := writeType(t.Elem())
                t2 := types.NewSlice(t.Elem())
                s2 := writeType(t2)
-               ot = dcommontype(lsym, t)
-               ot = objw.SymPtr(lsym, ot, s1, 0)
-               ot = objw.SymPtr(lsym, ot, s2, 0)
-               ot = objw.Uintptr(lsym, ot, uint64(t.NumElem()))
-               ot = dextratype(lsym, ot, t, 0)
+               c.Field("Elem").WritePtr(s1)
+               c.Field("Slice").WritePtr(s2)
+               c.Field("Len").WriteUintptr(uint64(t.NumElem()))
 
        case types.TSLICE:
-               // ../../../../runtime/type.go:/sliceType
+               // internal/abi.SliceType
                s1 := writeType(t.Elem())
-               ot = dcommontype(lsym, t)
-               ot = objw.SymPtr(lsym, ot, s1, 0)
-               ot = dextratype(lsym, ot, t, 0)
+               c.Field("Elem").WritePtr(s1)
 
        case types.TCHAN:
-               // ../../../../runtime/type.go:/chanType
+               // internal/abi.ChanType
                s1 := writeType(t.Elem())
-               ot = dcommontype(lsym, t)
-               ot = objw.SymPtr(lsym, ot, s1, 0)
-               ot = objw.Uintptr(lsym, ot, uint64(t.ChanDir()))
-               ot = dextratype(lsym, ot, t, 0)
+               c.Field("Elem").WritePtr(s1)
+               c.Field("Dir").WriteInt(int64(t.ChanDir()))
 
        case types.TFUNC:
+               // internal/abi.FuncType
                for _, t1 := range t.RecvParamsResults() {
                        writeType(t1.Type)
                }
-
-               ot = dcommontype(lsym, t)
                inCount := t.NumRecvs() + t.NumParams()
                outCount := t.NumResults()
                if t.IsVariadic() {
                        outCount |= 1 << 15
                }
-               ot = objw.Uint16(lsym, ot, uint16(inCount))
-               ot = objw.Uint16(lsym, ot, uint16(outCount))
-               if types.PtrSize == 8 {
-                       ot += 4 // align for *rtype
-               }
 
-               dataAdd := (inCount + t.NumResults()) * types.PtrSize
-               ot = dextratype(lsym, ot, t, dataAdd)
+               c.Field("InCount").WriteUint16(uint16(inCount))
+               c.Field("OutCount").WriteUint16(uint16(outCount))
 
                // Array of rtype pointers follows funcType.
-               for _, t1 := range t.RecvParamsResults() {
-                       ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
+               typs := t.RecvParamsResults()
+               array := rttype.NewArrayCursor(lsym, C, types.Types[types.TUNSAFEPTR], len(typs))
+               for i, t1 := range typs {
+                       array.Elem(i).WritePtr(writeType(t1.Type))
                }
 
        case types.TINTER:
+               // internal/abi.InterfaceType
                m := imethods(t)
                n := len(m)
                for _, a := range m {
                        writeType(a.type_)
                }
 
-               // ../../../../runtime/type.go:/interfaceType
-               ot = dcommontype(lsym, t)
-
                var tpkg *types.Pkg
                if t.Sym() != nil && t != types.Types[t.Kind()] && t != types.ErrorType {
                        tpkg = t.Sym().Pkg
                }
-               ot = dgopkgpath(lsym, ot, tpkg)
+               dgopkgpath(c.Field("PkgPath"), tpkg)
+               c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))
 
-               ot = objw.SymPtr(lsym, ot, lsym, ot+3*types.PtrSize+uncommonSize(t))
-               ot = objw.Uintptr(lsym, ot, uint64(n))
-               ot = objw.Uintptr(lsym, ot, uint64(n))
-               dataAdd := imethodSize() * n
-               ot = dextratype(lsym, ot, t, dataAdd)
-
-               for _, a := range m {
-                       // ../../../../runtime/type.go:/imethod
+               array := rttype.NewArrayCursor(lsym, C, rttype.IMethod, n)
+               for i, a := range m {
                        exported := types.IsExported(a.name.Name)
                        var pkg *types.Pkg
                        if !exported && a.name.Pkg != tpkg {
@@ -1061,39 +1105,39 @@ func writeType(t *types.Type) *obj.LSym {
                        }
                        nsym := dname(a.name.Name, "", pkg, exported, false)
 
-                       ot = objw.SymPtrOff(lsym, ot, nsym)
-                       ot = objw.SymPtrOff(lsym, ot, writeType(a.type_))
+                       e := array.Elem(i)
+                       e.Field("Name").WriteSymPtrOff(nsym, false)
+                       e.Field("Typ").WriteSymPtrOff(writeType(a.type_), false)
                }
 
-       // ../../../../runtime/type.go:/mapType
        case types.TMAP:
+               // internal/abi.MapType
                s1 := writeType(t.Key())
                s2 := writeType(t.Elem())
                s3 := writeType(MapBucketType(t))
                hasher := genhash(t.Key())
 
-               ot = dcommontype(lsym, t)
-               ot = objw.SymPtr(lsym, ot, s1, 0)
-               ot = objw.SymPtr(lsym, ot, s2, 0)
-               ot = objw.SymPtr(lsym, ot, s3, 0)
-               ot = objw.SymPtr(lsym, ot, hasher, 0)
+               c.Field("Key").WritePtr(s1)
+               c.Field("Elem").WritePtr(s2)
+               c.Field("Bucket").WritePtr(s3)
+               c.Field("Hasher").WritePtr(hasher)
                var flags uint32
                // Note: flags must match maptype accessors in ../../../../runtime/type.go
                // and maptype builder in ../../../../reflect/type.go:MapOf.
                if t.Key().Size() > MAXKEYSIZE {
-                       ot = objw.Uint8(lsym, ot, uint8(types.PtrSize))
+                       c.Field("KeySize").WriteUint8(uint8(types.PtrSize))
                        flags |= 1 // indirect key
                } else {
-                       ot = objw.Uint8(lsym, ot, uint8(t.Key().Size()))
+                       c.Field("KeySize").WriteUint8(uint8(t.Key().Size()))
                }
 
                if t.Elem().Size() > MAXELEMSIZE {
-                       ot = objw.Uint8(lsym, ot, uint8(types.PtrSize))
+                       c.Field("ValueSize").WriteUint8(uint8(types.PtrSize))
                        flags |= 2 // indirect value
                } else {
-                       ot = objw.Uint8(lsym, ot, uint8(t.Elem().Size()))
+                       c.Field("ValueSize").WriteUint8(uint8(t.Elem().Size()))
                }
-               ot = objw.Uint16(lsym, ot, uint16(MapBucketType(t).Size()))
+               c.Field("BucketSize").WriteUint16(uint16(MapBucketType(t).Size()))
                if types.IsReflexive(t.Key()) {
                        flags |= 4 // reflexive key
                }
@@ -1103,8 +1147,8 @@ func writeType(t *types.Type) *obj.LSym {
                if hashMightPanic(t.Key()) {
                        flags |= 16 // hash might panic
                }
-               ot = objw.Uint32(lsym, ot, flags)
-               ot = dextratype(lsym, ot, t, 0)
+               c.Field("Flags").WriteUint32(flags)
+
                if u := t.Underlying(); u != t {
                        // If t is a named map type, also keep the underlying map
                        // type live in the binary. This is important to make sure that
@@ -1116,24 +1160,16 @@ func writeType(t *types.Type) *obj.LSym {
                }
 
        case types.TPTR:
+               // internal/abi.PtrType
                if t.Elem().Kind() == types.TANY {
-                       // ../../../../runtime/type.go:/UnsafePointerType
-                       ot = dcommontype(lsym, t)
-                       ot = dextratype(lsym, ot, t, 0)
-
-                       break
+                       base.Fatalf("bad pointer base type")
                }
 
-               // ../../../../runtime/type.go:/ptrType
                s1 := writeType(t.Elem())
+               c.Field("Elem").WritePtr(s1)
 
-               ot = dcommontype(lsym, t)
-               ot = objw.SymPtr(lsym, ot, s1, 0)
-               ot = dextratype(lsym, ot, t, 0)
-
-       // ../../../../runtime/type.go:/structType
-       // for security, only the exported fields.
        case types.TSTRUCT:
+               // internal/abi.StructType
                fields := t.Fields()
                for _, t1 := range fields {
                        writeType(t1.Type)
@@ -1152,23 +1188,23 @@ func writeType(t *types.Type) *obj.LSym {
                        }
                }
 
-               ot = dcommontype(lsym, t)
-               ot = dgopkgpath(lsym, ot, spkg)
-               ot = objw.SymPtr(lsym, ot, lsym, ot+3*types.PtrSize+uncommonSize(t))
-               ot = objw.Uintptr(lsym, ot, uint64(len(fields)))
-               ot = objw.Uintptr(lsym, ot, uint64(len(fields)))
-
-               dataAdd := len(fields) * structfieldSize()
-               ot = dextratype(lsym, ot, t, dataAdd)
+               dgopkgpath(c.Field("PkgPath"), spkg)
+               c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))
 
-               for _, f := range fields {
-                       // ../../../../runtime/type.go:/structField
-                       ot = dnameField(lsym, ot, spkg, f)
-                       ot = objw.SymPtr(lsym, ot, writeType(f.Type), 0)
-                       ot = objw.Uintptr(lsym, ot, uint64(f.Offset))
+               array := rttype.NewArrayCursor(lsym, C, rttype.StructField, len(fields))
+               for i, f := range fields {
+                       e := array.Elem(i)
+                       dnameField(e.Field("Name"), spkg, f)
+                       e.Field("Typ").WritePtr(writeType(f.Type))
+                       e.Field("Offset").WriteUintptr(uint64(f.Offset))
                }
        }
 
+       // Write the extra info, if any.
+       if extra {
+               dextratype(lsym, B, t, dataAdd)
+       }
+
        // Note: DUPOK is required to ensure that we don't end up with more
        // than one type descriptor for a given type, if the type descriptor
        // can be defined in multiple packages, that is, unnamed types,
@@ -1178,8 +1214,7 @@ func writeType(t *types.Type) *obj.LSym {
                dupok = obj.DUPOK
        }
 
-       ot = dextratypeData(lsym, ot, t)
-       objw.Global(lsym, int32(ot), int16(dupok|obj.RODATA))
+       objw.Global(lsym, int32(E), int16(dupok|obj.RODATA))
 
        // The linker will leave a table of all the typelinks for
        // types in the binary, so the runtime can find them.
index 474203631deeabc1a80c653c5ccaa5a77f474f05..1a614c86784bd17bd1bf20c7a3a524b7bab30bbf 100644 (file)
@@ -16,32 +16,46 @@ import (
        "cmd/compile/internal/objw"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
-       "fmt"
        "internal/abi"
        "reflect"
 )
 
-type RuntimeType struct {
-       // A *types.Type representing a type used at runtime.
-       t *types.Type
-       // components maps from component names to their location in the type.
-       components map[string]location
-}
+// The type structures shared with the runtime.
+var Type *types.Type
 
-type location struct {
-       offset int64
-       kind   types.Kind // Just used for bug detection
-}
+var ArrayType *types.Type
+var ChanType *types.Type
+var FuncType *types.Type
+var InterfaceType *types.Type
+var MapType *types.Type
+var PtrType *types.Type
+var SliceType *types.Type
+var StructType *types.Type
 
-// Types shared with the runtime via internal/abi.
-// TODO: add more
-var Type *RuntimeType
+// Types that are parts of the types above.
+var IMethod *types.Type
+var Method *types.Type
+var StructField *types.Type
+var UncommonType *types.Type
 
 func Init() {
        // Note: this has to be called explicitly instead of being
        // an init function so it runs after the types package has
        // been properly initialized.
        Type = fromReflect(reflect.TypeOf(abi.Type{}))
+       ArrayType = fromReflect(reflect.TypeOf(abi.ArrayType{}))
+       ChanType = fromReflect(reflect.TypeOf(abi.ChanType{}))
+       FuncType = fromReflect(reflect.TypeOf(abi.FuncType{}))
+       InterfaceType = fromReflect(reflect.TypeOf(abi.InterfaceType{}))
+       MapType = fromReflect(reflect.TypeOf(abi.MapType{}))
+       PtrType = fromReflect(reflect.TypeOf(abi.PtrType{}))
+       SliceType = fromReflect(reflect.TypeOf(abi.SliceType{}))
+       StructType = fromReflect(reflect.TypeOf(abi.StructType{}))
+
+       IMethod = fromReflect(reflect.TypeOf(abi.Imethod{}))
+       Method = fromReflect(reflect.TypeOf(abi.Method{}))
+       StructField = fromReflect(reflect.TypeOf(abi.StructField{}))
+       UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{}))
 
        // Make sure abi functions are correct. These functions are used
        // by the linker which doesn't have the ability to do type layout,
@@ -50,17 +64,22 @@ func Init() {
        if got, want := int64(abi.CommonSize(ptrSize)), Type.Size(); got != want {
                base.Fatalf("abi.CommonSize() == %d, want %d", got, want)
        }
-       if got, want := int64(abi.TFlagOff(ptrSize)), Type.Offset("TFlag"); got != want {
+       if got, want := int64(abi.StructFieldSize(ptrSize)), StructField.Size(); got != want {
+               base.Fatalf("abi.StructFieldSize() == %d, want %d", got, want)
+       }
+       if got, want := int64(abi.UncommonSize()), UncommonType.Size(); got != want {
+               base.Fatalf("abi.UncommonSize() == %d, want %d", got, want)
+       }
+       if got, want := int64(abi.TFlagOff(ptrSize)), Type.OffsetOf("TFlag"); got != want {
                base.Fatalf("abi.TFlagOff() == %d, want %d", got, want)
        }
 }
 
-// fromReflect translates from a host type to the equivalent
-// target type.
-func fromReflect(rt reflect.Type) *RuntimeType {
+// fromReflect translates from a host type to the equivalent target type.
+func fromReflect(rt reflect.Type) *types.Type {
        t := reflectToType(rt)
        types.CalcSize(t)
-       return &RuntimeType{t: t, components: unpack(t)}
+       return t
 }
 
 // reflectToType converts from a reflect.Type (which is a compiler
@@ -68,8 +87,6 @@ func fromReflect(rt reflect.Type) *RuntimeType {
 // must be CalcSize'd before using.
 func reflectToType(rt reflect.Type) *types.Type {
        switch rt.Kind() {
-       case reflect.Bool:
-               return types.Types[types.TBOOL]
        case reflect.Int:
                return types.Types[types.TINT]
        case reflect.Int32:
@@ -86,6 +103,8 @@ func reflectToType(rt reflect.Type) *types.Type {
                // TODO: there's no mechanism to distinguish different pointer types,
                // so we treat them all as unsafe.Pointer.
                return types.Types[types.TUNSAFEPTR]
+       case reflect.Slice:
+               return types.NewSlice(reflectToType(rt.Elem()))
        case reflect.Array:
                return types.NewArray(reflectToType(rt.Elem()), int64(rt.Len()))
        case reflect.Struct:
@@ -102,91 +121,137 @@ func reflectToType(rt reflect.Type) *types.Type {
        }
 }
 
-// Unpack generates a set of components of a *types.Type.
-// The type must have already been CalcSize'd.
-func unpack(t *types.Type) map[string]location {
-       components := map[string]location{}
-       switch t.Kind() {
-       default:
-               components[""] = location{0, t.Kind()}
-       case types.TARRAY:
-               // TODO: not used yet
-               elemSize := t.Elem().Size()
-               for name, loc := range unpack(t.Elem()) {
-                       for i := int64(0); i < t.NumElem(); i++ {
-                               components[fmt.Sprintf("[%d]%s", i, name)] = location{i*elemSize + loc.offset, loc.kind}
-                       }
-               }
-       case types.TSTRUCT:
-               for _, f := range t.Fields() {
-                       for name, loc := range unpack(f.Type) {
-                               n := f.Sym.Name
-                               if name != "" {
-                                       n += "." + name
-                               }
-                               components[n] = location{f.Offset + loc.offset, loc.kind}
-                       }
-               }
-       }
-       return components
-}
-
-func (r *RuntimeType) Size() int64 {
-       return r.t.Size()
-}
-
-func (r *RuntimeType) Alignment() int64 {
-       return r.t.Alignment()
+// A Cursor represents a typed location inside a static variable where we
+// are going to write.
+type Cursor struct {
+       lsym   *obj.LSym
+       offset int64
+       typ    *types.Type
 }
 
-func (r *RuntimeType) Offset(name string) int64 {
-       return r.components[name].offset
+// NewCursor returns a cursor starting at lsym+off and having type t.
+func NewCursor(lsym *obj.LSym, off int64, t *types.Type) Cursor {
+       return Cursor{lsym: lsym, offset: off, typ: t}
 }
 
-// WritePtr writes a pointer "target" to the component named "name" in the
-// static object "lsym".
-func (r *RuntimeType) WritePtr(lsym *obj.LSym, name string, target *obj.LSym) {
-       loc := r.components[name]
-       if loc.kind != types.TUNSAFEPTR {
-               base.Fatalf("can't write ptr to field %s, it has kind %s", name, loc.kind)
+// WritePtr writes a pointer "target" to the component at the location specified by c.
+func (c Cursor) WritePtr(target *obj.LSym) {
+       if c.typ.Kind() != types.TUNSAFEPTR {
+               base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind())
        }
        if target == nil {
-               objw.Uintptr(lsym, int(loc.offset), 0)
+               objw.Uintptr(c.lsym, int(c.offset), 0)
        } else {
-               objw.SymPtr(lsym, int(loc.offset), target, 0)
+               objw.SymPtr(c.lsym, int(c.offset), target, 0)
+       }
+}
+func (c Cursor) WriteUintptr(val uint64) {
+       if c.typ.Kind() != types.TUINTPTR {
+               base.Fatalf("can't write uintptr, it has kind %s", c.typ.Kind())
+       }
+       objw.Uintptr(c.lsym, int(c.offset), val)
+}
+func (c Cursor) WriteUint32(val uint32) {
+       if c.typ.Kind() != types.TUINT32 {
+               base.Fatalf("can't write uint32, it has kind %s", c.typ.Kind())
        }
+       objw.Uint32(c.lsym, int(c.offset), val)
 }
-func (r *RuntimeType) WriteUintptr(lsym *obj.LSym, name string, val uint64) {
-       loc := r.components[name]
-       if loc.kind != types.TUINTPTR {
-               base.Fatalf("can't write uintptr to field %s, it has kind %s", name, loc.kind)
+func (c Cursor) WriteUint16(val uint16) {
+       if c.typ.Kind() != types.TUINT16 {
+               base.Fatalf("can't write uint16, it has kind %s", c.typ.Kind())
        }
-       objw.Uintptr(lsym, int(loc.offset), val)
+       objw.Uint16(c.lsym, int(c.offset), val)
 }
-func (r *RuntimeType) WriteUint32(lsym *obj.LSym, name string, val uint32) {
-       loc := r.components[name]
-       if loc.kind != types.TUINT32 {
-               base.Fatalf("can't write uint32 to field %s, it has kind %s", name, loc.kind)
+func (c Cursor) WriteUint8(val uint8) {
+       if c.typ.Kind() != types.TUINT8 {
+               base.Fatalf("can't write uint8, it has kind %s", c.typ.Kind())
        }
-       objw.Uint32(lsym, int(loc.offset), val)
+       objw.Uint8(c.lsym, int(c.offset), val)
 }
-func (r *RuntimeType) WriteUint8(lsym *obj.LSym, name string, val uint8) {
-       loc := r.components[name]
-       if loc.kind != types.TUINT8 {
-               base.Fatalf("can't write uint8 to field %s, it has kind %s", name, loc.kind)
+func (c Cursor) WriteInt(val int64) {
+       if c.typ.Kind() != types.TINT {
+               base.Fatalf("can't write int, it has kind %s", c.typ.Kind())
        }
-       objw.Uint8(lsym, int(loc.offset), val)
+       objw.Uintptr(c.lsym, int(c.offset), uint64(val))
 }
-func (r *RuntimeType) WriteSymPtrOff(lsym *obj.LSym, name string, target *obj.LSym, weak bool) {
-       loc := r.components[name]
-       if loc.kind != types.TINT32 {
-               base.Fatalf("can't write SymPtr to field %s, it has kind %s", name, loc.kind)
+func (c Cursor) WriteInt32(val int32) {
+       if c.typ.Kind() != types.TINT32 {
+               base.Fatalf("can't write int32, it has kind %s", c.typ.Kind())
+       }
+       objw.Uint32(c.lsym, int(c.offset), uint32(val))
+}
+
+// WriteSymPtrOff writes a "pointer" to the given symbol. The symbol
+// is encoded as a uint32 offset from the start of the section.
+func (c Cursor) WriteSymPtrOff(target *obj.LSym, weak bool) {
+       if c.typ.Kind() != types.TINT32 && c.typ.Kind() != types.TUINT32 {
+               base.Fatalf("can't write SymPtr, it has kind %s", c.typ.Kind())
        }
        if target == nil {
-               objw.Uint32(lsym, int(loc.offset), 0)
+               objw.Uint32(c.lsym, int(c.offset), 0)
        } else if weak {
-               objw.SymPtrWeakOff(lsym, int(loc.offset), target)
+               objw.SymPtrWeakOff(c.lsym, int(c.offset), target)
        } else {
-               objw.SymPtrOff(lsym, int(loc.offset), target)
+               objw.SymPtrOff(c.lsym, int(c.offset), target)
+       }
+}
+
+// WriteSlice writes a slice header to c. The pointer is target+off, the len and cap fields are given.
+func (c Cursor) WriteSlice(target *obj.LSym, off, len, cap int64) {
+       if c.typ.Kind() != types.TSLICE {
+               base.Fatalf("can't write slice, it has kind %s", c.typ.Kind())
+       }
+       objw.SymPtr(c.lsym, int(c.offset), target, int(off))
+       objw.Uintptr(c.lsym, int(c.offset)+types.PtrSize, uint64(len))
+       objw.Uintptr(c.lsym, int(c.offset)+2*types.PtrSize, uint64(cap))
+       // TODO: ability to switch len&cap. Maybe not needed here, as every caller
+       // passes the same thing for both?
+       if len != cap {
+               base.Fatalf("len != cap (%d != %d)", len, cap)
+       }
+}
+
+// Reloc adds a relocation from the current cursor position.
+// Reloc fills in Off and Siz fields. Caller should fill in the rest (Type, others).
+func (c Cursor) Reloc() *obj.Reloc {
+       r := obj.Addrel(c.lsym)
+       r.Off = int32(c.offset)
+       r.Siz = uint8(c.typ.Size())
+       return r
+}
+
+// Field selects the field with the given name from the struct pointed to by c.
+func (c Cursor) Field(name string) Cursor {
+       if c.typ.Kind() != types.TSTRUCT {
+               base.Fatalf("can't call Field on non-struct %v", c.typ)
+       }
+       for _, f := range c.typ.Fields() {
+               if f.Sym.Name == name {
+                       return Cursor{lsym: c.lsym, offset: c.offset + f.Offset, typ: f.Type}
+               }
+       }
+       base.Fatalf("couldn't find field %s in %v", name, c.typ)
+       return Cursor{}
+}
+
+type ArrayCursor struct {
+       c Cursor // cursor pointing at first element
+       n int    // number of elements
+}
+
+// NewArrayCursor returns a cursor starting at lsym+off and having n copies of type t.
+func NewArrayCursor(lsym *obj.LSym, off int64, t *types.Type, n int) ArrayCursor {
+       return ArrayCursor{
+               c: NewCursor(lsym, off, t),
+               n: n,
+       }
+}
+
+// Elem selects element i of the array pointed to by c.
+func (a ArrayCursor) Elem(i int) Cursor {
+       if i < 0 || i >= a.n {
+               base.Fatalf("element index %d out of range [0:%d]", i, a.n)
        }
+       return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ}
 }
index 3655c5db022ea16061b5ad0e73c874510495e07b..2777b4f007318b2104034aed0954d6228a0ddb23 100644 (file)
@@ -1471,6 +1471,21 @@ func (t *Type) FieldName(i int) string {
        return t.Field(i).Sym.Name
 }
 
+// OffsetOf reports the offset of the field of a struct.
+// The field is looked up by name.
+func (t *Type) OffsetOf(name string) int64 {
+       if t.kind != TSTRUCT {
+               base.Fatalf("can't call OffsetOf on non-struct %v", t)
+       }
+       for _, f := range t.Fields() {
+               if f.Sym.Name == name {
+                       return f.Offset
+               }
+       }
+       base.Fatalf("couldn't find field %s in %v", name, t)
+       return -1
+}
+
 func (t *Type) NumElem() int64 {
        t.wantEtype(TARRAY)
        return t.extra.(*Array).Bound
index 1aff97d7fd3caf58c336397b5648ed51903762b4..b406f502aa787e9cae0ef0bf1cd9305d84db25e3 100644 (file)
@@ -692,7 +692,7 @@ func typeHashFieldOf(pos src.XPos, itab *ir.UnaryExpr) *ir.SelectorExpr {
        if itab.X.Type().IsEmptyInterface() {
                // runtime._type's hash field
                if rtypeHashField == nil {
-                       rtypeHashField = runtimeField("hash", rttype.Type.Offset("Hash"), types.Types[types.TUINT32])
+                       rtypeHashField = runtimeField("hash", rttype.Type.OffsetOf("Hash"), types.Types[types.TUINT32])
                }
                hashField = rtypeHashField
        } else {
index f2a3001d2ea3757b6dafb66835767a19c164d748..6f1a2d672c430f9f4e3a073d941294d2204f0200 100644 (file)
@@ -21,138 +21,5 @@ func StructFieldSize(ptrSize int) int { return 3 * ptrSize }
 // This exported function is in an internal package, so it may change to depend on ptrSize in the future.
 func UncommonSize() uint64 { return 4 + 2 + 2 + 4 + 4 }
 
-// IMethodSize returns sizeof(IMethod) for a compilation target with a given ptrSize
-func IMethodSize(ptrSize int) int { return 4 + 4 }
-
 // TFlagOff returns the offset of Type.TFlag for a compilation target with a given ptrSize
 func TFlagOff(ptrSize int) int { return 2*ptrSize + 4 }
-
-// Offset is for computing offsets of type data structures at compile/link time;
-// the target platform may not be the host platform.  Its state includes the
-// current offset, necessary alignment for the sequence of types, and the size
-// of pointers and alignment of slices, interfaces, and strings (this is for tearing-
-// resistant access to these types, if/when that is supported).
-type Offset struct {
-       off        uint64 // the current offset
-       align      uint8  // the required alignmentof the container
-       ptrSize    uint8  // the size of a pointer in bytes
-       sliceAlign uint8  // the alignment of slices (and interfaces and strings)
-}
-
-// NewOffset returns a new Offset with offset 0 and alignment 1.
-func NewOffset(ptrSize uint8, twoWordAlignSlices bool) Offset {
-       if twoWordAlignSlices {
-               return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: 2 * ptrSize}
-       }
-       return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: ptrSize}
-}
-
-func assertIsAPowerOfTwo(x uint8) {
-       if x == 0 {
-               panic("Zero is not a power of two")
-       }
-       if x&-x == x {
-               return
-       }
-       panic("Not a power of two")
-}
-
-// InitializedOffset returns a new Offset with specified offset, alignment, pointer size, and slice alignment.
-func InitializedOffset(off int, align uint8, ptrSize uint8, twoWordAlignSlices bool) Offset {
-       assertIsAPowerOfTwo(align)
-       o0 := NewOffset(ptrSize, twoWordAlignSlices)
-       o0.off = uint64(off)
-       o0.align = align
-       return o0
-}
-
-func (o Offset) align_(a uint8) Offset {
-       o.off = (o.off + uint64(a) - 1) & ^(uint64(a) - 1)
-       if o.align < a {
-               o.align = a
-       }
-       return o
-}
-
-// Align returns the offset obtained by aligning offset to a multiple of a.
-// a must be a power of two.
-func (o Offset) Align(a uint8) Offset {
-       assertIsAPowerOfTwo(a)
-       return o.align_(a)
-}
-
-// plus returns the offset obtained by appending a power-of-2-sized-and-aligned object to o.
-func (o Offset) plus(x uint64) Offset {
-       o = o.align_(uint8(x))
-       o.off += x
-       return o
-}
-
-// D8 returns the offset obtained by appending an 8-bit field to o.
-func (o Offset) D8() Offset {
-       return o.plus(1)
-}
-
-// D16 returns the offset obtained by appending a 16-bit field to o.
-func (o Offset) D16() Offset {
-       return o.plus(2)
-}
-
-// D32 returns the offset obtained by appending a 32-bit field to o.
-func (o Offset) D32() Offset {
-       return o.plus(4)
-}
-
-// D64 returns the offset obtained by appending a 64-bit field to o.
-func (o Offset) D64() Offset {
-       return o.plus(8)
-}
-
-// D64 returns the offset obtained by appending a pointer field to o.
-func (o Offset) P() Offset {
-       if o.ptrSize == 0 {
-               panic("This offset has no defined pointer size")
-       }
-       return o.plus(uint64(o.ptrSize))
-}
-
-// Slice returns the offset obtained by appending a slice field to o.
-func (o Offset) Slice() Offset {
-       o = o.align_(o.sliceAlign)
-       o.off += 3 * uint64(o.ptrSize)
-       // There's been discussion of whether slices should be 2-word aligned to allow
-       // use of aligned 2-word load/store to prevent tearing, this is future proofing.
-       // In general, for purposes of struct layout (and very likely default C layout
-       // compatibility) the "size" of a Go type is rounded up to its alignment.
-       return o.Align(o.sliceAlign)
-}
-
-// String returns the offset obtained by appending a string field to o.
-func (o Offset) String() Offset {
-       o = o.align_(o.sliceAlign)
-       o.off += 2 * uint64(o.ptrSize)
-       return o // We "know" it needs no further alignment
-}
-
-// Interface returns the offset obtained by appending an interface field to o.
-func (o Offset) Interface() Offset {
-       o = o.align_(o.sliceAlign)
-       o.off += 2 * uint64(o.ptrSize)
-       return o // We "know" it needs no further alignment
-}
-
-// Offset returns the struct-aligned offset (size) of o.
-// This is at least as large as the current internal offset; it may be larger.
-func (o Offset) Offset() uint64 {
-       return o.Align(o.align).off
-}
-
-func (o Offset) PlusUncommon() Offset {
-       o.off += UncommonSize()
-       return o
-}
-
-// CommonOffset returns the Offset to the data after the common portion of type data structures.
-func CommonOffset(ptrSize int, twoWordAlignSlices bool) Offset {
-       return InitializedOffset(CommonSize(ptrSize), uint8(ptrSize), uint8(ptrSize), twoWordAlignSlices)
-}