]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/escape: change escapes and persists into bitset
authorMatthew Dempsky <mdempsky@google.com>
Tue, 15 Aug 2023 21:20:50 +0000 (14:20 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 17 Aug 2023 14:31:30 +0000 (14:31 +0000)
This CL introduces a locAttr bitset type, which will make it easier to
add additional attributes in the near future.

Change-Id: I2689aa623097279dc1e7b7cf2adf5184d710c5a8
Reviewed-on: https://go-review.googlesource.com/c/go/+/520258
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/escape/escape.go
src/cmd/compile/internal/escape/graph.go
src/cmd/compile/internal/escape/solve.go

index ea9287712c027cd779f506b2149948690e434878..5ad73bfc0dc0876b7257ab558d1454bbd6807cda 100644 (file)
@@ -129,8 +129,7 @@ func Batch(fns []*ir.Func, recursive bool) {
        }
 
        var b batch
-       b.heapLoc.escapes = true
-       b.heapLoc.persists = true
+       b.heapLoc.attrs = attrEscapes | attrPersists
 
        // Construct data-flow graph from syntax trees.
        for _, fn := range fns {
@@ -301,7 +300,7 @@ func (b *batch) finish(fns []*ir.Func) {
                // TODO(mdempsky): Update tests to expect this.
                goDeferWrapper := n.Op() == ir.OCLOSURE && n.(*ir.ClosureExpr).Func.Wrapper()
 
-               if loc.escapes {
+               if loc.hasAttr(attrEscapes) {
                        if n.Op() == ir.ONAME {
                                if base.Flag.CompilingRuntime {
                                        base.ErrorfAt(n.Pos(), 0, "%v escapes to heap, not allowed in runtime", n)
@@ -324,7 +323,7 @@ func (b *batch) finish(fns []*ir.Func) {
                                base.WarnfAt(n.Pos(), "%v does not escape", n)
                        }
                        n.SetEsc(ir.EscNone)
-                       if !loc.persists {
+                       if !loc.hasAttr(attrPersists) {
                                switch n.Op() {
                                case ir.OCLOSURE:
                                        n := n.(*ir.ClosureExpr)
@@ -453,7 +452,7 @@ func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
        esc := loc.paramEsc
        esc.Optimize()
 
-       if diagnose && !loc.escapes {
+       if diagnose && !loc.hasAttr(attrEscapes) {
                if esc.Empty() {
                        base.WarnfAt(f.Pos, "%v does not escape", name())
                }
index ad97b7c28c28cec082cc8506843c27479595deea..9b3a4558fb214d60c827816bf38496ea9141dd96 100644 (file)
@@ -66,15 +66,8 @@ type location struct {
        // in the walk queue.
        queued bool
 
-       // escapes reports whether the represented variable's address
-       // escapes; that is, whether the variable must be heap
-       // allocated.
-       escapes bool
-
-       // persists reports whether the represented expression's address
-       // outlives the statement; that is, whether its storage cannot be
-       // immediately reused.
-       persists bool
+       // attrs is a bitset of location attributes.
+       attrs locAttr
 
        // paramEsc records the represented parameter's leak set.
        paramEsc leaks
@@ -84,6 +77,21 @@ type location struct {
        addrtaken  bool // has this variable's address been taken?
 }
 
+type locAttr uint8
+
+const (
+       // attrEscapes indicates whether the represented variable's address
+       // escapes; that is, whether the variable must be heap allocated.
+       attrEscapes locAttr = 1 << iota
+
+       // attrPersists indicates whether the represented expression's
+       // address outlives the statement; that is, whether its storage
+       // cannot be immediately reused.
+       attrPersists
+)
+
+func (l *location) hasAttr(attr locAttr) bool { return l.attrs&attr != 0 }
+
 // An edge represents an assignment edge between two Go variables.
 type edge struct {
        src    *location
@@ -100,7 +108,7 @@ func (l *location) leakTo(sink *location, derefs int) {
        // If sink is a result parameter that doesn't escape (#44614)
        // and we can fit return bits into the escape analysis tag,
        // then record as a result leak.
-       if !sink.escapes && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn {
+       if !sink.hasAttr(attrEscapes) && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn {
                ri := sink.resultIndex - 1
                if ri < numEscResults {
                        // Leak to result parameter.
@@ -182,7 +190,7 @@ func (b *batch) flow(k hole, src *location) {
        if dst == src && k.derefs >= 0 { // dst = dst, dst = *dst, ...
                return
        }
-       if dst.escapes && k.derefs < 0 { // dst = &src
+       if dst.hasAttr(attrEscapes) && k.derefs < 0 { // dst = &src
                if base.Flag.LowerM >= 2 || logopt.Enabled() {
                        pos := base.FmtPos(src.n.Pos())
                        if base.Flag.LowerM >= 2 {
@@ -195,7 +203,7 @@ func (b *batch) flow(k hole, src *location) {
                        }
 
                }
-               src.escapes = true
+               src.attrs |= attrEscapes
                return
        }
 
@@ -230,7 +238,9 @@ func (e *escape) newLoc(n ir.Node, persists bool) *location {
                n:         n,
                curfn:     e.curfn,
                loopDepth: e.loopDepth,
-               persists:  persists,
+       }
+       if persists {
+               loc.attrs |= attrPersists
        }
        e.allLocs = append(e.allLocs, loc)
        if n != nil {
index 2856c9c13144e2ccbb999db8b71bdfa79917cd74..12866c0dc8b12bbef1832ef16a129f7543b517f8 100644 (file)
@@ -79,8 +79,8 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
 
                        // If l's address flows to a persistent location, then l needs
                        // to persist too.
-                       if root.persists && !l.persists {
-                               l.persists = true
+                       if root.hasAttr(attrPersists) && !l.hasAttr(attrPersists) {
+                               l.attrs |= attrPersists
                                enqueue(l)
                        }
                }
@@ -92,7 +92,7 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
                        // that value flow for tagging the function
                        // later.
                        if l.isName(ir.PPARAM) {
-                               if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes {
+                               if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.hasAttr(attrEscapes) {
                                        if base.Flag.LowerM >= 2 {
                                                fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), derefs)
                                        }
@@ -109,7 +109,7 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
                        // If l's address flows somewhere that
                        // outlives it, then l needs to be heap
                        // allocated.
-                       if addressOf && !l.escapes {
+                       if addressOf && !l.hasAttr(attrEscapes) {
                                if logopt.Enabled() || base.Flag.LowerM >= 2 {
                                        if base.Flag.LowerM >= 2 {
                                                fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n)
@@ -120,14 +120,14 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
                                                logopt.LogOpt(l.n.Pos(), "escape", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation)
                                        }
                                }
-                               l.escapes = true
+                               l.attrs |= attrEscapes
                                enqueue(l)
                                continue
                        }
                }
 
                for i, edge := range l.edges {
-                       if edge.src.escapes {
+                       if edge.src.hasAttr(attrEscapes) {
                                continue
                        }
                        d := derefs + edge.derefs
@@ -227,7 +227,7 @@ func (b *batch) explainLoc(l *location) string {
 // other's lifetime if stack allocated.
 func (b *batch) outlives(l, other *location) bool {
        // The heap outlives everything.
-       if l.escapes {
+       if l.hasAttr(attrEscapes) {
                return true
        }