github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/cmd/compile/internal/gc/esc.go (about)

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