diff options
author | Dan Willemsen <dwillemsen@google.com> | 2023-03-15 13:19:36 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@google.com> | 2023-03-15 14:18:08 -0400 |
commit | 09c5a32afc5b66f28f166a68afe1fc71afbf9b73 (patch) | |
tree | 194d7b0e539d014393564a256bec571e18d6533a /go/ssa/interp/interp.go | |
parent | f10932f763d058b0dcb3acfb795c869996fef47b (diff) | |
parent | 031fc75960d487b0b15db12fb328676236a3a39c (diff) | |
download | golang-x-tools-master.tar.gz |
Not using external_updater this time to switch to the new upstream tags.
Test: treehugger
Change-Id: I31488b4958a366ed7f183bb387d3e1446acc13ae
Diffstat (limited to 'go/ssa/interp/interp.go')
-rw-r--r-- | go/ssa/interp/interp.go | 65 |
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, |