golang.org/x/tools@v0.21.0/go/ssa/interp/interp.go (about) 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 5 // Package ssa/interp defines an interpreter for the SSA 6 // representation of Go programs. 7 // 8 // This interpreter is provided as an adjunct for testing the SSA 9 // construction algorithm. Its purpose is to provide a minimal 10 // metacircular implementation of the dynamic semantics of each SSA 11 // instruction. It is not, and will never be, a production-quality Go 12 // interpreter. 13 // 14 // The following is a partial list of Go features that are currently 15 // unsupported or incomplete in the interpreter. 16 // 17 // * Unsafe operations, including all uses of unsafe.Pointer, are 18 // impossible to support given the "boxed" value representation we 19 // have chosen. 20 // 21 // * The reflect package is only partially implemented. 22 // 23 // * The "testing" package is no longer supported because it 24 // depends on low-level details that change too often. 25 // 26 // * "sync/atomic" operations are not atomic due to the "boxed" value 27 // representation: it is not possible to read, modify and write an 28 // interface value atomically. As a consequence, Mutexes are currently 29 // broken. 30 // 31 // * recover is only partially implemented. Also, the interpreter 32 // makes no attempt to distinguish target panics from interpreter 33 // crashes. 34 // 35 // * the sizes of the int, uint and uintptr types in the target 36 // program are assumed to be the same as those of the interpreter 37 // itself. 38 // 39 // * all values occupy space, even those of types defined by the spec 40 // to have zero size, e.g. struct{}. This can cause asymptotic 41 // performance degradation. 42 // 43 // * os.Exit is implemented using panic, causing deferred functions to 44 // run. 45 package interp // import "golang.org/x/tools/go/ssa/interp" 46 47 import ( 48 "fmt" 49 "go/token" 50 "go/types" 51 "os" 52 "reflect" 53 "runtime" 54 "sync/atomic" 55 56 "golang.org/x/tools/go/ssa" 57 "golang.org/x/tools/internal/typeparams" 58 ) 59 60 type continuation int 61 62 const ( 63 kNext continuation = iota 64 kReturn 65 kJump 66 ) 67 68 // Mode is a bitmask of options affecting the interpreter. 69 type Mode uint 70 71 const ( 72 DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead. 73 EnableTracing // Print a trace of all instructions as they are interpreted. 74 ) 75 76 type methodSet map[string]*ssa.Function 77 78 // State shared between all interpreted goroutines. 79 type interpreter struct { 80 osArgs []value // the value of os.Args 81 prog *ssa.Program // the SSA program 82 globals map[*ssa.Global]*value // addresses of global variables (immutable) 83 mode Mode // interpreter options 84 reflectPackage *ssa.Package // the fake reflect package 85 errorMethods methodSet // the method set of reflect.error, which implements the error interface. 86 rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface. 87 runtimeErrorString types.Type // the runtime.errorString type 88 sizes types.Sizes // the effective type-sizing function 89 goroutines int32 // atomically updated 90 } 91 92 type deferred struct { 93 fn value 94 args []value 95 instr *ssa.Defer 96 tail *deferred 97 } 98 99 type frame struct { 100 i *interpreter 101 caller *frame 102 fn *ssa.Function 103 block, prevBlock *ssa.BasicBlock 104 env map[ssa.Value]value // dynamic values of SSA variables 105 locals []value 106 defers *deferred 107 result value 108 panicking bool 109 panic interface{} 110 } 111 112 func (fr *frame) get(key ssa.Value) value { 113 switch key := key.(type) { 114 case nil: 115 // Hack; simplifies handling of optional attributes 116 // such as ssa.Slice.{Low,High}. 117 return nil 118 case *ssa.Function, *ssa.Builtin: 119 return key 120 case *ssa.Const: 121 return constValue(key) 122 case *ssa.Global: 123 if r, ok := fr.i.globals[key]; ok { 124 return r 125 } 126 } 127 if r, ok := fr.env[key]; ok { 128 return r 129 } 130 panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name())) 131 } 132 133 // runDefer runs a deferred call d. 134 // It always returns normally, but may set or clear fr.panic. 135 func (fr *frame) runDefer(d *deferred) { 136 if fr.i.mode&EnableTracing != 0 { 137 fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n", 138 fr.i.prog.Fset.Position(d.instr.Pos())) 139 } 140 var ok bool 141 defer func() { 142 if !ok { 143 // Deferred call created a new state of panic. 144 fr.panicking = true 145 fr.panic = recover() 146 } 147 }() 148 call(fr.i, fr, d.instr.Pos(), d.fn, d.args) 149 ok = true 150 } 151 152 // runDefers executes fr's deferred function calls in LIFO order. 153 // 154 // On entry, fr.panicking indicates a state of panic; if 155 // true, fr.panic contains the panic value. 156 // 157 // On completion, if a deferred call started a panic, or if no 158 // deferred call recovered from a previous state of panic, then 159 // runDefers itself panics after the last deferred call has run. 160 // 161 // If there was no initial state of panic, or it was recovered from, 162 // runDefers returns normally. 163 func (fr *frame) runDefers() { 164 for d := fr.defers; d != nil; d = d.tail { 165 fr.runDefer(d) 166 } 167 fr.defers = nil 168 if fr.panicking { 169 panic(fr.panic) // new panic, or still panicking 170 } 171 } 172 173 // lookupMethod returns the method set for type typ, which may be one 174 // of the interpreter's fake types. 175 func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function { 176 switch typ { 177 case rtypeType: 178 return i.rtypeMethods[meth.Id()] 179 case errorType: 180 return i.errorMethods[meth.Id()] 181 } 182 return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name()) 183 } 184 185 // visitInstr interprets a single ssa.Instruction within the activation 186 // record frame. It returns a continuation value indicating where to 187 // read the next instruction from. 188 func visitInstr(fr *frame, instr ssa.Instruction) continuation { 189 switch instr := instr.(type) { 190 case *ssa.DebugRef: 191 // no-op 192 193 case *ssa.UnOp: 194 fr.env[instr] = unop(instr, fr.get(instr.X)) 195 196 case *ssa.BinOp: 197 fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y)) 198 199 case *ssa.Call: 200 fn, args := prepareCall(fr, &instr.Call) 201 fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args) 202 203 case *ssa.ChangeInterface: 204 fr.env[instr] = fr.get(instr.X) 205 206 case *ssa.ChangeType: 207 fr.env[instr] = fr.get(instr.X) // (can't fail) 208 209 case *ssa.Convert: 210 fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X)) 211 212 case *ssa.SliceToArrayPointer: 213 fr.env[instr] = sliceToArrayPointer(instr.Type(), instr.X.Type(), fr.get(instr.X)) 214 215 case *ssa.MakeInterface: 216 fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)} 217 218 case *ssa.Extract: 219 fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index] 220 221 case *ssa.Slice: 222 fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max)) 223 224 case *ssa.Return: 225 switch len(instr.Results) { 226 case 0: 227 case 1: 228 fr.result = fr.get(instr.Results[0]) 229 default: 230 var res []value 231 for _, r := range instr.Results { 232 res = append(res, fr.get(r)) 233 } 234 fr.result = tuple(res) 235 } 236 fr.block = nil 237 return kReturn 238 239 case *ssa.RunDefers: 240 fr.runDefers() 241 242 case *ssa.Panic: 243 panic(targetPanic{fr.get(instr.X)}) 244 245 case *ssa.Send: 246 fr.get(instr.Chan).(chan value) <- fr.get(instr.X) 247 248 case *ssa.Store: 249 store(typeparams.MustDeref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val)) 250 251 case *ssa.If: 252 succ := 1 253 if fr.get(instr.Cond).(bool) { 254 succ = 0 255 } 256 fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ] 257 return kJump 258 259 case *ssa.Jump: 260 fr.prevBlock, fr.block = fr.block, fr.block.Succs[0] 261 return kJump 262 263 case *ssa.Defer: 264 fn, args := prepareCall(fr, &instr.Call) 265 fr.defers = &deferred{ 266 fn: fn, 267 args: args, 268 instr: instr, 269 tail: fr.defers, 270 } 271 272 case *ssa.Go: 273 fn, args := prepareCall(fr, &instr.Call) 274 atomic.AddInt32(&fr.i.goroutines, 1) 275 go func() { 276 call(fr.i, nil, instr.Pos(), fn, args) 277 atomic.AddInt32(&fr.i.goroutines, -1) 278 }() 279 280 case *ssa.MakeChan: 281 fr.env[instr] = make(chan value, asInt64(fr.get(instr.Size))) 282 283 case *ssa.Alloc: 284 var addr *value 285 if instr.Heap { 286 // new 287 addr = new(value) 288 fr.env[instr] = addr 289 } else { 290 // local 291 addr = fr.env[instr].(*value) 292 } 293 *addr = zero(typeparams.MustDeref(instr.Type())) 294 295 case *ssa.MakeSlice: 296 slice := make([]value, asInt64(fr.get(instr.Cap))) 297 tElt := instr.Type().Underlying().(*types.Slice).Elem() 298 for i := range slice { 299 slice[i] = zero(tElt) 300 } 301 fr.env[instr] = slice[:asInt64(fr.get(instr.Len))] 302 303 case *ssa.MakeMap: 304 var reserve int64 305 if instr.Reserve != nil { 306 reserve = asInt64(fr.get(instr.Reserve)) 307 } 308 if !fitsInt(reserve, fr.i.sizes) { 309 panic(fmt.Sprintf("ssa.MakeMap.Reserve value %d does not fit in int", reserve)) 310 } 311 fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve) 312 313 case *ssa.Range: 314 fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type()) 315 316 case *ssa.Next: 317 fr.env[instr] = fr.get(instr.Iter).(iter).next() 318 319 case *ssa.FieldAddr: 320 fr.env[instr] = &(*fr.get(instr.X).(*value)).(structure)[instr.Field] 321 322 case *ssa.Field: 323 fr.env[instr] = fr.get(instr.X).(structure)[instr.Field] 324 325 case *ssa.IndexAddr: 326 x := fr.get(instr.X) 327 idx := fr.get(instr.Index) 328 switch x := x.(type) { 329 case []value: 330 fr.env[instr] = &x[asInt64(idx)] 331 case *value: // *array 332 fr.env[instr] = &(*x).(array)[asInt64(idx)] 333 default: 334 panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x)) 335 } 336 337 case *ssa.Index: 338 x := fr.get(instr.X) 339 idx := fr.get(instr.Index) 340 341 switch x := x.(type) { 342 case array: 343 fr.env[instr] = x[asInt64(idx)] 344 case string: 345 fr.env[instr] = x[asInt64(idx)] 346 default: 347 panic(fmt.Sprintf("unexpected x type in Index: %T", x)) 348 } 349 350 case *ssa.Lookup: 351 fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index)) 352 353 case *ssa.MapUpdate: 354 m := fr.get(instr.Map) 355 key := fr.get(instr.Key) 356 v := fr.get(instr.Value) 357 switch m := m.(type) { 358 case map[value]value: 359 m[key] = v 360 case *hashmap: 361 m.insert(key.(hashable), v) 362 default: 363 panic(fmt.Sprintf("illegal map type: %T", m)) 364 } 365 366 case *ssa.TypeAssert: 367 fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface)) 368 369 case *ssa.MakeClosure: 370 var bindings []value 371 for _, binding := range instr.Bindings { 372 bindings = append(bindings, fr.get(binding)) 373 } 374 fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings} 375 376 case *ssa.Phi: 377 for i, pred := range instr.Block().Preds { 378 if fr.prevBlock == pred { 379 fr.env[instr] = fr.get(instr.Edges[i]) 380 break 381 } 382 } 383 384 case *ssa.Select: 385 var cases []reflect.SelectCase 386 if !instr.Blocking { 387 cases = append(cases, reflect.SelectCase{ 388 Dir: reflect.SelectDefault, 389 }) 390 } 391 for _, state := range instr.States { 392 var dir reflect.SelectDir 393 if state.Dir == types.RecvOnly { 394 dir = reflect.SelectRecv 395 } else { 396 dir = reflect.SelectSend 397 } 398 var send reflect.Value 399 if state.Send != nil { 400 send = reflect.ValueOf(fr.get(state.Send)) 401 } 402 cases = append(cases, reflect.SelectCase{ 403 Dir: dir, 404 Chan: reflect.ValueOf(fr.get(state.Chan)), 405 Send: send, 406 }) 407 } 408 chosen, recv, recvOk := reflect.Select(cases) 409 if !instr.Blocking { 410 chosen-- // default case should have index -1. 411 } 412 r := tuple{chosen, recvOk} 413 for i, st := range instr.States { 414 if st.Dir == types.RecvOnly { 415 var v value 416 if i == chosen && recvOk { 417 // No need to copy since send makes an unaliased copy. 418 v = recv.Interface().(value) 419 } else { 420 v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem()) 421 } 422 r = append(r, v) 423 } 424 } 425 fr.env[instr] = r 426 427 default: 428 panic(fmt.Sprintf("unexpected instruction: %T", instr)) 429 } 430 431 // if val, ok := instr.(ssa.Value); ok { 432 // fmt.Println(toString(fr.env[val])) // debugging 433 // } 434 435 return kNext 436 } 437 438 // prepareCall determines the function value and argument values for a 439 // function call in a Call, Go or Defer instruction, performing 440 // interface method lookup if needed. 441 func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) { 442 v := fr.get(call.Value) 443 if call.Method == nil { 444 // Function call. 445 fn = v 446 } else { 447 // Interface method invocation. 448 recv := v.(iface) 449 if recv.t == nil { 450 panic("method invoked on nil interface") 451 } 452 if f := lookupMethod(fr.i, recv.t, call.Method); f == nil { 453 // Unreachable in well-typed programs. 454 panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method)) 455 } else { 456 fn = f 457 } 458 args = append(args, recv.v) 459 } 460 for _, arg := range call.Args { 461 args = append(args, fr.get(arg)) 462 } 463 return 464 } 465 466 // call interprets a call to a function (function, builtin or closure) 467 // fn with arguments args, returning its result. 468 // callpos is the position of the callsite. 469 func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value { 470 switch fn := fn.(type) { 471 case *ssa.Function: 472 if fn == nil { 473 panic("call of nil function") // nil of func type 474 } 475 return callSSA(i, caller, callpos, fn, args, nil) 476 case *closure: 477 return callSSA(i, caller, callpos, fn.Fn, args, fn.Env) 478 case *ssa.Builtin: 479 return callBuiltin(caller, callpos, fn, args) 480 } 481 panic(fmt.Sprintf("cannot call %T", fn)) 482 } 483 484 func loc(fset *token.FileSet, pos token.Pos) string { 485 if pos == token.NoPos { 486 return "" 487 } 488 return " at " + fset.Position(pos).String() 489 } 490 491 // callSSA interprets a call to function fn with arguments args, 492 // and lexical environment env, returning its result. 493 // callpos is the position of the callsite. 494 func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value { 495 if i.mode&EnableTracing != 0 { 496 fset := fn.Prog.Fset 497 // TODO(adonovan): fix: loc() lies for external functions. 498 fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos())) 499 suffix := "" 500 if caller != nil { 501 suffix = ", resuming " + caller.fn.String() + loc(fset, callpos) 502 } 503 defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix) 504 } 505 fr := &frame{ 506 i: i, 507 caller: caller, // for panic/recover 508 fn: fn, 509 } 510 if fn.Parent() == nil { 511 name := fn.String() 512 if ext := externals[name]; ext != nil { 513 if i.mode&EnableTracing != 0 { 514 fmt.Fprintln(os.Stderr, "\t(external)") 515 } 516 return ext(fr, args) 517 } 518 if fn.Blocks == nil { 519 panic("no code for function: " + name) 520 } 521 } 522 523 // generic function body? 524 if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 { 525 panic("interp requires ssa.BuilderMode to include InstantiateGenerics to execute generics") 526 } 527 528 fr.env = make(map[ssa.Value]value) 529 fr.block = fn.Blocks[0] 530 fr.locals = make([]value, len(fn.Locals)) 531 for i, l := range fn.Locals { 532 fr.locals[i] = zero(typeparams.MustDeref(l.Type())) 533 fr.env[l] = &fr.locals[i] 534 } 535 for i, p := range fn.Params { 536 fr.env[p] = args[i] 537 } 538 for i, fv := range fn.FreeVars { 539 fr.env[fv] = env[i] 540 } 541 for fr.block != nil { 542 runFrame(fr) 543 } 544 // Destroy the locals to avoid accidental use after return. 545 for i := range fn.Locals { 546 fr.locals[i] = bad{} 547 } 548 return fr.result 549 } 550 551 // runFrame executes SSA instructions starting at fr.block and 552 // continuing until a return, a panic, or a recovered panic. 553 // 554 // After a panic, runFrame panics. 555 // 556 // After a normal return, fr.result contains the result of the call 557 // and fr.block is nil. 558 // 559 // A recovered panic in a function without named return parameters 560 // (NRPs) becomes a normal return of the zero value of the function's 561 // result type. 562 // 563 // After a recovered panic in a function with NRPs, fr.result is 564 // undefined and fr.block contains the block at which to resume 565 // control. 566 func runFrame(fr *frame) { 567 defer func() { 568 if fr.block == nil { 569 return // normal return 570 } 571 if fr.i.mode&DisableRecover != 0 { 572 return // let interpreter crash 573 } 574 fr.panicking = true 575 fr.panic = recover() 576 if fr.i.mode&EnableTracing != 0 { 577 fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic) 578 } 579 fr.runDefers() 580 fr.block = fr.fn.Recover 581 }() 582 583 for { 584 if fr.i.mode&EnableTracing != 0 { 585 fmt.Fprintf(os.Stderr, ".%s:\n", fr.block) 586 } 587 block: 588 for _, instr := range fr.block.Instrs { 589 if fr.i.mode&EnableTracing != 0 { 590 if v, ok := instr.(ssa.Value); ok { 591 fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr) 592 } else { 593 fmt.Fprintln(os.Stderr, "\t", instr) 594 } 595 } 596 switch visitInstr(fr, instr) { 597 case kReturn: 598 return 599 case kNext: 600 // no-op 601 case kJump: 602 break block 603 } 604 } 605 } 606 } 607 608 // doRecover implements the recover() built-in. 609 func doRecover(caller *frame) value { 610 // recover() must be exactly one level beneath the deferred 611 // function (two levels beneath the panicking function) to 612 // have any effect. Thus we ignore both "defer recover()" and 613 // "defer f() -> g() -> recover()". 614 if caller.i.mode&DisableRecover == 0 && 615 caller != nil && !caller.panicking && 616 caller.caller != nil && caller.caller.panicking { 617 caller.caller.panicking = false 618 p := caller.caller.panic 619 caller.caller.panic = nil 620 621 // TODO(adonovan): support runtime.Goexit. 622 switch p := p.(type) { 623 case targetPanic: 624 // The target program explicitly called panic(). 625 return p.v 626 case runtime.Error: 627 // The interpreter encountered a runtime error. 628 return iface{caller.i.runtimeErrorString, p.Error()} 629 case string: 630 // The interpreter explicitly called panic(). 631 return iface{caller.i.runtimeErrorString, p} 632 default: 633 panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p)) 634 } 635 } 636 return iface{} 637 } 638 639 // Interpret interprets the Go program whose main package is mainpkg. 640 // mode specifies various interpreter options. filename and args are 641 // the initial values of os.Args for the target program. sizes is the 642 // effective type-sizing function for this program. 643 // 644 // Interpret returns the exit code of the program: 2 for panic (like 645 // gc does), or the argument to os.Exit for normal termination. 646 // 647 // The SSA program must include the "runtime" package. 648 // 649 // Type parameterized functions must have been built with 650 // InstantiateGenerics in the ssa.BuilderMode to be interpreted. 651 func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) { 652 i := &interpreter{ 653 prog: mainpkg.Prog, 654 globals: make(map[*ssa.Global]*value), 655 mode: mode, 656 sizes: sizes, 657 goroutines: 1, 658 } 659 runtimePkg := i.prog.ImportedPackage("runtime") 660 if runtimePkg == nil { 661 panic("ssa.Program doesn't include runtime package") 662 } 663 i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type() 664 665 initReflect(i) 666 667 i.osArgs = append(i.osArgs, filename) 668 for _, arg := range args { 669 i.osArgs = append(i.osArgs, arg) 670 } 671 672 for _, pkg := range i.prog.AllPackages() { 673 // Initialize global storage. 674 for _, m := range pkg.Members { 675 switch v := m.(type) { 676 case *ssa.Global: 677 cell := zero(typeparams.MustDeref(v.Type())) 678 i.globals[v] = &cell 679 } 680 } 681 } 682 683 // Top-level error handler. 684 exitCode = 2 685 defer func() { 686 if exitCode != 2 || i.mode&DisableRecover != 0 { 687 return 688 } 689 switch p := recover().(type) { 690 case exitPanic: 691 exitCode = int(p) 692 return 693 case targetPanic: 694 fmt.Fprintln(os.Stderr, "panic:", toString(p.v)) 695 case runtime.Error: 696 fmt.Fprintln(os.Stderr, "panic:", p.Error()) 697 case string: 698 fmt.Fprintln(os.Stderr, "panic:", p) 699 default: 700 fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p) 701 } 702 703 // TODO(adonovan): dump panicking interpreter goroutine? 704 // buf := make([]byte, 0x10000) 705 // runtime.Stack(buf, false) 706 // fmt.Fprintln(os.Stderr, string(buf)) 707 // (Or dump panicking target goroutine?) 708 }() 709 710 // Run! 711 call(i, nil, token.NoPos, mainpkg.Func("init"), nil) 712 if mainFn := mainpkg.Func("main"); mainFn != nil { 713 call(i, nil, token.NoPos, mainFn, nil) 714 exitCode = 0 715 } else { 716 fmt.Fprintln(os.Stderr, "No main function.") 717 exitCode = 1 718 } 719 return 720 }