mirror of
https://github.com/golang/go.git
synced 2025-05-29 11:25:43 +00:00
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:
parent
cb9bf93078
commit
e1e66a03a6
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user