github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/gc/esc.c (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Escape analysis.
     6  
     7  #include <u.h>
     8  #include <libc.h>
     9  #include "go.h"
    10  
    11  // Run analysis on minimal sets of mutually recursive functions
    12  // or single non-recursive functions, bottom up.
    13  //
    14  // Finding these sets is finding strongly connected components
    15  // in the static call graph.  The algorithm for doing that is taken
    16  // from Sedgewick, Algorithms, Second Edition, p. 482, with two
    17  // adaptations.
    18  //
    19  // First, a hidden closure function (n->curfn != N) cannot be the
    20  // root of a connected component. Refusing to use it as a root
    21  // forces it into the component of the function in which it appears.
    22  // The analysis assumes that closures and the functions in which they
    23  // appear are analyzed together, so that the aliasing between their
    24  // variables can be modeled more precisely.
    25  //
    26  // Second, each function becomes two virtual nodes in the graph,
    27  // with numbers n and n+1. We record the function's node number as n
    28  // but search from node n+1. If the search tells us that the component
    29  // number (min) is n+1, we know that this is a trivial component: one function
    30  // plus its closures. If the search tells us that the component number is
    31  // n, then there was a path from node n+1 back to node n, meaning that
    32  // the function set is mutually recursive. The escape analysis can be
    33  // more precise when analyzing a single non-recursive function than
    34  // when analyzing a set of mutually recursive functions.
    35  
    36  static NodeList *stack;
    37  static uint32 visitgen;
    38  static uint32 visit(Node*);
    39  static uint32 visitcode(Node*, uint32);
    40  static uint32 visitcodelist(NodeList*, uint32);
    41  
    42  static void analyze(NodeList*, int);
    43  
    44  enum
    45  {
    46  	EscFuncUnknown = 0,
    47  	EscFuncPlanned,
    48  	EscFuncStarted,
    49  	EscFuncTagged,
    50  };
    51  
    52  void
    53  escapes(NodeList *all)
    54  {
    55  	NodeList *l;
    56  
    57  	for(l=all; l; l=l->next)
    58  		l->n->walkgen = 0;
    59  
    60  	visitgen = 0;
    61  	for(l=all; l; l=l->next)
    62  		if(l->n->op == ODCLFUNC && l->n->curfn == N)
    63  			visit(l->n);
    64  
    65  	for(l=all; l; l=l->next)
    66  		l->n->walkgen = 0;
    67  }
    68  
    69  static uint32
    70  visit(Node *n)
    71  {
    72  	uint32 min, recursive;
    73  	NodeList *l, *block;
    74  
    75  	if(n->walkgen > 0) {
    76  		// already visited
    77  		return n->walkgen;
    78  	}
    79  	
    80  	visitgen++;
    81  	n->walkgen = visitgen;
    82  	visitgen++;
    83  	min = visitgen;
    84  
    85  	l = mal(sizeof *l);
    86  	l->next = stack;
    87  	l->n = n;
    88  	stack = l;
    89  	min = visitcodelist(n->nbody, min);
    90  	if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
    91  		// This node is the root of a strongly connected component.
    92  
    93  		// The original min passed to visitcodelist was n->walkgen+1.
    94  		// If visitcodelist found its way back to n->walkgen, then this
    95  		// block is a set of mutually recursive functions.
    96  		// Otherwise it's just a lone function that does not recurse.
    97  		recursive = min == n->walkgen;
    98  
    99  		// Remove connected component from stack.
   100  		// Mark walkgen so that future visits return a large number
   101  		// so as not to affect the caller's min.
   102  		block = stack;
   103  		for(l=stack; l->n != n; l=l->next)
   104  			l->n->walkgen = (uint32)~0U;
   105  		n->walkgen = (uint32)~0U;
   106  		stack = l->next;
   107  		l->next = nil;
   108  
   109  		// Run escape analysis on this set of functions.
   110  		analyze(block, recursive);
   111  	}
   112  
   113  	return min;
   114  }
   115  
   116  static uint32
   117  visitcodelist(NodeList *l, uint32 min)
   118  {
   119  	for(; l; l=l->next)
   120  		min = visitcode(l->n, min);
   121  	return min;
   122  }
   123  
   124  static uint32
   125  visitcode(Node *n, uint32 min)
   126  {
   127  	Node *fn;
   128  	uint32 m;
   129  
   130  	if(n == N)
   131  		return min;
   132  
   133  	min = visitcodelist(n->ninit, min);
   134  	min = visitcode(n->left, min);
   135  	min = visitcode(n->right, min);
   136  	min = visitcodelist(n->list, min);
   137  	min = visitcode(n->ntest, min);
   138  	min = visitcode(n->nincr, min);
   139  	min = visitcodelist(n->nbody, min);
   140  	min = visitcodelist(n->nelse, min);
   141  	min = visitcodelist(n->rlist, min);
   142  	
   143  	if(n->op == OCALLFUNC || n->op == OCALLMETH) {
   144  		fn = n->left;
   145  		if(n->op == OCALLMETH)
   146  			fn = n->left->right->sym->def;
   147  		if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody)
   148  			if((m = visit(fn->defn)) < min)
   149  				min = m;
   150  	}
   151  	
   152  	if(n->op == OCLOSURE)
   153  		if((m = visit(n->closure)) < min)
   154  			min = m;
   155  
   156  	return min;
   157  }
   158  
   159  // An escape analysis pass for a set of functions.
   160  //
   161  // First escfunc, esc and escassign recurse over the ast of each
   162  // function to dig out flow(dst,src) edges between any
   163  // pointer-containing nodes and store them in dst->escflowsrc.  For
   164  // variables assigned to a variable in an outer scope or used as a
   165  // return value, they store a flow(theSink, src) edge to a fake node
   166  // 'the Sink'.  For variables referenced in closures, an edge
   167  // flow(closure, &var) is recorded and the flow of a closure itself to
   168  // an outer scope is tracked the same way as other variables.
   169  //
   170  // Then escflood walks the graph starting at theSink and tags all
   171  // variables of it can reach an & node as escaping and all function
   172  // parameters it can reach as leaking.
   173  //
   174  // If a value's address is taken but the address does not escape,
   175  // then the value can stay on the stack.  If the value new(T) does
   176  // not escape, then new(T) can be rewritten into a stack allocation.
   177  // The same is true of slice literals.
   178  //
   179  // If optimizations are disabled (-N), this code is not used.
   180  // Instead, the compiler assumes that any value whose address
   181  // is taken without being immediately dereferenced
   182  // needs to be moved to the heap, and new(T) and slice
   183  // literals are always real allocations.
   184  
   185  typedef struct EscState EscState;
   186  
   187  static void escfunc(EscState*, Node *func);
   188  static void esclist(EscState*, NodeList *l);
   189  static void esc(EscState*, Node *n);
   190  static void escloopdepthlist(EscState*, NodeList *l);
   191  static void escloopdepth(EscState*, Node *n);
   192  static void escassign(EscState*, Node *dst, Node *src);
   193  static void esccall(EscState*, Node*);
   194  static void escflows(EscState*, Node *dst, Node *src);
   195  static void escflood(EscState*, Node *dst);
   196  static void escwalk(EscState*, int level, Node *dst, Node *src);
   197  static void esctag(EscState*, Node *func);
   198  
   199  struct EscState {
   200  	// Fake node that all
   201  	//   - return values and output variables
   202  	//   - parameters on imported functions not marked 'safe'
   203  	//   - assignments to global variables
   204  	// flow to.
   205  	Node	theSink;
   206  	
   207  	NodeList*	dsts;		// all dst nodes
   208  	int	loopdepth;	// for detecting nested loop scopes
   209  	int	pdepth;		// for debug printing in recursions.
   210  	int	dstcount, edgecount;	// diagnostic
   211  	NodeList*	noesc;	// list of possible non-escaping nodes, for printing
   212  	int	recursive;	// recursive function or group of mutually recursive functions.
   213  };
   214  
   215  static Strlit *tags[16];
   216  
   217  static Strlit*
   218  mktag(int mask)
   219  {
   220  	Strlit *s;
   221  	char buf[40];
   222  
   223  	switch(mask&EscMask) {
   224  	case EscNone:
   225  	case EscReturn:
   226  		break;
   227  	default:
   228  		fatal("escape mktag");
   229  	}
   230  
   231  	mask >>= EscBits;
   232  
   233  	if(mask < nelem(tags) && tags[mask] != nil)
   234  		return tags[mask];
   235  
   236  	snprint(buf, sizeof buf, "esc:0x%x", mask);
   237  	s = strlit(buf);
   238  	if(mask < nelem(tags))
   239  		tags[mask] = s;
   240  	return s;
   241  }
   242  
   243  static int
   244  parsetag(Strlit *note)
   245  {
   246  	int em;
   247  
   248  	if(note == nil)
   249  		return EscUnknown;
   250  	if(strncmp(note->s, "esc:", 4) != 0)
   251  		return EscUnknown;
   252  	em = atoi(note->s + 4);
   253  	if (em == 0)
   254  		return EscNone;
   255  	return EscReturn | (em << EscBits);
   256  }
   257  
   258  static void
   259  analyze(NodeList *all, int recursive)
   260  {
   261  	NodeList *l;
   262  	EscState es, *e;
   263  	
   264  	memset(&es, 0, sizeof es);
   265  	e = &es;
   266  	e->theSink.op = ONAME;
   267  	e->theSink.orig = &e->theSink;
   268  	e->theSink.class = PEXTERN;
   269  	e->theSink.sym = lookup(".sink");
   270  	e->theSink.escloopdepth = -1;
   271  	e->recursive = recursive;
   272  
   273  	for(l=all; l; l=l->next)
   274  		if(l->n->op == ODCLFUNC)
   275  			l->n->esc = EscFuncPlanned;
   276  
   277  	// flow-analyze functions
   278  	for(l=all; l; l=l->next)
   279  		if(l->n->op == ODCLFUNC)
   280  			escfunc(e, l->n);
   281  
   282  	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
   283  
   284  	// visit the upstream of each dst, mark address nodes with
   285  	// addrescapes, mark parameters unsafe
   286  	for(l = e->dsts; l; l=l->next)
   287  		escflood(e, l->n);
   288  
   289  	// for all top level functions, tag the typenodes corresponding to the param nodes
   290  	for(l=all; l; l=l->next)
   291  		if(l->n->op == ODCLFUNC)
   292  			esctag(e, l->n);
   293  
   294  	if(debug['m']) {
   295  		for(l=e->noesc; l; l=l->next)
   296  			if(l->n->esc == EscNone)
   297  				warnl(l->n->lineno, "%S %hN does not escape",
   298  					(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
   299  					l->n);
   300  	}
   301  }
   302  
   303  
   304  static void
   305  escfunc(EscState *e, Node *func)
   306  {
   307  	Node *savefn;
   308  	NodeList *ll;
   309  	int saveld;
   310  
   311  //	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
   312  
   313  	if(func->esc != 1)
   314  		fatal("repeat escfunc %N", func->nname);
   315  	func->esc = EscFuncStarted;
   316  
   317  	saveld = e->loopdepth;
   318  	e->loopdepth = 1;
   319  	savefn = curfn;
   320  	curfn = func;
   321  
   322  	for(ll=curfn->dcl; ll; ll=ll->next) {
   323  		if(ll->n->op != ONAME)
   324  			continue;
   325  		switch (ll->n->class) {
   326  		case PPARAMOUT:
   327  			// out params are in a loopdepth between the sink and all local variables
   328  			ll->n->escloopdepth = 0;
   329  			break;
   330  		case PPARAM:
   331  			if(ll->n->type && !haspointers(ll->n->type))
   332  				break;
   333  			if(curfn->nbody == nil && !curfn->noescape)
   334  				ll->n->esc = EscHeap;
   335  			else
   336  				ll->n->esc = EscNone;	// prime for escflood later
   337  			e->noesc = list(e->noesc, ll->n);
   338  			ll->n->escloopdepth = 1; 
   339  			break;
   340  		}
   341  	}
   342  
   343  	// in a mutually recursive group we lose track of the return values
   344  	if(e->recursive)
   345  		for(ll=curfn->dcl; ll; ll=ll->next)
   346  			if(ll->n->op == ONAME && ll->n->class == PPARAMOUT)
   347  				escflows(e, &e->theSink, ll->n);
   348  
   349  	escloopdepthlist(e, curfn->nbody);
   350  	esclist(e, curfn->nbody);
   351  	curfn = savefn;
   352  	e->loopdepth = saveld;
   353  }
   354  
   355  // Mark labels that have no backjumps to them as not increasing e->loopdepth.
   356  // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
   357  // and set it to one of the following two.  Then in esc we'll clear it again.
   358  static Label looping;
   359  static Label nonlooping;
   360  
   361  static void
   362  escloopdepthlist(EscState *e, NodeList *l)
   363  {
   364  	for(; l; l=l->next)
   365  		escloopdepth(e, l->n);
   366  }
   367  
   368  static void
   369  escloopdepth(EscState *e, Node *n)
   370  {
   371  	if(n == N)
   372  		return;
   373  
   374  	escloopdepthlist(e, n->ninit);
   375  
   376  	switch(n->op) {
   377  	case OLABEL:
   378  		if(!n->left || !n->left->sym)
   379  			fatal("esc:label without label: %+N", n);
   380  		// Walk will complain about this label being already defined, but that's not until
   381  		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
   382  		// if(n->left->sym->label != nil)
   383  		//	fatal("escape analysis messed up analyzing label: %+N", n);
   384  		n->left->sym->label = &nonlooping;
   385  		break;
   386  	case OGOTO:
   387  		if(!n->left || !n->left->sym)
   388  			fatal("esc:goto without label: %+N", n);
   389  		// If we come past one that's uninitialized, this must be a (harmless) forward jump
   390  		// but if it's set to nonlooping the label must have preceded this goto.
   391  		if(n->left->sym->label == &nonlooping)
   392  			n->left->sym->label = &looping;
   393  		break;
   394  	}
   395  
   396  	escloopdepth(e, n->left);
   397  	escloopdepth(e, n->right);
   398  	escloopdepthlist(e, n->list);
   399  	escloopdepth(e, n->ntest);
   400  	escloopdepth(e, n->nincr);
   401  	escloopdepthlist(e, n->nbody);
   402  	escloopdepthlist(e, n->nelse);
   403  	escloopdepthlist(e, n->rlist);
   404  
   405  }
   406  
   407  static void
   408  esclist(EscState *e, NodeList *l)
   409  {
   410  	for(; l; l=l->next)
   411  		esc(e, l->n);
   412  }
   413  
   414  static void
   415  esc(EscState *e, Node *n)
   416  {
   417  	int lno;
   418  	NodeList *ll, *lr;
   419  	Node *a;
   420  
   421  	if(n == N)
   422  		return;
   423  
   424  	lno = setlineno(n);
   425  
   426  	if(n->op == OFOR || n->op == ORANGE)
   427  		e->loopdepth++;
   428  
   429  	esc(e, n->left);
   430  	esc(e, n->right);
   431  	esc(e, n->ntest);
   432  	esc(e, n->nincr);
   433  	esclist(e, n->ninit);
   434  	esclist(e, n->nbody);
   435  	esclist(e, n->nelse);
   436  	esclist(e, n->list);
   437  	esclist(e, n->rlist);
   438  
   439  	if(n->op == OFOR || n->op == ORANGE)
   440  		e->loopdepth--;
   441  
   442  	if(debug['m'] > 1)
   443  		print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
   444  		      (curfn && curfn->nname) ? curfn->nname->sym : S, n);
   445  
   446  	switch(n->op) {
   447  	case ODCL:
   448  		// Record loop depth at declaration.
   449  		if(n->left)
   450  			n->left->escloopdepth = e->loopdepth;
   451  		break;
   452  
   453  	case OLABEL:
   454  		if(n->left->sym->label == &nonlooping) {
   455  			if(debug['m'] > 1)
   456  				print("%L:%N non-looping label\n", lineno, n);
   457  		} else if(n->left->sym->label == &looping) {
   458  			if(debug['m'] > 1)
   459  				print("%L: %N looping label\n", lineno, n);
   460  			e->loopdepth++;
   461  		}
   462  		// See case OLABEL in escloopdepth above
   463  		// else if(n->left->sym->label == nil)
   464  		//	fatal("escape analysis missed or messed up a label: %+N", n);
   465  
   466  		n->left->sym->label = nil;
   467  		break;
   468  
   469  	case ORANGE:
   470  		// Everything but fixed array is a dereference.
   471  		if(isfixedarray(n->type) && n->list->next)
   472  			escassign(e, n->list->next->n, n->right);
   473  		break;
   474  
   475  	case OSWITCH:
   476  		if(n->ntest && n->ntest->op == OTYPESW) {
   477  			for(ll=n->list; ll; ll=ll->next) {  // cases
   478  				// ntest->right is the argument of the .(type),
   479  				// ll->n->nname is the variable per case
   480  				escassign(e, ll->n->nname, n->ntest->right);
   481  			}
   482  		}
   483  		break;
   484  
   485  	case OAS:
   486  	case OASOP:
   487  		escassign(e, n->left, n->right);
   488  		break;
   489  
   490  	case OAS2:	// x,y = a,b
   491  		if(count(n->list) == count(n->rlist))
   492  			for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
   493  				escassign(e, ll->n, lr->n);
   494  		break;
   495  
   496  	case OAS2RECV:		// v, ok = <-ch
   497  	case OAS2MAPR:		// v, ok = m[k]
   498  	case OAS2DOTTYPE:	// v, ok = x.(type)
   499  		escassign(e, n->list->n, n->rlist->n);
   500  		break;
   501  
   502  	case OSEND:		// ch <- x
   503  		escassign(e, &e->theSink, n->right);
   504  		break;
   505  
   506  	case ODEFER:
   507  		if(e->loopdepth == 1)  // top level
   508  			break;
   509  		// arguments leak out of scope
   510  		// TODO: leak to a dummy node instead
   511  		// fallthrough
   512  	case OPROC:
   513  		// go f(x) - f and x escape
   514  		escassign(e, &e->theSink, n->left->left);
   515  		escassign(e, &e->theSink, n->left->right);  // ODDDARG for call
   516  		for(ll=n->left->list; ll; ll=ll->next)
   517  			escassign(e, &e->theSink, ll->n);
   518  		break;
   519  
   520  	case OCALLMETH:
   521  	case OCALLFUNC:
   522  	case OCALLINTER:
   523  		esccall(e, n);
   524  		break;
   525  
   526  	case OAS2FUNC:	// x,y = f()
   527  		// esccall already done on n->rlist->n. tie it's escretval to n->list
   528  		lr=n->rlist->n->escretval;
   529  		for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next)
   530  			escassign(e, ll->n, lr->n);
   531  		if(lr || ll)
   532  			fatal("esc oas2func");
   533  		break;
   534  
   535  	case ORETURN:
   536  		ll=n->list;
   537  		if(count(n->list) == 1 && curfn->type->outtuple > 1) {
   538  			// OAS2FUNC in disguise
   539  			// esccall already done on n->list->n
   540  			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
   541  			ll = n->list->n->escretval;
   542  		}
   543  
   544  		for(lr = curfn->dcl; lr && ll; lr=lr->next) {
   545  			if (lr->n->op != ONAME || lr->n->class != PPARAMOUT)
   546  				continue;
   547  			escassign(e, lr->n, ll->n);
   548  			ll = ll->next;
   549  		}
   550  		if (ll != nil)
   551  			fatal("esc return list");
   552  		break;
   553  
   554  	case OPANIC:
   555  		// Argument could leak through recover.
   556  		escassign(e, &e->theSink, n->left);
   557  		break;
   558  
   559  	case OAPPEND:
   560  		if(!n->isddd)
   561  			for(ll=n->list->next; ll; ll=ll->next)
   562  				escassign(e, &e->theSink, ll->n);  // lose track of assign to dereference
   563  		break;
   564  
   565  	case OCONV:
   566  	case OCONVNOP:
   567  	case OCONVIFACE:
   568  		escassign(e, n, n->left);
   569  		break;
   570  
   571  	case OARRAYLIT:
   572  		if(isslice(n->type)) {
   573  			n->esc = EscNone;  // until proven otherwise
   574  			e->noesc = list(e->noesc, n);
   575  			n->escloopdepth = e->loopdepth;
   576  			// Values make it to memory, lose track.
   577  			for(ll=n->list; ll; ll=ll->next)
   578  				escassign(e, &e->theSink, ll->n->right);
   579  		} else {
   580  			// Link values to array.
   581  			for(ll=n->list; ll; ll=ll->next)
   582  				escassign(e, n, ll->n->right);
   583  		}
   584  		break;
   585  
   586  	case OSTRUCTLIT:
   587  		// Link values to struct.
   588  		for(ll=n->list; ll; ll=ll->next)
   589  			escassign(e, n, ll->n->right);
   590  		break;
   591  	
   592  	case OPTRLIT:
   593  		n->esc = EscNone;  // until proven otherwise
   594  		e->noesc = list(e->noesc, n);
   595  		n->escloopdepth = e->loopdepth;
   596  		// Contents make it to memory, lose track.
   597  		escassign(e, &e->theSink, n->left);
   598  		break;
   599  	
   600  	case OCALLPART:
   601  		n->esc = EscNone; // until proven otherwise
   602  		e->noesc = list(e->noesc, n);
   603  		n->escloopdepth = e->loopdepth;
   604  		// Contents make it to memory, lose track.
   605  		escassign(e, &e->theSink, n->left);
   606  		break;
   607  
   608  	case OMAPLIT:
   609  		n->esc = EscNone;  // until proven otherwise
   610  		e->noesc = list(e->noesc, n);
   611  		n->escloopdepth = e->loopdepth;
   612  		// Keys and values make it to memory, lose track.
   613  		for(ll=n->list; ll; ll=ll->next) {
   614  			escassign(e, &e->theSink, ll->n->left);
   615  			escassign(e, &e->theSink, ll->n->right);
   616  		}
   617  		break;
   618  	
   619  	case OCLOSURE:
   620  		// Link addresses of captured variables to closure.
   621  		for(ll=n->cvars; ll; ll=ll->next) {
   622  			if(ll->n->op == OXXX)  // unnamed out argument; see dcl.c:/^funcargs
   623  				continue;
   624  			a = nod(OADDR, ll->n->closure, N);
   625  			a->lineno = ll->n->lineno;
   626  			a->escloopdepth = e->loopdepth;
   627  			typecheck(&a, Erv);
   628  			escassign(e, n, a);
   629  		}
   630  		// fallthrough
   631  	case OADDR:
   632  	case OMAKECHAN:
   633  	case OMAKEMAP:
   634  	case OMAKESLICE:
   635  	case ONEW:
   636  		n->escloopdepth = e->loopdepth;
   637  		n->esc = EscNone;  // until proven otherwise
   638  		e->noesc = list(e->noesc, n);
   639  		break;
   640  	}
   641  
   642  	lineno = lno;
   643  }
   644  
   645  // Assert that expr somehow gets assigned to dst, if non nil.  for
   646  // dst==nil, any name node expr still must be marked as being
   647  // evaluated in curfn.	For expr==nil, dst must still be examined for
   648  // evaluations inside it (e.g *f(x) = y)
   649  static void
   650  escassign(EscState *e, Node *dst, Node *src)
   651  {
   652  	int lno;
   653  	NodeList *ll;
   654  
   655  	if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
   656  		return;
   657  
   658  	if(debug['m'] > 1)
   659  		print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
   660  		      (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
   661  
   662  	setlineno(dst);
   663  	
   664  	// Analyze lhs of assignment.
   665  	// Replace dst with e->theSink if we can't track it.
   666  	switch(dst->op) {
   667  	default:
   668  		dump("dst", dst);
   669  		fatal("escassign: unexpected dst");
   670  
   671  	case OARRAYLIT:
   672  	case OCLOSURE:
   673  	case OCONV:
   674  	case OCONVIFACE:
   675  	case OCONVNOP:
   676  	case OMAPLIT:
   677  	case OSTRUCTLIT:
   678  	case OCALLPART:
   679  		break;
   680  
   681  	case ONAME:
   682  		if(dst->class == PEXTERN)
   683  			dst = &e->theSink;
   684  		break;
   685  	case ODOT:	      // treat "dst.x  = src" as "dst = src"
   686  		escassign(e, dst->left, src);
   687  		return;
   688  	case OINDEX:
   689  		if(isfixedarray(dst->left->type)) {
   690  			escassign(e, dst->left, src);
   691  			return;
   692  		}
   693  		dst = &e->theSink;  // lose track of dereference
   694  		break;
   695  	case OIND:
   696  	case ODOTPTR:
   697  		dst = &e->theSink;  // lose track of dereference
   698  		break;
   699  	case OINDEXMAP:
   700  		// lose track of key and value
   701  		escassign(e, &e->theSink, dst->right);
   702  		dst = &e->theSink;
   703  		break;
   704  	}
   705  
   706  	lno = setlineno(src);
   707  	e->pdepth++;
   708  
   709  	switch(src->op) {
   710  	case OADDR:	// dst = &x
   711  	case OIND:	// dst = *x
   712  	case ODOTPTR:	// dst = (*x).f
   713  	case ONAME:
   714  	case OPARAM:
   715  	case ODDDARG:
   716  	case OPTRLIT:
   717  	case OARRAYLIT:
   718  	case OMAPLIT:
   719  	case OSTRUCTLIT:
   720  	case OMAKECHAN:
   721  	case OMAKEMAP:
   722  	case OMAKESLICE:
   723  	case ONEW:
   724  	case OCLOSURE:
   725  	case OCALLPART:
   726  		escflows(e, dst, src);
   727  		break;
   728  
   729  	case OCALLMETH:
   730  	case OCALLFUNC:
   731  	case OCALLINTER:
   732  		// Flowing multiple returns to a single dst happens when
   733  		// analyzing "go f(g())": here g() flows to sink (issue 4529).
   734  		for(ll=src->escretval; ll; ll=ll->next)
   735  			escflows(e, dst, ll->n);
   736  		break;
   737  
   738  	case ODOT:
   739  		// A non-pointer escaping from a struct does not concern us.
   740  		if(src->type && !haspointers(src->type))
   741  			break;
   742  		// fallthrough
   743  	case OCONV:
   744  	case OCONVIFACE:
   745  	case OCONVNOP:
   746  	case ODOTMETH:	// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
   747  			// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
   748  	case ODOTTYPE:
   749  	case ODOTTYPE2:
   750  	case OSLICE:
   751  	case OSLICEARR:
   752  		// Conversions, field access, slice all preserve the input value.
   753  		escassign(e, dst, src->left);
   754  		break;
   755  
   756  	case OAPPEND:
   757  		// Append returns first argument.
   758  		escassign(e, dst, src->list->n);
   759  		break;
   760  	
   761  	case OINDEX:
   762  		// Index of array preserves input value.
   763  		if(isfixedarray(src->left->type))
   764  			escassign(e, dst, src->left);
   765  		break;
   766  
   767  	case OADD:
   768  	case OSUB:
   769  	case OOR:
   770  	case OXOR:
   771  	case OMUL:
   772  	case ODIV:
   773  	case OMOD:
   774  	case OLSH:
   775  	case ORSH:
   776  	case OAND:
   777  	case OANDNOT:
   778  	case OPLUS:
   779  	case OMINUS:
   780  	case OCOM:
   781  		// Might be pointer arithmetic, in which case
   782  		// the operands flow into the result.
   783  		// TODO(rsc): Decide what the story is here.  This is unsettling.
   784  		escassign(e, dst, src->left);
   785  		escassign(e, dst, src->right);
   786  		break;
   787  	}
   788  
   789  	e->pdepth--;
   790  	lineno = lno;
   791  }
   792  
   793  static void
   794  escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
   795  {
   796  	int em;
   797  	
   798  	em = parsetag(note);
   799  	
   800  	if(em == EscUnknown) {
   801  		escassign(e, &e->theSink, src);
   802  		return;
   803  	}
   804  		
   805  	for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next)
   806  		if(em & 1)
   807  			escassign(e, dsts->n, src);
   808  
   809  	if (em != 0 && dsts == nil)
   810  		fatal("corrupt esc tag %Z or messed up escretval list\n", note);
   811  }
   812  
   813  // This is a bit messier than fortunate, pulled out of esc's big
   814  // switch for clarity.	We either have the paramnodes, which may be
   815  // connected to other things through flows or we have the parameter type
   816  // nodes, which may be marked "noescape". Navigating the ast is slightly
   817  // different for methods vs plain functions and for imported vs
   818  // this-package
   819  static void
   820  esccall(EscState *e, Node *n)
   821  {
   822  	NodeList *ll, *lr;
   823  	Node *a, *fn, *src;
   824  	Type *t, *fntype;
   825  	char buf[40];
   826  	int i;
   827  
   828  	fn = N;
   829  	switch(n->op) {
   830  	default:
   831  		fatal("esccall");
   832  
   833  	case OCALLFUNC:
   834  		fn = n->left;
   835  		fntype = fn->type;
   836  		break;
   837  
   838  	case OCALLMETH:
   839  		fn = n->left->right->sym->def;
   840  		if(fn)
   841  			fntype = fn->type;
   842  		else
   843  			fntype = n->left->type;
   844  		break;
   845  
   846  	case OCALLINTER:
   847  		fntype = n->left->type;
   848  		break;
   849  	}
   850  
   851  	ll = n->list;
   852  	if(n->list != nil && n->list->next == nil) {
   853  		a = n->list->n;
   854  		if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
   855  			ll = a->escretval;
   856  	}
   857  			
   858  	if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
   859  		// function in same mutually recursive group.  Incorporate into flow graph.
   860  //		print("esc local fn: %N\n", fn->ntype);
   861  		if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
   862  			fatal("graph inconsistency");
   863  
   864  		// set up out list on this call node
   865  		for(lr=fn->ntype->rlist; lr; lr=lr->next)
   866  			n->escretval = list(n->escretval, lr->n->left);  // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
   867  
   868  		// Receiver.
   869  		if(n->op != OCALLFUNC)
   870  			escassign(e, fn->ntype->left->left, n->left->left);
   871  
   872  		for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
   873  			src = ll->n;
   874  			if(lr->n->isddd && !n->isddd) {
   875  				// Introduce ODDDARG node to represent ... allocation.
   876  				src = nod(ODDDARG, N, N);
   877  				src->escloopdepth = e->loopdepth;
   878  				src->lineno = n->lineno;
   879  				src->esc = EscNone;  // until we find otherwise
   880  				e->noesc = list(e->noesc, src);
   881  				n->right = src;
   882  			}
   883  			if(lr->n->left != N)
   884  				escassign(e, lr->n->left, src);
   885  			if(src != ll->n)
   886  				break;
   887  		}
   888  		// "..." arguments are untracked
   889  		for(; ll; ll=ll->next)
   890  			escassign(e, &e->theSink, ll->n);
   891  
   892  		return;
   893  	}
   894  
   895  	// Imported or completely analyzed function.  Use the escape tags.
   896  	if(n->escretval != nil)
   897  		fatal("esc already decorated call %+N\n", n);
   898  
   899  	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
   900  	i = 0;
   901  	for(t=getoutargx(fntype)->type; t; t=t->down) {
   902  		src = nod(ONAME, N, N);
   903  		snprint(buf, sizeof buf, ".dum%d", i++);
   904  		src->sym = lookup(buf);
   905  		src->type = t->type;
   906  		src->class = PAUTO;
   907  		src->curfn = curfn;
   908  		src->escloopdepth = e->loopdepth;
   909  		src->used = 1;
   910  		src->lineno = n->lineno;
   911  		n->escretval = list(n->escretval, src); 
   912  	}
   913  
   914  //	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
   915  
   916  	// Receiver.
   917  	if(n->op != OCALLFUNC)
   918  		escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left);
   919  	
   920  	for(t=getinargx(fntype)->type; ll; ll=ll->next) {
   921  		src = ll->n;
   922  		if(t->isddd && !n->isddd) {
   923  			// Introduce ODDDARG node to represent ... allocation.
   924  			src = nod(ODDDARG, N, N);
   925  			src->escloopdepth = e->loopdepth;
   926  			src->lineno = n->lineno;
   927  			src->esc = EscNone;  // until we find otherwise
   928  			e->noesc = list(e->noesc, src);
   929  			n->right = src;
   930  		}
   931  		escassignfromtag(e, t->note, n->escretval, src);
   932  		if(src != ll->n)
   933  			break;
   934  		t = t->down;
   935  	}
   936  	// "..." arguments are untracked
   937  	for(; ll; ll=ll->next)
   938  		escassign(e, &e->theSink, ll->n);
   939  }
   940  
   941  // Store the link src->dst in dst, throwing out some quick wins.
   942  static void
   943  escflows(EscState *e, Node *dst, Node *src)
   944  {
   945  	if(dst == nil || src == nil || dst == src)
   946  		return;
   947  
   948  	// Don't bother building a graph for scalars.
   949  	if(src->type && !haspointers(src->type))
   950  		return;
   951  
   952  	if(debug['m']>2)
   953  		print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
   954  
   955  	if(dst->escflowsrc == nil) {
   956  		e->dsts = list(e->dsts, dst);
   957  		e->dstcount++;
   958  	}
   959  	e->edgecount++;
   960  
   961  	dst->escflowsrc = list(dst->escflowsrc, src);
   962  }
   963  
   964  // Whenever we hit a reference node, the level goes up by one, and whenever
   965  // we hit an OADDR, the level goes down by one. as long as we're on a level > 0
   966  // finding an OADDR just means we're following the upstream of a dereference,
   967  // so this address doesn't leak (yet).
   968  // If level == 0, it means the /value/ of this node can reach the root of this flood.
   969  // so if this node is an OADDR, it's argument should be marked as escaping iff
   970  // it's currfn/e->loopdepth are different from the flood's root.
   971  // Once an object has been moved to the heap, all of it's upstream should be considered
   972  // escaping to the global scope.
   973  static void
   974  escflood(EscState *e, Node *dst)
   975  {
   976  	NodeList *l;
   977  
   978  	switch(dst->op) {
   979  	case ONAME:
   980  	case OCLOSURE:
   981  		break;
   982  	default:
   983  		return;
   984  	}
   985  
   986  	if(debug['m']>1)
   987  		print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
   988  		      (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
   989  		      dst->escloopdepth);
   990  
   991  	for(l = dst->escflowsrc; l; l=l->next) {
   992  		walkgen++;
   993  		escwalk(e, 0, dst, l->n);
   994  	}
   995  }
   996  
   997  // There appear to be some loops in the escape graph, causing
   998  // arbitrary recursion into deeper and deeper levels.
   999  // Cut this off safely by making minLevel sticky: once you
  1000  // get that deep, you cannot go down any further but you also
  1001  // cannot go up any further. This is a conservative fix.
  1002  // Making minLevel smaller (more negative) would handle more
  1003  // complex chains of indirections followed by address-of operations,
  1004  // at the cost of repeating the traversal once for each additional
  1005  // allowed level when a loop is encountered. Using -2 suffices to
  1006  // pass all the tests we have written so far, which we assume matches
  1007  // the level of complexity we want the escape analysis code to handle.
  1008  #define MinLevel (-2)
  1009  
  1010  static void
  1011  escwalk(EscState *e, int level, Node *dst, Node *src)
  1012  {
  1013  	NodeList *ll;
  1014  	int leaks, newlevel;
  1015  
  1016  	if(src->walkgen == walkgen && src->esclevel <= level)
  1017  		return;
  1018  	src->walkgen = walkgen;
  1019  	src->esclevel = level;
  1020  
  1021  	if(debug['m']>1)
  1022  		print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
  1023  		      level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
  1024  		      (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
  1025  
  1026  	e->pdepth++;
  1027  
  1028  	// Input parameter flowing to output parameter?
  1029  	if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
  1030  		if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
  1031  			if(src->esc != EscScope && src->esc != EscHeap) {
  1032  				if(debug['m'])
  1033  					warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
  1034  				if((src->esc&EscMask) != EscReturn)
  1035  					src->esc = EscReturn;
  1036  				src->esc |= 1<<((dst->vargen-1) + EscBits);
  1037  				goto recurse;
  1038  			}
  1039  		}
  1040  	}
  1041  
  1042  	leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
  1043  
  1044  	switch(src->op) {
  1045  	case ONAME:
  1046  		if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
  1047  			src->esc = EscScope;
  1048  			if(debug['m'])
  1049  				warnl(src->lineno, "leaking param: %hN", src);
  1050  		}
  1051  
  1052  		// Treat a PPARAMREF closure variable as equivalent to the
  1053  		// original variable.
  1054  		if(src->class == PPARAMREF) {
  1055  			if(leaks && debug['m'])
  1056  				warnl(src->lineno, "leaking closure reference %hN", src);
  1057  			escwalk(e, level, dst, src->closure);
  1058  		}
  1059  		break;
  1060  
  1061  	case OPTRLIT:
  1062  	case OADDR:
  1063  		if(leaks) {
  1064  			src->esc = EscHeap;
  1065  			addrescapes(src->left);
  1066  			if(debug['m'])
  1067  				warnl(src->lineno, "%hN escapes to heap", src);
  1068  		}
  1069  		newlevel = level;
  1070  		if(level > MinLevel)
  1071  			newlevel--;
  1072  		escwalk(e, newlevel, dst, src->left);
  1073  		break;
  1074  
  1075  	case OARRAYLIT:
  1076  		if(isfixedarray(src->type))
  1077  			break;
  1078  		// fall through
  1079  	case ODDDARG:
  1080  	case OMAKECHAN:
  1081  	case OMAKEMAP:
  1082  	case OMAKESLICE:
  1083  	case OMAPLIT:
  1084  	case ONEW:
  1085  	case OCLOSURE:
  1086  	case OCALLPART:
  1087  		if(leaks) {
  1088  			src->esc = EscHeap;
  1089  			if(debug['m'])
  1090  				warnl(src->lineno, "%hN escapes to heap", src);
  1091  		}
  1092  		break;
  1093  
  1094  	case ODOT:
  1095  		escwalk(e, level, dst, src->left);
  1096  		break;
  1097  
  1098  	case OINDEX:
  1099  		if(isfixedarray(src->left->type)) {
  1100  			escwalk(e, level, dst, src->left);
  1101  			break;
  1102  		}
  1103  		// fall through
  1104  	case OSLICE:
  1105  	case ODOTPTR:
  1106  	case OINDEXMAP:
  1107  	case OIND:
  1108  		newlevel = level;
  1109  		if(level > MinLevel)
  1110  			newlevel++;
  1111  		escwalk(e, newlevel, dst, src->left);
  1112  	}
  1113  
  1114  recurse:
  1115  	for(ll=src->escflowsrc; ll; ll=ll->next)
  1116  		escwalk(e, level, dst, ll->n);
  1117  
  1118  	e->pdepth--;
  1119  }
  1120  
  1121  static void
  1122  esctag(EscState *e, Node *func)
  1123  {
  1124  	Node *savefn;
  1125  	NodeList *ll;
  1126  	Type *t;
  1127  
  1128  	USED(e);
  1129  	func->esc = EscFuncTagged;
  1130  	
  1131  	// External functions are assumed unsafe,
  1132  	// unless //go:noescape is given before the declaration.
  1133  	if(func->nbody == nil) {
  1134  		if(func->noescape) {
  1135  			for(t=getinargx(func->type)->type; t; t=t->down)
  1136  				if(haspointers(t->type))
  1137  					t->note = mktag(EscNone);
  1138  		}
  1139  		return;
  1140  	}
  1141  
  1142  	savefn = curfn;
  1143  	curfn = func;
  1144  
  1145  	for(ll=curfn->dcl; ll; ll=ll->next) {
  1146  		if(ll->n->op != ONAME || ll->n->class != PPARAM)
  1147  			continue;
  1148  
  1149  		switch (ll->n->esc&EscMask) {
  1150  		case EscNone:	// not touched by escflood
  1151  		case EscReturn:	
  1152  			if(haspointers(ll->n->type)) // don't bother tagging for scalars
  1153  				ll->n->paramfld->note = mktag(ll->n->esc);
  1154  			break;
  1155  		case EscHeap:	// touched by escflood, moved to heap
  1156  		case EscScope:	// touched by escflood, value leaves scope
  1157  			break;
  1158  		}
  1159  	}
  1160  
  1161  	curfn = savefn;
  1162  }