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