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 { ...@@ -937,11 +937,6 @@ func tracksym(t *Type, f *Field) *Sym {
return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg) 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 { func typesymprefix(prefix string, t *Type) *Sym {
p := prefix + "." + t.tconv(FmtLeft) p := prefix + "." + t.tconv(FmtLeft)
s := Pkglookup(p, typepkg) s := Pkglookup(p, typepkg)
...@@ -1338,8 +1333,6 @@ ok: ...@@ -1338,8 +1333,6 @@ ok:
ot = dextratypeData(s, ot, t) ot = dextratypeData(s, ot, t)
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) 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 // The linker will leave a table of all the typelinks for
// types in the binary, so the runtime can find them. // types in the binary, so the runtime can find them.
// //
...@@ -1357,11 +1350,7 @@ ok: ...@@ -1357,11 +1350,7 @@ ok:
keep = true keep = true
} }
} }
if keep { s.Lsym.MakeTypelink = keep
slink := typelinkLSym(t)
dsymptrOffLSym(slink, 0, Linksym(s), 0)
ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
}
return s return s
} }
......
...@@ -330,6 +330,9 @@ type LSym struct { ...@@ -330,6 +330,9 @@ type LSym struct {
Seenglobl bool Seenglobl bool
Onlist 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 // ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type // reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
// can be used through a custom interface), so ReflectMethod may be // can be used through a custom interface), so ReflectMethod may be
......
...@@ -52,7 +52,9 @@ ...@@ -52,7 +52,9 @@
// - type [int] // - type [int]
// - name & version [symref index] // - name & version [symref index]
// - flags [int] // - flags [int]
// 1 dupok // 1<<0 dupok
// 1<<1 local
// 1<<2 add to typelink table
// - size [int] // - size [int]
// - gotype [symref index] // - gotype [symref index]
// - p [data block] // - p [data block]
...@@ -395,6 +397,9 @@ func (w *objWriter) writeSym(s *LSym) { ...@@ -395,6 +397,9 @@ func (w *objWriter) writeSym(s *LSym) {
if s.Local { if s.Local {
flags |= 1 << 1 flags |= 1 << 1
} }
if s.MakeTypelink {
flags |= 1 << 2
}
w.writeInt(flags) w.writeInt(flags)
w.writeInt(s.Size) w.writeInt(s.Size)
w.writeRefIndex(s.Gotype) w.writeRefIndex(s.Gotype)
......
...@@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) { ...@@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Addr{}, 40, 64}, {Addr{}, 40, 64},
{LSym{}, 80, 136}, {LSym{}, 84, 136},
{Prog{}, 144, 224}, {Prog{}, 144, 224},
} }
......
...@@ -1717,15 +1717,10 @@ func (ctxt *Link) dodata() { ...@@ -1717,15 +1717,10 @@ func (ctxt *Link) dodata() {
sect.Align = dataMaxAlign[obj.STYPELINK] sect.Align = dataMaxAlign[obj.STYPELINK]
datsize = Rnd(datsize, int64(sect.Align)) datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize) sect.Vaddr = uint64(datsize)
ctxt.Syms.Lookup("runtime.typelink", 0).Sect = sect typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
ctxt.Syms.Lookup("runtime.etypelink", 0).Sect = sect typelink.Sect = sect
for _, s := range data[obj.STYPELINK] { typelink.Type = obj.RODATA
datsize = aligndatsize(datsize, s) datsize += typelink.Size
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
checkdatsize(ctxt, datsize, obj.STYPELINK) checkdatsize(ctxt, datsize, obj.STYPELINK)
sect.Length = uint64(datsize) - sect.Vaddr sect.Length = uint64(datsize) - sect.Vaddr
...@@ -1909,10 +1904,6 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol, ...@@ -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 // we skip size comparison and fall through to the name
// comparison (conveniently, .got sorts before .toc). // comparison (conveniently, .got sorts before .toc).
key.size = 0 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) symsSort = append(symsSort, key)
...@@ -2235,7 +2226,6 @@ func (ctxt *Link) address() { ...@@ -2235,7 +2226,6 @@ func (ctxt *Link) address() {
var ( var (
text = Segtext.Sect text = Segtext.Sect
rodata = ctxt.Syms.Lookup("runtime.rodata", 0).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 itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
...@@ -2291,8 +2281,6 @@ func (ctxt *Link) address() { ...@@ -2291,8 +2281,6 @@ func (ctxt *Link) address() {
ctxt.xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length)) ctxt.xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
ctxt.xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr)) ctxt.xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
ctxt.xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length)) 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.itablink", obj.SRODATA, int64(itablink.Vaddr))
ctxt.xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length)) ctxt.xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
......
...@@ -110,11 +110,10 @@ func deadcode(ctxt *Link) { ...@@ -110,11 +110,10 @@ func deadcode(ctxt *Link) {
} }
if Buildmode != BuildmodeShared { if Buildmode != BuildmodeShared {
// Keep a typelink or itablink if the symbol it points at is being kept. // Keep a itablink if the symbol it points at is being kept.
// (When BuildmodeShared, always keep typelinks and itablinks.) // (When BuildmodeShared, always keep itablinks.)
for _, s := range ctxt.Syms.Allsym { for _, s := range ctxt.Syms.Allsym {
if strings.HasPrefix(s.Name, "go.typelink.") || if strings.HasPrefix(s.Name, "go.itablink.") {
strings.HasPrefix(s.Name, "go.itablink.") {
s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable()) s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
} }
} }
......
...@@ -105,6 +105,7 @@ const ( ...@@ -105,6 +105,7 @@ const (
AttrOnList AttrOnList
AttrLocal AttrLocal
AttrReflectMethod AttrReflectMethod
AttrMakeTypelink
) )
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
...@@ -119,6 +120,7 @@ func (a Attribute) Hidden() bool { return a&AttrHidden != 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) OnList() bool { return a&AttrOnList != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 } func (a Attribute) Local() bool { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 } func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CgoExport() bool { func (a Attribute) CgoExport() bool {
return a.CgoExportDynamic() || a.CgoExportStatic() return a.CgoExportDynamic() || a.CgoExportStatic()
......
...@@ -201,6 +201,7 @@ func Main() { ...@@ -201,6 +201,7 @@ func Main() {
ctxt.textaddress() ctxt.textaddress()
ctxt.pclntab() ctxt.pclntab()
ctxt.findfunctab() ctxt.findfunctab()
ctxt.typelink()
ctxt.symtab() ctxt.symtab()
ctxt.dodata() ctxt.dodata()
ctxt.address() ctxt.address()
......
...@@ -54,7 +54,9 @@ package ld ...@@ -54,7 +54,9 @@ package ld
// - type [int] // - type [int]
// - name & version [symref index] // - name & version [symref index]
// - flags [int] // - flags [int]
// 1 dupok // 1<<0 dupok
// 1<<1 local
// 1<<2 add to typelink table
// - size [int] // - size [int]
// - gotype [symref index] // - gotype [symref index]
// - p [data block] // - p [data block]
...@@ -264,6 +266,7 @@ func (r *objReader) readSym() { ...@@ -264,6 +266,7 @@ func (r *objReader) readSym() {
flags := r.readInt() flags := r.readInt()
dupok := flags&1 != 0 dupok := flags&1 != 0
local := flags&2 != 0 local := flags&2 != 0
makeTypelink := flags&4 != 0
size := r.readInt() size := r.readInt()
typ := r.readSymIndex() typ := r.readSymIndex()
data := r.readData() data := r.readData()
...@@ -315,6 +318,7 @@ overwrite: ...@@ -315,6 +318,7 @@ overwrite:
s.Size = int64(size) s.Size = int64(size)
} }
s.Attr.Set(AttrLocal, local) s.Attr.Set(AttrLocal, local)
s.Attr.Set(AttrMakeTypelink, makeTypelink)
if typ != nil { if typ != nil {
s.Gotype = typ s.Gotype = typ
} }
......
...@@ -366,8 +366,6 @@ func (ctxt *Link) symtab() { ...@@ -366,8 +366,6 @@ func (ctxt *Link) symtab() {
ctxt.xdefine("runtime.text", obj.STEXT, 0) ctxt.xdefine("runtime.text", obj.STEXT, 0)
ctxt.xdefine("runtime.etext", 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.itablink", obj.SRODATA, 0)
ctxt.xdefine("runtime.eitablink", obj.SRODATA, 0) ctxt.xdefine("runtime.eitablink", obj.SRODATA, 0)
ctxt.xdefine("runtime.rodata", obj.SRODATA, 0) ctxt.xdefine("runtime.rodata", obj.SRODATA, 0)
...@@ -449,9 +447,6 @@ func (ctxt *Link) symtab() { ...@@ -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 := ctxt.Syms.Lookup("runtime.itablink", 0)
symitablink.Type = obj.SITABLINK symitablink.Type = obj.SITABLINK
...@@ -461,7 +456,6 @@ func (ctxt *Link) symtab() { ...@@ -461,7 +456,6 @@ func (ctxt *Link) symtab() {
symt.Size = 0 symt.Size = 0
symt.Attr |= AttrReachable symt.Attr |= AttrReachable
ntypelinks := 0
nitablinks := 0 nitablinks := 0
// assign specific types so that they sort together. // assign specific types so that they sort together.
...@@ -491,12 +485,6 @@ func (ctxt *Link) symtab() { ...@@ -491,12 +485,6 @@ func (ctxt *Link) symtab() {
// names, as they can be referred to by a section offset. // names, as they can be referred to by a section offset.
s.Type = obj.STYPERELRO 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."): case strings.HasPrefix(s.Name, "go.itablink."):
nitablinks++ nitablinks++
s.Type = obj.SITABLINK s.Type = obj.SITABLINK
...@@ -590,9 +578,11 @@ func (ctxt *Link) symtab() { ...@@ -590,9 +578,11 @@ func (ctxt *Link) symtab() {
adduint(ctxt, moduledata, uint64(nsections)) adduint(ctxt, moduledata, uint64(nsections))
// The typelinks slice // The typelinks slice
Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.typelink", 0)) typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
adduint(ctxt, moduledata, uint64(ntypelinks)) ntypelinks := uint64(typelinkSym.Size) / 4
adduint(ctxt, moduledata, uint64(ntypelinks)) Addaddr(ctxt, moduledata, typelinkSym)
adduint(ctxt, moduledata, ntypelinks)
adduint(ctxt, moduledata, ntypelinks)
// The itablinks slice // The itablinks slice
Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0)) Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0))
adduint(ctxt, moduledata, uint64(nitablinks)) 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