github.com/jonasi/go@v0.0.0-20150930005915-e78e654c1de0/src/cmd/compile/internal/gc/esc.go (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  package gc
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"fmt"
    10  	"strings"
    11  )
    12  
    13  // Run analysis on minimal sets of mutually recursive functions
    14  // or single non-recursive functions, bottom up.
    15  //
    16  // Finding these sets is finding strongly connected components
    17  // in the static call graph.  The algorithm for doing that is taken
    18  // from Sedgewick, Algorithms, Second Edition, p. 482, with two
    19  // adaptations.
    20  //
    21  // First, a hidden closure function (n->curfn != N) cannot be the
    22  // root of a connected component. Refusing to use it as a root
    23  // forces it into the component of the function in which it appears.
    24  // This is more convenient for escape analysis.
    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  type bottomUpVisitor struct {
    37  	analyze  func([]*Node, bool)
    38  	visitgen uint32
    39  	nodeID   map[*Node]uint32
    40  	stack    []*Node
    41  }
    42  
    43  // visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
    44  // It calls analyze with successive groups of functions, working from
    45  // the bottom of the call graph upward. Each time analyze is called with
    46  // a list of functions, every function on that list only calls other functions
    47  // on the list or functions that have been passed in previous invocations of
    48  // analyze. Closures appear in the same list as their outer functions.
    49  // The lists are as short as possible while preserving those requirements.
    50  // (In a typical program, many invocations of analyze will be passed just
    51  // a single function.) The boolean argument 'recursive' passed to analyze
    52  // specifies whether the functions on the list are mutually recursive.
    53  // If recursive is false, the list consists of only a single function and its closures.
    54  // If recursive is true, the list may still contain only a single function,
    55  // if that function is itself recursive.
    56  func visitBottomUp(list *NodeList, analyze func(list []*Node, recursive bool)) {
    57  	var v bottomUpVisitor
    58  	v.analyze = analyze
    59  	v.nodeID = make(map[*Node]uint32)
    60  	for l := list; l != nil; l = l.Next {
    61  		if l.N.Op == ODCLFUNC && l.N.Func.FCurfn == nil {
    62  			v.visit(l.N)
    63  		}
    64  	}
    65  }
    66  
    67  func (v *bottomUpVisitor) visit(n *Node) uint32 {
    68  	if id := v.nodeID[n]; id > 0 {
    69  		// already visited
    70  		return id
    71  	}
    72  
    73  	v.visitgen++
    74  	id := v.visitgen
    75  	v.nodeID[n] = id
    76  	v.visitgen++
    77  	min := v.visitgen
    78  
    79  	v.stack = append(v.stack, n)
    80  	min = v.visitcodelist(n.Nbody, min)
    81  	if (min == id || min == id+1) && n.Func.FCurfn == nil {
    82  		// This node is the root of a strongly connected component.
    83  
    84  		// The original min passed to visitcodelist was n->walkgen+1.
    85  		// If visitcodelist found its way back to n->walkgen, then this
    86  		// block is a set of mutually recursive functions.
    87  		// Otherwise it's just a lone function that does not recurse.
    88  		recursive := min == id
    89  
    90  		// Remove connected component from stack.
    91  		// Mark walkgen so that future visits return a large number
    92  		// so as not to affect the caller's min.
    93  
    94  		var i int
    95  		for i = len(v.stack) - 1; i >= 0; i-- {
    96  			x := v.stack[i]
    97  			if x == n {
    98  				break
    99  			}
   100  			v.nodeID[x] = ^uint32(0)
   101  		}
   102  		v.nodeID[n] = ^uint32(0)
   103  		block := v.stack[i:]
   104  		// Run escape analysis on this set of functions.
   105  		v.stack = v.stack[:i]
   106  		v.analyze(block, recursive)
   107  	}
   108  
   109  	return min
   110  }
   111  
   112  func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 {
   113  	for ; l != nil; l = l.Next {
   114  		min = v.visitcode(l.N, min)
   115  	}
   116  	return min
   117  }
   118  
   119  func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
   120  	if n == nil {
   121  		return min
   122  	}
   123  
   124  	min = v.visitcodelist(n.Ninit, min)
   125  	min = v.visitcode(n.Left, min)
   126  	min = v.visitcode(n.Right, min)
   127  	min = v.visitcodelist(n.List, min)
   128  	min = v.visitcodelist(n.Nbody, min)
   129  	min = v.visitcodelist(n.Rlist, min)
   130  
   131  	if n.Op == OCALLFUNC || n.Op == OCALLMETH {
   132  		fn := n.Left
   133  		if n.Op == OCALLMETH {
   134  			fn = n.Left.Right.Sym.Def
   135  		}
   136  		if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
   137  			m := v.visit(fn.Name.Defn)
   138  			if m < min {
   139  				min = m
   140  			}
   141  		}
   142  	}
   143  
   144  	if n.Op == OCLOSURE {
   145  		m := v.visit(n.Func.Closure)
   146  		if m < min {
   147  			min = m
   148  		}
   149  	}
   150  
   151  	return min
   152  }
   153  
   154  // Escape analysis.
   155  
   156  // An escape analysis pass for a set of functions.
   157  // The analysis assumes that closures and the functions in which they
   158  // appear are analyzed together, so that the aliasing between their
   159  // variables can be modeled more precisely.
   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  func escapes(all *NodeList) {
   186  	visitBottomUp(all, escAnalyze)
   187  }
   188  
   189  const (
   190  	EscFuncUnknown = 0 + iota
   191  	EscFuncPlanned
   192  	EscFuncStarted
   193  	EscFuncTagged
   194  )
   195  
   196  // There appear to be some loops in the escape graph, causing
   197  // arbitrary recursion into deeper and deeper levels.
   198  // Cut this off safely by making minLevel sticky: once you
   199  // get that deep, you cannot go down any further but you also
   200  // cannot go up any further. This is a conservative fix.
   201  // Making minLevel smaller (more negative) would handle more
   202  // complex chains of indirections followed by address-of operations,
   203  // at the cost of repeating the traversal once for each additional
   204  // allowed level when a loop is encountered. Using -2 suffices to
   205  // pass all the tests we have written so far, which we assume matches
   206  // the level of complexity we want the escape analysis code to handle.
   207  const (
   208  	MinLevel = -2
   209  )
   210  
   211  // A Level encodes the reference state and context applied to
   212  // (stack, heap) allocated memory.
   213  //
   214  // value is the overall sum of *(1) and &(-1) operations encountered
   215  // along a path from a destination (sink, return value) to a source
   216  // (allocation, parameter).
   217  //
   218  // suffixValue is the maximum-copy-started-suffix-level applied to a sink.
   219  // For example:
   220  // sink = x.left.left --> level=2, x is dereferenced twice and does not escape to sink.
   221  // sink = &Node{x} --> level=-1, x is accessible from sink via one "address of"
   222  // sink = &Node{&Node{x}} --> level=-2, x is accessible from sink via two "address of"
   223  // sink = &Node{&Node{x.left}} --> level=-1, but x is NOT accessible from sink because it was indirected and then copied.
   224  // (The copy operations are sometimes implicit in the source code; in this case,
   225  // value of x.left was copied into a field of a newly allocated Node)
   226  //
   227  // There's one of these for each Node, and the integer values
   228  // rarely exceed even what can be stored in 4 bits, never mind 8.
   229  type Level struct {
   230  	value, suffixValue int8
   231  }
   232  
   233  func (l Level) int() int {
   234  	return int(l.value)
   235  }
   236  
   237  func levelFrom(i int) Level {
   238  	if i <= MinLevel {
   239  		return Level{value: MinLevel}
   240  	}
   241  	return Level{value: int8(i)}
   242  }
   243  
   244  func satInc8(x int8) int8 {
   245  	if x == 127 {
   246  		return 127
   247  	}
   248  	return x + 1
   249  }
   250  
   251  func min8(a, b int8) int8 {
   252  	if a < b {
   253  		return a
   254  	}
   255  	return b
   256  }
   257  
   258  func max8(a, b int8) int8 {
   259  	if a > b {
   260  		return a
   261  	}
   262  	return b
   263  }
   264  
   265  // inc returns the level l + 1, representing the effect of an indirect (*) operation.
   266  func (l Level) inc() Level {
   267  	if l.value <= MinLevel {
   268  		return Level{value: MinLevel}
   269  	}
   270  	return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)}
   271  }
   272  
   273  // dec returns the level l - 1, representing the effect of an address-of (&) operation.
   274  func (l Level) dec() Level {
   275  	if l.value <= MinLevel {
   276  		return Level{value: MinLevel}
   277  	}
   278  	return Level{value: l.value - 1, suffixValue: l.suffixValue - 1}
   279  }
   280  
   281  // copy returns the level for a copy of a value with level l.
   282  func (l Level) copy() Level {
   283  	return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)}
   284  }
   285  
   286  func (l1 Level) min(l2 Level) Level {
   287  	return Level{
   288  		value:       min8(l1.value, l2.value),
   289  		suffixValue: min8(l1.suffixValue, l2.suffixValue)}
   290  }
   291  
   292  // guaranteedDereference returns the number of dereferences
   293  // applied to a pointer before addresses are taken/generated.
   294  // This is the maximum level computed from path suffixes starting
   295  // with copies where paths flow from destination to source.
   296  func (l Level) guaranteedDereference() int {
   297  	return int(l.suffixValue)
   298  }
   299  
   300  type NodeEscState struct {
   301  	Curfn        *Node
   302  	Escflowsrc   *NodeList // flow(this, src)
   303  	Escretval    *NodeList // on OCALLxxx, list of dummy return values
   304  	Escloopdepth int32     // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
   305  	Esclevel     Level
   306  	Walkgen      uint32
   307  }
   308  
   309  func (e *EscState) nodeEscState(n *Node) *NodeEscState {
   310  	if nE, ok := n.Opt().(*NodeEscState); ok {
   311  		return nE
   312  	}
   313  	if n.Opt() != nil {
   314  		Fatalf("nodeEscState: opt in use (%T)", n.Opt())
   315  	}
   316  	nE := new(NodeEscState)
   317  	nE.Curfn = Curfn
   318  	n.SetOpt(nE)
   319  	e.opts = append(e.opts, n)
   320  	return nE
   321  }
   322  
   323  func (e *EscState) track(n *Node) {
   324  	if Curfn == nil {
   325  		Fatalf("EscState.track: Curfn nil")
   326  	}
   327  	n.Esc = EscNone // until proven otherwise
   328  	nE := e.nodeEscState(n)
   329  	nE.Escloopdepth = e.loopdepth
   330  	e.noesc = list(e.noesc, n)
   331  }
   332  
   333  // Escape constants are numbered in order of increasing "escapiness"
   334  // to help make inferences be monotonic.  With the exception of
   335  // EscNever which is sticky, eX < eY means that eY is more exposed
   336  // than eX, and hence replaces it in a conservative analysis.
   337  const (
   338  	EscUnknown = iota
   339  	EscNone    // Does not escape to heap, result, or parameters.
   340  	EscReturn  // Is returned or reachable from returned.
   341  	EscScope   // Allocated in an inner loop scope, assigned to an outer loop scope,
   342  	// which allows the construction of non-escaping but arbitrarily large linked
   343  	// data structures (i.e., not eligible for allocation in a fixed-size stack frame).
   344  	EscHeap           // Reachable from the heap
   345  	EscNever          // By construction will not escape.
   346  	EscBits           = 3
   347  	EscMask           = (1 << EscBits) - 1
   348  	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap
   349  	EscReturnBits     = EscBits + 1
   350  	// Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3
   351  )
   352  
   353  // escMax returns the maximum of an existing escape value
   354  // (and its additional parameter flow flags) and a new escape type.
   355  func escMax(e, etype uint16) uint16 {
   356  	if e&EscMask >= EscScope {
   357  		// normalize
   358  		if e&^EscMask != 0 {
   359  			Fatalf("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask)
   360  		}
   361  	}
   362  	if e&EscMask > etype {
   363  		return e
   364  	}
   365  	if etype == EscNone || etype == EscReturn {
   366  		return (e &^ EscMask) | etype
   367  	}
   368  	return etype
   369  }
   370  
   371  // For each input parameter to a function, the escapeReturnEncoding describes
   372  // how the parameter may leak to the function's outputs.  This is currently the
   373  // "level" of the leak where level is 0 or larger (negative level means stored into
   374  // something whose address is returned -- but that implies stored into the heap,
   375  // hence EscHeap, which means that the details are not currently relevant. )
   376  const (
   377  	bitsPerOutputInTag = 3                                 // For each output, the number of bits for a tag
   378  	bitsMaskForTag     = uint16(1<<bitsPerOutputInTag) - 1 // The bit mask to extract a single tag.
   379  	maxEncodedLevel    = int(bitsMaskForTag - 1)           // The largest level that can be stored in a tag.
   380  )
   381  
   382  type EscState struct {
   383  	// Fake node that all
   384  	//   - return values and output variables
   385  	//   - parameters on imported functions not marked 'safe'
   386  	//   - assignments to global variables
   387  	// flow to.
   388  	theSink Node
   389  
   390  	dsts      *NodeList // all dst nodes
   391  	loopdepth int32     // for detecting nested loop scopes
   392  	pdepth    int       // for debug printing in recursions.
   393  	dstcount  int       // diagnostic
   394  	edgecount int       // diagnostic
   395  	noesc     *NodeList // list of possible non-escaping nodes, for printing
   396  	recursive bool      // recursive function or group of mutually recursive functions.
   397  	opts      []*Node   // nodes with .Opt initialized
   398  	walkgen   uint32
   399  }
   400  
   401  // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
   402  func funcSym(fn *Node) *Sym {
   403  	if fn == nil || fn.Func.Nname == nil {
   404  		return nil
   405  	}
   406  	return fn.Func.Nname.Sym
   407  }
   408  
   409  // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
   410  func (e *EscState) curfnSym(n *Node) *Sym {
   411  	nE := e.nodeEscState(n)
   412  	return funcSym(nE.Curfn)
   413  }
   414  
   415  func escAnalyze(all []*Node, recursive bool) {
   416  	var es EscState
   417  	e := &es
   418  	e.theSink.Op = ONAME
   419  	e.theSink.Orig = &e.theSink
   420  	e.theSink.Class = PEXTERN
   421  	e.theSink.Sym = Lookup(".sink")
   422  	e.nodeEscState(&e.theSink).Escloopdepth = -1
   423  	e.recursive = recursive
   424  
   425  	for i := len(all) - 1; i >= 0; i-- {
   426  		if n := all[i]; n.Op == ODCLFUNC {
   427  			n.Esc = EscFuncPlanned
   428  		}
   429  	}
   430  
   431  	// flow-analyze functions
   432  	for i := len(all) - 1; i >= 0; i-- {
   433  		if n := all[i]; n.Op == ODCLFUNC {
   434  			escfunc(e, n)
   435  		}
   436  	}
   437  
   438  	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
   439  
   440  	// visit the upstream of each dst, mark address nodes with
   441  	// addrescapes, mark parameters unsafe
   442  	for l := e.dsts; l != nil; l = l.Next {
   443  		escflood(e, l.N)
   444  	}
   445  
   446  	// for all top level functions, tag the typenodes corresponding to the param nodes
   447  	for i := len(all) - 1; i >= 0; i-- {
   448  		if n := all[i]; n.Op == ODCLFUNC {
   449  			esctag(e, n)
   450  		}
   451  	}
   452  
   453  	if Debug['m'] != 0 {
   454  		for l := e.noesc; l != nil; l = l.Next {
   455  			if l.N.Esc == EscNone {
   456  				Warnl(int(l.N.Lineno), "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort))
   457  			}
   458  		}
   459  	}
   460  	for _, x := range e.opts {
   461  		x.SetOpt(nil)
   462  	}
   463  }
   464  
   465  func escfunc(e *EscState, func_ *Node) {
   466  	//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
   467  	if func_.Esc != 1 {
   468  		Fatalf("repeat escfunc %v", func_.Func.Nname)
   469  	}
   470  	func_.Esc = EscFuncStarted
   471  
   472  	saveld := e.loopdepth
   473  	e.loopdepth = 1
   474  	savefn := Curfn
   475  	Curfn = func_
   476  
   477  	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
   478  		if ll.N.Op != ONAME {
   479  			continue
   480  		}
   481  		llNE := e.nodeEscState(ll.N)
   482  		switch ll.N.Class {
   483  		// out params are in a loopdepth between the sink and all local variables
   484  		case PPARAMOUT:
   485  			llNE.Escloopdepth = 0
   486  
   487  		case PPARAM:
   488  			llNE.Escloopdepth = 1
   489  			if ll.N.Type != nil && !haspointers(ll.N.Type) {
   490  				break
   491  			}
   492  			if Curfn.Nbody == nil && !Curfn.Noescape {
   493  				ll.N.Esc = EscHeap
   494  			} else {
   495  				ll.N.Esc = EscNone // prime for escflood later
   496  			}
   497  			e.noesc = list(e.noesc, ll.N)
   498  		}
   499  	}
   500  
   501  	// in a mutually recursive group we lose track of the return values
   502  	if e.recursive {
   503  		for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
   504  			if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT {
   505  				escflows(e, &e.theSink, ll.N)
   506  			}
   507  		}
   508  	}
   509  
   510  	escloopdepthlist(e, Curfn.Nbody)
   511  	esclist(e, Curfn.Nbody, Curfn)
   512  	Curfn = savefn
   513  	e.loopdepth = saveld
   514  }
   515  
   516  // Mark labels that have no backjumps to them as not increasing e->loopdepth.
   517  // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
   518  // and set it to one of the following two.  Then in esc we'll clear it again.
   519  var looping Label
   520  
   521  var nonlooping Label
   522  
   523  func escloopdepthlist(e *EscState, l *NodeList) {
   524  	for ; l != nil; l = l.Next {
   525  		escloopdepth(e, l.N)
   526  	}
   527  }
   528  
   529  func escloopdepth(e *EscState, n *Node) {
   530  	if n == nil {
   531  		return
   532  	}
   533  
   534  	escloopdepthlist(e, n.Ninit)
   535  
   536  	switch n.Op {
   537  	case OLABEL:
   538  		if n.Left == nil || n.Left.Sym == nil {
   539  			Fatalf("esc:label without label: %v", Nconv(n, obj.FmtSign))
   540  		}
   541  
   542  		// Walk will complain about this label being already defined, but that's not until
   543  		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
   544  		// if(n->left->sym->label != nil)
   545  		//	fatal("escape analysis messed up analyzing label: %+N", n);
   546  		n.Left.Sym.Label = &nonlooping
   547  
   548  	case OGOTO:
   549  		if n.Left == nil || n.Left.Sym == nil {
   550  			Fatalf("esc:goto without label: %v", Nconv(n, obj.FmtSign))
   551  		}
   552  
   553  		// If we come past one that's uninitialized, this must be a (harmless) forward jump
   554  		// but if it's set to nonlooping the label must have preceded this goto.
   555  		if n.Left.Sym.Label == &nonlooping {
   556  			n.Left.Sym.Label = &looping
   557  		}
   558  	}
   559  
   560  	escloopdepth(e, n.Left)
   561  	escloopdepth(e, n.Right)
   562  	escloopdepthlist(e, n.List)
   563  	escloopdepthlist(e, n.Nbody)
   564  	escloopdepthlist(e, n.Rlist)
   565  }
   566  
   567  func esclist(e *EscState, l *NodeList, up *Node) {
   568  	for ; l != nil; l = l.Next {
   569  		esc(e, l.N, up)
   570  	}
   571  }
   572  
   573  func esc(e *EscState, n *Node, up *Node) {
   574  	if n == nil {
   575  		return
   576  	}
   577  
   578  	lno := int(setlineno(n))
   579  
   580  	// ninit logically runs at a different loopdepth than the rest of the for loop.
   581  	esclist(e, n.Ninit, n)
   582  
   583  	if n.Op == OFOR || n.Op == ORANGE {
   584  		e.loopdepth++
   585  	}
   586  
   587  	// type switch variables have no ODCL.
   588  	// process type switch as declaration.
   589  	// must happen before processing of switch body,
   590  	// so before recursion.
   591  	if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW {
   592  		for ll := n.List; ll != nil; ll = ll.Next { // cases
   593  
   594  			// ll.N.Rlist is the variable per case
   595  			if ll.N.Rlist != nil {
   596  				e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth
   597  			}
   598  		}
   599  	}
   600  
   601  	// Big stuff escapes unconditionally
   602  	// "Big" conditions that were scattered around in walk have been gathered here
   603  	if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
   604  		n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
   605  		n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
   606  		if Debug['m'] > 1 {
   607  			Warnl(int(n.Lineno), "%v is too large for stack", n)
   608  		}
   609  		n.Esc = EscHeap
   610  		addrescapes(n)
   611  		escassign(e, &e.theSink, n)
   612  	}
   613  
   614  	esc(e, n.Left, n)
   615  	esc(e, n.Right, n)
   616  	esclist(e, n.Nbody, n)
   617  	esclist(e, n.List, n)
   618  	esclist(e, n.Rlist, n)
   619  
   620  	if n.Op == OFOR || n.Op == ORANGE {
   621  		e.loopdepth--
   622  	}
   623  
   624  	if Debug['m'] > 1 {
   625  		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
   626  	}
   627  
   628  	switch n.Op {
   629  	// Record loop depth at declaration.
   630  	case ODCL:
   631  		if n.Left != nil {
   632  			e.nodeEscState(n.Left).Escloopdepth = e.loopdepth
   633  		}
   634  
   635  	case OLABEL:
   636  		if n.Left.Sym.Label == &nonlooping {
   637  			if Debug['m'] > 1 {
   638  				fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n)
   639  			}
   640  		} else if n.Left.Sym.Label == &looping {
   641  			if Debug['m'] > 1 {
   642  				fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n)
   643  			}
   644  			e.loopdepth++
   645  		}
   646  
   647  		// See case OLABEL in escloopdepth above
   648  		// else if(n->left->sym->label == nil)
   649  		//	fatal("escape analysis missed or messed up a label: %+N", n);
   650  
   651  		n.Left.Sym.Label = nil
   652  
   653  		// Everything but fixed array is a dereference.
   654  	case ORANGE:
   655  		if n.List != nil && n.List.Next != nil {
   656  			if Isfixedarray(n.Type) {
   657  				escassign(e, n.List.Next.N, n.Right)
   658  			} else {
   659  				escassignDereference(e, n.List.Next.N, n.Right)
   660  			}
   661  		}
   662  
   663  	case OSWITCH:
   664  		if n.Left != nil && n.Left.Op == OTYPESW {
   665  			for ll := n.List; ll != nil; ll = ll.Next {
   666  				// cases
   667  				// n.Left.Right is the argument of the .(type),
   668  				// ll.N.Rlist is the variable per case
   669  				if ll.N.Rlist != nil {
   670  					escassign(e, ll.N.Rlist.N, n.Left.Right)
   671  				}
   672  			}
   673  		}
   674  
   675  		// Filter out the following special case.
   676  	//
   677  	//	func (b *Buffer) Foo() {
   678  	//		n, m := ...
   679  	//		b.buf = b.buf[n:m]
   680  	//	}
   681  	//
   682  	// This assignment is a no-op for escape analysis,
   683  	// it does not store any new pointers into b that were not already there.
   684  	// However, without this special case b will escape, because we assign to OIND/ODOTPTR.
   685  	case OAS, OASOP, OASWB:
   686  		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference
   687  			(n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation
   688  			(n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference
   689  			n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME
   690  
   691  			// Here we also assume that the statement will not contain calls,
   692  			// that is, that order will move any calls to init.
   693  			// Otherwise base ONAME value could change between the moments
   694  			// when we evaluate it for dst and for src.
   695  			//
   696  			// Note, this optimization does not apply to OSLICEARR,
   697  			// because it does introduce a new pointer into b that was not already there
   698  			// (pointer to b itself). After such assignment, if b contents escape,
   699  			// b escapes as well. If we ignore such OSLICEARR, we will conclude
   700  			// that b does not escape when b contents do.
   701  			if Debug['m'] != 0 {
   702  				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort))
   703  			}
   704  
   705  			break
   706  		}
   707  
   708  		escassign(e, n.Left, n.Right)
   709  
   710  	case OAS2: // x,y = a,b
   711  		if count(n.List) == count(n.Rlist) {
   712  			ll := n.List
   713  			lr := n.Rlist
   714  			for ; ll != nil; ll, lr = ll.Next, lr.Next {
   715  				escassign(e, ll.N, lr.N)
   716  			}
   717  		}
   718  
   719  	case OAS2RECV, // v, ok = <-ch
   720  		OAS2MAPR,    // v, ok = m[k]
   721  		OAS2DOTTYPE: // v, ok = x.(type)
   722  		escassign(e, n.List.N, n.Rlist.N)
   723  
   724  	case OSEND: // ch <- x
   725  		escassign(e, &e.theSink, n.Right)
   726  
   727  	case ODEFER:
   728  		if e.loopdepth == 1 { // top level
   729  			break
   730  		}
   731  		// arguments leak out of scope
   732  		// TODO: leak to a dummy node instead
   733  		fallthrough
   734  
   735  	case OPROC:
   736  		// go f(x) - f and x escape
   737  		escassign(e, &e.theSink, n.Left.Left)
   738  
   739  		escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call
   740  		for ll := n.Left.List; ll != nil; ll = ll.Next {
   741  			escassign(e, &e.theSink, ll.N)
   742  		}
   743  
   744  	case OCALLMETH, OCALLFUNC, OCALLINTER:
   745  		esccall(e, n, up)
   746  
   747  		// esccall already done on n->rlist->n. tie it's escretval to n->list
   748  	case OAS2FUNC: // x,y = f()
   749  		lr := e.nodeEscState(n.Rlist.N).Escretval
   750  
   751  		var ll *NodeList
   752  		for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next {
   753  			escassign(e, ll.N, lr.N)
   754  		}
   755  		if lr != nil || ll != nil {
   756  			Fatalf("esc oas2func")
   757  		}
   758  
   759  	case ORETURN:
   760  		ll := n.List
   761  		if count(n.List) == 1 && Curfn.Type.Outtuple > 1 {
   762  			// OAS2FUNC in disguise
   763  			// esccall already done on n->list->n
   764  			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
   765  			ll = e.nodeEscState(n.List.N).Escretval
   766  		}
   767  
   768  		for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
   769  			if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
   770  				continue
   771  			}
   772  			escassign(e, lr.N, ll.N)
   773  			ll = ll.Next
   774  		}
   775  
   776  		if ll != nil {
   777  			Fatalf("esc return list")
   778  		}
   779  
   780  		// Argument could leak through recover.
   781  	case OPANIC:
   782  		escassign(e, &e.theSink, n.Left)
   783  
   784  	case OAPPEND:
   785  		if !n.Isddd {
   786  			for ll := n.List.Next; ll != nil; ll = ll.Next {
   787  				escassign(e, &e.theSink, ll.N) // lose track of assign to dereference
   788  			}
   789  		} else {
   790  			// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
   791  			slice2 := n.List.Next.N
   792  			escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference
   793  			if Debug['m'] > 2 {
   794  				Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort))
   795  			}
   796  		}
   797  		escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too
   798  
   799  	case OCOPY:
   800  		escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference
   801  
   802  	case OCONV, OCONVNOP:
   803  		escassign(e, n, n.Left)
   804  
   805  	case OCONVIFACE:
   806  		e.track(n)
   807  		escassign(e, n, n.Left)
   808  
   809  	case OARRAYLIT:
   810  		if Isslice(n.Type) {
   811  			// Slice itself is not leaked until proven otherwise
   812  			e.track(n)
   813  		}
   814  
   815  		// Link values to array/slice
   816  		for ll := n.List; ll != nil; ll = ll.Next {
   817  			escassign(e, n, ll.N.Right)
   818  		}
   819  
   820  		// Link values to struct.
   821  	case OSTRUCTLIT:
   822  		for ll := n.List; ll != nil; ll = ll.Next {
   823  			escassign(e, n, ll.N.Right)
   824  		}
   825  
   826  	case OPTRLIT:
   827  		e.track(n)
   828  
   829  		// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
   830  		escassign(e, n, n.Left)
   831  
   832  	case OCALLPART:
   833  		e.track(n)
   834  
   835  		// Contents make it to memory, lose track.
   836  		escassign(e, &e.theSink, n.Left)
   837  
   838  	case OMAPLIT:
   839  		e.track(n)
   840  
   841  		// Keys and values make it to memory, lose track.
   842  		for ll := n.List; ll != nil; ll = ll.Next {
   843  			escassign(e, &e.theSink, ll.N.Left)
   844  			escassign(e, &e.theSink, ll.N.Right)
   845  		}
   846  
   847  		// Link addresses of captured variables to closure.
   848  	case OCLOSURE:
   849  		var a *Node
   850  		var v *Node
   851  		for ll := n.Func.Cvars; ll != nil; ll = ll.Next {
   852  			v = ll.N
   853  			if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs
   854  				continue
   855  			}
   856  			a = v.Name.Param.Closure
   857  			if !v.Name.Byval {
   858  				a = Nod(OADDR, a, nil)
   859  				a.Lineno = v.Lineno
   860  				e.nodeEscState(a).Escloopdepth = e.loopdepth
   861  				typecheck(&a, Erv)
   862  			}
   863  
   864  			escassign(e, n, a)
   865  		}
   866  		fallthrough
   867  
   868  	case OMAKECHAN,
   869  		OMAKEMAP,
   870  		OMAKESLICE,
   871  		ONEW,
   872  		OARRAYRUNESTR,
   873  		OARRAYBYTESTR,
   874  		OSTRARRAYRUNE,
   875  		OSTRARRAYBYTE,
   876  		ORUNESTR:
   877  		e.track(n)
   878  
   879  	case OADDSTR:
   880  		e.track(n)
   881  		// Arguments of OADDSTR do not escape.
   882  
   883  	case OADDR:
   884  		// current loop depth is an upper bound on actual loop depth
   885  		// of addressed value.
   886  		e.track(n)
   887  
   888  		// for &x, use loop depth of x if known.
   889  		// it should always be known, but if not, be conservative
   890  		// and keep the current loop depth.
   891  		if n.Left.Op == ONAME {
   892  			switch n.Left.Class {
   893  			case PAUTO:
   894  				nE := e.nodeEscState(n)
   895  				leftE := e.nodeEscState(n.Left)
   896  				if leftE.Escloopdepth != 0 {
   897  					nE.Escloopdepth = leftE.Escloopdepth
   898  				}
   899  
   900  				// PPARAM is loop depth 1 always.
   901  			// PPARAMOUT is loop depth 0 for writes
   902  			// but considered loop depth 1 for address-of,
   903  			// so that writing the address of one result
   904  			// to another (or the same) result makes the
   905  			// first result move to the heap.
   906  			case PPARAM, PPARAMOUT:
   907  				nE := e.nodeEscState(n)
   908  				nE.Escloopdepth = 1
   909  			}
   910  		}
   911  	}
   912  
   913  	lineno = int32(lno)
   914  }
   915  
   916  // Assert that expr somehow gets assigned to dst, if non nil.  for
   917  // dst==nil, any name node expr still must be marked as being
   918  // evaluated in curfn.	For expr==nil, dst must still be examined for
   919  // evaluations inside it (e.g *f(x) = y)
   920  func escassign(e *EscState, dst *Node, src *Node) {
   921  	if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX {
   922  		return
   923  	}
   924  
   925  	if Debug['m'] > 1 {
   926  		fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
   927  			Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn),
   928  			Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0),
   929  			Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0))
   930  	}
   931  
   932  	setlineno(dst)
   933  
   934  	// Analyze lhs of assignment.
   935  	// Replace dst with e->theSink if we can't track it.
   936  	switch dst.Op {
   937  	default:
   938  		Dump("dst", dst)
   939  		Fatalf("escassign: unexpected dst")
   940  
   941  	case OARRAYLIT,
   942  		OCLOSURE,
   943  		OCONV,
   944  		OCONVIFACE,
   945  		OCONVNOP,
   946  		OMAPLIT,
   947  		OSTRUCTLIT,
   948  		OPTRLIT,
   949  		OCALLPART:
   950  		break
   951  
   952  	case ONAME:
   953  		if dst.Class == PEXTERN {
   954  			dst = &e.theSink
   955  		}
   956  
   957  	case ODOT: // treat "dst.x  = src" as "dst = src"
   958  		escassign(e, dst.Left, src)
   959  
   960  		return
   961  
   962  	case OINDEX:
   963  		if Isfixedarray(dst.Left.Type) {
   964  			escassign(e, dst.Left, src)
   965  			return
   966  		}
   967  
   968  		dst = &e.theSink // lose track of dereference
   969  
   970  	case OIND, ODOTPTR:
   971  		dst = &e.theSink // lose track of dereference
   972  
   973  		// lose track of key and value
   974  	case OINDEXMAP:
   975  		escassign(e, &e.theSink, dst.Right)
   976  
   977  		dst = &e.theSink
   978  	}
   979  
   980  	lno := int(setlineno(src))
   981  	e.pdepth++
   982  
   983  	switch src.Op {
   984  	case OADDR, // dst = &x
   985  		OIND,    // dst = *x
   986  		ODOTPTR, // dst = (*x).f
   987  		ONAME,
   988  		OPARAM,
   989  		ODDDARG,
   990  		OPTRLIT,
   991  		OARRAYLIT,
   992  		OMAPLIT,
   993  		OSTRUCTLIT,
   994  		OMAKECHAN,
   995  		OMAKEMAP,
   996  		OMAKESLICE,
   997  		OARRAYRUNESTR,
   998  		OARRAYBYTESTR,
   999  		OSTRARRAYRUNE,
  1000  		OSTRARRAYBYTE,
  1001  		OADDSTR,
  1002  		ONEW,
  1003  		OCALLPART,
  1004  		ORUNESTR,
  1005  		OCONVIFACE:
  1006  		escflows(e, dst, src)
  1007  
  1008  	case OCLOSURE:
  1009  		// OCLOSURE is lowered to OPTRLIT,
  1010  		// insert OADDR to account for the additional indirection.
  1011  		a := Nod(OADDR, src, nil)
  1012  		a.Lineno = src.Lineno
  1013  		e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth
  1014  		a.Type = Ptrto(src.Type)
  1015  		escflows(e, dst, a)
  1016  
  1017  	// Flowing multiple returns to a single dst happens when
  1018  	// analyzing "go f(g())": here g() flows to sink (issue 4529).
  1019  	case OCALLMETH, OCALLFUNC, OCALLINTER:
  1020  		for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next {
  1021  			escflows(e, dst, ll.N)
  1022  		}
  1023  
  1024  		// A non-pointer escaping from a struct does not concern us.
  1025  	case ODOT:
  1026  		if src.Type != nil && !haspointers(src.Type) {
  1027  			break
  1028  		}
  1029  		fallthrough
  1030  
  1031  		// Conversions, field access, slice all preserve the input value.
  1032  	case OCONV,
  1033  		OCONVNOP,
  1034  		ODOTMETH,
  1035  		// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
  1036  		// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
  1037  		ODOTTYPE,
  1038  		ODOTTYPE2,
  1039  		OSLICE,
  1040  		OSLICE3,
  1041  		OSLICEARR,
  1042  		OSLICE3ARR,
  1043  		OSLICESTR:
  1044  		// Conversions, field access, slice all preserve the input value.
  1045  		escassign(e, dst, src.Left)
  1046  
  1047  	case OAPPEND:
  1048  		// Append returns first argument.
  1049  		// Subsequent arguments are already leaked because they are operands to append.
  1050  		escassign(e, dst, src.List.N)
  1051  
  1052  	case OINDEX:
  1053  		// Index of array preserves input value.
  1054  		if Isfixedarray(src.Left.Type) {
  1055  			escassign(e, dst, src.Left)
  1056  		} else {
  1057  			escflows(e, dst, src)
  1058  		}
  1059  
  1060  		// Might be pointer arithmetic, in which case
  1061  	// the operands flow into the result.
  1062  	// TODO(rsc): Decide what the story is here.  This is unsettling.
  1063  	case OADD,
  1064  		OSUB,
  1065  		OOR,
  1066  		OXOR,
  1067  		OMUL,
  1068  		ODIV,
  1069  		OMOD,
  1070  		OLSH,
  1071  		ORSH,
  1072  		OAND,
  1073  		OANDNOT,
  1074  		OPLUS,
  1075  		OMINUS,
  1076  		OCOM:
  1077  		escassign(e, dst, src.Left)
  1078  
  1079  		escassign(e, dst, src.Right)
  1080  	}
  1081  
  1082  	e.pdepth--
  1083  	lineno = int32(lno)
  1084  }
  1085  
  1086  // Common case for escapes is 16 bits 000000000xxxEEEE
  1087  // where commonest cases for xxx encoding in-to-out pointer
  1088  //  flow are 000, 001, 010, 011  and EEEE is computed Esc bits.
  1089  // Note width of xxx depends on value of constant
  1090  // bitsPerOutputInTag -- expect 2 or 3, so in practice the
  1091  // tag cache array is 64 or 128 long.  Some entries will
  1092  // never be populated.
  1093  var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
  1094  
  1095  // mktag returns the string representation for an escape analysis tag.
  1096  func mktag(mask int) *string {
  1097  	switch mask & EscMask {
  1098  	case EscNone, EscReturn:
  1099  		break
  1100  
  1101  	default:
  1102  		Fatalf("escape mktag")
  1103  	}
  1104  
  1105  	if mask < len(tags) && tags[mask] != "" {
  1106  		return &tags[mask]
  1107  	}
  1108  
  1109  	s := fmt.Sprintf("esc:0x%x", mask)
  1110  	if mask < len(tags) {
  1111  		tags[mask] = s
  1112  	}
  1113  	return &s
  1114  }
  1115  
  1116  // parsetag decodes an escape analysis tag and returns the esc value.
  1117  func parsetag(note *string) uint16 {
  1118  	if note == nil || !strings.HasPrefix(*note, "esc:") {
  1119  		return EscUnknown
  1120  	}
  1121  	em := uint16(atoi((*note)[4:]))
  1122  	if em == 0 {
  1123  		return EscNone
  1124  	}
  1125  	return em
  1126  }
  1127  
  1128  // describeEscape returns a string describing the escape tag.
  1129  // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation
  1130  // or a description of parameter flow, which takes the form of an optional "contentToHeap"
  1131  // indicating that the content of this parameter is leaked to the heap, followed by a sequence
  1132  // of level encodings separated by spaces, one for each parameter, where _ means no flow,
  1133  // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow.
  1134  // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences)
  1135  // escapes to the heap, the parameter does not leak to the first output, but does leak directly
  1136  // to the second output (and if there are more than two outputs, there is no flow to those.)
  1137  func describeEscape(em uint16) string {
  1138  	var s string
  1139  	if em&EscMask == EscUnknown {
  1140  		s = "EscUnknown"
  1141  	}
  1142  	if em&EscMask == EscNone {
  1143  		s = "EscNone"
  1144  	}
  1145  	if em&EscMask == EscHeap {
  1146  		s = "EscHeap"
  1147  	}
  1148  	if em&EscMask == EscReturn {
  1149  		s = "EscReturn"
  1150  	}
  1151  	if em&EscMask == EscScope {
  1152  		s = "EscScope"
  1153  	}
  1154  	if em&EscContentEscapes != 0 {
  1155  		if s != "" {
  1156  			s += " "
  1157  		}
  1158  		s += "contentToHeap"
  1159  	}
  1160  	for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag {
  1161  		// See encoding description above
  1162  		if s != "" {
  1163  			s += " "
  1164  		}
  1165  		switch embits := em & bitsMaskForTag; embits {
  1166  		case 0:
  1167  			s += "_"
  1168  		case 1:
  1169  			s += "="
  1170  		default:
  1171  			for i := uint16(0); i < embits-1; i++ {
  1172  				s += "*"
  1173  			}
  1174  		}
  1175  
  1176  	}
  1177  	return s
  1178  }
  1179  
  1180  // escassignfromtag models the input-to-output assignment flow of one of a function
  1181  // calls arguments, where the flow is encoded in "note".
  1182  func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 {
  1183  	em := parsetag(note)
  1184  	if src.Op == OLITERAL {
  1185  		return em
  1186  	}
  1187  
  1188  	if Debug['m'] > 2 {
  1189  		fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
  1190  			Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em))
  1191  	}
  1192  
  1193  	if em == EscUnknown {
  1194  		escassign(e, &e.theSink, src)
  1195  		return em
  1196  	}
  1197  
  1198  	if em == EscNone {
  1199  		return em
  1200  	}
  1201  
  1202  	// If content inside parameter (reached via indirection)
  1203  	// escapes to heap, mark as such.
  1204  	if em&EscContentEscapes != 0 {
  1205  		escassign(e, &e.theSink, e.addDereference(src))
  1206  	}
  1207  
  1208  	em0 := em
  1209  	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next {
  1210  		// Prefer the lowest-level path to the reference (for escape purposes).
  1211  		// Two-bit encoding (for example. 1, 3, and 4 bits are other options)
  1212  		//  01 = 0-level
  1213  		//  10 = 1-level, (content escapes),
  1214  		//  11 = 2-level, (content of content escapes),
  1215  		embits := em & bitsMaskForTag
  1216  		if embits > 0 {
  1217  			n := src
  1218  			for i := uint16(0); i < embits-1; i++ {
  1219  				n = e.addDereference(n) // encode level>0 as indirections
  1220  			}
  1221  			escassign(e, dsts.N, n)
  1222  		}
  1223  	}
  1224  	// If there are too many outputs to fit in the tag,
  1225  	// that is handled at the encoding end as EscHeap,
  1226  	// so there is no need to check here.
  1227  
  1228  	if em != 0 && dsts == nil {
  1229  		Fatalf("corrupt esc tag %q or messed up escretval list\n", note)
  1230  	}
  1231  	return em0
  1232  }
  1233  
  1234  func escassignDereference(e *EscState, dst *Node, src *Node) {
  1235  	if src.Op == OLITERAL {
  1236  		return
  1237  	}
  1238  	escassign(e, dst, e.addDereference(src))
  1239  }
  1240  
  1241  // addDereference constructs a suitable OIND note applied to src.
  1242  // Because this is for purposes of escape accounting, not execution,
  1243  // some semantically dubious node combinations are (currently) possible.
  1244  func (e *EscState) addDereference(n *Node) *Node {
  1245  	ind := Nod(OIND, n, nil)
  1246  	e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth
  1247  	ind.Lineno = n.Lineno
  1248  	t := n.Type
  1249  	if Istype(t, Tptr) {
  1250  		// This should model our own sloppy use of OIND to encode
  1251  		// decreasing levels of indirection; i.e., "indirecting" an array
  1252  		// might yield the type of an element.  To be enhanced...
  1253  		t = t.Type
  1254  	}
  1255  	ind.Type = t
  1256  	return ind
  1257  }
  1258  
  1259  // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter.
  1260  // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel.
  1261  // If the encoding cannot describe the modified input level and output number, then EscHeap is returned.
  1262  func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
  1263  	// Flow+level is encoded in two bits.
  1264  	// 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel
  1265  	// 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful.
  1266  	if level.int() <= 0 && level.guaranteedDereference() > 0 {
  1267  		return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content.
  1268  	}
  1269  	if level.int() < 0 {
  1270  		return EscHeap
  1271  	}
  1272  	if level.int() > maxEncodedLevel {
  1273  		// Cannot encode larger values than maxEncodedLevel.
  1274  		level = levelFrom(maxEncodedLevel)
  1275  	}
  1276  	encoded := uint16(level.int() + 1)
  1277  
  1278  	shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits)
  1279  	old := (e >> shift) & bitsMaskForTag
  1280  	if old == 0 || encoded != 0 && encoded < old {
  1281  		old = encoded
  1282  	}
  1283  
  1284  	encodedFlow := old << shift
  1285  	if (encodedFlow>>shift)&bitsMaskForTag != old {
  1286  		// Encoding failure defaults to heap.
  1287  		return EscHeap
  1288  	}
  1289  
  1290  	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
  1291  }
  1292  
  1293  func initEscretval(e *EscState, n *Node, fntype *Type) {
  1294  	i := 0
  1295  	nE := e.nodeEscState(n)
  1296  	nE.Escretval = nil // Suspect this is not nil for indirect calls.
  1297  	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
  1298  		src := Nod(ONAME, nil, nil)
  1299  		buf := fmt.Sprintf(".out%d", i)
  1300  		i++
  1301  		src.Sym = Lookup(buf)
  1302  		src.Type = t.Type
  1303  		src.Class = PAUTO
  1304  		src.Name.Curfn = Curfn
  1305  		e.nodeEscState(src).Escloopdepth = e.loopdepth
  1306  		src.Used = true
  1307  		src.Lineno = n.Lineno
  1308  		nE.Escretval = list(nE.Escretval, src)
  1309  	}
  1310  }
  1311  
  1312  // This is a bit messier than fortunate, pulled out of esc's big
  1313  // switch for clarity.	We either have the paramnodes, which may be
  1314  // connected to other things through flows or we have the parameter type
  1315  // nodes, which may be marked "noescape". Navigating the ast is slightly
  1316  // different for methods vs plain functions and for imported vs
  1317  // this-package
  1318  func esccall(e *EscState, n *Node, up *Node) {
  1319  	var fntype *Type
  1320  	var indirect bool
  1321  	var fn *Node
  1322  	switch n.Op {
  1323  	default:
  1324  		Fatalf("esccall")
  1325  
  1326  	case OCALLFUNC:
  1327  		fn = n.Left
  1328  		fntype = fn.Type
  1329  		indirect = fn.Op != ONAME || fn.Class != PFUNC
  1330  
  1331  	case OCALLMETH:
  1332  		fn = n.Left.Right.Sym.Def
  1333  		if fn != nil {
  1334  			fntype = fn.Type
  1335  		} else {
  1336  			fntype = n.Left.Type
  1337  		}
  1338  
  1339  	case OCALLINTER:
  1340  		fntype = n.Left.Type
  1341  		indirect = true
  1342  	}
  1343  
  1344  	ll := n.List
  1345  	if n.List != nil && n.List.Next == nil {
  1346  		a := n.List.N
  1347  		if a.Type.Etype == TSTRUCT && a.Type.Funarg { // f(g()).
  1348  			ll = e.nodeEscState(a).Escretval
  1349  		}
  1350  	}
  1351  
  1352  	if indirect {
  1353  		// We know nothing!
  1354  		// Leak all the parameters
  1355  		for ; ll != nil; ll = ll.Next {
  1356  			escassign(e, &e.theSink, ll.N)
  1357  			if Debug['m'] > 2 {
  1358  				fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
  1359  			}
  1360  		}
  1361  		// Set up bogus outputs
  1362  		initEscretval(e, n, fntype)
  1363  		// If there is a receiver, it also leaks to heap.
  1364  		if n.Op != OCALLFUNC {
  1365  			t := getthisx(fntype).Type
  1366  			src := n.Left.Left
  1367  			if haspointers(t.Type) {
  1368  				escassign(e, &e.theSink, src)
  1369  			}
  1370  		}
  1371  		return
  1372  	}
  1373  
  1374  	nE := e.nodeEscState(n)
  1375  	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
  1376  		fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
  1377  		if Debug['m'] > 2 {
  1378  			fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
  1379  		}
  1380  
  1381  		// function in same mutually recursive group.  Incorporate into flow graph.
  1382  		//		print("esc local fn: %N\n", fn->ntype);
  1383  		if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil {
  1384  			Fatalf("graph inconsistency")
  1385  		}
  1386  
  1387  		// set up out list on this call node
  1388  		for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next {
  1389  			nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
  1390  		}
  1391  
  1392  		// Receiver.
  1393  		if n.Op != OCALLFUNC {
  1394  			escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left)
  1395  		}
  1396  
  1397  		var src *Node
  1398  		for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
  1399  			src = ll.N
  1400  			if lr.N.Isddd && !n.Isddd {
  1401  				// Introduce ODDDARG node to represent ... allocation.
  1402  				src = Nod(ODDDARG, nil, nil)
  1403  				src.Type = typ(TARRAY)
  1404  				src.Type.Type = lr.N.Type.Type
  1405  				src.Type.Bound = int64(count(ll))
  1406  				src.Type = Ptrto(src.Type) // make pointer so it will be tracked
  1407  				src.Lineno = n.Lineno
  1408  				e.track(src)
  1409  				n.Right = src
  1410  			}
  1411  
  1412  			if lr.N.Left != nil {
  1413  				escassign(e, lr.N.Left, src)
  1414  			}
  1415  			if src != ll.N {
  1416  				break
  1417  			}
  1418  		}
  1419  
  1420  		// "..." arguments are untracked
  1421  		for ; ll != nil; ll = ll.Next {
  1422  			if Debug['m'] > 2 {
  1423  				fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
  1424  			}
  1425  			escassign(e, &e.theSink, ll.N)
  1426  		}
  1427  
  1428  		return
  1429  	}
  1430  
  1431  	// Imported or completely analyzed function.  Use the escape tags.
  1432  	if nE.Escretval != nil {
  1433  		Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
  1434  	}
  1435  
  1436  	if Debug['m'] > 2 {
  1437  		fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
  1438  	}
  1439  
  1440  	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
  1441  	initEscretval(e, n, fntype)
  1442  
  1443  	//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
  1444  
  1445  	// Receiver.
  1446  	if n.Op != OCALLFUNC {
  1447  		t := getthisx(fntype).Type
  1448  		src := n.Left.Left
  1449  		if haspointers(t.Type) {
  1450  			escassignfromtag(e, t.Note, nE.Escretval, src)
  1451  		}
  1452  	}
  1453  
  1454  	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
  1455  		src := ll.N
  1456  		if t.Isddd && !n.Isddd {
  1457  			// Introduce ODDDARG node to represent ... allocation.
  1458  			src = Nod(ODDDARG, nil, nil)
  1459  			src.Lineno = n.Lineno
  1460  			src.Type = typ(TARRAY)
  1461  			src.Type.Type = t.Type.Type
  1462  			src.Type.Bound = int64(count(ll))
  1463  			src.Type = Ptrto(src.Type) // make pointer so it will be tracked
  1464  			e.track(src)
  1465  			n.Right = src
  1466  		}
  1467  
  1468  		if haspointers(t.Type) {
  1469  			if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
  1470  				a := src
  1471  				for a.Op == OCONVNOP {
  1472  					a = a.Left
  1473  				}
  1474  				switch a.Op {
  1475  				// The callee has already been analyzed, so its arguments have esc tags.
  1476  				// The argument is marked as not escaping at all.
  1477  				// Record that fact so that any temporary used for
  1478  				// synthesizing this expression can be reclaimed when
  1479  				// the function returns.
  1480  				// This 'noescape' is even stronger than the usual esc == EscNone.
  1481  				// src->esc == EscNone means that src does not escape the current function.
  1482  				// src->noescape = 1 here means that src does not escape this statement
  1483  				// in the current function.
  1484  				case OCALLPART,
  1485  					OCLOSURE,
  1486  					ODDDARG,
  1487  					OARRAYLIT,
  1488  					OPTRLIT,
  1489  					OSTRUCTLIT:
  1490  					a.Noescape = true
  1491  				}
  1492  			}
  1493  		}
  1494  
  1495  		if src != ll.N {
  1496  			break
  1497  		}
  1498  		t = t.Down
  1499  	}
  1500  
  1501  	// "..." arguments are untracked
  1502  	for ; ll != nil; ll = ll.Next {
  1503  		escassign(e, &e.theSink, ll.N)
  1504  		if Debug['m'] > 2 {
  1505  			fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
  1506  		}
  1507  	}
  1508  }
  1509  
  1510  // escflows records the link src->dst in dst, throwing out some quick wins,
  1511  // and also ensuring that dst is noted as a flow destination.
  1512  func escflows(e *EscState, dst *Node, src *Node) {
  1513  	if dst == nil || src == nil || dst == src {
  1514  		return
  1515  	}
  1516  
  1517  	// Don't bother building a graph for scalars.
  1518  	if src.Type != nil && !haspointers(src.Type) {
  1519  		return
  1520  	}
  1521  
  1522  	if Debug['m'] > 2 {
  1523  		fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort))
  1524  	}
  1525  
  1526  	dstE := e.nodeEscState(dst)
  1527  	if dstE.Escflowsrc == nil {
  1528  		e.dsts = list(e.dsts, dst)
  1529  		e.dstcount++
  1530  	}
  1531  
  1532  	e.edgecount++
  1533  
  1534  	dstE.Escflowsrc = list(dstE.Escflowsrc, src)
  1535  }
  1536  
  1537  // Whenever we hit a reference node, the level goes up by one, and whenever
  1538  // we hit an OADDR, the level goes down by one. as long as we're on a level > 0
  1539  // finding an OADDR just means we're following the upstream of a dereference,
  1540  // so this address doesn't leak (yet).
  1541  // If level == 0, it means the /value/ of this node can reach the root of this flood.
  1542  // so if this node is an OADDR, it's argument should be marked as escaping iff
  1543  // it's currfn/e->loopdepth are different from the flood's root.
  1544  // Once an object has been moved to the heap, all of it's upstream should be considered
  1545  // escaping to the global scope.
  1546  func escflood(e *EscState, dst *Node) {
  1547  	switch dst.Op {
  1548  	case ONAME, OCLOSURE:
  1549  		break
  1550  
  1551  	default:
  1552  		return
  1553  	}
  1554  
  1555  	dstE := e.nodeEscState(dst)
  1556  	if Debug['m'] > 1 {
  1557  		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
  1558  	}
  1559  
  1560  	for l := dstE.Escflowsrc; l != nil; l = l.Next {
  1561  		e.walkgen++
  1562  		escwalk(e, levelFrom(0), dst, l.N)
  1563  	}
  1564  }
  1565  
  1566  // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function.
  1567  func funcOutputAndInput(dst, src *Node) bool {
  1568  	// Note if dst is marked as escaping, then "returned" is too weak.
  1569  	return dst.Op == ONAME && dst.Class == PPARAMOUT &&
  1570  		src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn
  1571  }
  1572  
  1573  func escwalk(e *EscState, level Level, dst *Node, src *Node) {
  1574  	if src.Op == OLITERAL {
  1575  		return
  1576  	}
  1577  	srcE := e.nodeEscState(src)
  1578  	if srcE.Walkgen == e.walkgen {
  1579  		// Esclevels are vectors, do not compare as integers,
  1580  		// and must use "min" of old and new to guarantee
  1581  		// convergence.
  1582  		level = level.min(srcE.Esclevel)
  1583  		if level == srcE.Esclevel {
  1584  			return
  1585  		}
  1586  	}
  1587  
  1588  	srcE.Walkgen = e.walkgen
  1589  	srcE.Esclevel = level
  1590  
  1591  	if Debug['m'] > 1 {
  1592  		fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n",
  1593  			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), e.curfnSym(src), srcE.Escloopdepth)
  1594  	}
  1595  
  1596  	e.pdepth++
  1597  
  1598  	// Input parameter flowing to output parameter?
  1599  	var leaks bool
  1600  	dstE := e.nodeEscState(dst)
  1601  	if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
  1602  		// This case handles:
  1603  		// 1. return in
  1604  		// 2. return &in
  1605  		// 3. tmp := in; return &tmp
  1606  		// 4. return *in
  1607  		if Debug['m'] != 0 {
  1608  			if Debug['m'] == 1 {
  1609  				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int())
  1610  			} else {
  1611  				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level)
  1612  			}
  1613  		}
  1614  		if src.Esc&EscMask != EscReturn {
  1615  			src.Esc = EscReturn | src.Esc&EscContentEscapes
  1616  		}
  1617  		src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level)
  1618  		goto recurse
  1619  	}
  1620  
  1621  	// If parameter content escapes to heap, set EscContentEscapes
  1622  	// Note minor confusion around escape from pointer-to-struct vs escape from struct
  1623  	if dst.Esc == EscHeap &&
  1624  		src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope &&
  1625  		level.int() > 0 {
  1626  		src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
  1627  		if Debug['m'] != 0 {
  1628  			Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort))
  1629  		}
  1630  	}
  1631  
  1632  	leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth
  1633  
  1634  	switch src.Op {
  1635  	case ONAME:
  1636  		if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope {
  1637  			if level.guaranteedDereference() > 0 {
  1638  				src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
  1639  				if Debug['m'] != 0 {
  1640  					if Debug['m'] == 1 {
  1641  						Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort))
  1642  					} else {
  1643  						Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
  1644  							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
  1645  					}
  1646  				}
  1647  			} else {
  1648  				src.Esc = EscScope
  1649  				if Debug['m'] != 0 {
  1650  					if Debug['m'] == 1 {
  1651  						Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
  1652  					} else {
  1653  						Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
  1654  							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
  1655  					}
  1656  				}
  1657  			}
  1658  		}
  1659  
  1660  		// Treat a PPARAMREF closure variable as equivalent to the
  1661  		// original variable.
  1662  		if src.Class == PPARAMREF {
  1663  			if leaks && Debug['m'] != 0 {
  1664  				Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
  1665  			}
  1666  			escwalk(e, level, dst, src.Name.Param.Closure)
  1667  		}
  1668  
  1669  	case OPTRLIT, OADDR:
  1670  		if leaks {
  1671  			src.Esc = EscHeap
  1672  			addrescapes(src.Left)
  1673  			if Debug['m'] != 0 {
  1674  				p := src
  1675  				if p.Left.Op == OCLOSURE {
  1676  					p = p.Left // merely to satisfy error messages in tests
  1677  				}
  1678  				if Debug['m'] > 1 {
  1679  					Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
  1680  						Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth)
  1681  				} else {
  1682  					Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort))
  1683  				}
  1684  			}
  1685  		}
  1686  
  1687  		escwalk(e, level.dec(), dst, src.Left)
  1688  
  1689  	case OAPPEND:
  1690  		escwalk(e, level, dst, src.List.N)
  1691  
  1692  	case OARRAYLIT:
  1693  		if Isfixedarray(src.Type) {
  1694  			break
  1695  		}
  1696  		for ll := src.List; ll != nil; ll = ll.Next {
  1697  			escwalk(e, level.dec(), dst, ll.N.Right)
  1698  		}
  1699  
  1700  		fallthrough
  1701  
  1702  	case ODDDARG,
  1703  		OMAKECHAN,
  1704  		OMAKEMAP,
  1705  		OMAKESLICE,
  1706  		OARRAYRUNESTR,
  1707  		OARRAYBYTESTR,
  1708  		OSTRARRAYRUNE,
  1709  		OSTRARRAYBYTE,
  1710  		OADDSTR,
  1711  		OMAPLIT,
  1712  		ONEW,
  1713  		OCLOSURE,
  1714  		OCALLPART,
  1715  		ORUNESTR,
  1716  		OCONVIFACE:
  1717  		if leaks {
  1718  			src.Esc = EscHeap
  1719  			if Debug['m'] != 0 {
  1720  				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
  1721  			}
  1722  		}
  1723  
  1724  	case ODOT,
  1725  		ODOTTYPE,
  1726  		OSLICE,
  1727  		OSLICEARR,
  1728  		OSLICE3,
  1729  		OSLICE3ARR,
  1730  		OSLICESTR:
  1731  		escwalk(e, level, dst, src.Left)
  1732  
  1733  	case OINDEX:
  1734  		if Isfixedarray(src.Left.Type) {
  1735  			escwalk(e, level, dst, src.Left)
  1736  			break
  1737  		}
  1738  		fallthrough
  1739  
  1740  	case ODOTPTR, OINDEXMAP, OIND:
  1741  		escwalk(e, level.inc(), dst, src.Left)
  1742  
  1743  	// In this case a link went directly to a call, but should really go
  1744  	// to the dummy .outN outputs that were created for the call that
  1745  	// themselves link to the inputs with levels adjusted.
  1746  	// See e.g. #10466
  1747  	// This can only happen with functions returning a single result.
  1748  	case OCALLMETH, OCALLFUNC, OCALLINTER:
  1749  		if srcE.Escretval != nil {
  1750  			if Debug['m'] > 1 {
  1751  				fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
  1752  					Ctxt.Line(int(lineno)), e.loopdepth,
  1753  					Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort))
  1754  			}
  1755  			src = srcE.Escretval.N
  1756  			srcE = e.nodeEscState(src)
  1757  		}
  1758  	}
  1759  
  1760  recurse:
  1761  	level = level.copy()
  1762  	for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next {
  1763  		escwalk(e, level, dst, ll.N)
  1764  	}
  1765  
  1766  	e.pdepth--
  1767  }
  1768  
  1769  func esctag(e *EscState, func_ *Node) {
  1770  	func_.Esc = EscFuncTagged
  1771  
  1772  	// External functions are assumed unsafe,
  1773  	// unless //go:noescape is given before the declaration.
  1774  	if func_.Nbody == nil {
  1775  		if func_.Noescape {
  1776  			for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
  1777  				if haspointers(t.Type) {
  1778  					t.Note = mktag(EscNone)
  1779  				}
  1780  			}
  1781  		}
  1782  
  1783  		return
  1784  	}
  1785  
  1786  	savefn := Curfn
  1787  	Curfn = func_
  1788  
  1789  	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
  1790  		if ll.N.Op != ONAME {
  1791  			continue
  1792  		}
  1793  
  1794  		switch ll.N.Esc & EscMask {
  1795  		case EscNone, // not touched by escflood
  1796  			EscReturn:
  1797  			if haspointers(ll.N.Type) { // don't bother tagging for scalars
  1798  				ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc))
  1799  			}
  1800  
  1801  		case EscHeap, // touched by escflood, moved to heap
  1802  			EscScope: // touched by escflood, value leaves scope
  1803  			break
  1804  		}
  1805  	}
  1806  
  1807  	Curfn = savefn
  1808  }