Commit d8d44528 authored by shaharko's avatar shaharko Committed by Shahar Kohanim

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: 's avatarDavid Crawshaw <crawshaw@golang.org>
parent 5a954926
......@@ -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))
......
// 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
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment