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 }