aboutsummaryrefslogtreecommitdiff
path: root/go/ssa/interp/interp.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/ssa/interp/interp.go')
-rw-r--r--go/ssa/interp/interp.go65
1 files changed, 40 insertions, 25 deletions
diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go
index bf7862289..58cac4642 100644
--- a/go/ssa/interp/interp.go
+++ b/go/ssa/interp/interp.go
@@ -76,16 +76,16 @@ type methodSet map[string]*ssa.Function
// State shared between all interpreted goroutines.
type interpreter struct {
- osArgs []value // the value of os.Args
- prog *ssa.Program // the SSA program
- globals map[ssa.Value]*value // addresses of global variables (immutable)
- mode Mode // interpreter options
- reflectPackage *ssa.Package // the fake reflect package
- errorMethods methodSet // the method set of reflect.error, which implements the error interface.
- rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface.
- runtimeErrorString types.Type // the runtime.errorString type
- sizes types.Sizes // the effective type-sizing function
- goroutines int32 // atomically updated
+ osArgs []value // the value of os.Args
+ prog *ssa.Program // the SSA program
+ globals map[*ssa.Global]*value // addresses of global variables (immutable)
+ mode Mode // interpreter options
+ reflectPackage *ssa.Package // the fake reflect package
+ errorMethods methodSet // the method set of reflect.error, which implements the error interface.
+ rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface.
+ runtimeErrorString types.Type // the runtime.errorString type
+ sizes types.Sizes // the effective type-sizing function
+ goroutines int32 // atomically updated
}
type deferred struct {
@@ -131,7 +131,6 @@ func (fr *frame) get(key ssa.Value) value {
// runDefer runs a deferred call d.
// It always returns normally, but may set or clear fr.panic.
-//
func (fr *frame) runDefer(d *deferred) {
if fr.i.mode&EnableTracing != 0 {
fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n",
@@ -160,7 +159,6 @@ func (fr *frame) runDefer(d *deferred) {
//
// If there was no initial state of panic, or it was recovered from,
// runDefers returns normally.
-//
func (fr *frame) runDefers() {
for d := fr.defers; d != nil; d = d.tail {
fr.runDefer(d)
@@ -279,7 +277,7 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
}()
case *ssa.MakeChan:
- fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
+ fr.env[instr] = make(chan value, asInt64(fr.get(instr.Size)))
case *ssa.Alloc:
var addr *value
@@ -294,17 +292,20 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
*addr = zero(deref(instr.Type()))
case *ssa.MakeSlice:
- slice := make([]value, asInt(fr.get(instr.Cap)))
+ slice := make([]value, asInt64(fr.get(instr.Cap)))
tElt := instr.Type().Underlying().(*types.Slice).Elem()
for i := range slice {
slice[i] = zero(tElt)
}
- fr.env[instr] = slice[:asInt(fr.get(instr.Len))]
+ fr.env[instr] = slice[:asInt64(fr.get(instr.Len))]
case *ssa.MakeMap:
- reserve := 0
+ var reserve int64
if instr.Reserve != nil {
- reserve = asInt(fr.get(instr.Reserve))
+ reserve = asInt64(fr.get(instr.Reserve))
+ }
+ if !fitsInt(reserve, fr.i.sizes) {
+ panic(fmt.Sprintf("ssa.MakeMap.Reserve value %d does not fit in int", reserve))
}
fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
@@ -325,15 +326,25 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
idx := fr.get(instr.Index)
switch x := x.(type) {
case []value:
- fr.env[instr] = &x[asInt(idx)]
+ fr.env[instr] = &x[asInt64(idx)]
case *value: // *array
- fr.env[instr] = &(*x).(array)[asInt(idx)]
+ fr.env[instr] = &(*x).(array)[asInt64(idx)]
default:
panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
}
case *ssa.Index:
- fr.env[instr] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))]
+ x := fr.get(instr.X)
+ idx := fr.get(instr.Index)
+
+ switch x := x.(type) {
+ case array:
+ fr.env[instr] = x[asInt64(idx)]
+ case string:
+ fr.env[instr] = x[asInt64(idx)]
+ default:
+ panic(fmt.Sprintf("unexpected x type in Index: %T", x))
+ }
case *ssa.Lookup:
fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
@@ -426,7 +437,6 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
// prepareCall determines the function value and argument values for a
// function call in a Call, Go or Defer instruction, performing
// interface method lookup if needed.
-//
func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
v := fr.get(call.Value)
if call.Method == nil {
@@ -455,7 +465,6 @@ func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
// call interprets a call to a function (function, builtin or closure)
// fn with arguments args, returning its result.
// callpos is the position of the callsite.
-//
func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
switch fn := fn.(type) {
case *ssa.Function:
@@ -481,7 +490,6 @@ func loc(fset *token.FileSet, pos token.Pos) string {
// callSSA interprets a call to function fn with arguments args,
// and lexical environment env, returning its result.
// callpos is the position of the callsite.
-//
func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
if i.mode&EnableTracing != 0 {
fset := fn.Prog.Fset
@@ -510,6 +518,12 @@ func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function,
panic("no code for function: " + name)
}
}
+
+ // generic function body?
+ if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 {
+ panic("interp requires ssa.BuilderMode to include InstantiateGenerics to execute generics")
+ }
+
fr.env = make(map[ssa.Value]value)
fr.block = fn.Blocks[0]
fr.locals = make([]value, len(fn.Locals))
@@ -548,7 +562,6 @@ func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function,
// After a recovered panic in a function with NRPs, fr.result is
// undefined and fr.block contains the block at which to resume
// control.
-//
func runFrame(fr *frame) {
defer func() {
if fr.block == nil {
@@ -641,10 +654,12 @@ func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
//
// The SSA program must include the "runtime" package.
//
+// Type parameterized functions must have been built with
+// InstantiateGenerics in the ssa.BuilderMode to be interpreted.
func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
i := &interpreter{
prog: mainpkg.Prog,
- globals: make(map[ssa.Value]*value),
+ globals: make(map[*ssa.Global]*value),
mode: mode,
sizes: sizes,
goroutines: 1,