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:
parent
def1e7276a
commit
7047742f12
@ -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--
|
||||||
|
Loading…
Reference in New Issue
Block a user