|  | // Copyright 2018 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package escape | 
|  |  | 
|  | import ( | 
|  | "cmd/compile/internal/base" | 
|  | "math" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | // A leaks represents a set of assignment flows from a parameter to | 
|  | // the heap, mutator, callee, or to any of its function's (first | 
|  | // numEscResults) result parameters. | 
|  | type leaks [8]uint8 | 
|  |  | 
|  | const ( | 
|  | leakHeap = iota | 
|  | leakMutator | 
|  | leakCallee | 
|  | leakResult0 | 
|  | ) | 
|  |  | 
|  | const numEscResults = len(leaks{}) - leakResult0 | 
|  |  | 
|  | // Heap returns the minimum deref count of any assignment flow from l | 
|  | // to the heap. If no such flows exist, Heap returns -1. | 
|  | func (l leaks) Heap() int { return l.get(leakHeap) } | 
|  |  | 
|  | // Mutator returns the minimum deref count of any assignment flow from | 
|  | // l to the pointer operand of an indirect assignment statement. If no | 
|  | // such flows exist, Mutator returns -1. | 
|  | func (l leaks) Mutator() int { return l.get(leakMutator) } | 
|  |  | 
|  | // Callee returns the minimum deref count of any assignment flow from | 
|  | // l to the callee operand of call expression. If no such flows exist, | 
|  | // Callee returns -1. | 
|  | func (l leaks) Callee() int { return l.get(leakCallee) } | 
|  |  | 
|  | // Result returns the minimum deref count of any assignment flow from | 
|  | // l to its function's i'th result parameter. If no such flows exist, | 
|  | // Result returns -1. | 
|  | func (l leaks) Result(i int) int { return l.get(leakResult0 + i) } | 
|  |  | 
|  | // AddHeap adds an assignment flow from l to the heap. | 
|  | func (l *leaks) AddHeap(derefs int) { l.add(leakHeap, derefs) } | 
|  |  | 
|  | // AddMutator adds a flow from l to the mutator (i.e., a pointer | 
|  | // operand of an indirect assignment statement). | 
|  | func (l *leaks) AddMutator(derefs int) { l.add(leakMutator, derefs) } | 
|  |  | 
|  | // AddCallee adds an assignment flow from l to the callee operand of a | 
|  | // call expression. | 
|  | func (l *leaks) AddCallee(derefs int) { l.add(leakCallee, derefs) } | 
|  |  | 
|  | // AddResult adds an assignment flow from l to its function's i'th | 
|  | // result parameter. | 
|  | func (l *leaks) AddResult(i, derefs int) { l.add(leakResult0+i, derefs) } | 
|  |  | 
|  | func (l leaks) get(i int) int { return int(l[i]) - 1 } | 
|  |  | 
|  | func (l *leaks) add(i, derefs int) { | 
|  | if old := l.get(i); old < 0 || derefs < old { | 
|  | l.set(i, derefs) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (l *leaks) set(i, derefs int) { | 
|  | v := derefs + 1 | 
|  | if v < 0 { | 
|  | base.Fatalf("invalid derefs count: %v", derefs) | 
|  | } | 
|  | if v > math.MaxUint8 { | 
|  | v = math.MaxUint8 | 
|  | } | 
|  |  | 
|  | l[i] = uint8(v) | 
|  | } | 
|  |  | 
|  | // Optimize removes result flow paths that are equal in length or | 
|  | // longer than the shortest heap flow path. | 
|  | func (l *leaks) Optimize() { | 
|  | // If we have a path to the heap, then there's no use in | 
|  | // keeping equal or longer paths elsewhere. | 
|  | if x := l.Heap(); x >= 0 { | 
|  | for i := 1; i < len(*l); i++ { | 
|  | if l.get(i) >= x { | 
|  | l.set(i, -1) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | var leakTagCache = map[leaks]string{} | 
|  |  | 
|  | // Encode converts l into a binary string for export data. | 
|  | func (l leaks) Encode() string { | 
|  | if l.Heap() == 0 { | 
|  | // Space optimization: empty string encodes more | 
|  | // efficiently in export data. | 
|  | return "" | 
|  | } | 
|  | if s, ok := leakTagCache[l]; ok { | 
|  | return s | 
|  | } | 
|  |  | 
|  | n := len(l) | 
|  | for n > 0 && l[n-1] == 0 { | 
|  | n-- | 
|  | } | 
|  | s := "esc:" + string(l[:n]) | 
|  | leakTagCache[l] = s | 
|  | return s | 
|  | } | 
|  |  | 
|  | // parseLeaks parses a binary string representing a leaks. | 
|  | func parseLeaks(s string) leaks { | 
|  | var l leaks | 
|  | if !strings.HasPrefix(s, "esc:") { | 
|  | l.AddHeap(0) | 
|  | return l | 
|  | } | 
|  | copy(l[:], s[4:]) | 
|  | return l | 
|  | } |