]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, cmd/link: more efficient typelink generation
authorshaharko <skohanim@gmail.com>
Wed, 19 Oct 2016 04:33:16 +0000 (07:33 +0300)
committerShahar Kohanim <skohanim@gmail.com>
Tue, 25 Oct 2016 19:44:06 +0000 (19:44 +0000)
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>
src/cmd/compile/internal/gc/reflect.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/obj/sizeof_test.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/link.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/ld/objfile.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/ld/typelink.go [new file with mode: 0644]

index 32909490b62c8893bd478fd2e3d92d825e7e8c4e..1c887ced2519627a0fd4b3533f907f7980686e7a 100644 (file)
@@ -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
 }
index 46d249f88a39edac1a6b426528db5daac756ba71..aa2bbf2b2813c90acc46a85d982fb3268dddb742 100644 (file)
@@ -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
index f8d61cd1c2e4e183ac03fe2182fa7d9f2c6af482..0a269afdca6322cf95a26cceec0324305294f20c 100644 (file)
@@ -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)
index 65028ab4b916d2db012aab92601bf3471dfc9070..391ed37efbe1c37b8432065bda1aabd65b87e521 100644 (file)
@@ -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},
        }
 
index 5460b76c99f4aa32293b6e64957f1ffbdf1f531d..73c0daa77ccfad8caf210ae9a665a491f9409364 100644 (file)
@@ -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))
 
index 696a55849cb4cdbf5e4fc1bc5aec38933f76eb96..7ecc5b1ec2298c1b04762185694420ad2698c8d7 100644 (file)
@@ -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())
                        }
                }
index b6bde4cdfbe6cf87285dce4aeff0949117bdad32..ab7e49b51fb419a8379a0a4882ed5979af1a8fb3 100644 (file)
@@ -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()
index 40adf96f71813bf13648bdf9541afa9d31e4dd50..85af07d5af4554c4b56396152249d2ae0e914aa8 100644 (file)
@@ -201,6 +201,7 @@ func Main() {
        ctxt.textaddress()
        ctxt.pclntab()
        ctxt.findfunctab()
+       ctxt.typelink()
        ctxt.symtab()
        ctxt.dodata()
        ctxt.address()
index ce666dc57bfeca039d643621b975ff2f64fdf301..7626a4fbc18cf599ad98efc416a3a153dfb68708 100644 (file)
@@ -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
        }
index 97c6c2db72f3464a336116b387e21c300acbc8a7..74d2d3d93aa586e98db4711eed0c30ea84ceaaa5 100644 (file)
@@ -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))
diff --git a/src/cmd/link/internal/ld/typelink.go b/src/cmd/link/internal/ld/typelink.go
new file mode 100644 (file)
index 0000000..48a1104
--- /dev/null
@@ -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
+       }
+}