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