github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/cmd/compile/internal/gc/esc.go (about)

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