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://golang.org/cl/62380043
This commit is contained in:
Russ Cox 2014-02-13 19:59:09 -05:00
parent e0bb5ba52c
commit e5d742fcad
2 changed files with 29 additions and 2 deletions

View File

@ -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;

View File

@ -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"
}
}
}