mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile, cmd/link: more efficient typelink generation
Instead of generating typelink symbols in the compiler mark types that should have typelinks with a flag. The linker detects this flag and adds the marked types to the typelink table. name old s/op new s/op delta LinkCmdCompile 0.27 ± 6% 0.25 ± 6% -6.93% (p=0.000 n=97+98) LinkCmdGo 0.30 ± 5% 0.29 ±10% -4.22% (p=0.000 n=97+99) name old MaxRSS new MaxRSS delta LinkCmdCompile 112k ± 3% 106k ± 2% -4.85% (p=0.000 n=100+100) LinkCmdGo 107k ± 3% 103k ± 3% -3.00% (p=0.000 n=100+100) Change-Id: Ic95dd4b0101e90c1fa262c9c6c03a2028d6b3623 Reviewed-on: https://go-review.googlesource.com/31772 Run-TryBot: Shahar Kohanim <skohanim@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
5a9549260d
commit
d8d445280a
11 changed files with 80 additions and 50 deletions
|
|
@ -937,11 +937,6 @@ func tracksym(t *Type, f *Field) *Sym {
|
|||
return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg)
|
||||
}
|
||||
|
||||
func typelinkLSym(t *Type) *obj.LSym {
|
||||
name := "go.typelink." + t.tconv(FmtLeft) // complete, unambiguous type name
|
||||
return obj.Linklookup(Ctxt, name, 0)
|
||||
}
|
||||
|
||||
func typesymprefix(prefix string, t *Type) *Sym {
|
||||
p := prefix + "." + t.tconv(FmtLeft)
|
||||
s := Pkglookup(p, typepkg)
|
||||
|
|
@ -1338,8 +1333,6 @@ ok:
|
|||
ot = dextratypeData(s, ot, t)
|
||||
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
|
||||
|
||||
// generate typelink.foo pointing at s = type.foo.
|
||||
//
|
||||
// The linker will leave a table of all the typelinks for
|
||||
// types in the binary, so the runtime can find them.
|
||||
//
|
||||
|
|
@ -1357,11 +1350,7 @@ ok:
|
|||
keep = true
|
||||
}
|
||||
}
|
||||
if keep {
|
||||
slink := typelinkLSym(t)
|
||||
dsymptrOffLSym(slink, 0, Linksym(s), 0)
|
||||
ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
|
||||
}
|
||||
s.Lsym.MakeTypelink = keep
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,6 +330,9 @@ type LSym struct {
|
|||
Seenglobl bool
|
||||
Onlist bool
|
||||
|
||||
// MakeTypelink means that the type should have an entry in the typelink table.
|
||||
MakeTypelink bool
|
||||
|
||||
// ReflectMethod means the function may call reflect.Type.Method or
|
||||
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
|
||||
// can be used through a custom interface), so ReflectMethod may be
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@
|
|||
// - type [int]
|
||||
// - name & version [symref index]
|
||||
// - flags [int]
|
||||
// 1 dupok
|
||||
// 1<<0 dupok
|
||||
// 1<<1 local
|
||||
// 1<<2 add to typelink table
|
||||
// - size [int]
|
||||
// - gotype [symref index]
|
||||
// - p [data block]
|
||||
|
|
@ -395,6 +397,9 @@ func (w *objWriter) writeSym(s *LSym) {
|
|||
if s.Local {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
if s.MakeTypelink {
|
||||
flags |= 1 << 2
|
||||
}
|
||||
w.writeInt(flags)
|
||||
w.writeInt(s.Size)
|
||||
w.writeRefIndex(s.Gotype)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) {
|
|||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Addr{}, 40, 64},
|
||||
{LSym{}, 80, 136},
|
||||
{LSym{}, 84, 136},
|
||||
{Prog{}, 144, 224},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1717,15 +1717,10 @@ func (ctxt *Link) dodata() {
|
|||
sect.Align = dataMaxAlign[obj.STYPELINK]
|
||||
datsize = Rnd(datsize, int64(sect.Align))
|
||||
sect.Vaddr = uint64(datsize)
|
||||
ctxt.Syms.Lookup("runtime.typelink", 0).Sect = sect
|
||||
ctxt.Syms.Lookup("runtime.etypelink", 0).Sect = sect
|
||||
for _, s := range data[obj.STYPELINK] {
|
||||
datsize = aligndatsize(datsize, s)
|
||||
s.Sect = sect
|
||||
s.Type = obj.SRODATA
|
||||
s.Value = int64(uint64(datsize) - sect.Vaddr)
|
||||
datsize += s.Size
|
||||
}
|
||||
typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
typelink.Sect = sect
|
||||
typelink.Type = obj.RODATA
|
||||
datsize += typelink.Size
|
||||
checkdatsize(ctxt, datsize, obj.STYPELINK)
|
||||
sect.Length = uint64(datsize) - sect.Vaddr
|
||||
|
||||
|
|
@ -1909,10 +1904,6 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
|
|||
// we skip size comparison and fall through to the name
|
||||
// comparison (conveniently, .got sorts before .toc).
|
||||
key.size = 0
|
||||
case obj.STYPELINK:
|
||||
// Sort typelinks by the rtype.string field so the reflect
|
||||
// package can binary search type links.
|
||||
key.name = string(decodetypeStr(s.R[0].Sym))
|
||||
}
|
||||
|
||||
symsSort = append(symsSort, key)
|
||||
|
|
@ -2235,7 +2226,6 @@ func (ctxt *Link) address() {
|
|||
var (
|
||||
text = Segtext.Sect
|
||||
rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
|
||||
typelink = ctxt.Syms.Lookup("runtime.typelink", 0).Sect
|
||||
itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
|
||||
symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
|
||||
pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
|
||||
|
|
@ -2291,8 +2281,6 @@ func (ctxt *Link) address() {
|
|||
ctxt.xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
|
||||
ctxt.xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
|
||||
ctxt.xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
|
||||
ctxt.xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
|
||||
ctxt.xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
|
||||
ctxt.xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
|
||||
ctxt.xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
|
||||
|
||||
|
|
|
|||
|
|
@ -110,11 +110,10 @@ func deadcode(ctxt *Link) {
|
|||
}
|
||||
|
||||
if Buildmode != BuildmodeShared {
|
||||
// Keep a typelink or itablink if the symbol it points at is being kept.
|
||||
// (When BuildmodeShared, always keep typelinks and itablinks.)
|
||||
// Keep a itablink if the symbol it points at is being kept.
|
||||
// (When BuildmodeShared, always keep itablinks.)
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.typelink.") ||
|
||||
strings.HasPrefix(s.Name, "go.itablink.") {
|
||||
if strings.HasPrefix(s.Name, "go.itablink.") {
|
||||
s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ const (
|
|||
AttrOnList
|
||||
AttrLocal
|
||||
AttrReflectMethod
|
||||
AttrMakeTypelink
|
||||
)
|
||||
|
||||
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
|
||||
|
|
@ -119,6 +120,7 @@ func (a Attribute) Hidden() bool { return a&AttrHidden != 0 }
|
|||
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
|
||||
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
|
||||
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
|
||||
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
|
||||
|
||||
func (a Attribute) CgoExport() bool {
|
||||
return a.CgoExportDynamic() || a.CgoExportStatic()
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ func Main() {
|
|||
ctxt.textaddress()
|
||||
ctxt.pclntab()
|
||||
ctxt.findfunctab()
|
||||
ctxt.typelink()
|
||||
ctxt.symtab()
|
||||
ctxt.dodata()
|
||||
ctxt.address()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ package ld
|
|||
// - type [int]
|
||||
// - name & version [symref index]
|
||||
// - flags [int]
|
||||
// 1 dupok
|
||||
// 1<<0 dupok
|
||||
// 1<<1 local
|
||||
// 1<<2 add to typelink table
|
||||
// - size [int]
|
||||
// - gotype [symref index]
|
||||
// - p [data block]
|
||||
|
|
@ -264,6 +266,7 @@ func (r *objReader) readSym() {
|
|||
flags := r.readInt()
|
||||
dupok := flags&1 != 0
|
||||
local := flags&2 != 0
|
||||
makeTypelink := flags&4 != 0
|
||||
size := r.readInt()
|
||||
typ := r.readSymIndex()
|
||||
data := r.readData()
|
||||
|
|
@ -315,6 +318,7 @@ overwrite:
|
|||
s.Size = int64(size)
|
||||
}
|
||||
s.Attr.Set(AttrLocal, local)
|
||||
s.Attr.Set(AttrMakeTypelink, makeTypelink)
|
||||
if typ != nil {
|
||||
s.Gotype = typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,8 +366,6 @@ func (ctxt *Link) symtab() {
|
|||
ctxt.xdefine("runtime.text", obj.STEXT, 0)
|
||||
|
||||
ctxt.xdefine("runtime.etext", obj.STEXT, 0)
|
||||
ctxt.xdefine("runtime.typelink", obj.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.etypelink", obj.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.itablink", obj.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.eitablink", obj.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.rodata", obj.SRODATA, 0)
|
||||
|
|
@ -449,9 +447,6 @@ func (ctxt *Link) symtab() {
|
|||
}
|
||||
}
|
||||
|
||||
symtypelink := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
symtypelink.Type = obj.STYPELINK
|
||||
|
||||
symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
|
||||
symitablink.Type = obj.SITABLINK
|
||||
|
||||
|
|
@ -461,7 +456,6 @@ func (ctxt *Link) symtab() {
|
|||
symt.Size = 0
|
||||
symt.Attr |= AttrReachable
|
||||
|
||||
ntypelinks := 0
|
||||
nitablinks := 0
|
||||
|
||||
// assign specific types so that they sort together.
|
||||
|
|
@ -491,12 +485,6 @@ func (ctxt *Link) symtab() {
|
|||
// names, as they can be referred to by a section offset.
|
||||
s.Type = obj.STYPERELRO
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.typelink."):
|
||||
ntypelinks++
|
||||
s.Type = obj.STYPELINK
|
||||
s.Attr |= AttrHidden
|
||||
s.Outer = symtypelink
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.itablink."):
|
||||
nitablinks++
|
||||
s.Type = obj.SITABLINK
|
||||
|
|
@ -590,9 +578,11 @@ func (ctxt *Link) symtab() {
|
|||
adduint(ctxt, moduledata, uint64(nsections))
|
||||
|
||||
// The typelinks slice
|
||||
Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.typelink", 0))
|
||||
adduint(ctxt, moduledata, uint64(ntypelinks))
|
||||
adduint(ctxt, moduledata, uint64(ntypelinks))
|
||||
typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
ntypelinks := uint64(typelinkSym.Size) / 4
|
||||
Addaddr(ctxt, moduledata, typelinkSym)
|
||||
adduint(ctxt, moduledata, ntypelinks)
|
||||
adduint(ctxt, moduledata, ntypelinks)
|
||||
// The itablinks slice
|
||||
Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0))
|
||||
adduint(ctxt, moduledata, uint64(nitablinks))
|
||||
|
|
|
|||
49
src/cmd/link/internal/ld/typelink.go
Normal file
49
src/cmd/link/internal/ld/typelink.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"cmd/internal/obj"
|
||||
)
|
||||
|
||||
type byTypeStr []typelinkSortKey
|
||||
|
||||
type typelinkSortKey struct {
|
||||
TypeStr string
|
||||
Type *Symbol
|
||||
}
|
||||
|
||||
func (s byTypeStr) Less(i, j int) bool { return s[i].TypeStr < s[j].TypeStr }
|
||||
func (s byTypeStr) Len() int { return len(s) }
|
||||
func (s byTypeStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// typelink generates the typelink table which is used by reflect.typelinks().
|
||||
// Types that should be added to the typelinks table are marked with the
|
||||
// MakeTypelink attribute by the compiler.
|
||||
func (ctxt *Link) typelink() {
|
||||
typelinks := byTypeStr{}
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if s.Attr.Reachable() && s.Attr.MakeTypelink() {
|
||||
typelinks = append(typelinks, typelinkSortKey{decodetypeStr(s), s})
|
||||
}
|
||||
}
|
||||
sort.Sort(typelinks)
|
||||
|
||||
tl := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
tl.Type = obj.STYPELINK
|
||||
tl.Attr |= AttrReachable | AttrLocal
|
||||
tl.Size = int64(4 * len(typelinks))
|
||||
tl.P = make([]byte, tl.Size)
|
||||
tl.R = make([]Reloc, len(typelinks))
|
||||
for i, s := range typelinks {
|
||||
r := &tl.R[i]
|
||||
r.Sym = s.Type
|
||||
r.Off = int32(i * 4)
|
||||
r.Siz = 4
|
||||
r.Type = obj.R_ADDROFF
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue