mirror of
https://github.com/golang/go
synced 2024-11-11 20:01:37 -07:00
[dev.regabi] cmd/compile: use reflection in ir.Dump
ir.Dump is the final (I think!) piece of the compiler that was walking nodes using Left, Right etc without knowing what they meant. This CL uses reflection to walk nodes without knowing what they mean instead. One benefit is that we can print actual meanings (field names). While we are here, I could not resist fixing a long-standing mental TODO: make the line number more clearly a line number. I've forgotten where the line number is in the dumps far too many times in the last decade. As a small example, here is a fragment of go tool compile -W test/235.go: . FOR l(28) tc(1) . . LT-init . . . AS l(28) tc(1) . . . . NAME-main..autotmp_4 l(28) x(0) class(PAUTO) esc(N) tc(1) assigned used int . . . . LEN l(28) tc(1) int . . . . . NAME-main.xs g(2) l(26) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 . . LT l(28) tc(1) hascall bool . . . NAME-main.i g(4) l(28) x(0) class(PAUTO) esc(no) tc(1) assigned used int . . . NAME-main..autotmp_4 l(28) x(0) class(PAUTO) esc(N) tc(1) assigned used int . . BLOCK l(28) . . BLOCK-list . . . ASOP-ADD l(28) tc(1) implicit(true) int . . . . NAME-main.i g(4) l(28) x(0) class(PAUTO) esc(no) tc(1) assigned used int . . . . LITERAL-1 l(28) tc(1) int . FOR-body . . VARKILL l(28) tc(1) . . . NAME-main..autotmp_4 l(28) x(0) class(PAUTO) esc(N) tc(1) assigned used int . . IF l(29) tc(1) . . . LT l(29) tc(1) bool . . . . INDEX l(29) tc(1) uint64 . . . . . NAME-main.xs g(2) l(26) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 . . . . . NAME-main.i g(4) l(28) x(0) class(PAUTO) esc(no) tc(1) assigned used int . . . . NAME-main.m g(3) l(27) x(0) class(PAUTO) esc(no) tc(1) assigned used uint64 . . IF-body . . . AS l(30) tc(1) . . . . NAME-main.m g(3) l(27) x(0) class(PAUTO) esc(no) tc(1) assigned used uint64 . . . . INDEX l(30) tc(1) uint64 . . . . . NAME-main.xs g(2) l(26) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 . . . . . NAME-main.i g(4) l(28) x(0) class(PAUTO) esc(no) tc(1) assigned used int and here it is after this CL: . FOR tc(1) # 235.go:28 . FOR-Cond . . LT-init . . . AS tc(1) # 235.go:28 . . . . NAME-main..autotmp_4 x(0) class(PAUTO) esc(N) tc(1) assigned used int # 235.go:28 . . . . LEN tc(1) int # 235.go:28 int . . . . . NAME-main.xs g(2) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 # 235.go:26 . . LT tc(1) hascall bool # 235.go:28 bool . . . NAME-main.i g(4) x(0) class(PAUTO) esc(no) tc(1) assigned used int # 235.go:28 . . . NAME-main..autotmp_4 x(0) class(PAUTO) esc(N) tc(1) assigned used int # 235.go:28 . FOR-Post . . BLOCK # 235.go:28 . . BLOCK-List . . . ASOP-ADD tc(1) implicit(true) int # 235.go:28 int . . . . NAME-main.i g(4) x(0) class(PAUTO) esc(no) tc(1) assigned used int # 235.go:28 . . . . LITERAL-1 tc(1) int # 235.go:28 . FOR-Body . . VARKILL tc(1) # 235.go:28 . . . NAME-main..autotmp_4 x(0) class(PAUTO) esc(N) tc(1) assigned used int # 235.go:28 . . IF tc(1) # 235.go:29 . . IF-Cond . . . LT tc(1) bool # 235.go:29 bool . . . . INDEX tc(1) uint64 # 235.go:29 uint64 . . . . . NAME-main.xs g(2) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 # 235.go:26 . . . . . NAME-main.i g(4) x(0) class(PAUTO) esc(no) tc(1) assigned used int # 235.go:28 . . . . NAME-main.m g(3) x(0) class(PAUTO) esc(no) tc(1) assigned used uint64 # 235.go:27 . . IF-Body . . . AS tc(1) # 235.go:30 . . . . NAME-main.m g(3) x(0) class(PAUTO) esc(no) tc(1) assigned used uint64 # 235.go:27 . . . . INDEX tc(1) uint64 # 235.go:30 uint64 . . . . . NAME-main.xs g(2) x(0) class(PPARAM) esc(no) tc(1) used SLICE-[]uint64 # 235.go:26 . . . . . NAME-main.i g(4) x(0) class(PAUTO) esc(no) tc(1) assigned used int # 235.go:28 Note in particular the clear marking of FOR-Cond, FOR-Post, FOR-Body compared to the original. The only changes to a few test files are the improved field name lines, and of course the line numbers. Passes buildall w/ toolstash -cmp. Change-Id: I5b654d9d8ee898976d4c387742ea688a082bac78 Reviewed-on: https://go-review.googlesource.com/c/go/+/275785 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
e2d278bfeb
commit
4090af83c5
@ -10,6 +10,9 @@ import (
|
||||
"go/constant"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"unicode/utf8"
|
||||
|
||||
@ -957,17 +960,6 @@ func dumpNodeHeader(w io.Writer, n Node) {
|
||||
fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
|
||||
}
|
||||
|
||||
if n.Pos().IsKnown() {
|
||||
pfx := ""
|
||||
switch n.Pos().IsStmt() {
|
||||
case src.PosNotStmt:
|
||||
pfx = "_" // "-" would be confusing
|
||||
case src.PosIsStmt:
|
||||
pfx = "+"
|
||||
}
|
||||
fmt.Fprintf(w, " l(%s%d)", pfx, n.Pos().Line())
|
||||
}
|
||||
|
||||
if n.Offset() != types.BADWIDTH {
|
||||
fmt.Fprintf(w, " x(%d)", n.Offset())
|
||||
}
|
||||
@ -1029,6 +1021,32 @@ func dumpNodeHeader(w io.Writer, n Node) {
|
||||
if n.Name() != nil && n.Name().Used() {
|
||||
fmt.Fprint(w, " used")
|
||||
}
|
||||
|
||||
if n.Op() == OCLOSURE {
|
||||
if fn := n.Func(); fn != nil && fn.Nname.Sym() != nil {
|
||||
fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
|
||||
}
|
||||
}
|
||||
|
||||
if n.Type() != nil {
|
||||
if n.Op() == OTYPE {
|
||||
fmt.Fprintf(w, " type")
|
||||
}
|
||||
fmt.Fprintf(w, " %+v", n.Type())
|
||||
}
|
||||
|
||||
if n.Pos().IsKnown() {
|
||||
pfx := ""
|
||||
switch n.Pos().IsStmt() {
|
||||
case src.PosNotStmt:
|
||||
pfx = "_" // "-" would be confusing
|
||||
case src.PosIsStmt:
|
||||
pfx = "+"
|
||||
}
|
||||
pos := base.Ctxt.PosTable.Pos(n.Pos())
|
||||
file := filepath.Base(pos.Filename())
|
||||
fmt.Fprintf(w, " # %s%s:%d", pfx, file, pos.Line())
|
||||
}
|
||||
}
|
||||
|
||||
func dumpNode(w io.Writer, n Node, depth int) {
|
||||
@ -1052,6 +1070,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
|
||||
case OLITERAL:
|
||||
fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())
|
||||
dumpNodeHeader(w, n)
|
||||
return
|
||||
|
||||
case ONAME, ONONAME, OMETHEXPR:
|
||||
if n.Sym() != nil {
|
||||
@ -1065,6 +1084,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
|
||||
fmt.Fprintf(w, "%+v-ntype", n.Op())
|
||||
dumpNode(w, n.Name().Ntype, depth+1)
|
||||
}
|
||||
return
|
||||
|
||||
case OASOP:
|
||||
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.SubOp())
|
||||
@ -1073,62 +1093,87 @@ func dumpNode(w io.Writer, n Node, depth int) {
|
||||
case OTYPE:
|
||||
fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())
|
||||
dumpNodeHeader(w, n)
|
||||
fmt.Fprintf(w, " type=%+v", n.Type())
|
||||
if n.Type() == nil && n.Name() != nil && n.Name().Ntype != nil {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-ntype", n.Op())
|
||||
dumpNode(w, n.Name().Ntype, depth+1)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Nname.Sym() != nil {
|
||||
fmt.Fprintf(w, " fnName %+v", n.Func().Nname.Sym())
|
||||
}
|
||||
if n.Sym() != nil && n.Op() != ONAME {
|
||||
fmt.Fprintf(w, " %+v", n.Sym())
|
||||
}
|
||||
case OCLOSURE:
|
||||
fmt.Fprintf(w, "%+v", n.Op())
|
||||
dumpNodeHeader(w, n)
|
||||
|
||||
if n.Type() != nil {
|
||||
fmt.Fprintf(w, " %+v", n.Type())
|
||||
}
|
||||
|
||||
if n.Left() != nil {
|
||||
dumpNode(w, n.Left(), depth+1)
|
||||
}
|
||||
if n.Right() != nil {
|
||||
dumpNode(w, n.Right(), depth+1)
|
||||
}
|
||||
if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Body().Len() != 0 {
|
||||
case ODCLFUNC:
|
||||
// Func has many fields we don't want to print.
|
||||
// Bypass reflection and just print what we want.
|
||||
fmt.Fprintf(w, "%+v", n.Op())
|
||||
dumpNodeHeader(w, n)
|
||||
fn := n.Func()
|
||||
if len(fn.Dcl) > 0 {
|
||||
indent(w, depth)
|
||||
// The function associated with a closure
|
||||
fmt.Fprintf(w, "%+v-clofunc", n.Op())
|
||||
dumpNode(w, n.Func(), depth+1)
|
||||
}
|
||||
if n.Op() == ODCLFUNC && n.Func() != nil && n.Func().Dcl != nil && len(n.Func().Dcl) != 0 {
|
||||
indent(w, depth)
|
||||
// The dcls for a func or closure
|
||||
fmt.Fprintf(w, "%+v-dcl", n.Op())
|
||||
fmt.Fprintf(w, "%+v-Dcl", n.Op())
|
||||
for _, dcl := range n.Func().Dcl {
|
||||
dumpNode(w, dcl, depth+1)
|
||||
}
|
||||
}
|
||||
if n.List().Len() != 0 {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-list", n.Op())
|
||||
dumpNodes(w, n.List(), depth+1)
|
||||
}
|
||||
|
||||
if n.Rlist().Len() != 0 {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-rlist", n.Op())
|
||||
dumpNodes(w, n.Rlist(), depth+1)
|
||||
}
|
||||
|
||||
if n.Body().Len() != 0 {
|
||||
if fn.Body().Len() > 0 {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-body", n.Op())
|
||||
dumpNodes(w, n.Body(), depth+1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if n.Sym() != nil {
|
||||
fmt.Fprintf(w, " %+v", n.Sym())
|
||||
}
|
||||
if n.Type() != nil {
|
||||
fmt.Fprintf(w, " %+v", n.Type())
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(n).Elem()
|
||||
t := reflect.TypeOf(n).Elem()
|
||||
nf := t.NumField()
|
||||
for i := 0; i < nf; i++ {
|
||||
tf := t.Field(i)
|
||||
vf := v.Field(i)
|
||||
if tf.PkgPath != "" {
|
||||
// skip unexported field - Interface will fail
|
||||
continue
|
||||
}
|
||||
switch tf.Type.Kind() {
|
||||
case reflect.Interface, reflect.Ptr, reflect.Slice:
|
||||
if vf.IsNil() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
name := strings.TrimSuffix(tf.Name, "_")
|
||||
// Do not bother with field name header lines for the
|
||||
// most common positional arguments: unary, binary expr,
|
||||
// index expr, send stmt, go and defer call expression.
|
||||
switch name {
|
||||
case "X", "Y", "Index", "Chan", "Value", "Call":
|
||||
name = ""
|
||||
}
|
||||
switch val := vf.Interface().(type) {
|
||||
case Node:
|
||||
if name != "" {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
|
||||
}
|
||||
dumpNode(w, val, depth+1)
|
||||
case Nodes:
|
||||
if val.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
if name != "" {
|
||||
indent(w, depth)
|
||||
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
|
||||
}
|
||||
dumpNodes(w, val, depth+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpNodes(w io.Writer, list Nodes, depth int) {
|
||||
|
Loading…
Reference in New Issue
Block a user