github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/link/dead.go (about)

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Removal of dead code and data.
     6  
     7  package main
     8  
     9  import "cmd/internal/goobj"
    10  
    11  // dead removes unreachable code and data from the program.
    12  // It is basically a mark-sweep garbage collection: traverse all the
    13  // symbols reachable from the entry (startSymID) and then delete
    14  // the rest.
    15  func (p *Prog) dead() {
    16  	p.Dead = make(map[goobj.SymID]bool)
    17  	reachable := make(map[goobj.SymID]bool)
    18  	p.walkDead(p.startSym, reachable)
    19  
    20  	for sym := range p.Syms {
    21  		if !reachable[sym] {
    22  			delete(p.Syms, sym)
    23  			p.Dead[sym] = true
    24  		}
    25  	}
    26  
    27  	for sym := range p.Missing {
    28  		if !reachable[sym] {
    29  			delete(p.Missing, sym)
    30  			p.Dead[sym] = true
    31  		}
    32  	}
    33  
    34  	p.SymOrder = removeDead(p.SymOrder, reachable)
    35  
    36  	for _, pkg := range p.Packages {
    37  		pkg.Syms = removeDead(pkg.Syms, reachable)
    38  	}
    39  }
    40  
    41  // walkDead traverses the symbols reachable from sym, adding them to reachable.
    42  // The caller has verified that reachable[sym] = false.
    43  func (p *Prog) walkDead(sym goobj.SymID, reachable map[goobj.SymID]bool) {
    44  	reachable[sym] = true
    45  	s := p.Syms[sym]
    46  	if s == nil {
    47  		return
    48  	}
    49  	for i := range s.Reloc {
    50  		r := &s.Reloc[i]
    51  		if !reachable[r.Sym] {
    52  			p.walkDead(r.Sym, reachable)
    53  		}
    54  	}
    55  	if s.Func != nil {
    56  		for _, fdata := range s.Func.FuncData {
    57  			if fdata.Sym.Name != "" && !reachable[fdata.Sym] {
    58  				p.walkDead(fdata.Sym, reachable)
    59  			}
    60  		}
    61  	}
    62  }
    63  
    64  // removeDead removes unreachable (dead) symbols from syms,
    65  // returning a shortened slice using the same underlying array.
    66  func removeDead(syms []*Sym, reachable map[goobj.SymID]bool) []*Sym {
    67  	keep := syms[:0]
    68  	for _, sym := range syms {
    69  		if reachable[sym.SymID] {
    70  			keep = append(keep, sym)
    71  		}
    72  	}
    73  	return keep
    74  }