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