)
func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
-func imethodSize() int { return 2 * Widthptr } // Sizeof(runtime.imethod{})
+func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
if t.Sym == nil && len(methods(t)) == 0 {
return 0
pkg = a.pkg
}
nsym := dname(a.name, "", pkg, exported)
- ot = dsymptrLSym(lsym, ot, nsym, 0)
+
+ ot = dsymptrOffLSym(lsym, ot, nsym, 0)
ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype)))
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym))
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
- if Widthptr == 8 {
- ot = duintxxLSym(lsym, ot, 0, 4) // pad to reflect.method size
- }
}
return ot
}
dataAdd := imethodSize() * n
ot = dextratype(s, ot, t, dataAdd)
+ lsym := Linksym(s)
for _, a := range m {
// ../../../../runtime/type.go:/imethod
exported := exportname(a.name)
pkg = a.pkg
}
nsym := dname(a.name, "", pkg, exported)
- ot = dsymptrLSym(Linksym(s), ot, nsym, 0)
- ot = dsymptr(s, ot, dtypesym(a.type_), 0)
+
+ ot = dsymptrOffLSym(lsym, ot, nsym, 0)
+ ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0)
}
// ../../../../runtime/type.go:/mapType
)
// decode_methodsig decodes an array of method signature information.
-// Each element of the array is size bytes. The first word is a
-// reflect.name for the name, the second word is a *rtype for the funcType.
+// Each element of the array is size bytes. The first 4 bytes is a
+// nameOff for the method name, and the next 4 bytes is a typeOff for
+// the function type.
//
// Conveniently this is the layout of both runtime.method and runtime.imethod.
func decode_methodsig(s *LSym, off, size, count int) []methodsig {
var methods []methodsig
for i := 0; i < count; i++ {
buf.WriteString(decodetype_name(s, off))
- mtypSym := decode_reloc_sym(s, int32(off+SysArch.PtrSize))
+ mtypSym := decode_reloc_sym(s, int32(off+4))
buf.WriteRune('(')
inCount := decodetype_funcincount(mtypSym)
}
off := int(r.Add) // array of reflect.imethod values
numMethods := int(decodetype_ifacemethodcount(s))
- sizeofIMethod := 2 * SysArch.PtrSize
+ sizeofIMethod := 4 + 4
return decode_methodsig(s, off, sizeofIMethod, numMethods)
}
mcount := int(decode_inuxi(s.P[off+SysArch.PtrSize:], 2))
moff := int(decode_inuxi(s.P[off+SysArch.PtrSize+2:], 2))
- off += moff // offset to array of reflect.method values
- var sizeofMethod int // sizeof reflect.method in program
- if SysArch.PtrSize == 4 {
- sizeofMethod = 4 * SysArch.PtrSize
- } else {
- sizeofMethod = 3 * SysArch.PtrSize
- }
+ off += moff // offset to array of reflect.method values
+ const sizeofMethod = 4 * 4 // sizeof reflect.method in program
return decode_methodsig(s, off, sizeofMethod, mcount)
}
if !DynlinkingGo() {
s.Attr |= AttrHidden
}
- if UseRelro() && len(s.R) > 0 {
+ if UseRelro() {
s.Type = obj.STYPERELRO
s.Outer = symtyperel
} else {
for i, offs := range offset {
rodata := sections[i]
for _, off := range offs {
- r = append(r, rtypeOff(rodata, off).string)
+ typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off))
+ r = append(r, typ.string)
}
}
return r
panic("type has no methods")
}
m := ut.methods()[0]
- if *m.name.data(0)&(1<<2) == 0 {
+ mname := t.(*rtype).nameOff(m.name)
+ if *mname.data(0)&(1<<2) == 0 {
panic("method name does not have pkgPath *string")
}
- return m.name.bytes
+ return mname.bytes
}
type OtherPkgFields struct {
// Method on non-interface type
type method struct {
- name name // name of method
+ name nameOff // name of method
mtyp typeOff // method type (without receiver)
ifn textOff // fn used in interface call (one-word receiver)
tfn textOff // fn used for normal method call
// imethod represents a method on an interface type
type imethod struct {
- name name // name of method
- typ *rtype // .(*FuncType) underneath
+ name nameOff // name of method
+ typ typeOff // .(*FuncType) underneath
}
// interfaceType represents an interface type.
bytes *byte
}
-func (n *name) data(off int) *byte {
+func (n name) data(off int) *byte {
return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
}
-func (n *name) isExported() bool {
+func (n name) isExported() bool {
return (*n.bytes)&(1<<0) != 0
}
-func (n *name) nameLen() int {
+func (n name) nameLen() int {
return int(uint16(*n.data(1))<<8 | uint16(*n.data(2)))
}
-func (n *name) tagLen() int {
+func (n name) tagLen() int {
if *n.data(0)&(1<<1) == 0 {
return 0
}
return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1)))
}
-func (n *name) name() (s string) {
+func (n name) name() (s string) {
if n.bytes == nil {
return ""
}
return s
}
-func (n *name) tag() (s string) {
+func (n name) tag() (s string) {
tl := n.tagLen()
if tl == 0 {
return ""
return s
}
-func (n *name) pkgPath() string {
+func (n name) pkgPath() string {
if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
return ""
}
}
var nameOff int32
copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
- pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n), nameOff))}
+ pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))}
return pkgPathName.name()
}
return t.pkgPath.name()
}
+// resolveNameOff resolves a name offset from a base pointer.
+// The (*rtype).nameOff method is a convenience wrapper for this function.
+// Implemented in the runtime package.
+func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer
+
// resolveTypeOff resolves an *rtype offset from a base type.
// The (*rtype).typeOff method is a convenience wrapper for this function.
// Implemented in the runtime package.
// be resolved correctly. Implemented in the runtime package.
func addReflectOff(ptr unsafe.Pointer) int32
+// resolveReflectType adds a name to the reflection lookup map in the runtime.
+// It returns a new nameOff that can be used to refer to the pointer.
+func resolveReflectName(n name) nameOff {
+ return nameOff(addReflectOff(unsafe.Pointer(n.bytes)))
+}
+
// resolveReflectType adds a *rtype to the reflection lookup map in the runtime.
// It returns a new typeOff that can be used to refer to the pointer.
func resolveReflectType(t *rtype) typeOff {
return textOff(addReflectOff(ptr))
}
+type nameOff int32 // offset to a name
type typeOff int32 // offset to an *rtype
type textOff int32 // offset from top of text section
+func (t *rtype) nameOff(off nameOff) name {
+ if off == 0 {
+ return name{}
+ }
+ return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
+}
+
func (t *rtype) typeOff(off typeOff) *rtype {
if off == 0 {
return nil
panic("reflect: Method index out of range")
}
p := ut.methods()[i]
- m.Name = p.name.name()
+ pname := t.nameOff(p.name)
+ m.Name = pname.name()
fl := flag(Func)
- if !p.name.isExported() {
- m.PkgPath = p.name.pkgPath()
+ if !pname.isExported() {
+ m.PkgPath = pname.pkgPath()
if m.PkgPath == "" {
m.PkgPath = ut.pkgPath.name()
}
utmethods := ut.methods()
for i := 0; i < int(ut.mcount); i++ {
p := utmethods[i]
- if p.name.name() == name {
+ pname := t.nameOff(p.name)
+ if pname.name() == name {
return t.Method(i), true
}
}
return
}
p := &t.methods[i]
- m.Name = p.name.name()
- if !p.name.isExported() {
- m.PkgPath = p.name.pkgPath()
+ pname := t.nameOff(p.name)
+ m.Name = pname.name()
+ if !pname.isExported() {
+ m.PkgPath = pname.pkgPath()
if m.PkgPath == "" {
m.PkgPath = t.pkgPath.name()
}
}
- m.Type = toType(p.typ)
+ m.Type = toType(t.typeOff(p.typ))
m.Index = i
return
}
var p *imethod
for i := range t.methods {
p = &t.methods[i]
- if p.name.name() == name {
+ if t.nameOff(p.name).name() == name {
return t.Method(i), true
}
}
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
vm := &v.methods[j]
- if vm.name.name() == tm.name.name() && vm.typ == tm.typ {
+ if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
if i++; i >= len(t.methods) {
return true
}
for j := 0; j < int(v.mcount); j++ {
tm := &t.methods[i]
vm := vmethods[j]
- if vm.name.name() == tm.name.name() && V.typeOff(vm.mtyp) == tm.typ {
+ if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
if i++; i >= len(t.methods) {
return true
}
case Interface:
ift := (*interfaceType)(unsafe.Pointer(ft))
for im, m := range ift.methods {
- if m.name.pkgPath() != "" {
+ if ift.nameOff(m.name).pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
var (
+ mtyp = ift.typeOff(m.typ)
ifield = i
imethod = im
ifn Value
)
if ft.kind&kindDirectIface != 0 {
- tfn = MakeFunc(m.typ, func(in []Value) []Value {
+ tfn = MakeFunc(mtyp, func(in []Value) []Value {
var args []Value
var recv = in[0]
if len(in) > 1 {
}
return recv.Field(ifield).Method(imethod).Call(args)
})
- ifn = MakeFunc(m.typ, func(in []Value) []Value {
+ ifn = MakeFunc(mtyp, func(in []Value) []Value {
var args []Value
var recv = in[0]
if len(in) > 1 {
return recv.Field(ifield).Method(imethod).Call(args)
})
} else {
- tfn = MakeFunc(m.typ, func(in []Value) []Value {
+ tfn = MakeFunc(mtyp, func(in []Value) []Value {
var args []Value
var recv = in[0]
if len(in) > 1 {
}
return recv.Field(ifield).Method(imethod).Call(args)
})
- ifn = MakeFunc(m.typ, func(in []Value) []Value {
+ ifn = MakeFunc(mtyp, func(in []Value) []Value {
var args []Value
var recv = Indirect(in[0])
if len(in) > 1 {
}
methods = append(methods, method{
- name: m.name,
- mtyp: resolveReflectType(m.typ),
+ name: resolveReflectName(ift.nameOff(m.name)),
+ mtyp: resolveReflectType(mtyp),
ifn: resolveReflectText(unsafe.Pointer(&ifn)),
tfn: resolveReflectText(unsafe.Pointer(&tfn)),
})
ptr := (*ptrType)(unsafe.Pointer(ft))
if unt := ptr.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != "" {
+ mname := ptr.nameOff(m.name)
+ if mname.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
methods = append(methods, method{
- name: m.name,
+ name: resolveReflectName(mname),
mtyp: resolveReflectType(ptr.typeOff(m.mtyp)),
ifn: resolveReflectText(ptr.textOff(m.ifn)),
tfn: resolveReflectText(ptr.textOff(m.tfn)),
}
if unt := ptr.elem.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != "" {
+ mname := ptr.nameOff(m.name)
+ if mname.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
methods = append(methods, method{
- name: m.name,
+ name: resolveReflectName(mname),
mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)),
ifn: resolveReflectText(ptr.elem.textOff(m.ifn)),
tfn: resolveReflectText(ptr.elem.textOff(m.tfn)),
default:
if unt := ft.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != "" {
+ mname := ft.nameOff(m.name)
+ if mname.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
methods = append(methods, method{
- name: m.name,
+ name: resolveReflectName(mname),
mtyp: resolveReflectType(ft.typeOff(m.mtyp)),
ifn: resolveReflectText(ft.textOff(m.ifn)),
tfn: resolveReflectText(ft.textOff(m.tfn)),
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
- if !m.name.isExported() {
+ if !tt.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
iface := (*nonEmptyInterface)(v.ptr)
}
rcvrtype = iface.itab.typ
fn = unsafe.Pointer(&iface.itab.fun[i])
- t = m.typ
+ t = tt.typeOff(m.typ)
} else {
rcvrtype = v.typ
ut := v.typ.uncommon()
panic("reflect: internal error: invalid method index")
}
m := ut.methods()[i]
- if !m.name.isExported() {
+ if !v.typ.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
ifn := v.typ.textOff(m.ifn)
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
- return m.typ
+ return v.typ.typeOff(m.typ)
}
// Method on concrete type.
ut := v.typ.uncommon()
if canfail {
return nil
}
- panic(&TypeAssertionError{"", typ._string, inter.typ._string, inter.mhdr[0].name.name()})
+ name := inter.typ.nameOff(inter.mhdr[0].name)
+ panic(&TypeAssertionError{"", typ._string, inter.typ._string, name.name()})
}
h := itabhash(inter, typ)
j := 0
for k := 0; k < ni; k++ {
i := &inter.mhdr[k]
- iname := i.name.name()
- itype := i._type
- ipkg := i.name.pkgPath()
+ itype := inter.typ.typeOff(i.ityp)
+ name := inter.typ.nameOff(i.name)
+ iname := name.name()
+ ipkg := name.pkgPath()
if ipkg == "" {
ipkg = inter.pkgpath.name()
}
for ; j < nt; j++ {
t := &xmhdr[j]
- if typ.typeOff(t.mtyp) == itype && t.name.name() == iname {
- pkgPath := t.name.pkgPath()
+ tname := typ.nameOff(t.name)
+ if typ.typeOff(t.mtyp) == itype && tname.name() == iname {
+ pkgPath := tname.pkgPath()
if pkgPath == "" {
pkgPath = x.pkgpath.name()
}
- if t.name.isExported() || pkgPath == ipkg {
+ if tname.isExported() || pkgPath == ipkg {
if m != nil {
ifn := typ.textOff(t.ifn)
*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn
return sections, ret
}
+// reflect_resolveNameOff resolves a name offset from a base pointer.
+//go:linkname reflect_resolveNameOff reflect.resolveNameOff
+func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer {
+ return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes)
+}
+
// reflect_resolveTypeOff resolves an *rtype offset from a base type.
//go:linkname reflect_resolveTypeOff reflect.resolveTypeOff
func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
}
}
if md == nil {
- println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
- for next := &firstmoduledata; next != nil; next = next.next {
- println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
+ lock(&reflectOffs.lock)
+ res, found := reflectOffs.m[int32(off)]
+ unlock(&reflectOffs.lock)
+ if !found {
+ println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
+ for next := &firstmoduledata; next != nil; next = next.next {
+ println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
+ }
+ throw("runtime: name offset base pointer out of range")
}
- throw("runtime: name offset base pointer out of range")
+ return name{(*byte)(res)}
}
res := md.types + uintptr(off)
if res > md.etypes {
return name{(*byte)(unsafe.Pointer(res))}
}
+func (t *_type) nameOff(off nameOff) name {
+ return resolveNameOff(unsafe.Pointer(t), off)
+}
+
func (t *_type) typeOff(off typeOff) *_type {
if off == 0 {
return nil
type textOff int32
type method struct {
- name name
+ name nameOff
mtyp typeOff
ifn textOff
tfn textOff
}
type imethod struct {
- name name
- _type *_type
+ name nameOff
+ ityp typeOff
}
type interfacetype struct {
bytes *byte
}
-func (n *name) data(off int) *byte {
+func (n name) data(off int) *byte {
return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
}
-func (n *name) isExported() bool {
+func (n name) isExported() bool {
return (*n.bytes)&(1<<0) != 0
}
-func (n *name) nameLen() int {
+func (n name) nameLen() int {
return int(uint16(*n.data(1))<<8 | uint16(*n.data(2)))
}
-func (n *name) tagLen() int {
+func (n name) tagLen() int {
if *n.data(0)&(1<<1) == 0 {
return 0
}
return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1)))
}
-func (n *name) name() (s string) {
+func (n name) name() (s string) {
if n.bytes == nil {
return ""
}
return s
}
-func (n *name) tag() (s string) {
+func (n name) tag() (s string) {
tl := n.tagLen()
if tl == 0 {
return ""
return s
}
-func (n *name) pkgPath() string {
+func (n name) pkgPath() string {
if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
return ""
}
for i := range it.mhdr {
tm := &it.mhdr[i]
vm := &iv.mhdr[i]
- if tm.name.name() != vm.name.name() {
+ tname := it.typ.nameOff(tm.name)
+ vname := iv.typ.nameOff(vm.name)
+ if tname.name() != vname.name() {
return false
}
- if tm.name.pkgPath() != vm.name.pkgPath() {
+ if tname.pkgPath() != vname.pkgPath() {
return false
}
- if !typesEqual(tm._type, vm._type) {
+ if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) {
return false
}
}