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 5package escape 6 7import ( 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. 16type leaks [8]uint8 17 18const ( 19 leakHeap = iota 20 leakMutator 21 leakCallee 22 leakResult0 23) 24 25const 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. 29func (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. 34func (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. 39func (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. 44func (l leaks) Result(i int) int { return l.get(leakResult0 + i) } 45 46// AddHeap adds an assignment flow from l to the heap. 47func (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). 51func (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. 55func (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. 59func (l *leaks) AddResult(i, derefs int) { l.add(leakResult0+i, derefs) } 60 61func (l leaks) get(i int) int { return int(l[i]) - 1 } 62 63func (l *leaks) add(i, derefs int) { 64 if old := l.get(i); old < 0 || derefs < old { 65 l.set(i, derefs) 66 } 67} 68 69func (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. 83func (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 95var leakTagCache = map[leaks]string{} 96 97// Encode converts l into a binary string for export data. 98func (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. 118func 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