summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-02-13 19:59:09 -0500
committerRuss Cox <rsc@golang.org>2014-02-13 19:59:09 -0500
commit627d914dff9f9b31d835a6aaa57073364c13638a (patch)
tree6f45bea4f8f604dd9313cb582c5550478d81de1f
parent21040f3f52f99a0fff5a3a7a707352f7a32b5e93 (diff)
downloadgo-627d914dff9f9b31d835a6aaa57073364c13638a.tar.gz
cmd/gc: relax address-of escape analysis
Make the loop nesting depth of &x depend on where x is declared, not on where the &x appears. The latter is only a conservative estimate of the former. Being more careful can avoid some variables escaping, and it is easier to reason about. It would have avoided issue 7313, although that was still a bug worth fixing. Not much effect in the tree: one variable in the whole tree is saved from a heap allocation (something in x509 parsing). LGTM=daniel.morsing R=daniel.morsing CC=golang-codereviews https://codereview.appspot.com/62380043
-rw-r--r--src/cmd/gc/esc.c21
-rw-r--r--test/escape2.go10
2 files changed, 29 insertions, 2 deletions
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index c038dfc58..5a1a9ed21 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -328,6 +328,7 @@ escfunc(EscState *e, Node *func)
ll->n->escloopdepth = 0;
break;
case PPARAM:
+ ll->n->escloopdepth = 1;
if(ll->n->type && !haspointers(ll->n->type))
break;
if(curfn->nbody == nil && !curfn->noescape)
@@ -335,7 +336,6 @@ escfunc(EscState *e, Node *func)
else
ll->n->esc = EscNone; // prime for escflood later
e->noesc = list(e->noesc, ll->n);
- ll->n->escloopdepth = 1;
break;
}
}
@@ -630,7 +630,6 @@ esc(EscState *e, Node *n)
escassign(e, n, a);
}
// fallthrough
- case OADDR:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
@@ -639,6 +638,24 @@ esc(EscState *e, Node *n)
n->esc = EscNone; // until proven otherwise
e->noesc = list(e->noesc, n);
break;
+
+ case OADDR:
+ n->esc = EscNone; // until proven otherwise
+ e->noesc = list(e->noesc, n);
+ // current loop depth is an upper bound on actual loop depth
+ // of addressed value.
+ n->escloopdepth = e->loopdepth;
+ // for &x, use loop depth of x.
+ if(n->left->op == ONAME) {
+ switch(n->left->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ n->escloopdepth = n->left->escloopdepth;
+ break;
+ }
+ }
+ break;
}
lineno = lno;
diff --git a/test/escape2.go b/test/escape2.go
index 73342fd2b..047adf514 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1389,3 +1389,13 @@ func foo148(l List) { // ERROR " l does not escape"
for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
}
}
+
+// related: address of variable should have depth of variable, not of loop
+
+func foo149(l List) { // ERROR " l does not escape"
+ var p *List
+ for {
+ for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+ }
+ }
+}