]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: rename deadcode2 to deadcode
authorJeremy Faller <jeremy@golang.org>
Mon, 20 Apr 2020 16:13:42 +0000 (12:13 -0400)
committerJeremy Faller <jeremy@golang.org>
Mon, 20 Apr 2020 18:29:24 +0000 (18:29 +0000)
deadcode's been completely replaced. Make its death official.

Change-Id: I85f1e3968463f216b8bce2fb7217c3b51641939f
Reviewed-on: https://go-review.googlesource.com/c/go/+/229002
Run-TryBot: Jeremy Faller <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/deadcode2.go [deleted file]
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/loader/loader.go

index ae676935fc0bccd2954a5a7e40757385bd5b3667..26c468c7a5973d554f50261f381c2599bd16c53d 100644 (file)
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2019 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 (
+       "bytes"
+       "cmd/internal/objabi"
+       "cmd/internal/sys"
+       "cmd/link/internal/loader"
        "cmd/link/internal/sym"
+       "container/heap"
+       "fmt"
+       "unicode"
 )
 
+var _ = fmt.Print
+
+type workQueue []loader.Sym
+
+// Implement container/heap.Interface.
+func (q *workQueue) Len() int           { return len(*q) }
+func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
+func (q *workQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
+func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
+func (q *workQueue) Pop() interface{}   { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
+
+// Functions for deadcode pass to use.
+// Deadcode pass should call push/pop, not Push/Pop.
+func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
+func (q *workQueue) pop() loader.Sym   { return heap.Pop(q).(loader.Sym) }
+func (q *workQueue) empty() bool       { return len(*q) == 0 }
+
+type deadcodePass struct {
+       ctxt *Link
+       ldr  *loader.Loader
+       wq   workQueue
+
+       ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
+       markableMethods []methodref2       // methods of reached types
+       reflectSeen     bool               // whether we have seen a reflect method call
+}
+
+func (d *deadcodePass) init() {
+       d.ldr.InitReachable()
+       d.ifaceMethod = make(map[methodsig]bool)
+       if d.ctxt.Reachparent != nil {
+               d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
+       }
+       heap.Init(&d.wq)
+
+       if d.ctxt.BuildMode == BuildModeShared {
+               // Mark all symbols defined in this library as reachable when
+               // building a shared library.
+               n := d.ldr.NDef()
+               for i := 1; i < n; i++ {
+                       s := loader.Sym(i)
+                       d.mark(s, 0)
+               }
+               return
+       }
+
+       var names []string
+
+       // In a normal binary, start at main.main and the init
+       // functions and mark what is reachable from there.
+       if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+               names = append(names, "main.main", "main..inittask")
+       } else {
+               // The external linker refers main symbol directly.
+               if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+                       if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
+                               *flagEntrySymbol = "_main"
+                       } else {
+                               *flagEntrySymbol = "main"
+                       }
+               }
+               names = append(names, *flagEntrySymbol)
+               if d.ctxt.BuildMode == BuildModePlugin {
+                       names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
+
+                       // We don't keep the go.plugin.exports symbol,
+                       // but we do keep the symbols it refers to.
+                       exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
+                       if exportsIdx != 0 {
+                               relocs := d.ldr.Relocs(exportsIdx)
+                               for i := 0; i < relocs.Count(); i++ {
+                                       d.mark(relocs.At2(i).Sym(), 0)
+                               }
+                       }
+               }
+       }
+
+       dynexpMap := d.ctxt.cgo_export_dynamic
+       if d.ctxt.LinkMode == LinkExternal {
+               dynexpMap = d.ctxt.cgo_export_static
+       }
+       for exp := range dynexpMap {
+               names = append(names, exp)
+       }
+
+       for _, name := range names {
+               // Mark symbol as a data/ABI0 symbol.
+               d.mark(d.ldr.Lookup(name, 0), 0)
+               // Also mark any Go functions (internal ABI).
+               d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
+       }
+}
+
+func (d *deadcodePass) flood() {
+       for !d.wq.empty() {
+               symIdx := d.wq.pop()
+
+               d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
+
+               isgotype := d.ldr.IsGoType(symIdx)
+               relocs := d.ldr.Relocs(symIdx)
+
+               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, &relocs) {
+                                       if d.ctxt.Debugvlog > 1 {
+                                               d.ctxt.Logf("reached iface method: %s\n", sig)
+                                       }
+                                       d.ifaceMethod[sig] = true
+                               }
+                       }
+               }
+
+               var methods []methodref2
+               for i := 0; i < relocs.Count(); i++ {
+                       r := relocs.At2(i)
+                       t := r.Type()
+                       if t == objabi.R_WEAKADDROFF {
+                               continue
+                       }
+                       if t == objabi.R_METHODOFF {
+                               if i+2 >= relocs.Count() {
+                                       panic("expect three consecutive R_METHODOFF relocs")
+                               }
+                               methods = append(methods, methodref2{src: symIdx, r: i})
+                               i += 2
+                               continue
+                       }
+                       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)
+               }
+               naux := d.ldr.NAux(symIdx)
+               for i := 0; i < naux; i++ {
+                       d.mark(d.ldr.Aux2(symIdx, i).Sym(), symIdx)
+               }
+               // Some host object symbols have an outer object, which acts like a
+               // "carrier" symbol, or it holds all the symbols for a particular
+               // section. We need to mark all "referenced" symbols from that carrier,
+               // so we make sure we're pulling in all outer symbols, and their sub
+               // symbols. This is not ideal, and these carrier/section symbols could
+               // be removed.
+               if d.ldr.IsExternal(symIdx) {
+                       d.mark(d.ldr.OuterSym(symIdx), symIdx)
+                       d.mark(d.ldr.SubSym(symIdx), symIdx)
+               }
+
+               if len(methods) != 0 {
+                       if !isgotype {
+                               panic("method found on non-type symbol")
+                       }
+                       // 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, &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)))
+                       }
+                       for i, m := range methodsigs {
+                               methods[i].m = m
+                       }
+                       d.markableMethods = append(d.markableMethods, methods...)
+               }
+       }
+}
+
+func (d *deadcodePass) mark(symIdx, parent loader.Sym) {
+       if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
+               d.wq.push(symIdx)
+               d.ldr.SetAttrReachable(symIdx, true)
+               if d.ctxt.Reachparent != nil {
+                       d.ldr.Reachparent[symIdx] = parent
+               }
+               if *flagDumpDep {
+                       to := d.ldr.SymName(symIdx)
+                       if to != "" {
+                               from := "_"
+                               if parent != 0 {
+                                       from = d.ldr.SymName(parent)
+                               }
+                               fmt.Printf("%s -> %s\n", from, to)
+                       }
+               }
+       }
+}
+
+func (d *deadcodePass) markMethod(m methodref2) {
+       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)
+}
+
 // deadcode marks all reachable symbols.
 //
 // The basis of the dead code elimination is a flood fill of symbols,
@@ -42,24 +247,173 @@ import (
 //
 // Any unreached text symbols are removed from ctxt.Textp.
 func deadcode(ctxt *Link) {
-       deadcode2(ctxt)
+       ldr := ctxt.loader
+       d := deadcodePass{ctxt: ctxt, ldr: ldr}
+       d.init()
+       d.flood()
+
+       methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
+       methByNameSym := ldr.Lookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
+
+       if ctxt.DynlinkingGo() {
+               // Exported methods may satisfy interfaces we don't know
+               // about yet when dynamically linking.
+               d.reflectSeen = true
+       }
+
+       for {
+               // Methods might be called via reflection. Give up on
+               // static analysis, mark all exported methods of
+               // all reachable types as reachable.
+               d.reflectSeen = d.reflectSeen || (methSym != 0 && ldr.AttrReachable(methSym)) || (methByNameSym != 0 && ldr.AttrReachable(methByNameSym))
+
+               // Mark all methods that could satisfy a discovered
+               // interface as reachable. We recheck old marked interfaces
+               // as new types (with new methods) may have been discovered
+               // in the last pass.
+               rem := d.markableMethods[:0]
+               for _, m := range d.markableMethods {
+                       if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
+                               d.markMethod(m)
+                       } else {
+                               rem = append(rem, m)
+                       }
+               }
+               d.markableMethods = rem
+
+               if d.wq.empty() {
+                       // No new work was discovered. Done.
+                       break
+               }
+               d.flood()
+       }
+
+       n := ldr.NSym()
+
+       if ctxt.BuildMode != BuildModeShared {
+               // Keep a itablink if the symbol it points at is being kept.
+               // (When BuildModeShared, always keep itablinks.)
+               for i := 1; i < n; i++ {
+                       s := loader.Sym(i)
+                       if ldr.IsItabLink(s) {
+                               relocs := ldr.Relocs(s)
+                               if relocs.Count() > 0 && ldr.AttrReachable(relocs.At2(0).Sym()) {
+                                       ldr.SetAttrReachable(s, true)
+                               }
+                       }
+               }
+       }
 }
 
-// addToTextp populates the context Textp slice (needed in various places
-// in the linker).
-func addToTextp(ctxt *Link) {
-       // Set up ctxt.Textp, based on ctxt.Textp2.
-       textp := make([]*sym.Symbol, 0, len(ctxt.Textp2))
-       haveshlibs := len(ctxt.Shlibs) > 0
-       for _, tsym := range ctxt.Textp2 {
-               sp := ctxt.loader.Syms[tsym]
-               if sp == nil || !ctxt.loader.AttrReachable(tsym) {
-                       panic("should never happen")
+// methodref2 holds the relocations from a receiver type symbol to its
+// method. There are three relocations, one for each of the fields in
+// the reflect.method struct: mtyp, ifn, and tfn.
+type methodref2 struct {
+       m   methodsig
+       src loader.Sym // receiver type symbol
+       r   int        // the index of R_METHODOFF relocations
+}
+
+func (m methodref2) isExported() bool {
+       for _, r := range m.m {
+               return unicode.IsUpper(r)
+       }
+       panic("methodref has no signature")
+}
+
+// decodeMethodSig2 decodes an array of method signature information.
+// Each element of the array is size bytes. The first 4 bytes is a
+// nameOff for the method name, and the next 4 bytes is a typeOff for
+// the function type.
+//
+// Conveniently this is the layout of both runtime.method and runtime.imethod.
+func (d *deadcodePass) 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, relocs, off))
+               mtypSym := decodeRelocSym2(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.
+               mrelocs := ldr.Relocs(mtypSym)
+               mp := ldr.Data(mtypSym)
+
+               buf.WriteRune('(')
+               inCount := decodetypeFuncInCount(arch, mp)
+               for i := 0; i < inCount; i++ {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       a := decodetypeFuncInType2(ldr, arch, mtypSym, &mrelocs, i)
+                       buf.WriteString(ldr.SymName(a))
                }
-               if haveshlibs && sp.Type == sym.SDYNIMPORT {
-                       continue
+               buf.WriteString(") (")
+               outCount := decodetypeFuncOutCount(arch, mp)
+               for i := 0; i < outCount; i++ {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       a := decodetypeFuncOutType2(ldr, arch, mtypSym, &mrelocs, i)
+                       buf.WriteString(ldr.SymName(a))
                }
-               textp = append(textp, sp)
+               buf.WriteRune(')')
+
+               off += size
+               methods = append(methods, methodsig(buf.String()))
+               buf.Reset()
+       }
+       return methods
+}
+
+func (d *deadcodePass) 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, relocs, int32(commonsize(arch)+arch.PtrSize))
+       s := rel.Sym()
+       if s == 0 {
+               return nil
        }
-       ctxt.Textp = textp
+       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
+       numMethods := int(decodetypeIfaceMethodCount(arch, p))
+       sizeofIMethod := 4 + 4
+       return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
+}
+
+func (d *deadcodePass) 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)))
+       }
+       off := commonsize(arch) // reflect.rtype
+       switch decodetypeKind(arch, p) & kindMask {
+       case kindStruct: // reflect.structType
+               off += 4 * arch.PtrSize
+       case kindPtr: // reflect.ptrType
+               off += arch.PtrSize
+       case kindFunc: // reflect.funcType
+               off += arch.PtrSize // 4 bytes, pointer aligned
+       case kindSlice: // reflect.sliceType
+               off += arch.PtrSize
+       case kindArray: // reflect.arrayType
+               off += 3 * arch.PtrSize
+       case kindChan: // reflect.chanType
+               off += 2 * arch.PtrSize
+       case kindMap: // reflect.mapType
+               off += 4*arch.PtrSize + 8
+       case kindInterface: // reflect.interfaceType
+               off += 3 * arch.PtrSize
+       default:
+               // just Sizeof(rtype)
+       }
+
+       mcount := int(decodeInuxi(arch, p[off+4:], 2))
+       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, relocs, off, sizeofMethod, mcount)
 }
