github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/escape/leaks.go (about)

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