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  }