1
2
3
4
5
6
7
8
9 package ir
10
11 import (
12 "fmt"
13 "io"
14 "os"
15 "reflect"
16 "regexp"
17
18 "cmd/compile/internal/base"
19 "cmd/compile/internal/types"
20 "cmd/internal/src"
21 )
22
23
24 func DumpAny(root interface{}, filter string, depth int) {
25 FDumpAny(os.Stderr, root, filter, depth)
26 }
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 func FDumpAny(w io.Writer, root interface{}, filter string, depth int) {
46 if root == nil {
47 fmt.Fprintln(w, "nil")
48 return
49 }
50
51 if filter == "" {
52 filter = ".*"
53 }
54
55 p := dumper{
56 output: w,
57 fieldrx: regexp.MustCompile(filter),
58 ptrmap: make(map[uintptr]int),
59 last: '\n',
60 }
61
62 p.dump(reflect.ValueOf(root), depth)
63 p.printf("\n")
64 }
65
66 type dumper struct {
67 output io.Writer
68 fieldrx *regexp.Regexp
69 ptrmap map[uintptr]int
70 lastadr string
71
72
73 indent int
74 last byte
75 line int
76 }
77
78 var indentBytes = []byte(". ")
79
80 func (p *dumper) Write(data []byte) (n int, err error) {
81 var m int
82 for i, b := range data {
83
84 if b == '\n' {
85 m, err = p.output.Write(data[n : i+1])
86 n += m
87 if err != nil {
88 return
89 }
90 } else if p.last == '\n' {
91 p.line++
92 _, err = fmt.Fprintf(p.output, "%6d ", p.line)
93 if err != nil {
94 return
95 }
96 for j := p.indent; j > 0; j-- {
97 _, err = p.output.Write(indentBytes)
98 if err != nil {
99 return
100 }
101 }
102 }
103 p.last = b
104 }
105 if len(data) > n {
106 m, err = p.output.Write(data[n:])
107 n += m
108 }
109 return
110 }
111
112
113 func (p *dumper) printf(format string, args ...interface{}) {
114 if _, err := fmt.Fprintf(p, format, args...); err != nil {
115 panic(err)
116 }
117 }
118
119
120
121
122
123 func (p *dumper) addr(x reflect.Value) string {
124 if !x.CanAddr() {
125 return "?"
126 }
127 adr := fmt.Sprintf("%p", x.Addr().Interface())
128 s := adr
129 if i := commonPrefixLen(p.lastadr, adr); i > 0 {
130 s = "0x…" + adr[i:]
131 }
132 p.lastadr = adr
133 return s
134 }
135
136
137 func (p *dumper) dump(x reflect.Value, depth int) {
138 if depth == 0 {
139 p.printf("…")
140 return
141 }
142
143 if pos, ok := x.Interface().(src.XPos); ok {
144 p.printf("%s", base.FmtPos(pos))
145 return
146 }
147
148 switch x.Kind() {
149 case reflect.String:
150 p.printf("%q", x.Interface())
151
152 case reflect.Interface:
153 if x.IsNil() {
154 p.printf("nil")
155 return
156 }
157 p.dump(x.Elem(), depth-1)
158
159 case reflect.Ptr:
160 if x.IsNil() {
161 p.printf("nil")
162 return
163 }
164
165 p.printf("*")
166 ptr := x.Pointer()
167 if line, exists := p.ptrmap[ptr]; exists {
168 p.printf("(@%d)", line)
169 return
170 }
171 p.ptrmap[ptr] = p.line
172 p.dump(x.Elem(), depth)
173
174 case reflect.Slice:
175 if x.IsNil() {
176 p.printf("nil")
177 return
178 }
179 p.printf("%s (%d entries) {", x.Type(), x.Len())
180 if x.Len() > 0 {
181 p.indent++
182 p.printf("\n")
183 for i, n := 0, x.Len(); i < n; i++ {
184 p.printf("%d: ", i)
185 p.dump(x.Index(i), depth-1)
186 p.printf("\n")
187 }
188 p.indent--
189 }
190 p.printf("}")
191
192 case reflect.Struct:
193 typ := x.Type()
194
195 isNode := false
196 if n, ok := x.Interface().(Node); ok {
197 isNode = true
198 p.printf("%s %s {", n.Op().String(), p.addr(x))
199 } else {
200 p.printf("%s {", typ)
201 }
202 p.indent++
203
204 first := true
205 omitted := false
206 for i, n := 0, typ.NumField(); i < n; i++ {
207
208
209 if name := typ.Field(i).Name; types.IsExported(name) {
210 if !p.fieldrx.MatchString(name) {
211 omitted = true
212 continue
213 }
214
215
216 if isNode && name == "Op" {
217 omitted = true
218 continue
219 }
220 x := x.Field(i)
221 if isZeroVal(x) {
222 omitted = true
223 continue
224 }
225 if n, ok := x.Interface().(Nodes); ok && len(n) == 0 {
226 omitted = true
227 continue
228 }
229
230 if first {
231 p.printf("\n")
232 first = false
233 }
234 p.printf("%s: ", name)
235 p.dump(x, depth-1)
236 p.printf("\n")
237 }
238 }
239 if omitted {
240 p.printf("…\n")
241 }
242
243 p.indent--
244 p.printf("}")
245
246 default:
247 p.printf("%v", x.Interface())
248 }
249 }
250
251 func isZeroVal(x reflect.Value) bool {
252 switch x.Kind() {
253 case reflect.Bool:
254 return !x.Bool()
255 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
256 return x.Int() == 0
257 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
258 return x.Uint() == 0
259 case reflect.String:
260 return x.String() == ""
261 case reflect.Interface, reflect.Ptr, reflect.Slice:
262 return x.IsNil()
263 }
264 return false
265 }
266
267 func commonPrefixLen(a, b string) (i int) {
268 for i < len(a) && i < len(b) && a[i] == b[i] {
269 i++
270 }
271 return
272 }
273
View as plain text