// 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 }
// prettyFunc pretty-prints fn for the user interface. // TODO(adonovan): return HTML so we have more markup freedom. func prettyFunc(this *types.Package, fn *ssa.Function) string { if fn.Parent() != nil { return fmt.Sprintf("%s in %s", types.TypeString(this, fn.Signature), prettyFunc(this, fn.Parent())) } if fn.Synthetic != "" && fn.Name() == "init" { // (This is the actual initializer, not a declared 'func init'). if fn.Pkg.Object == this { return "package initializer" } return fmt.Sprintf("%q package initializer", fn.Pkg.Object.Path()) } return fn.RelString(this) }