Home | History | Annotate | Download | only in gc
      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/internal/obj"
      9 	"fmt"
     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(*NodeList, bool)
     38 	visitgen uint32
     39 	nodeID   map[*Node]uint32
     40 	stack    *NodeList
     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 *NodeList, analyze func(list *NodeList, recursive bool)) {
     57 	var v bottomUpVisitor
     58 	v.analyze = analyze
     59 	v.nodeID = make(map[*Node]uint32)
     60 	for l := list; l != nil; l = l.Next {
     61 		if l.N.Op == ODCLFUNC && l.N.Func.FCurfn == nil {
     62 			v.visit(l.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 	l := new(NodeList)
     80 	l.Next = v.stack
     81 	l.N = n
     82 	v.stack = l
     83 	min = v.visitcodelist(n.Nbody, min)
     84 	if (min == id || min == id+1) && n.Func.FCurfn == nil {
     85 		// This node is the root of a strongly connected component.
     86 
     87 		// The original min passed to visitcodelist was n->walkgen+1.
     88 		// If visitcodelist found its way back to n->walkgen, then this
     89 		// block is a set of mutually recursive functions.
     90 		// Otherwise it's just a lone function that does not recurse.
     91 		recursive := min == id
     92 
     93 		// Remove connected component from stack.
     94 		// Mark walkgen so that future visits return a large number
     95 		// so as not to affect the caller's min.
     96 		block := v.stack
     97 
     98 		var l *NodeList
     99 		for l = v.stack; l.N != n; l = l.Next {
    100 			v.nodeID[l.N] = ^uint32(0)
    101 		}
    102 		v.nodeID[n] = ^uint32(0)
    103 		v.stack = l.Next
    104 		l.Next = nil
    105 
    106 		// Run escape analysis on this set of functions.
    107 		v.analyze(block, recursive)
    108 	}
    109 
    110 	return min
    111 }
    112 
    113 func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 {
    114 	for ; l != nil; l = l.Next {
    115 		min = v.visitcode(l.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 = n.Left.Right.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 dst->escflowsrc.  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 *NodeList) {
    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 satAdd8(x, y int8) int8 {
    253 	z := x + y
    254 	if x^y < 0 || x^z >= 0 {
    255 		return z
    256 	}
    257 	if x < 0 {
    258 		return -128
    259 	}
    260 	return 127
    261 }
    262 
    263 func min8(a, b int8) int8 {
    264 	if a < b {
    265 		return a
    266 	}
    267 	return b
    268 }
    269 
    270 func max8(a, b int8) int8 {
    271 	if a > b {
    272 		return a
    273 	}
    274 	return b
    275 }
    276 
    277 // inc returns the level l + 1, representing the effect of an indirect (*) operation.
    278 func (l Level) inc() Level {
    279 	if l.value <= MinLevel {
    280 		return Level{value: MinLevel}
    281 	}
    282 	return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)}
    283 }
    284 
    285 // dec returns the level l - 1, representing the effect of an address-of (&) operation.
    286 func (l Level) dec() Level {
    287 	if l.value <= MinLevel {
    288 		return Level{value: MinLevel}
    289 	}
    290 	return Level{value: l.value - 1, suffixValue: l.suffixValue - 1}
    291 }
    292 
    293 // copy returns the level for a copy of a value with level l.
    294 func (l Level) copy() Level {
    295 	return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)}
    296 }
    297 
    298 func (l1 Level) min(l2 Level) Level {
    299 	return Level{
    300 		value:       min8(l1.value, l2.value),
    301 		suffixValue: min8(l1.suffixValue, l2.suffixValue)}
    302 }
    303 
    304 // guaranteedDereference returns the number of dereferences
    305 // applied to a pointer before addresses are taken/generated.
    306 // This is the maximum level computed from path suffixes starting
    307 // with copies where paths flow from destination to source.
    308 func (l Level) guaranteedDereference() int {
    309 	return int(l.suffixValue)
    310 }
    311 
    312 type NodeEscState struct {
    313 	Curfn        *Node
    314 	Escflowsrc   *NodeList // flow(this, src)
    315 	Escretval    *NodeList // on OCALLxxx, list of dummy return values
    316 	Escloopdepth int32     // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
    317 	Esclevel     Level
    318 	Walkgen      uint32
    319 }
    320 
    321 func (e *EscState) nodeEscState(n *Node) *NodeEscState {
    322 	if nE, ok := n.Opt().(*NodeEscState); ok {
    323 		return nE
    324 	}
    325 	if n.Opt() != nil {
    326 		Fatal("nodeEscState: opt in use (%T)", n.Opt())
    327 	}
    328 	nE := new(NodeEscState)
    329 	nE.Curfn = Curfn
    330 	n.SetOpt(nE)
    331 	e.opts = append(e.opts, n)
    332 	return nE
    333 }
    334 
    335 func (e *EscState) track(n *Node) {
    336 	if Curfn == nil {
    337 		Fatal("EscState.track: Curfn nil")
    338 	}
    339 	n.Esc = EscNone // until proven otherwise
    340 	nE := e.nodeEscState(n)
    341 	nE.Escloopdepth = e.loopdepth
    342 	e.noesc = list(e.noesc, n)
    343 }
    344 
    345 // Escape constants are numbered in order of increasing "escapiness"
    346 // to help make inferences be monotonic.  With the exception of
    347 // EscNever which is sticky, eX < eY means that eY is more exposed
    348 // than eX, and hence replaces it in a conservative analysis.
    349 const (
    350 	EscUnknown = iota
    351 	EscNone    // Does not escape to heap, result, or parameters.
    352 	EscReturn  // Is returned or reachable from returned.
    353 	EscScope   // Allocated in an inner loop scope, assigned to an outer loop scope,
    354 	// which allows the construction of non-escaping but arbitrarily large linked
    355 	// data structures (i.e., not eligible for allocation in a fixed-size stack frame).
    356 	EscHeap           // Reachable from the heap
    357 	EscNever          // By construction will not escape.
    358 	EscBits           = 3
    359 	EscMask           = (1 << EscBits) - 1
    360 	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap
    361 	EscReturnBits     = EscBits + 1
    362 	// Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3
    363 )
    364 
    365 // escMax returns the maximum of an existing escape value
    366 // (and its additional parameter flow flags) and a new escape type.
    367 func escMax(e, etype uint16) uint16 {
    368 	if e&EscMask >= EscScope {
    369 		// normalize
    370 		if e&^EscMask != 0 {
    371 			Fatal("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask)
    372 		}
    373 	}
    374 	if e&EscMask > etype {
    375 		return e
    376 	}
    377 	if etype == EscNone || etype == EscReturn {
    378 		return (e &^ EscMask) | etype
    379 	}
    380 	return etype
    381 }
    382 
    383 // For each input parameter to a function, the escapeReturnEncoding describes
    384 // how the parameter may leak to the function's outputs.  This is currently the
    385 // "level" of the leak where level is 0 or larger (negative level means stored into
    386 // something whose address is returned -- but that implies stored into the heap,
    387 // hence EscHeap, which means that the details are not currently relevant. )
    388 const (
    389 	bitsPerOutputInTag = 3                                         // For each output, the number of bits for a tag
    390 	bitsMaskForTag     = uint16(1<<bitsPerOutputInTag) - 1         // The bit mask to extract a single tag.
    391 	outputsPerTag      = (16 - EscReturnBits) / bitsPerOutputInTag // The number of outputs that can be tagged.
    392 	maxEncodedLevel    = int(bitsMaskForTag - 1)                   // The largest level that can be stored in a tag.
    393 )
    394 
    395 type EscState struct {
    396 	// Fake node that all
    397 	//   - return values and output variables
    398 	//   - parameters on imported functions not marked 'safe'
    399 	//   - assignments to global variables
    400 	// flow to.
    401 	theSink Node
    402 
    403 	dsts      *NodeList // all dst nodes
    404 	loopdepth int32     // for detecting nested loop scopes
    405 	pdepth    int       // for debug printing in recursions.
    406 	dstcount  int       // diagnostic
    407 	edgecount int       // diagnostic
    408 	noesc     *NodeList // list of possible non-escaping nodes, for printing
    409 	recursive bool      // recursive function or group of mutually recursive functions.
    410 	opts      []*Node   // nodes with .Opt initialized
    411 	walkgen   uint32
    412 }
    413 
    414 // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
    415 func funcSym(fn *Node) *Sym {
    416 	if fn == nil || fn.Func.Nname == nil {
    417 		return nil
    418 	}
    419 	return fn.Func.Nname.Sym
    420 }
    421 
    422 // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
    423 func (e *EscState) curfnSym(n *Node) *Sym {
    424 	nE := e.nodeEscState(n)
    425 	return funcSym(nE.Curfn)
    426 }
    427 
    428 func escAnalyze(all *NodeList, recursive bool) {
    429 	var es EscState
    430 	e := &es
    431 	e.theSink.Op = ONAME
    432 	e.theSink.Orig = &e.theSink
    433 	e.theSink.Class = PEXTERN
    434 	e.theSink.Sym = Lookup(".sink")
    435 	e.nodeEscState(&e.theSink).Escloopdepth = -1
    436 	e.recursive = recursive
    437 
    438 	for l := all; l != nil; l = l.Next {
    439 		if l.N.Op == ODCLFUNC {
    440 			l.N.Esc = EscFuncPlanned
    441 		}
    442 	}
    443 
    444 	// flow-analyze functions
    445 	for l := all; l != nil; l = l.Next {
    446 		if l.N.Op == ODCLFUNC {
    447 			escfunc(e, l.N)
    448 		}
    449 	}
    450 
    451 	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
    452 
    453 	// visit the upstream of each dst, mark address nodes with
    454 	// addrescapes, mark parameters unsafe
    455 	for l := e.dsts; l != nil; l = l.Next {
    456 		escflood(e, l.N)
    457 	}
    458 
    459 	// for all top level functions, tag the typenodes corresponding to the param nodes
    460 	for l := all; l != nil; l = l.Next {
    461 		if l.N.Op == ODCLFUNC {
    462 			esctag(e, l.N)
    463 		}
    464 	}
    465 
    466 	if Debug['m'] != 0 {
    467 		for l := e.noesc; l != nil; l = l.Next {
    468 			if l.N.Esc == EscNone {
    469 				Warnl(int(l.N.Lineno), "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort))
    470 			}
    471 		}
    472 	}
    473 	for _, x := range e.opts {
    474 		x.SetOpt(nil)
    475 	}
    476 }
    477 
    478 func escfunc(e *EscState, func_ *Node) {
    479 	//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
    480 	if func_.Esc != 1 {
    481 		Fatal("repeat escfunc %v", func_.Func.Nname)
    482 	}
    483 	func_.Esc = EscFuncStarted
    484 
    485 	saveld := e.loopdepth
    486 	e.loopdepth = 1
    487 	savefn := Curfn
    488 	Curfn = func_
    489 
    490 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    491 		if ll.N.Op != ONAME {
    492 			continue
    493 		}
    494 		llNE := e.nodeEscState(ll.N)
    495 		switch ll.N.Class {
    496 		// out params are in a loopdepth between the sink and all local variables
    497 		case PPARAMOUT:
    498 			llNE.Escloopdepth = 0
    499 
    500 		case PPARAM:
    501 			llNE.Escloopdepth = 1
    502 			if ll.N.Type != nil && !haspointers(ll.N.Type) {
    503 				break
    504 			}
    505 			if Curfn.Nbody == nil && !Curfn.Noescape {
    506 				ll.N.Esc = EscHeap
    507 			} else {
    508 				ll.N.Esc = EscNone // prime for escflood later
    509 			}
    510 			e.noesc = list(e.noesc, ll.N)
    511 		}
    512 	}
    513 
    514 	// in a mutually recursive group we lose track of the return values
    515 	if e.recursive {
    516 		for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    517 			if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT {
    518 				escflows(e, &e.theSink, ll.N)
    519 			}
    520 		}
    521 	}
    522 
    523 	escloopdepthlist(e, Curfn.Nbody)
    524 	esclist(e, Curfn.Nbody, Curfn)
    525 	Curfn = savefn
    526 	e.loopdepth = saveld
    527 }
    528 
    529 // Mark labels that have no backjumps to them as not increasing e->loopdepth.
    530 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
    531 // and set it to one of the following two.  Then in esc we'll clear it again.
    532 var looping Label
    533 
    534 var nonlooping Label
    535 
    536 func escloopdepthlist(e *EscState, l *NodeList) {
    537 	for ; l != nil; l = l.Next {
    538 		escloopdepth(e, l.N)
    539 	}
    540 }
    541 
    542 func escloopdepth(e *EscState, n *Node) {
    543 	if n == nil {
    544 		return
    545 	}
    546 
    547 	escloopdepthlist(e, n.Ninit)
    548 
    549 	switch n.Op {
    550 	case OLABEL:
    551 		if n.Left == nil || n.Left.Sym == nil {
    552 			Fatal("esc:label without label: %v", Nconv(n, obj.FmtSign))
    553 		}
    554 
    555 		// Walk will complain about this label being already defined, but that's not until
    556 		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
    557 		// if(n->left->sym->label != nil)
    558 		//	fatal("escape analysis messed up analyzing label: %+N", n);
    559 		n.Left.Sym.Label = &nonlooping
    560 
    561 	case OGOTO:
    562 		if n.Left == nil || n.Left.Sym == nil {
    563 			Fatal("esc:goto without label: %v", Nconv(n, obj.FmtSign))
    564 		}
    565 
    566 		// If we come past one that's uninitialized, this must be a (harmless) forward jump
    567 		// but if it's set to nonlooping the label must have preceded this goto.
    568 		if n.Left.Sym.Label == &nonlooping {
    569 			n.Left.Sym.Label = &looping
    570 		}
    571 	}
    572 
    573 	escloopdepth(e, n.Left)
    574 	escloopdepth(e, n.Right)
    575 	escloopdepthlist(e, n.List)
    576 	escloopdepthlist(e, n.Nbody)
    577 	escloopdepthlist(e, n.Rlist)
    578 }
    579 
    580 func esclist(e *EscState, l *NodeList, up *Node) {
    581 	for ; l != nil; l = l.Next {
    582 		esc(e, l.N, up)
    583 	}
    584 }
    585 
    586 func esc(e *EscState, n *Node, up *Node) {
    587 	if n == nil {
    588 		return
    589 	}
    590 
    591 	lno := int(setlineno(n))
    592 
    593 	// ninit logically runs at a different loopdepth than the rest of the for loop.
    594 	esclist(e, n.Ninit, n)
    595 
    596 	if n.Op == OFOR || n.Op == ORANGE {
    597 		e.loopdepth++
    598 	}
    599 
    600 	// type switch variables have no ODCL.
    601 	// process type switch as declaration.
    602 	// must happen before processing of switch body,
    603 	// so before recursion.
    604 	if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW {
    605 		for ll := n.List; ll != nil; ll = ll.Next { // cases
    606 
    607 			// ll.N.Rlist is the variable per case
    608 			if ll.N.Rlist != nil {
    609 				e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth
    610 			}
    611 		}
    612 	}
    613 
    614 	// Big stuff escapes unconditionally
    615 	// "Big" conditions that were scattered around in walk have been gathered here
    616 	if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
    617 		n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
    618 		n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
    619 		if Debug['m'] > 1 {
    620 			Warnl(int(n.Lineno), "%v is too large for stack", n)
    621 		}
    622 		n.Esc = EscHeap
    623 		addrescapes(n)
    624 		escassign(e, &e.theSink, n)
    625 	}
    626 
    627 	esc(e, n.Left, n)
    628 	esc(e, n.Right, n)
    629 	esclist(e, n.Nbody, n)
    630 	esclist(e, n.List, n)
    631 	esclist(e, n.Rlist, n)
    632 
    633 	if n.Op == OFOR || n.Op == ORANGE {
    634 		e.loopdepth--
    635 	}
    636 
    637 	if Debug['m'] > 1 {
    638 		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
    639 	}
    640 
    641 	switch n.Op {
    642 	// Record loop depth at declaration.
    643 	case ODCL:
    644 		if n.Left != nil {
    645 			e.nodeEscState(n.Left).Escloopdepth = e.loopdepth
    646 		}
    647 
    648 	case OLABEL:
    649 		if n.Left.Sym.Label == &nonlooping {
    650 			if Debug['m'] > 1 {
    651 				fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n)
    652 			}
    653 		} else if n.Left.Sym.Label == &looping {
    654 			if Debug['m'] > 1 {
    655 				fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n)
    656 			}
    657 			e.loopdepth++
    658 		}
    659 
    660 		// See case OLABEL in escloopdepth above
    661 		// else if(n->left->sym->label == nil)
    662 		//	fatal("escape analysis missed or messed up a label: %+N", n);
    663 
    664 		n.Left.Sym.Label = nil
    665 
    666 		// Everything but fixed array is a dereference.
    667 	case ORANGE:
    668 		if n.List != nil && n.List.Next != nil {
    669 			if Isfixedarray(n.Type) {
    670 				escassign(e, n.List.Next.N, n.Right)
    671 			} else {
    672 				escassignDereference(e, n.List.Next.N, n.Right)
    673 			}
    674 		}
    675 
    676 	case OSWITCH:
    677 		if n.Left != nil && n.Left.Op == OTYPESW {
    678 			for ll := n.List; ll != nil; ll = ll.Next {
    679 				// cases
    680 				// n.Left.Right is the argument of the .(type),
    681 				// ll.N.Rlist is the variable per case
    682 				if ll.N.Rlist != nil {
    683 					escassign(e, ll.N.Rlist.N, n.Left.Right)
    684 				}
    685 			}
    686 		}
    687 
    688 		// Filter out the following special case.
    689 	//
    690 	//	func (b *Buffer) Foo() {
    691 	//		n, m := ...
    692 	//		b.buf = b.buf[n:m]
    693 	//	}
    694 	//
    695 	// This assignment is a no-op for escape analysis,
    696 	// it does not store any new pointers into b that were not already there.
    697 	// However, without this special case b will escape, because we assign to OIND/ODOTPTR.
    698 	case OAS, OASOP, OASWB:
    699 		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference
    700 			(n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation
    701 			(n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference
    702 			n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME
    703 
    704 			// Here we also assume that the statement will not contain calls,
    705 			// that is, that order will move any calls to init.
    706 			// Otherwise base ONAME value could change between the moments
    707 			// when we evaluate it for dst and for src.
    708 			//
    709 			// Note, this optimization does not apply to OSLICEARR,
    710 			// because it does introduce a new pointer into b that was not already there
    711 			// (pointer to b itself). After such assignment, if b contents escape,
    712 			// b escapes as well. If we ignore such OSLICEARR, we will conclude
    713 			// that b does not escape when b contents do.
    714 			if Debug['m'] != 0 {
    715 				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort))
    716 			}
    717 
    718 			break
    719 		}
    720 
    721 		escassign(e, n.Left, n.Right)
    722 
    723 	case OAS2: // x,y = a,b
    724 		if count(n.List) == count(n.Rlist) {
    725 			ll := n.List
    726 			lr := n.Rlist
    727 			for ; ll != nil; ll, lr = ll.Next, lr.Next {
    728 				escassign(e, ll.N, lr.N)
    729 			}
    730 		}
    731 
    732 	case OAS2RECV, // v, ok = <-ch
    733 		OAS2MAPR,    // v, ok = m[k]
    734 		OAS2DOTTYPE: // v, ok = x.(type)
    735 		escassign(e, n.List.N, n.Rlist.N)
    736 
    737 	case OSEND: // ch <- x
    738 		escassign(e, &e.theSink, n.Right)
    739 
    740 	case ODEFER:
    741 		if e.loopdepth == 1 { // top level
    742 			break
    743 		}
    744 		// arguments leak out of scope
    745 		// TODO: leak to a dummy node instead
    746 		fallthrough
    747 
    748 	case OPROC:
    749 		// go f(x) - f and x escape
    750 		escassign(e, &e.theSink, n.Left.Left)
    751 
    752 		escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call
    753 		for ll := n.Left.List; ll != nil; ll = ll.Next {
    754 			escassign(e, &e.theSink, ll.N)
    755 		}
    756 
    757 	case OCALLMETH, OCALLFUNC, OCALLINTER:
    758 		esccall(e, n, up)
    759 
    760 		// esccall already done on n->rlist->n. tie it's escretval to n->list
    761 	case OAS2FUNC: // x,y = f()
    762 		lr := e.nodeEscState(n.Rlist.N).Escretval
    763 
    764 		var ll *NodeList
    765 		for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next {
    766 			escassign(e, ll.N, lr.N)
    767 		}
    768 		if lr != nil || ll != nil {
    769 			Fatal("esc oas2func")
    770 		}
    771 
    772 	case ORETURN:
    773 		ll := n.List
    774 		if count(n.List) == 1 && Curfn.Type.Outtuple > 1 {
    775 			// OAS2FUNC in disguise
    776 			// esccall already done on n->list->n
    777 			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
    778 			ll = e.nodeEscState(n.List.N).Escretval
    779 		}
    780 
    781 		for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
    782 			if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
    783 				continue
    784 			}
    785 			escassign(e, lr.N, ll.N)
    786 			ll = ll.Next
    787 		}
    788 
    789 		if ll != nil {
    790 			Fatal("esc return list")
    791 		}
    792 
    793 		// Argument could leak through recover.
    794 	case OPANIC:
    795 		escassign(e, &e.theSink, n.Left)
    796 
    797 	case OAPPEND:
    798 		if !n.Isddd {
    799 			for ll := n.List.Next; ll != nil; ll = ll.Next {
    800 				escassign(e, &e.theSink, ll.N) // lose track of assign to dereference
    801 			}
    802 		} else {
    803 			// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
    804 			slice2 := n.List.Next.N
    805 			escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference
    806 			if Debug['m'] > 2 {
    807 				Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort))
    808 			}
    809 		}
    810 		escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too
    811 
    812 	case OCOPY:
    813 		escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference
    814 
    815 	case OCONV, OCONVNOP:
    816 		escassign(e, n, n.Left)
    817 
    818 	case OCONVIFACE:
    819 		e.track(n)
    820 		escassign(e, n, n.Left)
    821 
    822 	case OARRAYLIT:
    823 		if Isslice(n.Type) {
    824 			// Slice itself is not leaked until proven otherwise
    825 			e.track(n)
    826 		}
    827 
    828 		// Link values to array/slice
    829 		for ll := n.List; ll != nil; ll = ll.Next {
    830 			escassign(e, n, ll.N.Right)
    831 		}
    832 
    833 		// Link values to struct.
    834 	case OSTRUCTLIT:
    835 		for ll := n.List; ll != nil; ll = ll.Next {
    836 			escassign(e, n, ll.N.Right)
    837 		}
    838 
    839 	case OPTRLIT:
    840 		e.track(n)
    841 
    842 		// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
    843 		escassign(e, n, n.Left)
    844 
    845 	case OCALLPART:
    846 		e.track(n)
    847 
    848 		// Contents make it to memory, lose track.
    849 		escassign(e, &e.theSink, n.Left)
    850 
    851 	case OMAPLIT:
    852 		e.track(n)
    853 
    854 		// Keys and values make it to memory, lose track.
    855 		for ll := n.List; ll != nil; ll = ll.Next {
    856 			escassign(e, &e.theSink, ll.N.Left)
    857 			escassign(e, &e.theSink, ll.N.Right)
    858 		}
    859 
    860 		// Link addresses of captured variables to closure.
    861 	case OCLOSURE:
    862 		var a *Node
    863 		var v *Node
    864 		for ll := n.Func.Cvars; ll != nil; ll = ll.Next {
    865 			v = ll.N
    866 			if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs
    867 				continue
    868 			}
    869 			a = v.Name.Param.Closure
    870 			if !v.Name.Byval {
    871 				a = Nod(OADDR, a, nil)
    872 				a.Lineno = v.Lineno
    873 				e.nodeEscState(a).Escloopdepth = e.loopdepth
    874 				typecheck(&a, Erv)
    875 			}
    876 
    877 			escassign(e, n, a)
    878 		}
    879 		fallthrough
    880 
    881 	case OMAKECHAN,
    882 		OMAKEMAP,
    883 		OMAKESLICE,
    884 		ONEW,
    885 		OARRAYRUNESTR,
    886 		OARRAYBYTESTR,
    887 		OSTRARRAYRUNE,
    888 		OSTRARRAYBYTE,
    889 		ORUNESTR:
    890 		e.track(n)
    891 
    892 	case OADDSTR:
    893 		e.track(n)
    894 		// Arguments of OADDSTR do not escape.
    895 
    896 	case OADDR:
    897 		// current loop depth is an upper bound on actual loop depth
    898 		// of addressed value.
    899 		e.track(n)
    900 
    901 		// for &x, use loop depth of x if known.
    902 		// it should always be known, but if not, be conservative
    903 		// and keep the current loop depth.
    904 		if n.Left.Op == ONAME {
    905 			switch n.Left.Class {
    906 			case PAUTO:
    907 				nE := e.nodeEscState(n)
    908 				leftE := e.nodeEscState(n.Left)
    909 				if leftE.Escloopdepth != 0 {
    910 					nE.Escloopdepth = leftE.Escloopdepth
    911 				}
    912 
    913 				// PPARAM is loop depth 1 always.
    914 			// PPARAMOUT is loop depth 0 for writes
    915 			// but considered loop depth 1 for address-of,
    916 			// so that writing the address of one result
    917 			// to another (or the same) result makes the
    918 			// first result move to the heap.
    919 			case PPARAM, PPARAMOUT:
    920 				nE := e.nodeEscState(n)
    921 				nE.Escloopdepth = 1
    922 			}
    923 		}
    924 	}
    925 
    926 	lineno = int32(lno)
    927 }
    928 
    929 // Assert that expr somehow gets assigned to dst, if non nil.  for
    930 // dst==nil, any name node expr still must be marked as being
    931 // evaluated in curfn.	For expr==nil, dst must still be examined for
    932 // evaluations inside it (e.g *f(x) = y)
    933 func escassign(e *EscState, dst *Node, src *Node) {
    934 	if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX {
    935 		return
    936 	}
    937 
    938 	if Debug['m'] > 1 {
    939 		fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
    940 			Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn),
    941 			Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0),
    942 			Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0))
    943 	}
    944 
    945 	setlineno(dst)
    946 
    947 	// Analyze lhs of assignment.
    948 	// Replace dst with e->theSink if we can't track it.
    949 	switch dst.Op {
    950 	default:
    951 		Dump("dst", dst)
    952 		Fatal("escassign: unexpected dst")
    953 
    954 	case OARRAYLIT,
    955 		OCLOSURE,
    956 		OCONV,
    957 		OCONVIFACE,
    958 		OCONVNOP,
    959 		OMAPLIT,
    960 		OSTRUCTLIT,
    961 		OPTRLIT,
    962 		OCALLPART:
    963 		break
    964 
    965 	case ONAME:
    966 		if dst.Class == PEXTERN {
    967 			dst = &e.theSink
    968 		}
    969 
    970 	case ODOT: // treat "dst.x  = src" as "dst = src"
    971 		escassign(e, dst.Left, src)
    972 
    973 		return
    974 
    975 	case OINDEX:
    976 		if Isfixedarray(dst.Left.Type) {
    977 			escassign(e, dst.Left, src)
    978 			return
    979 		}
    980 
    981 		dst = &e.theSink // lose track of dereference
    982 
    983 	case OIND, ODOTPTR:
    984 		dst = &e.theSink // lose track of dereference
    985 
    986 		// lose track of key and value
    987 	case OINDEXMAP:
    988 		escassign(e, &e.theSink, dst.Right)
    989 
    990 		dst = &e.theSink
    991 	}
    992 
    993 	lno := int(setlineno(src))
    994 	e.pdepth++
    995 
    996 	switch src.Op {
    997 	case OADDR, // dst = &x
    998 		OIND,    // dst = *x
    999 		ODOTPTR, // dst = (*x).f
   1000 		ONAME,
   1001 		OPARAM,
   1002 		ODDDARG,
   1003 		OPTRLIT,
   1004 		OARRAYLIT,
   1005 		OMAPLIT,
   1006 		OSTRUCTLIT,
   1007 		OMAKECHAN,
   1008 		OMAKEMAP,
   1009 		OMAKESLICE,
   1010 		OARRAYRUNESTR,
   1011 		OARRAYBYTESTR,
   1012 		OSTRARRAYRUNE,
   1013 		OSTRARRAYBYTE,
   1014 		OADDSTR,
   1015 		ONEW,
   1016 		OCALLPART,
   1017 		ORUNESTR,
   1018 		OCONVIFACE:
   1019 		escflows(e, dst, src)
   1020 
   1021 	case OCLOSURE:
   1022 		// OCLOSURE is lowered to OPTRLIT,
   1023 		// insert OADDR to account for the additional indirection.
   1024 		a := Nod(OADDR, src, nil)
   1025 		a.Lineno = src.Lineno
   1026 		e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth
   1027 		a.Type = Ptrto(src.Type)
   1028 		escflows(e, dst, a)
   1029 
   1030 	// Flowing multiple returns to a single dst happens when
   1031 	// analyzing "go f(g())": here g() flows to sink (issue 4529).
   1032 	case OCALLMETH, OCALLFUNC, OCALLINTER:
   1033 		for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next {
   1034 			escflows(e, dst, ll.N)
   1035 		}
   1036 
   1037 		// A non-pointer escaping from a struct does not concern us.
   1038 	case ODOT:
   1039 		if src.Type != nil && !haspointers(src.Type) {
   1040 			break
   1041 		}
   1042 		fallthrough
   1043 
   1044 		// Conversions, field access, slice all preserve the input value.
   1045 	case OCONV,
   1046 		OCONVNOP,
   1047 		ODOTMETH,
   1048 		// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
   1049 		// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
   1050 		ODOTTYPE,
   1051 		ODOTTYPE2,
   1052 		OSLICE,
   1053 		OSLICE3,
   1054 		OSLICEARR,
   1055 		OSLICE3ARR,
   1056 		OSLICESTR:
   1057 		// Conversions, field access, slice all preserve the input value.
   1058 		escassign(e, dst, src.Left)
   1059 
   1060 	case OAPPEND:
   1061 		// Append returns first argument.
   1062 		// Subsequent arguments are already leaked because they are operands to append.
   1063 		escassign(e, dst, src.List.N)
   1064 
   1065 	case OINDEX:
   1066 		// Index of array preserves input value.
   1067 		if Isfixedarray(src.Left.Type) {
   1068 			escassign(e, dst, src.Left)
   1069 		} else {
   1070 			escflows(e, dst, src)
   1071 		}
   1072 
   1073 		// Might be pointer arithmetic, in which case
   1074 	// the operands flow into the result.
   1075 	// TODO(rsc): Decide what the story is here.  This is unsettling.
   1076 	case OADD,
   1077 		OSUB,
   1078 		OOR,
   1079 		OXOR,
   1080 		OMUL,
   1081 		ODIV,
   1082 		OMOD,
   1083 		OLSH,
   1084 		ORSH,
   1085 		OAND,
   1086 		OANDNOT,
   1087 		OPLUS,
   1088 		OMINUS,
   1089 		OCOM:
   1090 		escassign(e, dst, src.Left)
   1091 
   1092 		escassign(e, dst, src.Right)
   1093 	}
   1094 
   1095 	e.pdepth--
   1096 	lineno = int32(lno)
   1097 }
   1098 
   1099 // Common case for escapes is 16 bits 000000000xxxEEEE
   1100 // where commonest cases for xxx encoding in-to-out pointer
   1101 //  flow are 000, 001, 010, 011  and EEEE is computed Esc bits.
   1102 // Note width of xxx depends on value of constant
   1103 // bitsPerOutputInTag -- expect 2 or 3, so in practice the
   1104 // tag cache array is 64 or 128 long.  Some entries will
   1105 // never be populated.
   1106 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
   1107 
   1108 // mktag returns the string representation for an escape analysis tag.
   1109 func mktag(mask int) *string {
   1110 	switch mask & EscMask {
   1111 	case EscNone, EscReturn:
   1112 		break
   1113 
   1114 	default:
   1115 		Fatal("escape mktag")
   1116 	}
   1117 
   1118 	if mask < len(tags) && tags[mask] != "" {
   1119 		return &tags[mask]
   1120 	}
   1121 
   1122 	s := fmt.Sprintf("esc:0x%x", mask)
   1123 	if mask < len(tags) {
   1124 		tags[mask] = s
   1125 	}
   1126 	return &s
   1127 }
   1128 
   1129 // parsetag decodes an escape analysis tag and returns the esc value.
   1130 func parsetag(note *string) uint16 {
   1131 	if note == nil || !strings.HasPrefix(*note, "esc:") {
   1132 		return EscUnknown
   1133 	}
   1134 	em := uint16(atoi((*note)[4:]))
   1135 	if em == 0 {
   1136 		return EscNone
   1137 	}
   1138 	return em
   1139 }
   1140 
   1141 // describeEscape returns a string describing the escape tag.
   1142 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation
   1143 // or a description of parameter flow, which takes the form of an optional "contentToHeap"
   1144 // indicating that the content of this parameter is leaked to the heap, followed by a sequence
   1145 // of level encodings separated by spaces, one for each parameter, where _ means no flow,
   1146 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow.
   1147 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences)
   1148 // escapes to the heap, the parameter does not leak to the first output, but does leak directly
   1149 // to the second output (and if there are more than two outputs, there is no flow to those.)
   1150 func describeEscape(em uint16) string {
   1151 	var s string
   1152 	if em&EscMask == EscUnknown {
   1153 		s = "EscUnknown"
   1154 	}
   1155 	if em&EscMask == EscNone {
   1156 		s = "EscNone"
   1157 	}
   1158 	if em&EscMask == EscHeap {
   1159 		s = "EscHeap"
   1160 	}
   1161 	if em&EscMask == EscReturn {
   1162 		s = "EscReturn"
   1163 	}
   1164 	if em&EscMask == EscScope {
   1165 		s = "EscScope"
   1166 	}
   1167 	if em&EscContentEscapes != 0 {
   1168 		if s != "" {
   1169 			s += " "
   1170 		}
   1171 		s += "contentToHeap"
   1172 	}
   1173 	for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag {
   1174 		// See encoding description above
   1175 		if s != "" {
   1176 			s += " "
   1177 		}
   1178 		switch embits := em & bitsMaskForTag; embits {
   1179 		case 0:
   1180 			s += "_"
   1181 		case 1:
   1182 			s += "="
   1183 		default:
   1184 			for i := uint16(0); i < embits-1; i++ {
   1185 				s += "*"
   1186 			}
   1187 		}
   1188 
   1189 	}
   1190 	return s
   1191 }
   1192 
   1193 // escassignfromtag models the input-to-output assignment flow of one of a function
   1194 // calls arguments, where the flow is encoded in "note".
   1195 func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 {
   1196 	em := parsetag(note)
   1197 	if src.Op == OLITERAL {
   1198 		return em
   1199 	}
   1200 
   1201 	if Debug['m'] > 2 {
   1202 		fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
   1203 			Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em))
   1204 	}
   1205 
   1206 	if em == EscUnknown {
   1207 		escassign(e, &e.theSink, src)
   1208 		return em
   1209 	}
   1210 
   1211 	if em == EscNone {
   1212 		return em
   1213 	}
   1214 
   1215 	// If content inside parameter (reached via indirection)
   1216 	// escapes to heap, mark as such.
   1217 	if em&EscContentEscapes != 0 {
   1218 		escassign(e, &e.theSink, e.addDereference(src))
   1219 	}
   1220 
   1221 	em0 := em
   1222 	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next {
   1223 		// Prefer the lowest-level path to the reference (for escape purposes).
   1224 		// Two-bit encoding (for example. 1, 3, and 4 bits are other options)
   1225 		//  01 = 0-level
   1226 		//  10 = 1-level, (content escapes),
   1227 		//  11 = 2-level, (content of content escapes),
   1228 		embits := em & bitsMaskForTag
   1229 		if embits > 0 {
   1230 			n := src
   1231 			for i := uint16(0); i < embits-1; i++ {
   1232 				n = e.addDereference(n) // encode level>0 as indirections
   1233 			}
   1234 			escassign(e, dsts.N, n)
   1235 		}
   1236 	}
   1237 	// If there are too many outputs to fit in the tag,
   1238 	// that is handled at the encoding end as EscHeap,
   1239 	// so there is no need to check here.
   1240 
   1241 	if em != 0 && dsts == nil {
   1242 		Fatal("corrupt esc tag %q or messed up escretval list\n", note)
   1243 	}
   1244 	return em0
   1245 }
   1246 
   1247 func escassignDereference(e *EscState, dst *Node, src *Node) {
   1248 	if src.Op == OLITERAL {
   1249 		return
   1250 	}
   1251 	escassign(e, dst, e.addDereference(src))
   1252 }
   1253 
   1254 // addDereference constructs a suitable OIND note applied to src.
   1255 // Because this is for purposes of escape accounting, not execution,
   1256 // some semantically dubious node combinations are (currently) possible.
   1257 func (e *EscState) addDereference(n *Node) *Node {
   1258 	ind := Nod(OIND, n, nil)
   1259 	e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth
   1260 	ind.Lineno = n.Lineno
   1261 	t := n.Type
   1262 	if Istype(t, Tptr) {
   1263 		// This should model our own sloppy use of OIND to encode
   1264 		// decreasing levels of indirection; i.e., "indirecting" an array
   1265 		// might yield the type of an element.  To be enhanced...
   1266 		t = t.Type
   1267 	}
   1268 	ind.Type = t
   1269 	return ind
   1270 }
   1271 
   1272 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter.
   1273 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel.
   1274 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned.
   1275 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
   1276 	// Flow+level is encoded in two bits.
   1277 	// 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel
   1278 	// 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful.
   1279 	if level.int() <= 0 && level.guaranteedDereference() > 0 {
   1280 		return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content.
   1281 	}
   1282 	if level.int() < 0 {
   1283 		return EscHeap
   1284 	}
   1285 	if level.int() > maxEncodedLevel {
   1286 		// Cannot encode larger values than maxEncodedLevel.
   1287 		level = levelFrom(maxEncodedLevel)
   1288 	}
   1289 	encoded := uint16(level.int() + 1)
   1290 
   1291 	shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits)
   1292 	old := (e >> shift) & bitsMaskForTag
   1293 	if old == 0 || encoded != 0 && encoded < old {
   1294 		old = encoded
   1295 	}
   1296 
   1297 	encodedFlow := old << shift
   1298 	if (encodedFlow>>shift)&bitsMaskForTag != old {
   1299 		// Encoding failure defaults to heap.
   1300 		return EscHeap
   1301 	}
   1302 
   1303 	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
   1304 }
   1305 
   1306 func initEscretval(e *EscState, n *Node, fntype *Type) {
   1307 	i := 0
   1308 	nE := e.nodeEscState(n)
   1309 	nE.Escretval = nil // Suspect this is not nil for indirect calls.
   1310 	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
   1311 		src := Nod(ONAME, nil, nil)
   1312 		buf := fmt.Sprintf(".out%d", i)
   1313 		i++
   1314 		src.Sym = Lookup(buf)
   1315 		src.Type = t.Type
   1316 		src.Class = PAUTO
   1317 		src.Name.Curfn = Curfn
   1318 		e.nodeEscState(src).Escloopdepth = e.loopdepth
   1319 		src.Used = true
   1320 		src.Lineno = n.Lineno
   1321 		nE.Escretval = list(nE.Escretval, src)
   1322 	}
   1323 }
   1324 
   1325 // This is a bit messier than fortunate, pulled out of esc's big
   1326 // switch for clarity.	We either have the paramnodes, which may be
   1327 // connected to other things through flows or we have the parameter type
   1328 // nodes, which may be marked "noescape". Navigating the ast is slightly
   1329 // different for methods vs plain functions and for imported vs
   1330 // this-package
   1331 func esccall(e *EscState, n *Node, up *Node) {
   1332 	var fntype *Type
   1333 	var indirect bool
   1334 	var fn *Node
   1335 	switch n.Op {
   1336 	default:
   1337 		Fatal("esccall")
   1338 
   1339 	case OCALLFUNC:
   1340 		fn = n.Left
   1341 		fntype = fn.Type
   1342 		indirect = fn.Op != ONAME || fn.Class != PFUNC
   1343 
   1344 	case OCALLMETH:
   1345 		fn = n.Left.Right.Sym.Def
   1346 		if fn != nil {
   1347 			fntype = fn.Type
   1348 		} else {
   1349 			fntype = n.Left.Type
   1350 		}
   1351 
   1352 	case OCALLINTER:
   1353 		fntype = n.Left.Type
   1354 		indirect = true
   1355 	}
   1356 
   1357 	ll := n.List
   1358 	if n.List != nil && n.List.Next == nil {
   1359 		a := n.List.N
   1360 		if a.Type.Etype == TSTRUCT && a.Type.Funarg != 0 { // f(g()).
   1361 			ll = e.nodeEscState(a).Escretval
   1362 		}
   1363 	}
   1364 
   1365 	if indirect {
   1366 		// We know nothing!
   1367 		// Leak all the parameters
   1368 		for ; ll != nil; ll = ll.Next {
   1369 			escassign(e, &e.theSink, ll.N)
   1370 			if Debug['m'] > 2 {
   1371 				fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
   1372 			}
   1373 		}
   1374 		// Set up bogus outputs
   1375 		initEscretval(e, n, fntype)
   1376 		// If there is a receiver, it also leaks to heap.
   1377 		if n.Op != OCALLFUNC {
   1378 			t := getthisx(fntype).Type
   1379 			src := n.Left.Left
   1380 			if haspointers(t.Type) {
   1381 				escassign(e, &e.theSink, src)
   1382 			}
   1383 		}
   1384 		return
   1385 	}
   1386 
   1387 	nE := e.nodeEscState(n)
   1388 	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
   1389 		fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
   1390 		if Debug['m'] > 2 {
   1391 			fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
   1392 		}
   1393 
   1394 		// function in same mutually recursive group.  Incorporate into flow graph.
   1395 		//		print("esc local fn: %N\n", fn->ntype);
   1396 		if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil {
   1397 			Fatal("graph inconsistency")
   1398 		}
   1399 
   1400 		// set up out list on this call node
   1401 		for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next {
   1402 			nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
   1403 		}
   1404 
   1405 		// Receiver.
   1406 		if n.Op != OCALLFUNC {
   1407 			escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left)
   1408 		}
   1409 
   1410 		var src *Node
   1411 		for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
   1412 			src = ll.N
   1413 			if lr.N.Isddd && !n.Isddd {
   1414 				// Introduce ODDDARG node to represent ... allocation.
   1415 				src = Nod(ODDDARG, nil, nil)
   1416 				src.Type = typ(TARRAY)
   1417 				src.Type.Type = lr.N.Type.Type
   1418 				src.Type.Bound = int64(count(ll))
   1419 				src.Type = Ptrto(src.Type) // make pointer so it will be tracked
   1420 				src.Lineno = n.Lineno
   1421 				e.track(src)
   1422 				n.Right = src
   1423 			}
   1424 
   1425 			if lr.N.Left != nil {
   1426 				escassign(e, lr.N.Left, src)
   1427 			}
   1428 			if src != ll.N {
   1429 				break
   1430 			}
   1431 		}
   1432 
   1433 		// "..." arguments are untracked
   1434 		for ; ll != nil; ll = ll.Next {
   1435 			if Debug['m'] > 2 {
   1436 				fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
   1437 			}
   1438 			escassign(e, &e.theSink, ll.N)
   1439 		}
   1440 
   1441 		return
   1442 	}
   1443 
   1444 	// Imported or completely analyzed function.  Use the escape tags.
   1445 	if nE.Escretval != nil {
   1446 		Fatal("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
   1447 	}
   1448 
   1449 	if Debug['m'] > 2 {
   1450 		fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
   1451 	}
   1452 
   1453 	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
   1454 	initEscretval(e, n, fntype)
   1455 
   1456 	//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
   1457 
   1458 	// Receiver.
   1459 	if n.Op != OCALLFUNC {
   1460 		t := getthisx(fntype).Type
   1461 		src := n.Left.Left
   1462 		if haspointers(t.Type) {
   1463 			escassignfromtag(e, t.Note, nE.Escretval, src)
   1464 		}
   1465 	}
   1466 
   1467 	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
   1468 		src := ll.N
   1469 		if t.Isddd && !n.Isddd {
   1470 			// Introduce ODDDARG node to represent ... allocation.
   1471 			src = Nod(ODDDARG, nil, nil)
   1472 			src.Lineno = n.Lineno
   1473 			src.Type = typ(TARRAY)
   1474 			src.Type.Type = t.Type.Type
   1475 			src.Type.Bound = int64(count(ll))
   1476 			src.Type = Ptrto(src.Type) // make pointer so it will be tracked
   1477 			e.track(src)
   1478 			n.Right = src
   1479 		}
   1480 
   1481 		if haspointers(t.Type) {
   1482 			if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
   1483 				a := src
   1484 				for a.Op == OCONVNOP {
   1485 					a = a.Left
   1486 				}
   1487 				switch a.Op {
   1488 				// The callee has already been analyzed, so its arguments have esc tags.
   1489 				// The argument is marked as not escaping at all.
   1490 				// Record that fact so that any temporary used for
   1491 				// synthesizing this expression can be reclaimed when
   1492 				// the function returns.
   1493 				// This 'noescape' is even stronger than the usual esc == EscNone.
   1494 				// src->esc == EscNone means that src does not escape the current function.
   1495 				// src->noescape = 1 here means that src does not escape this statement
   1496 				// in the current function.
   1497 				case OCALLPART,
   1498 					OCLOSURE,
   1499 					ODDDARG,
   1500 					OARRAYLIT,
   1501 					OPTRLIT,
   1502 					OSTRUCTLIT:
   1503 					a.Noescape = true
   1504 				}
   1505 			}
   1506 		}
   1507 
   1508 		if src != ll.N {
   1509 			break
   1510 		}
   1511 		t = t.Down
   1512 	}
   1513 
   1514 	// "..." arguments are untracked
   1515 	for ; ll != nil; ll = ll.Next {
   1516 		escassign(e, &e.theSink, ll.N)
   1517 		if Debug['m'] > 2 {
   1518 			fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
   1519 		}
   1520 	}
   1521 }
   1522 
   1523 // escflows records the link src->dst in dst, throwing out some quick wins,
   1524 // and also ensuring that dst is noted as a flow destination.
   1525 func escflows(e *EscState, dst *Node, src *Node) {
   1526 	if dst == nil || src == nil || dst == src {
   1527 		return
   1528 	}
   1529 
   1530 	// Don't bother building a graph for scalars.
   1531 	if src.Type != nil && !haspointers(src.Type) {
   1532 		return
   1533 	}
   1534 
   1535 	if Debug['m'] > 2 {
   1536 		fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort))
   1537 	}
   1538 
   1539 	dstE := e.nodeEscState(dst)
   1540 	if dstE.Escflowsrc == nil {
   1541 		e.dsts = list(e.dsts, dst)
   1542 		e.dstcount++
   1543 	}
   1544 
   1545 	e.edgecount++
   1546 
   1547 	dstE.Escflowsrc = list(dstE.Escflowsrc, src)
   1548 }
   1549 
   1550 // Whenever we hit a reference node, the level goes up by one, and whenever
   1551 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0
   1552 // finding an OADDR just means we're following the upstream of a dereference,
   1553 // so this address doesn't leak (yet).
   1554 // If level == 0, it means the /value/ of this node can reach the root of this flood.
   1555 // so if this node is an OADDR, it's argument should be marked as escaping iff
   1556 // it's currfn/e->loopdepth are different from the flood's root.
   1557 // Once an object has been moved to the heap, all of it's upstream should be considered
   1558 // escaping to the global scope.
   1559 func escflood(e *EscState, dst *Node) {
   1560 	switch dst.Op {
   1561 	case ONAME, OCLOSURE:
   1562 		break
   1563 
   1564 	default:
   1565 		return
   1566 	}
   1567 
   1568 	dstE := e.nodeEscState(dst)
   1569 	if Debug['m'] > 1 {
   1570 		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
   1571 	}
   1572 
   1573 	for l := dstE.Escflowsrc; l != nil; l = l.Next {
   1574 		e.walkgen++
   1575 		escwalk(e, levelFrom(0), dst, l.N)
   1576 	}
   1577 }
   1578 
   1579 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function.
   1580 func funcOutputAndInput(dst, src *Node) bool {
   1581 	// Note if dst is marked as escaping, then "returned" is too weak.
   1582 	return dst.Op == ONAME && dst.Class == PPARAMOUT &&
   1583 		src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn
   1584 }
   1585 
   1586 func escwalk(e *EscState, level Level, dst *Node, src *Node) {
   1587 	if src.Op == OLITERAL {
   1588 		return
   1589 	}
   1590 	srcE := e.nodeEscState(src)
   1591 	if srcE.Walkgen == e.walkgen {
   1592 		// Esclevels are vectors, do not compare as integers,
   1593 		// and must use "min" of old and new to guarantee
   1594 		// convergence.
   1595 		level = level.min(srcE.Esclevel)
   1596 		if level == srcE.Esclevel {
   1597 			return
   1598 		}
   1599 	}
   1600 
   1601 	srcE.Walkgen = e.walkgen
   1602 	srcE.Esclevel = level
   1603 
   1604 	if Debug['m'] > 1 {
   1605 		fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n",
   1606 			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), e.curfnSym(src), srcE.Escloopdepth)
   1607 	}
   1608 
   1609 	e.pdepth++
   1610 
   1611 	// Input parameter flowing to output parameter?
   1612 	var leaks bool
   1613 	dstE := e.nodeEscState(dst)
   1614 	if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
   1615 		// This case handles:
   1616 		// 1. return in
   1617 		// 2. return &in
   1618 		// 3. tmp := in; return &tmp
   1619 		// 4. return *in
   1620 		if Debug['m'] != 0 {
   1621 			if Debug['m'] == 1 {
   1622 				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int())
   1623 			} else {
   1624 				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level)
   1625 			}
   1626 		}
   1627 		if src.Esc&EscMask != EscReturn {
   1628 			src.Esc = EscReturn | src.Esc&EscContentEscapes
   1629 		}
   1630 		src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level)
   1631 		goto recurse
   1632 	}
   1633 
   1634 	// If parameter content escapes to heap, set EscContentEscapes
   1635 	// Note minor confusion around escape from pointer-to-struct vs escape from struct
   1636 	if dst.Esc == EscHeap &&
   1637 		src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope &&
   1638 		level.int() > 0 {
   1639 		src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
   1640 		if Debug['m'] != 0 {
   1641 			Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort))
   1642 		}
   1643 	}
   1644 
   1645 	leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth
   1646 
   1647 	switch src.Op {
   1648 	case ONAME:
   1649 		if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope {
   1650 			if level.guaranteedDereference() > 0 {
   1651 				src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
   1652 				if Debug['m'] != 0 {
   1653 					if Debug['m'] == 1 {
   1654 						Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort))
   1655 					} else {
   1656 						Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
   1657 							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
   1658 					}
   1659 				}
   1660 			} else {
   1661 				src.Esc = EscScope
   1662 				if Debug['m'] != 0 {
   1663 					if Debug['m'] == 1 {
   1664 						Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
   1665 					} else {
   1666 						Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
   1667 							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
   1668 					}
   1669 				}
   1670 			}
   1671 		}
   1672 
   1673 		// Treat a PPARAMREF closure variable as equivalent to the
   1674 		// original variable.
   1675 		if src.Class == PPARAMREF {
   1676 			if leaks && Debug['m'] != 0 {
   1677 				Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
   1678 			}
   1679 			escwalk(e, level, dst, src.Name.Param.Closure)
   1680 		}
   1681 
   1682 	case OPTRLIT, OADDR:
   1683 		if leaks {
   1684 			src.Esc = EscHeap
   1685 			addrescapes(src.Left)
   1686 			if Debug['m'] != 0 {
   1687 				p := src
   1688 				if p.Left.Op == OCLOSURE {
   1689 					p = p.Left // merely to satisfy error messages in tests
   1690 				}
   1691 				if Debug['m'] > 1 {
   1692 					Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
   1693 						Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth)
   1694 				} else {
   1695 					Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort))
   1696 				}
   1697 			}
   1698 		}
   1699 
   1700 		escwalk(e, level.dec(), dst, src.Left)
   1701 
   1702 	case OAPPEND:
   1703 		escwalk(e, level, dst, src.List.N)
   1704 
   1705 	case OARRAYLIT:
   1706 		if Isfixedarray(src.Type) {
   1707 			break
   1708 		}
   1709 		for ll := src.List; ll != nil; ll = ll.Next {
   1710 			escwalk(e, level.dec(), dst, ll.N.Right)
   1711 		}
   1712 
   1713 		fallthrough
   1714 
   1715 	case ODDDARG,
   1716 		OMAKECHAN,
   1717 		OMAKEMAP,
   1718 		OMAKESLICE,
   1719 		OARRAYRUNESTR,
   1720 		OARRAYBYTESTR,
   1721 		OSTRARRAYRUNE,
   1722 		OSTRARRAYBYTE,
   1723 		OADDSTR,
   1724 		OMAPLIT,
   1725 		ONEW,
   1726 		OCLOSURE,
   1727 		OCALLPART,
   1728 		ORUNESTR,
   1729 		OCONVIFACE:
   1730 		if leaks {
   1731 			src.Esc = EscHeap
   1732 			if Debug['m'] != 0 {
   1733 				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
   1734 			}
   1735 		}
   1736 
   1737 	case ODOT,
   1738 		ODOTTYPE,
   1739 		OSLICE,
   1740 		OSLICEARR,
   1741 		OSLICE3,
   1742 		OSLICE3ARR,
   1743 		OSLICESTR:
   1744 		escwalk(e, level, dst, src.Left)
   1745 
   1746 	case OINDEX:
   1747 		if Isfixedarray(src.Left.Type) {
   1748 			escwalk(e, level, dst, src.Left)
   1749 			break
   1750 		}
   1751 		fallthrough
   1752 
   1753 	case ODOTPTR, OINDEXMAP, OIND:
   1754 		escwalk(e, level.inc(), dst, src.Left)
   1755 
   1756 	// In this case a link went directly to a call, but should really go
   1757 	// to the dummy .outN outputs that were created for the call that
   1758 	// themselves link to the inputs with levels adjusted.
   1759 	// See e.g. #10466
   1760 	// This can only happen with functions returning a single result.
   1761 	case OCALLMETH, OCALLFUNC, OCALLINTER:
   1762 		if srcE.Escretval != nil {
   1763 			if Debug['m'] > 1 {
   1764 				fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
   1765 					Ctxt.Line(int(lineno)), e.loopdepth,
   1766 					Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort))
   1767 			}
   1768 			src = srcE.Escretval.N
   1769 			srcE = e.nodeEscState(src)
   1770 		}
   1771 	}
   1772 
   1773 recurse:
   1774 	level = level.copy()
   1775 	for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next {
   1776 		escwalk(e, level, dst, ll.N)
   1777 	}
   1778 
   1779 	e.pdepth--
   1780 }
   1781 
   1782 func esctag(e *EscState, func_ *Node) {
   1783 	func_.Esc = EscFuncTagged
   1784 
   1785 	// External functions are assumed unsafe,
   1786 	// unless //go:noescape is given before the declaration.
   1787 	if func_.Nbody == nil {
   1788 		if func_.Noescape {
   1789 			for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
   1790 				if haspointers(t.Type) {
   1791 					t.Note = mktag(EscNone)
   1792 				}
   1793 			}
   1794 		}
   1795 
   1796 		return
   1797 	}
   1798 
   1799 	savefn := Curfn
   1800 	Curfn = func_
   1801 
   1802 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
   1803 		if ll.N.Op != ONAME {
   1804 			continue
   1805 		}
   1806 
   1807 		switch ll.N.Esc & EscMask {
   1808 		case EscNone, // not touched by escflood
   1809 			EscReturn:
   1810 			if haspointers(ll.N.Type) { // don't bother tagging for scalars
   1811 				ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc))
   1812 			}
   1813 
   1814 		case EscHeap, // touched by escflood, moved to heap
   1815 			EscScope: // touched by escflood, value leaves scope
   1816 			break
   1817 		}
   1818 	}
   1819 
   1820 	Curfn = savefn
   1821 }
   1822