.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / ssa / interp / interp.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/ssa/interp/interp.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/ssa/interp/interp.go
new file mode 100644 (file)
index 0000000..d776594
--- /dev/null
@@ -0,0 +1,719 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ssa/interp defines an interpreter for the SSA
+// representation of Go programs.
+//
+// This interpreter is provided as an adjunct for testing the SSA
+// construction algorithm.  Its purpose is to provide a minimal
+// metacircular implementation of the dynamic semantics of each SSA
+// instruction.  It is not, and will never be, a production-quality Go
+// interpreter.
+//
+// The following is a partial list of Go features that are currently
+// unsupported or incomplete in the interpreter.
+//
+// * Unsafe operations, including all uses of unsafe.Pointer, are
+// impossible to support given the "boxed" value representation we
+// have chosen.
+//
+// * The reflect package is only partially implemented.
+//
+// * The "testing" package is no longer supported because it
+// depends on low-level details that change too often.
+//
+// * "sync/atomic" operations are not atomic due to the "boxed" value
+// representation: it is not possible to read, modify and write an
+// interface value atomically. As a consequence, Mutexes are currently
+// broken.
+//
+// * recover is only partially implemented.  Also, the interpreter
+// makes no attempt to distinguish target panics from interpreter
+// crashes.
+//
+// * the sizes of the int, uint and uintptr types in the target
+// program are assumed to be the same as those of the interpreter
+// itself.
+//
+// * all values occupy space, even those of types defined by the spec
+// to have zero size, e.g. struct{}.  This can cause asymptotic
+// performance degradation.
+//
+// * os.Exit is implemented using panic, causing deferred functions to
+// run.
+package interp // import "golang.org/x/tools/go/ssa/interp"
+
+import (
+       "fmt"
+       "go/token"
+       "go/types"
+       "os"
+       "reflect"
+       "runtime"
+       "sync/atomic"
+
+       "golang.org/x/tools/go/ssa"
+)
+
+type continuation int
+
+const (
+       kNext continuation = iota
+       kReturn
+       kJump
+)
+
+// Mode is a bitmask of options affecting the interpreter.
+type Mode uint
+
+const (
+       DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead.
+       EnableTracing                   // Print a trace of all instructions as they are interpreted.
+)
+
+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
+}
+
+type deferred struct {
+       fn    value
+       args  []value
+       instr *ssa.Defer
+       tail  *deferred
+}
+
+type frame struct {
+       i                *interpreter
+       caller           *frame
+       fn               *ssa.Function
+       block, prevBlock *ssa.BasicBlock
+       env              map[ssa.Value]value // dynamic values of SSA variables
+       locals           []value
+       defers           *deferred
+       result           value
+       panicking        bool
+       panic            interface{}
+}
+
+func (fr *frame) get(key ssa.Value) value {
+       switch key := key.(type) {
+       case nil:
+               // Hack; simplifies handling of optional attributes
+               // such as ssa.Slice.{Low,High}.
+               return nil
+       case *ssa.Function, *ssa.Builtin:
+               return key
+       case *ssa.Const:
+               return constValue(key)
+       case *ssa.Global:
+               if r, ok := fr.i.globals[key]; ok {
+                       return r
+               }
+       }
+       if r, ok := fr.env[key]; ok {
+               return r
+       }
+       panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name()))
+}
+
+// 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",
+                       fr.i.prog.Fset.Position(d.instr.Pos()))
+       }
+       var ok bool
+       defer func() {
+               if !ok {
+                       // Deferred call created a new state of panic.
+                       fr.panicking = true
+                       fr.panic = recover()
+               }
+       }()
+       call(fr.i, fr, d.instr.Pos(), d.fn, d.args)
+       ok = true
+}
+
+// runDefers executes fr's deferred function calls in LIFO order.
+//
+// On entry, fr.panicking indicates a state of panic; if
+// true, fr.panic contains the panic value.
+//
+// On completion, if a deferred call started a panic, or if no
+// deferred call recovered from a previous state of panic, then
+// runDefers itself panics after the last deferred call has run.
+//
+// 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)
+       }
+       fr.defers = nil
+       if fr.panicking {
+               panic(fr.panic) // new panic, or still panicking
+       }
+}
+
+// lookupMethod returns the method set for type typ, which may be one
+// of the interpreter's fake types.
+func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
+       switch typ {
+       case rtypeType:
+               return i.rtypeMethods[meth.Id()]
+       case errorType:
+               return i.errorMethods[meth.Id()]
+       }
+       return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
+}
+
+// visitInstr interprets a single ssa.Instruction within the activation
+// record frame.  It returns a continuation value indicating where to
+// read the next instruction from.
+func visitInstr(fr *frame, instr ssa.Instruction) continuation {
+       switch instr := instr.(type) {
+       case *ssa.DebugRef:
+               // no-op
+
+       case *ssa.UnOp:
+               fr.env[instr] = unop(instr, fr.get(instr.X))
+
+       case *ssa.BinOp:
+               fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y))
+
+       case *ssa.Call:
+               fn, args := prepareCall(fr, &instr.Call)
+               fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
+
+       case *ssa.ChangeInterface:
+               fr.env[instr] = fr.get(instr.X)
+
+       case *ssa.ChangeType:
+               fr.env[instr] = fr.get(instr.X) // (can't fail)
+
+       case *ssa.Convert:
+               fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X))
+
+       case *ssa.MakeInterface:
+               fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)}
+
+       case *ssa.Extract:
+               fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
+
+       case *ssa.Slice:
+               fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
+
+       case *ssa.Return:
+               switch len(instr.Results) {
+               case 0:
+               case 1:
+                       fr.result = fr.get(instr.Results[0])
+               default:
+                       var res []value
+                       for _, r := range instr.Results {
+                               res = append(res, fr.get(r))
+                       }
+                       fr.result = tuple(res)
+               }
+               fr.block = nil
+               return kReturn
+
+       case *ssa.RunDefers:
+               fr.runDefers()
+
+       case *ssa.Panic:
+               panic(targetPanic{fr.get(instr.X)})
+
+       case *ssa.Send:
+               fr.get(instr.Chan).(chan value) <- fr.get(instr.X)
+
+       case *ssa.Store:
+               store(deref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val))
+
+       case *ssa.If:
+               succ := 1
+               if fr.get(instr.Cond).(bool) {
+                       succ = 0
+               }
+               fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ]
+               return kJump
+
+       case *ssa.Jump:
+               fr.prevBlock, fr.block = fr.block, fr.block.Succs[0]
+               return kJump
+
+       case *ssa.Defer:
+               fn, args := prepareCall(fr, &instr.Call)
+               fr.defers = &deferred{
+                       fn:    fn,
+                       args:  args,
+                       instr: instr,
+                       tail:  fr.defers,
+               }
+
+       case *ssa.Go:
+               fn, args := prepareCall(fr, &instr.Call)
+               atomic.AddInt32(&fr.i.goroutines, 1)
+               go func() {
+                       call(fr.i, nil, instr.Pos(), fn, args)
+                       atomic.AddInt32(&fr.i.goroutines, -1)
+               }()
+
+       case *ssa.MakeChan:
+               fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
+
+       case *ssa.Alloc:
+               var addr *value
+               if instr.Heap {
+                       // new
+                       addr = new(value)
+                       fr.env[instr] = addr
+               } else {
+                       // local
+                       addr = fr.env[instr].(*value)
+               }
+               *addr = zero(deref(instr.Type()))
+
+       case *ssa.MakeSlice:
+               slice := make([]value, asInt(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))]
+
+       case *ssa.MakeMap:
+               reserve := 0
+               if instr.Reserve != nil {
+                       reserve = asInt(fr.get(instr.Reserve))
+               }
+               fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
+
+       case *ssa.Range:
+               fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
+
+       case *ssa.Next:
+               fr.env[instr] = fr.get(instr.Iter).(iter).next()
+
+       case *ssa.FieldAddr:
+               fr.env[instr] = &(*fr.get(instr.X).(*value)).(structure)[instr.Field]
+
+       case *ssa.Field:
+               fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
+
+       case *ssa.IndexAddr:
+               x := fr.get(instr.X)
+               idx := fr.get(instr.Index)
+               switch x := x.(type) {
+               case []value:
+                       fr.env[instr] = &x[asInt(idx)]
+               case *value: // *array
+                       fr.env[instr] = &(*x).(array)[asInt(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))]
+
+       case *ssa.Lookup:
+               fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
+
+       case *ssa.MapUpdate:
+               m := fr.get(instr.Map)
+               key := fr.get(instr.Key)
+               v := fr.get(instr.Value)
+               switch m := m.(type) {
+               case map[value]value:
+                       m[key] = v
+               case *hashmap:
+                       m.insert(key.(hashable), v)
+               default:
+                       panic(fmt.Sprintf("illegal map type: %T", m))
+               }
+
+       case *ssa.TypeAssert:
+               fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
+
+       case *ssa.MakeClosure:
+               var bindings []value
+               for _, binding := range instr.Bindings {
+                       bindings = append(bindings, fr.get(binding))
+               }
+               fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
+
+       case *ssa.Phi:
+               for i, pred := range instr.Block().Preds {
+                       if fr.prevBlock == pred {
+                               fr.env[instr] = fr.get(instr.Edges[i])
+                               break
+                       }
+               }
+
+       case *ssa.Select:
+               var cases []reflect.SelectCase
+               if !instr.Blocking {
+                       cases = append(cases, reflect.SelectCase{
+                               Dir: reflect.SelectDefault,
+                       })
+               }
+               for _, state := range instr.States {
+                       var dir reflect.SelectDir
+                       if state.Dir == types.RecvOnly {
+                               dir = reflect.SelectRecv
+                       } else {
+                               dir = reflect.SelectSend
+                       }
+                       var send reflect.Value
+                       if state.Send != nil {
+                               send = reflect.ValueOf(fr.get(state.Send))
+                       }
+                       cases = append(cases, reflect.SelectCase{
+                               Dir:  dir,
+                               Chan: reflect.ValueOf(fr.get(state.Chan)),
+                               Send: send,
+                       })
+               }
+               chosen, recv, recvOk := reflect.Select(cases)
+               if !instr.Blocking {
+                       chosen-- // default case should have index -1.
+               }
+               r := tuple{chosen, recvOk}
+               for i, st := range instr.States {
+                       if st.Dir == types.RecvOnly {
+                               var v value
+                               if i == chosen && recvOk {
+                                       // No need to copy since send makes an unaliased copy.
+                                       v = recv.Interface().(value)
+                               } else {
+                                       v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
+                               }
+                               r = append(r, v)
+                       }
+               }
+               fr.env[instr] = r
+
+       default:
+               panic(fmt.Sprintf("unexpected instruction: %T", instr))
+       }
+
+       // if val, ok := instr.(ssa.Value); ok {
+       //      fmt.Println(toString(fr.env[val])) // debugging
+       // }
+
+       return kNext
+}
+
+// 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 {
+               // Function call.
+               fn = v
+       } else {
+               // Interface method invocation.
+               recv := v.(iface)
+               if recv.t == nil {
+                       panic("method invoked on nil interface")
+               }
+               if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
+                       // Unreachable in well-typed programs.
+                       panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
+               } else {
+                       fn = f
+               }
+               args = append(args, recv.v)
+       }
+       for _, arg := range call.Args {
+               args = append(args, fr.get(arg))
+       }
+       return
+}
+
+// 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:
+               if fn == nil {
+                       panic("call of nil function") // nil of func type
+               }
+               return callSSA(i, caller, callpos, fn, args, nil)
+       case *closure:
+               return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
+       case *ssa.Builtin:
+               return callBuiltin(caller, callpos, fn, args)
+       }
+       panic(fmt.Sprintf("cannot call %T", fn))
+}
+
+func loc(fset *token.FileSet, pos token.Pos) string {
+       if pos == token.NoPos {
+               return ""
+       }
+       return " at " + fset.Position(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
+               // TODO(adonovan): fix: loc() lies for external functions.
+               fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
+               suffix := ""
+               if caller != nil {
+                       suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
+               }
+               defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
+       }
+       fr := &frame{
+               i:      i,
+               caller: caller, // for panic/recover
+               fn:     fn,
+       }
+       if fn.Parent() == nil {
+               name := fn.String()
+               if ext := externals[name]; ext != nil {
+                       if i.mode&EnableTracing != 0 {
+                               fmt.Fprintln(os.Stderr, "\t(external)")
+                       }
+                       return ext(fr, args)
+               }
+               if fn.Blocks == nil {
+                       panic("no code for function: " + name)
+               }
+       }
+       fr.env = make(map[ssa.Value]value)
+       fr.block = fn.Blocks[0]
+       fr.locals = make([]value, len(fn.Locals))
+       for i, l := range fn.Locals {
+               fr.locals[i] = zero(deref(l.Type()))
+               fr.env[l] = &fr.locals[i]
+       }
+       for i, p := range fn.Params {
+               fr.env[p] = args[i]
+       }
+       for i, fv := range fn.FreeVars {
+               fr.env[fv] = env[i]
+       }
+       for fr.block != nil {
+               runFrame(fr)
+       }
+       // Destroy the locals to avoid accidental use after return.
+       for i := range fn.Locals {
+               fr.locals[i] = bad{}
+       }
+       return fr.result
+}
+
+// runFrame executes SSA instructions starting at fr.block and
+// continuing until a return, a panic, or a recovered panic.
+//
+// After a panic, runFrame panics.
+//
+// After a normal return, fr.result contains the result of the call
+// and fr.block is nil.
+//
+// A recovered panic in a function without named return parameters
+// (NRPs) becomes a normal return of the zero value of the function's
+// result type.
+//
+// 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 {
+                       return // normal return
+               }
+               if fr.i.mode&DisableRecover != 0 {
+                       return // let interpreter crash
+               }
+               fr.panicking = true
+               fr.panic = recover()
+               if fr.i.mode&EnableTracing != 0 {
+                       fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
+               }
+               fr.runDefers()
+               fr.block = fr.fn.Recover
+       }()
+
+       for {
+               if fr.i.mode&EnableTracing != 0 {
+                       fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
+               }
+       block:
+               for _, instr := range fr.block.Instrs {
+                       if fr.i.mode&EnableTracing != 0 {
+                               if v, ok := instr.(ssa.Value); ok {
+                                       fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
+                               } else {
+                                       fmt.Fprintln(os.Stderr, "\t", instr)
+                               }
+                       }
+                       switch visitInstr(fr, instr) {
+                       case kReturn:
+                               return
+                       case kNext:
+                               // no-op
+                       case kJump:
+                               break block
+                       }
+               }
+       }
+}
+
+// doRecover implements the recover() built-in.
+func doRecover(caller *frame) value {
+       // recover() must be exactly one level beneath the deferred
+       // function (two levels beneath the panicking function) to
+       // have any effect.  Thus we ignore both "defer recover()" and
+       // "defer f() -> g() -> recover()".
+       if caller.i.mode&DisableRecover == 0 &&
+               caller != nil && !caller.panicking &&
+               caller.caller != nil && caller.caller.panicking {
+               caller.caller.panicking = false
+               p := caller.caller.panic
+               caller.caller.panic = nil
+
+               // TODO(adonovan): support runtime.Goexit.
+               switch p := p.(type) {
+               case targetPanic:
+                       // The target program explicitly called panic().
+                       return p.v
+               case runtime.Error:
+                       // The interpreter encountered a runtime error.
+                       return iface{caller.i.runtimeErrorString, p.Error()}
+               case string:
+                       // The interpreter explicitly called panic().
+                       return iface{caller.i.runtimeErrorString, p}
+               default:
+                       panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
+               }
+       }
+       return iface{}
+}
+
+// setGlobal sets the value of a system-initialized global variable.
+func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
+       if g, ok := i.globals[pkg.Var(name)]; ok {
+               *g = v
+               return
+       }
+       panic("no global variable: " + pkg.Pkg.Path() + "." + name)
+}
+
+// Interpret interprets the Go program whose main package is mainpkg.
+// mode specifies various interpreter options.  filename and args are
+// the initial values of os.Args for the target program.  sizes is the
+// effective type-sizing function for this program.
+//
+// Interpret returns the exit code of the program: 2 for panic (like
+// gc does), or the argument to os.Exit for normal termination.
+//
+// The SSA program must include the "runtime" package.
+//
+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),
+               mode:       mode,
+               sizes:      sizes,
+               goroutines: 1,
+       }
+       runtimePkg := i.prog.ImportedPackage("runtime")
+       if runtimePkg == nil {
+               panic("ssa.Program doesn't include runtime package")
+       }
+       i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
+
+       initReflect(i)
+
+       i.osArgs = append(i.osArgs, filename)
+       for _, arg := range args {
+               i.osArgs = append(i.osArgs, arg)
+       }
+
+       for _, pkg := range i.prog.AllPackages() {
+               // Initialize global storage.
+               for _, m := range pkg.Members {
+                       switch v := m.(type) {
+                       case *ssa.Global:
+                               cell := zero(deref(v.Type()))
+                               i.globals[v] = &cell
+                       }
+               }
+       }
+
+       // Top-level error handler.
+       exitCode = 2
+       defer func() {
+               if exitCode != 2 || i.mode&DisableRecover != 0 {
+                       return
+               }
+               switch p := recover().(type) {
+               case exitPanic:
+                       exitCode = int(p)
+                       return
+               case targetPanic:
+                       fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
+               case runtime.Error:
+                       fmt.Fprintln(os.Stderr, "panic:", p.Error())
+               case string:
+                       fmt.Fprintln(os.Stderr, "panic:", p)
+               default:
+                       fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
+               }
+
+               // TODO(adonovan): dump panicking interpreter goroutine?
+               // buf := make([]byte, 0x10000)
+               // runtime.Stack(buf, false)
+               // fmt.Fprintln(os.Stderr, string(buf))
+               // (Or dump panicking target goroutine?)
+       }()
+
+       // Run!
+       call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
+       if mainFn := mainpkg.Func("main"); mainFn != nil {
+               call(i, nil, token.NoPos, mainFn, nil)
+               exitCode = 0
+       } else {
+               fmt.Fprintln(os.Stderr, "No main function.")
+               exitCode = 1
+       }
+       return
+}
+
+// deref returns a pointer's element type; otherwise it returns typ.
+// TODO(adonovan): Import from ssa?
+func deref(typ types.Type) types.Type {
+       if p, ok := typ.Underlying().(*types.Pointer); ok {
+               return p.Elem()
+       }
+       return typ
+}