summaryrefslogtreecommitdiff
path: root/src/cmd/gc/esc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/esc.c')
-rw-r--r--src/cmd/gc/esc.c105
1 files changed, 93 insertions, 12 deletions
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index cd1f9770e..7e20457d9 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -35,6 +35,8 @@
static void escfunc(Node *func);
static void esclist(NodeList *l);
static void esc(Node *n);
+static void escloopdepthlist(NodeList *l);
+static void escloopdepth(Node *n);
static void escassign(Node *dst, Node *src);
static void esccall(Node*);
static void escflows(Node *dst, Node *src);
@@ -62,6 +64,7 @@ escapes(void)
NodeList *l;
theSink.op = ONAME;
+ theSink.orig = &theSink;
theSink.class = PEXTERN;
theSink.sym = lookup(".sink");
theSink.escloopdepth = -1;
@@ -88,7 +91,7 @@ escapes(void)
if(debug['m']) {
for(l=noesc; l; l=l->next)
if(l->n->esc == EscNone)
- warnl(l->n->lineno, "%S %#N does not escape",
+ warnl(l->n->lineno, "%S %hN does not escape",
(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
l->n);
}
@@ -138,11 +141,64 @@ escfunc(Node *func)
escassign(curfn, n);
}
+ escloopdepthlist(curfn->nbody);
esclist(curfn->nbody);
curfn = savefn;
loopdepth = saveld;
}
+// Mark labels that have no backjumps to them as not increasing loopdepth.
+// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
+// and set it to one of the following two. Then in esc we'll clear it again.
+static Label looping;
+static Label nonlooping;
+
+static void
+escloopdepthlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ escloopdepth(l->n);
+}
+
+static void
+escloopdepth(Node *n)
+{
+ if(n == N)
+ return;
+
+ escloopdepthlist(n->ninit);
+
+ switch(n->op) {
+ case OLABEL:
+ if(!n->left || !n->left->sym)
+ fatal("esc:label without label: %+N", n);
+ // Walk will complain about this label being already defined, but that's not until
+ // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
+ // if(n->left->sym->label != nil)
+ // fatal("escape analysis messed up analyzing label: %+N", n);
+ n->left->sym->label = &nonlooping;
+ break;
+ case OGOTO:
+ if(!n->left || !n->left->sym)
+ fatal("esc:goto without label: %+N", n);
+ // If we come past one that's uninitialized, this must be a (harmless) forward jump
+ // but if it's set to nonlooping the label must have preceded this goto.
+ if(n->left->sym->label == &nonlooping)
+ n->left->sym->label = &looping;
+ break;
+ }
+
+ escloopdepth(n->left);
+ escloopdepth(n->right);
+ escloopdepthlist(n->list);
+ escloopdepth(n->ntest);
+ escloopdepth(n->nincr);
+ escloopdepthlist(n->nbody);
+ escloopdepthlist(n->nelse);
+ escloopdepthlist(n->rlist);
+
+}
+
static void
esclist(NodeList *l)
{
@@ -178,7 +234,7 @@ esc(Node *n)
loopdepth--;
if(debug['m'] > 1)
- print("%L:[%d] %#S esc: %#N\n", lineno, loopdepth,
+ print("%L:[%d] %S esc: %N\n", lineno, loopdepth,
(curfn && curfn->nname) ? curfn->nname->sym : S, n);
switch(n->op) {
@@ -188,9 +244,20 @@ esc(Node *n)
n->left->escloopdepth = loopdepth;
break;
- case OLABEL: // TODO: new loop/scope only if there are backjumps to it.
- loopdepth++;
- break;
+ case OLABEL:
+ if(n->left->sym->label == &nonlooping) {
+ if(debug['m'] > 1)
+ print("%L:%N non-looping label\n", lineno, n);
+ } else if(n->left->sym->label == &looping) {
+ if(debug['m'] > 1)
+ print("%L: %N looping label\n", lineno, n);
+ loopdepth++;
+ }
+ // See case OLABEL in escloopdepth above
+ // else if(n->left->sym->label == nil)
+ // fatal("escape anaylysis missed or messed up a label: %+N", n);
+
+ n->left->sym->label = nil;
case ORANGE:
// Everything but fixed array is a dereference.
@@ -222,7 +289,6 @@ esc(Node *n)
case OAS2RECV: // v, ok = <-ch
case OAS2MAPR: // v, ok = m[k]
case OAS2DOTTYPE: // v, ok = x.(type)
- case OAS2MAPW: // m[k] = x, ok
escassign(n->list->n, n->rlist->n);
break;
@@ -239,6 +305,7 @@ esc(Node *n)
case OPROC:
// go f(x) - f and x escape
escassign(&theSink, n->left->left);
+ escassign(&theSink, n->left->right); // ODDDARG for call
for(ll=n->left->list; ll; ll=ll->next)
escassign(&theSink, ll->n);
break;
@@ -291,6 +358,14 @@ esc(Node *n)
for(ll=n->list; ll; ll=ll->next)
escassign(n, ll->n->right);
break;
+
+ case OPTRLIT:
+ n->esc = EscNone; // until proven otherwise
+ noesc = list(noesc, n);
+ n->escloopdepth = loopdepth;
+ // Contents make it to memory, lose track.
+ escassign(&theSink, n->left);
+ break;
case OMAPLIT:
n->esc = EscNone; // until proven otherwise
@@ -331,7 +406,7 @@ escassign(Node *dst, Node *src)
return;
if(debug['m'] > 1)
- print("%L:[%d] %#S escassign: %hN = %hN\n", lineno, loopdepth,
+ print("%L:[%d] %S escassign: %hN = %hN\n", lineno, loopdepth,
(curfn && curfn->nname) ? curfn->nname->sym : S, dst, src);
setlineno(dst);
@@ -387,6 +462,7 @@ escassign(Node *dst, Node *src)
case ONAME:
case OPARAM:
case ODDDARG:
+ case OPTRLIT:
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
@@ -394,10 +470,14 @@ escassign(Node *dst, Node *src)
escflows(dst, src);
break;
+ case ODOT:
+ // A non-pointer escaping from a struct does not concern us.
+ if(src->type && !haspointers(src->type))
+ break;
+ // fallthrough
case OCONV:
case OCONVIFACE:
case OCONVNOP:
- case ODOT:
case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
case ODOTTYPE:
@@ -609,7 +689,7 @@ escflood(Node *dst)
}
if(debug['m']>1)
- print("\nescflood:%d: dst %hN scope:%#S[%d]\n", walkgen, dst,
+ print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
(dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
dst->escloopdepth);
@@ -630,7 +710,7 @@ escwalk(int level, Node *dst, Node *src)
src->walkgen = walkgen;
if(debug['m']>1)
- print("escwalk: level:%d depth:%d %.*s %hN scope:%#S[%d]\n",
+ print("escwalk: level:%d depth:%d %.*s %hN scope:%S[%d]\n",
level, pdepth, pdepth, "\t\t\t\t\t\t\t\t\t\t", src,
(src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
@@ -647,12 +727,13 @@ escwalk(int level, Node *dst, Node *src)
}
break;
+ case OPTRLIT:
case OADDR:
if(leaks) {
src->esc = EscHeap;
addrescapes(src->left);
if(debug['m'])
- warnl(src->lineno, "%#N escapes to heap", src);
+ warnl(src->lineno, "%hN escapes to heap", src);
}
escwalk(level-1, dst, src->left);
break;
@@ -671,7 +752,7 @@ escwalk(int level, Node *dst, Node *src)
if(leaks) {
src->esc = EscHeap;
if(debug['m'])
- warnl(src->lineno, "%#N escapes to heap", src);
+ warnl(src->lineno, "%hN escapes to heap", src);
}
break;