mirror of
https://github.com/golang/go
synced 2024-11-23 18:10:04 -07:00
cmd/compile, etc: use name for type pkgPath
By replacing the *string used to represent pkgPath with a reflect.name everywhere, the embedded *string for package paths inside the reflect.name can be replaced by an offset, nameOff. This reduces the number of pointers in the type information. This also moves all reflect.name types into the same section, making it possible to use nameOff more widely in later CLs. No significant binary size change for normal binaries, but: linux/amd64 PIE: cmd/go: -440KB (3.7%) jujud: -2.6MB (3.2%) For #6853. Change-Id: I3890b132a784a1090b1b72b32febfe0bea77eaee Reviewed-on: https://go-review.googlesource.com/21395 Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
73e2ad2022
commit
f120936dff
@ -20,7 +20,7 @@ const (
|
|||||||
type Pkg struct {
|
type Pkg struct {
|
||||||
Name string // package name, e.g. "sys"
|
Name string // package name, e.g. "sys"
|
||||||
Path string // string literal used in import statement, e.g. "runtime/internal/sys"
|
Path string // string literal used in import statement, e.g. "runtime/internal/sys"
|
||||||
Pathsym *Sym
|
Pathsym *obj.LSym
|
||||||
Prefix string // escaped path for use in symbol table
|
Prefix string // escaped path for use in symbol table
|
||||||
Imported bool // export data of this package was parsed
|
Imported bool // export data of this package was parsed
|
||||||
Exported bool // import line written in export data
|
Exported bool // import line written in export data
|
||||||
|
@ -412,8 +412,6 @@ func imethods(t *Type) []*Sig {
|
|||||||
return methods
|
return methods
|
||||||
}
|
}
|
||||||
|
|
||||||
var dimportpath_gopkg *Pkg
|
|
||||||
|
|
||||||
func dimportpath(p *Pkg) {
|
func dimportpath(p *Pkg) {
|
||||||
if p.Pathsym != nil {
|
if p.Pathsym != nil {
|
||||||
return
|
return
|
||||||
@ -426,27 +424,18 @@ func dimportpath(p *Pkg) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if dimportpath_gopkg == nil {
|
var str string
|
||||||
dimportpath_gopkg = mkpkg("go")
|
|
||||||
dimportpath_gopkg.Name = "go"
|
|
||||||
}
|
|
||||||
|
|
||||||
nam := "importpath." + p.Prefix + "."
|
|
||||||
|
|
||||||
n := Nod(ONAME, nil, nil)
|
|
||||||
n.Sym = Pkglookup(nam, dimportpath_gopkg)
|
|
||||||
|
|
||||||
n.Class = PEXTERN
|
|
||||||
n.Xoffset = 0
|
|
||||||
p.Pathsym = n.Sym
|
|
||||||
|
|
||||||
if p == localpkg {
|
if p == localpkg {
|
||||||
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
|
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
|
||||||
gdatastring(n, myimportpath)
|
str = myimportpath
|
||||||
} else {
|
} else {
|
||||||
gdatastring(n, p.Path)
|
str = p.Path
|
||||||
}
|
}
|
||||||
ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
|
|
||||||
|
s := obj.Linklookup(Ctxt, "go.importpath."+p.Prefix+".", 0)
|
||||||
|
ot := dnameData(s, 0, str, "", nil, false)
|
||||||
|
ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
|
||||||
|
p.Pathsym = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
|
func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
|
||||||
@ -469,7 +458,23 @@ func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dimportpath(pkg)
|
dimportpath(pkg)
|
||||||
return dsymptrLSym(s, ot, Linksym(pkg.Pathsym), 0)
|
return dsymptrLSym(s, ot, pkg.Pathsym, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dgopkgpathOffLSym writes an offset relocation in s at offset ot to the pkg path symbol.
|
||||||
|
func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int {
|
||||||
|
if pkg == localpkg && myimportpath == "" {
|
||||||
|
// If we don't know the full import path of the package being compiled
|
||||||
|
// (i.e. -p was not passed on the compiler command line), emit a reference to
|
||||||
|
// go.importpath.""., which the linker will rewrite using the correct import path.
|
||||||
|
// Every package that imports this one directly defines the symbol.
|
||||||
|
// See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
|
||||||
|
ns := obj.Linklookup(Ctxt, `go.importpath."".`, 0)
|
||||||
|
return dsymptrOffLSym(s, ot, ns, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
dimportpath(pkg)
|
||||||
|
return dsymptrOffLSym(s, ot, pkg.Pathsym, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isExportedField reports whether a struct field is exported.
|
// isExportedField reports whether a struct field is exported.
|
||||||
@ -495,13 +500,12 @@ func dnameField(s *Sym, ot int, ft *Field) int {
|
|||||||
if ft.Note != nil {
|
if ft.Note != nil {
|
||||||
tag = *ft.Note
|
tag = *ft.Note
|
||||||
}
|
}
|
||||||
return dname(s, ot, name, tag, nil, isExportedField(ft))
|
nsym := dname(name, tag, nil, isExportedField(ft))
|
||||||
|
return dsymptrLSym(Linksym(s), ot, nsym, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var dnameCount int
|
// dnameData writes the contents of a reflect.name into s at offset ot.
|
||||||
|
func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) int {
|
||||||
// dname dumps a reflect.name for a struct field or method.
|
|
||||||
func dname(s *Sym, ot int, name, tag string, pkg *Pkg, exported bool) int {
|
|
||||||
if len(name) > 1<<16-1 {
|
if len(name) > 1<<16-1 {
|
||||||
Fatalf("name too long: %s", name)
|
Fatalf("name too long: %s", name)
|
||||||
}
|
}
|
||||||
@ -534,33 +538,48 @@ func dname(s *Sym, ot int, name, tag string, pkg *Pkg, exported bool) int {
|
|||||||
copy(tb[2:], tag)
|
copy(tb[2:], tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Very few names require a pkgPath *string (only those
|
ot = int(s.WriteBytes(Ctxt, int64(ot), b))
|
||||||
// defined in a different package than their type). So if
|
|
||||||
// there is no pkgPath, we treat the name contents as string
|
if pkg != nil {
|
||||||
// data that duplicates across packages.
|
ot = dgopkgpathOffLSym(s, ot, pkg)
|
||||||
var bsym *obj.LSym
|
|
||||||
if pkg == nil {
|
|
||||||
_, bsym = stringsym(string(b))
|
|
||||||
} else {
|
|
||||||
// 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
|
|
||||||
// contents should not be decoded as a type.
|
|
||||||
bsymname := fmt.Sprintf(`type..methodname."".%d`, dnameCount)
|
|
||||||
dnameCount++
|
|
||||||
bsym = obj.Linklookup(Ctxt, bsymname, 0)
|
|
||||||
bsym.P = b
|
|
||||||
boff := len(b)
|
|
||||||
boff = int(Rnd(int64(boff), int64(Widthptr)))
|
|
||||||
boff = dgopkgpathLSym(bsym, boff, pkg)
|
|
||||||
ggloblLSym(bsym, int32(boff), obj.RODATA|obj.LOCAL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ot = dsymptrLSym(Linksym(s), ot, bsym, 0)
|
|
||||||
|
|
||||||
return ot
|
return ot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dnameCount int
|
||||||
|
|
||||||
|
// dname creates a reflect.name for a struct field or method.
|
||||||
|
func dname(name, tag string, pkg *Pkg, exported 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
|
||||||
|
// contents should not be decoded as a type.
|
||||||
|
sname := "type..namedata."
|
||||||
|
if pkg == nil {
|
||||||
|
// In the common case, share data with other packages.
|
||||||
|
if name == "" {
|
||||||
|
if exported {
|
||||||
|
sname += "-noname-exported." + tag
|
||||||
|
} else {
|
||||||
|
sname += "-noname-unexported." + tag
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sname += name + "." + tag
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
|
||||||
|
dnameCount++
|
||||||
|
}
|
||||||
|
s := obj.Linklookup(Ctxt, sname, 0)
|
||||||
|
if len(s.P) > 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
ot := dnameData(s, 0, name, tag, pkg, exported)
|
||||||
|
ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// dextratype dumps the fields of a runtime.uncommontype.
|
// dextratype dumps the fields of a runtime.uncommontype.
|
||||||
// dataAdd is the offset in bytes after the header where the
|
// dataAdd is the offset in bytes after the header where the
|
||||||
// backing array of the []method field is written (by dextratypeData).
|
// backing array of the []method field is written (by dextratypeData).
|
||||||
@ -627,7 +646,8 @@ func dextratypeData(s *Sym, ot int, t *Type) int {
|
|||||||
if !exported && a.pkg != typePkg(t) {
|
if !exported && a.pkg != typePkg(t) {
|
||||||
pkg = a.pkg
|
pkg = a.pkg
|
||||||
}
|
}
|
||||||
ot = dname(s, ot, a.name, "", pkg, exported)
|
nsym := dname(a.name, "", pkg, exported)
|
||||||
|
ot = dsymptrLSym(lsym, ot, nsym, 0)
|
||||||
ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype)))
|
ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype)))
|
||||||
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym))
|
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym))
|
||||||
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
|
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
|
||||||
@ -1213,7 +1233,8 @@ ok:
|
|||||||
if !exported && a.pkg != tpkg {
|
if !exported && a.pkg != tpkg {
|
||||||
pkg = a.pkg
|
pkg = a.pkg
|
||||||
}
|
}
|
||||||
ot = dname(s, ot, a.name, "", pkg, exported)
|
nsym := dname(a.name, "", pkg, exported)
|
||||||
|
ot = dsymptrLSym(Linksym(s), ot, nsym, 0)
|
||||||
ot = dsymptr(s, ot, dtypesym(a.type_), 0)
|
ot = dsymptr(s, ot, dtypesym(a.type_), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,11 @@ func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
|
|||||||
if s.Type == SBSS || s.Type == STLSBSS {
|
if s.Type == SBSS || s.Type == STLSBSS {
|
||||||
ctxt.Diag("cannot supply data for BSS var")
|
ctxt.Diag("cannot supply data for BSS var")
|
||||||
}
|
}
|
||||||
s.Grow(off + int64(siz))
|
l := off + int64(siz)
|
||||||
|
s.Grow(l)
|
||||||
|
if l > s.Size {
|
||||||
|
s.Size = l
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteFloat32 writes f into s at offset off.
|
// WriteFloat32 writes f into s at offset off.
|
||||||
@ -150,6 +154,13 @@ func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
|
|||||||
copy(s.P[off:off+int64(siz)], str)
|
copy(s.P[off:off+int64(siz)], str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteBytes writes a slice of bytes into s at offset off.
|
||||||
|
func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
|
||||||
|
s.prepwrite(ctxt, off, len(b))
|
||||||
|
copy(s.P[off:], b)
|
||||||
|
return off + int64(len(b))
|
||||||
|
}
|
||||||
|
|
||||||
func Addrel(s *LSym) *Reloc {
|
func Addrel(s *LSym) *Reloc {
|
||||||
s.R = append(s.R, Reloc{})
|
s.R = append(s.R, Reloc{})
|
||||||
return &s.R[len(s.R)-1]
|
return &s.R[len(s.R)-1]
|
||||||
|
@ -299,9 +299,9 @@ type method struct {
|
|||||||
// Using a pointer to this struct reduces the overall size required
|
// Using a pointer to this struct reduces the overall size required
|
||||||
// to describe an unnamed type with no methods.
|
// to describe an unnamed type with no methods.
|
||||||
type uncommonType struct {
|
type uncommonType struct {
|
||||||
pkgPath *string // import path; nil for built-in types like int, string
|
pkgPath name // import path; empty for built-in types like int, string
|
||||||
mcount uint16 // number of methods
|
mcount uint16 // number of methods
|
||||||
moff uint16 // offset from this uncommontype to [mcount]method
|
moff uint16 // offset from this uncommontype to [mcount]method
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChanDir represents a channel type's direction.
|
// ChanDir represents a channel type's direction.
|
||||||
@ -354,7 +354,7 @@ type imethod struct {
|
|||||||
// interfaceType represents an interface type.
|
// interfaceType represents an interface type.
|
||||||
type interfaceType struct {
|
type interfaceType struct {
|
||||||
rtype `reflect:"interface"`
|
rtype `reflect:"interface"`
|
||||||
pkgPath *string // import path
|
pkgPath name // import path
|
||||||
methods []imethod // sorted by hash
|
methods []imethod // sorted by hash
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ type structField struct {
|
|||||||
// structType represents a struct type.
|
// structType represents a struct type.
|
||||||
type structType struct {
|
type structType struct {
|
||||||
rtype `reflect:"struct"`
|
rtype `reflect:"struct"`
|
||||||
pkgPath *string
|
pkgPath name
|
||||||
fields []structField // sorted by offset
|
fields []structField // sorted by offset
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +406,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 *string follow the name and tag
|
// 1<<2 pkgPath nameOff follows the name and tag
|
||||||
//
|
//
|
||||||
// The next two bytes are the data length:
|
// The next two bytes are the data length:
|
||||||
//
|
//
|
||||||
@ -417,10 +417,9 @@ type structType struct {
|
|||||||
// If tag data follows then bytes 3+l and 3+l+1 are the tag length,
|
// If tag data follows then bytes 3+l and 3+l+1 are the tag length,
|
||||||
// with the data following.
|
// with the data following.
|
||||||
//
|
//
|
||||||
// If the import path follows, then ptrSize bytes at the end of
|
// If the import path follows, then 4 bytes at the end of
|
||||||
// the data form a *string. The pointer is aligned to its width.
|
// the data form a nameOff. The import path is only set for concrete
|
||||||
// The import path is only set for concrete methods that are defined
|
// methods that are defined in a different package than their type.
|
||||||
// in a different package than their type.
|
|
||||||
type name struct {
|
type name struct {
|
||||||
bytes *byte
|
bytes *byte
|
||||||
}
|
}
|
||||||
@ -446,6 +445,9 @@ func (n *name) tagLen() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *name) name() (s string) {
|
func (n *name) name() (s string) {
|
||||||
|
if n.bytes == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
nl := n.nameLen()
|
nl := n.nameLen()
|
||||||
if nl == 0 {
|
if nl == 0 {
|
||||||
return ""
|
return ""
|
||||||
@ -468,16 +470,18 @@ func (n *name) tag() (s string) {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *name) pkgPath() *string {
|
func (n *name) pkgPath() string {
|
||||||
if *n.data(0)&(1<<2) == 0 {
|
if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
|
||||||
return nil
|
return ""
|
||||||
}
|
}
|
||||||
off := 3 + n.nameLen()
|
off := 3 + n.nameLen()
|
||||||
if tl := n.tagLen(); tl > 0 {
|
if tl := n.tagLen(); tl > 0 {
|
||||||
off += 2 + tl
|
off += 2 + tl
|
||||||
}
|
}
|
||||||
off = int(round(uintptr(off), ptrSize))
|
var nameOff int32
|
||||||
return *(**string)(unsafe.Pointer(n.data(off)))
|
copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
|
||||||
|
pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n), nameOff))}
|
||||||
|
return pkgPathName.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// round n up to a multiple of a. a must be a power of 2.
|
// round n up to a multiple of a. a must be a power of 2.
|
||||||
@ -595,10 +599,10 @@ func (t *uncommonType) methods() []method {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *uncommonType) PkgPath() string {
|
func (t *uncommonType) PkgPath() string {
|
||||||
if t == nil || t.pkgPath == nil {
|
if t == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return *t.pkgPath
|
return t.pkgPath.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveTypeOff resolves an *rtype offset from a base type.
|
// resolveTypeOff resolves an *rtype offset from a base type.
|
||||||
@ -752,11 +756,10 @@ func (t *rtype) Method(i int) (m Method) {
|
|||||||
m.Name = p.name.name()
|
m.Name = p.name.name()
|
||||||
fl := flag(Func)
|
fl := flag(Func)
|
||||||
if !p.name.isExported() {
|
if !p.name.isExported() {
|
||||||
pkgPath := p.name.pkgPath()
|
m.PkgPath = p.name.pkgPath()
|
||||||
if pkgPath == nil {
|
if m.PkgPath == "" {
|
||||||
pkgPath = ut.pkgPath
|
m.PkgPath = ut.pkgPath.name()
|
||||||
}
|
}
|
||||||
m.PkgPath = *pkgPath
|
|
||||||
fl |= flagStickyRO
|
fl |= flagStickyRO
|
||||||
}
|
}
|
||||||
if p.mtyp != 0 {
|
if p.mtyp != 0 {
|
||||||
@ -1004,11 +1007,10 @@ func (t *interfaceType) Method(i int) (m Method) {
|
|||||||
p := &t.methods[i]
|
p := &t.methods[i]
|
||||||
m.Name = p.name.name()
|
m.Name = p.name.name()
|
||||||
if !p.name.isExported() {
|
if !p.name.isExported() {
|
||||||
pkgPath := p.name.pkgPath()
|
m.PkgPath = p.name.pkgPath()
|
||||||
if pkgPath == nil {
|
if m.PkgPath == "" {
|
||||||
pkgPath = t.pkgPath
|
m.PkgPath = t.pkgPath.name()
|
||||||
}
|
}
|
||||||
m.PkgPath = *pkgPath
|
|
||||||
}
|
}
|
||||||
m.Type = toType(p.typ)
|
m.Type = toType(p.typ)
|
||||||
m.Index = i
|
m.Index = i
|
||||||
@ -1146,9 +1148,9 @@ func (t *structType) Field(i int) (f StructField) {
|
|||||||
f.Name = t.Name()
|
f.Name = t.Name()
|
||||||
f.Anonymous = true
|
f.Anonymous = true
|
||||||
}
|
}
|
||||||
if t.pkgPath != nil && !p.name.isExported() {
|
if !p.name.isExported() {
|
||||||
// Fields never have an import path in their name.
|
// Fields never have an import path in their name.
|
||||||
f.PkgPath = *t.pkgPath
|
f.PkgPath = t.pkgPath.name()
|
||||||
}
|
}
|
||||||
if tag := p.name.tag(); tag != "" {
|
if tag := p.name.tag(); tag != "" {
|
||||||
f.Tag = StructTag(tag)
|
f.Tag = StructTag(tag)
|
||||||
@ -2325,7 +2327,7 @@ func StructOf(fields []StructField) Type {
|
|||||||
case Interface:
|
case Interface:
|
||||||
ift := (*interfaceType)(unsafe.Pointer(ft))
|
ift := (*interfaceType)(unsafe.Pointer(ft))
|
||||||
for im, m := range ift.methods {
|
for im, m := range ift.methods {
|
||||||
if m.name.pkgPath() != nil {
|
if m.name.pkgPath() != "" {
|
||||||
// TODO(sbinet)
|
// TODO(sbinet)
|
||||||
panic("reflect: embedded interface with unexported method(s) not implemented")
|
panic("reflect: embedded interface with unexported method(s) not implemented")
|
||||||
}
|
}
|
||||||
@ -2384,7 +2386,7 @@ func StructOf(fields []StructField) Type {
|
|||||||
ptr := (*ptrType)(unsafe.Pointer(ft))
|
ptr := (*ptrType)(unsafe.Pointer(ft))
|
||||||
if unt := ptr.uncommon(); unt != nil {
|
if unt := ptr.uncommon(); unt != nil {
|
||||||
for _, m := range unt.methods() {
|
for _, m := range unt.methods() {
|
||||||
if m.name.pkgPath() != nil {
|
if m.name.pkgPath() != "" {
|
||||||
// TODO(sbinet)
|
// TODO(sbinet)
|
||||||
panic("reflect: embedded interface with unexported method(s) not implemented")
|
panic("reflect: embedded interface with unexported method(s) not implemented")
|
||||||
}
|
}
|
||||||
@ -2398,7 +2400,7 @@ func StructOf(fields []StructField) Type {
|
|||||||
}
|
}
|
||||||
if unt := ptr.elem.uncommon(); unt != nil {
|
if unt := ptr.elem.uncommon(); unt != nil {
|
||||||
for _, m := range unt.methods() {
|
for _, m := range unt.methods() {
|
||||||
if m.name.pkgPath() != nil {
|
if m.name.pkgPath() != "" {
|
||||||
// TODO(sbinet)
|
// TODO(sbinet)
|
||||||
panic("reflect: embedded interface with unexported method(s) not implemented")
|
panic("reflect: embedded interface with unexported method(s) not implemented")
|
||||||
}
|
}
|
||||||
@ -2413,7 +2415,7 @@ func StructOf(fields []StructField) Type {
|
|||||||
default:
|
default:
|
||||||
if unt := ft.uncommon(); unt != nil {
|
if unt := ft.uncommon(); unt != nil {
|
||||||
for _, m := range unt.methods() {
|
for _, m := range unt.methods() {
|
||||||
if m.name.pkgPath() != nil {
|
if m.name.pkgPath() != "" {
|
||||||
// TODO(sbinet)
|
// TODO(sbinet)
|
||||||
panic("reflect: embedded interface with unexported method(s) not implemented")
|
panic("reflect: embedded interface with unexported method(s) not implemented")
|
||||||
}
|
}
|
||||||
|
@ -183,10 +183,11 @@ func dumptype(t *_type) {
|
|||||||
dumpint(tagType)
|
dumpint(tagType)
|
||||||
dumpint(uint64(uintptr(unsafe.Pointer(t))))
|
dumpint(uint64(uintptr(unsafe.Pointer(t))))
|
||||||
dumpint(uint64(t.size))
|
dumpint(uint64(t.size))
|
||||||
if x := t.uncommon(); x == nil || x.pkgpath == nil {
|
if x := t.uncommon(); x == nil || x.pkgpath.name() == "" {
|
||||||
dumpstr(t._string)
|
dumpstr(t._string)
|
||||||
} else {
|
} else {
|
||||||
pkgpath := stringStructOf(x.pkgpath)
|
pkgpathstr := x.pkgpath.name()
|
||||||
|
pkgpath := stringStructOf(&pkgpathstr)
|
||||||
namestr := t.name()
|
namestr := t.name()
|
||||||
name := stringStructOf(&namestr)
|
name := stringStructOf(&namestr)
|
||||||
dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
|
dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
|
||||||
|
@ -101,15 +101,15 @@ func additab(m *itab, locked, canfail bool) {
|
|||||||
iname := i.name.name()
|
iname := i.name.name()
|
||||||
itype := i._type
|
itype := i._type
|
||||||
ipkg := i.name.pkgPath()
|
ipkg := i.name.pkgPath()
|
||||||
if ipkg == nil {
|
if ipkg == "" {
|
||||||
ipkg = inter.pkgpath
|
ipkg = inter.pkgpath.name()
|
||||||
}
|
}
|
||||||
for ; j < nt; j++ {
|
for ; j < nt; j++ {
|
||||||
t := &xmhdr[j]
|
t := &xmhdr[j]
|
||||||
if typ.typeOff(t.mtyp) == itype && t.name.name() == iname {
|
if typ.typeOff(t.mtyp) == itype && t.name.name() == iname {
|
||||||
pkgPath := t.name.pkgPath()
|
pkgPath := t.name.pkgPath()
|
||||||
if pkgPath == nil {
|
if pkgPath == "" {
|
||||||
pkgPath = x.pkgpath
|
pkgPath = x.pkgpath.name()
|
||||||
}
|
}
|
||||||
if t.name.isExported() || pkgPath == ipkg {
|
if t.name.isExported() || pkgPath == ipkg {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
|
@ -6,10 +6,7 @@
|
|||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import "unsafe"
|
||||||
"runtime/internal/sys"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// tflag is documented in ../reflect/type.go.
|
// tflag is documented in ../reflect/type.go.
|
||||||
type tflag uint8
|
type tflag uint8
|
||||||
@ -151,6 +148,33 @@ var reflectOffs struct {
|
|||||||
minv map[unsafe.Pointer]int32
|
minv map[unsafe.Pointer]int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
|
||||||
|
if off == 0 {
|
||||||
|
return name{}
|
||||||
|
}
|
||||||
|
base := uintptr(ptrInModule)
|
||||||
|
var md *moduledata
|
||||||
|
for next := &firstmoduledata; next != nil; next = next.next {
|
||||||
|
if base >= next.types && base < next.etypes {
|
||||||
|
md = next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
throw("runtime: name offset base pointer out of range")
|
||||||
|
}
|
||||||
|
res := md.types + uintptr(off)
|
||||||
|
if res > md.etypes {
|
||||||
|
println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
|
||||||
|
throw("runtime: name offset out of range")
|
||||||
|
}
|
||||||
|
return name{(*byte)(unsafe.Pointer(res))}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *_type) typeOff(off typeOff) *_type {
|
func (t *_type) typeOff(off typeOff) *_type {
|
||||||
if off == 0 {
|
if off == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -240,6 +264,7 @@ func (t *functype) dotdotdot() bool {
|
|||||||
return t.outCount&(1<<15) != 0
|
return t.outCount&(1<<15) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nameOff int32
|
||||||
type typeOff int32
|
type typeOff int32
|
||||||
type textOff int32
|
type textOff int32
|
||||||
|
|
||||||
@ -251,7 +276,7 @@ type method struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type uncommontype struct {
|
type uncommontype struct {
|
||||||
pkgpath *string
|
pkgpath name
|
||||||
mcount uint16 // number of methods
|
mcount uint16 // number of methods
|
||||||
moff uint16 // offset from this uncommontype to [mcount]method
|
moff uint16 // offset from this uncommontype to [mcount]method
|
||||||
}
|
}
|
||||||
@ -263,7 +288,7 @@ type imethod struct {
|
|||||||
|
|
||||||
type interfacetype struct {
|
type interfacetype struct {
|
||||||
typ _type
|
typ _type
|
||||||
pkgpath *string
|
pkgpath name
|
||||||
mhdr []imethod
|
mhdr []imethod
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +344,7 @@ type structfield struct {
|
|||||||
|
|
||||||
type structtype struct {
|
type structtype struct {
|
||||||
typ _type
|
typ _type
|
||||||
pkgPath *string
|
pkgPath name
|
||||||
fields []structfield
|
fields []structfield
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,6 +375,9 @@ func (n *name) tagLen() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *name) name() (s string) {
|
func (n *name) name() (s string) {
|
||||||
|
if n.bytes == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
nl := n.nameLen()
|
nl := n.nameLen()
|
||||||
if nl == 0 {
|
if nl == 0 {
|
||||||
return ""
|
return ""
|
||||||
@ -372,16 +400,18 @@ func (n *name) tag() (s string) {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *name) pkgPath() *string {
|
func (n *name) pkgPath() string {
|
||||||
if *n.data(0)&(1<<2) == 0 {
|
if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
|
||||||
return nil
|
return ""
|
||||||
}
|
}
|
||||||
off := 3 + n.nameLen()
|
off := 3 + n.nameLen()
|
||||||
if tl := n.tagLen(); tl > 0 {
|
if tl := n.tagLen(); tl > 0 {
|
||||||
off += 2 + tl
|
off += 2 + tl
|
||||||
}
|
}
|
||||||
off = int(round(uintptr(off), sys.PtrSize))
|
var nameOff nameOff
|
||||||
return *(**string)(unsafe.Pointer(n.data(off)))
|
copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
|
||||||
|
pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
|
||||||
|
return pkgPathName.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// typelinksinit scans the types from extra modules and builds the
|
// typelinksinit scans the types from extra modules and builds the
|
||||||
@ -466,7 +496,7 @@ func typesEqual(t, v *_type) bool {
|
|||||||
if ut == nil || uv == nil {
|
if ut == nil || uv == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !pkgPathEqual(ut.pkgpath, uv.pkgpath) {
|
if ut.pkgpath.name() != uv.pkgpath.name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,7 +536,7 @@ func typesEqual(t, v *_type) bool {
|
|||||||
case kindInterface:
|
case kindInterface:
|
||||||
it := (*interfacetype)(unsafe.Pointer(t))
|
it := (*interfacetype)(unsafe.Pointer(t))
|
||||||
iv := (*interfacetype)(unsafe.Pointer(v))
|
iv := (*interfacetype)(unsafe.Pointer(v))
|
||||||
if !pkgPathEqual(it.pkgpath, iv.pkgpath) {
|
if it.pkgpath.name() != iv.pkgpath.name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(it.mhdr) != len(iv.mhdr) {
|
if len(it.mhdr) != len(iv.mhdr) {
|
||||||
@ -518,7 +548,7 @@ func typesEqual(t, v *_type) bool {
|
|||||||
if tm.name.name() != vm.name.name() {
|
if tm.name.name() != vm.name.name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !pkgPathEqual(tm.name.pkgPath(), vm.name.pkgPath()) {
|
if tm.name.pkgPath() != vm.name.pkgPath() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !typesEqual(tm._type, vm._type) {
|
if !typesEqual(tm._type, vm._type) {
|
||||||
@ -550,7 +580,7 @@ func typesEqual(t, v *_type) bool {
|
|||||||
if tf.name.name() != vf.name.name() {
|
if tf.name.name() != vf.name.name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !pkgPathEqual(tf.name.pkgPath(), vf.name.pkgPath()) {
|
if tf.name.pkgPath() != vf.name.pkgPath() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !typesEqual(tf.typ, vf.typ) {
|
if !typesEqual(tf.typ, vf.typ) {
|
||||||
@ -570,13 +600,3 @@ func typesEqual(t, v *_type) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pkgPathEqual(p, q *string) bool {
|
|
||||||
if p == q {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p == nil || q == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return *p == *q
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user