Source file src/cmd/compile/internal/escape/leaks.go

     1  // Copyright 2018 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  package escape
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"math"
    10  	"strings"
    11  )
    12  
    13  // A leaks represents a set of assignment flows from a parameter to
    14  // the heap, mutator, callee, or to any of its function's (first
    15  // numEscResults) result parameters.
    16  type leaks [8]uint8
    17  
    18  const (
    19  	leakHeap = iota
    20  	leakMutator
    21  	leakCallee
    22  	leakResult0
    23  )
    24  
    25  const numEscResults = len(leaks{}) - leakResult0
    26  
    27  // Heap returns the minimum deref count of any assignment flow from l
    28  // to the heap. If no such flows exist, Heap returns -1.
    29  func (l leaks) Heap() int { return l.get(leakHeap) }
    30  
    31  // Mutator returns the minimum deref count of any assignment flow from
    32  // l to the pointer operand of an indirect assignment statement. If no
    33  // such flows exist, Mutator returns -1.
    34  func (l leaks) Mutator() int { return l.get(leakMutator) }
    35  
    36  // Callee returns the minimum deref count of any assignment flow from
    37  // l to the callee operand of call expression. If no such flows exist,
    38  // Callee returns -1.
    39  func (l leaks) Callee() int { return l.get(leakCallee) }
    40  
    41  // Result returns the minimum deref count of any assignment flow from
    42  // l to its function's i'th result parameter. If no such flows exist,
    43  // Result returns -1.
    44  func (l leaks) Result(i int) int { return l.get(leakResult0 + i) }
    45  
    46  // AddHeap adds an assignment flow from l to the heap.
    47  func (l *leaks) AddHeap(derefs int) { l.add(leakHeap, derefs) }
    48  
    49  // AddMutator adds a flow from l to the mutator (i.e., a pointer
    50  // operand of an indirect assignment statement).
    51  func (l *leaks) AddMutator(derefs int) { l.add(leakMutator, derefs) }
    52  
    53  // AddCallee adds an assignment flow from l to the callee operand of a
    54  // call expression.
    55  func (l *leaks) AddCallee(derefs int) { l.add(leakCallee, derefs) }
    56  
    57  // AddResult adds an assignment flow from l to its function's i'th
    58  // result parameter.
    59  func (l *leaks) AddResult(i, derefs int) { l.add(leakResult0+i, derefs) }
    60  
    61  func (l leaks) get(i int) int { return int(l[i]) - 1 }
    62  
    63  func (l *leaks) add(i, derefs int) {
    64  	if old := l.get(i); old < 0 || derefs < old {
    65  		l.set(i, derefs)
    66  	}
    67  }
    68  
    69  func (l *leaks) set(i, derefs int) {
    70  	v := derefs + 1
    71  	if v < 0 {
    72  		base.Fatalf("invalid derefs count: %v", derefs)
    73  	}
    74  	if v > math.MaxUint8 {
    75  		v = math.MaxUint8
    76  	}
    77  
    78  	l[i] = uint8(v)
    79  }
    80  
    81  // Optimize removes result flow paths that are equal in length or
    82  // longer than the shortest heap flow path.
    83  func (l *leaks) Optimize() {
    84  	// If we have a path to the heap, then there's no use in
    85  	// keeping equal or longer paths elsewhere.
    86  	if x := l.Heap(); x >= 0 {
    87  		for i := 1; i < len(*l); i++ {
    88  			if l.get(i) >= x {
    89  				l.set(i, -1)
    90  			}
    91  		}
    92  	}
    93  }
    94  
    95  var leakTagCache = map[leaks]string{}
    96  
    97  // Encode converts l into a binary string for export data.
    98  func (l leaks) Encode() string {
    99  	if l.Heap() == 0 {
   100  		// Space optimization: empty string encodes more
   101  		// efficiently in export data.
   102  		return ""
   103  	}
   104  	if s, ok := leakTagCache[l]; ok {
   105  		return s
   106  	}
   107  
   108  	n := len(l)
   109  	for n > 0 && l[n-1] == 0 {
   110  		n--
   111  	}
   112  	s := "esc:" + string(l[:n])
   113  	leakTagCache[l] = s
   114  	return s
   115  }
   116  
   117  // parseLeaks parses a binary string representing a leaks.
   118  func parseLeaks(s string) leaks {
   119  	var l leaks
   120  	if !strings.HasPrefix(s, "esc:") {
   121  		l.AddHeap(0)
   122  		return l
   123  	}
   124  	copy(l[:], s[4:])
   125  	return l
   126  }
   127  

View as plain text