]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: experiment new reloc accessors in deadcode pass
authorCherry Zhang <cherryyz@google.com>
Thu, 5 Mar 2020 21:43:37 +0000 (16:43 -0500)
committerCherry Zhang <cherryyz@google.com>
Fri, 13 Mar 2020 01:19:15 +0000 (01:19 +0000)
There is a small speedup:

(linking cmd/compile)

name       old time/op    new time/op    delta
Deadcode     57.1ms ± 1%    53.5ms ± 1%   -6.44%  (p=0.008 n=5+5)

With this, we don't need a slice to read the relocations, reduce
some allocations.

name       old alloc/op   new alloc/op   delta
Deadcode     4.16MB ± 0%    3.84MB ± 0%   -7.85%  (p=0.008 n=5+5)

Change-Id: Icd41c05682ba3f293a8cb9d2fe818e39d7276e5a
Reviewed-on: https://go-review.googlesource.com/c/go/+/222244
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/internal/goobj2/objfile.go
src/cmd/link/internal/ld/deadcode2.go
src/cmd/link/internal/ld/decodesym2.go
src/cmd/link/internal/loader/loader.go

index 6d9b0f9e8d83f856eb6fbb93ad44bc37b9596263..d5a9b4aa8cd193c340ebc8667e7be0c7db70d9f4 100644 (file)
@@ -321,6 +321,15 @@ func (r *Reloc2) Sym() SymRef {
        return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
 }
 
