1
0
mirror of https://github.com/golang/go synced 2024-11-18 04:44:46 -07:00

cmd/compile: change esc.go to use nodeSeq

Move a few local fields all the way to []*Node while I'm at it.

Update #14473.

Change-Id: Ib18360879839ac592f778cf1042f111bdf14add3
Reviewed-on: https://go-review.googlesource.com/20197
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Ian Lance Taylor 2016-03-03 17:38:14 -08:00
parent def1e7276a
commit 7047742f12

View File

@ -78,7 +78,7 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
min := v.visitgen min := v.visitgen
v.stack = append(v.stack, n) v.stack = append(v.stack, n)
min = v.visitcodeslice(n.Nbody.Slice(), min) min = v.visitcodelist(n.Nbody, min)
if (min == id || min == id+1) && n.Func.FCurfn == nil { if (min == id || min == id+1) && n.Func.FCurfn == nil {
// This node is the root of a strongly connected component. // This node is the root of a strongly connected component.
@ -110,16 +110,9 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
return min return min
} }
func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 { func (v *bottomUpVisitor) visitcodelist(l nodesOrNodeList, min uint32) uint32 {
for ; l != nil; l = l.Next { for it := nodeSeqIterate(l); !it.Done(); it.Next() {
min = v.visitcode(l.N, min) min = v.visitcode(it.N(), min)
}
return min
}
func (v *bottomUpVisitor) visitcodeslice(l []*Node, min uint32) uint32 {
for _, n := range l {
min = v.visitcode(n, min)
} }
return min return min
} }
@ -133,7 +126,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
min = v.visitcode(n.Left, min) min = v.visitcode(n.Left, min)
min = v.visitcode(n.Right, min) min = v.visitcode(n.Right, min)
min = v.visitcodelist(n.List, min) min = v.visitcodelist(n.List, min)
min = v.visitcodeslice(n.Nbody.Slice(), min) min = v.visitcodelist(n.Nbody, min)
min = v.visitcodelist(n.Rlist, min) min = v.visitcodelist(n.Rlist, min)
if n.Op == OCALLFUNC || n.Op == OCALLMETH { if n.Op == OCALLFUNC || n.Op == OCALLMETH {
@ -307,7 +300,7 @@ func (l Level) guaranteedDereference() int {
type NodeEscState struct { type NodeEscState struct {
Curfn *Node Curfn *Node
Escflowsrc *NodeList // flow(this, src) Escflowsrc []*Node // flow(this, src)
Escretval *NodeList // on OCALLxxx, list of dummy return values Escretval *NodeList // on OCALLxxx, list of dummy return values
Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
Esclevel Level Esclevel Level
@ -336,7 +329,7 @@ func (e *EscState) track(n *Node) {
n.Esc = EscNone // until proven otherwise n.Esc = EscNone // until proven otherwise
nE := e.nodeEscState(n) nE := e.nodeEscState(n)
nE.Escloopdepth = e.loopdepth nE.Escloopdepth = e.loopdepth
e.noesc = list(e.noesc, n) e.noesc = append(e.noesc, n)
} }
// Escape constants are numbered in order of increasing "escapiness" // Escape constants are numbered in order of increasing "escapiness"
@ -396,14 +389,14 @@ type EscState struct {
// flow to. // flow to.
theSink Node theSink Node
dsts *NodeList // all dst nodes dsts []*Node // all dst nodes
loopdepth int32 // for detecting nested loop scopes loopdepth int32 // for detecting nested loop scopes
pdepth int // for debug printing in recursions. pdepth int // for debug printing in recursions.
dstcount int // diagnostic dstcount int // diagnostic
edgecount int // diagnostic edgecount int // diagnostic
noesc *NodeList // list of possible non-escaping nodes, for printing noesc []*Node // list of possible non-escaping nodes, for printing
recursive bool // recursive function or group of mutually recursive functions. recursive bool // recursive function or group of mutually recursive functions.
opts []*Node // nodes with .Opt initialized opts []*Node // nodes with .Opt initialized
walkgen uint32 walkgen uint32
} }
@ -448,8 +441,8 @@ func escAnalyze(all []*Node, recursive bool) {
// visit the upstream of each dst, mark address nodes with // visit the upstream of each dst, mark address nodes with
// addrescapes, mark parameters unsafe // addrescapes, mark parameters unsafe
for l := e.dsts; l != nil; l = l.Next { for _, n := range e.dsts {
escflood(e, l.N) escflood(e, n)
} }
// for all top level functions, tag the typenodes corresponding to the param nodes // for all top level functions, tag the typenodes corresponding to the param nodes
@ -460,9 +453,9 @@ func escAnalyze(all []*Node, recursive bool) {
} }
if Debug['m'] != 0 { if Debug['m'] != 0 {
for l := e.noesc; l != nil; l = l.Next { for _, n := range e.noesc {
if l.N.Esc == EscNone { if n.Esc == EscNone {
Warnl(l.N.Lineno, "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort)) Warnl(n.Lineno, "%v %v does not escape", e.curfnSym(n), Nconv(n, obj.FmtShort))
} }
} }
} }
@ -503,7 +496,7 @@ func escfunc(e *EscState, func_ *Node) {
} else { } else {
ln.Esc = EscNone // prime for escflood later ln.Esc = EscNone // prime for escflood later
} }
e.noesc = list(e.noesc, ln) e.noesc = append(e.noesc, ln)
} }
} }
@ -516,8 +509,8 @@ func escfunc(e *EscState, func_ *Node) {
} }
} }
escloopdepthslice(e, Curfn.Nbody.Slice()) escloopdepthlist(e, Curfn.Nbody)
escslice(e, Curfn.Nbody.Slice(), Curfn) esclist(e, Curfn.Nbody, Curfn)
Curfn = savefn Curfn = savefn
e.loopdepth = saveld e.loopdepth = saveld
} }
@ -529,15 +522,9 @@ var looping Label
var nonlooping Label var nonlooping Label
func escloopdepthlist(e *EscState, l *NodeList) { func escloopdepthlist(e *EscState, l nodesOrNodeList) {
for ; l != nil; l = l.Next { for it := nodeSeqIterate(l); !it.Done(); it.Next() {
escloopdepth(e, l.N) escloopdepth(e, it.N())
}
}
func escloopdepthslice(e *EscState, l []*Node) {
for _, n := range l {
escloopdepth(e, n)
} }
} }
@ -575,19 +562,13 @@ func escloopdepth(e *EscState, n *Node) {
escloopdepth(e, n.Left) escloopdepth(e, n.Left)
escloopdepth(e, n.Right) escloopdepth(e, n.Right)
escloopdepthlist(e, n.List) escloopdepthlist(e, n.List)
escloopdepthslice(e, n.Nbody.Slice()) escloopdepthlist(e, n.Nbody)
escloopdepthlist(e, n.Rlist) escloopdepthlist(e, n.Rlist)
} }
func esclist(e *EscState, l *NodeList, up *Node) { func esclist(e *EscState, l nodesOrNodeList, up *Node) {
for ; l != nil; l = l.Next { for it := nodeSeqIterate(l); !it.Done(); it.Next() {
esc(e, l.N, up) esc(e, it.N(), up)
}
}
func escslice(e *EscState, l []*Node, up *Node) {
for _, n := range l {
esc(e, n, up)
} }
} }
@ -616,11 +597,10 @@ func esc(e *EscState, n *Node, up *Node) {
// must happen before processing of switch body, // must happen before processing of switch body,
// so before recursion. // so before recursion.
if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW { if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW {
for ll := n.List; ll != nil; ll = ll.Next { // cases for it := nodeSeqIterate(n.List); !it.Done(); it.Next() { // cases
// it.N().Rlist is the variable per case
// ll.N.Rlist is the variable per case if nodeSeqLen(it.N().Rlist) != 0 {
if ll.N.Rlist != nil { e.nodeEscState(nodeSeqFirst(it.N().Rlist)).Escloopdepth = e.loopdepth
e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth
} }
} }
} }
@ -641,7 +621,7 @@ func esc(e *EscState, n *Node, up *Node) {
esc(e, n.Left, n) esc(e, n.Left, n)
esc(e, n.Right, n) esc(e, n.Right, n)
escslice(e, n.Nbody.Slice(), n) esclist(e, n.Nbody, n)
esclist(e, n.List, n) esclist(e, n.List, n)
esclist(e, n.Rlist, n) esclist(e, n.Rlist, n)
@ -679,7 +659,7 @@ func esc(e *EscState, n *Node, up *Node) {
n.Left.Sym.Label = nil n.Left.Sym.Label = nil
case ORANGE: case ORANGE:
if n.List != nil && n.List.Next != nil { if nodeSeqLen(n.List) >= 2 {
// Everything but fixed array is a dereference. // Everything but fixed array is a dereference.
// If fixed array is really the address of fixed array, // If fixed array is really the address of fixed array,
@ -687,20 +667,20 @@ func esc(e *EscState, n *Node, up *Node) {
// dereferenced (see #12588) // dereferenced (see #12588)
if Isfixedarray(n.Type) && if Isfixedarray(n.Type) &&
!(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Type, n.Type)) { !(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Type, n.Type)) {
escassign(e, n.List.Next.N, n.Right) escassign(e, nodeSeqSecond(n.List), n.Right)
} else { } else {
escassignDereference(e, n.List.Next.N, n.Right) escassignDereference(e, nodeSeqSecond(n.List), n.Right)
} }
} }
case OSWITCH: case OSWITCH:
if n.Left != nil && n.Left.Op == OTYPESW { if n.Left != nil && n.Left.Op == OTYPESW {
for ll := n.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
// cases // cases
// n.Left.Right is the argument of the .(type), // n.Left.Right is the argument of the .(type),
// ll.N.Rlist is the variable per case // it.N().Rlist is the variable per case
if ll.N.Rlist != nil { if nodeSeqLen(it.N().Rlist) != 0 {
escassign(e, ll.N.Rlist.N, n.Left.Right) escassign(e, nodeSeqFirst(it.N().Rlist), n.Left.Right)
} }
} }
} }
@ -741,18 +721,18 @@ func esc(e *EscState, n *Node, up *Node) {
escassign(e, n.Left, n.Right) escassign(e, n.Left, n.Right)
case OAS2: // x,y = a,b case OAS2: // x,y = a,b
if count(n.List) == count(n.Rlist) { if nodeSeqLen(n.List) == nodeSeqLen(n.Rlist) {
ll := n.List lrit := nodeSeqIterate(n.Rlist)
lr := n.Rlist for llit := nodeSeqIterate(n.List); !llit.Done(); llit.Next() {
for ; ll != nil; ll, lr = ll.Next, lr.Next { escassign(e, llit.N(), lrit.N())
escassign(e, ll.N, lr.N) lrit.Next()
} }
} }
case OAS2RECV, // v, ok = <-ch case OAS2RECV, // v, ok = <-ch
OAS2MAPR, // v, ok = m[k] OAS2MAPR, // v, ok = m[k]
OAS2DOTTYPE: // v, ok = x.(type) OAS2DOTTYPE: // v, ok = x.(type)
escassign(e, n.List.N, n.Rlist.N) escassign(e, nodeSeqFirst(n.List), nodeSeqFirst(n.Rlist))
case OSEND: // ch <- x case OSEND: // ch <- x
escassign(e, &e.theSink, n.Right) escassign(e, &e.theSink, n.Right)
@ -770,8 +750,8 @@ func esc(e *EscState, n *Node, up *Node) {
escassign(e, &e.theSink, n.Left.Left) escassign(e, &e.theSink, n.Left.Left)
escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call
for ll := n.Left.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(n.Left.List); !it.Done(); it.Next() {
escassign(e, &e.theSink, ll.N) escassign(e, &e.theSink, it.N())
} }
case OCALLMETH, OCALLFUNC, OCALLINTER: case OCALLMETH, OCALLFUNC, OCALLINTER:
@ -779,37 +759,39 @@ func esc(e *EscState, n *Node, up *Node) {
// esccall already done on n->rlist->n. tie it's escretval to n->list // esccall already done on n->rlist->n. tie it's escretval to n->list
case OAS2FUNC: // x,y = f() case OAS2FUNC: // x,y = f()
lr := e.nodeEscState(n.Rlist.N).Escretval lrit := nodeSeqIterate(e.nodeEscState(nodeSeqFirst(n.Rlist)).Escretval)
var ll *NodeList var llit nodeSeqIterator
for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next { for llit = nodeSeqIterate(n.List); !lrit.Done() && !llit.Done(); llit.Next() {
escassign(e, ll.N, lr.N) escassign(e, llit.N(), lrit.N())
lrit.Next()
} }
if lr != nil || ll != nil { if !llit.Done() || !lrit.Done() {
Fatalf("esc oas2func") Fatalf("esc oas2func")
} }
case ORETURN: case ORETURN:
ll := n.List ll := n.List
if count(n.List) == 1 && Curfn.Type.Outtuple > 1 { if nodeSeqLen(n.List) == 1 && Curfn.Type.Outtuple > 1 {
// OAS2FUNC in disguise // OAS2FUNC in disguise
// esccall already done on n->list->n // esccall already done on n->list->n
// tie n->list->n->escretval to curfn->dcl PPARAMOUT's // tie n->list->n->escretval to curfn->dcl PPARAMOUT's
ll = e.nodeEscState(n.List.N).Escretval ll = e.nodeEscState(n.List.N).Escretval
} }
llit := nodeSeqIterate(ll)
for _, lrn := range Curfn.Func.Dcl { for _, lrn := range Curfn.Func.Dcl {
if ll == nil { if llit.Done() {
break break
} }
if lrn.Op != ONAME || lrn.Class != PPARAMOUT { if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
continue continue
} }
escassign(e, lrn, ll.N) escassign(e, lrn, llit.N())
ll = ll.Next llit.Next()
} }
if ll != nil { if !llit.Done() {
Fatalf("esc return list") Fatalf("esc return list")
} }
@ -819,18 +801,20 @@ func esc(e *EscState, n *Node, up *Node) {
case OAPPEND: case OAPPEND:
if !n.Isddd { if !n.Isddd {
for ll := n.List.Next; ll != nil; ll = ll.Next { llit := nodeSeqIterate(n.List)
escassign(e, &e.theSink, ll.N) // lose track of assign to dereference llit.Next()
for ; !llit.Done(); llit.Next() {
escassign(e, &e.theSink, llit.N()) // lose track of assign to dereference
} }
} else { } else {
// append(slice1, slice2...) -- slice2 itself does not escape, but contents do. // append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
slice2 := n.List.Next.N slice2 := nodeSeqSecond(n.List)
escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference
if Debug['m'] > 2 { if Debug['m'] > 2 {
Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort)) Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort))
} }
} }
escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too escassignDereference(e, &e.theSink, nodeSeqFirst(n.List)) // The original elements are now leaked, too
case OCOPY: case OCOPY:
escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference
@ -849,14 +833,14 @@ func esc(e *EscState, n *Node, up *Node) {
} }
// Link values to array/slice // Link values to array/slice
for ll := n.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
escassign(e, n, ll.N.Right) escassign(e, n, it.N().Right)
} }
// Link values to struct. // Link values to struct.
case OSTRUCTLIT: case OSTRUCTLIT:
for ll := n.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
escassign(e, n, ll.N.Right) escassign(e, n, it.N().Right)
} }
case OPTRLIT: case OPTRLIT:
@ -875,9 +859,9 @@ func esc(e *EscState, n *Node, up *Node) {
e.track(n) e.track(n)
// Keys and values make it to memory, lose track. // Keys and values make it to memory, lose track.
for ll := n.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
escassign(e, &e.theSink, ll.N.Left) escassign(e, &e.theSink, it.N().Left)
escassign(e, &e.theSink, ll.N.Right) escassign(e, &e.theSink, it.N().Right)
} }
// Link addresses of captured variables to closure. // Link addresses of captured variables to closure.
@ -1052,8 +1036,8 @@ func escassign(e *EscState, dst *Node, src *Node) {
// Flowing multiple returns to a single dst happens when // Flowing multiple returns to a single dst happens when
// analyzing "go f(g())": here g() flows to sink (issue 4529). // analyzing "go f(g())": here g() flows to sink (issue 4529).
case OCALLMETH, OCALLFUNC, OCALLINTER: case OCALLMETH, OCALLFUNC, OCALLINTER:
for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next { for it := nodeSeqIterate(e.nodeEscState(src).Escretval); !it.Done(); it.Next() {
escflows(e, dst, ll.N) escflows(e, dst, it.N())
} }
// A non-pointer escaping from a struct does not concern us. // A non-pointer escaping from a struct does not concern us.
@ -1087,7 +1071,7 @@ func escassign(e *EscState, dst *Node, src *Node) {
case OAPPEND: case OAPPEND:
// Append returns first argument. // Append returns first argument.
// Subsequent arguments are already leaked because they are operands to append. // Subsequent arguments are already leaked because they are operands to append.
escassign(e, dst, src.List.N) escassign(e, dst, nodeSeqFirst(src.List))
case OINDEX: case OINDEX:
// Index of array preserves input value. // Index of array preserves input value.
@ -1220,7 +1204,7 @@ func describeEscape(em uint16) string {
// escassignfromtag models the input-to-output assignment flow of one of a function // escassignfromtag models the input-to-output assignment flow of one of a function
// calls arguments, where the flow is encoded in "note". // calls arguments, where the flow is encoded in "note".
func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 { func escassignfromtag(e *EscState, note *string, dsts nodesOrNodeList, src *Node) uint16 {
em := parsetag(note) em := parsetag(note)
if src.Op == OLITERAL { if src.Op == OLITERAL {
return em return em
@ -1247,7 +1231,8 @@ func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint
} }
em0 := em em0 := em
for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next { it := nodeSeqIterate(dsts)
for em >>= EscReturnBits; em != 0 && !it.Done(); em = em >> bitsPerOutputInTag {
// Prefer the lowest-level path to the reference (for escape purposes). // Prefer the lowest-level path to the reference (for escape purposes).
// Two-bit encoding (for example. 1, 3, and 4 bits are other options) // Two-bit encoding (for example. 1, 3, and 4 bits are other options)
// 01 = 0-level // 01 = 0-level
@ -1259,14 +1244,15 @@ func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint
for i := uint16(0); i < embits-1; i++ { for i := uint16(0); i < embits-1; i++ {
n = e.addDereference(n) // encode level>0 as indirections n = e.addDereference(n) // encode level>0 as indirections
} }
escassign(e, dsts.N, n) escassign(e, it.N(), n)
} }
it.Next()
} }
// If there are too many outputs to fit in the tag, // If there are too many outputs to fit in the tag,
// that is handled at the encoding end as EscHeap, // that is handled at the encoding end as EscHeap,
// so there is no need to check here. // so there is no need to check here.
if em != 0 && dsts == nil { if em != 0 && it.Done() {
Fatalf("corrupt esc tag %q or messed up escretval list\n", note) Fatalf("corrupt esc tag %q or messed up escretval list\n", note)
} }
return em0 return em0
@ -1334,7 +1320,7 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
func initEscretval(e *EscState, n *Node, fntype *Type) { func initEscretval(e *EscState, n *Node, fntype *Type) {
i := 0 i := 0
nE := e.nodeEscState(n) nE := e.nodeEscState(n)
nE.Escretval = nil // Suspect this is not nil for indirect calls. setNodeSeq(&nE.Escretval, nil) // Suspect this is not nil for indirect calls.
for t := getoutargx(fntype).Type; t != nil; t = t.Down { for t := getoutargx(fntype).Type; t != nil; t = t.Down {
src := Nod(ONAME, nil, nil) src := Nod(ONAME, nil, nil)
buf := fmt.Sprintf(".out%d", i) buf := fmt.Sprintf(".out%d", i)
@ -1346,7 +1332,7 @@ func initEscretval(e *EscState, n *Node, fntype *Type) {
e.nodeEscState(src).Escloopdepth = e.loopdepth e.nodeEscState(src).Escloopdepth = e.loopdepth
src.Used = true src.Used = true
src.Lineno = n.Lineno src.Lineno = n.Lineno
nE.Escretval = list(nE.Escretval, src) appendNodeSeqNode(&nE.Escretval, src)
} }
} }
@ -1393,10 +1379,10 @@ func esccall(e *EscState, n *Node, up *Node) {
if indirect { if indirect {
// We know nothing! // We know nothing!
// Leak all the parameters // Leak all the parameters
for ; ll != nil; ll = ll.Next { for it := nodeSeqIterate(ll); !it.Done(); it.Next() {
escassign(e, &e.theSink, ll.N) escassign(e, &e.theSink, it.N())
if Debug['m'] > 2 { if Debug['m'] > 2 {
fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", linestr(lineno), Nconv(ll.N, obj.FmtShort)) fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", linestr(lineno), Nconv(it.N(), obj.FmtShort))
} }
} }
// Set up bogus outputs // Set up bogus outputs
@ -1421,13 +1407,13 @@ func esccall(e *EscState, n *Node, up *Node) {
// function in same mutually recursive group. Incorporate into flow graph. // function in same mutually recursive group. Incorporate into flow graph.
// print("esc local fn: %N\n", fn->ntype); // print("esc local fn: %N\n", fn->ntype);
if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil { if fn.Name.Defn.Esc == EscFuncUnknown || nodeSeqLen(nE.Escretval) != 0 {
Fatalf("graph inconsistency") Fatalf("graph inconsistency")
} }
// set up out list on this call node // set up out list on this call node
for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next { for it := nodeSeqIterate(fn.Name.Param.Ntype.Rlist); !it.Done(); it.Next() {
nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT) appendNodeSeqNode(&nE.Escretval, it.N().Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT)
} }
// Receiver. // Receiver.
@ -1436,41 +1422,43 @@ func esccall(e *EscState, n *Node, up *Node) {
} }
var src *Node var src *Node
for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { llit := nodeSeqIterate(ll)
src = ll.N for lrit := nodeSeqIterate(fn.Name.Param.Ntype.List); !llit.Done() && !lrit.Done(); llit.Next() {
if lr.N.Isddd && !n.Isddd { src = llit.N()
if lrit.N().Isddd && !n.Isddd {
// Introduce ODDDARG node to represent ... allocation. // Introduce ODDDARG node to represent ... allocation.
src = Nod(ODDDARG, nil, nil) src = Nod(ODDDARG, nil, nil)
src.Type = typ(TARRAY) src.Type = typ(TARRAY)
src.Type.Type = lr.N.Type.Type src.Type.Type = lrit.N().Type.Type
src.Type.Bound = int64(count(ll)) src.Type.Bound = int64(llit.Len())
src.Type = Ptrto(src.Type) // make pointer so it will be tracked src.Type = Ptrto(src.Type) // make pointer so it will be tracked
src.Lineno = n.Lineno src.Lineno = n.Lineno
e.track(src) e.track(src)
n.Right = src n.Right = src
} }
if lr.N.Left != nil { if lrit.N().Left != nil {
escassign(e, lr.N.Left, src) escassign(e, lrit.N().Left, src)
} }
if src != ll.N { if src != llit.N() {
break break
} }
lrit.Next()
} }
// "..." arguments are untracked // "..." arguments are untracked
for ; ll != nil; ll = ll.Next { for ; !llit.Done(); llit.Next() {
if Debug['m'] > 2 { if Debug['m'] > 2 {
fmt.Printf("%v::esccall:: ... <- %v, untracked\n", linestr(lineno), Nconv(ll.N, obj.FmtShort)) fmt.Printf("%v::esccall:: ... <- %v, untracked\n", linestr(lineno), Nconv(llit.N(), obj.FmtShort))
} }
escassign(e, &e.theSink, ll.N) escassign(e, &e.theSink, llit.N())
} }
return return
} }
// Imported or completely analyzed function. Use the escape tags. // Imported or completely analyzed function. Use the escape tags.
if nE.Escretval != nil { if nodeSeqLen(nE.Escretval) != 0 {
Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign)) Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
} }
@ -1566,14 +1554,14 @@ func escflows(e *EscState, dst *Node, src *Node) {
} }
dstE := e.nodeEscState(dst) dstE := e.nodeEscState(dst)
if dstE.Escflowsrc == nil { if len(dstE.Escflowsrc) == 0 {
e.dsts = list(e.dsts, dst) e.dsts = append(e.dsts, dst)
e.dstcount++ e.dstcount++
} }
e.edgecount++ e.edgecount++
dstE.Escflowsrc = list(dstE.Escflowsrc, src) dstE.Escflowsrc = append(dstE.Escflowsrc, src)
} }
// Whenever we hit a reference node, the level goes up by one, and whenever // Whenever we hit a reference node, the level goes up by one, and whenever
@ -1599,9 +1587,9 @@ func escflood(e *EscState, dst *Node) {
fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth) fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
} }
for l := dstE.Escflowsrc; l != nil; l = l.Next { for _, n := range dstE.Escflowsrc {
e.walkgen++ e.walkgen++
escwalk(e, levelFrom(0), dst, l.N) escwalk(e, levelFrom(0), dst, n)
} }
} }
@ -1750,7 +1738,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
} }
case OAPPEND: case OAPPEND:
escwalk(e, level, dst, src.List.N) escwalk(e, level, dst, nodeSeqFirst(src.List))
case ODDDARG: case ODDDARG:
if leaks { if leaks {
@ -1767,8 +1755,8 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
if Isfixedarray(src.Type) { if Isfixedarray(src.Type) {
break break
} }
for ll := src.List; ll != nil; ll = ll.Next { for it := nodeSeqIterate(src.List); !it.Done(); it.Next() {
escwalk(e, level.dec(), dst, ll.N.Right) escwalk(e, level.dec(), dst, it.N().Right)
} }
fallthrough fallthrough
@ -1820,21 +1808,21 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
// See e.g. #10466 // See e.g. #10466
// This can only happen with functions returning a single result. // This can only happen with functions returning a single result.
case OCALLMETH, OCALLFUNC, OCALLINTER: case OCALLMETH, OCALLFUNC, OCALLINTER:
if srcE.Escretval != nil { if nodeSeqLen(srcE.Escretval) != 0 {
if Debug['m'] > 1 { if Debug['m'] > 1 {
fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n", fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
linestr(lineno), e.loopdepth, linestr(lineno), e.loopdepth,
Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort)) Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(nodeSeqFirst(srcE.Escretval), obj.FmtShort))
} }
src = srcE.Escretval.N src = nodeSeqFirst(srcE.Escretval)
srcE = e.nodeEscState(src) srcE = e.nodeEscState(src)
} }
} }
recurse: recurse:
level = level.copy() level = level.copy()
for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next { for _, n := range srcE.Escflowsrc {
escwalkBody(e, level, dst, ll.N, extraloopdepth) escwalkBody(e, level, dst, n, extraloopdepth)
} }
e.pdepth-- e.pdepth--