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