MAXVALSIZE = 128
)
+func structfieldSize() int { return 5 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int { return 3 * Widthptr } // Sizeof(runtime.imethod{})
+func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
+ if t.Sym == nil && len(methods(t)) == 0 {
+ return 0
+ }
+ return 2*Widthptr + 2*Widthint
+}
+
func makefield(name string, t *Type) *Type {
f := typ(TFIELD)
f.Type = t
return dsymptr(s, ot, pkg.Pathsym, 0)
}
-// uncommonType
-// ../../../../runtime/type.go:/uncommonType
-func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
+// 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(sym *Sym, off int, t *Type, dataAdd int) int {
m := methods(t)
if t.Sym == nil && len(m) == 0 {
return off
}
-
- // fill in *extraType pointer in header
- off = int(Rnd(int64(off), int64(Widthptr)))
-
- dsymptr(sym, ptroff, sym, off)
+ noff := int(Rnd(int64(off), int64(Widthptr)))
+ if noff != off {
+ panic("dextratype rounding does something. :-(")
+ }
+ off = noff
for _, a := range m {
dtypesym(a.type_)
}
// slice header
- ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+ ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd)
n := len(m)
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
- // methods
- for _, a := range m {
+ return ot
+}
+
+// dextratypeData dumps the backing array for the []method field of
+// runtime.uncommontype.
+func dextratypeData(s *Sym, ot int, t *Type) int {
+ for _, a := range methods(t) {
// method
// ../../../../runtime/type.go:/method
ot = dgostringptr(s, ot, a.name)
ot = duintptr(s, ot, 0)
}
}
-
return ot
}
}
}
+// tflag is documented in ../../../../reflect/type.go.
+const tflagUncommon = 1
+
// commonType
-// ../../runtime/type.go:/commonType
+// ../../../../runtime/type.go:/commonType
var dcommontype_algarray *Sym
// size uintptr
// ptrdata uintptr
// hash uint32
- // _ uint8
+ // tflag tflag
// align uint8
// fieldAlign uint8
// kind uint8
// alg *typeAlg
// gcdata *byte
// string *string
- // *uncommonType
// }
ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata))
ot = duint32(s, ot, typehash(t))
- ot = duint8(s, ot, 0) // unused
+
+ var tflag uint8
+ if uncommonSize(t) != 0 {
+ tflag |= tflagUncommon
+ }
+ ot = duint8(s, ot, tflag)
// runtime (and common sense) expects alignment to be a power of two.
i := int(t.Align)
_, symdata := stringsym(p) // string
ot = dsymptr(s, ot, symdata, prefix)
ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint)
- //fmt.Printf("dcommontype: %s\n", p)
-
- // skip pointer to extraType,
- // which follows the rest of this type structure.
- // caller will fill in if needed.
- // otherwise linker will assume 0.
- ot += Widthptr
return ot
}
ok:
ot := 0
- xt := 0
switch t.Etype {
default:
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
+ ot = dextratype(s, ot, t, 0)
case TARRAY:
if t.Bound >= 0 {
t2.Bound = -1 // slice
s2 := dtypesym(t2)
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0)
ot = dsymptr(s, ot, s2, 0)
ot = duintptr(s, ot, uint64(t.Bound))
s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0)
}
+ ot = dextratype(s, ot, t, 0)
// ../../../../runtime/type.go:/chanType
case TCHAN:
s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0)
ot = duintptr(s, ot, uint64(t.Chan))
+ ot = dextratype(s, ot, t, 0)
case TFUNC:
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
}
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
// two slice headers: in and out.
ot = int(Rnd(int64(ot), int64(Widthptr)))
- ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint))
+ ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint)+uncommonSize(t))
n := t.Thistuple + t.Intuple
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
- ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+n*Widthptr)
+ ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+uncommonSize(t)+n*Widthptr)
ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
+ dataAdd := 0
+ for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
+ dataAdd += Widthptr
+ }
+ for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
+ dataAdd += Widthptr
+ }
+ for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
+ dataAdd += Widthptr
+ }
+ ot = dextratype(s, ot, t, dataAdd)
+
// slice data
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
// ../../../../runtime/type.go:/interfaceType
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
- ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+ ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
+ dataAdd := imethodSize() * n
+ ot = dextratype(s, ot, t, dataAdd)
+
for _, a := range m {
// ../../../../runtime/type.go:/imethod
ot = dgostringptr(s, ot, a.name)
-
ot = dgopkgpath(s, ot, a.pkg)
ot = dsymptr(s, ot, dtypesym(a.type_), 0)
}
s3 := dtypesym(mapbucket(t))
s4 := dtypesym(hmap(t))
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0)
ot = dsymptr(s, ot, s2, 0)
ot = dsymptr(s, ot, s3, 0)
ot = duint16(s, ot, uint16(mapbucket(t).Width))
ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
+ ot = dextratype(s, ot, t, 0)
case TPTR32, TPTR64:
if t.Type.Etype == TANY {
// ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(s, ot, t)
+ ot = dextratype(s, ot, t, 0)
break
}
s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0)
+ ot = dextratype(s, ot, t, 0)
// ../../../../runtime/type.go:/structType
// for security, only the exported fields.
}
ot = dcommontype(s, ot, t)
- xt = ot - 1*Widthptr
- ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+ ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
+
+ dataAdd := n * structfieldSize()
+ ot = dextratype(s, ot, t, dataAdd)
+
for t1 := t.Type; t1 != nil; t1 = t1.Down {
- // ../../../../runtime/type.go:/structField
+ // ../../../../runtime/type.go:/structfield
if t1.Sym != nil && t1.Embedded == 0 {
ot = dgostringptr(s, ot, t1.Sym.Name)
if exportname(t1.Sym.Name) {
}
}
- ot = dextratype(s, ot, t, xt)
+ ot = dextratypeData(s, ot, t)
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
// generate typelink.foo pointing at s = type.foo.
}
}
-// commonsize returns the size of the common prefix for all type
-// structures (runtime._type).
-func commonsize() int {
- return 7*Thearch.Ptrsize + 8
-}
+func commonsize() int { return 6*Thearch.Ptrsize + 8 } // runtime._type
+func structfieldSize() int { return 5 * Thearch.Ptrsize } // runtime.structfield
+func uncommonSize() int { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
// Type.commonType.kind
func decodetype_kind(s *LSym) uint8 {
return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
}
+// Type.commonType.tflag
+func decodetype_hasUncommon(s *LSym) bool {
+ const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
+ return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0
+}
+
// Find the elf.Section of a given shared library that contains a given address.
func findShlibSection(path string, addr uint64) *elf.Section {
for _, shlib := range Ctxt.Shlibs {
return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
}
-func structfieldsize() int {
- return 5 * Thearch.Ptrsize
+func decodetype_structfieldarrayoff(s *LSym, i int) int {
+ off := commonsize() + Thearch.Ptrsize + 2*Thearch.Intsize
+ if decodetype_hasUncommon(s) {
+ off += uncommonSize()
+ }
+ off += i * structfieldSize()
+ return off
}
-// Type.StructType.fields[]-> name, typ and offset.
func decodetype_structfieldname(s *LSym, i int) string {
- // go.string."foo" 0x28 / 0x40
- s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
-
+ off := decodetype_structfieldarrayoff(s, i)
+ s = decode_reloc_sym(s, int32(off))
if s == nil { // embedded structs have a nil name.
return ""
}
}
func decodetype_structfieldtype(s *LSym, i int) *LSym {
- return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
+ off := decodetype_structfieldarrayoff(s, i)
+ return decode_reloc_sym(s, int32(off+2*Thearch.Ptrsize))
}
func decodetype_structfieldoffs(s *LSym, i int) int64 {
- return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
+ off := decodetype_structfieldarrayoff(s, i)
+ return int64(decode_inuxi(s.P[off+4*Thearch.Ptrsize:], Thearch.Intsize))
}
// InterfaceType.methods.length
UnsafePointer
)
+// tflag is used by an rtype to signal what extra type information is
+// available in the memory directly following the rtype value.
+type tflag uint8
+
+const (
+ // tflagUncommon means that there is a pointer, *uncommonType,
+ // just beyond the outer type structure.
+ //
+ // For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0,
+ // then t has uncommonType data and it can be accessed as:
+ //
+ // type tUncommon struct {
+ // structType
+ // u uncommonType
+ // }
+ // u := &(*tUncommon)(unsafe.Pointer(t)).u
+ tflagUncommon tflag = 1
+)
+
// rtype is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct {
- size uintptr
- ptrdata uintptr
- hash uint32 // hash of type; avoids computation in hash tables
- _ uint8 // unused/padding
- align uint8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- kind uint8 // enumeration for C
- alg *typeAlg // algorithm table
- gcdata *byte // garbage collection data
- string string // string form; unnecessary but undeniably useful
- *uncommonType // (relatively) uncommon fields
+ size uintptr
+ ptrdata uintptr
+ hash uint32 // hash of type; avoids computation in hash tables
+ tflag tflag // extra type information flags
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ alg *typeAlg // algorithm table
+ gcdata *byte // garbage collection data
+ string string // string form; unnecessary but undeniably useful
}
// a copy of runtime.typeAlg
UnsafePointer: "unsafe.Pointer",
}
-func (t *uncommonType) uncommon() *uncommonType {
- return t
-}
-
func (t *uncommonType) PkgPath() string {
if t == nil || t.pkgPath == nil {
return ""
return *t.pkgPath
}
+func (t *rtype) uncommon() *uncommonType {
+ if t.tflag&tflagUncommon == 0 {
+ return nil
+ }
+ switch t.Kind() {
+ case Struct:
+ type u struct {
+ structType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Ptr:
+ type u struct {
+ ptrType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Func:
+ type u struct {
+ funcType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Slice:
+ type u struct {
+ sliceType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Array:
+ type u struct {
+ arrayType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Chan:
+ type u struct {
+ chanType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Map:
+ type u struct {
+ mapType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ case Interface:
+ type u struct {
+ interfaceType
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ default:
+ type u struct {
+ rtype
+ u uncommonType
+ }
+ return &(*u)(unsafe.Pointer(t)).u
+ }
+}
+
func (t *rtype) String() string { return t.string }
func (t *rtype) Size() uintptr { return t.size }
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod()
}
- return t.uncommonType.NumMethod()
+ return t.uncommon().NumMethod()
}
func (t *rtype) Method(i int) (m Method) {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i)
}
- return t.uncommonType.Method(i)
+ return t.uncommon().Method(i)
}
func (t *rtype) MethodByName(name string) (m Method, ok bool) {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.MethodByName(name)
}
- return t.uncommonType.MethodByName(name)
+ return t.uncommon().MethodByName(name)
}
func (t *rtype) PkgPath() string {
- return t.uncommonType.PkgPath()
+ return t.uncommon().PkgPath()
}
func hasPrefix(s, prefix string) bool {
// old hash and the new "*".
p.hash = fnv1(t.hash, '*')
- p.uncommonType = nil
p.elem = t
ptrMap.m[t] = p
ch.string = s
ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ
- ch.uncommonType = nil
return cachePut(ckey, &ch.rtype)
}
mt.bucketsize = uint16(mt.bucket.size)
mt.reflexivekey = isReflexive(ktyp)
mt.needkeyupdate = needKeyUpdate(ktyp)
- mt.uncommonType = nil
return cachePut(ckey, &mt.rtype)
}
// Populate the remaining fields of ft and store in cache.
ft.string = str
- ft.uncommonType = nil
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
return &ft.rtype
slice.string = s
slice.hash = fnv1(typ.hash, '[')
slice.elem = typ
- slice.uncommonType = nil
return cachePut(ckey, &slice.rtype)
}
}
array.align = typ.align
array.fieldAlign = typ.fieldAlign
- array.uncommonType = nil
array.len = uintptr(count)
array.slice = slice.(*rtype)