From e1e66a03a6bb3210034b640923fa253d7def1a26 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 14 Jun 2022 13:38:02 -0700 Subject: [PATCH] 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 Run-TryBot: Keith Randall TryBot-Result: Gopher Robot Reviewed-by: Keith Randall --- .../compile/internal/reflectdata/reflect.go | 33 ++++---- src/cmd/link/internal/ld/decodesym.go | 17 ++++- src/cmd/link/internal/ld/dwarf.go | 6 +- src/internal/reflectlite/export_test.go | 2 +- src/internal/reflectlite/type.go | 21 ++--- src/reflect/abi.go | 2 +- src/reflect/export_test.go | 2 +- src/reflect/type.go | 76 ++++++++++--------- src/reflect/value.go | 2 +- src/runtime/alg.go | 2 +- src/runtime/cgocall.go | 2 +- src/runtime/syscall_windows.go | 2 +- src/runtime/type.go | 19 +++-- 13 files changed, 104 insertions(+), 82 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 3ffb7dcefa..21301ab149 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -412,7 +412,7 @@ func dimportpath(p *types.Pkg) { } 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 @@ -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 { 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]) } @@ -491,6 +491,9 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported b if pkg != nil { bits |= 1 << 2 } + if embedded { + bits |= 1 << 3 + } b := make([]byte, l) b[0] = bits 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 // 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 @@ -538,11 +541,14 @@ func dname(name, tag string, pkg *types.Pkg, exported bool) *obj.LSym { 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 @@ -610,7 +616,7 @@ func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int { 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)) @@ -775,7 +781,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int { } 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 { @@ -1074,7 +1080,7 @@ func writeType(t *types.Type) *obj.LSym { 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_)) @@ -1180,14 +1186,7 @@ func writeType(t *types.Type) *obj.LSym { // ../../../../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)) } } @@ -1356,7 +1355,7 @@ func WriteTabs() { // 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) diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index a6ae202859..b0f4b87563 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -132,6 +132,15 @@ func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs 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 { @@ -204,12 +213,18 @@ func decodetypeStructFieldType(ldr *loader.Loader, arch *sys.Arch, symIdx loader 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) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 6ed9697aec..c42511ea3f 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -682,9 +682,9 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie { } 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) } } diff --git a/src/internal/reflectlite/export_test.go b/src/internal/reflectlite/export_test.go index 3e5c258fb1..e9a928bdc6 100644 --- a/src/internal/reflectlite/export_test.go +++ b/src/internal/reflectlite/export_test.go @@ -36,7 +36,7 @@ func Field(v Value, i int) Value { // 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} } diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index bc6fc94773..21e3c1278d 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -269,17 +269,13 @@ type sliceType 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. @@ -328,6 +324,10 @@ func (n name) hasTag() bool { 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) { @@ -947,7 +947,10 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { 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 } } diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 9957d23768..32cb314188 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -237,7 +237,7 @@ func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool { 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 } } diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index a5a3c1c271..f7d2cc362d 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -140,7 +140,7 @@ func IsExported(t Type) bool { } func ResolveReflectName(s string) { - resolveReflectName(newName(s, "", false)) + resolveReflectName(newName(s, "", false, false)) } type Buffer struct { diff --git a/src/reflect/type.go b/src/reflect/type.go index 97040b5188..7b8cf0ee62 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -433,17 +433,13 @@ type sliceType 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. @@ -460,6 +456,7 @@ type structType struct { // 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. @@ -496,6 +493,10 @@ func (n name) hasTag() bool { 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) { @@ -565,7 +566,7 @@ func (n name) pkgPath() string { 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] + "...") } @@ -586,6 +587,9 @@ func newName(n, tag string, exported bool) name { l += tagLenLen + len(tag) bits |= 1 << 1 } + if embedded { + bits |= 1 << 3 + } b := make([]byte, l) b[0] = bits @@ -1256,7 +1260,7 @@ func (t *structType) Field(i int) (f StructField) { 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, @@ -1472,7 +1476,7 @@ func (t *rtype) ptrTo() *rtype { 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 @@ -1739,7 +1743,10 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { 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 } } @@ -1891,7 +1898,7 @@ func ChanOf(dir ChanDir, t Type) Type { 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 @@ -1934,7 +1941,7 @@ func MapOf(key, elem Type) Type { // 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 @@ -2113,7 +2120,7 @@ func FuncOf(in, out []Type, variadic bool) Type { } // 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) } @@ -2290,7 +2297,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype { gcdata: gcdata, } s := "bucket(" + ktyp.String() + "," + etyp.String() + ")" - b.str = resolveReflectName(newName(s, "", false)) + b.str = resolveReflectName(newName(s, "", false, false)) return b } @@ -2369,7 +2376,7 @@ func SliceOf(t Type) Type { 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 @@ -2632,7 +2639,7 @@ func StructOf(fields []StructField) Type { typalign = ft.align } size = offset + ft.size - f.offsetEmbed |= offset << 1 + f.offset = offset if ft.size == 0 { lastzero = size @@ -2698,7 +2705,7 @@ func StructOf(fields []StructField) Type { *typ = *prototype typ.fields = fs if pkgpath != "" { - typ.pkgPath = newName(pkgpath, "", false) + typ.pkgPath = newName(pkgpath, "", false, false) } // 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.hash = hash typ.size = size @@ -2774,14 +2781,14 @@ func StructOf(fields []StructField) Type { 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) @@ -2803,8 +2810,8 @@ func StructOf(fields []StructField) Type { 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 } @@ -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 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 } @@ -2874,7 +2876,7 @@ func typeptrdata(t *rtype) uintptr { 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()) @@ -2917,7 +2919,7 @@ func ArrayOf(length int, elem Type) Type { 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)) @@ -3097,7 +3099,7 @@ func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, framePool *sync.Poo } 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 { @@ -3165,7 +3167,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) { 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) } } } diff --git a/src/reflect/value.go b/src/reflect/value.go index 5abdca2820..74554a3ac8 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1287,7 +1287,7 @@ func (v Value) Field(i int) Value { // 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} } diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 5d7d1c77f4..2a413eeef3 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -182,7 +182,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { 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: diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 977d049378..892654ed5b 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -536,7 +536,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { 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 { diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index a841a31a27..e42d71ad65 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -174,7 +174,7 @@ func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool { 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 } } diff --git a/src/runtime/type.go b/src/runtime/type.go index b650d6d795..e8e7819ecf 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -414,13 +414,9 @@ type ptrtype struct { } 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 { @@ -443,6 +439,10 @@ func (n name) isExported() bool { 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++ { @@ -703,7 +703,10 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { 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 } } -- 2.48.1