cmd/compile,runtime,reflect: move embedded bit from offset to name

Previously we stole a bit from the field offset to encode whether
a struct field was embedded.

Instead, encode that bit in the name field, where we already have
some unused bits to play with. The bit associates naturally with
the name in any case.

This leaves a full uintptr to specify field offsets. This will make
the fix for #52740 cleaner.

Change-Id: I0bfb85564dc26e8c18101bc8b432f332176d7836
Reviewed-on: https://go-review.googlesource.com/c/go/+/412138
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Keith Randall 2022-06-14 13:38:02 -07:00 committed by Keith Randall
parent cb9bf93078
commit e1e66a03a6
13 changed files with 104 additions and 82 deletions

View File

@ -412,7 +412,7 @@ func dimportpath(p *types.Pkg) {
} }
s := base.Ctxt.Lookup("type..importpath." + p.Prefix + ".") 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) objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
s.Set(obj.AttrContentAddressable, true) s.Set(obj.AttrContentAddressable, true)
p.Pathsym = s p.Pathsym = s
@ -461,12 +461,12 @@ func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int {
if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg { if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg {
base.Fatalf("package mismatch for %v", ft.Sym) 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) return objw.SymPtr(lsym, ot, nsym, 0)
} }
// dnameData writes the contents of a reflect.name into s at offset ot. // 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 { if len(name) >= 1<<29 {
base.Fatalf("name too long: %d %s...", len(name), name[:1024]) base.Fatalf("name too long: %d %s...", len(name), name[:1024])
} }
@ -491,6 +491,9 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported b
if pkg != nil { if pkg != nil {
bits |= 1 << 2 bits |= 1 << 2
} }
if embedded {
bits |= 1 << 3
}
b := make([]byte, l) b := make([]byte, l)
b[0] = bits b[0] = bits
copy(b[1:], nameLen[:nameLenLen]) copy(b[1:], nameLen[:nameLenLen])
@ -513,7 +516,7 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported b
var dnameCount int var dnameCount int
// dname creates a reflect.name for a struct field or method. // 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 // Write out data as "type.." to signal two things to the
// linker, first that when dynamically linking, the symbol // linker, first that when dynamically linking, the symbol
// should be moved to a relro section, and second that the // should be moved to a relro section, and second that the
@ -538,11 +541,14 @@ func dname(name, tag string, pkg *types.Pkg, exported bool) *obj.LSym {
sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount) sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
dnameCount++ dnameCount++
} }
if embedded {
sname += ".embedded"
}
s := base.Ctxt.Lookup(sname) s := base.Ctxt.Lookup(sname)
if len(s.P) > 0 { if len(s.P) > 0 {
return s 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) objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
s.Set(obj.AttrContentAddressable, true) s.Set(obj.AttrContentAddressable, true)
return s return s
@ -610,7 +616,7 @@ func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
if !exported && a.name.Pkg != typePkg(t) { if !exported && a.name.Pkg != typePkg(t) {
pkg = a.name.Pkg 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, nsym)
ot = dmethodptrOff(lsym, ot, writeType(a.mtype)) ot = dmethodptrOff(lsym, ot, writeType(a.mtype))
@ -775,7 +781,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
} }
ot = objw.SymPtr(lsym, ot, gcsym, 0) // gcdata 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 ot = objw.SymPtrOff(lsym, ot, nsym) // str
// ptrToThis // ptrToThis
if sptr == nil { if sptr == nil {
@ -1074,7 +1080,7 @@ func writeType(t *types.Type) *obj.LSym {
if !exported && a.name.Pkg != tpkg { if !exported && a.name.Pkg != tpkg {
pkg = a.name.Pkg 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, nsym)
ot = objw.SymPtrOff(lsym, ot, writeType(a.type_)) ot = objw.SymPtrOff(lsym, ot, writeType(a.type_))
@ -1180,14 +1186,7 @@ func writeType(t *types.Type) *obj.LSym {
// ../../../../runtime/type.go:/structField // ../../../../runtime/type.go:/structField
ot = dnameField(lsym, ot, spkg, f) ot = dnameField(lsym, ot, spkg, f)
ot = objw.SymPtr(lsym, ot, writeType(f.Type), 0) ot = objw.SymPtr(lsym, ot, writeType(f.Type), 0)
offsetAnon := uint64(f.Offset) << 1 ot = objw.Uintptr(lsym, ot, uint64(f.Offset))
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)
} }
} }
@ -1356,7 +1355,7 @@ func WriteTabs() {
// name nameOff // name nameOff
// typ typeOff // pointer to symbol // typ typeOff // pointer to symbol
// } // }
nsym := dname(p.Sym().Name, "", nil, true) nsym := dname(p.Sym().Name, "", nil, true, false)
t := p.Type() t := p.Type()
if p.Class != ir.PFUNC { if p.Class != ir.PFUNC {
t = types.NewPtr(t) t = types.NewPtr(t)

View File

@ -132,6 +132,15 @@ func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs
return string(data[1+nameLenLen : 1+nameLenLen+int(nameLen)]) 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 { func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
uadd := commonsize(arch) + 4 uadd := commonsize(arch) + 4
if arch.PtrSize == 8 { if arch.PtrSize == 8 {
@ -204,12 +213,18 @@ func decodetypeStructFieldType(ldr *loader.Loader, arch *sys.Arch, symIdx loader
return decodeRelocSym(ldr, symIdx, &relocs, int32(off+arch.PtrSize)) 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) off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
data := ldr.Data(symIdx) data := ldr.Data(symIdx)
return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize)) 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). // decodetypeStr returns the contents of an rtype's str field (a nameOff).
func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string { func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string {
relocs := ldr.Relocs(symIdx) relocs := ldr.Relocs(symIdx)

View File

@ -682,9 +682,9 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
} }
fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f) fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f)
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s)) d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
offsetAnon := decodetypeStructFieldOffsAnon(d.ldr, d.arch, gotype, i) offset := decodetypeStructFieldOffset(d.ldr, d.arch, gotype, i)
newmemberoffsetattr(fld, int32(offsetAnon>>1)) newmemberoffsetattr(fld, int32(offset))
if offsetAnon&1 != 0 { // is embedded field if decodetypeStructFieldEmbedded(d.ldr, d.arch, gotype, i) {
newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0) newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
} }
} }