diff --git a/src/cmd/link/internal/ld/deadcode2.go b/src/cmd/link/internal/ld/deadcode2.go
deleted file mode 100644 (file)
index 93df626..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-// Copyright 2019 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 (
-       "bytes"
-       "cmd/internal/objabi"
-       "cmd/internal/sys"
-       "cmd/link/internal/loader"
-       "cmd/link/internal/sym"
-       "container/heap"
-       "fmt"
-       "unicode"
-)
-
-var _ = fmt.Print
-
-type workQueue []loader.Sym
-
-// Implement container/heap.Interface.
-func (q *workQueue) Len() int           { return len(*q) }
-func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
-func (q *workQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
-func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
-func (q *workQueue) Pop() interface{}   { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
-
-// Functions for deadcode pass to use.
-// Deadcode pass should call push/pop, not Push/Pop.
-func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
-func (q *workQueue) pop() loader.Sym   { return heap.Pop(q).(loader.Sym) }
-func (q *workQueue) empty() bool       { return len(*q) == 0 }
-
-type deadcodePass2 struct {
-       ctxt *Link
-       ldr  *loader.Loader
-       wq   workQueue
-
-       ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
-       markableMethods []methodref2       // methods of reached types
-       reflectSeen     bool               // whether we have seen a reflect method call
-}
-
-func (d *deadcodePass2) init() {
-       d.ldr.InitReachable()
-       d.ifaceMethod = make(map[methodsig]bool)
-       if d.ctxt.Reachparent != nil {
-               d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
-       }
-       heap.Init(&d.wq)
-
-       if d.ctxt.BuildMode == BuildModeShared {
-               // Mark all symbols defined in this library as reachable when
-               // building a shared library.
-               n := d.ldr.NDef()
-               for i := 1; i < n; i++ {
-                       s := loader.Sym(i)
-                       d.mark(s, 0)
-               }
-               return
-       }
-
-       var names []string
-
-       // In a normal binary, start at main.main and the init
-       // functions and mark what is reachable from there.
-       if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
-               names = append(names, "main.main", "main..inittask")
-       } else {
-               // The external linker refers main symbol directly.
-               if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
-                       if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
-                               *flagEntrySymbol = "_main"
-                       } else {
-                               *flagEntrySymbol = "main"
-                       }
-               }
-               names = append(names, *flagEntrySymbol)
-               if d.ctxt.BuildMode == BuildModePlugin {
-                       names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
-
-                       // We don't keep the go.plugin.exports symbol,
-                       // but we do keep the symbols it refers to.
-                       exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
-                       if exportsIdx != 0 {
-                               relocs := d.ldr.Relocs(exportsIdx)
-                               for i := 0; i < relocs.Count(); i++ {
-                                       d.mark(relocs.At2(i).Sym(), 0)
-                               }
-                       }
-               }
-       }
-
-       dynexpMap := d.ctxt.cgo_export_dynamic
-       if d.ctxt.LinkMode == LinkExternal {
-               dynexpMap = d.ctxt.cgo_export_static
-       }
-       for exp := range dynexpMap {
-               names = append(names, exp)
-       }
-
-       for _, name := range names {
-               // Mark symbol as a data/ABI0 symbol.
-               d.mark(d.ldr.Lookup(name, 0), 0)
-               // Also mark any Go functions (internal ABI).
-               d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
-       }
-}
-
-func (d *deadcodePass2) flood() {
-       for !d.wq.empty() {
-               symIdx := d.wq.pop()
-
-               d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
-
-               isgotype := d.ldr.IsGoType(symIdx)
-               relocs := d.ldr.Relocs(symIdx)
-
-               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, &relocs) {
-                                       if d.ctxt.Debugvlog > 1 {
-                                               d.ctxt.Logf("reached iface method: %s\n", sig)
-                                       }
-                                       d.ifaceMethod[sig] = true
-                               }
-                       }
-               }
-
-               var methods []methodref2
-               for i := 0; i < relocs.Count(); i++ {
-                       r := relocs.At2(i)
-                       t := r.Type()
-                       if t == objabi.R_WEAKADDROFF {
-                               continue
-                       }
-                       if t == objabi.R_METHODOFF {
-                               if i+2 >= relocs.Count() {
-                                       panic("expect three consecutive R_METHODOFF relocs")
-                               }
-                               methods = append(methods, methodref2{src: symIdx, r: i})
-                               i += 2
-                               continue
-                       }
-                       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)
-               }
-               naux := d.ldr.NAux(symIdx)
-               for i := 0; i < naux; i++ {
-                       d.mark(d.ldr.Aux2(symIdx, i).Sym(), symIdx)
-               }
-               // Some host object symbols have an outer object, which acts like a
-               // "carrier" symbol, or it holds all the symbols for a particular
-               // section. We need to mark all "referenced" symbols from that carrier,
-               // so we make sure we're pulling in all outer symbols, and their sub
-               // symbols. This is not ideal, and these carrier/section symbols could
-               // be removed.
-               if d.ldr.IsExternal(symIdx) {
-                       d.mark(d.ldr.OuterSym(symIdx), symIdx)
-                       d.mark(d.ldr.SubSym(symIdx), symIdx)
-               }
-
-               if len(methods) != 0 {
-                       if !isgotype {
-                               panic("method found on non-type symbol")
-                       }
-                       // 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, &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)))
-                       }
-                       for i, m := range methodsigs {
-                               methods[i].m = m
-                       }
-                       d.markableMethods = append(d.markableMethods, methods...)
-               }
-       }
-}
-
-func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
-       if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
-               d.wq.push(symIdx)
-               d.ldr.SetAttrReachable(symIdx, true)
-               if d.ctxt.Reachparent != nil {
-                       d.ldr.Reachparent[symIdx] = parent
-               }
-               if *flagDumpDep {
-                       to := d.ldr.SymName(symIdx)
-                       if to != "" {
-                               from := "_"
-                               if parent != 0 {
-                                       from = d.ldr.SymName(parent)
-                               }
-                               fmt.Printf("%s -> %s\n", from, to)
-                       }
-               }
-       }
-}
-
-func (d *deadcodePass2) markMethod(m methodref2) {
-       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) {
-       ldr := ctxt.loader
-       d := deadcodePass2{ctxt: ctxt, ldr: ldr}
-       d.init()
-       d.flood()
-
-       methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
-       methByNameSym := ldr.Lookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
-       if ctxt.DynlinkingGo() {
-               // Exported methods may satisfy interfaces we don't know
-               // about yet when dynamically linking.
-               d.reflectSeen = true
-       }
-
-       for {
-               // Methods might be called via reflection. Give up on
-               // static analysis, mark all exported methods of
-               // all reachable types as reachable.
-               d.reflectSeen = d.reflectSeen || (methSym != 0 && ldr.AttrReachable(methSym)) || (methByNameSym != 0 && ldr.AttrReachable(methByNameSym))
-
-               // Mark all methods that could satisfy a discovered
-               // interface as reachable. We recheck old marked interfaces
-               // as new types (with new methods) may have been discovered
-               // in the last pass.
-               rem := d.markableMethods[:0]
-               for _, m := range d.markableMethods {
-                       if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
-                               d.markMethod(m)
-                       } else {
-                               rem = append(rem, m)
-                       }
-               }
-               d.markableMethods = rem
-
-               if d.wq.empty() {
-                       // No new work was discovered. Done.
-                       break
-               }
-               d.flood()
-       }
-
-       n := ldr.NSym()
-
-       if ctxt.BuildMode != BuildModeShared {
-               // Keep a itablink if the symbol it points at is being kept.
-               // (When BuildModeShared, always keep itablinks.)
-               for i := 1; i < n; i++ {
-                       s := loader.Sym(i)
-                       if ldr.IsItabLink(s) {
-                               relocs := ldr.Relocs(s)
-                               if relocs.Count() > 0 && ldr.AttrReachable(relocs.At2(0).Sym()) {
-                                       ldr.SetAttrReachable(s, true)
-                               }
-                       }
-               }
-       }
-}
-
-// methodref2 holds the relocations from a receiver type symbol to its
-// method. There are three relocations, one for each of the fields in
-// the reflect.method struct: mtyp, ifn, and tfn.
-type methodref2 struct {
-       m   methodsig
-       src loader.Sym // receiver type symbol
-       r   int        // the index of R_METHODOFF relocations
-}
-
-func (m methodref2) isExported() bool {
-       for _, r := range m.m {
-               return unicode.IsUpper(r)
-       }
-       panic("methodref has no signature")
-}
-
-// decodeMethodSig2 decodes an array of method signature information.
-// Each element of the array is size bytes. The first 4 bytes is a
-// nameOff for the method name, and the next 4 bytes is a typeOff for
-// 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, 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, relocs, off))
-               mtypSym := decodeRelocSym2(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.
-               mrelocs := ldr.Relocs(mtypSym)
-               mp := ldr.Data(mtypSym)
-
-               buf.WriteRune('(')
-               inCount := decodetypeFuncInCount(arch, mp)
-               for i := 0; i < inCount; i++ {
-                       if i > 0 {
-                               buf.WriteString(", ")
-                       }
-                       a := decodetypeFuncInType2(ldr, arch, mtypSym, &mrelocs, i)
-                       buf.WriteString(ldr.SymName(a))
-               }
-               buf.WriteString(") (")
-               outCount := decodetypeFuncOutCount(arch, mp)
-               for i := 0; i < outCount; i++ {
-                       if i > 0 {
-                               buf.WriteString(", ")
-                       }
-                       a := decodetypeFuncOutType2(ldr, arch, mtypSym, &mrelocs, i)
-                       buf.WriteString(ldr.SymName(a))
-               }
-               buf.WriteRune(')')
-
-               off += size
-               methods = append(methods, methodsig(buf.String()))
-               buf.Reset()
-       }
-       return methods
-}
-
-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, relocs, int32(commonsize(arch)+arch.PtrSize))
-       s := rel.Sym()
-       if s == 0 {
-               return nil
-       }
-       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
-       numMethods := int(decodetypeIfaceMethodCount(arch, p))
-       sizeofIMethod := 4 + 4
-       return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
-}
-
-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)))
-       }
-       off := commonsize(arch) // reflect.rtype
-       switch decodetypeKind(arch, p) & kindMask {
-       case kindStruct: // reflect.structType
-               off += 4 * arch.PtrSize
-       case kindPtr: // reflect.ptrType
-               off += arch.PtrSize
-       case kindFunc: // reflect.funcType
-               off += arch.PtrSize // 4 bytes, pointer aligned
-       case kindSlice: // reflect.sliceType
-               off += arch.PtrSize
-       case kindArray: // reflect.arrayType
-               off += 3 * arch.PtrSize
-       case kindChan: // reflect.chanType
-               off += 2 * arch.PtrSize
-       case kindMap: // reflect.mapType
-               off += 4*arch.PtrSize + 8
-       case kindInterface: // reflect.interfaceType
-               off += 3 * arch.PtrSize
-       default:
-               // just Sizeof(rtype)
-       }
-
-       mcount := int(decodeInuxi(arch, p[off+4:], 2))
-       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, relocs, off, sizeofMethod, mcount)
-}
index 108171aaf8a41d21eeff016bf163ea5ae7efae79..c400d80a186e7d8776c41d9a4e66f7e298edbb86 100644 (file)
@@ -2772,6 +2772,24 @@ func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library
        *order = append(*order, lib)
 }
 
