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 {
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.
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
// 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)
}
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)
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 {
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{
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)
// 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 {
// 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()))
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) {
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
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 {
}
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
}
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
}
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)
}
}
- 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,
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.
"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,
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
// 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:
// 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:
}
}
-// 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}
}
// 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)
-}