mirror of
https://github.com/golang/go
synced 2024-11-23 02:10:03 -07:00
cmd/compile: reorganize compiler type descriptor generation
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>
This commit is contained in:
parent
9162c4be9c
commit
2d9e8ded94
@ -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:
|
||||
// ../../../../runtime/type.go:/arrayType
|
||||
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:
|
||||
// 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)))
|
||||
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,
|
||||
@ -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.
|
||||
|
@ -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
|
||||
// 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) Size() int64 {
|
||||
return r.t.Size()
|
||||
// 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}
|
||||
}
|
||||
|
||||
func (r *RuntimeType) Alignment() int64 {
|
||||
return r.t.Alignment()
|
||||
}
|
||||
|
||||
func (r *RuntimeType) Offset(name string) int64 {
|
||||
return r.components[name].offset
|
||||
}
|
||||
|
||||
// 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 (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) WriteUintptr(val uint64) {
|
||||
if c.typ.Kind() != types.TUINTPTR {
|
||||
base.Fatalf("can't write uintptr, it has kind %s", c.typ.Kind())
|
||||
}
|
||||
objw.Uintptr(lsym, int(loc.offset), val)
|
||||
objw.Uintptr(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) WriteUint32(val uint32) {
|
||||
if c.typ.Kind() != types.TUINT32 {
|
||||
base.Fatalf("can't write uint32, it has kind %s", c.typ.Kind())
|
||||
}
|
||||
objw.Uint32(lsym, int(loc.offset), val)
|
||||
objw.Uint32(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) WriteUint16(val uint16) {
|
||||
if c.typ.Kind() != types.TUINT16 {
|
||||
base.Fatalf("can't write uint16, it has kind %s", c.typ.Kind())
|
||||
}
|
||||
objw.Uint8(lsym, int(loc.offset), val)
|
||||
objw.Uint16(c.lsym, int(c.offset), 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) WriteUint8(val uint8) {
|
||||
if c.typ.Kind() != types.TUINT8 {
|
||||
base.Fatalf("can't write uint8, it has kind %s", c.typ.Kind())
|
||||
}
|
||||
objw.Uint8(c.lsym, int(c.offset), val)
|
||||
}
|
||||
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.Uintptr(c.lsym, int(c.offset), uint64(val))
|
||||
}
|
||||
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}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user