+func (r *Reloc2) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
+       binary.LittleEndian.PutUint32(r[:], uint32(off))
+       r[4] = size
+       r[5] = typ
+       binary.LittleEndian.PutUint64(r[6:], uint64(add))
+       binary.LittleEndian.PutUint32(r[14:], sym.PkgIdx)
+       binary.LittleEndian.PutUint32(r[18:], sym.SymIdx)
+}
+
 // Aux symbol info.
 type Aux struct {
        Type uint8
index 4733f47446f69c3b65dd22c199aeee4755acc56a..a7a41e3e16d5c32e38aee7acac5a48d47463b515 100644 (file)
@@ -37,7 +37,6 @@ type deadcodePass2 struct {
        ctxt *Link
        ldr  *loader.Loader
        wq   workQueue
-       rtmp []loader.Reloc
 
        ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
        markableMethods []methodref2       // methods of reached types
@@ -86,9 +85,9 @@ func (d *deadcodePass2) init() {
                        // but we do keep the symbols it refers to.
                        exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
                        if exportsIdx != 0 {
-                               d.ReadRelocSyms(exportsIdx)
-                               for i := 0; i < len(d.rtmp); i++ {
-                                       d.mark(d.rtmp[i].Sym, 0)
+                               relocs := d.ldr.Relocs(exportsIdx)
+                               for i := 0; i < relocs.Count; i++ {
+                                       d.mark(relocs.At2(i).Sym(), 0)
                                }
                        }
                }
@@ -119,7 +118,6 @@ func (d *deadcodePass2) init() {
 }
 
 func (d *deadcodePass2) flood() {
-       symRelocs := []loader.Reloc{}
        auxSyms := []loader.Sym{}
        for !d.wq.empty() {
                symIdx := d.wq.pop()
@@ -128,22 +126,11 @@ func (d *deadcodePass2) flood() {
 
                isgotype := d.ldr.IsGoType(symIdx)
                relocs := d.ldr.Relocs(symIdx)
-               // For non-type symbols, we only need the target and the reloc
-               // type, so don't read other fields.
-               // For type symbols we may need all fields for interface
-               // satisfaction check.
-               // TODO: we don't even need the reloc type for non-type non-dwarf
-               // symbols.
-               if isgotype {
-                       symRelocs = relocs.ReadAll(symRelocs)
-               } else {
-                       symRelocs = relocs.ReadSyms(symRelocs)
-               }
 
                if isgotype {
                        p := d.ldr.Data(symIdx)
                        if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
-                               for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs) {
+                               for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
                                        if d.ctxt.Debugvlog > 1 {
                                                d.ctxt.Logf("reached iface method: %s\n", sig)
                                        }
@@ -154,11 +141,12 @@ func (d *deadcodePass2) flood() {
 
                var methods []methodref2
                for i := 0; i < relocs.Count; i++ {
-                       r := symRelocs[i]
-                       if r.Type == objabi.R_WEAKADDROFF {
+                       r := relocs.At2(i)
+                       t := r.Type()
+                       if t == objabi.R_WEAKADDROFF {
                                continue
                        }
-                       if r.Type == objabi.R_METHODOFF {
+                       if t == objabi.R_METHODOFF {
                                if i+2 >= relocs.Count {
                                        panic("expect three consecutive R_METHODOFF relocs")
                                }
@@ -166,13 +154,13 @@ func (d *deadcodePass2) flood() {
                                i += 2
                                continue
                        }
-                       if r.Type == objabi.R_USETYPE {
+                       if t == objabi.R_USETYPE {
                                // type symbol used for DWARF. we need to load the symbol but it may not
                                // be otherwise reachable in the program.
                                // do nothing for now as we still load all type symbols.
                                continue
                        }
-                       d.mark(r.Sym, symIdx)
+                       d.mark(r.Sym(), symIdx)
                }
                auxSyms = d.ldr.ReadAuxSyms(symIdx, auxSyms)
                for i := 0; i < len(auxSyms); i++ {
@@ -194,7 +182,7 @@ func (d *deadcodePass2) flood() {
                        // Decode runtime type information for type methods
                        // to help work out which methods can be called
                        // dynamically via interfaces.
-                       methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs)
+                       methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs)
                        if len(methods) != len(methodsigs) {
                                panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
                        }
@@ -227,10 +215,10 @@ func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
 }
 
 func (d *deadcodePass2) markMethod(m methodref2) {
-       d.ReadRelocSyms(m.src)
-       d.mark(d.rtmp[m.r].Sym, m.src)
-       d.mark(d.rtmp[m.r+1].Sym, m.src)
-       d.mark(d.rtmp[m.r+2].Sym, m.src)
+       relocs := d.ldr.Relocs(m.src)
+       d.mark(relocs.At2(m.r).Sym(), m.src)
+       d.mark(relocs.At2(m.r+1).Sym(), m.src)
+       d.mark(relocs.At2(m.r+2).Sym(), m.src)
 }
 
 func deadcode2(ctxt *Link) {
@@ -313,15 +301,15 @@ func (m methodref2) isExported() bool {
 // the function type.
 //
 // Conveniently this is the layout of both runtime.method and runtime.imethod.
-func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, off, size, count int) []methodsig {
+func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, off, size, count int) []methodsig {
        var buf bytes.Buffer
        var methods []methodsig
        for i := 0; i < count; i++ {
-               buf.WriteString(decodetypeName2(ldr, symIdx, symRelocs, off))
-               mtypSym := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off+4))
+               buf.WriteString(decodetypeName3(ldr, symIdx, relocs, off))
+               mtypSym := decodeRelocSym3(ldr, symIdx, relocs, int32(off+4))
                // FIXME: add some sort of caching here, since we may see some of the
                // same symbols over time for param types.
-               d.ReadRelocs(mtypSym)
+               mrelocs := ldr.Relocs(mtypSym)
                mp := ldr.Data(mtypSym)
 
                buf.WriteRune('(')
@@ -330,7 +318,7 @@ func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, sym
                        if i > 0 {
                                buf.WriteString(", ")
                        }
-                       a := decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
+                       a := decodetypeFuncInType3(ldr, arch, mtypSym, &mrelocs, i)
                        buf.WriteString(ldr.SymName(a))
                }
                buf.WriteString(") (")
@@ -339,7 +327,7 @@ func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, sym
                        if i > 0 {
                                buf.WriteString(", ")
                        }
-                       a := decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
+                       a := decodetypeFuncOutType3(ldr, arch, mtypSym, &mrelocs, i)
                        buf.WriteString(ldr.SymName(a))
                }
                buf.WriteRune(')')
@@ -351,25 +339,26 @@ func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, sym
        return methods
 }
 
-func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
+func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
        p := ldr.Data(symIdx)
        if decodetypeKind(arch, p)&kindMask != kindInterface {
                panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
        }
-       rel := decodeReloc2(ldr, symIdx, symRelocs, int32(commonsize(arch)+arch.PtrSize))
-       if rel.Sym == 0 {
+       rel := decodeReloc3(ldr, symIdx, relocs, int32(commonsize(arch)+arch.PtrSize))
+       s := rel.Sym()
+       if s == 0 {
                return nil
        }
-       if rel.Sym != symIdx {
+       if s != symIdx {
                panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx)))
        }
-       off := int(rel.Add) // array of reflect.imethod values
+       off := int(rel.Add()) // array of reflect.imethod values
        numMethods := int(decodetypeIfaceMethodCount(arch, p))
        sizeofIMethod := 4 + 4
-       return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofIMethod, numMethods)
+       return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
 }
 
-func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
+func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
        p := ldr.Data(symIdx)
        if !decodetypeHasUncommon(arch, p) {
                panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
@@ -400,19 +389,5 @@ func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, s
        moff := int(decodeInuxi(arch, p[off+4+2+2:], 4))
        off += moff                // offset to array of reflect.method values
        const sizeofMethod = 4 * 4 // sizeof reflect.method in program
-       return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofMethod, mcount)
-}
-
-// readRelocs reads the relocations for the specified symbol into the
-// deadcode relocs work array. Use with care, since the work array
-// is a singleton.
-func (d *deadcodePass2) ReadRelocs(symIdx loader.Sym) {
-       relocs := d.ldr.Relocs(symIdx)
-       d.rtmp = relocs.ReadAll(d.rtmp)
-}
-
-// Like ReadRelocs, but only reads target symbols.
-func (d *deadcodePass2) ReadRelocSyms(symIdx loader.Sym) {
-       relocs := d.ldr.Relocs(symIdx)
-       d.rtmp = relocs.ReadSyms(d.rtmp)
+       return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofMethod, mcount)
 }
index 78967406bfbcbf58796167c7cfb49ed50b87896a..e93cc91a9f1352daf62835377689e9a2a15baf45 100644 (file)
@@ -25,10 +25,24 @@ func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Relo
        return loader.Reloc{}
 }
 
+func decodeReloc3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Reloc2 {
+       for j := 0; j < relocs.Count; j++ {
+               rel := relocs.At2(j)
+               if rel.Off() == off {
+                       return rel
+               }
+       }
+       return loader.Reloc2{}
+}
+
 func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
        return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
 }
 
+func decodeRelocSym3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Sym {
+       return decodeReloc3(ldr, symIdx, relocs, off).Sym()
+}
+
 // decodetypeName2 decodes the name from a reflect.name.
 func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
        r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
@@ -41,6 +55,17 @@ func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.R
        return string(data[3 : 3+namelen])
 }
 
+func decodetypeName3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) string {
+       r := decodeRelocSym3(ldr, symIdx, relocs, int32(off))
+       if r == 0 {
+               return ""
+       }
+
+       data := ldr.Data(r)
+       namelen := int(uint16(data[1])<<8 | uint16(data[2]))
+       return string(data[3 : 3+namelen])
+}
+
 func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
        uadd := commonsize(arch) + 4
        if arch.PtrSize == 8 {
@@ -52,10 +77,25 @@ func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym
        return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
 }
 
