// 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" ) const numEscResults = 7 // An leaks represents a set of assignment flows from a parameter // to the heap or to any of its function's (first numEscResults) // result parameters. type leaks [1 + numEscResults]uint8 // Empty reports whether l is an empty set (i.e., no assignment flows). func (l leaks) Empty() bool { return l == leaks{} } // 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(0) } // 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(1 + i) } // AddHeap adds an assignment flow from l to the heap. func (l *leaks) AddHeap(derefs int) { l.add(0, 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(1+i, derefs) } func (l *leaks) setResult(i, derefs int) { l.set(1+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 := 0; i < numEscResults; i++ { if l.Result(i) >= x { l.setResult(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 }