aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2023-08-15 14:20:50 -0700
committerGopher Robot <gobot@golang.org>2023-08-17 14:31:30 +0000
commit1038fc207bcd8bd35a50ffd8aaa4bba40c9bca9a (patch)
tree8f489386fb5ed8f97a3e2ced7ad1b342776b3897
parent4e336b8e1ee9bde0d8b797ea0131f6859361e368 (diff)
downloadgo-1038fc207bcd8bd35a50ffd8aaa4bba40c9bca9a.tar.xz
cmd/compile/internal/escape: change escapes and persists into bitset
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>
-rw-r--r--src/cmd/compile/internal/escape/escape.go9
-rw-r--r--src/cmd/compile/internal/escape/graph.go36
-rw-r--r--src/cmd/compile/internal/escape/solve.go14
3 files changed, 34 insertions, 25 deletions
diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index ea9287712c..5ad73bfc0d 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -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())
}
diff --git a/src/cmd/compile/internal/escape/graph.go b/src/cmd/compile/internal/escape/graph.go
index ad97b7c28c..9b3a4558fb 100644
--- a/src/cmd/compile/internal/escape/graph.go
+++ b/src/cmd/compile/internal/escape/graph.go
@@ -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 {
diff --git a/src/cmd/compile/internal/escape/solve.go b/src/cmd/compile/internal/escape/solve.go
index 2856c9c131..12866c0dc8 100644
--- a/src/cmd/compile/internal/escape/solve.go
+++ b/src/cmd/compile/internal/escape/solve.go
@@ -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
}