github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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)
   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  	case OSLICE3:
   753  	case OSLICE3ARR:
   754  		// Conversions, field access, slice all preserve the input value.
   755  		escassign(e, dst, src->left);
   756  		break;
   757  
   758  	case OAPPEND:
   759  		// Append returns first argument.
   760  		escassign(e, dst, src->list->n);
   761  		break;
   762  	
   763  	case OINDEX:
   764  		// Index of array preserves input value.
   765  		if(isfixedarray(src->left->type))
   766  			escassign(e, dst, src->left);
   767  		break;
   768  
   769  	case OADD:
   770  	case OSUB:
   771  	case OOR:
   772  	case OXOR:
   773  	case OMUL:
   774  	case ODIV:
   775  	case OMOD:
   776  	case OLSH:
   777  	case ORSH:
   778  	case OAND:
   779  	case OANDNOT:
   780  	case OPLUS:
   781  	case OMINUS:
   782  	case OCOM:
   783  		// Might be pointer arithmetic, in which case
   784  		// the operands flow into the result.
   785  		// TODO(rsc): Decide what the story is here.  This is unsettling.
   786  		escassign(e, dst, src->left);
   787  		escassign(e, dst, src->right);
   788  		break;
   789  	}
   790  
   791  	e->pdepth--;
   792  	lineno = lno;
   793  }
   794  
   795  static void
   796  escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
   797  {
   798  	int em;
   799  	
   800  	em = parsetag(note);
   801  	
   802  	if(em == EscUnknown) {
   803  		escassign(e, &e->theSink, src);
   804  		return;
   805  	}
   806  		
   807  	for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next)
   808  		if(em & 1)
   809  			escassign(e, dsts->n, src);
   810  
   811  	if (em != 0 && dsts == nil)
   812  		fatal("corrupt esc tag %Z or messed up escretval list\n", note);
   813  }
   814  
   815  // This is a bit messier than fortunate, pulled out of esc's big
   816  // switch for clarity.	We either have the paramnodes, which may be
   817  // connected to other things through flows or we have the parameter type
   818  // nodes, which may be marked "noescape". Navigating the ast is slightly
   819  // different for methods vs plain functions and for imported vs
   820  // this-package
   821  static void
   822  esccall(EscState *e, Node *n)
   823  {
   824  	NodeList *ll, *lr;
   825  	Node *a, *fn, *src;
   826  	Type *t, *fntype;
   827  	char buf[40];
   828  	int i;
   829  
   830  	fn = N;
   831  	switch(n->op) {
   832  	default:
   833  		fatal("esccall");
   834  
   835  	case OCALLFUNC:
   836  		fn = n->left;
   837  		fntype = fn->type;
   838  		break;
   839  
   840  	case OCALLMETH:
   841  		fn = n->left->right->sym->def;
   842  		if(fn)
   843  			fntype = fn->type;
   844  		else
   845  			fntype = n->left->type;
   846  		break;
   847  
   848  	case OCALLINTER:
   849  		fntype = n->left->type;
   850  		break;
   851  	}
   852  
   853  	ll = n->list;
   854  	if(n->list != nil && n->list->next == nil) {
   855  		a = n->list->n;
   856  		if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
   857  			ll = a->escretval;
   858  	}
   859  			
   860  	if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
   861  		// function in same mutually recursive group.  Incorporate into flow graph.
   862  //		print("esc local fn: %N\n", fn->ntype);
   863  		if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
   864  			fatal("graph inconsistency");
   865  
   866  		// set up out list on this call node
   867  		for(lr=fn->ntype->rlist; lr; lr=lr->next)
   868  			n->escretval = list(n->escretval, lr->n->left);  // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
   869  
   870  		// Receiver.
   871  		if(n->op != OCALLFUNC)
   872  			escassign(e, fn->ntype->left->left, n->left->left);
   873  
   874  		for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
   875  			src = ll->n;
   876  			if(lr->n->isddd && !n->isddd) {
   877  				// Introduce ODDDARG node to represent ... allocation.
   878  				src = nod(ODDDARG, N, N);
   879  				src->escloopdepth = e->loopdepth;
   880  				src->lineno = n->lineno;
   881  				src->esc = EscNone;  // until we find otherwise
   882  				e->noesc = list(e->noesc, src);
   883  				n->right = src;
   884  			}
   885  			if(lr->n->left != N)
   886  				escassign(e, lr->n->left, src);
   887  			if(src != ll->n)
   888  				break;
   889  		}
   890  		// "..." arguments are untracked
   891  		for(; ll; ll=ll->next)
   892  			escassign(e, &e->theSink, ll->n);
   893  
   894  		return;
   895  	}
   896  
   897  	// Imported or completely analyzed function.  Use the escape tags.
   898  	if(n->escretval != nil)
   899  		fatal("esc already decorated call %+N\n", n);
   900  
   901  	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
   902  	i = 0;
   903  	for(t=getoutargx(fntype)->type; t; t=t->down) {
   904  		src = nod(ONAME, N, N);
   905  		snprint(buf, sizeof buf, ".dum%d", i++);
   906  		src->sym = lookup(buf);
   907  		src->type = t->type;
   908  		src->class = PAUTO;
   909  		src->curfn = curfn;
   910  		src->escloopdepth = e->loopdepth;
   911  		src->used = 1;
   912  		src->lineno = n->lineno;
   913  		n->escretval = list(n->escretval, src); 
   914  	}
   915  
   916  //	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
   917  
   918  	// Receiver.
   919  	if(n->op != OCALLFUNC)
   920  		escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left);
   921  	
   922  	for(t=getinargx(fntype)->type; ll; ll=ll->next) {
   923  		src = ll->n;
   924  		if(t->isddd && !n->isddd) {
   925  			// Introduce ODDDARG node to represent ... allocation.
   926  			src = nod(ODDDARG, N, N);
   927  			src->escloopdepth = e->loopdepth;
   928  			src->lineno = n->lineno;
   929  			src->esc = EscNone;  // until we find otherwise
   930  			e->noesc = list(e->noesc, src);
   931  			n->right = src;
   932  		}
   933  		escassignfromtag(e, t->note, n->escretval, src);
   934  		if(src != ll->n)
   935  			break;
   936  		t = t->down;
   937  	}
   938  	// "..." arguments are untracked
   939  	for(; ll; ll=ll->next)
   940  		escassign(e, &e->theSink, ll->n);
   941  }
   942  
   943  // Store the link src->dst in dst, throwing out some quick wins.
   944  static void
   945  escflows(EscState *e, Node *dst, Node *src)
   946  {
   947  	if(dst == nil || src == nil || dst == src)
   948  		return;
   949  
   950  	// Don't bother building a graph for scalars.
   951  	if(src->type && !haspointers(src->type))
   952  		return;
   953  
   954  	if(debug['m']>2)
   955  		print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
   956  
   957  	if(dst->escflowsrc == nil) {
   958  		e->dsts = list(e->dsts, dst);
   959  		e->dstcount++;
   960  	}
   961  	e->edgecount++;
   962  
   963  	dst->escflowsrc = list(dst->escflowsrc, src);
   964  }
   965  
   966  // Whenever we hit a reference node, the level goes up by one, and whenever
   967  // we hit an OADDR, the level goes down by one. as long as we're on a level > 0
   968  // finding an OADDR just means we're following the upstream of a dereference,
   969  // so this address doesn't leak (yet).
   970  // If level == 0, it means the /value/ of this node can reach the root of this flood.
   971  // so if this node is an OADDR, it's argument should be marked as escaping iff
   972  // it's currfn/e->loopdepth are different from the flood's root.
   973  // Once an object has been moved to the heap, all of it's upstream should be considered
   974  // escaping to the global scope.
   975  static void
   976  escflood(EscState *e, Node *dst)
   977  {
   978  	NodeList *l;
   979  
   980  	switch(dst->op) {
   981  	case ONAME:
   982  	case OCLOSURE:
   983  		break;
   984  	default:
   985  		return;
   986  	}
   987  
   988  	if(debug['m']>1)
   989  		print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
   990  		      (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
   991  		      dst->escloopdepth);
   992  
   993  	for(l = dst->escflowsrc; l; l=l->next) {
   994  		walkgen++;
   995  		escwalk(e, 0, dst, l->n);
   996  	}
   997  }
   998  
   999  // There appear to be some loops in the escape graph, causing
  1000  // arbitrary recursion into deeper and deeper levels.
  1001  // Cut this off safely by making minLevel sticky: once you
  1002  // get that deep, you cannot go down any further but you also
  1003  // cannot go up any further. This is a conservative fix.
  1004  // Making minLevel smaller (more negative) would handle more
  1005  // complex chains of indirections followed by address-of operations,
  1006  // at the cost of repeating the traversal once for each additional
  1007  // allowed level when a loop is encountered. Using -2 suffices to
  1008  // pass all the tests we have written so far, which we assume matches
  1009  // the level of complexity we want the escape analysis code to handle.
  1010  #define MinLevel (-2)
  1011  
  1012  static void
  1013  escwalk(EscState *e, int level, Node *dst, Node *src)
  1014  {
  1015  	NodeList *ll;
  1016  	int leaks, newlevel;
  1017  
  1018  	if(src->walkgen == walkgen && src->esclevel <= level)
  1019  		return;
  1020  	src->walkgen = walkgen;
  1021  	src->esclevel = level;
  1022  
  1023  	if(debug['m']>1)
  1024  		print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
  1025  		      level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
  1026  		      (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
  1027  
  1028  	e->pdepth++;
  1029  
  1030  	// Input parameter flowing to output parameter?
  1031  	if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
  1032  		if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
  1033  			if(src->esc != EscScope && src->esc != EscHeap) {
  1034  				if(debug['m'])
  1035  					warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
  1036  				if((src->esc&EscMask) != EscReturn)
  1037  					src->esc = EscReturn;
  1038  				src->esc |= 1<<((dst->vargen-1) + EscBits);
  1039  				goto recurse;
  1040  			}
  1041  		}
  1042  	}
  1043  
  1044  	leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
  1045  
  1046  	switch(src->op) {
  1047  	case ONAME:
  1048  		if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
  1049  			src->esc = EscScope;
  1050  			if(debug['m'])
  1051  				warnl(src->lineno, "leaking param: %hN", src);
  1052  		}
  1053  
  1054  		// Treat a PPARAMREF closure variable as equivalent to the
  1055  		// original variable.
  1056  		if(src->class == PPARAMREF) {
  1057  			if(leaks && debug['m'])
  1058  				warnl(src->lineno, "leaking closure reference %hN", src);
  1059  			escwalk(e, level, dst, src->closure);
  1060  		}
  1061  		break;
  1062  
  1063  	case OPTRLIT:
  1064  	case OADDR:
  1065  		if(leaks) {
  1066  			src->esc = EscHeap;
  1067  			addrescapes(src->left);
  1068  			if(debug['m'])
  1069  				warnl(src->lineno, "%hN escapes to heap", src);
  1070  		}
  1071  		newlevel = level;
  1072  		if(level > MinLevel)
  1073  			newlevel--;
  1074  		escwalk(e, newlevel, dst, src->left);
  1075  		break;
  1076  
  1077  	case OARRAYLIT:
  1078  		if(isfixedarray(src->type))
  1079  			break;
  1080  		// fall through
  1081  	case ODDDARG:
  1082  	case OMAKECHAN:
  1083  	case OMAKEMAP:
  1084  	case OMAKESLICE:
  1085  	case OMAPLIT:
  1086  	case ONEW:
  1087  	case OCLOSURE:
  1088  	case OCALLPART:
  1089  		if(leaks) {
  1090  			src->esc = EscHeap;
  1091  			if(debug['m'])
  1092  				warnl(src->lineno, "%hN escapes to heap", src);
  1093  		}
  1094  		break;
  1095  
  1096  	case ODOT:
  1097  		escwalk(e, level, dst, src->left);
  1098  		break;
  1099  
  1100  	case OINDEX:
  1101  		if(isfixedarray(src->left->type)) {
  1102  			escwalk(e, level, dst, src->left);
  1103  			break;
  1104  		}
  1105  		// fall through
  1106  	case OSLICE:
  1107  	case ODOTPTR:
  1108  	case OINDEXMAP:
  1109  	case OIND:
  1110  		newlevel = level;
  1111  		if(level > MinLevel)
  1112  			newlevel++;
  1113  		escwalk(e, newlevel, dst, src->left);
  1114  	}
  1115  
  1116  recurse:
  1117  	for(ll=src->escflowsrc; ll; ll=ll->next)
  1118  		escwalk(e, level, dst, ll->n);
  1119  
  1120  	e->pdepth--;
  1121  }
  1122  
  1123  static void
  1124  esctag(EscState *e, Node *func)
  1125  {
  1126  	Node *savefn;
  1127  	NodeList *ll;
  1128  	Type *t;
  1129  
  1130  	USED(e);
  1131  	func->esc = EscFuncTagged;
  1132  	
  1133  	// External functions are assumed unsafe,
  1134  	// unless //go:noescape is given before the declaration.
  1135  	if(func->nbody == nil) {
  1136  		if(func->noescape) {
  1137  			for(t=getinargx(func->type)->type; t; t=t->down)
  1138  				if(haspointers(t->type))
  1139  					t->note = mktag(EscNone);
  1140  		}
  1141  		return;
  1142  	}
  1143  
  1144  	savefn = curfn;
  1145  	curfn = func;
  1146  
  1147  	for(ll=curfn->dcl; ll; ll=ll->next) {
  1148  		if(ll->n->op != ONAME || ll->n->class != PPARAM)
  1149  			continue;
  1150  
  1151  		switch (ll->n->esc&EscMask) {
  1152  		case EscNone:	// not touched by escflood
  1153  		case EscReturn:	
  1154  			if(haspointers(ll->n->type)) // don't bother tagging for scalars
  1155  				ll->n->paramfld->note = mktag(ll->n->esc);
  1156  			break;
  1157  		case EscHeap:	// touched by escflood, moved to heap
  1158  		case EscScope:	// touched by escflood, value leaves scope
  1159  			break;
  1160  		}
  1161  	}
  1162  
  1163  	curfn = savefn;
  1164  }