+func decodetypeFuncInType3(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
+       uadd := commonsize(arch) + 4
+       if arch.PtrSize == 8 {
+               uadd += 4
+       }
+       if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
+               uadd += uncommonSize()
+       }
+       return decodeRelocSym3(ldr, symIdx, relocs, int32(uadd+i*arch.PtrSize))
+}
+
 func decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
        return decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
 }
 
+func decodetypeFuncOutType3(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
+       return decodetypeFuncInType3(ldr, arch, symIdx, relocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
+}
+
 func decodetypeArrayElem2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
        // FIXME: it's inefficient to read the relocations each time. Add some
        // sort of cache here, or pass in the relocs. Alternatively we could
index 979d94402ee150e2cb2176f376cad10cd28c8329..102fee5a41ae5b57ec2658e3dba226a1e4ae2fa4 100644 (file)
@@ -520,6 +520,12 @@ func (l *Loader) resolve(r *oReader, s goobj2.SymRef) Sym {
        var rr *oReader
        switch p := s.PkgIdx; p {
        case goobj2.PkgIdxInvalid:
+               // {0, X} with non-zero X is never a valid sym reference from a Go object.
+               // We steal this space for symbol references from external objects.
+               // In this case, X is just the global index.
+               if l.isExtReader(r) {
+                       return Sym(s.SymIdx)
+               }
                if s.SymIdx != 0 {
                        panic("bad sym ref")
                }
@@ -1448,10 +1454,14 @@ func (relocs *Relocs) At(j int) Reloc {
 
 func (relocs *Relocs) At2(j int) Reloc2 {
        if relocs.l.isExtReader(relocs.r) {
-               // TODO: implement this. How? Maybe we can construct the reloc
-               // data for external symbols in the same byte form as the one
-               // in the object file?
-               panic("not implemented")
+               pp := relocs.l.payloads[relocs.li]
+               r := pp.relocs[j]
+               // XXX populate a goobj2.Reloc from external reloc record.
+               // Ugly. Maybe we just want to use this format to store the
+               // reloc record in the first place?
+               var b goobj2.Reloc2
+               b.Set(r.Off, r.Size, uint8(r.Type), r.Add, goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(r.Sym)})
+               return Reloc2{&b, relocs.r, relocs.l}
        }
        return Reloc2{relocs.r.Reloc2(relocs.li, j), relocs.r, relocs.l}
 }