View File

@ -36,7 +36,7 @@ func Field(v Value, i int) Value {
// In the former case, we want v.ptr + offset. // In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0, // In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still the correct address. // 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} return Value{typ, ptr, fl}
} }

View File

@ -269,17 +269,13 @@ type sliceType struct {
// Struct field // Struct field
type structField struct { type structField struct {
name name // name is always non-empty name name // name is always non-empty
typ *rtype // type of field typ *rtype // type of field
offsetEmbed uintptr // byte offset of field<<1 | isEmbedded offset uintptr // byte offset of field
}
func (f *structField) offset() uintptr {
return f.offsetEmbed >> 1
} }
func (f *structField) embedded() bool { func (f *structField) embedded() bool {
return f.offsetEmbed&1 != 0 return f.name.embedded()
} }
// structType represents a struct type. // structType represents a struct type.
@ -328,6 +324,10 @@ func (n name) hasTag() bool {
return (*n.bytes)&(1<<1) != 0 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. // readVarint parses a varint as encoded by encoding/binary.
// It returns the number of encoded bytes and the encoded value. // It returns the number of encoded bytes and the encoded value.
func (n name) readVarint(off int) (int, int) { func (n name) readVarint(off int) (int, int) {
@ -947,7 +947,10 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if cmpTags && tf.name.tag() != vf.name.tag() { if cmpTags && tf.name.tag() != vf.name.tag() {
return false return false
} }
if tf.offsetEmbed != vf.offsetEmbed { if tf.offset != vf.offset {
return false
}
if tf.embedded() != vf.embedded() {
return false return false
} }
} }

View File

@ -237,7 +237,7 @@ func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool {
st := (*structType)(unsafe.Pointer(t)) st := (*structType)(unsafe.Pointer(t))
for i := range st.fields { for i := range st.fields {
f := &st.fields[i] f := &st.fields[i]
if !a.regAssign(f.typ, offset+f.offset()) { if !a.regAssign(f.typ, offset+f.offset) {
return false return false
} }
} }

View File

@ -140,7 +140,7 @@ func IsExported(t Type) bool {
} }
func ResolveReflectName(s string) { func ResolveReflectName(s string) {
resolveReflectName(newName(s, "", false)) resolveReflectName(newName(s, "", false, false))
} }
type Buffer struct { type Buffer struct {

View File

@ -433,17 +433,13 @@ type sliceType struct {
// Struct field // Struct field
type structField struct { type structField struct {
name name // name is always non-empty name name // name is always non-empty
typ *rtype // type of field typ *rtype // type of field
offsetEmbed uintptr // byte offset of field<<1 | isEmbedded offset uintptr // byte offset of field
}
func (f *structField) offset() uintptr {
return f.offsetEmbed >> 1
} }
func (f *structField) embedded() bool { func (f *structField) embedded() bool {
return f.offsetEmbed&1 != 0 return f.name.embedded()
} }
// structType represents a struct type. // structType represents a struct type.
@ -460,6 +456,7 @@ type structType struct {
// 1<<0 the name is exported // 1<<0 the name is exported
// 1<<1 tag data follows the name // 1<<1 tag data follows the name
// 1<<2 pkgPath nameOff follows the name and tag // 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, // Following that, there is a varint-encoded length of the name,
// followed by the name itself. // followed by the name itself.
@ -496,6 +493,10 @@ func (n name) hasTag() bool {
return (*n.bytes)&(1<<1) != 0 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. // readVarint parses a varint as encoded by encoding/binary.
// It returns the number of encoded bytes and the encoded value. // It returns the number of encoded bytes and the encoded value.
func (n name) readVarint(off int) (int, int) { func (n name) readVarint(off int) (int, int) {
@ -565,7 +566,7 @@ func (n name) pkgPath() string {
return pkgPathName.name() 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 { if len(n) >= 1<<29 {
panic("reflect.nameFrom: name too long: " + n[:1024] + "...") panic("reflect.nameFrom: name too long: " + n[:1024] + "...")
} }
@ -586,6 +587,9 @@ func newName(n, tag string, exported bool) name {
l += tagLenLen + len(tag) l += tagLenLen + len(tag)
bits |= 1 << 1 bits |= 1 << 1
} }
if embedded {
bits |= 1 << 3
}
b := make([]byte, l) b := make([]byte, l)
b[0] = bits b[0] = bits
@ -1256,7 +1260,7 @@ func (t *structType) Field(i int) (f StructField) {
if tag := p.name.tag(); tag != "" { if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag) f.Tag = StructTag(tag)
} }
f.Offset = p.offset() f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface // NOTE(rsc): This is the only allocation in the interface
// presented by a reflect.Type. It would be nice to avoid, // presented by a reflect.Type. It would be nice to avoid,
@ -1472,7 +1476,7 @@ func (t *rtype) ptrTo() *rtype {
prototype := *(**ptrType)(unsafe.Pointer(&iptr)) prototype := *(**ptrType)(unsafe.Pointer(&iptr))
pp := *prototype pp := *prototype
pp.str = resolveReflectName(newName(s, "", false)) pp.str = resolveReflectName(newName(s, "", false, false))
pp.ptrToThis = 0 pp.ptrToThis = 0
// For the type structures linked into the binary, the // For the type structures linked into the binary, the
@ -1739,7 +1743,10 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if cmpTags && tf.name.tag() != vf.name.tag() { if cmpTags && tf.name.tag() != vf.name.tag() {
return false return false
} }
if tf.offsetEmbed != vf.offsetEmbed { if tf.offset != vf.offset {
return false
}
if tf.embedded() != vf.embedded() {
return false return false
} }
} }
@ -1891,7 +1898,7 @@ func ChanOf(dir ChanDir, t Type) Type {
ch := *prototype ch := *prototype
ch.tflag = tflagRegularMemory ch.tflag = tflagRegularMemory
ch.dir = uintptr(dir) 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.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ ch.elem = typ
@ -1934,7 +1941,7 @@ func MapOf(key, elem Type) Type {
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType. // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil) var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap)) mt := **(**mapType)(unsafe.Pointer(&imap))
mt.str = resolveReflectName(newName(s, "", false)) mt.str = resolveReflectName(newName(s, "", false, false))
mt.tflag = 0 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.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
mt.key = ktyp mt.key = ktyp
@ -2113,7 +2120,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
} }
// Populate the remaining fields of ft and store in cache. // 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 ft.ptrToThis = 0
return addToCache(&ft.rtype) return addToCache(&ft.rtype)
} }
@ -2290,7 +2297,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
gcdata: gcdata, gcdata: gcdata,
} }
s := "bucket(" + ktyp.String() + "," + etyp.String() + ")" s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
b.str = resolveReflectName(newName(s, "", false)) b.str = resolveReflectName(newName(s, "", false, false))
return b return b
} }
@ -2369,7 +2376,7 @@ func SliceOf(t Type) Type {
prototype := *(**sliceType)(unsafe.Pointer(&islice)) prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := *prototype slice := *prototype
slice.tflag = 0 slice.tflag = 0
slice.str = resolveReflectName(newName(s, "", false)) slice.str = resolveReflectName(newName(s, "", false, false))
slice.hash = fnv1(typ.hash, '[') slice.hash = fnv1(typ.hash, '[')
slice.elem = typ slice.elem = typ
slice.ptrToThis = 0 slice.ptrToThis = 0
@ -2632,7 +2639,7 @@ func StructOf(fields []StructField) Type {
typalign = ft.align typalign = ft.align
} }
size = offset + ft.size size = offset + ft.size
f.offsetEmbed |= offset << 1 f.offset = offset
if ft.size == 0 { if ft.size == 0 {
lastzero = size lastzero = size
@ -2698,7 +2705,7 @@ func StructOf(fields []StructField) Type {
*typ = *prototype *typ = *prototype
typ.fields = fs typ.fields = fs
if pkgpath != "" { if pkgpath != "" {
typ.pkgPath = newName(pkgpath, "", false) typ.pkgPath = newName(pkgpath, "", false, false)
} }
// Look in cache. // Look in cache.
@ -2742,7 +2749,7 @@ func StructOf(fields []StructField) Type {
} }
} }
typ.str = resolveReflectName(newName(str, "", false)) typ.str = resolveReflectName(newName(str, "", false, false))
typ.tflag = 0 // TODO: set tflagRegularMemory typ.tflag = 0 // TODO: set tflagRegularMemory
typ.hash = hash typ.hash = hash
typ.size = size typ.size = size
@ -2774,14 +2781,14 @@ func StructOf(fields []StructField) Type {
continue continue
} }
// Pad to start of this field with zeros. // Pad to start of this field with zeros.
if ft.offset() > off { if ft.offset > off {
n := (ft.offset() - off) / goarch.PtrSize n := (ft.offset - off) / goarch.PtrSize
prog = append(prog, 0x01, 0x00) // emit a 0 bit prog = append(prog, 0x01, 0x00) // emit a 0 bit
if n > 1 { if n > 1 {
prog = append(prog, 0x81) // repeat previous bit prog = append(prog, 0x81) // repeat previous bit
prog = appendVarint(prog, n-1) // n-1 times prog = appendVarint(prog, n-1) // n-1 times
} }
off = ft.offset() off = ft.offset
} }
prog = appendGCProg(prog, ft.typ) prog = appendGCProg(prog, ft.typ)
@ -2803,8 +2810,8 @@ func StructOf(fields []StructField) Type {
if comparable { if comparable {
typ.equal = func(p, q unsafe.Pointer) bool { typ.equal = func(p, q unsafe.Pointer) bool {
for _, ft := range typ.fields { for _, ft := range typ.fields {
pi := add(p, ft.offset(), "&x.field safe") pi := add(p, ft.offset, "&x.field safe")
qi := add(q, ft.offset(), "&x.field safe") qi := add(q, ft.offset, "&x.field safe")
if !ft.typ.equal(pi, qi) { if !ft.typ.equal(pi, qi) {
return false return false
} }
@ -2841,16 +2848,11 @@ func runtimeStructField(field StructField) (structField, string) {
} }
} }
offsetEmbed := uintptr(0)
if field.Anonymous {
offsetEmbed |= 1
}
resolveReflectType(field.Type.common()) // install in runtime resolveReflectType(field.Type.common()) // install in runtime
f := structField{ f := structField{
name: newName(field.Name, string(field.Tag), field.IsExported()), name: newName(field.Name, string(field.Tag), field.IsExported(), field.Anonymous),
typ: field.Type.common(), typ: field.Type.common(),
offsetEmbed: offsetEmbed, offset: 0,
} }
return f, field.PkgPath return f, field.PkgPath
} }
@ -2874,7 +2876,7 @@ func typeptrdata(t *rtype) uintptr {
return 0 return 0
} }
f := st.fields[field] f := st.fields[field]
return f.offset() + f.typ.ptrdata return f.offset + f.typ.ptrdata
default: default:
panic("reflect.typeptrdata: unexpected type, " + t.String()) panic("reflect.typeptrdata: unexpected type, " + t.String())
@ -2917,7 +2919,7 @@ func ArrayOf(length int, elem Type) Type {
prototype := *(**arrayType)(unsafe.Pointer(&iarray)) prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := *prototype array := *prototype
array.tflag = typ.tflag & tflagRegularMemory array.tflag = typ.tflag & tflagRegularMemory
array.str = resolveReflectName(newName(s, "", false)) array.str = resolveReflectName(newName(s, "", false, false))
array.hash = fnv1(typ.hash, '[') array.hash = fnv1(typ.hash, '[')
for n := uint32(length); n > 0; n >>= 8 { for n := uint32(length); n > 0; n >>= 8 {
array.hash = fnv1(array.hash, byte(n)) array.hash = fnv1(array.hash, byte(n))
@ -3097,7 +3099,7 @@ func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, framePool *sync.Poo
} else { } else {
s = "funcargs(" + t.String() + ")" s = "funcargs(" + t.String() + ")"
} }
x.str = resolveReflectName(newName(s, "", false)) x.str = resolveReflectName(newName(s, "", false, false))
// cache result for future callers // cache result for future callers
framePool = &sync.Pool{New: func() any { framePool = &sync.Pool{New: func() any {
@ -3165,7 +3167,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
tt := (*structType)(unsafe.Pointer(t)) tt := (*structType)(unsafe.Pointer(t))
for i := range tt.fields { for i := range tt.fields {
f := &tt.fields[i] f := &tt.fields[i]
addTypeBits(bv, offset+f.offset(), f.typ) addTypeBits(bv, offset+f.offset, f.typ)
} }
} }
} }

View File

@ -1287,7 +1287,7 @@ func (v Value) Field(i int) Value {
// In the former case, we want v.ptr + offset. // In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0, // In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still the correct address. // 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} return Value{typ, ptr, fl}
} }

View File

@ -182,7 +182,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
if f.name.isBlank() { if f.name.isBlank() {
continue continue
} }
h = typehash(f.typ, add(p, f.offset()), h) h = typehash(f.typ, add(p, f.offset), h)
} }
return h return h
default: default:

View File

@ -536,7 +536,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
if f.typ.ptrdata == 0 { if f.typ.ptrdata == 0 {
continue continue
} }
cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg) cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
} }
case kindPtr, kindUnsafePointer: case kindPtr, kindUnsafePointer:
if indir { if indir {

View File

@ -174,7 +174,7 @@ func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool {
st := (*structtype)(unsafe.Pointer(t)) st := (*structtype)(unsafe.Pointer(t))
for i := range st.fields { for i := range st.fields {
f := &st.fields[i] f := &st.fields[i]
if !p.tryRegAssignArg(f.typ, offset+f.offset()) { if !p.tryRegAssignArg(f.typ, offset+f.offset) {
return false return false
} }
} }

View File

@ -414,13 +414,9 @@ type ptrtype struct {
} }
type structfield struct { type structfield struct {
name name name name
typ *_type typ *_type
offsetAnon uintptr offset uintptr
}
func (f *structfield) offset() uintptr {
return f.offsetAnon >> 1
} }
type structtype struct { type structtype struct {
@ -443,6 +439,10 @@ func (n name) isExported() bool {
return (*n.bytes)&(1<<0) != 0 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) { func (n name) readvarint(off int) (int, int) {
v := 0 v := 0
for i := 0; ; i++ { for i := 0; ; i++ {
@ -703,7 +703,10 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
if tf.name.tag() != vf.name.tag() { if tf.name.tag() != vf.name.tag() {
return false return false
} }
if tf.offsetAnon != vf.offsetAnon { if tf.offset != vf.offset {
return false
}
if tf.name.isEmbedded() != vf.name.isEmbedded() {
return false return false
} }
} }