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  const numEscResults = 7
    14  
    15  // An leaks represents a set of assignment flows from a parameter
    16  // to the heap or to any of its function's (first numEscResults)
    17  // result parameters.
    18  type leaks [1 + numEscResults]uint8
    19  
    20  // Empty reports whether l is an empty set (i.e., no assignment flows).
    21  func (l leaks) Empty() bool { return l == leaks{} }
    22  
    23  // Heap returns the minimum deref count of any assignment flow from l
    24  // to the heap. If no such flows exist, Heap returns -1.
    25  func (l leaks) Heap() int { return l.get(0) }
    26  
    27  // Result returns the minimum deref count of any assignment flow from
    28  // l to its function's i'th result parameter. If no such flows exist,
    29  // Result returns -1.
    30  func (l leaks) Result(i int) int { return l.get(1 + i) }
    31  
    32  // AddHeap adds an assignment flow from l to the heap.
    33  func (l *leaks) AddHeap(derefs int) { l.add(0, derefs) }
    34  
    35  // AddResult adds an assignment flow from l to its function's i'th
    36  // result parameter.
    37  func (l *leaks) AddResult(i, derefs int) { l.add(1+i, derefs) }
    38  
    39  func (l *leaks) setResult(i, derefs int) { l.set(1+i, derefs) }
    40  
    41  func (l leaks) get(i int) int { return int(l[i]) - 1 }
    42  
    43  func (l *leaks) add(i, derefs int) {
    44  	if old := l.get(i); old < 0 || derefs < old {
    45  		l.set(i, derefs)
    46  	}
    47  }
    48  
    49  func (l *leaks) set(i, derefs int) {
    50  	v := derefs + 1
    51  	if v < 0 {
    52  		base.Fatalf("invalid derefs count: %v", derefs)
    53  	}
    54  	if v > math.MaxUint8 {
    55  		v = math.MaxUint8
    56  	}
    57  
    58  	l[i] = uint8(v)
    59  }
    60  
    61  // Optimize removes result flow paths that are equal in length or
    62  // longer than the shortest heap flow path.
    63  func (l *leaks) Optimize() {
    64  	// If we have a path to the heap, then there's no use in
    65  	// keeping equal or longer paths elsewhere.
    66  	if x := l.Heap(); x >= 0 {
    67  		for i := 0; i < numEscResults; i++ {
    68  			if l.Result(i) >= x {
    69  				l.setResult(i, -1)
    70  			}
    71  		}
    72  	}
    73  }
    74  
    75  var leakTagCache = map[leaks]string{}
    76  
    77  // Encode converts l into a binary string for export data.
    78  func (l leaks) Encode() string {
    79  	if l.Heap() == 0 {
    80  		// Space optimization: empty string encodes more
    81  		// efficiently in export data.
    82  		return ""
    83  	}
    84  	if s, ok := leakTagCache[l]; ok {
    85  		return s
    86  	}
    87  
    88  	n := len(l)
    89  	for n > 0 && l[n-1] == 0 {
    90  		n--
    91  	}
    92  	s := "esc:" + string(l[:n])
    93  	leakTagCache[l] = s
    94  	return s
    95  }
    96  
    97  // parseLeaks parses a binary string representing a leaks
    98  func parseLeaks(s string) leaks {
    99  	var l leaks
   100  	if !strings.HasPrefix(s, "esc:") {
   101  		l.AddHeap(0)
   102  		return l
   103  	}
   104  	copy(l[:], s[4:])
   105  	return l
   106  }
   107  

View as plain text