This source file includes following definitions.
- escapes
- visit
- visitcodelist
- visitcode
- mktag
- parsetag
- analyze
- escfunc
- escloopdepthlist
- escloopdepth
- esclist
- esc
- escassign
- escassignfromtag
- esccall
- escflows
- escflood
- escwalk
- esctag
#include <u.h>
#include <libc.h>
#include "go.h"
static NodeList *stack;
static uint32 visitgen;
static uint32 visit(Node*);
static uint32 visitcode(Node*, uint32);
static uint32 visitcodelist(NodeList*, uint32);
static void analyze(NodeList*, int);
enum
{
EscFuncUnknown = 0,
EscFuncPlanned,
EscFuncStarted,
EscFuncTagged,
};
void
escapes(NodeList *all)
{
NodeList *l;
for(l=all; l; l=l->next)
l->n->walkgen = 0;
visitgen = 0;
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC && l->n->curfn == N)
visit(l->n);
for(l=all; l; l=l->next)
l->n->walkgen = 0;
}
static uint32
visit(Node *n)
{
uint32 min, recursive;
NodeList *l, *block;
if(n->walkgen > 0) {
return n->walkgen;
}
visitgen++;
n->walkgen = visitgen;
visitgen++;
min = visitgen;
l = mal(sizeof *l);
l->next = stack;
l->n = n;
stack = l;
min = visitcodelist(n->nbody, min);
if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
recursive = min == n->walkgen;
block = stack;
for(l=stack; l->n != n; l=l->next)
l->n->walkgen = (uint32)~0U;
n->walkgen = (uint32)~0U;
stack = l->next;
l->next = nil;
analyze(block, recursive);
}
return min;
}
static uint32
visitcodelist(NodeList *l, uint32 min)
{
for(; l; l=l->next)
min = visitcode(l->n, min);
return min;
}
static uint32
visitcode(Node *n, uint32 min)
{
Node *fn;
uint32 m;
if(n == N)
return min;
min = visitcodelist(n->ninit, min);
min = visitcode(n->left, min);
min = visitcode(n->right, min);
min = visitcodelist(n->list, min);
min = visitcode(n->ntest, min);
min = visitcode(n->nincr, min);
min = visitcodelist(n->nbody, min);
min = visitcodelist(n->nelse, min);
min = visitcodelist(n->rlist, min);
if(n->op == OCALLFUNC || n->op == OCALLMETH) {
fn = n->left;
if(n->op == OCALLMETH)
fn = n->left->right->sym->def;
if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn)
if((m = visit(fn->defn)) < min)
min = m;
}
if(n->op == OCLOSURE)
if((m = visit(n->closure)) < min)
min = m;
return min;
}
typedef struct EscState EscState;
static void escfunc(EscState*, Node *func);
static void esclist(EscState*, NodeList *l, Node *up);
static void esc(EscState*, Node *n, Node *up);
static void escloopdepthlist(EscState*, NodeList *l);
static void escloopdepth(EscState*, Node *n);
static void escassign(EscState*, Node *dst, Node *src);
static void esccall(EscState*, Node*, Node *up);
static void escflows(EscState*, Node *dst, Node *src);
static void escflood(EscState*, Node *dst);
static void escwalk(EscState*, int level, Node *dst, Node *src);
static void esctag(EscState*, Node *func);
struct EscState {
Node theSink;
Node funcParam;
NodeList* dsts;
int loopdepth;
int pdepth;
int dstcount, edgecount;
NodeList* noesc;
int recursive;
};
static Strlit *tags[16];
static Strlit*
mktag(int mask)
{
Strlit *s;
char buf[40];
switch(mask&EscMask) {
case EscNone:
case EscReturn:
break;
default:
fatal("escape mktag");
}
mask >>= EscBits;
if(mask < nelem(tags) && tags[mask] != nil)
return tags[mask];
snprint(buf, sizeof buf, "esc:0x%x", mask);
s = strlit(buf);
if(mask < nelem(tags))
tags[mask] = s;
return s;
}
static int
parsetag(Strlit *note)
{
int em;
if(note == nil)
return EscUnknown;
if(strncmp(note->s, "esc:", 4) != 0)
return EscUnknown;
em = atoi(note->s + 4);
if (em == 0)
return EscNone;
return EscReturn | (em << EscBits);
}
static void
analyze(NodeList *all, int recursive)
{
NodeList *l;
EscState es, *e;
memset(&es, 0, sizeof es);
e = &es;
e->theSink.op = ONAME;
e->theSink.orig = &e->theSink;
e->theSink.class = PEXTERN;
e->theSink.sym = lookup(".sink");
e->theSink.escloopdepth = -1;
e->recursive = recursive;
e->funcParam.op = ONAME;
e->funcParam.orig = &e->funcParam;
e->funcParam.class = PAUTO;
e->funcParam.sym = lookup(".param");
e->funcParam.escloopdepth = 10000000;
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC)
l->n->esc = EscFuncPlanned;
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC)
escfunc(e, l->n);
for(l = e->dsts; l; l=l->next)
escflood(e, l->n);
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC)
esctag(e, l->n);
if(debug['m']) {
for(l=e->noesc; l; l=l->next)
if(l->n->esc == EscNone)
warnl(l->n->lineno, "%S %hN does not escape",
(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
l->n);
}
}
static void
escfunc(EscState *e, Node *func)
{
Node *savefn;
NodeList *ll;
int saveld;
if(func->esc != 1)
fatal("repeat escfunc %N", func->nname);
func->esc = EscFuncStarted;
saveld = e->loopdepth;
e->loopdepth = 1;
savefn = curfn;
curfn = func;
for(ll=curfn->dcl; ll; ll=ll->next) {
if(ll->n->op != ONAME)
continue;
switch (ll->n->class) {
case PPARAMOUT:
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)
ll->n->esc = EscHeap;
else
ll->n->esc = EscNone;
e->noesc = list(e->noesc, ll->n);
break;
}
}
if(e->recursive)
for(ll=curfn->dcl; ll; ll=ll->next)
if(ll->n->op == ONAME && ll->n->class == PPARAMOUT)
escflows(e, &e->theSink, ll->n);
escloopdepthlist(e, curfn->nbody);
esclist(e, curfn->nbody, curfn);
curfn = savefn;
e->loopdepth = saveld;
}
static Label looping;
static Label nonlooping;
static void
escloopdepthlist(EscState *e, NodeList *l)
{
for(; l; l=l->next)
escloopdepth(e, l->n);
}
static void
escloopdepth(EscState *e, Node *n)
{
if(n == N)
return;
escloopdepthlist(e, n->ninit);
switch(n->op) {
case OLABEL:
if(!n->left || !n->left->sym)
fatal("esc:label without 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(n->left->sym->label == &nonlooping)
n->left->sym->label = &looping;
break;
}
escloopdepth(e, n->left);
escloopdepth(e, n->right);
escloopdepthlist(e, n->list);
escloopdepth(e, n->ntest);
escloopdepth(e, n->nincr);
escloopdepthlist(e, n->nbody);
escloopdepthlist(e, n->nelse);
escloopdepthlist(e, n->rlist);
}
static void
esclist(EscState *e, NodeList *l, Node *up)
{
for(; l; l=l->next)
esc(e, l->n, up);
}
static void
esc(EscState *e, Node *n, Node *up)
{
int lno;
NodeList *ll, *lr;
Node *a;
if(n == N)
return;
lno = setlineno(n);
esclist(e, n->ninit, n);
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth++;
if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
for(ll=n->list; ll; ll=ll->next) {
if(ll->n->nname)
ll->n->nname->escloopdepth = e->loopdepth;
}
}
esc(e, n->left, n);
esc(e, n->right, n);
esc(e, n->ntest, n);
esc(e, n->nincr, n);
esclist(e, n->nbody, n);
esclist(e, n->nelse, n);
esclist(e, n->list, n);
esclist(e, n->rlist, n);
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth--;
if(debug['m'] > 1)
print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
(curfn && curfn->nname) ? curfn->nname->sym : S, n);
switch(n->op) {
case ODCL:
if(n->left)
n->left->escloopdepth = e->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);
e->loopdepth++;
}
n->left->sym->label = nil;
break;
case ORANGE:
if(isfixedarray(n->type) && n->list->next)
escassign(e, n->list->next->n, n->right);
break;
case OSWITCH:
if(n->ntest && n->ntest->op == OTYPESW) {
for(ll=n->list; ll; ll=ll->next) {
escassign(e, ll->n->nname, n->ntest->right);
}
}
break;
case OAS:
case OASOP:
escassign(e, n->left, n->right);
break;
case OAS2:
if(count(n->list) == count(n->rlist))
for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
escassign(e, ll->n, lr->n);
break;
case OAS2RECV:
case OAS2MAPR:
case OAS2DOTTYPE:
escassign(e, n->list->n, n->rlist->n);
break;
case OSEND:
escassign(e, &e->theSink, n->right);
break;
case ODEFER:
if(e->loopdepth == 1)
break;
case OPROC:
escassign(e, &e->theSink, n->left->left);
escassign(e, &e->theSink, n->left->right);
for(ll=n->left->list; ll; ll=ll->next)
escassign(e, &e->theSink, ll->n);
break;
case OCALLMETH:
case OCALLFUNC:
case OCALLINTER:
esccall(e, n, up);
break;
case OAS2FUNC:
lr=n->rlist->n->escretval;
for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next)
escassign(e, ll->n, lr->n);
if(lr || ll)
fatal("esc oas2func");
break;
case ORETURN:
ll=n->list;
if(count(n->list) == 1 && curfn->type->outtuple > 1) {
ll = n->list->n->escretval;
}
for(lr = curfn->dcl; lr && ll; lr=lr->next) {
if (lr->n->op != ONAME || lr->n->class != PPARAMOUT)
continue;
escassign(e, lr->n, ll->n);
ll = ll->next;
}
if (ll != nil)
fatal("esc return list");
break;
case OPANIC:
escassign(e, &e->theSink, n->left);
break;
case OAPPEND:
if(!n->isddd)
for(ll=n->list->next; ll; ll=ll->next)
escassign(e, &e->theSink, ll->n);
break;
case OCONV:
case OCONVNOP:
case OCONVIFACE:
escassign(e, n, n->left);
break;
case OARRAYLIT:
if(isslice(n->type)) {
n->esc = EscNone;
e->noesc = list(e->noesc, n);
n->escloopdepth = e->loopdepth;
for(ll=n->list; ll; ll=ll->next)
escassign(e, &e->theSink, ll->n->right);
} else {
for(ll=n->list; ll; ll=ll->next)
escassign(e, n, ll->n->right);
}
break;
case OSTRUCTLIT:
for(ll=n->list; ll; ll=ll->next)
escassign(e, n, ll->n->right);
break;
case OPTRLIT:
n->esc = EscNone;
e->noesc = list(e->noesc, n);
n->escloopdepth = e->loopdepth;
escassign(e, &e->theSink, n->left);
break;
case OCALLPART:
n->esc = EscNone;
e->noesc = list(e->noesc, n);
n->escloopdepth = e->loopdepth;
escassign(e, &e->theSink, n->left);
break;
case OMAPLIT:
n->esc = EscNone;
e->noesc = list(e->noesc, n);
n->escloopdepth = e->loopdepth;
for(ll=n->list; ll; ll=ll->next) {
escassign(e, &e->theSink, ll->n->left);
escassign(e, &e->theSink, ll->n->right);
}
break;
case OCLOSURE:
for(ll=n->cvars; ll; ll=ll->next) {
if(ll->n->op == OXXX)
continue;
a = nod(OADDR, ll->n->closure, N);
a->lineno = ll->n->lineno;
a->escloopdepth = e->loopdepth;
typecheck(&a, Erv);
escassign(e, n, a);
}
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
case ONEW:
n->escloopdepth = e->loopdepth;
n->esc = EscNone;
e->noesc = list(e->noesc, n);
break;
case OADDR:
n->esc = EscNone;
e->noesc = list(e->noesc, n);
n->escloopdepth = e->loopdepth;
if(n->left->op == ONAME) {
switch(n->left->class) {
case PAUTO:
if(n->left->escloopdepth != 0)
n->escloopdepth = n->left->escloopdepth;
break;
case PPARAM:
case PPARAMOUT:
n->escloopdepth = 1;
break;
}
}
break;
}
lineno = lno;
}
static void
escassign(EscState *e, Node *dst, Node *src)
{
int lno;
NodeList *ll;
if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
return;
if(debug['m'] > 1)
print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
(curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
setlineno(dst);
switch(dst->op) {
default:
dump("dst", dst);
fatal("escassign: unexpected dst");
case OARRAYLIT:
case OCLOSURE:
case OCONV:
case OCONVIFACE:
case OCONVNOP:
case OMAPLIT:
case OSTRUCTLIT:
case OCALLPART:
break;
case ONAME:
if(dst->class == PEXTERN)
dst = &e->theSink;
break;
case ODOT:
escassign(e, dst->left, src);
return;
case OINDEX:
if(isfixedarray(dst->left->type)) {
escassign(e, dst->left, src);
return;
}
dst = &e->theSink;
break;
case OIND:
case ODOTPTR:
dst = &e->theSink;
break;
case OINDEXMAP:
escassign(e, &e->theSink, dst->right);
dst = &e->theSink;
break;
}
lno = setlineno(src);
e->pdepth++;
switch(src->op) {
case OADDR:
case OIND:
case ODOTPTR:
case ONAME:
case OPARAM:
case ODDDARG:
case OPTRLIT:
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
case ONEW:
case OCLOSURE:
case OCALLPART:
escflows(e, dst, src);
break;
case OCALLMETH:
case OCALLFUNC:
case OCALLINTER:
for(ll=src->escretval; ll; ll=ll->next)
escflows(e, dst, ll->n);
break;
case ODOT:
if(src->type && !haspointers(src->type))
break;
case OCONV:
case OCONVIFACE:
case OCONVNOP:
case ODOTMETH:
case ODOTTYPE:
case ODOTTYPE2:
case OSLICE:
case OSLICE3:
case OSLICEARR:
case OSLICE3ARR:
escassign(e, dst, src->left);
break;
case OAPPEND:
escassign(e, dst, src->list->n);
break;
case OINDEX:
if(isfixedarray(src->left->type))
escassign(e, dst, src->left);
break;
case OADD:
case OSUB:
case OOR:
case OXOR:
case OMUL:
case ODIV:
case OMOD:
case OLSH:
case ORSH:
case OAND:
case OANDNOT:
case OPLUS:
case OMINUS:
case OCOM:
escassign(e, dst, src->left);
escassign(e, dst, src->right);
break;
}
e->pdepth--;
lineno = lno;
}
static int
escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
{
int em, em0;
em = parsetag(note);
if(em == EscUnknown) {
escassign(e, &e->theSink, src);
return em;
}
if(em == EscNone)
return em;
if(em & EscContentEscapes)
escassign(e, &e->funcParam, src);
em0 = em;
for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next)
if(em & 1)
escassign(e, dsts->n, src);
if (em != 0 && dsts == nil)
fatal("corrupt esc tag %Z or messed up escretval list\n", note);
return em0;
}
static void
esccall(EscState *e, Node *n, Node *up)
{
NodeList *ll, *lr;
Node *a, *fn, *src;
Type *t, *fntype;
char buf[40];
int i;
fn = N;
switch(n->op) {
default:
fatal("esccall");
case OCALLFUNC:
fn = n->left;
fntype = fn->type;
break;
case OCALLMETH:
fn = n->left->right->sym->def;
if(fn)
fntype = fn->type;
else
fntype = n->left->type;
break;
case OCALLINTER:
fntype = n->left->type;
break;
}
ll = n->list;
if(n->list != nil && n->list->next == nil) {
a = n->list->n;
if(a->type->etype == TSTRUCT && a->type->funarg)
ll = a->escretval;
}
if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
fatal("graph inconsistency");
for(lr=fn->ntype->rlist; lr; lr=lr->next)
n->escretval = list(n->escretval, lr->n->left);
if(n->op != OCALLFUNC)
escassign(e, fn->ntype->left->left, n->left->left);
for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
src = ll->n;
if(lr->n->isddd && !n->isddd) {
src = nod(ODDDARG, N, N);
src->type = typ(TARRAY);
src->type->type = lr->n->type->type;
src->type->bound = count(ll);
src->type = ptrto(src->type);
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
src->esc = EscNone;
e->noesc = list(e->noesc, src);
n->right = src;
}
if(lr->n->left != N)
escassign(e, lr->n->left, src);
if(src != ll->n)
break;
}
for(; ll; ll=ll->next)
escassign(e, &e->theSink, ll->n);
return;
}
if(n->escretval != nil)
fatal("esc already decorated call %+N\n", n);
i = 0;
for(t=getoutargx(fntype)->type; t; t=t->down) {
src = nod(ONAME, N, N);
snprint(buf, sizeof buf, ".dum%d", i++);
src->sym = lookup(buf);
src->type = t->type;
src->class = PAUTO;
src->curfn = curfn;
src->escloopdepth = e->loopdepth;
src->used = 1;
src->lineno = n->lineno;
n->escretval = list(n->escretval, src);
}
if(n->op != OCALLFUNC) {
t = getthisx(fntype)->type;
src = n->left->left;
if(haspointers(t->type))
escassignfromtag(e, t->note, n->escretval, src);
}
for(t=getinargx(fntype)->type; ll; ll=ll->next) {
src = ll->n;
if(t->isddd && !n->isddd) {
src = nod(ODDDARG, N, N);
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
src->type = typ(TARRAY);
src->type->type = t->type->type;
src->type->bound = count(ll);
src->type = ptrto(src->type);
src->esc = EscNone;
e->noesc = list(e->noesc, src);
n->right = src;
}
if(haspointers(t->type)) {
if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) {
a = src;
while(a->op == OCONVNOP)
a = a->left;
switch(a->op) {
case OCALLPART:
case OCLOSURE:
case ODDDARG:
case OARRAYLIT:
case OPTRLIT:
case OSTRUCTLIT:
a->noescape = 1;
break;
}
}
}
if(src != ll->n)
break;
t = t->down;
}
for(; ll; ll=ll->next)
escassign(e, &e->theSink, ll->n);
}
static void
escflows(EscState *e, Node *dst, Node *src)
{
if(dst == nil || src == nil || dst == src)
return;
if(src->type && !haspointers(src->type))
return;
if(debug['m']>2)
print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
if(dst->escflowsrc == nil) {
e->dsts = list(e->dsts, dst);
e->dstcount++;
}
e->edgecount++;
dst->escflowsrc = list(dst->escflowsrc, src);
}
static void
escflood(EscState *e, Node *dst)
{
NodeList *l;
switch(dst->op) {
case ONAME:
case OCLOSURE:
break;
default:
return;
}
if(debug['m']>1)
print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
(dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
dst->escloopdepth);
for(l = dst->escflowsrc; l; l=l->next) {
walkgen++;
escwalk(e, 0, dst, l->n);
}
}
#define MinLevel (-2)
static void
escwalk(EscState *e, int level, Node *dst, Node *src)
{
NodeList *ll;
int leaks, newlevel;
if(src->walkgen == walkgen && src->esclevel <= level)
return;
src->walkgen = walkgen;
src->esclevel = level;
if(debug['m']>1)
print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
(src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
e->pdepth++;
if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) {
if(level == 0) {
if(debug['m'])
warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
if((src->esc&EscMask) != EscReturn)
src->esc = EscReturn;
src->esc |= 1<<((dst->vargen-1) + EscReturnBits);
goto recurse;
} else if(level > 0) {
if(debug['m'])
warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym);
if((src->esc&EscMask) != EscReturn)
src->esc = EscReturn;
src->esc |= EscContentEscapes;
goto recurse;
}
}
}
leaks = level <= 0 && dst->escloopdepth < src->escloopdepth ||
level < 0 && dst == &e->funcParam && haspointers(src->type);
switch(src->op) {
case ONAME:
if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
src->esc = EscScope;
if(debug['m'])
warnl(src->lineno, "leaking param: %hN", src);
}
if(src->class == PPARAMREF) {
if(leaks && debug['m'])
warnl(src->lineno, "leaking closure reference %hN", src);
escwalk(e, level, dst, src->closure);
}
break;
case OPTRLIT:
case OADDR:
if(leaks) {
src->esc = EscHeap;
addrescapes(src->left);
if(debug['m'])
warnl(src->lineno, "%hN escapes to heap", src);
}
newlevel = level;
if(level > MinLevel)
newlevel--;
escwalk(e, newlevel, dst, src->left);
break;
case OARRAYLIT:
if(isfixedarray(src->type))
break;
case ODDDARG:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
case OMAPLIT:
case ONEW:
case OCLOSURE:
case OCALLPART:
if(leaks) {
src->esc = EscHeap;
if(debug['m'])
warnl(src->lineno, "%hN escapes to heap", src);
}
break;
case ODOT:
case OSLICE:
case OSLICEARR:
case OSLICE3:
case OSLICE3ARR:
escwalk(e, level, dst, src->left);
break;
case OINDEX:
if(isfixedarray(src->left->type)) {
escwalk(e, level, dst, src->left);
break;
}
case ODOTPTR:
case OINDEXMAP:
case OIND:
newlevel = level;
if(level > MinLevel)
newlevel++;
escwalk(e, newlevel, dst, src->left);
}
recurse:
for(ll=src->escflowsrc; ll; ll=ll->next)
escwalk(e, level, dst, ll->n);
e->pdepth--;
}
static void
esctag(EscState *e, Node *func)
{
Node *savefn;
NodeList *ll;
Type *t;
USED(e);
func->esc = EscFuncTagged;
if(func->nbody == nil) {
if(func->noescape) {
for(t=getinargx(func->type)->type; t; t=t->down)
if(haspointers(t->type))
t->note = mktag(EscNone);
}
return;
}
savefn = curfn;
curfn = func;
for(ll=curfn->dcl; ll; ll=ll->next) {
if(ll->n->op != ONAME || ll->n->class != PPARAM)
continue;
switch (ll->n->esc&EscMask) {
case EscNone:
case EscReturn:
if(haspointers(ll->n->type))
ll->n->paramfld->note = mktag(ll->n->esc);
break;
case EscHeap:
case EscScope:
break;
}
}
curfn = savefn;
}