1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package ir 6 7// This file implements the String() methods for all Value and 8// Instruction types. 9 10import ( 11 "bytes" 12 "fmt" 13 "go/types" 14 "io" 15 "reflect" 16 "sort" 17 18 "golang.org/x/tools/go/types/typeutil" 19) 20 21// relName returns the name of v relative to i. 22// In most cases, this is identical to v.Name(), but references to 23// Functions (including methods) and Globals use RelString and 24// all types are displayed with relType, so that only cross-package 25// references are package-qualified. 26// 27func relName(v Value, i Instruction) string { 28 if v == nil { 29 return "<nil>" 30 } 31 var from *types.Package 32 if i != nil { 33 from = i.Parent().pkg() 34 } 35 switch v := v.(type) { 36 case Member: // *Function or *Global 37 return v.RelString(from) 38 } 39 return v.Name() 40} 41 42func relType(t types.Type, from *types.Package) string { 43 return types.TypeString(t, types.RelativeTo(from)) 44} 45 46func relString(m Member, from *types.Package) string { 47 // NB: not all globals have an Object (e.g. init$guard), 48 // so use Package().Object not Object.Package(). 49 if pkg := m.Package().Pkg; pkg != nil && pkg != from { 50 return fmt.Sprintf("%s.%s", pkg.Path(), m.Name()) 51 } 52 return m.Name() 53} 54 55// Value.String() 56// 57// This method is provided only for debugging. 58// It never appears in disassembly, which uses Value.Name(). 59 60func (v *Parameter) String() string { 61 from := v.Parent().pkg() 62 return fmt.Sprintf("Parameter <%s> {%s}", relType(v.Type(), from), v.name) 63} 64 65func (v *FreeVar) String() string { 66 from := v.Parent().pkg() 67 return fmt.Sprintf("FreeVar <%s> %s", relType(v.Type(), from), v.Name()) 68} 69 70func (v *Builtin) String() string { 71 return fmt.Sprintf("Builtin %s", v.Name()) 72} 73 74// Instruction.String() 75 76func (v *Alloc) String() string { 77 from := v.Parent().pkg() 78 storage := "Stack" 79 if v.Heap { 80 storage = "Heap" 81 } 82 return fmt.Sprintf("%sAlloc <%s>", storage, relType(v.Type(), from)) 83} 84 85func (v *Sigma) String() string { 86 from := v.Parent().pkg() 87 s := fmt.Sprintf("Sigma <%s> [b%d] %s", relType(v.Type(), from), v.From.Index, v.X.Name()) 88 return s 89} 90 91func (v *Phi) String() string { 92 var b bytes.Buffer 93 fmt.Fprintf(&b, "Phi <%s>", v.Type()) 94 for i, edge := range v.Edges { 95 b.WriteString(" ") 96 // Be robust against malformed CFG. 97 if v.block == nil { 98 b.WriteString("??") 99 continue 100 } 101 block := -1 102 if i < len(v.block.Preds) { 103 block = v.block.Preds[i].Index 104 } 105 fmt.Fprintf(&b, "%d:", block) 106 edgeVal := "<nil>" // be robust 107 if edge != nil { 108 edgeVal = relName(edge, v) 109 } 110 b.WriteString(edgeVal) 111 } 112 return b.String() 113} 114 115func printCall(v *CallCommon, prefix string, instr Instruction) string { 116 var b bytes.Buffer 117 if !v.IsInvoke() { 118 if value, ok := instr.(Value); ok { 119 fmt.Fprintf(&b, "%s <%s> %s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr)) 120 } else { 121 fmt.Fprintf(&b, "%s %s", prefix, relName(v.Value, instr)) 122 } 123 } else { 124 if value, ok := instr.(Value); ok { 125 fmt.Fprintf(&b, "%sInvoke <%s> %s.%s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr), v.Method.Name()) 126 } else { 127 fmt.Fprintf(&b, "%sInvoke %s.%s", prefix, relName(v.Value, instr), v.Method.Name()) 128 } 129 } 130 for _, arg := range v.Args { 131 b.WriteString(" ") 132 b.WriteString(relName(arg, instr)) 133 } 134 return b.String() 135} 136 137func (c *CallCommon) String() string { 138 return printCall(c, "", nil) 139} 140 141func (v *Call) String() string { 142 return printCall(&v.Call, "Call", v) 143} 144 145func (v *BinOp) String() string { 146 return fmt.Sprintf("BinOp <%s> {%s} %s %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v), relName(v.Y, v)) 147} 148 149func (v *UnOp) String() string { 150 return fmt.Sprintf("UnOp <%s> {%s} %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v)) 151} 152 153func (v *Load) String() string { 154 return fmt.Sprintf("Load <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v)) 155} 156 157func printConv(prefix string, v, x Value) string { 158 from := v.Parent().pkg() 159 return fmt.Sprintf("%s <%s> %s", 160 prefix, 161 relType(v.Type(), from), 162 relName(x, v.(Instruction))) 163} 164 165func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) } 166func (v *Convert) String() string { return printConv("Convert", v, v.X) } 167func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) } 168func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) } 169 170func (v *MakeClosure) String() string { 171 from := v.Parent().pkg() 172 var b bytes.Buffer 173 fmt.Fprintf(&b, "MakeClosure <%s> %s", relType(v.Type(), from), relName(v.Fn, v)) 174 if v.Bindings != nil { 175 for _, c := range v.Bindings { 176 b.WriteString(" ") 177 b.WriteString(relName(c, v)) 178 } 179 } 180 return b.String() 181} 182 183func (v *MakeSlice) String() string { 184 from := v.Parent().pkg() 185 return fmt.Sprintf("MakeSlice <%s> %s %s", 186 relType(v.Type(), from), 187 relName(v.Len, v), 188 relName(v.Cap, v)) 189} 190 191func (v *Slice) String() string { 192 from := v.Parent().pkg() 193 return fmt.Sprintf("Slice <%s> %s %s %s %s", 194 relType(v.Type(), from), relName(v.X, v), relName(v.Low, v), relName(v.High, v), relName(v.Max, v)) 195} 196 197func (v *MakeMap) String() string { 198 res := "" 199 if v.Reserve != nil { 200 res = relName(v.Reserve, v) 201 } 202 from := v.Parent().pkg() 203 return fmt.Sprintf("MakeMap <%s> %s", relType(v.Type(), from), res) 204} 205 206func (v *MakeChan) String() string { 207 from := v.Parent().pkg() 208 return fmt.Sprintf("MakeChan <%s> %s", relType(v.Type(), from), relName(v.Size, v)) 209} 210 211func (v *FieldAddr) String() string { 212 from := v.Parent().pkg() 213 st := deref(v.X.Type()).Underlying().(*types.Struct) 214 // Be robust against a bad index. 215 name := "?" 216 if 0 <= v.Field && v.Field < st.NumFields() { 217 name = st.Field(v.Field).Name() 218 } 219 return fmt.Sprintf("FieldAddr <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v)) 220} 221 222func (v *Field) String() string { 223 st := v.X.Type().Underlying().(*types.Struct) 224 // Be robust against a bad index. 225 name := "?" 226 if 0 <= v.Field && v.Field < st.NumFields() { 227 name = st.Field(v.Field).Name() 228 } 229 from := v.Parent().pkg() 230 return fmt.Sprintf("Field <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v)) 231} 232 233func (v *IndexAddr) String() string { 234 from := v.Parent().pkg() 235 return fmt.Sprintf("IndexAddr <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) 236} 237 238func (v *Index) String() string { 239 from := v.Parent().pkg() 240 return fmt.Sprintf("Index <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) 241} 242 243func (v *MapLookup) String() string { 244 from := v.Parent().pkg() 245 return fmt.Sprintf("MapLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) 246} 247 248func (v *StringLookup) String() string { 249 from := v.Parent().pkg() 250 return fmt.Sprintf("StringLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) 251} 252 253func (v *Range) String() string { 254 from := v.Parent().pkg() 255 return fmt.Sprintf("Range <%s> %s", relType(v.Type(), from), relName(v.X, v)) 256} 257 258func (v *Next) String() string { 259 from := v.Parent().pkg() 260 return fmt.Sprintf("Next <%s> %s", relType(v.Type(), from), relName(v.Iter, v)) 261} 262 263func (v *TypeAssert) String() string { 264 from := v.Parent().pkg() 265 return fmt.Sprintf("TypeAssert <%s> %s", relType(v.Type(), from), relName(v.X, v)) 266} 267 268func (v *Extract) String() string { 269 from := v.Parent().pkg() 270 name := v.Tuple.Type().(*types.Tuple).At(v.Index).Name() 271 return fmt.Sprintf("Extract <%s> [%d] (%s) %s", relType(v.Type(), from), v.Index, name, relName(v.Tuple, v)) 272} 273 274func (s *Jump) String() string { 275 // Be robust against malformed CFG. 276 block := -1 277 if s.block != nil && len(s.block.Succs) == 1 { 278 block = s.block.Succs[0].Index 279 } 280 str := fmt.Sprintf("Jump → b%d", block) 281 if s.Comment != "" { 282 str = fmt.Sprintf("%s # %s", str, s.Comment) 283 } 284 return str 285} 286 287func (s *Unreachable) String() string { 288 // Be robust against malformed CFG. 289 block := -1 290 if s.block != nil && len(s.block.Succs) == 1 { 291 block = s.block.Succs[0].Index 292 } 293 return fmt.Sprintf("Unreachable → b%d", block) 294} 295 296func (s *If) String() string { 297 // Be robust against malformed CFG. 298 tblock, fblock := -1, -1 299 if s.block != nil && len(s.block.Succs) == 2 { 300 tblock = s.block.Succs[0].Index 301 fblock = s.block.Succs[1].Index 302 } 303 return fmt.Sprintf("If %s → b%d b%d", relName(s.Cond, s), tblock, fblock) 304} 305 306func (s *ConstantSwitch) String() string { 307 var b bytes.Buffer 308 fmt.Fprintf(&b, "ConstantSwitch %s", relName(s.Tag, s)) 309 for _, cond := range s.Conds { 310 fmt.Fprintf(&b, " %s", relName(cond, s)) 311 } 312 fmt.Fprint(&b, " →") 313 for _, succ := range s.block.Succs { 314 fmt.Fprintf(&b, " b%d", succ.Index) 315 } 316 return b.String() 317} 318 319func (s *TypeSwitch) String() string { 320 from := s.Parent().pkg() 321 var b bytes.Buffer 322 fmt.Fprintf(&b, "TypeSwitch <%s> %s", relType(s.typ, from), relName(s.Tag, s)) 323 for _, cond := range s.Conds { 324 fmt.Fprintf(&b, " %q", relType(cond, s.block.parent.pkg())) 325 } 326 return b.String() 327} 328 329func (s *Go) String() string { 330 return printCall(&s.Call, "Go", s) 331} 332 333func (s *Panic) String() string { 334 // Be robust against malformed CFG. 335 block := -1 336 if s.block != nil && len(s.block.Succs) == 1 { 337 block = s.block.Succs[0].Index 338 } 339 return fmt.Sprintf("Panic %s → b%d", relName(s.X, s), block) 340} 341 342func (s *Return) String() string { 343 var b bytes.Buffer 344 b.WriteString("Return") 345 for _, r := range s.Results { 346 b.WriteString(" ") 347 b.WriteString(relName(r, s)) 348 } 349 return b.String() 350} 351 352func (*RunDefers) String() string { 353 return "RunDefers" 354} 355 356func (s *Send) String() string { 357 return fmt.Sprintf("Send %s %s", relName(s.Chan, s), relName(s.X, s)) 358} 359 360func (recv *Recv) String() string { 361 from := recv.Parent().pkg() 362 return fmt.Sprintf("Recv <%s> %s", relType(recv.Type(), from), relName(recv.Chan, recv)) 363} 364 365func (s *Defer) String() string { 366 return printCall(&s.Call, "Defer", s) 367} 368 369func (s *Select) String() string { 370 var b bytes.Buffer 371 for i, st := range s.States { 372 if i > 0 { 373 b.WriteString(", ") 374 } 375 if st.Dir == types.RecvOnly { 376 b.WriteString("<-") 377 b.WriteString(relName(st.Chan, s)) 378 } else { 379 b.WriteString(relName(st.Chan, s)) 380 b.WriteString("<-") 381 b.WriteString(relName(st.Send, s)) 382 } 383 } 384 non := "" 385 if !s.Blocking { 386 non = "Non" 387 } 388 from := s.Parent().pkg() 389 return fmt.Sprintf("Select%sBlocking <%s> [%s]", non, relType(s.Type(), from), b.String()) 390} 391 392func (s *Store) String() string { 393 return fmt.Sprintf("Store {%s} %s %s", 394 s.Val.Type(), relName(s.Addr, s), relName(s.Val, s)) 395} 396 397func (s *BlankStore) String() string { 398 return fmt.Sprintf("BlankStore %s", relName(s.Val, s)) 399} 400 401func (s *MapUpdate) String() string { 402 return fmt.Sprintf("MapUpdate %s %s %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) 403} 404 405func (s *DebugRef) String() string { 406 p := s.Parent().Prog.Fset.Position(s.Pos()) 407 var descr interface{} 408 if s.object != nil { 409 descr = s.object // e.g. "var x int" 410 } else { 411 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr" 412 } 413 var addr string 414 if s.IsAddr { 415 addr = "address of " 416 } 417 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name()) 418} 419 420func (p *Package) String() string { 421 return "package " + p.Pkg.Path() 422} 423 424var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer 425 426func (p *Package) WriteTo(w io.Writer) (int64, error) { 427 var buf bytes.Buffer 428 WritePackage(&buf, p) 429 n, err := w.Write(buf.Bytes()) 430 return int64(n), err 431} 432 433// WritePackage writes to buf a human-readable summary of p. 434func WritePackage(buf *bytes.Buffer, p *Package) { 435 fmt.Fprintf(buf, "%s:\n", p) 436 437 var names []string 438 maxname := 0 439 for name := range p.Members { 440 if l := len(name); l > maxname { 441 maxname = l 442 } 443 names = append(names, name) 444 } 445 446 from := p.Pkg 447 sort.Strings(names) 448 for _, name := range names { 449 switch mem := p.Members[name].(type) { 450 case *NamedConst: 451 fmt.Fprintf(buf, " const %-*s %s = %s\n", 452 maxname, name, mem.Name(), mem.Value.RelString(from)) 453 454 case *Function: 455 fmt.Fprintf(buf, " func %-*s %s\n", 456 maxname, name, relType(mem.Type(), from)) 457 458 case *Type: 459 fmt.Fprintf(buf, " type %-*s %s\n", 460 maxname, name, relType(mem.Type().Underlying(), from)) 461 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) { 462 fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from))) 463 } 464 465 case *Global: 466 fmt.Fprintf(buf, " var %-*s %s\n", 467 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) 468 } 469 } 470 471 fmt.Fprintf(buf, "\n") 472} 473