+// addToTextp populates the context Textp slice.
+func addToTextp(ctxt *Link) {
+       // Set up ctxt.Textp, based on ctxt.Textp2.
+       textp := make([]*sym.Symbol, 0, len(ctxt.Textp2))
+       haveshlibs := len(ctxt.Shlibs) > 0
+       for _, tsym := range ctxt.Textp2 {
+               sp := ctxt.loader.Syms[tsym]
+               if sp == nil || !ctxt.loader.AttrReachable(tsym) {
+                       panic("should never happen")
+               }
+               if haveshlibs && sp.Type == sym.SDYNIMPORT {
+                       continue
+               }
+               textp = append(textp, sp)
+       }
+       ctxt.Textp = textp
+}
+
 func (ctxt *Link) loadlibfull() {
 
        // Load full symbol contents, resolve indexed references.
index 59c022d5a98f58558887e912c77503963fbe0172..b09832b5c3d34d63cb662e540d471b82e1400f4e 100644 (file)
@@ -1909,8 +1909,6 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
 
        // Resolve ABI aliases for external symbols. This is only
        // needed for internal cgo linking.
-       // (The old code does this in deadcode, but deadcode2 doesn't
-       // do this.)
        for _, i := range l.extReader.syms {
                if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
                        for ri := range s.R {