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