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