type Pkg struct {
Name string // package name, e.g. "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
Imported bool // export data of this package was parsed
Exported bool // import line written in export data
return methods
}
-var dimportpath_gopkg *Pkg
-
func dimportpath(p *Pkg) {
if p.Pathsym != nil {
return
return
}
- if dimportpath_gopkg == nil {
- 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
-
+ var str string
if p == localpkg {
// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
- gdatastring(n, myimportpath)
+ str = myimportpath
} 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 {
}
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.
if ft.Note != nil {
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
-
-// 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 {
+// 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 {
if len(name) > 1<<16-1 {
Fatalf("name too long: %s", name)
}
copy(tb[2:], tag)
}
- // Very few names require a pkgPath *string (only those
- // defined in a different package than their type). So if
- // there is no pkgPath, we treat the name contents as string
- // data that duplicates across packages.
- var bsym *obj.LSym
+ ot = int(s.WriteBytes(Ctxt, int64(ot), b))
+
+ if pkg != nil {
+ ot = dgopkgpathOffLSym(s, ot, pkg)
+ }
+
+ 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 {
- _, bsym = stringsym(string(b))
+ // 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 {
- // 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)
+ sname = fmt.Sprintf(`%s"".%d`, sname, 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
+ 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.
if !exported && a.pkg != typePkg(t) {
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(a.isym))
ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
if !exported && a.pkg != tpkg {
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)
}
if s.Type == SBSS || s.Type == STLSBSS {
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.
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 {
s.R = append(s.R, Reloc{})
return &s.R[len(s.R)-1]
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
- pkgPath *string // import path; nil for built-in types like int, string
- mcount uint16 // number of methods
- moff uint16 // offset from this uncommontype to [mcount]method
+ pkgPath name // import path; empty for built-in types like int, string
+ mcount uint16 // number of methods
+ moff uint16 // offset from this uncommontype to [mcount]method
}
// ChanDir represents a channel type's direction.
// interfaceType represents an interface type.
type interfaceType struct {
rtype `reflect:"interface"`
- pkgPath *string // import path
+ pkgPath name // import path
methods []imethod // sorted by hash
}
// structType represents a struct type.
type structType struct {
rtype `reflect:"struct"`
- pkgPath *string
+ pkgPath name
fields []structField // sorted by offset
}
//
// 1<<0 the name is exported
// 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:
//
// If tag data follows then bytes 3+l and 3+l+1 are the tag length,
// with the data following.
//
-// If the import path follows, then ptrSize bytes at the end of
-// the data form a *string. The pointer is aligned to its width.
-// The import path is only set for concrete methods that are defined
-// in a different package than their type.
+// If the import path follows, then 4 bytes at the end of
+// the data form a nameOff. The import path is only set for concrete
+// methods that are defined in a different package than their type.
type name struct {
bytes *byte
}
}
func (n *name) name() (s string) {
+ if n.bytes == nil {
+ return ""
+ }
nl := n.nameLen()
if nl == 0 {
return ""
return s
}
-func (n *name) pkgPath() *string {
- if *n.data(0)&(1<<2) == 0 {
- return nil
+func (n *name) pkgPath() string {
+ if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
+ return ""
}
off := 3 + n.nameLen()
if tl := n.tagLen(); tl > 0 {
off += 2 + tl
}
- off = int(round(uintptr(off), ptrSize))
- return *(**string)(unsafe.Pointer(n.data(off)))
+ var nameOff int32
+ 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.
}
func (t *uncommonType) PkgPath() string {
- if t == nil || t.pkgPath == nil {
+ if t == nil {
return ""
}
- return *t.pkgPath
+ return t.pkgPath.name()
}
// resolveTypeOff resolves an *rtype offset from a base type.
m.Name = p.name.name()
fl := flag(Func)
if !p.name.isExported() {
- pkgPath := p.name.pkgPath()
- if pkgPath == nil {
- pkgPath = ut.pkgPath
+ m.PkgPath = p.name.pkgPath()
+ if m.PkgPath == "" {
+ m.PkgPath = ut.pkgPath.name()
}
- m.PkgPath = *pkgPath
fl |= flagStickyRO
}
if p.mtyp != 0 {
p := &t.methods[i]
m.Name = p.name.name()
if !p.name.isExported() {
- pkgPath := p.name.pkgPath()
- if pkgPath == nil {
- pkgPath = t.pkgPath
+ m.PkgPath = p.name.pkgPath()
+ if m.PkgPath == "" {
+ m.PkgPath = t.pkgPath.name()
}
- m.PkgPath = *pkgPath
}
m.Type = toType(p.typ)
m.Index = i
f.Name = t.Name()
f.Anonymous = true
}
- if t.pkgPath != nil && !p.name.isExported() {
+ if !p.name.isExported() {
// Fields never have an import path in their name.
- f.PkgPath = *t.pkgPath
+ f.PkgPath = t.pkgPath.name()
}
if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag)
case Interface:
ift := (*interfaceType)(unsafe.Pointer(ft))
for im, m := range ift.methods {
- if m.name.pkgPath() != nil {
+ if m.name.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
ptr := (*ptrType)(unsafe.Pointer(ft))
if unt := ptr.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != nil {
+ if m.name.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
}
if unt := ptr.elem.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != nil {
+ if m.name.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
default:
if unt := ft.uncommon(); unt != nil {
for _, m := range unt.methods() {
- if m.name.pkgPath() != nil {
+ if m.name.pkgPath() != "" {
// TODO(sbinet)
panic("reflect: embedded interface with unexported method(s) not implemented")
}
dumpint(tagType)
dumpint(uint64(uintptr(unsafe.Pointer(t))))
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)
} else {
- pkgpath := stringStructOf(x.pkgpath)
+ pkgpathstr := x.pkgpath.name()
+ pkgpath := stringStructOf(&pkgpathstr)
namestr := t.name()
name := stringStructOf(&namestr)
dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
iname := i.name.name()
itype := i._type
ipkg := i.name.pkgPath()
- if ipkg == nil {
- ipkg = inter.pkgpath
+ if ipkg == "" {
+ ipkg = inter.pkgpath.name()
}
for ; j < nt; j++ {
t := &xmhdr[j]
if typ.typeOff(t.mtyp) == itype && t.name.name() == iname {
pkgPath := t.name.pkgPath()
- if pkgPath == nil {
- pkgPath = x.pkgpath
+ if pkgPath == "" {
+ pkgPath = x.pkgpath.name()
}
if t.name.isExported() || pkgPath == ipkg {
if m != nil {
package runtime
-import (
- "runtime/internal/sys"
- "unsafe"
-)
+import "unsafe"
// tflag is documented in ../reflect/type.go.
type tflag uint8
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 {
if off == 0 {
return nil
return t.outCount&(1<<15) != 0
}
+type nameOff int32
type typeOff int32
type textOff int32
}
type uncommontype struct {
- pkgpath *string
+ pkgpath name
mcount uint16 // number of methods
moff uint16 // offset from this uncommontype to [mcount]method
}
type interfacetype struct {
typ _type
- pkgpath *string
+ pkgpath name
mhdr []imethod
}
type structtype struct {
typ _type
- pkgPath *string
+ pkgPath name
fields []structfield
}
}
func (n *name) name() (s string) {
+ if n.bytes == nil {
+ return ""
+ }
nl := n.nameLen()
if nl == 0 {
return ""
return s
}
-func (n *name) pkgPath() *string {
- if *n.data(0)&(1<<2) == 0 {
- return nil
+func (n *name) pkgPath() string {
+ if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
+ return ""
}
off := 3 + n.nameLen()
if tl := n.tagLen(); tl > 0 {
off += 2 + tl
}
- off = int(round(uintptr(off), sys.PtrSize))
- return *(**string)(unsafe.Pointer(n.data(off)))
+ var nameOff nameOff
+ 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
if ut == nil || uv == nil {
return false
}
- if !pkgPathEqual(ut.pkgpath, uv.pkgpath) {
+ if ut.pkgpath.name() != uv.pkgpath.name() {
return false
}
}
case kindInterface:
it := (*interfacetype)(unsafe.Pointer(t))
iv := (*interfacetype)(unsafe.Pointer(v))
- if !pkgPathEqual(it.pkgpath, iv.pkgpath) {
+ if it.pkgpath.name() != iv.pkgpath.name() {
return false
}
if len(it.mhdr) != len(iv.mhdr) {
if tm.name.name() != vm.name.name() {
return false
}
- if !pkgPathEqual(tm.name.pkgPath(), vm.name.pkgPath()) {
+ if tm.name.pkgPath() != vm.name.pkgPath() {
return false
}
if !typesEqual(tm._type, vm._type) {
if tf.name.name() != vf.name.name() {
return false
}
- if !pkgPathEqual(tf.name.pkgPath(), vf.name.pkgPath()) {
+ if tf.name.pkgPath() != vf.name.pkgPath() {
return false
}
if !typesEqual(tf.typ, vf.typ) {
return false
}
}
-
-func pkgPathEqual(p, q *string) bool {
- if p == q {
- return true
- }
- if p == nil || q == nil {
- return false
- }
- return *p == *q
-}