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  }