github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/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 "github.com/bir3/gocompiler/src/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 }