From 12c9d753f83ab4755151c8a72c212358dd85bc83 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 19 Oct 2017 11:23:12 -0700 Subject: [PATCH] cmd/compile: refactor generic AST walking code racewalk's "foreach" function applies a function to all of a Node's immediate children, but with a non-idiomatic signature. This CL reworks it to recursively iterate over the entire subtree rooted at Node and provides a way to short-circuit iteration. Passes toolstash -cmp for std cmd with -race. Change-Id: I738b73953d608709802c97945b7e0f4e4940d3f4 Reviewed-on: https://go-review.googlesource.com/71911 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/racewalk.go | 40 ++++++------------------- src/cmd/compile/internal/gc/syntax.go | 20 +++++++++++++ 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 4a4c4126c0..2ffd0f96a8 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -452,9 +452,15 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool { // that has got a pointer inside. Whether it points to // the heap or not is impossible to know at compile time if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { - hascalls := 0 - foreach(n, hascallspred, &hascalls) - if hascalls != 0 { + hasCalls := false + inspect(n, func(n *Node) bool { + switch n.Op { + case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: + hasCalls = true + } + return !hasCalls + }) + if hasCalls { n = detachexpr(n, init) *np = n } @@ -542,34 +548,6 @@ func detachexpr(n *Node, init *Nodes) *Node { return ind } -func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) { - if n != nil { - f(n, c) - } -} - -func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) { - for _, n := range l.Slice() { - foreachnode(n, f, c) - } -} - -func foreach(n *Node, f func(*Node, interface{}), c interface{}) { - foreachlist(n.Ninit, f, c) - foreachnode(n.Left, f, c) - foreachnode(n.Right, f, c) - foreachlist(n.List, f, c) - foreachlist(n.Nbody, f, c) - foreachlist(n.Rlist, f, c) -} - -func hascallspred(n *Node, c interface{}) { - switch n.Op { - case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: - (*c.(*int))++ - } -} - // appendinit is like addinit in subr.go // but appends rather than prepends. func appendinit(np **Node, init Nodes) { diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 3640eb7381..68067bf1b3 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -744,3 +744,23 @@ func (n *Nodes) AppendNodes(n2 *Nodes) { } n2.slice = nil } + +// inspect invokes f on each node in an AST in depth-first order. +// If f(n) returns false, inspect skips visiting n's children. +func inspect(n *Node, f func(*Node) bool) { + if n == nil || !f(n) { + return + } + inspectList(n.Ninit, f) + inspect(n.Left, f) + inspect(n.Right, f) + inspectList(n.List, f) + inspectList(n.Nbody, f) + inspectList(n.Rlist, f) +} + +func inspectList(l Nodes, f func(*Node) bool) { + for _, n := range l.Slice() { + inspect(n, f) + } +} -- 2.48.1