From 5a91c83ce82509551d353b1b5ea25cd72b44fec3 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 6 Apr 2018 16:21:26 -0400 Subject: [PATCH] cmd/compile: in escape analysis, propagate loop depth to field The escape analysis models "loop depth". If the address of an expression is assigned to something defined at a lower (outer) loop depth, the escape analysis decides it escapes. However, it uses the loop depth of the address operator instead of where the RHS is defined. This causes an unnecessary escape if there is an assignment inside a loop but the RHS is defined outside the loop. This CL propagates the loop depth. Fixes #24730. Change-Id: I5ff1530688bdfd90561a7b39c8be9bfc009a9dae Reviewed-on: https://go-review.googlesource.com/105257 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/esc.go | 22 +++++++++++++++------- test/escape5.go | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 42159505767..fcb4e96a75c 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -715,6 +715,7 @@ func (e *EscState) esc(n *Node, parent *Node) { fmt.Printf("%v:[%d] %v esc: %v\n", linestr(lineno), e.loopdepth, funcSym(Curfn), n) } +opSwitch: switch n.Op { // Record loop depth at declaration. case ODCL: @@ -1000,13 +1001,6 @@ func (e *EscState) esc(n *Node, parent *Node) { // and keep the current loop depth. if n.Left.Op == ONAME { switch n.Left.Class() { - case PAUTO: - nE := e.nodeEscState(n) - leftE := e.nodeEscState(n.Left) - if leftE.Loopdepth != 0 { - nE.Loopdepth = leftE.Loopdepth - } - // PPARAM is loop depth 1 always. // PPARAMOUT is loop depth 0 for writes // but considered loop depth 1 for address-of, @@ -1016,8 +1010,22 @@ func (e *EscState) esc(n *Node, parent *Node) { case PPARAM, PPARAMOUT: nE := e.nodeEscState(n) nE.Loopdepth = 1 + break opSwitch } } + nE := e.nodeEscState(n) + leftE := e.nodeEscState(n.Left) + if leftE.Loopdepth != 0 { + nE.Loopdepth = leftE.Loopdepth + } + + case ODOT, + ODOTPTR, + OINDEX: + // Propagate the loopdepth of t to t.field. + if n.Left.Op != OLITERAL { // OLITERAL node doesn't have esc state + e.nodeEscState(n).Loopdepth = e.nodeEscState(n.Left).Loopdepth + } } lineno = lno diff --git a/test/escape5.go b/test/escape5.go index 0bae1e84010..d02f735f8fc 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -175,3 +175,22 @@ func _() { u.M() // ERROR "u does not escape" u.N() // ERROR "u does not escape" } + +// Issue 24730: taking address in a loop causes unnecessary escape +type T24730 struct { + x [64]byte +} + +func (t *T24730) g() { // ERROR "t does not escape" + y := t.x[:] // ERROR "t\.x does not escape" + for i := range t.x[:] { // ERROR "t\.x does not escape" + y = t.x[:] // ERROR "t\.x does not escape" + y[i] = 1 + } + + var z *byte + for i := range t.x[:] { // ERROR "t\.x does not escape" + z = &t.x[i] // ERROR "t\.x\[i\] does not escape" + *z = 2 + } +}