| // 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 ( |
| "cmd/internal/objabi" |
| "cmd/link/internal/sym" |
| ) |
| |
| // deadcode marks all reachable symbols. |
| // |
| // The basis of the dead code elimination is a flood fill of symbols, |
| // following their relocations, beginning at *flagEntrySymbol. |
| // |
| // This flood fill is wrapped in logic for pruning unused methods. |
| // All methods are mentioned by relocations on their receiver's *rtype. |
| // These relocations are specially defined as R_METHODOFF by the compiler |
| // so we can detect and manipulated them here. |
| // |
| // There are three ways a method of a reachable type can be invoked: |
| // |
| // 1. direct call |
| // 2. through a reachable interface type |
| // 3. reflect.Value.Call, .Method, or reflect.Method.Func |
| // |
| // The first case is handled by the flood fill, a directly called method |
| // is marked as reachable. |
| // |
| // The second case is handled by decomposing all reachable interface |
| // types into method signatures. Each encountered method is compared |
| // against the interface method signatures, if it matches it is marked |
| // as reachable. This is extremely conservative, but easy and correct. |
| // |
| // The third case is handled by looking to see if any of: |
| // - reflect.Value.Call is reachable |
| // - reflect.Value.Method is reachable |
| // - reflect.Type.Method or MethodByName is called. |
| // If any of these happen, all bets are off and all exported methods |
| // of reachable types are marked reachable. |
| // |
| // Any unreached text symbols are removed from ctxt.Textp. |
| func deadcode(ctxt *Link) { |
| deadcode2(ctxt) |
| } |
| |
| func addToTextp(ctxt *Link) { |
| // Remove dead text but keep file information (z symbols). |
| textp := []*sym.Symbol{} |
| for _, s := range ctxt.Textp { |
| if s.Attr.Reachable() { |
| textp = append(textp, s) |
| } |
| } |
| |
| // Put reachable text symbols into Textp. |
| // do it in postorder so that packages are laid down in dependency order |
| // internal first, then everything else |
| ctxt.Library = postorder(ctxt.Library) |
| for _, doInternal := range [2]bool{true, false} { |
| for _, lib := range ctxt.Library { |
| if isRuntimeDepPkg(lib.Pkg) != doInternal { |
| continue |
| } |
| libtextp := lib.Textp[:0] |
| for _, s := range lib.Textp { |
| if s.Attr.Reachable() { |
| textp = append(textp, s) |
| libtextp = append(libtextp, s) |
| if s.Unit != nil { |
| s.Unit.Textp = append(s.Unit.Textp, s) |
| } |
| } |
| } |
| for _, s := range lib.DupTextSyms { |
| if s.Attr.Reachable() && !s.Attr.OnList() { |
| textp = append(textp, s) |
| libtextp = append(libtextp, s) |
| if s.Unit != nil { |
| s.Unit.Textp = append(s.Unit.Textp, s) |
| } |
| s.Attr |= sym.AttrOnList |
| // dupok symbols may be defined in multiple packages. its |
| // associated package is chosen sort of arbitrarily (the |
| // first containing package that the linker loads). canonicalize |
| // it here to the package with which it will be laid down |
| // in text. |
| s.File = objabi.PathToPrefix(lib.Pkg) |
| } |
| } |
| lib.Textp = libtextp |
| } |
| } |
| ctxt.Textp = textp |
| |
| if len(ctxt.Shlibs) > 0 { |
| // We might have overwritten some functions above (this tends to happen for the |
| // autogenerated type equality/hashing functions) and we don't want to generated |
| // pcln table entries for these any more so remove them from Textp. |
| textp := make([]*sym.Symbol, 0, len(ctxt.Textp)) |
| for _, s := range ctxt.Textp { |
| if s.Type != sym.SDYNIMPORT { |
| textp = append(textp, s) |
| } |
| } |
| ctxt.Textp = textp |
| } |
| } |