1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package 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 "golang.org/x/tools/internal/typeparams"
58 )
59
60 type continuation int
61
62 const (
63 kNext continuation = iota
64 kReturn
65 kJump
66 )
67
68
69 type Mode uint
70
71 const (
72 DisableRecover Mode = 1 << iota
73 EnableTracing
74 )
75
76 type methodSet map[string]*ssa.Function
77
78
79 type interpreter struct {
80 osArgs []value
81 prog *ssa.Program
82 globals map[*ssa.Global]*value
83 mode Mode
84 reflectPackage *ssa.Package
85 errorMethods methodSet
86 rtypeMethods methodSet
87 runtimeErrorString types.Type
88 sizes types.Sizes
89 goroutines int32
90 }
91
92 type deferred struct {
93 fn value
94 args []value
95 instr *ssa.Defer
96 tail *deferred
97 }
98
99 type frame struct {
100 i *interpreter
101 caller *frame
102 fn *ssa.Function
103 block, prevBlock *ssa.BasicBlock
104 env map[ssa.Value]value
105 locals []value
106 defers *deferred
107 result value
108 panicking bool
109 panic interface{}
110 }
111
112 func (fr *frame) get(key ssa.Value) value {
113 switch key := key.(type) {
114 case nil:
115
116
117 return nil
118 case *ssa.Function, *ssa.Builtin:
119 return key
120 case *ssa.Const:
121 return constValue(key)
122 case *ssa.Global:
123 if r, ok := fr.i.globals[key]; ok {
124 return r
125 }
126 }
127 if r, ok := fr.env[key]; ok {
128 return r
129 }
130 panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name()))
131 }
132
133
134
135 func (fr *frame) runDefer(d *deferred) {
136 if fr.i.mode&EnableTracing != 0 {
137 fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n",
138 fr.i.prog.Fset.Position(d.instr.Pos()))
139 }
140 var ok bool
141 defer func() {
142 if !ok {
143
144 fr.panicking = true
145 fr.panic = recover()
146 }
147 }()
148 call(fr.i, fr, d.instr.Pos(), d.fn, d.args)
149 ok = true
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163 func (fr *frame) runDefers() {
164 for d := fr.defers; d != nil; d = d.tail {
165 fr.runDefer(d)
166 }
167 fr.defers = nil
168 if fr.panicking {
169 panic(fr.panic)
170 }
171 }
172
173
174
175 func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
176 switch typ {
177 case rtypeType:
178 return i.rtypeMethods[meth.Id()]
179 case errorType:
180 return i.errorMethods[meth.Id()]
181 }
182 return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
183 }
184
185
186
187
188 func visitInstr(fr *frame, instr ssa.Instruction) continuation {
189 switch instr := instr.(type) {
190 case *ssa.DebugRef:
191
192
193 case *ssa.UnOp:
194 fr.env[instr] = unop(instr, fr.get(instr.X))
195
196 case *ssa.BinOp:
197 fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y))
198
199 case *ssa.Call:
200 fn, args := prepareCall(fr, &instr.Call)
201 fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
202
203 case *ssa.ChangeInterface:
204 fr.env[instr] = fr.get(instr.X)
205
206 case *ssa.ChangeType:
207 fr.env[instr] = fr.get(instr.X)
208
209 case *ssa.Convert:
210 fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X))
211
212 case *ssa.SliceToArrayPointer:
213 fr.env[instr] = sliceToArrayPointer(instr.Type(), instr.X.Type(), fr.get(instr.X))
214
215 case *ssa.MakeInterface:
216 fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)}
217
218 case *ssa.Extract:
219 fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
220
221 case *ssa.Slice:
222 fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
223
224 case *ssa.Return:
225 switch len(instr.Results) {
226 case 0:
227 case 1:
228 fr.result = fr.get(instr.Results[0])
229 default:
230 var res []value
231 for _, r := range instr.Results {
232 res = append(res, fr.get(r))
233 }
234 fr.result = tuple(res)
235 }
236 fr.block = nil
237 return kReturn
238
239 case *ssa.RunDefers:
240 fr.runDefers()
241
242 case *ssa.Panic:
243 panic(targetPanic{fr.get(instr.X)})
244
245 case *ssa.Send:
246 fr.get(instr.Chan).(chan value) <- fr.get(instr.X)
247
248 case *ssa.Store:
249 store(typeparams.MustDeref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val))
250
251 case *ssa.If:
252 succ := 1
253 if fr.get(instr.Cond).(bool) {
254 succ = 0
255 }
256 fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ]
257 return kJump
258
259 case *ssa.Jump:
260 fr.prevBlock, fr.block = fr.block, fr.block.Succs[0]
261 return kJump
262
263 case *ssa.Defer:
264 fn, args := prepareCall(fr, &instr.Call)
265 fr.defers = &deferred{
266 fn: fn,
267 args: args,
268 instr: instr,
269 tail: fr.defers,
270 }
271
272 case *ssa.Go:
273 fn, args := prepareCall(fr, &instr.Call)
274 atomic.AddInt32(&fr.i.goroutines, 1)
275 go func() {
276 call(fr.i, nil, instr.Pos(), fn, args)
277 atomic.AddInt32(&fr.i.goroutines, -1)
278 }()
279
280 case *ssa.MakeChan:
281 fr.env[instr] = make(chan value, asInt64(fr.get(instr.Size)))
282
283 case *ssa.Alloc:
284 var addr *value
285 if instr.Heap {
286
287 addr = new(value)
288 fr.env[instr] = addr
289 } else {
290
291 addr = fr.env[instr].(*value)
292 }
293 *addr = zero(typeparams.MustDeref(instr.Type()))
294
295 case *ssa.MakeSlice:
296 slice := make([]value, asInt64(fr.get(instr.Cap)))
297 tElt := instr.Type().Underlying().(*types.Slice).Elem()
298 for i := range slice {
299 slice[i] = zero(tElt)
300 }
301 fr.env[instr] = slice[:asInt64(fr.get(instr.Len))]
302
303 case *ssa.MakeMap:
304 var reserve int64
305 if instr.Reserve != nil {
306 reserve = asInt64(fr.get(instr.Reserve))
307 }
308 if !fitsInt(reserve, fr.i.sizes) {
309 panic(fmt.Sprintf("ssa.MakeMap.Reserve value %d does not fit in int", reserve))
310 }
311 fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
312
313 case *ssa.Range:
314 fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
315
316 case *ssa.Next:
317 fr.env[instr] = fr.get(instr.Iter).(iter).next()
318
319 case *ssa.FieldAddr:
320 fr.env[instr] = &(*fr.get(instr.X).(*value)).(structure)[instr.Field]
321
322 case *ssa.Field:
323 fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
324
325 case *ssa.IndexAddr:
326 x := fr.get(instr.X)
327 idx := fr.get(instr.Index)
328 switch x := x.(type) {
329 case []value:
330 fr.env[instr] = &x[asInt64(idx)]
331 case *value:
332 fr.env[instr] = &(*x).(array)[asInt64(idx)]
333 default:
334 panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
335 }
336
337 case *ssa.Index:
338 x := fr.get(instr.X)
339 idx := fr.get(instr.Index)
340
341 switch x := x.(type) {
342 case array:
343 fr.env[instr] = x[asInt64(idx)]
344 case string:
345 fr.env[instr] = x[asInt64(idx)]
346 default:
347 panic(fmt.Sprintf("unexpected x type in Index: %T", x))
348 }
349
350 case *ssa.Lookup:
351 fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
352
353 case *ssa.MapUpdate:
354 m := fr.get(instr.Map)
355 key := fr.get(instr.Key)
356 v := fr.get(instr.Value)
357 switch m := m.(type) {
358 case map[value]value:
359 m[key] = v
360 case *hashmap:
361 m.insert(key.(hashable), v)
362 default:
363 panic(fmt.Sprintf("illegal map type: %T", m))
364 }
365
366 case *ssa.TypeAssert:
367 fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
368
369 case *ssa.MakeClosure:
370 var bindings []value
371 for _, binding := range instr.Bindings {
372 bindings = append(bindings, fr.get(binding))
373 }
374 fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
375
376 case *ssa.Phi:
377 for i, pred := range instr.Block().Preds {
378 if fr.prevBlock == pred {
379 fr.env[instr] = fr.get(instr.Edges[i])
380 break
381 }
382 }
383
384 case *ssa.Select:
385 var cases []reflect.SelectCase
386 if !instr.Blocking {
387 cases = append(cases, reflect.SelectCase{
388 Dir: reflect.SelectDefault,
389 })
390 }
391 for _, state := range instr.States {
392 var dir reflect.SelectDir
393 if state.Dir == types.RecvOnly {
394 dir = reflect.SelectRecv
395 } else {
396 dir = reflect.SelectSend
397 }
398 var send reflect.Value
399 if state.Send != nil {
400 send = reflect.ValueOf(fr.get(state.Send))
401 }
402 cases = append(cases, reflect.SelectCase{
403 Dir: dir,
404 Chan: reflect.ValueOf(fr.get(state.Chan)),
405 Send: send,
406 })
407 }
408 chosen, recv, recvOk := reflect.Select(cases)
409 if !instr.Blocking {
410 chosen--
411 }
412 r := tuple{chosen, recvOk}
413 for i, st := range instr.States {
414 if st.Dir == types.RecvOnly {
415 var v value
416 if i == chosen && recvOk {
417
418 v = recv.Interface().(value)
419 } else {
420 v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
421 }
422 r = append(r, v)
423 }
424 }
425 fr.env[instr] = r
426
427 default:
428 panic(fmt.Sprintf("unexpected instruction: %T", instr))
429 }
430
431
432
433
434
435 return kNext
436 }
437
438
439
440
441 func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
442 v := fr.get(call.Value)
443 if call.Method == nil {
444
445 fn = v
446 } else {
447
448 recv := v.(iface)
449 if recv.t == nil {
450 panic("method invoked on nil interface")
451 }
452 if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
453
454 panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
455 } else {
456 fn = f
457 }
458 args = append(args, recv.v)
459 }
460 for _, arg := range call.Args {
461 args = append(args, fr.get(arg))
462 }
463 return
464 }
465
466
467
468
469 func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
470 switch fn := fn.(type) {
471 case *ssa.Function:
472 if fn == nil {
473 panic("call of nil function")
474 }
475 return callSSA(i, caller, callpos, fn, args, nil)
476 case *closure:
477 return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
478 case *ssa.Builtin:
479 return callBuiltin(caller, callpos, fn, args)
480 }
481 panic(fmt.Sprintf("cannot call %T", fn))
482 }
483
484 func loc(fset *token.FileSet, pos token.Pos) string {
485 if pos == token.NoPos {
486 return ""
487 }
488 return " at " + fset.Position(pos).String()
489 }
490
491
492
493
494 func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
495 if i.mode&EnableTracing != 0 {
496 fset := fn.Prog.Fset
497
498 fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
499 suffix := ""
500 if caller != nil {
501 suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
502 }
503 defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
504 }
505 fr := &frame{
506 i: i,
507 caller: caller,
508 fn: fn,
509 }
510 if fn.Parent() == nil {
511 name := fn.String()
512 if ext := externals[name]; ext != nil {
513 if i.mode&EnableTracing != 0 {
514 fmt.Fprintln(os.Stderr, "\t(external)")
515 }
516 return ext(fr, args)
517 }
518 if fn.Blocks == nil {
519 panic("no code for function: " + name)
520 }
521 }
522
523
524 if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 {
525 panic("interp requires ssa.BuilderMode to include InstantiateGenerics to execute generics")
526 }
527
528 fr.env = make(map[ssa.Value]value)
529 fr.block = fn.Blocks[0]
530 fr.locals = make([]value, len(fn.Locals))
531 for i, l := range fn.Locals {
532 fr.locals[i] = zero(typeparams.MustDeref(l.Type()))
533 fr.env[l] = &fr.locals[i]
534 }
535 for i, p := range fn.Params {
536 fr.env[p] = args[i]
537 }
538 for i, fv := range fn.FreeVars {
539 fr.env[fv] = env[i]
540 }
541 for fr.block != nil {
542 runFrame(fr)
543 }
544
545 for i := range fn.Locals {
546 fr.locals[i] = bad{}
547 }
548 return fr.result
549 }
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566 func runFrame(fr *frame) {
567 defer func() {
568 if fr.block == nil {
569 return
570 }
571 if fr.i.mode&DisableRecover != 0 {
572 return
573 }
574 fr.panicking = true
575 fr.panic = recover()
576 if fr.i.mode&EnableTracing != 0 {
577 fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
578 }
579 fr.runDefers()
580 fr.block = fr.fn.Recover
581 }()
582
583 for {
584 if fr.i.mode&EnableTracing != 0 {
585 fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
586 }
587 block:
588 for _, instr := range fr.block.Instrs {
589 if fr.i.mode&EnableTracing != 0 {
590 if v, ok := instr.(ssa.Value); ok {
591 fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
592 } else {
593 fmt.Fprintln(os.Stderr, "\t", instr)
594 }
595 }
596 switch visitInstr(fr, instr) {
597 case kReturn:
598 return
599 case kNext:
600
601 case kJump:
602 break block
603 }
604 }
605 }
606 }
607
608
609 func doRecover(caller *frame) value {
610
611
612
613
614 if caller.i.mode&DisableRecover == 0 &&
615 caller != nil && !caller.panicking &&
616 caller.caller != nil && caller.caller.panicking {
617 caller.caller.panicking = false
618 p := caller.caller.panic
619 caller.caller.panic = nil
620
621
622 switch p := p.(type) {
623 case targetPanic:
624
625 return p.v
626 case runtime.Error:
627
628 return iface{caller.i.runtimeErrorString, p.Error()}
629 case string:
630
631 return iface{caller.i.runtimeErrorString, p}
632 default:
633 panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
634 }
635 }
636 return iface{}
637 }
638
639
640
641
642
643
644
645
646
647
648
649
650
651 func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
652 i := &interpreter{
653 prog: mainpkg.Prog,
654 globals: make(map[*ssa.Global]*value),
655 mode: mode,
656 sizes: sizes,
657 goroutines: 1,
658 }
659 runtimePkg := i.prog.ImportedPackage("runtime")
660 if runtimePkg == nil {
661 panic("ssa.Program doesn't include runtime package")
662 }
663 i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
664
665 initReflect(i)
666
667 i.osArgs = append(i.osArgs, filename)
668 for _, arg := range args {
669 i.osArgs = append(i.osArgs, arg)
670 }
671
672 for _, pkg := range i.prog.AllPackages() {
673
674 for _, m := range pkg.Members {
675 switch v := m.(type) {
676 case *ssa.Global:
677 cell := zero(typeparams.MustDeref(v.Type()))
678 i.globals[v] = &cell
679 }
680 }
681 }
682
683
684 exitCode = 2
685 defer func() {
686 if exitCode != 2 || i.mode&DisableRecover != 0 {
687 return
688 }
689 switch p := recover().(type) {
690 case exitPanic:
691 exitCode = int(p)
692 return
693 case targetPanic:
694 fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
695 case runtime.Error:
696 fmt.Fprintln(os.Stderr, "panic:", p.Error())
697 case string:
698 fmt.Fprintln(os.Stderr, "panic:", p)
699 default:
700 fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
701 }
702
703
704
705
706
707
708 }()
709
710
711 call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
712 if mainFn := mainpkg.Func("main"); mainFn != nil {
713 call(i, nil, token.NoPos, mainFn, nil)
714 exitCode = 0
715 } else {
716 fmt.Fprintln(os.Stderr, "No main function.")
717 exitCode = 1
718 }
719 return
720 }
721
View as plain text