aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/reflectdata/reflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/reflect.go')
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go698
1 files changed, 324 insertions, 374 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 6ef40cb84c..c2407af017 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -18,6 +18,8 @@ import (
"cmd/compile/internal/compare"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
+ "cmd/compile/internal/rttype"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typebits"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
@@ -32,10 +34,6 @@ type ptabEntry struct {
t *types.Type
}
-func CountPTabs() int {
- return len(ptabs)
-}
-
// runtime interface and reflection data structures
var (
// protects signatset and signatslice
@@ -47,8 +45,6 @@ var (
gcsymmu sync.Mutex // protects gcsymset and gcsymslice
gcsymset = make(map[*types.Type]struct{})
-
- ptabs []*ir.Name
)
type typeSig struct {
@@ -77,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 abi.CommonSize(types.PtrSize) } // 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 {
@@ -201,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
@@ -217,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
// }
@@ -228,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
@@ -245,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
@@ -280,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]),
@@ -298,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
}
@@ -327,7 +329,7 @@ func methods(t *types.Type) []*typeSig {
// make list of methods for t,
// generating code if necessary.
var ms []*typeSig
- for _, f := range mt.AllMethods().Slice() {
+ for _, f := range mt.AllMethods() {
if f.Sym == nil {
base.Fatalf("method with no sym on %v", mt)
}
@@ -374,7 +376,7 @@ func methods(t *types.Type) []*typeSig {
// imethods returns the methods of the interface type t, sorted by name.
func imethods(t *types.Type) []*typeSig {
var methods []*typeSig
- for _, f := range t.AllMethods().Slice() {
+ for _, f := range t.AllMethods() {
if f.Type.Kind() != types.TFUNC || f.Sym == nil {
continue
}
@@ -410,6 +412,10 @@ func dimportpath(p *types.Pkg) {
return
}
+ if p == types.LocalPkg && base.Ctxt.Pkgpath == "" {
+ panic("missing pkgpath")
+ }
+
// If we are compiling the runtime package, there are two runtime packages around
// -- localpkg and Pkgs.Runtime. We don't want to produce import path symbols for
// both of them, so just produce one for localpkg.
@@ -424,51 +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)
- }
-
- if pkg == types.LocalPkg && base.Ctxt.Pkgpath == "" {
- // If we don't know the full import path of the package being compiled
- // (i.e. -p was not passed on the compiler command line), emit a reference to
- // type:.importpath.""., which the linker will rewrite using the correct import path.
- // Every package that imports this one directly defines the symbol.
- // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
- ns := base.Ctxt.Lookup(`type:.importpath."".`)
- return objw.SymPtr(s, ot, ns, 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)
- }
- if pkg == types.LocalPkg && base.Ctxt.Pkgpath == "" {
- // If we don't know the full import path of the package being compiled
- // (i.e. -p was not passed on the compiler command line), emit a reference to
- // type:.importpath.""., which the linker will rewrite using the correct import path.
- // Every package that imports this one directly defines the symbol.
- // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
- ns := base.Ctxt.Lookup(`type:.importpath."".`)
- return objw.SymPtrOff(s, ot, ns)
+ 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.
@@ -513,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
@@ -544,7 +536,9 @@ func dname(name, tag string, pkg *types.Pkg, exported, embedded bool) *obj.LSym
}
}
} else {
- sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
+ // TODO(mdempsky): We should be able to share these too (except
+ // maybe when dynamic linking).
+ sname = fmt.Sprintf("%s%s.%d", sname, types.LocalPkg.Prefix, dnameCount)
dnameCount++
}
if embedded {
@@ -562,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)
}
@@ -577,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)
@@ -589,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 {
@@ -612,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{
@@ -676,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)
@@ -709,10 +697,9 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
// str nameOff
// ptrToThis typeOff
// }
- ot := 0
- ot = objw.Uintptr(lsym, ot, uint64(t.Size()))
- ot = objw.Uintptr(lsym, ot, uint64(ptrdata))
- ot = objw.Uint32(lsym, ot, 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 {
@@ -748,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")
}
- ot = objw.Uint8(lsym, ot, 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()))
@@ -759,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)
}
- ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // align
- ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // fieldAlign
+ c.Field("Align_").WriteUint8(uint8(t.Alignment()))
+ c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))
i = kinds[t.Kind()]
if types.IsDirectIface(t) {
@@ -769,26 +756,14 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
if useGCProg {
i |= objabi.KindGCProg
}
- ot = objw.Uint8(lsym, ot, uint8(i)) // kind
- if eqfunc != nil {
- ot = objw.SymPtr(lsym, ot, eqfunc, 0) // equality function
- } else {
- ot = objw.Uintptr(lsym, ot, 0) // type we can't do == with
- }
- ot = objw.SymPtr(lsym, ot, gcsym, 0) // gcdata
+ c.Field("Kind_").WriteUint8(uint8(i))
- nsym := dname(p, "", nil, exported, false)
- ot = objw.SymPtrOff(lsym, ot, nsym) // str
- // ptrToThis
- if sptr == nil {
- ot = objw.Uint32(lsym, ot, 0)
- } else if sptrWeak {
- ot = objw.SymPtrWeakOff(lsym, ot, sptr)
- } else {
- ot = objw.SymPtrOff(lsym, ot, sptr)
- }
+ c.Field("Equal").WritePtr(eqfunc)
+ c.Field("GCData").WritePtr(gcsym)
- return ot
+ nsym := dname(p, "", nil, exported, false)
+ c.Field("Str").WriteSymPtrOff(nsym, false)
+ c.Field("PtrToThis").WriteSymPtrOff(sptr, sptrWeak)
}
// TrackSym returns the symbol for tracking use of field/method f, assumed
@@ -845,11 +820,6 @@ func TypeLinksym(t *types.Type) *obj.LSym {
return lsym
}
-// Deprecated: Use TypePtrAt instead.
-func TypePtr(t *types.Type) *ir.AddrExpr {
- return TypePtrAt(base.Pos, t)
-}
-
// TypePtrAt returns an expression that evaluates to the
// *runtime._type value for t.
func TypePtrAt(pos src.XPos, t *types.Type) *ir.AddrExpr {
@@ -873,11 +843,6 @@ func ITabLsym(typ, iface *types.Type) *obj.LSym {
return lsym
}
-// Deprecated: Use ITabAddrAt instead.
-func ITabAddr(typ, iface *types.Type) *ir.AddrExpr {
- return ITabAddrAt(base.Pos, typ, iface)
-}
-
// ITabAddrAt returns an expression that evaluates to the
// *runtime.itab value for concrete type typ implementing interface
// iface.
@@ -909,7 +874,7 @@ func needkeyupdate(t *types.Type) bool {
return needkeyupdate(t.Elem())
case types.TSTRUCT:
- for _, t1 := range t.Fields().Slice() {
+ for _, t1 := range t.Fields() {
if needkeyupdate(t1.Type) {
return true
}
@@ -932,7 +897,7 @@ func hashMightPanic(t *types.Type) bool {
return hashMightPanic(t.Elem())
case types.TSTRUCT:
- for _, t1 := range t.Fields().Slice() {
+ for _, t1 := range t.Fields() {
if hashMightPanic(t1.Type) {
return true
}
@@ -963,16 +928,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()
}
@@ -980,6 +940,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
@@ -994,101 +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:
- for _, t1 := range t.Recvs().Fields().Slice() {
- writeType(t1.Type)
- }
- isddd := false
- for _, t1 := range t.Params().Fields().Slice() {
- isddd = t1.IsDDD()
- writeType(t1.Type)
- }
- for _, t1 := range t.Results().Fields().Slice() {
+ // internal/abi.FuncType
+ for _, t1 := range t.RecvParamsResults() {
writeType(t1.Type)
}
-
- ot = dcommontype(lsym, t)
inCount := t.NumRecvs() + t.NumParams()
outCount := t.NumResults()
- if isddd {
+ 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.Recvs().Fields().Slice() {
- ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
- }
- for _, t1 := range t.Params().Fields().Slice() {
- ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
- }
- for _, t1 := range t.Results().Fields().Slice() {
- 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)
-
- 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)
+ dgopkgpath(c.Field("PkgPath"), tpkg)
+ c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))
- 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 {
@@ -1096,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
}
@@ -1138,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
@@ -1151,25 +1160,17 @@ 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:
- fields := t.Fields().Slice()
+ // internal/abi.StructType
+ fields := t.Fields()
for _, t1 := range fields {
writeType(t1.Type)
}
@@ -1187,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)))
+ dgopkgpath(c.Field("PkgPath"), spkg)
+ c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))
- dataAdd := len(fields) * structfieldSize()
- ot = dextratype(lsym, ot, t, dataAdd)
-
- 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,
@@ -1213,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.
@@ -1224,7 +1224,7 @@ func writeType(t *types.Type) *obj.LSym {
keep := base.Ctxt.Flag_dynlink
if !keep && t.Sym() == nil {
// For an unnamed type, we only need the link if the type can
- // be created at run time by reflect.PtrTo and similar
+ // be created at run time by reflect.PointerTo and similar
// functions. If the type exists in the program, those
// functions must return the existing type structure rather
// than creating a new one.
@@ -1280,7 +1280,9 @@ func WriteRuntimeTypes() {
}
signatslice = signatslice[len(signats):]
}
+}
+func WriteGCSymbols() {
// Emit GC data symbols.
gcsyms := make([]typeAndStr, 0, len(gcsymset))
for t := range gcsymset {
@@ -1305,7 +1307,7 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
base.Fatalf("writeITab(%v, %v)", typ, iface)
}
- sigs := iface.AllMethods().Slice()
+ sigs := iface.AllMethods()
entries := make([]*obj.LSym, 0, len(sigs))
// both sigs and methods are sorted by name,
@@ -1352,58 +1354,52 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
lsym.Set(obj.AttrContentAddressable, true)
}
-func WriteTabs() {
- // process ptabs
- if types.LocalPkg.Name == "main" && len(ptabs) > 0 {
- ot := 0
- s := base.Ctxt.Lookup("go:plugin.tabs")
- for _, p := range ptabs {
- // Dump ptab symbol into go.pluginsym package.
- //
- // type ptab struct {
- // name nameOff
- // typ typeOff // pointer to symbol
- // }
- nsym := dname(p.Sym().Name, "", nil, true, false)
- t := p.Type()
- if p.Class != ir.PFUNC {
- t = types.NewPtr(t)
- }
- tsym := writeType(t)
- ot = objw.SymPtrOff(s, ot, nsym)
- ot = objw.SymPtrOff(s, ot, tsym)
- // Plugin exports symbols as interfaces. Mark their types
- // as UsedInIface.
- tsym.Set(obj.AttrUsedInIface, true)
- }
- objw.Global(s, int32(ot), int16(obj.RODATA))
+func WritePluginTable() {
+ ptabs := typecheck.Target.PluginExports
+ if len(ptabs) == 0 {
+ return
+ }
- ot = 0
- s = base.Ctxt.Lookup("go:plugin.exports")
- for _, p := range ptabs {
- ot = objw.SymPtr(s, ot, p.Linksym(), 0)
+ lsym := base.Ctxt.Lookup("go:plugin.tabs")
+ ot := 0
+ for _, p := range ptabs {
+ // Dump ptab symbol into go.pluginsym package.
+ //
+ // type ptab struct {
+ // name nameOff
+ // typ typeOff // pointer to symbol
+ // }
+ nsym := dname(p.Sym().Name, "", nil, true, false)
+ t := p.Type()
+ if p.Class != ir.PFUNC {
+ t = types.NewPtr(t)
}
- objw.Global(s, int32(ot), int16(obj.RODATA))
+ tsym := writeType(t)
+ ot = objw.SymPtrOff(lsym, ot, nsym)
+ ot = objw.SymPtrOff(lsym, ot, tsym)
+ // Plugin exports symbols as interfaces. Mark their types
+ // as UsedInIface.
+ tsym.Set(obj.AttrUsedInIface, true)
}
-}
+ objw.Global(lsym, int32(ot), int16(obj.RODATA))
-func WriteImportStrings() {
- // generate import strings for imported packages
- for _, p := range types.ImportedPkgList() {
- dimportpath(p)
+ lsym = base.Ctxt.Lookup("go:plugin.exports")
+ ot = 0
+ for _, p := range ptabs {
+ ot = objw.SymPtr(lsym, ot, p.Linksym(), 0)
}
+ objw.Global(lsym, int32(ot), int16(obj.RODATA))
}
// writtenByWriteBasicTypes reports whether typ is written by WriteBasicTypes.
// WriteBasicTypes always writes pointer types; any pointer has been stripped off typ already.
func writtenByWriteBasicTypes(typ *types.Type) bool {
if typ.Sym() == nil && typ.Kind() == types.TFUNC {
- f := typ.FuncType()
// func(error) string
- if f.Receiver.NumFields() == 0 &&
- f.Params.NumFields() == 1 && f.Results.NumFields() == 1 &&
- f.Params.FieldType(0) == types.ErrorType &&
- f.Results.FieldType(0) == types.Types[types.TSTRING] {
+ if typ.NumRecvs() == 0 &&
+ typ.NumParams() == 1 && typ.NumResults() == 1 &&
+ typ.Param(0).Type == types.ErrorType &&
+ typ.Result(0).Type == types.Types[types.TSTRING] {
return true
}
}
@@ -1431,45 +1427,32 @@ func WriteBasicTypes() {
// another possible choice would be package main,
// but using runtime means fewer copies in object files.
// The code here needs to be in sync with writtenByWriteBasicTypes above.
- if base.Ctxt.Pkgpath == "runtime" {
- // Note: always write NewPtr(t) because NeedEmit's caller strips the pointer.
- var list []*types.Type
- for i := types.Kind(1); i <= types.TBOOL; i++ {
- list = append(list, types.Types[i])
- }
- list = append(list,
- types.Types[types.TSTRING],
- types.Types[types.TUNSAFEPTR],
- types.AnyType,
- types.ErrorType)
- for _, t := range list {
- writeType(types.NewPtr(t))
- writeType(types.NewPtr(types.NewSlice(t)))
- }
-
- // emit type for func(error) string,
- // which is the type of an auto-generated wrapper.
- writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{
- types.NewField(base.Pos, nil, types.ErrorType),
- }, []*types.Field{
- types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
- })))
-
- // add paths for runtime and main, which 6l imports implicitly.
- dimportpath(ir.Pkgs.Runtime)
-
- if base.Flag.Race {
- dimportpath(types.NewPkg("runtime/race", ""))
- }
- if base.Flag.MSan {
- dimportpath(types.NewPkg("runtime/msan", ""))
- }
- if base.Flag.ASan {
- dimportpath(types.NewPkg("runtime/asan", ""))
- }
+ if base.Ctxt.Pkgpath != "runtime" {
+ return
+ }
- dimportpath(types.NewPkg("main", ""))
+ // Note: always write NewPtr(t) because NeedEmit's caller strips the pointer.
+ var list []*types.Type
+ for i := types.Kind(1); i <= types.TBOOL; i++ {
+ list = append(list, types.Types[i])
+ }
+ list = append(list,
+ types.Types[types.TSTRING],
+ types.Types[types.TUNSAFEPTR],
+ types.AnyType,
+ types.ErrorType)
+ for _, t := range list {
+ writeType(types.NewPtr(t))
+ writeType(types.NewPtr(types.NewSlice(t)))
}
+
+ // emit type for func(error) string,
+ // which is the type of an auto-generated wrapper.
+ writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{
+ types.NewField(base.Pos, nil, types.ErrorType),
+ }, []*types.Field{
+ types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
+ })))
}
type typeAndStr struct {
@@ -1509,8 +1492,8 @@ func (a typesByString) Less(i, j int) bool {
// will be equal for the above checks, but different in DWARF output.
// Sort by source position to ensure deterministic order.
// See issues 27013 and 30202.
- if a[i].t.Kind() == types.TINTER && a[i].t.AllMethods().Len() > 0 {
- return a[i].t.AllMethods().Index(0).Pos.Before(a[j].t.AllMethods().Index(0).Pos)
+ if a[i].t.Kind() == types.TINTER && len(a[i].t.AllMethods()) > 0 {
+ return a[i].t.AllMethods()[0].Pos.Before(a[j].t.AllMethods()[0].Pos)
}
return false
}
@@ -1734,7 +1717,7 @@ func (p *gcProg) emit(t *types.Type, offset int64) {
p.w.Repeat(elem.Size()/int64(types.PtrSize), count-1)
case types.TSTRUCT:
- for _, t1 := range t.Fields().Slice() {
+ for _, t1 := range t.Fields() {
p.emit(t1.Type, offset+t1.Offset)
}
}
@@ -1754,30 +1737,6 @@ func ZeroAddr(size int64) ir.Node {
return typecheck.Expr(typecheck.NodAddr(x))
}
-func CollectPTabs() {
- if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
- return
- }
- for _, exportn := range typecheck.Target.Exports {
- s := exportn.Sym()
- nn := ir.AsNode(s.Def)
- if nn == nil {
- continue
- }
- if nn.Op() != ir.ONAME {
- continue
- }
- n := nn.(*ir.Name)
- if !types.IsExported(s.Name) {
- continue
- }
- if s.Pkg.Name != "main" {
- continue
- }
- ptabs = append(ptabs, n)
- }
-}
-
// NeedEmit reports whether typ is a type that we need to emit code
// for (e.g., runtime type descriptors, method wrappers).
func NeedEmit(typ *types.Type) bool {
@@ -1893,7 +1852,7 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
if ir.CurFunc.LSym == nil {
return
}
- dot := n.X.(*ir.SelectorExpr)
+ dot := n.Fun.(*ir.SelectorExpr)
ityp := dot.X.Type()
if ityp.HasShape() {
// Here we're calling a method on a generic interface. Something like:
@@ -1916,17 +1875,8 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
// some sort of fuzzy shape matching. For now, only use the name
// of the method for matching.
r := obj.Addrel(ir.CurFunc.LSym)
- // We use a separate symbol just to tell the linker the method name.
- // (The symbol itself is not needed in the final binary. Do not use
- // staticdata.StringSym, which creates a content addessable symbol,
- // which may have trailing zero bytes. This symbol doesn't need to
- // be deduplicated anyway.)
- name := dot.Sel.Name
- var nameSym obj.LSym
- nameSym.WriteString(base.Ctxt, 0, len(name), name)
- objw.Global(&nameSym, int32(len(name)), obj.RODATA)
- r.Sym = &nameSym
- r.Type = objabi.R_USEGENERICIFACEMETHOD
+ r.Sym = staticdata.StringSymNoCommon(dot.Sel.Name)
+ r.Type = objabi.R_USENAMEDMETHOD
return
}