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