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.
45package interp // import "golang.org/x/tools/go/ssa/interp"
46
47import (
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)
58
59type continuation int
60
61const (
62	kNext continuation = iota
63	kReturn
64	kJump
65)
66
67// Mode is a bitmask of options affecting the interpreter.
68type Mode uint
69
70const (
71	DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead.
72	EnableTracing                   // Print a trace of all instructions as they are interpreted.
73)
74
75type methodSet map[string]*ssa.Function
76
77// State shared between all interpreted goroutines.
78type interpreter struct {
79	osArgs             []value              // the value of os.Args
80	prog               *ssa.Program         // the SSA program
81	globals            map[ssa.Value]*value // addresses of global variables (immutable)
82	mode               Mode                 // interpreter options
83	reflectPackage     *ssa.Package         // the fake reflect package
84	errorMethods       methodSet            // the method set of reflect.error, which implements the error interface.
85	rtypeMethods       methodSet            // the method set of rtype, which implements the reflect.Type interface.
86	runtimeErrorString types.Type           // the runtime.errorString type
87	sizes              types.Sizes          // the effective type-sizing function
88	goroutines         int32                // atomically updated
89}
90
91type deferred struct {
92	fn    value
93	args  []value
94	instr *ssa.Defer
95	tail  *deferred
96}
97
98type 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
111func (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//
135func (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//
164func (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.
176func 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.
189func 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		atomic.AddInt32(&fr.i.goroutines, 1)
273		go func() {
274			call(fr.i, nil, instr.Pos(), fn, args)
275			atomic.AddInt32(&fr.i.goroutines, -1)
276		}()
277
278	case *ssa.MakeChan:
279		fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
280
281	case *ssa.Alloc:
282		var addr *value
283		if instr.Heap {
284			// new
285			addr = new(value)
286			fr.env[instr] = addr
287		} else {
288			// local
289			addr = fr.env[instr].(*value)
290		}
291		*addr = zero(deref(instr.Type()))
292
293	case *ssa.MakeSlice:
294		slice := make([]value, asInt(fr.get(instr.Cap)))
295		tElt := instr.Type().Underlying().(*types.Slice).Elem()
296		for i := range slice {
297			slice[i] = zero(tElt)
298		}
299		fr.env[instr] = slice[:asInt(fr.get(instr.Len))]
300
301	case *ssa.MakeMap:
302		reserve := 0
303		if instr.Reserve != nil {
304			reserve = asInt(fr.get(instr.Reserve))
305		}
306		fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
307
308	case *ssa.Range:
309		fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
310
311	case *ssa.Next:
312		fr.env[instr] = fr.get(instr.Iter).(iter).next()
313
314	case *ssa.FieldAddr:
315		fr.env[instr] = &(*fr.get(instr.X).(*value)).(structure)[instr.Field]
316
317	case *ssa.Field:
318		fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
319
320	case *ssa.IndexAddr:
321		x := fr.get(instr.X)
322		idx := fr.get(instr.Index)
323		switch x := x.(type) {
324		case []value:
325			fr.env[instr] = &x[asInt(idx)]
326		case *value: // *array
327			fr.env[instr] = &(*x).(array)[asInt(idx)]
328		default:
329			panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
330		}
331
332	case *ssa.Index:
333		fr.env[instr] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))]
334
335	case *ssa.Lookup:
336		fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
337
338	case *ssa.MapUpdate:
339		m := fr.get(instr.Map)
340		key := fr.get(instr.Key)
341		v := fr.get(instr.Value)
342		switch m := m.(type) {
343		case map[value]value:
344			m[key] = v
345		case *hashmap:
346			m.insert(key.(hashable), v)
347		default:
348			panic(fmt.Sprintf("illegal map type: %T", m))
349		}
350
351	case *ssa.TypeAssert:
352		fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
353
354	case *ssa.MakeClosure:
355		var bindings []value
356		for _, binding := range instr.Bindings {
357			bindings = append(bindings, fr.get(binding))
358		}
359		fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
360
361	case *ssa.Phi:
362		for i, pred := range instr.Block().Preds {
363			if fr.prevBlock == pred {
364				fr.env[instr] = fr.get(instr.Edges[i])
365				break
366			}
367		}
368
369	case *ssa.Select:
370		var cases []reflect.SelectCase
371		if !instr.Blocking {
372			cases = append(cases, reflect.SelectCase{
373				Dir: reflect.SelectDefault,
374			})
375		}
376		for _, state := range instr.States {
377			var dir reflect.SelectDir
378			if state.Dir == types.RecvOnly {
379				dir = reflect.SelectRecv
380			} else {
381				dir = reflect.SelectSend
382			}
383			var send reflect.Value
384			if state.Send != nil {
385				send = reflect.ValueOf(fr.get(state.Send))
386			}
387			cases = append(cases, reflect.SelectCase{
388				Dir:  dir,
389				Chan: reflect.ValueOf(fr.get(state.Chan)),
390				Send: send,
391			})
392		}
393		chosen, recv, recvOk := reflect.Select(cases)
394		if !instr.Blocking {
395			chosen-- // default case should have index -1.
396		}
397		r := tuple{chosen, recvOk}
398		for i, st := range instr.States {
399			if st.Dir == types.RecvOnly {
400				var v value
401				if i == chosen && recvOk {
402					// No need to copy since send makes an unaliased copy.
403					v = recv.Interface().(value)
404				} else {
405					v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
406				}
407				r = append(r, v)
408			}
409		}
410		fr.env[instr] = r
411
412	default:
413		panic(fmt.Sprintf("unexpected instruction: %T", instr))
414	}
415
416	// if val, ok := instr.(ssa.Value); ok {
417	// 	fmt.Println(toString(fr.env[val])) // debugging
418	// }
419
420	return kNext
421}
422
423// prepareCall determines the function value and argument values for a
424// function call in a Call, Go or Defer instruction, performing
425// interface method lookup if needed.
426//
427func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
428	v := fr.get(call.Value)
429	if call.Method == nil {
430		// Function call.
431		fn = v
432	} else {
433		// Interface method invocation.
434		recv := v.(iface)
435		if recv.t == nil {
436			panic("method invoked on nil interface")
437		}
438		if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
439			// Unreachable in well-typed programs.
440			panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
441		} else {
442			fn = f
443		}
444		args = append(args, recv.v)
445	}
446	for _, arg := range call.Args {
447		args = append(args, fr.get(arg))
448	}
449	return
450}
451
452// call interprets a call to a function (function, builtin or closure)
453// fn with arguments args, returning its result.
454// callpos is the position of the callsite.
455//
456func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
457	switch fn := fn.(type) {
458	case *ssa.Function:
459		if fn == nil {
460			panic("call of nil function") // nil of func type
461		}
462		return callSSA(i, caller, callpos, fn, args, nil)
463	case *closure:
464		return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
465	case *ssa.Builtin:
466		return callBuiltin(caller, callpos, fn, args)
467	}
468	panic(fmt.Sprintf("cannot call %T", fn))
469}
470
471func loc(fset *token.FileSet, pos token.Pos) string {
472	if pos == token.NoPos {
473		return ""
474	}
475	return " at " + fset.Position(pos).String()
476}
477
478// callSSA interprets a call to function fn with arguments args,
479// and lexical environment env, returning its result.
480// callpos is the position of the callsite.
481//
482func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
483	if i.mode&EnableTracing != 0 {
484		fset := fn.Prog.Fset
485		// TODO(adonovan): fix: loc() lies for external functions.
486		fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
487		suffix := ""
488		if caller != nil {
489			suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
490		}
491		defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
492	}
493	fr := &frame{
494		i:      i,
495		caller: caller, // for panic/recover
496		fn:     fn,
497	}
498	if fn.Parent() == nil {
499		name := fn.String()
500		if ext := externals[name]; ext != nil {
501			if i.mode&EnableTracing != 0 {
502				fmt.Fprintln(os.Stderr, "\t(external)")
503			}
504			return ext(fr, args)
505		}
506		if fn.Blocks == nil {
507			panic("no code for function: " + name)
508		}
509	}
510	fr.env = make(map[ssa.Value]value)
511	fr.block = fn.Blocks[0]
512	fr.locals = make([]value, len(fn.Locals))
513	for i, l := range fn.Locals {
514		fr.locals[i] = zero(deref(l.Type()))
515		fr.env[l] = &fr.locals[i]
516	}
517	for i, p := range fn.Params {
518		fr.env[p] = args[i]
519	}
520	for i, fv := range fn.FreeVars {
521		fr.env[fv] = env[i]
522	}
523	for fr.block != nil {
524		runFrame(fr)
525	}
526	// Destroy the locals to avoid accidental use after return.
527	for i := range fn.Locals {
528		fr.locals[i] = bad{}
529	}
530	return fr.result
531}
532
533// runFrame executes SSA instructions starting at fr.block and
534// continuing until a return, a panic, or a recovered panic.
535//
536// After a panic, runFrame panics.
537//
538// After a normal return, fr.result contains the result of the call
539// and fr.block is nil.
540//
541// A recovered panic in a function without named return parameters
542// (NRPs) becomes a normal return of the zero value of the function's
543// result type.
544//
545// After a recovered panic in a function with NRPs, fr.result is
546// undefined and fr.block contains the block at which to resume
547// control.
548//
549func runFrame(fr *frame) {
550	defer func() {
551		if fr.block == nil {
552			return // normal return
553		}
554		if fr.i.mode&DisableRecover != 0 {
555			return // let interpreter crash
556		}
557		fr.panicking = true
558		fr.panic = recover()
559		if fr.i.mode&EnableTracing != 0 {
560			fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
561		}
562		fr.runDefers()
563		fr.block = fr.fn.Recover
564	}()
565
566	for {
567		if fr.i.mode&EnableTracing != 0 {
568			fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
569		}
570	block:
571		for _, instr := range fr.block.Instrs {
572			if fr.i.mode&EnableTracing != 0 {
573				if v, ok := instr.(ssa.Value); ok {
574					fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
575				} else {
576					fmt.Fprintln(os.Stderr, "\t", instr)
577				}
578			}
579			switch visitInstr(fr, instr) {
580			case kReturn:
581				return
582			case kNext:
583				// no-op
584			case kJump:
585				break block
586			}
587		}
588	}
589}
590
591// doRecover implements the recover() built-in.
592func doRecover(caller *frame) value {
593	// recover() must be exactly one level beneath the deferred
594	// function (two levels beneath the panicking function) to
595	// have any effect.  Thus we ignore both "defer recover()" and
596	// "defer f() -> g() -> recover()".
597	if caller.i.mode&DisableRecover == 0 &&
598		caller != nil && !caller.panicking &&
599		caller.caller != nil && caller.caller.panicking {
600		caller.caller.panicking = false
601		p := caller.caller.panic
602		caller.caller.panic = nil
603
604		// TODO(adonovan): support runtime.Goexit.
605		switch p := p.(type) {
606		case targetPanic:
607			// The target program explicitly called panic().
608			return p.v
609		case runtime.Error:
610			// The interpreter encountered a runtime error.
611			return iface{caller.i.runtimeErrorString, p.Error()}
612		case string:
613			// The interpreter explicitly called panic().
614			return iface{caller.i.runtimeErrorString, p}
615		default:
616			panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
617		}
618	}
619	return iface{}
620}
621
622// setGlobal sets the value of a system-initialized global variable.
623func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
624	if g, ok := i.globals[pkg.Var(name)]; ok {
625		*g = v
626		return
627	}
628	panic("no global variable: " + pkg.Pkg.Path() + "." + name)
629}
630
631// Interpret interprets the Go program whose main package is mainpkg.
632// mode specifies various interpreter options.  filename and args are
633// the initial values of os.Args for the target program.  sizes is the
634// effective type-sizing function for this program.
635//
636// Interpret returns the exit code of the program: 2 for panic (like
637// gc does), or the argument to os.Exit for normal termination.
638//
639// The SSA program must include the "runtime" package.
640//
641func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
642	i := &interpreter{
643		prog:       mainpkg.Prog,
644		globals:    make(map[ssa.Value]*value),
645		mode:       mode,
646		sizes:      sizes,
647		goroutines: 1,
648	}
649	runtimePkg := i.prog.ImportedPackage("runtime")
650	if runtimePkg == nil {
651		panic("ssa.Program doesn't include runtime package")
652	}
653	i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
654
655	initReflect(i)
656
657	i.osArgs = append(i.osArgs, filename)
658	for _, arg := range args {
659		i.osArgs = append(i.osArgs, arg)
660	}
661
662	for _, pkg := range i.prog.AllPackages() {
663		// Initialize global storage.
664		for _, m := range pkg.Members {
665			switch v := m.(type) {
666			case *ssa.Global:
667				cell := zero(deref(v.Type()))
668				i.globals[v] = &cell
669			}
670		}
671	}
672
673	// Top-level error handler.
674	exitCode = 2
675	defer func() {
676		if exitCode != 2 || i.mode&DisableRecover != 0 {
677			return
678		}
679		switch p := recover().(type) {
680		case exitPanic:
681			exitCode = int(p)
682			return
683		case targetPanic:
684			fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
685		case runtime.Error:
686			fmt.Fprintln(os.Stderr, "panic:", p.Error())
687		case string:
688			fmt.Fprintln(os.Stderr, "panic:", p)
689		default:
690			fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
691		}
692
693		// TODO(adonovan): dump panicking interpreter goroutine?
694		// buf := make([]byte, 0x10000)
695		// runtime.Stack(buf, false)
696		// fmt.Fprintln(os.Stderr, string(buf))
697		// (Or dump panicking target goroutine?)
698	}()
699
700	// Run!
701	call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
702	if mainFn := mainpkg.Func("main"); mainFn != nil {
703		call(i, nil, token.NoPos, mainFn, nil)
704		exitCode = 0
705	} else {
706		fmt.Fprintln(os.Stderr, "No main function.")
707		exitCode = 1
708	}
709	return
710}
711
712// deref returns a pointer's element type; otherwise it returns typ.
713// TODO(adonovan): Import from ssa?
714func deref(typ types.Type) types.Type {
715	if p, ok := typ.Underlying().(*types.Pointer); ok {
716		return p.Elem()
717	}
718	return typ
719}
720