github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/cmd/compile/internal/gc/esc.go (about)

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