]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: split out package escape [generated]
authorRuss Cox <rsc@golang.org>
Wed, 23 Dec 2020 05:51:28 +0000 (00:51 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 23 Dec 2020 06:39:00 +0000 (06:39 +0000)
[git-generate]

cd src/cmd/compile/internal/gc
rf '
# Trivial min, max defined in escape.go but only used in ssa.go.
mv min8 max8 ssa.go

# Export package escape API.
mv escapes Funcs
mv escapeFuncs Batch
mv escFmt Fmt
mv unsafeUintptrTag UnsafeUintptrNote
mv uintptrEscapesTag UintptrEscapesNote
mv heapAllocReason HeapAllocReason

# Unexport non-API.
mv EscEdge edge
mv EscHole hole
mv EscLeaks leaks
mv ParseLeaks parseLeaks
mv EscLocation location
mv EscNote note
mv Escape _escape # leave room for escape import, fixed below
mv EscFuncUnknown escFuncUnknown
mv EscFuncPlanned escFuncPlanned
mv EscFuncStarted escFuncStarted
mv EscFuncTagged escFuncTagged

mv escape.go cmd/compile/internal/escape
'
cd ../escape
rf '
mv _escape escape
'

Change-Id: I3a6d1bfb6eba12bea936354ea1fe9813cbde425c
Reviewed-on: https://go-review.googlesource.com/c/go/+/279472
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/escape/escape.go [moved from src/cmd/compile/internal/gc/escape.go with 90% similarity]
src/cmd/compile/internal/gc/gsubr.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/walk.go

similarity index 90%
rename from src/cmd/compile/internal/gc/escape.go
rename to src/cmd/compile/internal/escape/escape.go
index 187313695fa1c3f06fdda6d0c87191aa0d70d2b4..b7cb56b997d285074ab4d54e4cbf6452ec0e9f5e 100644 (file)
@@ -2,18 +2,19 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package escape
 
 import (
+       "fmt"
+       "math"
+       "strings"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "fmt"
-       "math"
-       "strings"
 )
 
 // Escape analysis.
@@ -84,8 +85,8 @@ import (
 // u[2], etc. However, we do record the implicit dereference involved
 // in indexing a slice.
 
-type Escape struct {
-       allLocs []*EscLocation
+type escape struct {
+       allLocs []*location
        labels  map[*types.Sym]labelState // known labels
 
        curfn *ir.Func
@@ -96,17 +97,17 @@ type Escape struct {
        // unstructured loop).
        loopDepth int
 
-       heapLoc  EscLocation
-       blankLoc EscLocation
+       heapLoc  location
+       blankLoc location
 }
 
-// An EscLocation represents an abstract location that stores a Go
+// An location represents an abstract location that stores a Go
 // variable.
-type EscLocation struct {
-       n         ir.Node   // represented variable or expression, if any
-       curfn     *ir.Func  // enclosing function
-       edges     []EscEdge // incoming edges
-       loopDepth int       // loopDepth at declaration
+type location struct {
+       n         ir.Node  // represented variable or expression, if any
+       curfn     *ir.Func // enclosing function
+       edges     []edge   // incoming edges
+       loopDepth int      // loopDepth at declaration
 
        // derefs and walkgen are used during walkOne to track the
        // minimal dereferences from the walk root.
@@ -116,7 +117,7 @@ type EscLocation struct {
        // dst and dstEdgeindex track the next immediate assignment
        // destination location during walkone, along with the index
        // of the edge pointing back to this location.
-       dst        *EscLocation
+       dst        *location
        dstEdgeIdx int
 
        // queued is used by walkAll to track whether this location is
@@ -134,18 +135,18 @@ type EscLocation struct {
        transient bool
 
        // paramEsc records the represented parameter's leak set.
-       paramEsc EscLeaks
+       paramEsc leaks
 }
 
-// An EscEdge represents an assignment edge between two Go variables.
-type EscEdge struct {
-       src    *EscLocation
+// An edge represents an assignment edge between two Go variables.
+type edge struct {
+       src    *location
        derefs int // >= -1
-       notes  *EscNote
+       notes  *note
 }
 
-// escFmt is called from node printing to print information about escape analysis results.
-func escFmt(n ir.Node) string {
+// Fmt is called from node printing to print information about escape analysis results.
+func Fmt(n ir.Node) string {
        text := ""
        switch n.Esc() {
        case ir.EscUnknown:
@@ -164,7 +165,7 @@ func escFmt(n ir.Node) string {
                text = fmt.Sprintf("esc(%d)", n.Esc())
        }
 
-       if e, ok := n.Opt().(*EscLocation); ok && e.loopDepth != 0 {
+       if e, ok := n.Opt().(*location); ok && e.loopDepth != 0 {
                if text != "" {
                        text += " "
                }
@@ -173,16 +174,16 @@ func escFmt(n ir.Node) string {
        return text
 }
 
-// escapeFuncs performs escape analysis on a minimal batch of
+// Batch performs escape analysis on a minimal batch of
 // functions.
-func escapeFuncs(fns []*ir.Func, recursive bool) {
+func Batch(fns []*ir.Func, recursive bool) {
        for _, fn := range fns {
                if fn.Op() != ir.ODCLFUNC {
                        base.Fatalf("unexpected node: %v", fn)
                }
        }
 
-       var e Escape
+       var e escape
        e.heapLoc.escapes = true
 
        // Construct data-flow graph from syntax trees.
@@ -198,11 +199,11 @@ func escapeFuncs(fns []*ir.Func, recursive bool) {
        e.finish(fns)
 }
 
-func (e *Escape) initFunc(fn *ir.Func) {
-       if fn.Esc() != EscFuncUnknown {
+func (e *escape) initFunc(fn *ir.Func) {
+       if fn.Esc() != escFuncUnknown {
                base.Fatalf("unexpected node: %v", fn)
        }
-       fn.SetEsc(EscFuncPlanned)
+       fn.SetEsc(escFuncPlanned)
        if base.Flag.LowerM > 3 {
                ir.Dump("escAnalyze", fn)
        }
@@ -218,8 +219,8 @@ func (e *Escape) initFunc(fn *ir.Func) {
        }
 }
 
-func (e *Escape) walkFunc(fn *ir.Func) {
-       fn.SetEsc(EscFuncStarted)
+func (e *escape) walkFunc(fn *ir.Func) {
+       fn.SetEsc(escFuncStarted)
 
        // Identify labels that mark the head of an unstructured loop.
        ir.Visit(fn, func(n ir.Node) {
@@ -277,7 +278,7 @@ func (e *Escape) walkFunc(fn *ir.Func) {
 //    }
 
 // stmt evaluates a single Go statement.
-func (e *Escape) stmt(n ir.Node) {
+func (e *escape) stmt(n ir.Node) {
        if n == nil {
                return
        }
@@ -368,7 +369,7 @@ func (e *Escape) stmt(n ir.Node) {
                n := n.(*ir.SwitchStmt)
                typesw := n.Tag != nil && n.Tag.Op() == ir.OTYPESW
 
-               var ks []EscHole
+               var ks []hole
                for _, cas := range n.Cases { // cases
                        cas := cas.(*ir.CaseStmt)
                        if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil {
@@ -456,14 +457,14 @@ func (e *Escape) stmt(n ir.Node) {
        }
 }
 
-func (e *Escape) stmts(l ir.Nodes) {
+func (e *escape) stmts(l ir.Nodes) {
        for _, n := range l {
                e.stmt(n)
        }
 }
 
 // block is like stmts, but preserves loopDepth.
-func (e *Escape) block(l ir.Nodes) {
+func (e *escape) block(l ir.Nodes) {
        old := e.loopDepth
        e.stmts(l)
        e.loopDepth = old
@@ -471,7 +472,7 @@ func (e *Escape) block(l ir.Nodes) {
 
 // expr models evaluating an expression n and flowing the result into
 // hole k.
-func (e *Escape) expr(k EscHole, n ir.Node) {
+func (e *escape) expr(k hole, n ir.Node) {
        if n == nil {
                return
        }
@@ -479,7 +480,7 @@ func (e *Escape) expr(k EscHole, n ir.Node) {
        e.exprSkipInit(k, n)
 }
 
-func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
+func (e *escape) exprSkipInit(k hole, n ir.Node) {
        if n == nil {
                return
        }
@@ -590,7 +591,7 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
                e.discard(n.X)
 
        case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY:
-               e.call([]EscHole{k}, n, nil)
+               e.call([]hole{k}, n, nil)
 
        case ir.ONEW:
                n := n.(*ir.UnaryExpr)
@@ -627,7 +628,7 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
                //
                // TODO(mdempsky): Change ks into a callback, so that
                // we don't have to create this slice?
-               var ks []EscHole
+               var ks []hole
                for i := m.Type.NumResults(); i > 0; i-- {
                        ks = append(ks, e.heapHole())
                }
@@ -709,7 +710,7 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
 
 // unsafeValue evaluates a uintptr-typed arithmetic expression looking
 // for conversions from an unsafe.Pointer.
-func (e *Escape) unsafeValue(k EscHole, n ir.Node) {
+func (e *escape) unsafeValue(k hole, n ir.Node) {
        if n.Type().Kind() != types.TUINTPTR {
                base.Fatalf("unexpected type %v for %v", n.Type(), n)
        }
@@ -751,11 +752,11 @@ func (e *Escape) unsafeValue(k EscHole, n ir.Node) {
 
 // discard evaluates an expression n for side-effects, but discards
 // its value.
-func (e *Escape) discard(n ir.Node) {
+func (e *escape) discard(n ir.Node) {
        e.expr(e.discardHole(), n)
 }
 
-func (e *Escape) discards(l ir.Nodes) {
+func (e *escape) discards(l ir.Nodes) {
        for _, n := range l {
                e.discard(n)
        }
@@ -763,7 +764,7 @@ func (e *Escape) discards(l ir.Nodes) {
 
 // addr evaluates an addressable expression n and returns an EscHole
 // that represents storing into the represented location.
-func (e *Escape) addr(n ir.Node) EscHole {
+func (e *escape) addr(n ir.Node) hole {
        if n == nil || ir.IsBlank(n) {
                // Can happen in select case, range, maybe others.
                return e.discardHole()
@@ -809,8 +810,8 @@ func (e *Escape) addr(n ir.Node) EscHole {
        return k
 }
 
-func (e *Escape) addrs(l ir.Nodes) []EscHole {
-       var ks []EscHole
+func (e *escape) addrs(l ir.Nodes) []hole {
+       var ks []hole
        for _, n := range l {
                ks = append(ks, e.addr(n))
        }
@@ -818,7 +819,7 @@ func (e *Escape) addrs(l ir.Nodes) []EscHole {
 }
 
 // assign evaluates the assignment dst = src.
-func (e *Escape) assign(dst, src ir.Node, why string, where ir.Node) {
+func (e *escape) assign(dst, src ir.Node, why string, where ir.Node) {
        // Filter out some no-op assignments for escape analysis.
        ignore := dst != nil && src != nil && isSelfAssign(dst, src)
        if ignore && base.Flag.LowerM != 0 {
@@ -836,14 +837,14 @@ func (e *Escape) assign(dst, src ir.Node, why string, where ir.Node) {
        }
 }
 
-func (e *Escape) assignHeap(src ir.Node, why string, where ir.Node) {
+func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) {
        e.expr(e.heapHole().note(where, why), src)
 }
 
 // call evaluates a call expressions, including builtin calls. ks
 // should contain the holes representing where the function callee's
 // results flows; where is the OGO/ODEFER context of the call, if any.
-func (e *Escape) call(ks []EscHole, call, where ir.Node) {
+func (e *escape) call(ks []hole, call, where ir.Node) {
        topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1
        if topLevelDefer {
                // force stack allocation of defer record, unless
@@ -851,7 +852,7 @@ func (e *Escape) call(ks []EscHole, call, where ir.Node) {
                where.SetEsc(ir.EscNever)
        }
 
-       argument := func(k EscHole, arg ir.Node) {
+       argument := func(k hole, arg ir.Node) {
                if topLevelDefer {
                        // Top level defers arguments don't escape to
                        // heap, but they do need to last until end of
@@ -969,7 +970,7 @@ func (e *Escape) call(ks []EscHole, call, where ir.Node) {
 // ks should contain the holes representing where the function
 // callee's results flows. fn is the statically-known callee function,
 // if any.
-func (e *Escape) tagHole(ks []EscHole, fn *ir.Name, param *types.Field) EscHole {
+func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole {
        // If this is a dynamic call, we can't rely on param.Note.
        if fn == nil {
                return e.heapHole()
@@ -981,15 +982,15 @@ func (e *Escape) tagHole(ks []EscHole, fn *ir.Name, param *types.Field) EscHole
 
        // Call to previously tagged function.
 
-       if param.Note == uintptrEscapesTag {
+       if param.Note == UintptrEscapesNote {
                k := e.heapHole()
                k.uintptrEscapesHack = true
                return k
        }
 
-       var tagKs []EscHole
+       var tagKs []hole
 
-       esc := ParseLeaks(param.Note)
+       esc := parseLeaks(param.Note)
        if x := esc.Heap(); x >= 0 {
                tagKs = append(tagKs, e.heapHole().shift(x))
        }
@@ -1010,9 +1011,9 @@ func (e *Escape) tagHole(ks []EscHole, fn *ir.Name, param *types.Field) EscHole
 // fn has not yet been analyzed, so its parameters and results
 // should be incorporated directly into the flow graph instead of
 // relying on its escape analysis tagging.
-func (e *Escape) inMutualBatch(fn *ir.Name) bool {
-       if fn.Defn != nil && fn.Defn.Esc() < EscFuncTagged {
-               if fn.Defn.Esc() == EscFuncUnknown {
+func (e *escape) inMutualBatch(fn *ir.Name) bool {
+       if fn.Defn != nil && fn.Defn.Esc() < escFuncTagged {
+               if fn.Defn.Esc() == escFuncUnknown {
                        base.Fatalf("graph inconsistency")
                }
                return true
@@ -1020,31 +1021,31 @@ func (e *Escape) inMutualBatch(fn *ir.Name) bool {
        return false
 }
 
-// An EscHole represents a context for evaluation a Go
+// An hole represents a context for evaluation a Go
 // expression. E.g., when evaluating p in "x = **p", we'd have a hole
 // with dst==x and derefs==2.
-type EscHole struct {
-       dst    *EscLocation
+type hole struct {
+       dst    *location
        derefs int // >= -1
-       notes  *EscNote
+       notes  *note
 
        // uintptrEscapesHack indicates this context is evaluating an
        // argument for a //go:uintptrescapes function.
        uintptrEscapesHack bool
 }
 
-type EscNote struct {
-       next  *EscNote
+type note struct {
+       next  *note
        where ir.Node
        why   string
 }
 
-func (k EscHole) note(where ir.Node, why string) EscHole {
+func (k hole) note(where ir.Node, why string) hole {
        if where == nil || why == "" {
                base.Fatalf("note: missing where/why")
        }
        if base.Flag.LowerM >= 2 || logopt.Enabled() {
-               k.notes = &EscNote{
+               k.notes = &note{
                        next:  k.notes,
                        where: where,
                        why:   why,
@@ -1053,7 +1054,7 @@ func (k EscHole) note(where ir.Node, why string) EscHole {
        return k
 }
 
-func (k EscHole) shift(delta int) EscHole {
+func (k hole) shift(delta int) hole {
        k.derefs += delta
        if k.derefs < -1 {
                base.Fatalf("derefs underflow: %v", k.derefs)
@@ -1061,10 +1062,10 @@ func (k EscHole) shift(delta int) EscHole {
        return k
 }
 
-func (k EscHole) deref(where ir.Node, why string) EscHole { return k.shift(1).note(where, why) }
-func (k EscHole) addr(where ir.Node, why string) EscHole  { return k.shift(-1).note(where, why) }
+func (k hole) deref(where ir.Node, why string) hole { return k.shift(1).note(where, why) }
+func (k hole) addr(where ir.Node, why string) hole  { return k.shift(-1).note(where, why) }
 
-func (k EscHole) dotType(t *types.Type, where ir.Node, why string) EscHole {
+func (k hole) dotType(t *types.Type, where ir.Node, why string) hole {
        if !t.IsInterface() && !types.IsDirectIface(t) {
                k = k.shift(1)
        }
@@ -1073,7 +1074,7 @@ func (k EscHole) dotType(t *types.Type, where ir.Node, why string) EscHole {
 
 // teeHole returns a new hole that flows into each hole of ks,
 // similar to the Unix tee(1) command.
-func (e *Escape) teeHole(ks ...EscHole) EscHole {
+func (e *escape) teeHole(ks ...hole) hole {
        if len(ks) == 0 {
                return e.discardHole()
        }
@@ -1101,7 +1102,7 @@ func (e *Escape) teeHole(ks ...EscHole) EscHole {
        return loc.asHole()
 }
 
-func (e *Escape) dcl(n ir.Node) EscHole {
+func (e *escape) dcl(n ir.Node) hole {
        loc := e.oldLoc(n)
        loc.loopDepth = e.loopDepth
        return loc.asHole()
@@ -1110,7 +1111,7 @@ func (e *Escape) dcl(n ir.Node) EscHole {
 // spill allocates a new location associated with expression n, flows
 // its address to k, and returns a hole that flows values to it. It's
 // intended for use with most expressions that allocate storage.
-func (e *Escape) spill(k EscHole, n ir.Node) EscHole {
+func (e *escape) spill(k hole, n ir.Node) hole {
        loc := e.newLoc(n, true)
        e.flow(k.addr(n, "spill"), loc)
        return loc.asHole()
@@ -1119,7 +1120,7 @@ func (e *Escape) spill(k EscHole, n ir.Node) EscHole {
 // later returns a new hole that flows into k, but some time later.
 // Its main effect is to prevent immediate reuse of temporary
 // variables introduced during Order.
-func (e *Escape) later(k EscHole) EscHole {
+func (e *escape) later(k hole) hole {
        loc := e.newLoc(nil, false)
        e.flow(k, loc)
        return loc.asHole()
@@ -1138,7 +1139,7 @@ func canonicalNode(n ir.Node) ir.Node {
        return n
 }
 
-func (e *Escape) newLoc(n ir.Node, transient bool) *EscLocation {
+func (e *escape) newLoc(n ir.Node, transient bool) *location {
        if e.curfn == nil {
                base.Fatalf("e.curfn isn't set")
        }
@@ -1147,7 +1148,7 @@ func (e *Escape) newLoc(n ir.Node, transient bool) *EscLocation {
        }
 
        n = canonicalNode(n)
-       loc := &EscLocation{
+       loc := &location{
                n:         n,
                curfn:     e.curfn,
                loopDepth: e.loopDepth,
@@ -1165,23 +1166,23 @@ func (e *Escape) newLoc(n ir.Node, transient bool) *EscLocation {
                }
                n.SetOpt(loc)
 
-               if why := heapAllocReason(n); why != "" {
+               if why := HeapAllocReason(n); why != "" {
                        e.flow(e.heapHole().addr(n, why), loc)
                }
        }
        return loc
 }
 
-func (e *Escape) oldLoc(n ir.Node) *EscLocation {
+func (e *escape) oldLoc(n ir.Node) *location {
        n = canonicalNode(n)
-       return n.Opt().(*EscLocation)
+       return n.Opt().(*location)
 }
 
-func (l *EscLocation) asHole() EscHole {
-       return EscHole{dst: l}
+func (l *location) asHole() hole {
+       return hole{dst: l}
 }
 
-func (e *Escape) flow(k EscHole, src *EscLocation) {
+func (e *escape) flow(k hole, src *location) {
        dst := k.dst
        if dst == &e.blankLoc {
                return
@@ -1206,15 +1207,15 @@ func (e *Escape) flow(k EscHole, src *EscLocation) {
        }
 
        // TODO(mdempsky): Deduplicate edges?
-       dst.edges = append(dst.edges, EscEdge{src: src, derefs: k.derefs, notes: k.notes})
+       dst.edges = append(dst.edges, edge{src: src, derefs: k.derefs, notes: k.notes})
 }
 
-func (e *Escape) heapHole() EscHole    { return e.heapLoc.asHole() }
-func (e *Escape) discardHole() EscHole { return e.blankLoc.asHole() }
+func (e *escape) heapHole() hole    { return e.heapLoc.asHole() }
+func (e *escape) discardHole() hole { return e.blankLoc.asHole() }
 
 // walkAll computes the minimal dereferences between all pairs of
 // locations.
-func (e *Escape) walkAll() {
+func (e *escape) walkAll() {
        // We use a work queue to keep track of locations that we need
        // to visit, and repeatedly walk until we reach a fixed point.
        //
@@ -1224,8 +1225,8 @@ func (e *Escape) walkAll() {
        // happen at most once. So we take Î˜(len(e.allLocs)) walks.
 
        // LIFO queue, has enough room for e.allLocs and e.heapLoc.
-       todo := make([]*EscLocation, 0, len(e.allLocs)+1)
-       enqueue := func(loc *EscLocation) {
+       todo := make([]*location, 0, len(e.allLocs)+1)
+       enqueue := func(loc *location) {
                if !loc.queued {
                        todo = append(todo, loc)
                        loc.queued = true
@@ -1250,7 +1251,7 @@ func (e *Escape) walkAll() {
 
 // walkOne computes the minimal number of dereferences from root to
 // all other locations.
-func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLocation)) {
+func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)) {
        // The data flow graph has negative edges (from addressing
        // operations), so we use the Bellman-Ford algorithm. However,
        // we don't have to worry about infinite negative cycles since
@@ -1260,7 +1261,7 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
        root.derefs = 0
        root.dst = nil
 
-       todo := []*EscLocation{root} // LIFO queue
+       todo := []*location{root} // LIFO queue
        for len(todo) > 0 {
                l := todo[len(todo)-1]
                todo = todo[:len(todo)-1]
@@ -1341,8 +1342,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
 }
 
 // explainPath prints an explanation of how src flows to the walk root.
-func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
-       visited := make(map[*EscLocation]bool)
+func (e *escape) explainPath(root, src *location) []*logopt.LoggedOpt {
+       visited := make(map[*location]bool)
        pos := base.FmtPos(src.n.Pos())
        var explanation []*logopt.LoggedOpt
        for {
@@ -1371,7 +1372,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
        return explanation
 }
 
-func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, notes *EscNote, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt {
+func (e *escape) explainFlow(pos string, dst, srcloc *location, derefs int, notes *note, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt {
        ops := "&"
        if derefs >= 0 {
                ops = strings.Repeat("*", derefs)
@@ -1404,7 +1405,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n
        return explanation
 }
 
-func (e *Escape) explainLoc(l *EscLocation) string {
+func (e *escape) explainLoc(l *location) string {
        if l == &e.heapLoc {
                return "{heap}"
        }
@@ -1420,7 +1421,7 @@ func (e *Escape) explainLoc(l *EscLocation) string {
 
 // outlives reports whether values stored in l may survive beyond
 // other's lifetime if stack allocated.
-func (e *Escape) outlives(l, other *EscLocation) bool {
+func (e *escape) outlives(l, other *location) bool {
        // The heap outlives everything.
        if l.escapes {
                return true
@@ -1484,7 +1485,7 @@ func containsClosure(f, c *ir.Func) bool {
 }
 
 // leak records that parameter l leaks to sink.
-func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
+func (l *location) leakTo(sink *location, derefs int) {
        // If sink is a result parameter and we can fit return bits
        // into the escape analysis tag, then record a return leak.
        if sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn {
@@ -1501,10 +1502,10 @@ func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
        l.paramEsc.AddHeap(derefs)
 }
 
-func (e *Escape) finish(fns []*ir.Func) {
+func (e *escape) finish(fns []*ir.Func) {
        // Record parameter tags for package export data.
        for _, fn := range fns {
-               fn.SetEsc(EscFuncTagged)
+               fn.SetEsc(escFuncTagged)
 
                narg := 0
                for _, fs := range &types.RecvsParams {
@@ -1557,47 +1558,47 @@ func (e *Escape) finish(fns []*ir.Func) {
        }
 }
 
-func (l *EscLocation) isName(c ir.Class) bool {
+func (l *location) isName(c ir.Class) bool {
        return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class_ == c
 }
 
 const numEscResults = 7
 
-// An EscLeaks represents a set of assignment flows from a parameter
+// 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 EscLeaks [1 + numEscResults]uint8
+type leaks [1 + numEscResults]uint8
 
 // Empty reports whether l is an empty set (i.e., no assignment flows).
-func (l EscLeaks) Empty() bool { return l == EscLeaks{} }
+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 EscLeaks) Heap() int { return l.get(0) }
+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 EscLeaks) Result(i int) int { return l.get(1 + i) }
+func (l leaks) Result(i int) int { return l.get(1 + i) }
 
 // AddHeap adds an assignment flow from l to the heap.
-func (l *EscLeaks) AddHeap(derefs int) { l.add(0, derefs) }
+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 *EscLeaks) AddResult(i, derefs int) { l.add(1+i, derefs) }
+func (l *leaks) AddResult(i, derefs int) { l.add(1+i, derefs) }
 
-func (l *EscLeaks) setResult(i, derefs int) { l.set(1+i, derefs) }
+func (l *leaks) setResult(i, derefs int) { l.set(1+i, derefs) }
 
-func (l EscLeaks) get(i int) int { return int(l[i]) - 1 }
+func (l leaks) get(i int) int { return int(l[i]) - 1 }
 
-func (l *EscLeaks) add(i, derefs int) {
+func (l *leaks) add(i, derefs int) {
        if old := l.get(i); old < 0 || derefs < old {
                l.set(i, derefs)
        }
 }
 
-func (l *EscLeaks) set(i, derefs int) {
+func (l *leaks) set(i, derefs int) {
        v := derefs + 1
        if v < 0 {
                base.Fatalf("invalid derefs count: %v", derefs)
@@ -1611,7 +1612,7 @@ func (l *EscLeaks) set(i, derefs int) {
 
 // Optimize removes result flow paths that are equal in length or
 // longer than the shortest heap flow path.
-func (l *EscLeaks) Optimize() {
+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 {
@@ -1623,10 +1624,10 @@ func (l *EscLeaks) Optimize() {
        }
 }
 
-var leakTagCache = map[EscLeaks]string{}
+var leakTagCache = map[leaks]string{}
 
 // Encode converts l into a binary string for export data.
-func (l EscLeaks) Encode() string {
+func (l leaks) Encode() string {
        if l.Heap() == 0 {
                // Space optimization: empty string encodes more
                // efficiently in export data.
@@ -1645,9 +1646,9 @@ func (l EscLeaks) Encode() string {
        return s
 }
 
-// ParseLeaks parses a binary string representing an EscLeaks.
-func ParseLeaks(s string) EscLeaks {
-       var l EscLeaks
+// parseLeaks parses a binary string representing an EscLeaks.
+func parseLeaks(s string) leaks {
+       var l leaks
        if !strings.HasPrefix(s, "esc:") {
                l.AddHeap(0)
                return l
@@ -1656,31 +1657,17 @@ func ParseLeaks(s string) EscLeaks {
        return l
 }
 
-func escapes(all []ir.Node) {
-       ir.VisitFuncsBottomUp(all, escapeFuncs)
+func Funcs(all []ir.Node) {
+       ir.VisitFuncsBottomUp(all, Batch)
 }
 
 const (
-       EscFuncUnknown = 0 + iota
-       EscFuncPlanned
-       EscFuncStarted
-       EscFuncTagged
+       escFuncUnknown = 0 + iota
+       escFuncPlanned
+       escFuncStarted
+       escFuncTagged
 )
 
-func min8(a, b int8) int8 {
-       if a < b {
-               return a
-       }
-       return b
-}
-
-func max8(a, b int8) int8 {
-       if a > b {
-               return a
-       }
-       return b
-}
-
 // funcSym returns fn.Nname.Sym if no nils are encountered along the way.
 func funcSym(fn *ir.Func) *types.Sym {
        if fn == nil || fn.Nname == nil {
@@ -1855,9 +1842,9 @@ func mayAffectMemory(n ir.Node) bool {
        }
 }
 
-// heapAllocReason returns the reason the given Node must be heap
+// HeapAllocReason returns the reason the given Node must be heap
 // allocated, or the empty string if it doesn't.
-func heapAllocReason(n ir.Node) string {
+func HeapAllocReason(n ir.Node) string {
        if n.Type() == nil {
                return ""
        }
@@ -2064,13 +2051,13 @@ func moveToHeap(n *ir.Name) {
 // This special tag is applied to uintptr variables
 // that we believe may hold unsafe.Pointers for
 // calls into assembly functions.
-const unsafeUintptrTag = "unsafe-uintptr"
+const UnsafeUintptrNote = "unsafe-uintptr"
 
 // This special tag is applied to uintptr parameters of functions
 // marked go:uintptrescapes.
-const uintptrEscapesTag = "uintptr-escapes"
+const UintptrEscapesNote = "uintptr-escapes"
 
-func (e *Escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
+func (e *escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
        name := func() string {
                if f.Sym != nil {
                        return f.Sym.Name
@@ -2089,14 +2076,14 @@ func (e *Escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
                        if base.Flag.LowerM != 0 {
                                base.WarnfAt(f.Pos, "assuming %v is unsafe uintptr", name())
                        }
-                       return unsafeUintptrTag
+                       return UnsafeUintptrNote
                }
 
                if !f.Type.HasPointers() { // don't bother tagging for scalars
                        return ""
                }
 
-               var esc EscLeaks
+               var esc leaks
 
                // External functions are assumed unsafe, unless
                // //go:noescape is given before the declaration.
@@ -2119,14 +2106,14 @@ func (e *Escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
                        if base.Flag.LowerM != 0 {
                                base.WarnfAt(f.Pos, "marking %v as escaping uintptr", name())
                        }
-                       return uintptrEscapesTag
+                       return UintptrEscapesNote
                }
                if f.IsDDD() && f.Type.Elem().IsUintptr() {
                        // final argument is ...uintptr.
                        if base.Flag.LowerM != 0 {
                                base.WarnfAt(f.Pos, "marking %v as escaping ...uintptr", name())
                        }
-                       return uintptrEscapesTag
+                       return UintptrEscapesNote
                }
        }
 
@@ -2136,7 +2123,7 @@ func (e *Escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
 
        // Unnamed parameters are unused and therefore do not escape.
        if f.Sym == nil || f.Sym.IsBlank() {
-               var esc EscLeaks
+               var esc leaks
                return esc.Encode()
        }
 
index f746a358caf5b6e31928beed803cdee8c7f133cf..81f7956d2e87ace0420b4f731c6aadbdc8f5a7a8 100644 (file)
@@ -32,6 +32,7 @@ package gc
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/escape"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
@@ -141,7 +142,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
        ir.CurFunc = fn
        typecheck.Stmts(fn.Body)
 
-       escapeFuncs([]*ir.Func{fn}, false)
+       escape.Batch([]*ir.Func{fn}, false)
 
        typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
 
index 7f20d6b8a565cf94746d2a7497df8933aa53d0ca..cda00fb9aebf455f932062a1397efaabf81bbe9a 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bufio"
        "bytes"
        "cmd/compile/internal/base"
+       "cmd/compile/internal/escape"
        "cmd/compile/internal/inline"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
@@ -183,7 +184,7 @@ func Main(archInit func(*Arch)) {
                logopt.LogJsonOption(base.Flag.JSON)
        }
 
-       ir.EscFmt = escFmt
+       ir.EscFmt = escape.Fmt
        ir.IsIntrinsicCall = isIntrinsicCall
        inline.SSADumpInline = ssaDumpInline
        initSSAEnv()
@@ -252,7 +253,7 @@ func Main(archInit func(*Arch)) {
        // Large values are also moved off stack in escape analysis;
        // because large values may contain pointers, it must happen early.
        base.Timer.Start("fe", "escapes")
-       escapes(typecheck.Target.Decls)
+       escape.Funcs(typecheck.Target.Decls)
 
        // Collect information for go:nowritebarrierrec
        // checking. This must happen before transformclosure.
index 075bcea92cf17d492c2244750769c1094d8ba9eb..32a355ae6b013444e615a5f4304e91f9300cde6b 100644 (file)
@@ -6,6 +6,7 @@ package gc
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/escape"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
@@ -521,7 +522,7 @@ func (o *Order) call(nn ir.Node) {
 
        // Check for "unsafe-uintptr" tag provided by escape analysis.
        for i, param := range n.X.Type().Params().FieldSlice() {
-               if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
+               if param.Note == escape.UnsafeUintptrNote || param.Note == escape.UintptrEscapesNote {
                        if arg := n.Args[i]; arg.Op() == ir.OSLICELIT {
                                arg := arg.(*ir.CompLitExpr)
                                for _, elt := range arg.List {
index 5c36e922a635f21c7117ca876e2d38467f925947..feb2d0de8f0da07ea2179a7a8e812f7c58d917b2 100644 (file)
@@ -7396,3 +7396,17 @@ func callTargetLSym(callee *types.Sym, callerLSym *obj.LSym) *obj.LSym {
        }
        return lsym
 }
+
+func min8(a, b int8) int8 {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func max8(a, b int8) int8 {
+       if a > b {
+               return a
+       }
+       return b
+}
index f76fb8e24a2b8cad0182f37bee4f1b15badac24b..cba9bdc253aa6ecce25bb7b44817615c2a16a320 100644 (file)
@@ -6,6 +6,7 @@ package gc
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/escape"
        "cmd/compile/internal/inline"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
@@ -484,7 +485,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
        if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil {
                inline.InlineCalls(fn)
        }
-       escapeFuncs([]*ir.Func{fn}, false)
+       escape.Batch([]*ir.Func{fn}, false)
 
        ir.CurFunc = nil
        typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
index 73f82f333c09ae17b464e226f7cd3f1cbb039535..9e4de7f804afd483306cf5c9e5494738951fb675 100644 (file)
@@ -6,6 +6,7 @@ package gc
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/escape"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
@@ -1455,7 +1456,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
                        base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
                }
                if n.Esc() == ir.EscNone {
-                       if why := heapAllocReason(n); why != "" {
+                       if why := escape.HeapAllocReason(n); why != "" {
                                base.Fatalf("%v has EscNone, but %v", n, why)
                        }
                        // var arr [r]T