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