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