From 095e0f48a19fa3bd7901f79420374b9cb50940e9 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Thu, 1 Oct 2020 12:03:27 +0200 Subject: cmd/compile: change mustHeapAlloc to return a reason why This change renames mustHeapAlloc to heapAllocReason, and changes it to return the reason why the argument must escape, so we don't have to re-deduce it in its callers just to print the escape reason. It also embeds isSmallMakeSlice body in heapAllocReason, since the former was only used by the latter, and deletes isSmallMakeSlice. An outdated TODO to remove smallintconst, which the TODO claimed was only used in one place, was also removed, since grepping shows we currently call smallintconst in 11 different places. Change-Id: I0bd11bf29b92c4126f5bb455877ff73217d5a155 Reviewed-on: https://go-review.googlesource.com/c/go/+/258678 Run-TryBot: Alberto Donizetti TryBot-Result: Go Bot Trust: Alberto Donizetti Trust: Cuong Manh Le Reviewed-by: Cuong Manh Le Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/escape.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/cmd/compile/internal/gc/escape.go') diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index d79d32ec48..79df584ab1 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -1051,11 +1051,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation { } n.SetOpt(loc) - if mustHeapAlloc(n) { - why := "too large for stack" - if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || (n.Right != nil && !Isconst(n.Right, CTINT))) { - why = "non-constant size" - } + if why := heapAllocReason(n); why != "" { e.flow(e.heapHole().addr(n, why), loc) } } -- cgit v1.2.1 From c0417df15664a84c3cc6de8292f78debce111def Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 22 Sep 2020 02:12:03 -0700 Subject: cmd/compile: improve escape analysis of known calls Escape analysis is currently very naive about identifying calls to known functions: it only recognizes direct calls to a declared function, or direct calls to a closure. This CL adds a new "staticValue" helper function that can trace back through local variables that were initialized and never reassigned based on a similar optimization already used by inlining. (And to be used by inlining in a followup CL.) Updates #41474. Change-Id: I8204fd3b1e150ab77a27f583985cf099a8572b2e Reviewed-on: https://go-review.googlesource.com/c/go/+/256458 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Trust: Matthew Dempsky Reviewed-by: Cuong Manh Le Reviewed-by: David Chase --- src/cmd/compile/internal/gc/escape.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/cmd/compile/internal/gc/escape.go') diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index 79df584ab1..93965d4fac 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -771,10 +771,11 @@ func (e *Escape) call(ks []EscHole, call, where *Node) { var fn *Node switch call.Op { case OCALLFUNC: - if call.Left.Op == ONAME && call.Left.Class() == PFUNC { - fn = call.Left - } else if call.Left.Op == OCLOSURE { - fn = call.Left.Func.Closure.Func.Nname + switch v := staticValue(call.Left); { + case v.Op == ONAME && v.Class() == PFUNC: + fn = v + case v.Op == OCLOSURE: + fn = v.Func.Closure.Func.Nname } case OCALLMETH: fn = asNode(call.Left.Type.FuncType().Nname) -- cgit v1.2.1 From 3bac5faa4af2f5c454b2cebaa8be5cde9b8e2add Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Mon, 19 Oct 2020 11:31:10 +0200 Subject: cmd/compile: make gc debug flags collector a struct gc debug flags are currently stored in a 256-long array, that is then addressed using the ASCII numeric value of the flag itself (a quirk inherited from the old C compiler). It is also a little wasteful, since we only define 16 flags, and the other 240 array elements are always empty. This change makes Debug a struct, which also provides static checking that we're not referencing flags that does not exist. Change-Id: I2f0dfef2529325514b3398cf78635543cdf48fe0 Reviewed-on: https://go-review.googlesource.com/c/go/+/263539 Trust: Alberto Donizetti Run-TryBot: Alberto Donizetti TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/escape.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/cmd/compile/internal/gc/escape.go') diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index 93965d4fac..618bdf78e2 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -170,7 +170,7 @@ func (e *Escape) initFunc(fn *Node) { Fatalf("unexpected node: %v", fn) } fn.Esc = EscFuncPlanned - if Debug['m'] > 3 { + if Debug.m > 3 { Dump("escAnalyze", fn) } @@ -247,7 +247,7 @@ func (e *Escape) stmt(n *Node) { lineno = lno }() - if Debug['m'] > 2 { + if Debug.m > 2 { fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n) } @@ -275,11 +275,11 @@ func (e *Escape) stmt(n *Node) { case OLABEL: switch asNode(n.Sym.Label) { case &nonlooping: - if Debug['m'] > 2 { + if Debug.m > 2 { fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n) } case &looping: - if Debug['m'] > 2 { + if Debug.m > 2 { fmt.Printf("%v: %v looping label\n", linestr(lineno), n) } e.loopDepth++ @@ -717,7 +717,7 @@ func (e *Escape) addrs(l Nodes) []EscHole { func (e *Escape) assign(dst, src *Node, why string, where *Node) { // Filter out some no-op assignments for escape analysis. ignore := dst != nil && src != nil && isSelfAssign(dst, src) - if ignore && Debug['m'] != 0 { + if ignore && Debug.m != 0 { Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where) } @@ -931,7 +931,7 @@ func (k EscHole) note(where *Node, why string) EscHole { if where == nil || why == "" { Fatalf("note: missing where/why") } - if Debug['m'] >= 2 || logopt.Enabled() { + if Debug.m >= 2 || logopt.Enabled() { k.notes = &EscNote{ next: k.notes, where: where, @@ -1077,9 +1077,9 @@ func (e *Escape) flow(k EscHole, src *EscLocation) { return } if dst.escapes && k.derefs < 0 { // dst = &src - if Debug['m'] >= 2 || logopt.Enabled() { + if Debug.m >= 2 || logopt.Enabled() { pos := linestr(src.n.Pos) - if Debug['m'] >= 2 { + if Debug.m >= 2 { fmt.Printf("%s: %v escapes to heap:\n", pos, src.n) } explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{}) @@ -1179,8 +1179,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc // that value flow for tagging the function // later. if l.isName(PPARAM) { - if (logopt.Enabled() || Debug['m'] >= 2) && !l.escapes { - if Debug['m'] >= 2 { + if (logopt.Enabled() || Debug.m >= 2) && !l.escapes { + if Debug.m >= 2 { fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base) } explanation := e.explainPath(root, l) @@ -1196,8 +1196,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc // outlives it, then l needs to be heap // allocated. if addressOf && !l.escapes { - if logopt.Enabled() || Debug['m'] >= 2 { - if Debug['m'] >= 2 { + if logopt.Enabled() || Debug.m >= 2 { + if Debug.m >= 2 { fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n) } explanation := e.explainPath(root, l) @@ -1235,7 +1235,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt { for { // Prevent infinite loop. if visited[src] { - if Debug['m'] >= 2 { + if Debug.m >= 2 { fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos) } break @@ -1263,7 +1263,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n if derefs >= 0 { ops = strings.Repeat("*", derefs) } - print := Debug['m'] >= 2 + print := Debug.m >= 2 flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc)) if print { @@ -1417,7 +1417,7 @@ func (e *Escape) finish(fns []*Node) { if loc.escapes { if n.Op != ONAME { - if Debug['m'] != 0 { + if Debug.m != 0 { Warnl(n.Pos, "%S escapes to heap", n) } if logopt.Enabled() { @@ -1427,7 +1427,7 @@ func (e *Escape) finish(fns []*Node) { n.Esc = EscHeap addrescapes(n) } else { - if Debug['m'] != 0 && n.Op != ONAME { + if Debug.m != 0 && n.Op != ONAME { Warnl(n.Pos, "%S does not escape", n) } n.Esc = EscNone -- cgit v1.2.1