}
s := base.Ctxt.Lookup("type..importpath." + p.Prefix + ".")
- ot := dnameData(s, 0, p.Path, "", nil, false)
+ ot := dnameData(s, 0, p.Path, "", nil, false, false)
objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
s.Set(obj.AttrContentAddressable, true)
p.Pathsym = s
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))
+ nsym := dname(ft.Sym.Name, ft.Note, nil, types.IsExported(ft.Sym.Name), ft.Embedded != 0)
return objw.SymPtr(lsym, ot, nsym, 0)
}
// dnameData writes the contents of a reflect.name into s at offset ot.
-func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported bool) int {
+func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported, embedded bool) int {
if len(name) >= 1<<29 {
base.Fatalf("name too long: %d %s...", len(name), name[:1024])
}
if pkg != nil {
bits |= 1 << 2
}
+ if embedded {
+ bits |= 1 << 3
+ }
b := make([]byte, l)
b[0] = bits
copy(b[1:], nameLen[:nameLenLen])
var dnameCount int
// dname creates a reflect.name for a struct field or method.
-func dname(name, tag string, pkg *types.Pkg, exported bool) *obj.LSym {
+func dname(name, tag string, pkg *types.Pkg, exported, embedded bool) *obj.LSym {
// Write out data as "type.." to signal two things to the
// linker, first that when dynamically linking, the symbol
// should be moved to a relro section, and second that the
sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
dnameCount++
}
+ if embedded {
+ sname += ".embedded"
+ }
s := base.Ctxt.Lookup(sname)
if len(s.P) > 0 {
return s
}
- ot := dnameData(s, 0, name, tag, pkg, exported)
+ ot := dnameData(s, 0, name, tag, pkg, exported, embedded)
objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
s.Set(obj.AttrContentAddressable, true)
return s
if !exported && a.name.Pkg != typePkg(t) {
pkg = a.name.Pkg
}
- nsym := dname(a.name.Name, "", pkg, exported)
+ nsym := dname(a.name.Name, "", pkg, exported, false)
ot = objw.SymPtrOff(lsym, ot, nsym)
ot = dmethodptrOff(lsym, ot, writeType(a.mtype))
}
ot = objw.SymPtr(lsym, ot, gcsym, 0) // gcdata
- nsym := dname(p, "", nil, exported)
+ nsym := dname(p, "", nil, exported, false)
ot = objw.SymPtrOff(lsym, ot, nsym) // str
// ptrToThis
if sptr == nil {
if !exported && a.name.Pkg != tpkg {
pkg = a.name.Pkg
}
- nsym := dname(a.name.Name, "", pkg, exported)
+ nsym := dname(a.name.Name, "", pkg, exported, false)
ot = objw.SymPtrOff(lsym, ot, nsym)
ot = objw.SymPtrOff(lsym, ot, writeType(a.type_))
// ../../../../runtime/type.go:/structField
ot = dnameField(lsym, ot, spkg, f)
ot = objw.SymPtr(lsym, ot, writeType(f.Type), 0)
- offsetAnon := uint64(f.Offset) << 1
- if offsetAnon>>1 != uint64(f.Offset) {
- base.Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
- }
- if f.Embedded != 0 {
- offsetAnon |= 1
- }
- ot = objw.Uintptr(lsym, ot, offsetAnon)
+ ot = objw.Uintptr(lsym, ot, uint64(f.Offset))
}
}
// name nameOff
// typ typeOff // pointer to symbol
// }
- nsym := dname(p.Sym().Name, "", nil, true)
+ nsym := dname(p.Sym().Name, "", nil, true, false)
t := p.Type()
if p.Class != ir.PFUNC {
t = types.NewPtr(t)
return string(data[1+nameLenLen : 1+nameLenLen+int(nameLen)])
}
+func decodetypeNameEmbedded(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) bool {
+ r := decodeRelocSym(ldr, symIdx, relocs, int32(off))
+ if r == 0 {
+ return false
+ }
+ data := ldr.Data(r)
+ return data[0]&(1<<3) != 0
+}
+
func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
uadd := commonsize(arch) + 4
if arch.PtrSize == 8 {
return decodeRelocSym(ldr, symIdx, &relocs, int32(off+arch.PtrSize))
}
-func decodetypeStructFieldOffsAnon(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 {
+func decodetypeStructFieldOffset(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 {
off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
data := ldr.Data(symIdx)
return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize))
}
+func decodetypeStructFieldEmbedded(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) bool {
+ off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
+ relocs := ldr.Relocs(symIdx)
+ return decodetypeNameEmbedded(ldr, symIdx, &relocs, off)
+}
+
// decodetypeStr returns the contents of an rtype's str field (a nameOff).
func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string {
relocs := ldr.Relocs(symIdx)
}
fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f)
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
- offsetAnon := decodetypeStructFieldOffsAnon(d.ldr, d.arch, gotype, i)
- newmemberoffsetattr(fld, int32(offsetAnon>>1))
- if offsetAnon&1 != 0 { // is embedded field
+ offset := decodetypeStructFieldOffset(d.ldr, d.arch, gotype, i)
+ newmemberoffsetattr(fld, int32(offset))
+ if decodetypeStructFieldEmbedded(d.ldr, d.arch, gotype, i) {
newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
}
}
// In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still the correct address.
- ptr := add(v.ptr, field.offset(), "same as non-reflect &v.field")
+ ptr := add(v.ptr, field.offset, "same as non-reflect &v.field")
return Value{typ, ptr, fl}
}
// Struct field
type structField struct {
- name name // name is always non-empty
- typ *rtype // type of field
- offsetEmbed uintptr // byte offset of field<<1 | isEmbedded
-}
-
-func (f *structField) offset() uintptr {
- return f.offsetEmbed >> 1
+ name name // name is always non-empty
+ typ *rtype // type of field
+ offset uintptr // byte offset of field
}
func (f *structField) embedded() bool {
- return f.offsetEmbed&1 != 0
+ return f.name.embedded()
}
// structType represents a struct type.
return (*n.bytes)&(1<<1) != 0
}
+func (n name) embedded() bool {
+ return (*n.bytes)&(1<<3) != 0
+}
+
// readVarint parses a varint as encoded by encoding/binary.
// It returns the number of encoded bytes and the encoded value.
func (n name) readVarint(off int) (int, int) {
if cmpTags && tf.name.tag() != vf.name.tag() {
return false
}
- if tf.offsetEmbed != vf.offsetEmbed {
+ if tf.offset != vf.offset {
+ return false
+ }
+ if tf.embedded() != vf.embedded() {
return false
}
}
st := (*structType)(unsafe.Pointer(t))
for i := range st.fields {
f := &st.fields[i]
- if !a.regAssign(f.typ, offset+f.offset()) {
+ if !a.regAssign(f.typ, offset+f.offset) {
return false
}
}
}
func ResolveReflectName(s string) {
- resolveReflectName(newName(s, "", false))
+ resolveReflectName(newName(s, "", false, false))
}
type Buffer struct {
// Struct field
type structField struct {
- name name // name is always non-empty
- typ *rtype // type of field
- offsetEmbed uintptr // byte offset of field<<1 | isEmbedded
-}
-
-func (f *structField) offset() uintptr {
- return f.offsetEmbed >> 1
+ name name // name is always non-empty
+ typ *rtype // type of field
+ offset uintptr // byte offset of field
}
func (f *structField) embedded() bool {
- return f.offsetEmbed&1 != 0
+ return f.name.embedded()
}
// structType represents a struct type.
// 1<<0 the name is exported
// 1<<1 tag data follows the name
// 1<<2 pkgPath nameOff follows the name and tag
+// 1<<3 the name is of an embedded (a.k.a. anonymous) field
//
// Following that, there is a varint-encoded length of the name,
// followed by the name itself.
return (*n.bytes)&(1<<1) != 0
}
+func (n name) embedded() bool {
+ return (*n.bytes)&(1<<3) != 0
+}
+
// readVarint parses a varint as encoded by encoding/binary.
// It returns the number of encoded bytes and the encoded value.
func (n name) readVarint(off int) (int, int) {
return pkgPathName.name()
}
-func newName(n, tag string, exported bool) name {
+func newName(n, tag string, exported, embedded bool) name {
if len(n) >= 1<<29 {
panic("reflect.nameFrom: name too long: " + n[:1024] + "...")
}
l += tagLenLen + len(tag)
bits |= 1 << 1
}
+ if embedded {
+ bits |= 1 << 3
+ }
b := make([]byte, l)
b[0] = bits
if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag)
}
- f.Offset = p.offset()
+ f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface
// presented by a reflect.Type. It would be nice to avoid,
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
pp := *prototype
- pp.str = resolveReflectName(newName(s, "", false))
+ pp.str = resolveReflectName(newName(s, "", false, false))
pp.ptrToThis = 0
// For the type structures linked into the binary, the
if cmpTags && tf.name.tag() != vf.name.tag() {
return false
}
- if tf.offsetEmbed != vf.offsetEmbed {
+ if tf.offset != vf.offset {
+ return false
+ }
+ if tf.embedded() != vf.embedded() {
return false
}
}
ch := *prototype
ch.tflag = tflagRegularMemory
ch.dir = uintptr(dir)
- ch.str = resolveReflectName(newName(s, "", false))
+ ch.str = resolveReflectName(newName(s, "", false, false))
ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap))
- mt.str = resolveReflectName(newName(s, "", false))
+ mt.str = resolveReflectName(newName(s, "", false, false))
mt.tflag = 0
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
mt.key = ktyp
}
// Populate the remaining fields of ft and store in cache.
- ft.str = resolveReflectName(newName(str, "", false))
+ ft.str = resolveReflectName(newName(str, "", false, false))
ft.ptrToThis = 0
return addToCache(&ft.rtype)
}
gcdata: gcdata,
}
s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
- b.str = resolveReflectName(newName(s, "", false))
+ b.str = resolveReflectName(newName(s, "", false, false))
return b
}
prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := *prototype
slice.tflag = 0
- slice.str = resolveReflectName(newName(s, "", false))
+ slice.str = resolveReflectName(newName(s, "", false, false))
slice.hash = fnv1(typ.hash, '[')
slice.elem = typ
slice.ptrToThis = 0
typalign = ft.align
}
size = offset + ft.size
- f.offsetEmbed |= offset << 1
+ f.offset = offset
if ft.size == 0 {
lastzero = size
*typ = *prototype
typ.fields = fs
if pkgpath != "" {
- typ.pkgPath = newName(pkgpath, "", false)
+ typ.pkgPath = newName(pkgpath, "", false, false)
}
// Look in cache.
}
}
- typ.str = resolveReflectName(newName(str, "", false))
+ typ.str = resolveReflectName(newName(str, "", false, false))
typ.tflag = 0 // TODO: set tflagRegularMemory
typ.hash = hash
typ.size = size
continue
}
// Pad to start of this field with zeros.
- if ft.offset() > off {
- n := (ft.offset() - off) / goarch.PtrSize
+ if ft.offset > off {
+ n := (ft.offset - off) / goarch.PtrSize
prog = append(prog, 0x01, 0x00) // emit a 0 bit
if n > 1 {
prog = append(prog, 0x81) // repeat previous bit
prog = appendVarint(prog, n-1) // n-1 times
}
- off = ft.offset()
+ off = ft.offset
}
prog = appendGCProg(prog, ft.typ)
if comparable {
typ.equal = func(p, q unsafe.Pointer) bool {
for _, ft := range typ.fields {
- pi := add(p, ft.offset(), "&x.field safe")
- qi := add(q, ft.offset(), "&x.field safe")
+ pi := add(p, ft.offset, "&x.field safe")
+ qi := add(q, ft.offset, "&x.field safe")
if !ft.typ.equal(pi, qi) {
return false
}
}
}
- offsetEmbed := uintptr(0)
- if field.Anonymous {
- offsetEmbed |= 1
- }
-
resolveReflectType(field.Type.common()) // install in runtime
f := structField{
- name: newName(field.Name, string(field.Tag), field.IsExported()),
- typ: field.Type.common(),
- offsetEmbed: offsetEmbed,
+ name: newName(field.Name, string(field.Tag), field.IsExported(), field.Anonymous),
+ typ: field.Type.common(),
+ offset: 0,
}
return f, field.PkgPath
}
return 0
}
f := st.fields[field]
- return f.offset() + f.typ.ptrdata
+ return f.offset + f.typ.ptrdata
default:
panic("reflect.typeptrdata: unexpected type, " + t.String())
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := *prototype
array.tflag = typ.tflag & tflagRegularMemory
- array.str = resolveReflectName(newName(s, "", false))
+ array.str = resolveReflectName(newName(s, "", false, false))
array.hash = fnv1(typ.hash, '[')
for n := uint32(length); n > 0; n >>= 8 {
array.hash = fnv1(array.hash, byte(n))
} else {
s = "funcargs(" + t.String() + ")"
}
- x.str = resolveReflectName(newName(s, "", false))
+ x.str = resolveReflectName(newName(s, "", false, false))
// cache result for future callers
framePool = &sync.Pool{New: func() any {
tt := (*structType)(unsafe.Pointer(t))
for i := range tt.fields {
f := &tt.fields[i]
- addTypeBits(bv, offset+f.offset(), f.typ)
+ addTypeBits(bv, offset+f.offset, f.typ)
}
}
}
// In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still the correct address.
- ptr := add(v.ptr, field.offset(), "same as non-reflect &v.field")
+ ptr := add(v.ptr, field.offset, "same as non-reflect &v.field")
return Value{typ, ptr, fl}
}
if f.name.isBlank() {
continue
}
- h = typehash(f.typ, add(p, f.offset()), h)
+ h = typehash(f.typ, add(p, f.offset), h)
}
return h
default:
if f.typ.ptrdata == 0 {
continue
}
- cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
+ cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
}
case kindPtr, kindUnsafePointer:
if indir {
st := (*structtype)(unsafe.Pointer(t))
for i := range st.fields {
f := &st.fields[i]
- if !p.tryRegAssignArg(f.typ, offset+f.offset()) {
+ if !p.tryRegAssignArg(f.typ, offset+f.offset) {
return false
}
}
}
type structfield struct {
- name name
- typ *_type
- offsetAnon uintptr
-}
-
-func (f *structfield) offset() uintptr {
- return f.offsetAnon >> 1
+ name name
+ typ *_type
+ offset uintptr
}
type structtype struct {
return (*n.bytes)&(1<<0) != 0
}
+func (n name) isEmbedded() bool {
+ return (*n.bytes)&(1<<3) != 0
+}
+
func (n name) readvarint(off int) (int, int) {
v := 0
for i := 0; ; i++ {
if tf.name.tag() != vf.name.tag() {
return false
}
- if tf.offsetAnon != vf.offsetAnon {
+ if tf.offset != vf.offset {
+ return false
+ }
+ if tf.name.isEmbedded() != vf.name.isEmbedded() {
return false
}
}