...

Source file src/golang.org/x/tools/go/ssa/interp/interp.go

Documentation: golang.org/x/tools/go/ssa/interp

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

View as plain text