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