├── interp ├── testdata │ ├── b_test.go │ ├── reflect.go │ ├── a_test.go │ ├── recover.go │ ├── range.go │ ├── ifaceprom.go │ ├── defer.go │ ├── static.go │ ├── methprom.go │ ├── callstack.go │ ├── initorder.go │ ├── mrvchain.go │ ├── ifaceconv.go │ ├── fieldprom.go │ ├── boundmeth.go │ ├── complit.go │ └── coverage.go ├── functionInfo.go ├── external_freebsd.go ├── external_darwin.go ├── interpgen │ └── gen.go ├── external_windows.go ├── external_plan9.go ├── map.go ├── addexternals.go ├── external_unix.go ├── interp_test.go ├── value.go ├── reflect.go ├── external.go ├── interp.go ├── generated.go └── preprocess.go ├── .gitignore ├── example_test.go ├── README.md ├── LICENSE ├── benchmark_test.go ├── ssainterp_test.go └── ssainterp.go /interp/testdata/b_test.go: -------------------------------------------------------------------------------- 1 | package b 2 | 3 | import "testing" 4 | 5 | func NotATest(t *testing.T) { 6 | t.Error("foo") 7 | } 8 | 9 | func NotABenchmark(b *testing.B) { 10 | b.Error("wiz") 11 | } 12 | -------------------------------------------------------------------------------- /interp/testdata/reflect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "reflect" 4 | 5 | func main() { 6 | // Regression test for issue 9462. 7 | got := reflect.SliceOf(reflect.TypeOf(byte(0))).String() 8 | if got != "[]uint8" && got != "[]byte" { // result varies by toolchain 9 | println("BUG: " + got) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /interp/testdata/a_test.go: -------------------------------------------------------------------------------- 1 | package a 2 | 3 | import "testing" 4 | 5 | func TestFoo(t *testing.T) { 6 | t.Error("foo") 7 | } 8 | 9 | func TestBar(t *testing.T) { 10 | t.Error("bar") 11 | } 12 | 13 | func BenchmarkWiz(b *testing.B) { 14 | b.Error("wiz") 15 | } 16 | 17 | // Don't test Examples since that testing package needs pipe(2) for that. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /interp/functionInfo.go: -------------------------------------------------------------------------------- 1 | package interp 2 | 3 | import ( 4 | "fmt" 5 | 6 | "golang.org/x/tools/go/ssa" 7 | ) 8 | 9 | type functionInfo struct { 10 | instrs [][]func(*frame) 11 | envEntries map[ssa.Value]int 12 | } 13 | 14 | func envEnt(fr *frame, key ssa.Value) int { 15 | ent, ok := fr.i.functions[fr.fn].envEntries[key] 16 | if !ok { 17 | panic(fmt.Sprintf("envRnt: no Ivalue for %T: %v", key, key.Name())) 18 | } 19 | return ent 20 | } 21 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package ssainterp_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/go-interpreter/ssainterp" 8 | ) 9 | 10 | const code = ` 11 | package main 12 | 13 | import "fmt" 14 | 15 | func main() { 16 | fmt.Println("42") 17 | } 18 | 19 | ` 20 | 21 | // ExampleRun trivial example, more to add. 22 | func ExampleRun() { 23 | var output bytes.Buffer 24 | ssainterp.Run(code, nil, nil, &output) 25 | fmt.Println(output.String()) 26 | // Output: 42 27 | } 28 | -------------------------------------------------------------------------------- /interp/testdata/recover.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of panic/recover. 4 | 5 | import "fmt" 6 | 7 | func fortyTwo() (r int) { 8 | r = 42 9 | // The next two statements simulate a 'return' statement. 10 | defer func() { recover() }() 11 | panic(nil) 12 | } 13 | 14 | func zero() int { 15 | defer func() { recover() }() 16 | panic(1) 17 | } 18 | 19 | func zeroEmpty() (int, string) { 20 | defer func() { recover() }() 21 | panic(1) 22 | } 23 | 24 | func main() { 25 | if r := fortyTwo(); r != 42 { 26 | panic(r) 27 | } 28 | if r := zero(); r != 0 { 29 | panic(r) 30 | } 31 | if r, s := zeroEmpty(); r != 0 || s != "" { 32 | panic(fmt.Sprint(r, s)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /interp/external_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd 6 | 7 | package interp 8 | 9 | import "syscall" 10 | 11 | func init() { 12 | externals["syscall.Sysctl"] = ext۰syscall۰Sysctl 13 | externals["syscall.SysctlUint32"] = ext۰syscall۰SysctlUint32 14 | } 15 | 16 | func ext۰syscall۰Sysctl(fr *frame, args []Ivalue) Ivalue { 17 | r, err := syscall.Sysctl(args[0].(string)) 18 | return tuple{r, wrapError(err)} 19 | } 20 | 21 | func ext۰syscall۰SysctlUint32(fr *frame, args []Ivalue) Ivalue { 22 | r, err := syscall.SysctlUint32(args[0].(string)) 23 | return tuple{r, wrapError(err)} 24 | } 25 | -------------------------------------------------------------------------------- /interp/external_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin 6 | 7 | package interp 8 | 9 | import "syscall" 10 | 11 | func init() { 12 | externals["syscall.Sysctl"] = ext۰syscall۰Sysctl 13 | externals["syscall.Syscall6"] = ext۰syscall۰Syscall6 14 | } 15 | 16 | func ext۰syscall۰Sysctl(fr *frame, args []Ivalue) Ivalue { 17 | r, err := syscall.Sysctl(args[0].(string)) 18 | return tuple{r, wrapError(err)} 19 | } 20 | 21 | func ext۰syscall۰Syscall6(fr *frame, args []Ivalue) Ivalue { 22 | // func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) 23 | var a [7]uintptr 24 | for i := range a { 25 | a[i] = args[i].(uintptr) 26 | } 27 | r1, r2, err := syscall.Syscall6(a[0], a[1], a[2], a[3], a[4], a[5], a[6]) 28 | return tuple{r1, r2, wrapError(err)} 29 | } 30 | -------------------------------------------------------------------------------- /interp/testdata/range.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of range loops. 4 | 5 | import "fmt" 6 | 7 | // Range over string. 8 | func init() { 9 | if x := len("Hello, 世界"); x != 13 { // bytes 10 | panic(x) 11 | } 12 | var indices []int 13 | var runes []rune 14 | for i, r := range "Hello, 世界" { 15 | runes = append(runes, r) 16 | indices = append(indices, i) 17 | } 18 | if x := fmt.Sprint(runes); x != "[72 101 108 108 111 44 32 19990 30028]" { 19 | panic(x) 20 | } 21 | if x := fmt.Sprint(indices); x != "[0 1 2 3 4 5 6 7 10]" { 22 | panic(x) 23 | } 24 | s := "" 25 | for _, r := range runes { 26 | s = fmt.Sprintf("%s%c", s, r) 27 | } 28 | if s != "Hello, 世界" { 29 | panic(s) 30 | } 31 | 32 | var x int 33 | for range "Hello, 世界" { 34 | x++ 35 | } 36 | if x != len(indices) { 37 | panic(x) 38 | } 39 | } 40 | 41 | // Regression test for range of pointer to named array type. 42 | func init() { 43 | type intarr [3]int 44 | ia := intarr{1, 2, 3} 45 | var count int 46 | for _, x := range &ia { 47 | count += x 48 | } 49 | if count != 6 { 50 | panic(count) 51 | } 52 | } 53 | 54 | func main() { 55 | } 56 | -------------------------------------------------------------------------------- /interp/testdata/ifaceprom.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Test of promotion of methods of an interface embedded within a 4 | // struct. In particular, this test exercises that the correct 5 | // method is called. 6 | 7 | type I interface { 8 | one() int 9 | two() string 10 | } 11 | 12 | type S struct { 13 | I 14 | } 15 | 16 | type impl struct{} 17 | 18 | func (impl) one() int { 19 | return 1 20 | } 21 | 22 | func (impl) two() string { 23 | return "two" 24 | } 25 | 26 | func main() { 27 | var s S 28 | s.I = impl{} 29 | if one := s.I.one(); one != 1 { 30 | panic(one) 31 | } 32 | if one := s.one(); one != 1 { 33 | panic(one) 34 | } 35 | closOne := s.I.one 36 | if one := closOne(); one != 1 { 37 | panic(one) 38 | } 39 | closOne = s.one 40 | if one := closOne(); one != 1 { 41 | panic(one) 42 | } 43 | 44 | if two := s.I.two(); two != "two" { 45 | panic(two) 46 | } 47 | if two := s.two(); two != "two" { 48 | panic(two) 49 | } 50 | closTwo := s.I.two 51 | if two := closTwo(); two != "two" { 52 | panic(two) 53 | } 54 | closTwo = s.two 55 | if two := closTwo(); two != "two" { 56 | panic(two) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOT WORKING, PLEASE HELP 2 | 3 | # ssainterp 4 | A Golang interpreter, built upon [golang.org/x/tools/go/ssa/interp](https://godoc.org/golang.org/x/tools/go/ssa/interp). That original code contains the comment that "It is not, and will never be, a production-quality Go interpreter.", but that does not mean that it could not be of use in some very limited circumstances. 5 | 6 | The planned use-case for this interpreter is where there is no access to a Go compiler in the production environment, for example in an embedded system or in Google App Engine. 7 | 8 | ### NOT PRODUCTION READY 9 | 10 | This code is a work-in-progress. 11 | It is neither fully working nor properly documented, and is full of security vulnerabilities. 12 | 13 | The tests are only known to pass on OSX & Ubuntu. The very simple benchmark suggests this interpreter runs 881x slower than compiled code, but 12x faster than the original implementation it was developed from. 14 | 15 | Some ideas for future development were set-out in a [discussion document](https://docs.google.com/document/d/1Hvxf6NMPaCUd-1iqm_968SuHN1Vf8dLZQyHjvPyVE0Q/edit?usp=sharing). 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /interp/interpgen/gen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io/ioutil" 4 | 5 | import "unicode" 6 | 7 | func main() { 8 | numT := []string{"int", "int8", "int16", "int32", "int64", 9 | "uint", "uint8", "uint16", "uint32", "uint64", 10 | "uintptr", "float32", "float64"} 11 | 12 | fns := "" 13 | 14 | body := "\tswitch srcT {\n" 15 | for s := range numT { 16 | styp := string(unicode.ToUpper(rune(numT[s][0]))) + numT[s][1:] 17 | body += "\tcase types." + styp + ":\n" 18 | body += "\t\tswitch desT {\n" 19 | for d := range numT { 20 | dtyp := string(unicode.ToUpper(rune(numT[d][0]))) + numT[d][1:] 21 | body += "\t\tcase types." + dtyp + ":\n" 22 | fname := "easyConvTo" + dtyp + "From" + styp 23 | body += "\t\t\treturn " + fname + "\n" 24 | fns += "func " + fname + "(v Ivalue) Ivalue {\n" 25 | fns += "\treturn " + numT[d] + "(v.(" + numT[s] + "))\n" 26 | fns += "}\n\n" 27 | } 28 | body += "\t\t}\n" 29 | } 30 | body += "\t}\n" 31 | 32 | ioutil.WriteFile("generated.go", []byte(`package interp 33 | 34 | import "go/types" 35 | 36 | `+fns+` 37 | func easyConvFunc(desT, srcT types.BasicKind) func(Ivalue) Ivalue { 38 | `+body+` 39 | return nil 40 | } 41 | `), 0666) 42 | } 43 | -------------------------------------------------------------------------------- /interp/testdata/defer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of defer. (Deferred recover() belongs is recover.go.) 4 | 5 | import "fmt" 6 | 7 | func deferMutatesResults(noArgReturn bool) (a, b int) { 8 | defer func() { 9 | if a != 1 || b != 2 { 10 | panic(fmt.Sprint(a, b)) 11 | } 12 | a, b = 3, 4 13 | }() 14 | if noArgReturn { 15 | a, b = 1, 2 16 | return 17 | } 18 | return 1, 2 19 | } 20 | 21 | func init() { 22 | a, b := deferMutatesResults(true) 23 | if a != 3 || b != 4 { 24 | panic(fmt.Sprint(a, b)) 25 | } 26 | a, b = deferMutatesResults(false) 27 | if a != 3 || b != 4 { 28 | panic(fmt.Sprint(a, b)) 29 | } 30 | } 31 | 32 | // We concatenate init blocks to make a single function, but we must 33 | // run defers at the end of each block, not the combined function. 34 | var deferCount = 0 35 | 36 | func init() { 37 | deferCount = 1 38 | defer func() { 39 | deferCount++ 40 | }() 41 | // defer runs HERE 42 | } 43 | 44 | func init() { 45 | // Strictly speaking the spec says deferCount may be 0 or 2 46 | // since the relative order of init blocks is unspecified. 47 | if deferCount != 2 { 48 | panic(deferCount) // defer call has not run! 49 | } 50 | } 51 | 52 | func main() { 53 | } 54 | -------------------------------------------------------------------------------- /interp/testdata/static.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Static tests of SSA builder (via the sanity checker). 4 | // Dynamic semantics are not exercised. 5 | 6 | func init() { 7 | // Regression test for issue 6806. 8 | ch := make(chan int) 9 | select { 10 | case n, _ := <-ch: 11 | _ = n 12 | default: 13 | // The default case disables the simplification of 14 | // select to a simple receive statement. 15 | } 16 | 17 | // Ivalue,ok-form receive where TypeOf(ok) is a named boolean. 18 | type mybool bool 19 | var x int 20 | var y mybool 21 | select { 22 | case x, y = <-ch: 23 | default: 24 | // The default case disables the simplification of 25 | // select to a simple receive statement. 26 | } 27 | _ = x 28 | _ = y 29 | } 30 | 31 | var a int 32 | 33 | // Regression test for issue 7840 (covered by SSA sanity checker). 34 | func bug7840() bool { 35 | // This creates a single-predecessor block with a φ-node. 36 | return false && a == 0 && a == 0 37 | } 38 | 39 | // A blocking select (sans "default:") cannot fall through. 40 | // Regression test for issue 7022. 41 | func bug7022() int { 42 | var c1, c2 chan int 43 | select { 44 | case <-c1: 45 | return 123 46 | case <-c2: 47 | return 456 48 | } 49 | } 50 | 51 | // Parens should not prevent intrinsic treatment of built-ins. 52 | // (Regression test for a crash.) 53 | func init() { 54 | _ = (new)(int) 55 | _ = (make)([]int, 0) 56 | } 57 | 58 | func main() {} 59 | -------------------------------------------------------------------------------- /interp/testdata/methprom.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of method promotion logic. 4 | 5 | type A struct{ magic int } 6 | 7 | func (a A) x() { 8 | if a.magic != 1 { 9 | panic(a.magic) 10 | } 11 | } 12 | func (a *A) y() *A { 13 | return a 14 | } 15 | 16 | type B struct{ magic int } 17 | 18 | func (b B) p() { 19 | if b.magic != 2 { 20 | panic(b.magic) 21 | } 22 | } 23 | func (b *B) q() { 24 | if b != theC.B { 25 | panic("oops") 26 | } 27 | } 28 | 29 | type I interface { 30 | f() 31 | } 32 | 33 | type impl struct{ magic int } 34 | 35 | func (i impl) f() { 36 | if i.magic != 3 { 37 | panic("oops") 38 | } 39 | } 40 | 41 | type C struct { 42 | A 43 | *B 44 | I 45 | } 46 | 47 | func assert(cond bool) { 48 | if !cond { 49 | panic("failed") 50 | } 51 | } 52 | 53 | var theC = C{ 54 | A: A{1}, 55 | B: &B{2}, 56 | I: impl{3}, 57 | } 58 | 59 | func addr() *C { 60 | return &theC 61 | } 62 | 63 | func Ivalue() C { 64 | return theC 65 | } 66 | 67 | func main() { 68 | // address 69 | addr().x() 70 | if addr().y() != &theC.A { 71 | panic("oops") 72 | } 73 | addr().p() 74 | addr().q() 75 | addr().f() 76 | 77 | // addressable Ivalue 78 | var c C = Ivalue() 79 | c.x() 80 | if c.y() != &c.A { 81 | panic("oops") 82 | } 83 | c.p() 84 | c.q() 85 | c.f() 86 | 87 | // non-addressable Ivalue 88 | Ivalue().x() 89 | // Ivalue().y() // not in method set 90 | Ivalue().p() 91 | Ivalue().q() 92 | Ivalue().f() 93 | } 94 | -------------------------------------------------------------------------------- /interp/testdata/callstack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "runtime" 7 | "strings" 8 | ) 9 | 10 | var stack string 11 | 12 | func f() { 13 | pc := make([]uintptr, 6) 14 | pc = pc[:runtime.Callers(1, pc)] 15 | for _, f := range pc { 16 | Func := runtime.FuncForPC(f) 17 | name := Func.Name() 18 | if strings.Contains(name, "$") || strings.Contains(name, ".func") { 19 | name = "func" // anon funcs vary across toolchains 20 | } 21 | file, line := Func.FileLine(0) 22 | stack += fmt.Sprintf("%s at %s:%d\n", name, path.Base(file), line) 23 | } 24 | } 25 | 26 | func g() { f() } 27 | func h() { g() } 28 | func i() { func() { h() }() } 29 | 30 | // Hack: the 'func' and the call to Caller are on the same line, 31 | // to paper over differences between toolchains. 32 | // (The interpreter's location info isn't yet complete.) 33 | func runtimeCaller0() (uintptr, string, int, bool) { return runtime.Caller(0) } 34 | 35 | func main() { 36 | i() 37 | if stack != `main.f at callstack.go:12 38 | main.g at callstack.go:26 39 | main.h at callstack.go:27 40 | func at callstack.go:28 41 | main.i at callstack.go:28 42 | main.main at callstack.go:35 43 | ` { 44 | panic("unexpected stack: " + stack) 45 | } 46 | 47 | pc, file, line, _ := runtimeCaller0() 48 | got := fmt.Sprintf("%s @ %s:%d", runtime.FuncForPC(pc).Name(), path.Base(file), line) 49 | if got != "main.runtimeCaller0 @ callstack.go:33" { 50 | panic("runtime.Caller: " + got) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /interp/testdata/initorder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Test of initialization order of package-level vars. 6 | 7 | var counter int 8 | 9 | func next() int { 10 | c := counter 11 | counter++ 12 | return c 13 | } 14 | 15 | func next2() (x int, y int) { 16 | x = next() 17 | y = next() 18 | return 19 | } 20 | 21 | func makeOrder() int { 22 | _, _, _, _ = f, b, d, e 23 | return 0 24 | } 25 | 26 | func main() { 27 | // Initialization constraints: 28 | // - {f,b,c/d,e} < order (ref graph traversal) 29 | // - order < {a} (lexical order) 30 | // - b < c/d < e < f (lexical order) 31 | // Solution: a b c/d e f 32 | abcdef := [6]int{a, b, c, d, e, f} 33 | if abcdef != [6]int{0, 1, 2, 3, 4, 5} { 34 | panic(abcdef) 35 | } 36 | } 37 | 38 | var order = makeOrder() 39 | 40 | var a, b = next(), next() 41 | var c, d = next2() 42 | var e, f = next(), next() 43 | 44 | // ------------------------------------------------------------------------ 45 | 46 | var order2 []string 47 | 48 | func create(x int, name string) int { 49 | order2 = append(order2, name) 50 | return x 51 | } 52 | 53 | var C = create(B+1, "C") 54 | var A, B = create(1, "A"), create(2, "B") 55 | 56 | // Initialization order of package-level Ivalue specs. 57 | func init() { 58 | x := fmt.Sprint(order2) 59 | // Result varies by toolchain. This is a spec bug. 60 | if x != "[B C A]" && // gc 61 | x != "[A B C]" { // go/types 62 | panic(x) 63 | } 64 | if C != 3 { 65 | panic(c) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /interp/testdata/mrvchain.go: -------------------------------------------------------------------------------- 1 | // Tests of call chaining f(g()) when g has multiple return Ivalues (MRVs). 2 | // See https://code.google.com/p/go/issues/detail?id=4573. 3 | 4 | package main 5 | 6 | func assert(actual, expected int) { 7 | if actual != expected { 8 | panic(actual) 9 | } 10 | } 11 | 12 | func g() (int, int) { 13 | return 5, 7 14 | } 15 | 16 | func g2() (float64, float64) { 17 | return 5, 7 18 | } 19 | 20 | func f1v(x int, v ...int) { 21 | assert(x, 5) 22 | assert(v[0], 7) 23 | } 24 | 25 | func f2(x, y int) { 26 | assert(x, 5) 27 | assert(y, 7) 28 | } 29 | 30 | func f2v(x, y int, v ...int) { 31 | assert(x, 5) 32 | assert(y, 7) 33 | assert(len(v), 0) 34 | } 35 | 36 | func complexArgs() (float64, float64) { 37 | return 5, 7 38 | } 39 | 40 | func appendArgs() ([]string, string) { 41 | return []string{"foo"}, "bar" 42 | } 43 | 44 | func h() (i interface{}, ok bool) { 45 | m := map[int]string{1: "hi"} 46 | i, ok = m[1] // string->interface{} conversion within multi-Ivalued expression 47 | return 48 | } 49 | 50 | func h2() (i interface{}, ok bool) { 51 | ch := make(chan string, 1) 52 | ch <- "hi" 53 | i, ok = <-ch // string->interface{} conversion within multi-Ivalued expression 54 | return 55 | } 56 | 57 | func main() { 58 | f1v(g()) 59 | f2(g()) 60 | f2v(g()) 61 | if c := complex(complexArgs()); c != 5+7i { 62 | panic(c) 63 | } 64 | if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" { 65 | panic(s) 66 | } 67 | i, ok := h() 68 | if !ok || i.(string) != "hi" { 69 | panic(i) 70 | } 71 | i, ok = h2() 72 | if !ok || i.(string) != "hi" { 73 | panic(i) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /interp/external_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | import "syscall" 8 | 9 | func ext۰syscall۰Close(fr *frame, args []Ivalue) Ivalue { 10 | panic("syscall.Close not yet implemented") 11 | } 12 | func ext۰syscall۰Fstat(fr *frame, args []Ivalue) Ivalue { 13 | panic("syscall.Fstat not yet implemented") 14 | } 15 | func ext۰syscall۰Kill(fr *frame, args []Ivalue) Ivalue { 16 | panic("syscall.Kill not yet implemented") 17 | } 18 | func ext۰syscall۰Lstat(fr *frame, args []Ivalue) Ivalue { 19 | panic("syscall.Lstat not yet implemented") 20 | } 21 | func ext۰syscall۰Open(fr *frame, args []Ivalue) Ivalue { 22 | panic("syscall.Open not yet implemented") 23 | } 24 | func ext۰syscall۰ParseDirent(fr *frame, args []Ivalue) Ivalue { 25 | panic("syscall.ParseDirent not yet implemented") 26 | } 27 | func ext۰syscall۰Read(fr *frame, args []Ivalue) Ivalue { 28 | panic("syscall.Read not yet implemented") 29 | } 30 | func ext۰syscall۰ReadDirent(fr *frame, args []Ivalue) Ivalue { 31 | panic("syscall.ReadDirent not yet implemented") 32 | } 33 | func ext۰syscall۰Stat(fr *frame, args []Ivalue) Ivalue { 34 | panic("syscall.Stat not yet implemented") 35 | } 36 | func ext۰syscall۰Write(fr *frame, args []Ivalue) Ivalue { 37 | panic("syscall.Write not yet implemented") 38 | } 39 | func ext۰syscall۰RawSyscall(fr *frame, args []Ivalue) Ivalue { 40 | return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)} 41 | } 42 | func syswrite(fd int, b []byte) (int, error) { 43 | panic("syswrite not yet implemented") 44 | } 45 | -------------------------------------------------------------------------------- /interp/testdata/ifaceconv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of interface conversions and type assertions. 4 | 5 | type I0 interface { 6 | } 7 | type I1 interface { 8 | f() 9 | } 10 | type I2 interface { 11 | f() 12 | g() 13 | } 14 | 15 | type C0 struct{} 16 | type C1 struct{} 17 | 18 | func (C1) f() {} 19 | 20 | type C2 struct{} 21 | 22 | func (C2) f() {} 23 | func (C2) g() {} 24 | 25 | func main() { 26 | var i0 I0 27 | var i1 I1 28 | var i2 I2 29 | 30 | // Nil always causes a type assertion to fail, even to the 31 | // same type. 32 | if _, ok := i0.(I0); ok { 33 | panic("nil i0.(I0) succeeded") 34 | } 35 | if _, ok := i1.(I1); ok { 36 | panic("nil i1.(I1) succeeded") 37 | } 38 | if _, ok := i2.(I2); ok { 39 | panic("nil i2.(I2) succeeded") 40 | } 41 | 42 | // Conversions can't fail, even with nil. 43 | _ = I0(i0) 44 | 45 | _ = I0(i1) 46 | _ = I1(i1) 47 | 48 | _ = I0(i2) 49 | _ = I1(i2) 50 | _ = I2(i2) 51 | 52 | // Non-nil type assertions pass or fail based on the concrete type. 53 | i1 = C1{} 54 | if _, ok := i1.(I0); !ok { 55 | panic("C1 i1.(I0) failed") 56 | } 57 | if _, ok := i1.(I1); !ok { 58 | panic("C1 i1.(I1) failed") 59 | } 60 | if _, ok := i1.(I2); ok { 61 | panic("C1 i1.(I2) succeeded") 62 | } 63 | 64 | i1 = C2{} 65 | if _, ok := i1.(I0); !ok { 66 | panic("C2 i1.(I0) failed") 67 | } 68 | if _, ok := i1.(I1); !ok { 69 | panic("C2 i1.(I1) failed") 70 | } 71 | if _, ok := i1.(I2); !ok { 72 | panic("C2 i1.(I2) failed") 73 | } 74 | 75 | // Conversions can't fail. 76 | i1 = C1{} 77 | if I0(i1) == nil { 78 | panic("C1 I0(i1) was nil") 79 | } 80 | if I1(i1) == nil { 81 | panic("C1 I1(i1) was nil") 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /interp/external_plan9.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | import "syscall" 8 | 9 | func ext۰syscall۰Close(fr *frame, args []Ivalue) Ivalue { 10 | panic("syscall.Close not yet implemented") 11 | } 12 | func ext۰syscall۰Fstat(fr *frame, args []Ivalue) Ivalue { 13 | panic("syscall.Fstat not yet implemented") 14 | } 15 | func ext۰syscall۰Kill(fr *frame, args []Ivalue) Ivalue { 16 | panic("syscall.Kill not yet implemented") 17 | } 18 | func ext۰syscall۰Lstat(fr *frame, args []Ivalue) Ivalue { 19 | panic("syscall.Lstat not yet implemented") 20 | } 21 | func ext۰syscall۰Open(fr *frame, args []Ivalue) Ivalue { 22 | panic("syscall.Open not yet implemented") 23 | } 24 | func ext۰syscall۰ParseDirent(fr *frame, args []Ivalue) Ivalue { 25 | panic("syscall.ParseDirent not yet implemented") 26 | } 27 | func ext۰syscall۰Read(fr *frame, args []Ivalue) Ivalue { 28 | panic("syscall.Read not yet implemented") 29 | } 30 | func ext۰syscall۰ReadDirent(fr *frame, args []Ivalue) Ivalue { 31 | panic("syscall.ReadDirent not yet implemented") 32 | } 33 | func ext۰syscall۰Stat(fr *frame, args []Ivalue) Ivalue { 34 | panic("syscall.Stat not yet implemented") 35 | } 36 | func ext۰syscall۰Write(fr *frame, args []Ivalue) Ivalue { 37 | // func Write(fd int, p []byte) (n int, err error) 38 | n, err := write(args[0].(int), IvalueToBytes(args[1])) 39 | return tuple{n, wrapError(err)} 40 | } 41 | func ext۰syscall۰RawSyscall(fr *frame, args []Ivalue) Ivalue { 42 | return tuple{^uintptr(0), uintptr(0), uintptr(0)} 43 | } 44 | 45 | func syswrite(fd int, b []byte) (int, error) { 46 | return syscall.Write(fd, b) 47 | } 48 | -------------------------------------------------------------------------------- /benchmark_test.go: -------------------------------------------------------------------------------- 1 | package ssainterp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "go/types" 7 | 8 | "github.com/go-interpreter/ssainterp" 9 | "github.com/go-interpreter/ssainterp/interp" 10 | 11 | orig "golang.org/x/tools/go/ssa/interp" 12 | ) 13 | 14 | // just using http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go 15 | func Fib(n int) int { 16 | if n < 2 { 17 | return n 18 | } 19 | return Fib(n-1) + Fib(n-2) 20 | } 21 | 22 | func BenchmarkFib10Native(b *testing.B) { 23 | // run the Fib function b.N times 24 | for n := 0; n < b.N; n++ { 25 | Fib(10) 26 | } 27 | } 28 | 29 | const codeFib = ` 30 | package main 31 | func main(){} 32 | func Fib(n int) int { 33 | if n < 2 { 34 | return n 35 | } 36 | return Fib(n-1) + Fib(n-2) 37 | } 38 | ` 39 | 40 | var ctx *ssainterp.Interpreter 41 | 42 | func init() { 43 | var err error 44 | ctx, _, err = ssainterp.Run(codeFib, nil, nil, nil) 45 | if err != nil { 46 | panic(err) 47 | } 48 | } 49 | 50 | func BenchmarkFib10SSAinterp(b *testing.B) { 51 | // run the Fib function b.N times 52 | for n := 0; n < b.N; n++ { 53 | ctx.Call("main.Fib", []interp.Ivalue{interp.Ivalue(10)}) 54 | } 55 | } 56 | 57 | const codeFib10Orig = ` 58 | package main 59 | func main(){ Fib(10) } 60 | func Fib(n int) int { 61 | if n < 2 { 62 | return n 63 | } 64 | return Fib(n-1) + Fib(n-2) 65 | } 66 | ` 67 | 68 | var ctxOrig *ssainterp.Interpreter 69 | 70 | func init() { 71 | var err error 72 | ctxOrig, _, err = ssainterp.Run(codeFib10Orig, nil, nil, nil) 73 | if err != nil { 74 | panic(err) 75 | } 76 | } 77 | 78 | func BenchmarkFib10Orig(b *testing.B) { 79 | // run the Fib function b.N times 80 | for n := 0; n < b.N; n++ { 81 | ec := orig.Interpret(ctxOrig.MainPkg, 0, &types.StdSizes{8, 8}, "filename.go", nil) 82 | if ec != 0 { 83 | b.Fatalf("returned error code non-zero:%d", ec) 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /interp/testdata/fieldprom.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of field promotion logic. 4 | 5 | type A struct { 6 | x int 7 | y *int 8 | } 9 | 10 | type B struct { 11 | p int 12 | q *int 13 | } 14 | 15 | type C struct { 16 | A 17 | *B 18 | } 19 | 20 | type D struct { 21 | a int 22 | C 23 | } 24 | 25 | func assert(cond bool) { 26 | if !cond { 27 | panic("failed") 28 | } 29 | } 30 | 31 | func f1(c C) { 32 | assert(c.x == c.A.x) 33 | assert(c.y == c.A.y) 34 | assert(&c.x == &c.A.x) 35 | assert(&c.y == &c.A.y) 36 | 37 | assert(c.p == c.B.p) 38 | assert(c.q == c.B.q) 39 | assert(&c.p == &c.B.p) 40 | assert(&c.q == &c.B.q) 41 | 42 | c.x = 1 43 | *c.y = 1 44 | c.p = 1 45 | *c.q = 1 46 | } 47 | 48 | func f2(c *C) { 49 | assert(c.x == c.A.x) 50 | assert(c.y == c.A.y) 51 | assert(&c.x == &c.A.x) 52 | assert(&c.y == &c.A.y) 53 | 54 | assert(c.p == c.B.p) 55 | assert(c.q == c.B.q) 56 | assert(&c.p == &c.B.p) 57 | assert(&c.q == &c.B.q) 58 | 59 | c.x = 1 60 | *c.y = 1 61 | c.p = 1 62 | *c.q = 1 63 | } 64 | 65 | func f3(d D) { 66 | assert(d.x == d.C.A.x) 67 | assert(d.y == d.C.A.y) 68 | assert(&d.x == &d.C.A.x) 69 | assert(&d.y == &d.C.A.y) 70 | 71 | assert(d.p == d.C.B.p) 72 | assert(d.q == d.C.B.q) 73 | assert(&d.p == &d.C.B.p) 74 | assert(&d.q == &d.C.B.q) 75 | 76 | d.x = 1 77 | *d.y = 1 78 | d.p = 1 79 | *d.q = 1 80 | } 81 | 82 | func f4(d *D) { 83 | assert(d.x == d.C.A.x) 84 | assert(d.y == d.C.A.y) 85 | assert(&d.x == &d.C.A.x) 86 | assert(&d.y == &d.C.A.y) 87 | 88 | assert(d.p == d.C.B.p) 89 | assert(d.q == d.C.B.q) 90 | assert(&d.p == &d.C.B.p) 91 | assert(&d.q == &d.C.B.q) 92 | 93 | d.x = 1 94 | *d.y = 1 95 | d.p = 1 96 | *d.q = 1 97 | } 98 | 99 | func main() { 100 | y := 123 101 | c := C{ 102 | A{x: 42, y: &y}, 103 | &B{p: 42, q: &y}, 104 | } 105 | 106 | assert(&c.x == &c.A.x) 107 | 108 | f1(c) 109 | f2(&c) 110 | 111 | d := D{C: c} 112 | f3(d) 113 | f4(&d) 114 | } 115 | -------------------------------------------------------------------------------- /interp/testdata/boundmeth.go: -------------------------------------------------------------------------------- 1 | // Tests of bound method closures. 2 | 3 | package main 4 | 5 | import "fmt" 6 | 7 | func assert(b bool) { 8 | if !b { 9 | panic("oops") 10 | } 11 | } 12 | 13 | type I int 14 | 15 | func (i I) add(x int) int { 16 | return int(i) + x 17 | } 18 | 19 | func IvalueReceiver() { 20 | var three I = 3 21 | assert(three.add(5) == 8) 22 | var add3 func(int) int = three.add 23 | assert(add3(5) == 8) 24 | } 25 | 26 | type S struct{ x int } 27 | 28 | func (s *S) incr() { 29 | s.x++ 30 | } 31 | 32 | func (s *S) get() int { 33 | return s.x 34 | } 35 | 36 | func pointerReceiver() { 37 | ps := new(S) 38 | incr := ps.incr 39 | get := ps.get 40 | assert(get() == 0) 41 | incr() 42 | incr() 43 | incr() 44 | assert(get() == 3) 45 | } 46 | 47 | func addressibleIvaluePointerReceiver() { 48 | var s S 49 | incr := s.incr 50 | get := s.get 51 | assert(get() == 0) 52 | incr() 53 | incr() 54 | incr() 55 | assert(get() == 3) 56 | } 57 | 58 | type S2 struct { 59 | S 60 | } 61 | 62 | func promotedReceiver() { 63 | var s2 S2 64 | incr := s2.incr 65 | get := s2.get 66 | assert(get() == 0) 67 | incr() 68 | incr() 69 | incr() 70 | assert(get() == 3) 71 | } 72 | 73 | func anonStruct() { 74 | var s struct{ S } 75 | incr := s.incr 76 | get := s.get 77 | assert(get() == 0) 78 | incr() 79 | incr() 80 | incr() 81 | assert(get() == 3) 82 | } 83 | 84 | func typeCheck() { 85 | var i interface{} 86 | i = (*S).incr 87 | _ = i.(func(*S)) // type assertion: receiver type prepended to params 88 | 89 | var s S 90 | i = s.incr 91 | _ = i.(func()) // type assertion: receiver type disappears 92 | } 93 | 94 | type errString string 95 | 96 | func (err errString) Error() string { 97 | return string(err) 98 | } 99 | 100 | // Regression test for a builder crash. 101 | func regress1(x error) func() string { 102 | return x.Error 103 | } 104 | 105 | // Regression test for b/7269: 106 | // taking the Ivalue of an interface method performs a nil check. 107 | func nilInterfaceMethodIvalue() { 108 | err := fmt.Errorf("ok") 109 | f := err.Error 110 | if got := f(); got != "ok" { 111 | panic(got) 112 | } 113 | 114 | err = nil 115 | if got := f(); got != "ok" { 116 | panic(got) 117 | } 118 | 119 | defer func() { 120 | r := fmt.Sprint(recover()) 121 | // runtime panic string varies across toolchains 122 | if r != "runtime error: interface conversion: interface is nil, not error" && 123 | r != "runtime error: invalid memory address or nil pointer dereference" { 124 | panic("want runtime panic from nil interface method Ivalue, got " + r) 125 | } 126 | }() 127 | f = err.Error // runtime panic: err is nil 128 | panic("unreachable") 129 | } 130 | 131 | func main() { 132 | IvalueReceiver() 133 | pointerReceiver() 134 | addressibleIvaluePointerReceiver() 135 | promotedReceiver() 136 | anonStruct() 137 | typeCheck() 138 | 139 | if e := regress1(errString("hi"))(); e != "hi" { 140 | panic(e) 141 | } 142 | 143 | nilInterfaceMethodIvalue() 144 | } 145 | -------------------------------------------------------------------------------- /ssainterp_test.go: -------------------------------------------------------------------------------- 1 | package ssainterp_test 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/go-interpreter/ssainterp" 8 | "github.com/go-interpreter/ssainterp/interp" 9 | ) 10 | 11 | func TestOutputCapture(t *testing.T) { 12 | var out bytes.Buffer 13 | 14 | _, _, err := ssainterp.Run(` 15 | package main 16 | 17 | func main() { 18 | println("TEST-OUTPUT") 19 | } 20 | `, nil, nil, &out) 21 | if err != nil { 22 | t.Error(err) 23 | } 24 | s := string(out.Bytes()) 25 | if s != "TEST-OUTPUT\n" { 26 | t.Error("output not as expected:" + s) 27 | } 28 | } 29 | 30 | func TestCallInOut(t *testing.T) { 31 | ctxt, exitCode, err := ssainterp.Run(` 32 | package main 33 | 34 | // function to call into proper Go 35 | func Foo(a,b int) int 36 | 37 | // function to be called from proper Go 38 | func fact(n int) int { 39 | //println("fact",n) 40 | if n == 0 { 41 | return 1 42 | } 43 | return n * fact(n-1) 44 | } 45 | 46 | func main() { 47 | // call a func defined externally 48 | if Foo(2,2) != 4 { 49 | panic("2+2 not equal 4!") 50 | } 51 | } 52 | `, []ssainterp.ExtFunc{ 53 | ssainterp.ExtFunc{ 54 | Nam: "main.Foo", 55 | Fun: func(args []interp.Ivalue) interp.Ivalue { 56 | return args[0].(int) + args[1].(int) 57 | }, 58 | }, 59 | }, nil, nil) 60 | if err != nil || exitCode != 0 { 61 | t.Error(exitCode, err) 62 | return 63 | } 64 | 65 | // call a function within the interpreter context 66 | ival, err := ctxt.Call("main.fact", []interp.Ivalue{int(5)}) 67 | if err != nil { 68 | t.Error(err) 69 | return 70 | } 71 | if ival != 120 { 72 | t.Error("context call fact(5) != 120, value:", ival) 73 | } 74 | } 75 | 76 | func TestSSAinterpBad(t *testing.T) { 77 | _, _, err := ssainterp.Run(`this is not go!`, nil, nil, nil) 78 | if err == nil { 79 | t.Error("bad code did not error") 80 | } 81 | //t.Log(err) 82 | 83 | _, _, err = ssainterp.Run(` 84 | package main 85 | 86 | func notmain() { 87 | } 88 | `, nil, nil, nil) 89 | if err == nil { 90 | t.Error("no main function did not error") 91 | } 92 | //t.Log(err) 93 | 94 | ctx, _, err := ssainterp.Run(` 95 | package main 96 | 97 | func main() { 98 | } 99 | `, nil, nil, nil) 100 | if err != nil { 101 | t.Error(err) 102 | return 103 | } 104 | _, err = ctx.Call("very.unknown", nil) 105 | if err == nil { 106 | t.Error("unknown Interpreter.Call did not error") 107 | } 108 | } 109 | 110 | func TestUnknownInclude(t *testing.T) { 111 | _, _, err := ssainterp.Run(` 112 | package main 113 | 114 | import "there/is/no/package/with/this/name" 115 | 116 | func main() { 117 | } 118 | `, nil, nil, nil) 119 | if err == nil { 120 | t.Error("bad import did not error") 121 | } 122 | t.Log("NOTE: there should be a file not found error above.") 123 | } 124 | 125 | func TestPanic(t *testing.T) { 126 | _, _, err := ssainterp.Run(` 127 | package main 128 | 129 | func main() { 130 | panic("HELP!") 131 | } 132 | `, nil, nil, nil) 133 | if err == nil { 134 | t.Error("panic did not error") 135 | } 136 | t.Log("NOTE: there should be a panic 'HELP!' above with a stack dump.") 137 | } 138 | -------------------------------------------------------------------------------- /interp/map.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | // Custom hashtable atop map. 8 | // For use when the key's equivalence relation is not consistent with ==. 9 | 10 | // The Go specification doesn't address the atomicity of map operations. 11 | // The FAQ states that an implementation is permitted to crash on 12 | // concurrent map access. 13 | 14 | import ( 15 | "go/types" 16 | ) 17 | 18 | type hashable interface { 19 | hash(t types.Type) int 20 | eq(t types.Type, x interface{}) bool 21 | } 22 | 23 | type entry struct { 24 | key hashable 25 | Ivalue Ivalue 26 | next *entry 27 | } 28 | 29 | // A hashtable atop the built-in map. Since each bucket contains 30 | // exactly one hash Ivalue, there's no need to perform hash-equality 31 | // tests when walking the linked list. Rehashing is done by the 32 | // underlying map. 33 | type hashmap struct { 34 | keyType types.Type 35 | table map[int]*entry 36 | length int // number of entries in map 37 | } 38 | 39 | // makeMap returns an empty initialized map of key type kt, 40 | // preallocating space for reserve elements. 41 | func makeMap(kt types.Type, reserve int) Ivalue { 42 | if usesBuiltinMap(kt) { 43 | return make(map[Ivalue]Ivalue, reserve) 44 | } 45 | return &hashmap{keyType: kt, table: make(map[int]*entry, reserve)} 46 | } 47 | 48 | // delete removes the association for key k, if any. 49 | func (m *hashmap) delete(k hashable) { 50 | if m != nil { 51 | hash := k.hash(m.keyType) 52 | head := m.table[hash] 53 | if head != nil { 54 | if k.eq(m.keyType, head.key) { 55 | m.table[hash] = head.next 56 | m.length-- 57 | return 58 | } 59 | prev := head 60 | for e := head.next; e != nil; e = e.next { 61 | if k.eq(m.keyType, e.key) { 62 | prev.next = e.next 63 | m.length-- 64 | return 65 | } 66 | prev = e 67 | } 68 | } 69 | } 70 | } 71 | 72 | // lookup returns the Ivalue associated with key k, if present, or 73 | // Ivalue(nil) otherwise. 74 | func (m *hashmap) lookup(k hashable) Ivalue { 75 | if m != nil { 76 | hash := k.hash(m.keyType) 77 | for e := m.table[hash]; e != nil; e = e.next { 78 | if k.eq(m.keyType, e.key) { 79 | return e.Ivalue 80 | } 81 | } 82 | } 83 | return nil 84 | } 85 | 86 | // insert updates the map to associate key k with Ivalue v. If there 87 | // was already an association for an eq() (though not necessarily ==) 88 | // k, the previous key remains in the map and its associated Ivalue is 89 | // updated. 90 | func (m *hashmap) insert(k hashable, v Ivalue) { 91 | hash := k.hash(m.keyType) 92 | head := m.table[hash] 93 | for e := head; e != nil; e = e.next { 94 | if k.eq(m.keyType, e.key) { 95 | e.Ivalue = v 96 | return 97 | } 98 | } 99 | m.table[hash] = &entry{ 100 | key: k, 101 | Ivalue: v, 102 | next: head, 103 | } 104 | m.length++ 105 | } 106 | 107 | // len returns the number of key/Ivalue associations in the map. 108 | func (m *hashmap) len() int { 109 | if m != nil { 110 | return m.length 111 | } 112 | return 0 113 | } 114 | -------------------------------------------------------------------------------- /interp/testdata/complit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Tests of composite literals. 4 | 5 | import "fmt" 6 | 7 | // Map literals. 8 | func init() { 9 | type M map[int]int 10 | m1 := []*M{{1: 1}, &M{2: 2}} 11 | want := "map[1:1] map[2:2]" 12 | if got := fmt.Sprint(*m1[0], *m1[1]); got != want { 13 | panic(got) 14 | } 15 | m2 := []M{{1: 1}, M{2: 2}} 16 | if got := fmt.Sprint(m2[0], m2[1]); got != want { 17 | panic(got) 18 | } 19 | } 20 | 21 | // Nonliteral keys in composite literal. 22 | func init() { 23 | const zero int = 1 24 | var v = []int{1 + zero: 42} 25 | if x := fmt.Sprint(v); x != "[0 0 42]" { 26 | panic(x) 27 | } 28 | } 29 | 30 | // Test for in-place initialization. 31 | func init() { 32 | // struct 33 | type S struct { 34 | a, b int 35 | } 36 | s := S{1, 2} 37 | s = S{b: 3} 38 | if s.a != 0 { 39 | panic("s.a != 0") 40 | } 41 | if s.b != 3 { 42 | panic("s.b != 3") 43 | } 44 | s = S{} 45 | if s.a != 0 { 46 | panic("s.a != 0") 47 | } 48 | if s.b != 0 { 49 | panic("s.b != 0") 50 | } 51 | 52 | // array 53 | type A [4]int 54 | a := A{2, 4, 6, 8} 55 | a = A{1: 6, 2: 4} 56 | if a[0] != 0 { 57 | panic("a[0] != 0") 58 | } 59 | if a[1] != 6 { 60 | panic("a[1] != 6") 61 | } 62 | if a[2] != 4 { 63 | panic("a[2] != 4") 64 | } 65 | if a[3] != 0 { 66 | panic("a[3] != 0") 67 | } 68 | a = A{} 69 | if a[0] != 0 { 70 | panic("a[0] != 0") 71 | } 72 | if a[1] != 0 { 73 | panic("a[1] != 0") 74 | } 75 | if a[2] != 0 { 76 | panic("a[2] != 0") 77 | } 78 | if a[3] != 0 { 79 | panic("a[3] != 0") 80 | } 81 | } 82 | 83 | // Regression test for https://github.com/golang/go/issues/10127: 84 | // composite literal clobbers destination before reading from it. 85 | func init() { 86 | // map 87 | { 88 | type M map[string]int 89 | m := M{"x": 1, "y": 2} 90 | m = M{"x": m["y"], "y": m["x"]} 91 | if m["x"] != 2 || m["y"] != 1 { 92 | panic(fmt.Sprint(m)) 93 | } 94 | 95 | n := M{"x": 3} 96 | m, n = M{"x": n["x"]}, M{"x": m["x"]} // parallel assignment 97 | if got := fmt.Sprint(m["x"], n["x"]); got != "3 2" { 98 | panic(got) 99 | } 100 | } 101 | 102 | // struct 103 | { 104 | type T struct{ x, y, z int } 105 | t := T{x: 1, y: 2, z: 3} 106 | 107 | t = T{x: t.y, y: t.z, z: t.x} // all fields 108 | if got := fmt.Sprint(t); got != "{2 3 1}" { 109 | panic(got) 110 | } 111 | 112 | t = T{x: t.y, y: t.z + 3} // not all fields 113 | if got := fmt.Sprint(t); got != "{3 4 0}" { 114 | panic(got) 115 | } 116 | 117 | u := T{x: 5, y: 6, z: 7} 118 | t, u = T{x: u.x}, T{x: t.x} // parallel assignment 119 | if got := fmt.Sprint(t, u); got != "{5 0 0} {3 0 0}" { 120 | panic(got) 121 | } 122 | } 123 | 124 | // array 125 | { 126 | a := [3]int{0: 1, 1: 2, 2: 3} 127 | 128 | a = [3]int{0: a[1], 1: a[2], 2: a[0]} // all elements 129 | if got := fmt.Sprint(a); got != "[2 3 1]" { 130 | panic(got) 131 | } 132 | 133 | a = [3]int{0: a[1], 1: a[2] + 3} // not all elements 134 | if got := fmt.Sprint(a); got != "[3 4 0]" { 135 | panic(got) 136 | } 137 | 138 | b := [3]int{0: 5, 1: 6, 2: 7} 139 | a, b = [3]int{0: b[0]}, [3]int{0: a[0]} // parallel assignment 140 | if got := fmt.Sprint(a, b); got != "[5 0 0] [3 0 0]" { 141 | panic(got) 142 | } 143 | } 144 | 145 | // slice 146 | { 147 | s := []int{0: 1, 1: 2, 2: 3} 148 | 149 | s = []int{0: s[1], 1: s[2], 2: s[0]} // all elements 150 | if got := fmt.Sprint(s); got != "[2 3 1]" { 151 | panic(got) 152 | } 153 | 154 | s = []int{0: s[1], 1: s[2] + 3} // not all elements 155 | if got := fmt.Sprint(s); got != "[3 4]" { 156 | panic(got) 157 | } 158 | 159 | t := []int{0: 5, 1: 6, 2: 7} 160 | s, t = []int{0: t[0]}, []int{0: s[0]} // parallel assignment 161 | if got := fmt.Sprint(s, t); got != "[5] [3]" { 162 | panic(got) 163 | } 164 | } 165 | } 166 | 167 | func main() { 168 | } 169 | -------------------------------------------------------------------------------- /ssainterp.go: -------------------------------------------------------------------------------- 1 | // Parts of this code are: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package ssainterp 7 | 8 | import ( 9 | "fmt" 10 | "github.com/go-interpreter/ssainterp/interp" 11 | "go/build" 12 | "io" 13 | //"./interp" 14 | 15 | "go/types" 16 | 17 | "golang.org/x/tools/go/loader" 18 | "golang.org/x/tools/go/ssa" 19 | "golang.org/x/tools/go/ssa/ssautil" 20 | ) 21 | 22 | // Func is the signature of a normal go function 23 | // that can be called from the interpreter. 24 | // TODO: currently the parameters can only reliably contain simple values. 25 | type Func func([]interp.Ivalue) interp.Ivalue 26 | 27 | // ExtFunc defines an external go function callable from the interpreter. 28 | type ExtFunc struct { 29 | Nam string // e.g. "main.Foo" 30 | Fun Func 31 | } 32 | 33 | // Interpreter defines the datastructure to run an interpreter. 34 | type Interpreter struct { 35 | Context *interp.Context 36 | Panic interface{} 37 | MainPkg *ssa.Package 38 | exts *interp.Externals 39 | } 40 | 41 | // Run the interpreter, given some code. 42 | func Run(code string, extFns []ExtFunc, args []string, output io.Writer) (interp *Interpreter, exitCode int, error error) { 43 | ssai := new(Interpreter) 44 | exitCode, err := ssai.run(code, extFns, args, output) 45 | if ssai.Panic != nil { 46 | return nil, -1, fmt.Errorf("panic in Run: %v", ssai.Panic) 47 | } 48 | return ssai, exitCode, err 49 | } 50 | 51 | func (ssai *Interpreter) run(code string, extFns []ExtFunc, args []string, output io.Writer) (int, error) { 52 | 53 | defer func() { 54 | if r := recover(); r != nil { 55 | ssai.Panic = r 56 | } 57 | }() 58 | 59 | conf := loader.Config{ 60 | Build: &build.Default, 61 | } 62 | 63 | // Parse the input file. 64 | file, err := conf.ParseFile("main.go", code) 65 | if err != nil { 66 | return -1, err // parse error 67 | } 68 | 69 | // Create single-file main package. 70 | conf.CreateFromFiles("main", file) 71 | conf.Import("runtime") // always need this for ssa/interp 72 | 73 | // Load the main package and its dependencies. 74 | iprog, err := conf.Load() 75 | if err != nil { 76 | return -1, err // type error in some package 77 | } 78 | 79 | // Create SSA-form program representation. 80 | prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions) 81 | 82 | var mainPkg *ssa.Package 83 | for _, pkg := range prog.AllPackages() { 84 | if pkg.Pkg.Name() == "main" { 85 | mainPkg = pkg 86 | if mainPkg.Func("main") == nil { 87 | return -1, fmt.Errorf("no func main() in main package") 88 | } 89 | break 90 | } 91 | } 92 | if mainPkg == nil { 93 | return -1, fmt.Errorf("no main package") 94 | } 95 | 96 | // Build SSA code for bodies for whole program 97 | prog.Build() 98 | 99 | //mainPkg.Func("main").WriteTo(os.Stdout) // list the main func in SSA form for DEBUG 100 | 101 | ssai.exts = interp.NewExternals() 102 | // add the callable external functions 103 | for _, ef := range extFns { 104 | ssai.exts.AddExtFunc(ef.Nam, ef.Fun) 105 | } 106 | 107 | context, exitCode := interp.Interpret(mainPkg, 0, 108 | &types.StdSizes{ 109 | WordSize: 8, // word size in bytes - must be >= 4 (32bits) 110 | MaxAlign: 8, // maximum alignment in bytes - must be >= 1 111 | }, "main.go", args, ssai.exts, output) 112 | if context == nil { 113 | return -1, fmt.Errorf("nil context returned") 114 | } 115 | ssai.Context = context 116 | ssai.MainPkg = mainPkg 117 | return exitCode, nil 118 | } 119 | 120 | // Call a function in an already created interpreter. 121 | func (ssai *Interpreter) Call(name string, args []interp.Ivalue) (interp.Ivalue, error) { 122 | if ssai == nil { 123 | return nil, fmt.Errorf("nil *Interpreter") 124 | } 125 | if ssai.Panic != nil { 126 | return nil, fmt.Errorf("prior panic in Interpreter: %v", ssai.Panic) 127 | } 128 | result := ssai.call(name, args) 129 | if ssai.Panic != nil { 130 | return nil, fmt.Errorf("panic in Call: %v", ssai.Panic) 131 | } 132 | return result, nil 133 | } 134 | 135 | func (ssai *Interpreter) call(name string, args []interp.Ivalue) interp.Ivalue { 136 | defer func() { 137 | if r := recover(); r != nil { 138 | ssai.Panic = r 139 | } 140 | }() 141 | return ssai.Context.Call(name, args) 142 | } 143 | -------------------------------------------------------------------------------- /interp/addexternals.go: -------------------------------------------------------------------------------- 1 | package interp 2 | 3 | // additions to the interp package 4 | /* 5 | type globInfo struct { 6 | addr *Ivalue // currently must be *Ivalue, in future *typ 7 | //typ reflect.Type // reserved for future use! 8 | } 9 | */ 10 | 11 | // Externals describes usable objects external to the interpreter. 12 | type Externals struct { 13 | funcs map[string]externalFn 14 | //globs map[string]*globInfo 15 | //globVals map[ssa.Value]*globInfo 16 | } 17 | 18 | // NewExternals makes an Externals type. 19 | func NewExternals() *Externals { 20 | return &Externals{ 21 | funcs: make(map[string]externalFn), 22 | //globs: make(map[string]*globInfo), 23 | } 24 | } 25 | 26 | // AddExtFunc adds an external function to the known map. 27 | func (ext *Externals) AddExtFunc(name string, fn func([]Ivalue) Ivalue) { 28 | ext.funcs[name] = func(fr *frame, args []Ivalue) Ivalue { 29 | return fn(args) 30 | } 31 | } 32 | 33 | /* 34 | // AddExtGlob adds read-only access to a global variable external to the interpreter, 35 | // the global variable must be one of types.BasicKind. 36 | // The benefit of this may not justify the cost TODO consider removing. 37 | func (ext *Externals) AddExtGlob(name string, reflectPointer reflect.Value) { 38 | fmt.Printf("DEBUG reflectPointer: %v:%T reflect.Indirect(reflectPointer): %v:%T\n", 39 | reflectPointer.Interface(), reflectPointer.Interface(), 40 | reflect.Indirect(reflectPointer).Interface(), 41 | reflect.Indirect(reflectPointer).Interface()) 42 | if reflectPointer.Interface() == reflect.Indirect(reflectPointer).Interface() { 43 | panic(fmt.Sprintf("AddExtGlob reflect value is not a pointer: %v:%T", 44 | reflectPointer.Interface(), reflectPointer.Interface())) 45 | } 46 | iv := Ivalue(reflectPointer) 47 | ext.globs[name] = &globInfo{addr: &iv} 48 | } 49 | */ 50 | 51 | // IvalIfaceSlice converts a slice of Ivalues into a slice of empty interfaces. 52 | func IvalIfaceSlice(ivs []Ivalue) []interface{} { 53 | rets := make([]interface{}, len(ivs)) 54 | for i, v := range ivs { 55 | rets[i] = IvalIface(v) 56 | } 57 | return rets 58 | } 59 | 60 | // IvalIface converts an Ivalue into an interface{}. 61 | func IvalIface(iv Ivalue) interface{} { 62 | 63 | switch iv.(type) { 64 | case bool: 65 | return iv.(bool) 66 | case int: 67 | return iv.(int) 68 | case int8: 69 | return iv.(int8) 70 | case int16: 71 | return iv.(int16) 72 | case int32: 73 | return iv.(int32) 74 | case int64: 75 | return iv.(int64) 76 | case uint: 77 | return iv.(uint) 78 | case uint8: 79 | return iv.(uint8) 80 | case uint16: 81 | return iv.(uint16) 82 | case uint32: 83 | return iv.(uint32) 84 | case uint64: 85 | return iv.(int64) 86 | case uintptr: 87 | return iv.(uintptr) 88 | case float32: 89 | return iv.(float32) 90 | case float64: 91 | return iv.(float64) 92 | case complex64: 93 | return iv.(complex64) 94 | case complex128: 95 | return iv.(complex128) 96 | case string: 97 | return iv.(string) 98 | case iface: 99 | return IvalIface(iv.(iface).v) 100 | case []Ivalue: 101 | return IvalIfaceSlice(iv.([]Ivalue)) 102 | case array: 103 | return IvalIfaceSlice(iv.([]Ivalue)) // TODO review 104 | case structure: 105 | return IvalIfaceSlice(iv.([]Ivalue)) // TODO review 106 | } 107 | 108 | return interface{}(iv) 109 | 110 | /* TODO 111 | switch t := iv.(iface).t.(type) { 112 | case *types.Named: 113 | return interface{}(iv) // TODO reflectKind(t.Underlying()) 114 | case *types.Basic: 115 | switch t.Kind() { 116 | case types.Bool: 117 | return iv.(bool) 118 | case types.Int: 119 | return iv.(int) 120 | case types.Int8: 121 | return iv.(int8) 122 | case types.Int16: 123 | return iv.(int16) 124 | case types.Int32: 125 | return iv.(int32) 126 | case types.Int64: 127 | return iv.(int64) 128 | case types.Uint: 129 | return iv.(uint) 130 | case types.Uint8: 131 | return iv.(uint8) 132 | case types.Uint16: 133 | return iv.(uint16) 134 | case types.Uint32: 135 | return iv.(uint32) 136 | case types.Uint64: 137 | return iv.(int64) 138 | case types.Uintptr: 139 | return iv.(uintptr) 140 | case types.Float32: 141 | return iv.(float32) 142 | case types.Float64: 143 | return iv.(float64) 144 | case types.Complex64: 145 | return iv.(complex64) 146 | case types.Complex128: 147 | return iv.(complex128) 148 | case types.String: 149 | return iv.(string) 150 | case types.UnsafePointer: 151 | return iv.(unsafe.Pointer) // commented out 152 | } 153 | /* TODO 154 | case *types.Array: 155 | return reflect.Array 156 | case *types.Chan: 157 | return reflect.Chan 158 | case *types.Signature: 159 | return reflect.Func 160 | case *types.Interface: 161 | return reflect.Interface 162 | case *types.Map: 163 | return reflect.Map 164 | case *types.Pointer: 165 | return reflect.Ptr 166 | case *types.Slice: 167 | return reflect.Slice 168 | case *types.Struct: 169 | return reflect.Struct 170 | */ 171 | //} 172 | //panic(fmt.Sprint("unexpected type: ", t)) 173 | } 174 | -------------------------------------------------------------------------------- /interp/external_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !windows,!plan9 6 | 7 | package interp 8 | 9 | import "syscall" 10 | 11 | func fillStat(st *syscall.Stat_t, stat structure) { 12 | stat[0] = st.Dev 13 | stat[1] = st.Ino 14 | stat[2] = st.Nlink 15 | stat[3] = st.Mode 16 | stat[4] = st.Uid 17 | stat[5] = st.Gid 18 | 19 | stat[7] = st.Rdev 20 | stat[8] = st.Size 21 | stat[9] = st.Blksize 22 | stat[10] = st.Blocks 23 | // TODO(adonovan): fix: copy Timespecs. 24 | // stat[11] = st.Atim 25 | // stat[12] = st.Mtim 26 | // stat[13] = st.Ctim 27 | } 28 | 29 | func ext۰syscall۰Close(fr *frame, args []Ivalue) Ivalue { 30 | // func Close(fd int) (err error) 31 | return wrapError(syscall.Close(args[0].(int))) 32 | } 33 | 34 | func ext۰syscall۰Fstat(fr *frame, args []Ivalue) Ivalue { 35 | // func Fstat(fd int, stat *Stat_t) (err error) 36 | fd := args[0].(int) 37 | stat := (*args[1].(*Ivalue)).(structure) 38 | 39 | var st syscall.Stat_t 40 | err := syscall.Fstat(fd, &st) 41 | fillStat(&st, stat) 42 | return wrapError(err) 43 | } 44 | 45 | func ext۰syscall۰ReadDirent(fr *frame, args []Ivalue) Ivalue { 46 | // func ReadDirent(fd int, buf []byte) (n int, err error) 47 | fd := args[0].(int) 48 | p := args[1].([]Ivalue) 49 | b := make([]byte, len(p)) 50 | n, err := syscall.ReadDirent(fd, b) 51 | for i := 0; i < n; i++ { 52 | p[i] = b[i] 53 | } 54 | return tuple{n, wrapError(err)} 55 | } 56 | 57 | func ext۰syscall۰Kill(fr *frame, args []Ivalue) Ivalue { 58 | // func Kill(pid int, sig Signal) (err error) 59 | return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int)))) 60 | } 61 | 62 | func ext۰syscall۰Lstat(fr *frame, args []Ivalue) Ivalue { 63 | // func Lstat(name string, stat *Stat_t) (err error) 64 | name := args[0].(string) 65 | stat := (*args[1].(*Ivalue)).(structure) 66 | 67 | var st syscall.Stat_t 68 | err := syscall.Lstat(name, &st) 69 | fillStat(&st, stat) 70 | return wrapError(err) 71 | } 72 | 73 | func ext۰syscall۰Open(fr *frame, args []Ivalue) Ivalue { 74 | // func Open(path string, mode int, perm uint32) (fd int, err error) { 75 | path := args[0].(string) 76 | mode := args[1].(int) 77 | perm := args[2].(uint32) 78 | fd, err := syscall.Open(path, mode, perm) 79 | return tuple{fd, wrapError(err)} 80 | } 81 | 82 | func ext۰syscall۰ParseDirent(fr *frame, args []Ivalue) Ivalue { 83 | // func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) 84 | max := args[1].(int) 85 | var names []string 86 | for _, iname := range args[2].([]Ivalue) { 87 | names = append(names, iname.(string)) 88 | } 89 | consumed, count, newnames := syscall.ParseDirent(IvalueToBytes(args[0]), max, names) 90 | var inewnames []Ivalue 91 | for _, newname := range newnames { 92 | inewnames = append(inewnames, newname) 93 | } 94 | return tuple{consumed, count, inewnames} 95 | } 96 | 97 | func ext۰syscall۰Read(fr *frame, args []Ivalue) Ivalue { 98 | // func Read(fd int, p []byte) (n int, err error) 99 | fd := args[0].(int) 100 | p := args[1].([]Ivalue) 101 | b := make([]byte, len(p)) 102 | n, err := syscall.Read(fd, b) 103 | for i := 0; i < n; i++ { 104 | p[i] = b[i] 105 | } 106 | return tuple{n, wrapError(err)} 107 | } 108 | 109 | func ext۰syscall۰Stat(fr *frame, args []Ivalue) Ivalue { 110 | // func Stat(name string, stat *Stat_t) (err error) 111 | name := args[0].(string) 112 | stat := (*args[1].(*Ivalue)).(structure) 113 | 114 | var st syscall.Stat_t 115 | err := syscall.Stat(name, &st) 116 | fillStat(&st, stat) 117 | return wrapError(err) 118 | } 119 | 120 | func ext۰syscall۰Write(fr *frame, args []Ivalue) Ivalue { 121 | // func Write(fd int, p []byte) (n int, err error) 122 | n, err := write(fr, args[0].(int), IvalueToBytes(args[1])) 123 | return tuple{n, wrapError(err)} 124 | } 125 | 126 | func ext۰syscall۰Pipe(fr *frame, args []Ivalue) Ivalue { 127 | //func Pipe(p []int) (err error) 128 | pp := args[0].([]Ivalue) 129 | p := make([]int, len(pp)) 130 | for k, v := range pp { 131 | p[k] = v.(int) 132 | } 133 | err := syscall.Pipe(p) 134 | for k, v := range p { 135 | pp[k] = v 136 | } 137 | return wrapError(err) 138 | } 139 | 140 | func ext۰syscall۰Syscall(fr *frame, args []Ivalue) Ivalue { 141 | //func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) 142 | p := make([]uintptr, len(args)) 143 | for k, v := range args { 144 | p[k] = v.(uintptr) 145 | } 146 | r1, r2, err := syscall.Syscall(p[0], p[1], p[2], p[3]) 147 | return tuple{Ivalue(r1), Ivalue(r2), wrapError(err)} 148 | } 149 | 150 | func ext۰syscall۰CloseOnExec(fr *frame, args []Ivalue) Ivalue { 151 | //func CloseOnExec(fd int) 152 | syscall.CloseOnExec(args[0].(int)) 153 | return nil 154 | } 155 | 156 | func ext۰syscall۰RawSyscall(fr *frame, args []Ivalue) Ivalue { 157 | return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)} 158 | } 159 | 160 | func syswrite(fd int, b []byte) (int, error) { 161 | return syscall.Write(fd, b) 162 | } 163 | -------------------------------------------------------------------------------- /interp/interp_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !android,!windows,!plan9 6 | 7 | package interp_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "go/build" 13 | "os" 14 | "path/filepath" 15 | "strings" 16 | "testing" 17 | "time" 18 | 19 | "go/types" 20 | 21 | "golang.org/x/tools/go/loader" 22 | "golang.org/x/tools/go/ssa" 23 | "golang.org/x/tools/go/ssa/ssautil" 24 | 25 | // interp "." 26 | "github.com/go-interpreter/ssainterp/interp" 27 | ) 28 | 29 | // Each line contains a space-separated list of $GOROOT/test/ 30 | // filenames comprising the main package of a program. 31 | // They are ordered quickest-first, roughly. 32 | // 33 | // TODO(adonovan): integrate into the $GOROOT/test driver scripts, 34 | // golden file checking, etc. 35 | var gorootTestTests = []string{ 36 | "235.go", 37 | "alias1.go", 38 | "chancap.go", 39 | "func5.go", 40 | "func6.go", 41 | "func7.go", 42 | "func8.go", 43 | "helloworld.go", 44 | "varinit.go", 45 | "escape3.go", 46 | "initcomma.go", 47 | "cmp.go", 48 | "compos.go", 49 | "turing.go", 50 | "indirect.go", 51 | "complit.go", 52 | "for.go", 53 | "struct0.go", 54 | "intcvt.go", 55 | "printbig.go", 56 | "deferprint.go", 57 | "escape.go", 58 | "range.go", 59 | "const4.go", 60 | "float_lit.go", 61 | "bigalg.go", 62 | "decl.go", 63 | "if.go", 64 | "named.go", 65 | "bigmap.go", 66 | "func.go", 67 | "reorder2.go", 68 | "closure.go", 69 | "gc.go", 70 | "simassign.go", 71 | "iota.go", 72 | "nilptr2.go", 73 | "goprint.go", // doesn't actually assert anything (cmpout) 74 | "utf.go", 75 | "method.go", 76 | "char_lit.go", 77 | "env.go", 78 | "int_lit.go", 79 | "string_lit.go", 80 | "defer.go", 81 | "typeswitch.go", 82 | "stringrange.go", 83 | "reorder.go", 84 | "method3.go", 85 | "literal.go", 86 | "nul1.go", // doesn't actually assert anything (errorcheckoutput) 87 | "zerodivide.go", 88 | "convert.go", 89 | "convT2X.go", 90 | "switch.go", 91 | "initialize.go", 92 | "ddd.go", 93 | "blank.go", // partly disabled 94 | "map.go", 95 | "closedchan.go", 96 | "divide.go", 97 | "rename.go", 98 | "const3.go", 99 | "nil.go", 100 | "recover.go", // reflection parts disabled 101 | "recover1.go", 102 | "recover2.go", 103 | "recover3.go", 104 | "typeswitch1.go", 105 | "floatcmp.go", 106 | "crlf.go", // doesn't actually assert anything (runoutput) 107 | // Slow tests follow. 108 | "bom.go", // ~1.7s 109 | "gc1.go", // ~1.7s 110 | "cmplxdivide.go cmplxdivide1.go", // ~2.4s 111 | 112 | // Working, but not worth enabling: 113 | // "append.go", // works, but slow (15s). 114 | // "gc2.go", // works, but slow, and cheats on the memory check. 115 | // "sigchld.go", // works, but only on POSIX. 116 | // "peano.go", // works only up to n=9, and slow even then. 117 | // "stack.go", // works, but too slow (~30s) by default. 118 | // "solitaire.go", // works, but too slow (~30s). 119 | // "const.go", // works but for but one bug: constant folder doesn't consider representations. 120 | // "init1.go", // too slow (80s) and not that interesting. Cheats on ReadMemStats check too. 121 | // "rotate.go rotate0.go", // emits source for a test 122 | // "rotate.go rotate1.go", // emits source for a test 123 | // "rotate.go rotate2.go", // emits source for a test 124 | // "rotate.go rotate3.go", // emits source for a test 125 | // "64bit.go", // emits source for a test 126 | // "run.go", // test driver, not a test. 127 | 128 | // Broken. TODO(adonovan): fix. 129 | // copy.go // very slow; but with N=4 quickly crashes, slice index out of range. 130 | // nilptr.go // interp: V > uintptr not implemented. Slow test, lots of mem 131 | // args.go // works, but requires specific os.Args from the driver. 132 | // index.go // a template, not a real test. 133 | // mallocfin.go // SetFinalizer not implemented. 134 | 135 | // TODO(adonovan): add tests from $GOROOT/test/* subtrees: 136 | // bench chan bugs fixedbugs interface ken. 137 | } 138 | 139 | // These are files in go.tools/go/ssa/interp/testdata/. 140 | var testdataTests = []string{ 141 | "boundmeth.go", 142 | "complit.go", 143 | "coverage.go", 144 | "defer.go", 145 | "fieldprom.go", 146 | "ifaceconv.go", 147 | "ifaceprom.go", 148 | "initorder.go", 149 | "methprom.go", 150 | "mrvchain.go", 151 | "range.go", 152 | "recover.go", 153 | "reflect.go", 154 | "static.go", 155 | "callstack.go", 156 | } 157 | 158 | // These are files and packages in $GOROOT/src/. 159 | var gorootSrcTests = []string{ 160 | //"bufio", // needs time.startTimer 161 | "encoding/ascii85", 162 | //"encoding/binary", // needs reflect.Indirect 163 | "encoding/hex", 164 | //"encoding/pem", // TODO(adonovan): implement (reflect.Value).SetString 165 | //"testing", // TODO(adonovan): implement runtime.Goexit correctly 166 | "unicode", 167 | 168 | /* libraries below not in the original tests */ 169 | "unicode/utf16", 170 | // "strings", // runtime error: invalid memory address 171 | // "bytes", // runtime error: interface is interp.array not uint64 172 | 173 | // Too slow: 174 | "container/heap", 175 | "container/list", 176 | "container/ring", 177 | "hash/adler32", 178 | 179 | // TODO(adonovan): packages with Examples require os.Pipe (unimplemented): 180 | "hash/crc32", 181 | "encoding/base32", 182 | //"encoding/base64", // needs time.startTimer 183 | "unicode/utf8", 184 | //"log", // pattern matching issue 185 | "path", 186 | "flag", 187 | "encoding/csv", 188 | "text/scanner", 189 | //"encoding/json", // unsafe pointer conversion issue - invalid / nil ptr 190 | } 191 | 192 | type successPredicate func(exitcode int, output string) error 193 | 194 | func run(t *testing.T, dir, input string, success successPredicate) bool { 195 | capturedOutput := &bytes.Buffer{} 196 | 197 | fmt.Printf("Input: %s\n", input) 198 | 199 | start := time.Now() 200 | 201 | var inputs []string 202 | for _, i := range strings.Split(input, " ") { 203 | if strings.HasSuffix(i, ".go") { 204 | i = dir + i 205 | } 206 | inputs = append(inputs, i) 207 | } 208 | 209 | var conf loader.Config 210 | 211 | if _, err := conf.FromArgs(inputs, true); err != nil { 212 | t.Errorf("FromArgs(%s) failed: %s", inputs, err) 213 | return false 214 | } 215 | 216 | conf.Import("runtime") 217 | 218 | // Print a helpful hint if we don't make it to the end. 219 | var hint string 220 | defer func() { 221 | if hint != "" { 222 | fmt.Println("FAIL") 223 | fmt.Println(hint) 224 | } else { 225 | fmt.Println("PASS") 226 | } 227 | 228 | capturedOutput = nil 229 | }() 230 | 231 | hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input) 232 | 233 | iprog, err := conf.Load() 234 | if err != nil { 235 | t.Errorf("conf.Load(%s) failed: %s", inputs, err) 236 | return false 237 | } 238 | 239 | prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions) 240 | prog.Build() 241 | 242 | var mainPkg *ssa.Package 243 | var initialPkgs []*ssa.Package 244 | for _, info := range iprog.InitialPackages() { 245 | if info.Pkg.Path() == "runtime" { 246 | continue // not an initial package 247 | } 248 | p := prog.Package(info.Pkg) 249 | initialPkgs = append(initialPkgs, p) 250 | if mainPkg == nil && p.Func("main") != nil { 251 | mainPkg = p 252 | } 253 | } 254 | if mainPkg == nil && len(initialPkgs) == 1 { 255 | testmainPkg := prog.CreateTestMainPackage(initialPkgs[0]) 256 | if testmainPkg == nil { 257 | t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg) 258 | return false 259 | } 260 | if testmainPkg.Func("main") == nil { 261 | t.Errorf("synthetic testmain package has no main") 262 | return false 263 | } 264 | mainPkg = testmainPkg 265 | } 266 | 267 | ext := interp.NewExternals() 268 | // TODO(Elliott5) - remove next line when error #12196 is resolved 269 | // see https://github.com/golang/go/issues/12196 270 | // so not requiring this cludge because of 271 | // required output not being captured for an example function. 272 | ext.AddExtFunc("testing.RunExamples", func([]interp.Ivalue) interp.Ivalue { return true }) // NoOp 273 | 274 | hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input) 275 | _, exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{WordSize: 8, MaxAlign: 8}, inputs[0], []string{}, ext, capturedOutput) 276 | 277 | // The definition of success varies with each file. 278 | if err := success(exitCode, (*capturedOutput).String()); err != nil { 279 | t.Errorf("interp.Interpret(%s) failed: %s", inputs, err) 280 | return false 281 | } 282 | 283 | hint = "" // call off the hounds 284 | 285 | if false { 286 | fmt.Println(input, time.Since(start)) // test profiling 287 | } 288 | 289 | return true 290 | } 291 | 292 | const slash = string(os.PathSeparator) 293 | 294 | func printFailures(failures []string) { 295 | if failures != nil { 296 | fmt.Println("The following tests failed:") 297 | for _, f := range failures { 298 | fmt.Printf("\t%s\n", f) 299 | } 300 | } 301 | } 302 | 303 | func success(exitcode int, output string) error { 304 | if exitcode != 0 { 305 | return fmt.Errorf("exit code was %d", exitcode) 306 | } 307 | if strings.Contains(output, "BUG") { 308 | return fmt.Errorf("exited zero but output contained 'BUG'") 309 | } 310 | return nil 311 | } 312 | 313 | // TestTestdataFiles runs the interpreter on testdata/*.go. 314 | func TestTestdataFiles(t *testing.T) { 315 | var failures []string 316 | start := time.Now() 317 | for _, input := range testdataTests { 318 | if testing.Short() && time.Since(start) > 30*time.Second { 319 | printFailures(failures) 320 | t.Skipf("timeout - aborting test") 321 | } 322 | if !run(t, "testdata"+slash, input, success) { 323 | failures = append(failures, input) 324 | } 325 | } 326 | printFailures(failures) 327 | } 328 | 329 | // TestGorootTest runs the interpreter on $GOROOT/test/*.go. 330 | func TestGorootTest(t *testing.T) { 331 | if testing.Short() { 332 | t.Skip() // too slow (~30s) 333 | } 334 | 335 | var failures []string 336 | 337 | for _, input := range gorootTestTests { 338 | if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) { 339 | failures = append(failures, input) 340 | } 341 | } 342 | for _, input := range gorootSrcTests { 343 | if !run(t, filepath.Join(build.Default.GOROOT, "src")+slash, input, success) { 344 | failures = append(failures, input) 345 | } 346 | } 347 | printFailures(failures) 348 | } 349 | 350 | // TestTestmainPackage runs the interpreter on a synthetic "testmain" package. 351 | func TestTestmainPackage(t *testing.T) { 352 | if testing.Short() { 353 | t.Skip() // too slow on some platforms 354 | } 355 | 356 | success := func(exitcode int, output string) error { 357 | if exitcode == 0 { 358 | return fmt.Errorf("unexpected success") 359 | } 360 | if !strings.Contains(output, "FAIL: TestFoo") { 361 | return fmt.Errorf("missing failure log for TestFoo") 362 | } 363 | if !strings.Contains(output, "FAIL: TestBar") { 364 | return fmt.Errorf("missing failure log for TestBar") 365 | } 366 | // TODO(adonovan): test benchmarks too 367 | return nil 368 | } 369 | run(t, "testdata"+slash, "a_test.go", success) 370 | } 371 | 372 | // CreateTestMainPackage should return nil if there were no tests. 373 | func TestNullTestmainPackage(t *testing.T) { 374 | var conf loader.Config 375 | conf.CreateFromFilenames("", "testdata/b_test.go") 376 | iprog, err := conf.Load() 377 | if err != nil { 378 | t.Fatalf("CreatePackages failed: %s", err) 379 | } 380 | prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions) 381 | mainPkg := prog.Package(iprog.Created[0].Pkg) 382 | if mainPkg.Func("main") != nil { 383 | t.Fatalf("unexpected main function") 384 | } 385 | if prog.CreateTestMainPackage(mainPkg) != nil { 386 | t.Fatalf("CreateTestMainPackage returned non-nil") 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /interp/testdata/coverage.go: -------------------------------------------------------------------------------- 1 | // This interpreter test is designed to run very quickly yet provide 2 | // some coverage of a broad selection of constructs. 3 | // 4 | // Validate this file with 'go run' after editing. 5 | // TODO(adonovan): break this into small files organized by theme. 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "reflect" 12 | ) 13 | 14 | func init() { 15 | // Call of variadic function with (implicit) empty slice. 16 | if x := fmt.Sprint(); x != "" { 17 | panic(x) 18 | } 19 | } 20 | 21 | type empty interface{} 22 | 23 | type I interface { 24 | f() int 25 | } 26 | 27 | type T struct{ z int } 28 | 29 | func (t T) f() int { return t.z } 30 | 31 | func use(interface{}) {} 32 | 33 | var counter = 2 34 | 35 | // Test initialization, including init blocks containing 'return'. 36 | // Assertion is in main. 37 | func init() { 38 | counter *= 3 39 | return 40 | counter *= 3 41 | } 42 | 43 | func init() { 44 | counter *= 5 45 | return 46 | counter *= 5 47 | } 48 | 49 | // Recursion. 50 | func fib(x int) int { 51 | if x < 2 { 52 | return x 53 | } 54 | return fib(x-1) + fib(x-2) 55 | } 56 | 57 | func fibgen(ch chan int) { 58 | for x := 0; x < 10; x++ { 59 | ch <- fib(x) 60 | } 61 | close(ch) 62 | } 63 | 64 | // Goroutines and channels. 65 | func init() { 66 | ch := make(chan int) 67 | go fibgen(ch) 68 | var fibs []int 69 | for v := range ch { 70 | fibs = append(fibs, v) 71 | if len(fibs) == 10 { 72 | break 73 | } 74 | } 75 | if x := fmt.Sprint(fibs); x != "[0 1 1 2 3 5 8 13 21 34]" { 76 | panic(x) 77 | } 78 | } 79 | 80 | // Test of aliasing. 81 | func init() { 82 | type S struct { 83 | a, b string 84 | } 85 | 86 | s1 := []string{"foo", "bar"} 87 | s2 := s1 // creates an alias 88 | s2[0] = "wiz" 89 | if x := fmt.Sprint(s1, s2); x != "[wiz bar] [wiz bar]" { 90 | panic(x) 91 | } 92 | 93 | pa1 := &[2]string{"foo", "bar"} 94 | pa2 := pa1 // creates an alias 95 | pa2[0] = "wiz" 96 | if x := fmt.Sprint(*pa1, *pa2); x != "[wiz bar] [wiz bar]" { 97 | panic(x) 98 | } 99 | 100 | a1 := [2]string{"foo", "bar"} 101 | a2 := a1 // creates a copy 102 | a2[0] = "wiz" 103 | if x := fmt.Sprint(a1, a2); x != "[foo bar] [wiz bar]" { 104 | panic(x) 105 | } 106 | 107 | t1 := S{"foo", "bar"} 108 | t2 := t1 // copy 109 | t2.a = "wiz" 110 | if x := fmt.Sprint(t1, t2); x != "{foo bar} {wiz bar}" { 111 | panic(x) 112 | } 113 | } 114 | 115 | func main() { 116 | print() // legal 117 | 118 | if counter != 2*3*5 { 119 | panic(counter) 120 | } 121 | 122 | // Test builtins (e.g. complex) preserve named argument types. 123 | type N complex128 124 | var n N 125 | n = complex(1.0, 2.0) 126 | if n != complex(1.0, 2.0) { 127 | panic(n) 128 | } 129 | if x := reflect.TypeOf(n).String(); x != "main.N" { 130 | panic(x) 131 | } 132 | if real(n) != 1.0 || imag(n) != 2.0 { 133 | panic(n) 134 | } 135 | 136 | // Channel + select. 137 | ch := make(chan int, 1) 138 | select { 139 | case ch <- 1: 140 | // ok 141 | default: 142 | panic("couldn't send") 143 | } 144 | if <-ch != 1 { 145 | panic("couldn't receive") 146 | } 147 | // A "receive" select-case that doesn't declare its vars. (regression test) 148 | anint := 0 149 | ok := false 150 | select { 151 | case anint, ok = <-ch: 152 | case anint = <-ch: 153 | default: 154 | } 155 | _ = anint 156 | _ = ok 157 | 158 | // Anon structs with methods. 159 | anon := struct{ T }{T: T{z: 1}} 160 | if x := anon.f(); x != 1 { 161 | panic(x) 162 | } 163 | var i I = anon 164 | if x := i.f(); x != 1 { 165 | panic(x) 166 | } 167 | // NB. precise output of reflect.Type.String is undefined. 168 | if x := reflect.TypeOf(i).String(); x != "struct { main.T }" && x != "struct{main.T}" { 169 | panic(x) 170 | } 171 | 172 | // fmt. 173 | const message = "Hello, World!" 174 | if fmt.Sprintf("%s, %s!", "Hello", "World") != message { 175 | panic("oops") 176 | } 177 | 178 | // Type assertion. 179 | type S struct { 180 | f int 181 | } 182 | var e empty = S{f: 42} 183 | switch v := e.(type) { 184 | case S: 185 | if v.f != 42 { 186 | panic(v.f) 187 | } 188 | default: 189 | panic(reflect.TypeOf(v)) 190 | } 191 | if i, ok := e.(I); ok { 192 | panic(i) 193 | } 194 | 195 | // Switch. 196 | var x int 197 | switch x { 198 | case 1: 199 | panic(x) 200 | fallthrough 201 | case 2, 3: 202 | panic(x) 203 | default: 204 | // ok 205 | } 206 | // empty switch 207 | switch { 208 | } 209 | // empty switch 210 | switch { 211 | default: 212 | } 213 | // empty switch 214 | switch { 215 | default: 216 | fallthrough 217 | case false: 218 | } 219 | 220 | // string -> []rune conversion. 221 | use([]rune("foo")) 222 | 223 | // Calls of form x.f(). 224 | type S2 struct { 225 | f func() int 226 | } 227 | S2{f: func() int { return 1 }}.f() // field is a func value 228 | T{}.f() // method call 229 | i.f() // interface method invocation 230 | (interface { 231 | f() int 232 | }(T{})).f() // anon interface method invocation 233 | 234 | // Map lookup. 235 | if v, ok := map[string]string{}["foo5"]; v != "" || ok { 236 | panic("oops") 237 | } 238 | 239 | // Regression test: implicit address-taken struct literal 240 | // inside literal map element. 241 | _ = map[int]*struct{}{0: {}} 242 | } 243 | 244 | type mybool bool 245 | 246 | func (mybool) f() {} 247 | 248 | func init() { 249 | type mybool bool 250 | var b mybool 251 | var i interface{} = b || b // result preserves types of operands 252 | _ = i.(mybool) 253 | 254 | i = false && b // result preserves type of "typed" operand 255 | _ = i.(mybool) 256 | 257 | i = b || true // result preserves type of "typed" operand 258 | _ = i.(mybool) 259 | } 260 | 261 | func init() { 262 | var x, y int 263 | var b mybool = x == y // x==y is an untyped bool 264 | b.f() 265 | } 266 | 267 | // Simple closures. 268 | func init() { 269 | b := 3 270 | f := func(a int) int { 271 | return a + b 272 | } 273 | b++ 274 | if x := f(1); x != 5 { // 1+4 == 5 275 | panic(x) 276 | } 277 | b++ 278 | if x := f(2); x != 7 { // 2+5 == 7 279 | panic(x) 280 | } 281 | if b := f(1) < 16 || f(2) < 17; !b { 282 | panic("oops") 283 | } 284 | } 285 | 286 | // Shifts. 287 | func init() { 288 | var i int64 = 1 289 | var u uint64 = 1 << 32 290 | if x := i << uint32(u); x != 1 { 291 | panic(x) 292 | } 293 | if x := i << uint64(u); x != 0 { 294 | panic(x) 295 | } 296 | } 297 | 298 | // Implicit conversion of delete() key operand. 299 | func init() { 300 | type I interface{} 301 | m := make(map[I]bool) 302 | m[1] = true 303 | m[I(2)] = true 304 | if len(m) != 2 { 305 | panic(m) 306 | } 307 | delete(m, I(1)) 308 | delete(m, 2) 309 | if len(m) != 0 { 310 | panic(m) 311 | } 312 | } 313 | 314 | // An I->I conversion always succeeds. 315 | func init() { 316 | var x I 317 | if I(x) != I(nil) { 318 | panic("I->I conversion failed") 319 | } 320 | } 321 | 322 | // An I->I type-assert fails iff the value is nil. 323 | func init() { 324 | defer func() { 325 | r := fmt.Sprint(recover()) 326 | // Exact error varies by toolchain. 327 | if r != "runtime error: interface conversion: interface is nil, not main.I" && 328 | r != "interface conversion: interface is nil, not main.I" { 329 | panic("I->I type assertion succeeded for nil value") 330 | } 331 | }() 332 | var x I 333 | _ = x.(I) 334 | } 335 | 336 | ////////////////////////////////////////////////////////////////////// 337 | // Variadic bridge methods and interface thunks. 338 | 339 | type VT int 340 | 341 | var vcount = 0 342 | 343 | func (VT) f(x int, y ...string) { 344 | vcount++ 345 | if x != 1 { 346 | panic(x) 347 | } 348 | if len(y) != 2 || y[0] != "foo" || y[1] != "bar" { 349 | panic(y) 350 | } 351 | } 352 | 353 | type VS struct { 354 | VT 355 | } 356 | 357 | type VI interface { 358 | f(x int, y ...string) 359 | } 360 | 361 | func init() { 362 | foobar := []string{"foo", "bar"} 363 | var s VS 364 | s.f(1, "foo", "bar") 365 | s.f(1, foobar...) 366 | if vcount != 2 { 367 | panic("s.f not called twice") 368 | } 369 | 370 | fn := VI.f 371 | fn(s, 1, "foo", "bar") 372 | fn(s, 1, foobar...) 373 | if vcount != 4 { 374 | panic("I.f not called twice") 375 | } 376 | } 377 | 378 | // Multiple labels on same statement. 379 | func multipleLabels() { 380 | var trace []int 381 | i := 0 382 | one: 383 | two: 384 | for ; i < 3; i++ { 385 | trace = append(trace, i) 386 | switch i { 387 | case 0: 388 | continue two 389 | case 1: 390 | i++ 391 | goto one 392 | case 2: 393 | break two 394 | } 395 | } 396 | if x := fmt.Sprint(trace); x != "[0 1 2]" { 397 | panic(x) 398 | } 399 | } 400 | 401 | func init() { 402 | multipleLabels() 403 | } 404 | 405 | func init() { 406 | // Struct equivalence ignores blank fields. 407 | type s struct{ x, _, z int } 408 | s1 := s{x: 1, z: 3} 409 | s2 := s{x: 1, z: 3} 410 | if s1 != s2 { 411 | panic("not equal") 412 | } 413 | } 414 | 415 | func init() { 416 | // A slice var can be compared to const []T nil. 417 | var i interface{} = []string{"foo"} 418 | var j interface{} = []string(nil) 419 | if i.([]string) == nil { 420 | panic("expected i non-nil") 421 | } 422 | if j.([]string) != nil { 423 | panic("expected j nil") 424 | } 425 | // But two slices cannot be compared, even if one is nil. 426 | defer func() { 427 | r := fmt.Sprint(recover()) 428 | if r != "runtime error: comparing uncomparable type []string" { 429 | panic("want panic from slice comparison, got " + r) 430 | } 431 | }() 432 | _ = i == j // interface comparison recurses on types 433 | } 434 | 435 | func init() { 436 | // Regression test for SSA renaming bug. 437 | var ints []int 438 | for _ = range "foo" { 439 | var x int 440 | x++ 441 | ints = append(ints, x) 442 | } 443 | if fmt.Sprint(ints) != "[1 1 1]" { 444 | panic(ints) 445 | } 446 | } 447 | 448 | // Regression test for issue 6949: 449 | // []byte("foo") is not a constant since it allocates memory. 450 | func init() { 451 | var r string 452 | for i, b := range "ABC" { 453 | x := []byte("abc") 454 | x[i] = byte(b) 455 | r += string(x) 456 | } 457 | if r != "AbcaBcabC" { 458 | panic(r) 459 | } 460 | } 461 | 462 | // Test of 3-operand x[lo:hi:max] slice. 463 | func init() { 464 | s := []int{0, 1, 2, 3} 465 | lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} } 466 | if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} { 467 | panic(got) 468 | } 469 | if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} { 470 | panic(got) 471 | } 472 | max := 3 473 | if "a"[0] == 'a' { 474 | max = 2 // max is non-constant, even in SSA form 475 | } 476 | if got := lenCapLoHi(s[1:2:max]); got != [4]int{1, 1, 1, 1} { 477 | panic(got) 478 | } 479 | } 480 | 481 | var one = 1 // not a constant 482 | 483 | // Test makeslice. 484 | func init() { 485 | check := func(s []string, wantLen, wantCap int) { 486 | if len(s) != wantLen { 487 | panic(len(s)) 488 | } 489 | if cap(s) != wantCap { 490 | panic(cap(s)) 491 | } 492 | } 493 | // SSA form: 494 | check(make([]string, 10), 10, 10) // new([10]string)[:10] 495 | check(make([]string, one), 1, 1) // make([]string, one, one) 496 | check(make([]string, 0, 10), 0, 10) // new([10]string)[:0] 497 | check(make([]string, 0, one), 0, 1) // make([]string, 0, one) 498 | check(make([]string, one, 10), 1, 10) // new([10]string)[:one] 499 | check(make([]string, one, one), 1, 1) // make([]string, one, one) 500 | } 501 | 502 | // Test that a nice error is issued by indirection wrappers. 503 | func init() { 504 | var ptr *T 505 | var i I = ptr 506 | 507 | defer func() { 508 | r := fmt.Sprint(recover()) 509 | // Exact error varies by toolchain: 510 | if r != "runtime error: value method (main.T).f called using nil *main.T pointer" && 511 | r != "value method main.T.f called using nil *T pointer" { 512 | panic("want panic from call with nil receiver, got " + r) 513 | } 514 | }() 515 | i.f() 516 | panic("unreachable") 517 | } 518 | 519 | // Regression test for a subtle bug in which copying values would causes 520 | // subcomponents of aggregate variables to change address, breaking 521 | // aliases. 522 | func init() { 523 | type T struct{ f int } 524 | var x T 525 | p := &x.f 526 | x = T{} 527 | *p = 1 528 | if x.f != 1 { 529 | panic("lost store") 530 | } 531 | if p != &x.f { 532 | panic("unstable address") 533 | } 534 | } 535 | -------------------------------------------------------------------------------- /interp/value.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io" 11 | "reflect" 12 | "strings" 13 | "sync" 14 | 15 | "go/types" 16 | 17 | "golang.org/x/tools/go/ssa" 18 | "golang.org/x/tools/go/types/typeutil" 19 | ) 20 | 21 | // Ivalue is an interpreter internal value. 22 | // 23 | // All interpreter Ivalues are "boxed" in the empty interface, Ivalue. 24 | // The range of possible dynamic types within Ivalue are: 25 | // 26 | // - bool 27 | // - numbers (all built-in int/float/complex types are distinguished) 28 | // - string 29 | // - map[Ivalue]Ivalue --- maps for which usesBuiltinMap(keyType) 30 | // *hashmap --- maps for which !usesBuiltinMap(keyType) 31 | // - chan Ivalue 32 | // - []Ivalue --- slices 33 | // - iface --- interfaces. 34 | // - structure --- structs. Fields are ordered and accessed by numeric indices. 35 | // - array --- arrays. 36 | // - *Ivalue --- pointers. Careful: *Ivalue is a distinct type from *array etc. 37 | // - *ssa.Function \ 38 | // *ssa.Builtin } --- functions. A nil 'func' is always of type *ssa.Function. 39 | // *closure / 40 | // - tuple --- as returned by Return, Next, "Ivalue,ok" modes, etc. 41 | // - iter --- iterators from 'range' over map or string. 42 | // - bad --- a poison pill for locals that have gone out of scope. 43 | // - rtype -- the interpreter's concrete implementation of reflect.Type 44 | // 45 | // Note that nil is not on this list. 46 | // 47 | // Pay close attention to whether or not the dynamic type is a pointer. 48 | // The compiler cannot help you since Ivalue is an empty interface. 49 | type Ivalue interface{} 50 | 51 | type offset struct { 52 | isStruct bool // this offset relates to a structure (rather than an array) 53 | off uint // the item within the array/structure 54 | } 55 | 56 | type pointer struct { // TODO use this type! 57 | isExt bool // if the object is external 58 | iobj *Ivalue // the base object of the pointer if internal 59 | xobj reflect.Value // the base object of the pointer if external 60 | offs []offset // the offests within that object to get to the item pointed at 61 | } 62 | 63 | type tuple []Ivalue 64 | 65 | type array []Ivalue 66 | 67 | type iface struct { 68 | t types.Type // never an "untyped" type 69 | v Ivalue 70 | } 71 | 72 | type structure []Ivalue 73 | 74 | // For map, array, *array, slice, string or channel. 75 | type iter interface { 76 | // next returns a Tuple (key, Ivalue, ok). 77 | // key and Ivalue are unaliased, e.g. copies of the sequence element. 78 | next() tuple 79 | } 80 | 81 | type closure struct { 82 | Fn *ssa.Function 83 | Env []Ivalue 84 | } 85 | 86 | type bad struct{} 87 | 88 | type rtype struct { 89 | t types.Type 90 | } 91 | 92 | // Hash functions and equivalence relation: 93 | 94 | // hashString computes the FNV hash of s. 95 | func hashString(s string) int { 96 | var h uint32 97 | for i := 0; i < len(s); i++ { 98 | h ^= uint32(s[i]) 99 | h *= 16777619 100 | } 101 | return int(h) 102 | } 103 | 104 | var ( 105 | mu sync.Mutex 106 | hasher = typeutil.MakeHasher() 107 | ) 108 | 109 | // hashType returns a hash for t such that 110 | // types.Identical(x, y) => hashType(x) == hashType(y). 111 | func hashType(t types.Type) int { 112 | mu.Lock() 113 | h := int(hasher.Hash(t)) 114 | mu.Unlock() 115 | return h 116 | } 117 | 118 | // usesBuiltinMap returns true if the built-in hash function and 119 | // equivalence relation for type t are consistent with those of the 120 | // interpreter's representation of type t. Such types are: all basic 121 | // types (bool, numbers, string), pointers and channels. 122 | // 123 | // usesBuiltinMap returns false for types that require a custom map 124 | // implementation: interfaces, arrays and structs. 125 | // 126 | // Panic ensues if t is an invalid map key type: function, map or slice. 127 | func usesBuiltinMap(t types.Type) bool { 128 | switch t := t.(type) { 129 | case *types.Basic, *types.Chan, *types.Pointer: 130 | return true 131 | case *types.Named: 132 | return usesBuiltinMap(t.Underlying()) 133 | case *types.Interface, *types.Array, *types.Struct: 134 | return false 135 | } 136 | panic(fmt.Sprintf("invalid map key type: %T", t)) 137 | } 138 | 139 | func (x array) eq(t types.Type, _y interface{}) bool { 140 | y := _y.(array) 141 | tElt := t.Underlying().(*types.Array).Elem() 142 | for i, xi := range x { 143 | if !equals(tElt, xi, y[i]) { 144 | return false 145 | } 146 | } 147 | return true 148 | } 149 | 150 | func (x array) hash(t types.Type) int { 151 | h := 0 152 | tElt := t.Underlying().(*types.Array).Elem() 153 | for _, xi := range x { 154 | h += hash(tElt, xi) 155 | } 156 | return h 157 | } 158 | 159 | func (x structure) eq(t types.Type, _y interface{}) bool { 160 | y := _y.(structure) 161 | tStruct := t.Underlying().(*types.Struct) 162 | for i, n := 0, tStruct.NumFields(); i < n; i++ { 163 | if f := tStruct.Field(i); !f.Anonymous() { 164 | if !equals(f.Type(), x[i], y[i]) { 165 | return false 166 | } 167 | } 168 | } 169 | return true 170 | } 171 | 172 | func (x structure) hash(t types.Type) int { 173 | tStruct := t.Underlying().(*types.Struct) 174 | h := 0 175 | for i, n := 0, tStruct.NumFields(); i < n; i++ { 176 | if f := tStruct.Field(i); !f.Anonymous() { 177 | h += hash(f.Type(), x[i]) 178 | } 179 | } 180 | return h 181 | } 182 | 183 | // nil-tolerant variant of types.Identical. 184 | func sameType(x, y types.Type) bool { 185 | if x == nil { 186 | return y == nil 187 | } 188 | return y != nil && types.Identical(x, y) 189 | } 190 | 191 | func (x iface) eq(t types.Type, _y interface{}) bool { 192 | y := _y.(iface) 193 | return sameType(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v)) 194 | } 195 | 196 | func (x iface) hash(_ types.Type) int { 197 | return hashType(x.t)*8581 + hash(x.t, x.v) 198 | } 199 | 200 | func (x rtype) hash(_ types.Type) int { 201 | return hashType(x.t) 202 | } 203 | 204 | func (x rtype) eq(_ types.Type, y interface{}) bool { 205 | return types.Identical(x.t, y.(rtype).t) 206 | } 207 | 208 | // equals returns true iff x and y are equal according to Go's 209 | // linguistic equivalence relation for type t. 210 | // In a well-typed program, the dynamic types of x and y are 211 | // guaranteed equal. 212 | func equals(t types.Type, x, y Ivalue) bool { 213 | switch x := x.(type) { 214 | case bool: 215 | return x == y.(bool) 216 | case int: 217 | return x == y.(int) 218 | case int8: 219 | return x == y.(int8) 220 | case int16: 221 | return x == y.(int16) 222 | case int32: 223 | return x == y.(int32) 224 | case int64: 225 | return x == y.(int64) 226 | case uint: 227 | return x == y.(uint) 228 | case uint8: 229 | return x == y.(uint8) 230 | case uint16: 231 | return x == y.(uint16) 232 | case uint32: 233 | return x == y.(uint32) 234 | case uint64: 235 | return x == y.(uint64) 236 | case uintptr: 237 | return x == y.(uintptr) 238 | case float32: 239 | return x == y.(float32) 240 | case float64: 241 | return x == y.(float64) 242 | case complex64: 243 | return x == y.(complex64) 244 | case complex128: 245 | return x == y.(complex128) 246 | case string: 247 | return x == y.(string) 248 | case *Ivalue: 249 | return x == y.(*Ivalue) 250 | case chan Ivalue: 251 | return x == y.(chan Ivalue) 252 | case structure: 253 | return x.eq(t, y) 254 | case array: 255 | return x.eq(t, y) 256 | case iface: 257 | return x.eq(t, y) 258 | case rtype: 259 | return x.eq(t, y) 260 | } 261 | 262 | // Since map, func and slice don't support comparison, this 263 | // case is only reachable if one of x or y is literally nil 264 | // (handled in eqnil) or via interface{} Ivalues. 265 | panic(fmt.Sprintf("comparing uncomparable type %s", t)) 266 | } 267 | 268 | // Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y). 269 | func hash(t types.Type, x Ivalue) int { 270 | switch x := x.(type) { 271 | case bool: 272 | if x { 273 | return 1 274 | } 275 | return 0 276 | case int: 277 | return x 278 | case int8: 279 | return int(x) 280 | case int16: 281 | return int(x) 282 | case int32: 283 | return int(x) 284 | case int64: 285 | return int(x) 286 | case uint: 287 | return int(x) 288 | case uint8: 289 | return int(x) 290 | case uint16: 291 | return int(x) 292 | case uint32: 293 | return int(x) 294 | case uint64: 295 | return int(x) 296 | case uintptr: 297 | return int(x) 298 | case float32: 299 | return int(x) 300 | case float64: 301 | return int(x) 302 | case complex64: 303 | return int(real(x)) 304 | case complex128: 305 | return int(real(x)) 306 | case string: 307 | return hashString(x) 308 | case *Ivalue: 309 | return int(uintptr(reflect.ValueOf(x).Elem().Pointer())) // int(uintptr(unsafe.Pointer(x))) 310 | case chan Ivalue: 311 | return int(uintptr(reflect.ValueOf(x).Pointer())) 312 | case structure: 313 | return x.hash(t) 314 | case array: 315 | return x.hash(t) 316 | case iface: 317 | return x.hash(t) 318 | case rtype: 319 | return x.hash(t) 320 | } 321 | panic(fmt.Sprintf("%T is unhashable", x)) 322 | } 323 | 324 | // reflect.Value struct values don't have a fixed shape, since the 325 | // payload can be a scalar or an aggregate depending on the instance. 326 | // So store (and load) can't simply use recursion over the shape of the 327 | // rhs value, or the lhs, to copy the value; we need the static type 328 | // information. (We can't make reflect.Value a new basic data type 329 | // because its "structness" is exposed to Go programs.) 330 | 331 | // load returns the Ivalue of type T in *addr. 332 | func load(T types.Type, addr *Ivalue) Ivalue { 333 | switch T := T.Underlying().(type) { 334 | case *types.Struct: 335 | v := (*addr).(structure) 336 | a := make(structure, len(v)) 337 | for i := range a { 338 | a[i] = load(T.Field(i).Type(), &v[i]) 339 | } 340 | return a 341 | case *types.Array: 342 | v := (*addr).(array) 343 | a := make(array, len(v)) 344 | for i := range a { 345 | a[i] = load(T.Elem(), &v[i]) 346 | } 347 | return a 348 | default: 349 | ret := *addr 350 | ext, isExt := ret.(reflect.Value) 351 | if isExt { // it is an external global value 352 | ret = Ivalue(reflect.Indirect(ext).Interface()) 353 | } 354 | return ret 355 | } 356 | } 357 | 358 | // store stores Ivalue v of type T into *addr. 359 | func store(T types.Type, addr *Ivalue, v Ivalue) { 360 | switch T := T.Underlying().(type) { 361 | case *types.Struct: 362 | lhs := (*addr).(structure) 363 | rhs := v.(structure) 364 | for i := range lhs { 365 | store(T.Field(i).Type(), &lhs[i], rhs[i]) 366 | } 367 | case *types.Array: 368 | lhs := (*addr).(array) 369 | rhs := v.(array) 370 | for i := range lhs { 371 | store(T.Elem(), &lhs[i], rhs[i]) 372 | } 373 | default: 374 | target := *addr 375 | _, isExt := target.(reflect.Value) 376 | if isExt { // it is an external global value 377 | // NOTE external global values can only be read, never written 378 | //ext.Elem().Set(reflect.ValueOf(IvalIface(v))) 379 | } else { 380 | *addr = v 381 | } 382 | } 383 | } 384 | 385 | // Prints in the style of built-in println. 386 | // (More or less; in gc println is actually a compiler intrinsic and 387 | // can distinguish println(1) from println(interface{}(1)).) 388 | func writeIvalue(buf *bytes.Buffer, v Ivalue) { 389 | switch v := v.(type) { 390 | case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string: 391 | fmt.Fprintf(buf, "%v", v) 392 | 393 | case map[Ivalue]Ivalue: 394 | buf.WriteString("map[") 395 | sep := "" 396 | for k, e := range v { 397 | buf.WriteString(sep) 398 | sep = " " 399 | writeIvalue(buf, k) 400 | buf.WriteString(":") 401 | writeIvalue(buf, e) 402 | } 403 | buf.WriteString("]") 404 | 405 | case *hashmap: 406 | buf.WriteString("map[") 407 | sep := " " 408 | for _, e := range v.table { 409 | for e != nil { 410 | buf.WriteString(sep) 411 | sep = " " 412 | writeIvalue(buf, e.key) 413 | buf.WriteString(":") 414 | writeIvalue(buf, e.Ivalue) 415 | e = e.next 416 | } 417 | } 418 | buf.WriteString("]") 419 | 420 | case chan Ivalue: 421 | fmt.Fprintf(buf, "%v", v) // (an address) 422 | 423 | case *Ivalue: 424 | if v == nil { 425 | buf.WriteString("") 426 | } else { 427 | fmt.Fprintf(buf, "%p", v) 428 | } 429 | 430 | case iface: 431 | fmt.Fprintf(buf, "(%s, ", v.t) 432 | writeIvalue(buf, v.v) 433 | buf.WriteString(")") 434 | 435 | case structure: 436 | buf.WriteString("{") 437 | for i, e := range v { 438 | if i > 0 { 439 | buf.WriteString(" ") 440 | } 441 | writeIvalue(buf, e) 442 | } 443 | buf.WriteString("}") 444 | 445 | case array: 446 | buf.WriteString("[") 447 | for i, e := range v { 448 | if i > 0 { 449 | buf.WriteString(" ") 450 | } 451 | writeIvalue(buf, e) 452 | } 453 | buf.WriteString("]") 454 | 455 | case []Ivalue: 456 | buf.WriteString("[") 457 | for i, e := range v { 458 | if i > 0 { 459 | buf.WriteString(" ") 460 | } 461 | writeIvalue(buf, e) 462 | } 463 | buf.WriteString("]") 464 | 465 | case *ssa.Function, *ssa.Builtin, *closure: 466 | fmt.Fprintf(buf, "%p", v) // (an address) 467 | 468 | case rtype: 469 | buf.WriteString(v.t.String()) 470 | 471 | case tuple: 472 | // Unreachable in well-formed Go programs 473 | buf.WriteString("(") 474 | for i, e := range v { 475 | if i > 0 { 476 | buf.WriteString(", ") 477 | } 478 | writeIvalue(buf, e) 479 | } 480 | buf.WriteString(")") 481 | 482 | default: 483 | fmt.Fprintf(buf, "<%T>", v) 484 | } 485 | } 486 | 487 | // Implements printing of Go Ivalues in the style of built-in println. 488 | func toString(v Ivalue) string { 489 | var b bytes.Buffer 490 | writeIvalue(&b, v) 491 | return b.String() 492 | } 493 | 494 | // ------------------------------------------------------------------------ 495 | // Iterators 496 | 497 | type stringIter struct { 498 | *strings.Reader 499 | i int 500 | } 501 | 502 | func (it *stringIter) next() tuple { 503 | okv := make(tuple, 3) 504 | ch, n, err := it.ReadRune() 505 | ok := err != io.EOF 506 | okv[0] = ok 507 | if ok { 508 | okv[1] = it.i 509 | okv[2] = ch 510 | } 511 | it.i += n 512 | return okv 513 | } 514 | 515 | type mapIter chan [2]Ivalue 516 | 517 | func (it mapIter) next() tuple { 518 | kv, ok := <-it 519 | return tuple{ok, kv[0], kv[1]} 520 | } 521 | -------------------------------------------------------------------------------- /interp/reflect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | // Emulated "reflect" package. 8 | // 9 | // We completely replace the built-in "reflect" package. 10 | // The only thing clients can depend upon are that reflect.Type is an 11 | // interface and reflect.Value is an (opaque) struct. 12 | 13 | import ( 14 | "fmt" 15 | "go/token" 16 | "reflect" 17 | 18 | "go/types" 19 | 20 | "golang.org/x/tools/go/ssa" 21 | ) 22 | 23 | type opaqueType struct { 24 | types.Type 25 | name string 26 | } 27 | 28 | func (t *opaqueType) String() string { return t.name } 29 | 30 | // A bogus "reflect" type-checker package. Shared across interpreters. 31 | var reflectTypesPackage = types.NewPackage("reflect", "reflect") 32 | 33 | // rtype is the concrete type the interpreter uses to implement the 34 | // reflect.Type interface. 35 | // 36 | // type rtype 37 | var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"}) 38 | 39 | // error is an (interpreted) named type whose underlying type is string. 40 | // The interpreter uses it for all implementations of the built-in error 41 | // interface that it creates. 42 | // We put it in the "reflect" package for expedience. 43 | // 44 | // type error string 45 | var errorType = makeNamedType("error", &opaqueType{nil, "error"}) 46 | 47 | func makeNamedType(name string, underlying types.Type) *types.Named { 48 | obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil) 49 | return types.NewNamed(obj, underlying, nil) 50 | } 51 | 52 | func makeReflectIvalue(t types.Type, v Ivalue) Ivalue { 53 | return structure{rtype{t}, v} 54 | } 55 | 56 | // Given a reflect.Value, returns its rtype. 57 | func rV2T(v Ivalue) rtype { 58 | return v.(structure)[0].(rtype) 59 | } 60 | 61 | // Given a reflect.Value, returns the underlying interpreter Ivalue. 62 | func rV2V(v Ivalue) Ivalue { 63 | return v.(structure)[1] 64 | } 65 | 66 | // makeReflectType boxes up an rtype in a reflect.Type interface. 67 | func makeReflectType(rt rtype) Ivalue { 68 | return iface{rtypeType, rt} 69 | } 70 | 71 | func ext۰reflect۰Init(fr *frame, args []Ivalue) Ivalue { 72 | // Signature: func() 73 | return nil 74 | } 75 | 76 | func ext۰reflect۰rtype۰Bits(fr *frame, args []Ivalue) Ivalue { 77 | // Signature: func (t reflect.rtype) int 78 | rt := args[0].(rtype).t 79 | basic, ok := rt.Underlying().(*types.Basic) 80 | if !ok { 81 | panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt)) 82 | } 83 | return int(fr.i.sizes.Sizeof(basic)) * 8 84 | } 85 | 86 | func ext۰reflect۰rtype۰Elem(fr *frame, args []Ivalue) Ivalue { 87 | // Signature: func (t reflect.rtype) reflect.Type 88 | return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface { 89 | Elem() types.Type 90 | }).Elem()}) 91 | } 92 | 93 | func ext۰reflect۰rtype۰Field(fr *frame, args []Ivalue) Ivalue { 94 | // Signature: func (t reflect.rtype, i int) reflect.StructField 95 | st := args[0].(rtype).t.Underlying().(*types.Struct) 96 | i := args[1].(int) 97 | f := st.Field(i) 98 | return structure{ 99 | f.Name(), 100 | f.Pkg().Path(), 101 | makeReflectType(rtype{f.Type()}), 102 | st.Tag(i), 103 | 0, // TODO(adonovan): offset 104 | []Ivalue{}, // TODO(adonovan): indices 105 | f.Anonymous(), 106 | } 107 | } 108 | 109 | func ext۰reflect۰rtype۰In(fr *frame, args []Ivalue) Ivalue { 110 | // Signature: func (t reflect.rtype, i int) int 111 | i := args[1].(int) 112 | return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()}) 113 | } 114 | 115 | func ext۰reflect۰rtype۰Kind(fr *frame, args []Ivalue) Ivalue { 116 | // Signature: func (t reflect.rtype) uint 117 | return uint(reflectKind(args[0].(rtype).t)) 118 | } 119 | 120 | func ext۰reflect۰rtype۰NumField(fr *frame, args []Ivalue) Ivalue { 121 | // Signature: func (t reflect.rtype) int 122 | return args[0].(rtype).t.Underlying().(*types.Struct).NumFields() 123 | } 124 | 125 | func ext۰reflect۰rtype۰NumIn(fr *frame, args []Ivalue) Ivalue { 126 | // Signature: func (t reflect.rtype) int 127 | return args[0].(rtype).t.(*types.Signature).Params().Len() 128 | } 129 | 130 | func ext۰reflect۰rtype۰NumMethod(fr *frame, args []Ivalue) Ivalue { 131 | // Signature: func (t reflect.rtype) int 132 | return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len() 133 | } 134 | 135 | func ext۰reflect۰rtype۰NumOut(fr *frame, args []Ivalue) Ivalue { 136 | // Signature: func (t reflect.rtype) int 137 | return args[0].(rtype).t.(*types.Signature).Results().Len() 138 | } 139 | 140 | func ext۰reflect۰rtype۰Out(fr *frame, args []Ivalue) Ivalue { 141 | // Signature: func (t reflect.rtype, i int) int 142 | i := args[1].(int) 143 | return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()}) 144 | } 145 | 146 | func ext۰reflect۰rtype۰Size(fr *frame, args []Ivalue) Ivalue { 147 | // Signature: func (t reflect.rtype) uintptr 148 | return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t)) 149 | } 150 | 151 | func ext۰reflect۰rtype۰String(fr *frame, args []Ivalue) Ivalue { 152 | // Signature: func (t reflect.rtype) string 153 | return args[0].(rtype).t.String() 154 | } 155 | 156 | func ext۰reflect۰New(fr *frame, args []Ivalue) Ivalue { 157 | // Signature: func (t reflect.Type) reflect.Value 158 | t := args[0].(iface).v.(rtype).t 159 | alloc := fr.i.zero(t) 160 | return makeReflectIvalue(types.NewPointer(t), &alloc) 161 | } 162 | 163 | func ext۰reflect۰SliceOf(fr *frame, args []Ivalue) Ivalue { 164 | // Signature: func (t reflect.rtype) Type 165 | return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)}) 166 | } 167 | 168 | func ext۰reflect۰TypeOf(fr *frame, args []Ivalue) Ivalue { 169 | // Signature: func (t reflect.rtype) Type 170 | return makeReflectType(rtype{args[0].(iface).t}) 171 | } 172 | 173 | func ext۰reflect۰ValueOf(fr *frame, args []Ivalue) Ivalue { 174 | // Signature: func (interface{}) reflect.Value 175 | itf := args[0].(iface) 176 | return makeReflectIvalue(itf.t, itf.v) 177 | } 178 | 179 | func ext۰reflect۰Zero(fr *frame, args []Ivalue) Ivalue { 180 | // Signature: func (t reflect.Type) reflect.Value 181 | t := args[0].(iface).v.(rtype).t 182 | return makeReflectIvalue(t, fr.i.zero(t)) 183 | } 184 | 185 | func reflectKind(t types.Type) reflect.Kind { 186 | switch t := t.(type) { 187 | case *types.Named: 188 | return reflectKind(t.Underlying()) 189 | case *types.Basic: 190 | switch t.Kind() { 191 | case types.Bool: 192 | return reflect.Bool 193 | case types.Int: 194 | return reflect.Int 195 | case types.Int8: 196 | return reflect.Int8 197 | case types.Int16: 198 | return reflect.Int16 199 | case types.Int32: 200 | return reflect.Int32 201 | case types.Int64: 202 | return reflect.Int64 203 | case types.Uint: 204 | return reflect.Uint 205 | case types.Uint8: 206 | return reflect.Uint8 207 | case types.Uint16: 208 | return reflect.Uint16 209 | case types.Uint32: 210 | return reflect.Uint32 211 | case types.Uint64: 212 | return reflect.Uint64 213 | case types.Uintptr: 214 | return reflect.Uintptr 215 | case types.Float32: 216 | return reflect.Float32 217 | case types.Float64: 218 | return reflect.Float64 219 | case types.Complex64: 220 | return reflect.Complex64 221 | case types.Complex128: 222 | return reflect.Complex128 223 | case types.String: 224 | return reflect.String 225 | case types.UnsafePointer: 226 | return reflect.UnsafePointer 227 | } 228 | case *types.Array: 229 | return reflect.Array 230 | case *types.Chan: 231 | return reflect.Chan 232 | case *types.Signature: 233 | return reflect.Func 234 | case *types.Interface: 235 | return reflect.Interface 236 | case *types.Map: 237 | return reflect.Map 238 | case *types.Pointer: 239 | return reflect.Ptr 240 | case *types.Slice: 241 | return reflect.Slice 242 | case *types.Struct: 243 | return reflect.Struct 244 | } 245 | panic(fmt.Sprint("unexpected type: ", t)) 246 | } 247 | 248 | func ext۰reflect۰Value۰Kind(fr *frame, args []Ivalue) Ivalue { 249 | // Signature: func (reflect.Value) uint 250 | return uint(reflectKind(rV2T(args[0]).t)) 251 | } 252 | 253 | func ext۰reflect۰Value۰String(fr *frame, args []Ivalue) Ivalue { 254 | // Signature: func (reflect.Value) string 255 | return toString(rV2V(args[0])) 256 | } 257 | 258 | func ext۰reflect۰Value۰Type(fr *frame, args []Ivalue) Ivalue { 259 | // Signature: func (reflect.Value) reflect.Type 260 | return makeReflectType(rV2T(args[0])) 261 | } 262 | 263 | func ext۰reflect۰Value۰Uint(fr *frame, args []Ivalue) Ivalue { 264 | // Signature: func (reflect.Value) uint64 265 | switch v := rV2V(args[0]).(type) { 266 | case uint: 267 | return uint64(v) 268 | case uint8: 269 | return uint64(v) 270 | case uint16: 271 | return uint64(v) 272 | case uint32: 273 | return uint64(v) 274 | case uint64: 275 | return uint64(v) 276 | case uintptr: 277 | return uint64(v) 278 | } 279 | panic("reflect.Value.Uint") 280 | } 281 | 282 | func ext۰reflect۰Value۰Len(fr *frame, args []Ivalue) Ivalue { 283 | // Signature: func (reflect.Value) int 284 | switch v := rV2V(args[0]).(type) { 285 | case string: 286 | return len(v) 287 | case array: 288 | return len(v) 289 | case chan Ivalue: 290 | return cap(v) 291 | case []Ivalue: 292 | return len(v) 293 | case *hashmap: 294 | return v.len() 295 | case map[Ivalue]Ivalue: 296 | return len(v) 297 | default: 298 | panic(fmt.Sprintf("reflect.(Ivalue).Len(%v)", v)) 299 | } 300 | } 301 | 302 | func ext۰reflect۰Value۰MapIndex(fr *frame, args []Ivalue) Ivalue { 303 | // Signature: func (reflect.Value) Ivalue 304 | tIvalue := rV2T(args[0]).t.Underlying().(*types.Map).Key() 305 | k := rV2V(args[1]) 306 | switch m := rV2V(args[0]).(type) { 307 | case map[Ivalue]Ivalue: 308 | if v, ok := m[k]; ok { 309 | return makeReflectIvalue(tIvalue, v) 310 | } 311 | 312 | case *hashmap: 313 | if v := m.lookup(k.(hashable)); v != nil { 314 | return makeReflectIvalue(tIvalue, v) 315 | } 316 | 317 | default: 318 | panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k)) 319 | } 320 | return makeReflectIvalue(nil, nil) 321 | } 322 | 323 | func ext۰reflect۰Value۰MapKeys(fr *frame, args []Ivalue) Ivalue { 324 | // Signature: func (reflect.Value) []Ivalue 325 | var keys []Ivalue 326 | tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key() 327 | switch v := rV2V(args[0]).(type) { 328 | case map[Ivalue]Ivalue: 329 | for k := range v { 330 | keys = append(keys, makeReflectIvalue(tKey, k)) 331 | } 332 | 333 | case *hashmap: 334 | for _, e := range v.table { 335 | for ; e != nil; e = e.next { 336 | keys = append(keys, makeReflectIvalue(tKey, e.key)) 337 | } 338 | } 339 | 340 | default: 341 | panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v)) 342 | } 343 | return keys 344 | } 345 | 346 | func ext۰reflect۰Value۰NumField(fr *frame, args []Ivalue) Ivalue { 347 | // Signature: func (reflect.Value) int 348 | return len(rV2V(args[0]).(structure)) 349 | } 350 | 351 | func ext۰reflect۰Value۰NumMethod(fr *frame, args []Ivalue) Ivalue { 352 | // Signature: func (reflect.Value) int 353 | return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len() 354 | } 355 | 356 | func ext۰reflect۰Value۰Pointer(fr *frame, args []Ivalue) Ivalue { 357 | // Signature: func (v reflect.Value) uintptr 358 | switch v := rV2V(args[0]).(type) { 359 | case *Ivalue: 360 | return reflect.ValueOf(v).Pointer() // uintptr(unsafe.Pointer(v)) 361 | case chan Ivalue: 362 | return reflect.ValueOf(v).Pointer() 363 | case []Ivalue: 364 | return reflect.ValueOf(v).Pointer() 365 | case *hashmap: 366 | return reflect.ValueOf(v.table).Pointer() 367 | case map[Ivalue]Ivalue: 368 | return reflect.ValueOf(v).Pointer() 369 | case *ssa.Function: 370 | return reflect.ValueOf(v).Pointer() // uintptr(unsafe.Pointer(v)) 371 | case *closure: 372 | return reflect.ValueOf(v).Pointer() // uintptr(unsafe.Pointer(v)) 373 | default: 374 | panic(fmt.Sprintf("reflect.(Ivalue).Pointer(%T)", v)) 375 | } 376 | } 377 | 378 | func ext۰reflect۰Value۰Index(fr *frame, args []Ivalue) Ivalue { 379 | // Signature: func (v reflect.Value, i int) Ivalue 380 | i := args[1].(int) 381 | t := rV2T(args[0]).t.Underlying() 382 | switch v := rV2V(args[0]).(type) { 383 | case array: 384 | return makeReflectIvalue(t.(*types.Array).Elem(), v[i]) 385 | case []Ivalue: 386 | return makeReflectIvalue(t.(*types.Slice).Elem(), v[i]) 387 | default: 388 | panic(fmt.Sprintf("reflect.(Ivalue).Index(%T)", v)) 389 | } 390 | } 391 | 392 | func ext۰reflect۰Value۰Bool(fr *frame, args []Ivalue) Ivalue { 393 | // Signature: func (reflect.Value) bool 394 | return rV2V(args[0]).(bool) 395 | } 396 | 397 | func ext۰reflect۰Value۰CanAddr(fr *frame, args []Ivalue) Ivalue { 398 | // Signature: func (v reflect.Value) bool 399 | // Always false for our representation. 400 | return false 401 | } 402 | 403 | func ext۰reflect۰Value۰CanInterface(fr *frame, args []Ivalue) Ivalue { 404 | // Signature: func (v reflect.Value) bool 405 | // Always true for our representation. 406 | return true 407 | } 408 | 409 | func ext۰reflect۰Value۰Elem(fr *frame, args []Ivalue) Ivalue { 410 | // Signature: func (v reflect.Value) reflect.Value 411 | switch x := rV2V(args[0]).(type) { 412 | case iface: 413 | return makeReflectIvalue(x.t, x.v) 414 | case *Ivalue: 415 | return makeReflectIvalue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x) 416 | default: 417 | panic(fmt.Sprintf("reflect.(Ivalue).Elem(%T)", x)) 418 | } 419 | } 420 | 421 | func ext۰reflect۰Value۰Field(fr *frame, args []Ivalue) Ivalue { 422 | // Signature: func (v reflect.Value, i int) reflect.Value 423 | v := args[0] 424 | i := args[1].(int) 425 | return makeReflectIvalue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i]) 426 | } 427 | 428 | func ext۰reflect۰Value۰Float(fr *frame, args []Ivalue) Ivalue { 429 | // Signature: func (reflect.Value) float64 430 | switch v := rV2V(args[0]).(type) { 431 | case float32: 432 | return float64(v) 433 | case float64: 434 | return float64(v) 435 | } 436 | panic("reflect.Value.Float") 437 | } 438 | 439 | func ext۰reflect۰Value۰Interface(fr *frame, args []Ivalue) Ivalue { 440 | // Signature: func (v reflect.Value) interface{} 441 | return ext۰reflect۰valueInterface(fr, args) 442 | } 443 | 444 | func ext۰reflect۰Value۰Int(fr *frame, args []Ivalue) Ivalue { 445 | // Signature: func (reflect.Value) int64 446 | switch x := rV2V(args[0]).(type) { 447 | case int: 448 | return int64(x) 449 | case int8: 450 | return int64(x) 451 | case int16: 452 | return int64(x) 453 | case int32: 454 | return int64(x) 455 | case int64: 456 | return x 457 | default: 458 | panic(fmt.Sprintf("reflect.(Ivalue).Int(%T)", x)) 459 | } 460 | } 461 | 462 | func ext۰reflect۰Value۰IsNil(fr *frame, args []Ivalue) Ivalue { 463 | // Signature: func (reflect.Value) bool 464 | switch x := rV2V(args[0]).(type) { 465 | case *Ivalue: 466 | return x == nil 467 | case chan Ivalue: 468 | return x == nil 469 | case map[Ivalue]Ivalue: 470 | return x == nil 471 | case *hashmap: 472 | return x == nil 473 | case iface: 474 | return x.t == nil 475 | case []Ivalue: 476 | return x == nil 477 | case *ssa.Function: 478 | return x == nil 479 | case *ssa.Builtin: 480 | return x == nil 481 | case *closure: 482 | return x == nil 483 | default: 484 | panic(fmt.Sprintf("reflect.(Ivalue).IsNil(%T)", x)) 485 | } 486 | } 487 | 488 | func ext۰reflect۰Value۰IsValid(fr *frame, args []Ivalue) Ivalue { 489 | // Signature: func (reflect.Value) bool 490 | return rV2V(args[0]) != nil 491 | } 492 | 493 | func ext۰reflect۰Value۰Set(fr *frame, args []Ivalue) Ivalue { 494 | // TODO(adonovan): implement. 495 | return nil 496 | } 497 | 498 | func ext۰reflect۰valueInterface(fr *frame, args []Ivalue) Ivalue { 499 | // Signature: func (v reflect.Value, safe bool) interface{} 500 | v := args[0].(structure) 501 | return iface{rV2T(v).t, rV2V(v)} 502 | } 503 | 504 | func ext۰reflect۰error۰Error(fr *frame, args []Ivalue) Ivalue { 505 | return args[0] 506 | } 507 | 508 | // newMethod creates a new method of the specified name, package and receiver type. 509 | func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function { 510 | // TODO(adonovan): fix: hack: currently the only part of Signature 511 | // that is needed is the "pointerness" of Recv.Type, and for 512 | // now, we'll set it to always be false since we're only 513 | // concerned with rtype. Encapsulate this better. 514 | sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) 515 | fn := pkg.Prog.NewFunction(name, sig, "fake reflect method") 516 | fn.Pkg = pkg 517 | return fn 518 | } 519 | 520 | func initReflect(i *interpreter) { 521 | i.reflectPackage = &ssa.Package{ 522 | Prog: i.prog, 523 | Pkg: reflectTypesPackage, 524 | Members: make(map[string]ssa.Member), 525 | } 526 | 527 | // Clobber the type-checker's notion of reflect.Value's 528 | // underlying type so that it more closely matches the fake one 529 | // (at least in the number of fields---we lie about the type of 530 | // the rtype field). 531 | // 532 | // We must ensure that calls to (ssa.Value).Type() return the 533 | // fake type so that correct "shape" is used when allocating 534 | // variables, making zero Ivalues, loading, and storing. 535 | // 536 | // TODO(adonovan): obviously this is a hack. We need a cleaner 537 | // way to fake the reflect package (almost---DeepEqual is fine). 538 | // One approach would be not to even load its source code, but 539 | // provide fake source files. This would guarantee that no bad 540 | // information leaks into other packages. 541 | if r := i.prog.ImportedPackage("reflect"); r != nil { 542 | rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named) 543 | 544 | // delete bodies of the old methods 545 | mset := i.prog.MethodSets.MethodSet(rV) 546 | for j := 0; j < mset.Len(); j++ { 547 | i.prog.MethodValue(mset.At(j)).Blocks = nil 548 | } 549 | 550 | tEface := types.NewInterface(nil, nil).Complete() 551 | rV.SetUnderlying(types.NewStruct([]*types.Var{ 552 | types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie 553 | types.NewField(token.NoPos, r.Pkg, "v", tEface, false), 554 | }, nil)) 555 | } 556 | 557 | i.rtypeMethods = methodSet{ 558 | "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), 559 | "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), 560 | "Field": newMethod(i.reflectPackage, rtypeType, "Field"), 561 | "In": newMethod(i.reflectPackage, rtypeType, "In"), 562 | "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), 563 | "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"), 564 | "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"), 565 | "NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"), 566 | "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"), 567 | "Out": newMethod(i.reflectPackage, rtypeType, "Out"), 568 | "Size": newMethod(i.reflectPackage, rtypeType, "Size"), 569 | "String": newMethod(i.reflectPackage, rtypeType, "String"), 570 | } 571 | i.errorMethods = methodSet{ 572 | "Error": newMethod(i.reflectPackage, errorType, "Error"), 573 | } 574 | } 575 | -------------------------------------------------------------------------------- /interp/external.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | // Emulated functions that we cannot interpret because they are 8 | // external or because they use "unsafe" or "reflect" operations. 9 | 10 | import ( 11 | "fmt" 12 | "math" 13 | "os" 14 | "reflect" 15 | "runtime" 16 | "strings" 17 | "sync" 18 | "sync/atomic" 19 | "syscall" 20 | "time" 21 | 22 | "go/types" 23 | 24 | "golang.org/x/tools/go/ssa" 25 | ) 26 | 27 | type externalFn func(fr *frame, args []Ivalue) Ivalue 28 | 29 | // TODO(adonovan): fix: reflect.Value abstracts an lIvalue or an 30 | // rIvalue; Set() causes mutations that can be observed via aliases. 31 | // We have not captured that correctly here. 32 | 33 | // Key strings are from Function.String(). 34 | var externals map[string]externalFn 35 | 36 | func init() { 37 | // That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd]. 38 | externals = map[string]externalFn{ 39 | "(*sync.Pool).Get": ext۰sync۰Pool۰Get, 40 | "(*sync.Pool).Put": ext۰sync۰Pool۰Put, 41 | "(reflect.Value).Bool": ext۰reflect۰Value۰Bool, 42 | "(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr, 43 | "(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface, 44 | "(reflect.Value).Elem": ext۰reflect۰Value۰Elem, 45 | "(reflect.Value).Field": ext۰reflect۰Value۰Field, 46 | "(reflect.Value).Float": ext۰reflect۰Value۰Float, 47 | "(reflect.Value).Index": ext۰reflect۰Value۰Index, 48 | "(reflect.Value).Int": ext۰reflect۰Value۰Int, 49 | "(reflect.Value).Interface": ext۰reflect۰Value۰Interface, 50 | "(reflect.Value).IsNil": ext۰reflect۰Value۰IsNil, 51 | "(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid, 52 | "(reflect.Value).Kind": ext۰reflect۰Value۰Kind, 53 | "(reflect.Value).Len": ext۰reflect۰Value۰Len, 54 | "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex, 55 | "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys, 56 | "(reflect.Value).NumField": ext۰reflect۰Value۰NumField, 57 | "(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod, 58 | "(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer, 59 | "(reflect.Value).Set": ext۰reflect۰Value۰Set, 60 | "(reflect.Value).String": ext۰reflect۰Value۰String, 61 | "(reflect.Value).Type": ext۰reflect۰Value۰Type, 62 | "(reflect.Value).Uint": ext۰reflect۰Value۰Uint, 63 | "(reflect.error).Error": ext۰reflect۰error۰Error, 64 | "(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits, 65 | "(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem, 66 | "(reflect.rtype).Field": ext۰reflect۰rtype۰Field, 67 | "(reflect.rtype).In": ext۰reflect۰rtype۰In, 68 | "(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind, 69 | "(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField, 70 | "(reflect.rtype).NumIn": ext۰reflect۰rtype۰NumIn, 71 | "(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod, 72 | "(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut, 73 | "(reflect.rtype).Out": ext۰reflect۰rtype۰Out, 74 | "(reflect.rtype).Size": ext۰reflect۰rtype۰Size, 75 | "(reflect.rtype).String": ext۰reflect۰rtype۰String, 76 | "bytes.Equal": ext۰bytes۰Equal, 77 | "bytes.Compare": ext۰bytes۰Compare, 78 | "bytes.IndexByte": ext۰bytes۰IndexByte, 79 | "hash/crc32.haveSSE41": ext۰crc32۰haveSSE42, // Elliott 80 | "hash/crc32.haveSSE42": ext۰crc32۰haveSSE42, 81 | "hash/crc32.haveCLMUL": ext۰crc32۰haveSSE42, // Elliott 82 | "math.Abs": ext۰math۰Abs, 83 | "math.Exp": ext۰math۰Exp, 84 | "math.Float32bits": ext۰math۰Float32bits, 85 | "math.Float32frombits": ext۰math۰Float32frombits, 86 | "math.Float64bits": ext۰math۰Float64bits, 87 | "math.Float64frombits": ext۰math۰Float64frombits, 88 | "math.Ldexp": ext۰math۰Ldexp, 89 | "math.Log": ext۰math۰Log, 90 | "math.Min": ext۰math۰Min, 91 | "math.Sqrt": ext۰math۰Sqrt, // Elliott 92 | "math.hasSSE4": ext۰math۰hasSSE4, // Elliott 93 | "os.runtime_args": ext۰os۰runtime_args, 94 | "os.runtime_beforeExit": ext۰os۰runtime_beforeExit, 95 | "reflect.New": ext۰reflect۰New, 96 | "reflect.SliceOf": ext۰reflect۰SliceOf, 97 | "reflect.TypeOf": ext۰reflect۰TypeOf, 98 | "reflect.ValueOf": ext۰reflect۰ValueOf, 99 | "reflect.Zero": ext۰reflect۰Zero, 100 | "reflect.init": ext۰reflect۰Init, 101 | "reflect.valueInterface": ext۰reflect۰valueInterface, 102 | "runtime.Breakpoint": ext۰runtime۰Breakpoint, 103 | "runtime.Caller": ext۰runtime۰Caller, 104 | "runtime.Callers": ext۰runtime۰Callers, 105 | "runtime.FuncForPC": ext۰runtime۰FuncForPC, 106 | "runtime.GC": ext۰runtime۰GC, 107 | "runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS, 108 | "runtime.Goexit": ext۰runtime۰Goexit, 109 | "runtime.Gosched": ext۰runtime۰Gosched, 110 | "runtime.init": ext۰runtime۰init, 111 | "runtime.NumCPU": ext۰runtime۰NumCPU, 112 | "runtime.NumGoroutine": ext۰runtime۰NumGoroutine, 113 | "runtime.ReadMemStats": ext۰runtime۰ReadMemStats, 114 | "runtime.SetFinalizer": ext۰runtime۰SetFinalizer, 115 | "(*runtime.Func).Entry": ext۰runtime۰Func۰Entry, 116 | "(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine, 117 | "(*runtime.Func).Name": ext۰runtime۰Func۰Name, 118 | "runtime.environ": ext۰runtime۰environ, 119 | "runtime.getgoroot": ext۰runtime۰getgoroot, 120 | "strings.IndexByte": ext۰strings۰IndexByte, 121 | "strings.indexShortStr": ext۰strings۰indexShortStr, //Elliott 122 | "sync.runtime_Semacquire": ext۰sync۰runtime_Semacquire, 123 | "sync.runtime_Semrelease": ext۰sync۰runtime_Semrelease, 124 | "sync.runtime_Syncsemcheck": ext۰sync۰runtime_Syncsemcheck, 125 | "sync.runtime_canSpin": sync۰runtime۰canSpin, // Elliott 126 | "sync.runtime_doSpin": sync۰runtime۰doSpin, // Elliott 127 | "sync.runtime_notifyListCheck": sync۰runtime۰notifyListCheck, // Elliott 128 | "sync.runtime_registerPoolCleanup": ext۰sync۰runtime_registerPoolCleanup, 129 | "sync/atomic.AddInt32": ext۰atomic۰AddInt32, 130 | "sync/atomic.AddUint32": ext۰atomic۰AddUint32, 131 | "sync/atomic.AddUint64": ext۰atomic۰AddUint64, 132 | "sync/atomic.AddInt64": ext۰atomic۰AddInt64, // Elliott 133 | "sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32, 134 | "sync/atomic.CompareAndSwapUint64": ext۰atomic۰CompareAndSwapUint64, // Elliott 135 | "sync/atomic.LoadInt32": ext۰atomic۰LoadInt32, 136 | "sync/atomic.LoadInt64": ext۰atomic۰LoadInt64, // Elliott 137 | "sync/atomic.LoadUint32": ext۰atomic۰LoadUint32, 138 | "sync/atomic.LoadUint64": ext۰atomic۰LoadUint64, // Elliott 139 | "sync/atomic.StoreInt32": ext۰atomic۰StoreInt32, 140 | "sync/atomic.StoreUint32": ext۰atomic۰StoreUint32, 141 | "syscall.Close": ext۰syscall۰Close, 142 | "syscall.Exit": ext۰syscall۰Exit, 143 | "syscall.Fstat": ext۰syscall۰Fstat, 144 | "syscall.Getpid": ext۰syscall۰Getpid, 145 | "syscall.Getwd": ext۰syscall۰Getwd, 146 | "syscall.Kill": ext۰syscall۰Kill, 147 | "syscall.Lstat": ext۰syscall۰Lstat, 148 | "syscall.Open": ext۰syscall۰Open, 149 | "syscall.ParseDirent": ext۰syscall۰ParseDirent, 150 | "syscall.RawSyscall": ext۰syscall۰RawSyscall, 151 | "syscall.Read": ext۰syscall۰Read, 152 | "syscall.ReadDirent": ext۰syscall۰ReadDirent, 153 | "syscall.Stat": ext۰syscall۰Stat, 154 | "syscall.Write": ext۰syscall۰Write, 155 | "syscall.Pipe": ext۰syscall۰Pipe, 156 | "syscall.Syscall": ext۰syscall۰Syscall, 157 | "syscall.CloseOnExec": ext۰syscall۰CloseOnExec, 158 | "syscall.runtime_envs": ext۰runtime۰environ, 159 | "syscall.now": ext۰time۰now, 160 | "time.Sleep": ext۰time۰Sleep, 161 | "time.now": ext۰time۰now, 162 | "time.runtimeNano": ext۰time۰runtimeNano, 163 | } 164 | } 165 | 166 | // wrapError returns an interpreted 'error' interface Ivalue for err. 167 | func wrapError(err error) Ivalue { 168 | if err == nil { 169 | return iface{} 170 | } 171 | return iface{t: errorType, v: err.Error()} 172 | } 173 | 174 | func sync۰runtime۰canSpin(fr *frame, args []Ivalue) Ivalue { //i int) bool { // Elliott 175 | return true 176 | } 177 | func sync۰runtime۰doSpin(fr *frame, args []Ivalue) Ivalue { //) { // Elliott 178 | runtime.Gosched() 179 | return nil 180 | } 181 | 182 | // NumGoroutine returns the number of goroutines that currently exist. 183 | func ext۰runtime۰NumGoroutine(fr *frame, args []Ivalue) Ivalue { // Elliott 184 | return int(atomic.LoadInt32(&fr.i.goroutines)) 185 | } 186 | 187 | // Ensure that sync and runtime agree on size of notifyList. 188 | func sync۰runtime۰notifyListCheck(fr *frame, args []Ivalue) Ivalue { // Elliott 189 | return nil 190 | } 191 | 192 | func ext۰sync۰Pool۰Get(fr *frame, args []Ivalue) Ivalue { 193 | Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object() 194 | _, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New") 195 | 196 | if New := (*args[0].(*Ivalue)).(structure)[newIndex[0]]; New != nil { 197 | return call(fr.i, fr, 0, New, nil) 198 | } 199 | return nil 200 | } 201 | 202 | func ext۰sync۰Pool۰Put(fr *frame, args []Ivalue) Ivalue { 203 | return nil 204 | } 205 | 206 | func ext۰bytes۰Equal(fr *frame, args []Ivalue) Ivalue { 207 | // func Equal(a, b []byte) bool 208 | a := args[0].([]Ivalue) 209 | b := args[1].([]Ivalue) 210 | if len(a) != len(b) { 211 | return false 212 | } 213 | for i := range a { 214 | if a[i] != b[i] { 215 | return false 216 | } 217 | } 218 | return true 219 | } 220 | 221 | func ext۰bytes۰IndexByte(fr *frame, args []Ivalue) Ivalue { 222 | // func IndexByte(s []byte, c byte) int 223 | s := args[0].([]Ivalue) 224 | c := args[1].(byte) 225 | for i, b := range s { 226 | if b.(byte) == c { 227 | return i 228 | } 229 | } 230 | return -1 231 | } 232 | 233 | // Compare returns an integer comparing two byte slices lexicographically. 234 | // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. 235 | // A nil argument is equivalent to an empty slice. 236 | func ext۰bytes۰Compare(fr *frame, args []Ivalue) Ivalue { 237 | // func Compare(a, b []byte) int { 238 | a := args[0].([]Ivalue) 239 | b := args[1].([]Ivalue) 240 | if a == nil { 241 | if b == nil { 242 | return 0 243 | } 244 | if len(b) == 0 { 245 | return 0 246 | } 247 | return -1 248 | } 249 | if b == nil { 250 | if len(a) == 0 { 251 | return 0 252 | } 253 | return 1 254 | } 255 | i := 0 256 | for (i < len(a)) && (i < len(b)) { 257 | if a[i].(byte) < b[i].(byte) { 258 | return -1 259 | } 260 | if a[i].(byte) > b[i].(byte) { 261 | return +1 262 | } 263 | i++ 264 | } 265 | if len(a) == len(b) { 266 | return 0 267 | } 268 | if len(a) < len(b) { 269 | return -1 270 | } 271 | return +1 272 | } 273 | 274 | func ext۰crc32۰haveSSE42(fr *frame, args []Ivalue) Ivalue { 275 | return false 276 | } 277 | 278 | func ext۰math۰Float64frombits(fr *frame, args []Ivalue) Ivalue { 279 | return math.Float64frombits(args[0].(uint64)) 280 | } 281 | 282 | func ext۰math۰Float64bits(fr *frame, args []Ivalue) Ivalue { 283 | return math.Float64bits(args[0].(float64)) 284 | } 285 | 286 | func ext۰math۰Float32frombits(fr *frame, args []Ivalue) Ivalue { 287 | return math.Float32frombits(args[0].(uint32)) 288 | } 289 | 290 | func ext۰math۰Abs(fr *frame, args []Ivalue) Ivalue { 291 | return math.Abs(args[0].(float64)) 292 | } 293 | 294 | func ext۰math۰Exp(fr *frame, args []Ivalue) Ivalue { 295 | return math.Exp(args[0].(float64)) 296 | } 297 | 298 | func ext۰math۰Float32bits(fr *frame, args []Ivalue) Ivalue { 299 | return math.Float32bits(args[0].(float32)) 300 | } 301 | 302 | func ext۰math۰Min(fr *frame, args []Ivalue) Ivalue { 303 | return math.Min(args[0].(float64), args[1].(float64)) 304 | } 305 | 306 | func ext۰math۰Ldexp(fr *frame, args []Ivalue) Ivalue { 307 | return math.Ldexp(args[0].(float64), args[1].(int)) 308 | } 309 | 310 | func ext۰math۰Log(fr *frame, args []Ivalue) Ivalue { 311 | return math.Log(args[0].(float64)) 312 | } 313 | 314 | func ext۰math۰Sqrt(fr *frame, args []Ivalue) Ivalue { // Elliott 315 | return math.Sqrt(args[0].(float64)) 316 | } 317 | 318 | func ext۰math۰hasSSE4(fr *frame, args []Ivalue) Ivalue { // Elliott 319 | return false 320 | } 321 | 322 | func ext۰os۰runtime_args(fr *frame, args []Ivalue) Ivalue { 323 | return fr.i.osArgs 324 | } 325 | 326 | func ext۰os۰runtime_beforeExit(fr *frame, args []Ivalue) Ivalue { 327 | return nil 328 | } 329 | 330 | func ext۰runtime۰Breakpoint(fr *frame, args []Ivalue) Ivalue { 331 | runtime.Breakpoint() 332 | return nil 333 | } 334 | 335 | func ext۰runtime۰Caller(fr *frame, args []Ivalue) Ivalue { 336 | // func Caller(skip int) (pc uintptr, file string, line int, ok bool) 337 | skip := 1 + args[0].(int) 338 | for i := 0; i < skip; i++ { 339 | if fr != nil { 340 | fr = fr.caller 341 | } 342 | } 343 | var pc uintptr 344 | var file string 345 | var line int 346 | var ok bool 347 | if fr != nil { 348 | fn := fr.fn 349 | // TODO(adonovan): use pc/posn of current instruction, not start of fn. 350 | pc = reflect.ValueOf(fn).Pointer() // uintptr(unsafe.Pointer(fn)) 351 | posn := fn.Prog.Fset.Position(fn.Pos()) 352 | file = posn.Filename 353 | line = posn.Line 354 | ok = true 355 | } 356 | return tuple{pc, file, line, ok} 357 | } 358 | 359 | func ext۰runtime۰Callers(fr *frame, args []Ivalue) Ivalue { 360 | // Callers(skip int, pc []uintptr) int 361 | skip := args[0].(int) 362 | pc := args[1].([]Ivalue) 363 | for i := 0; i < skip; i++ { 364 | if fr != nil { 365 | fr = fr.caller 366 | } 367 | } 368 | i := 0 369 | for fr != nil { 370 | pc[i] = reflect.ValueOf(fr.fn).Pointer() // uintptr(unsafe.Pointer(fr.fn)) 371 | i++ 372 | fr = fr.caller 373 | } 374 | return i 375 | } 376 | 377 | func ext۰runtime۰FuncForPC(fr *frame, args []Ivalue) Ivalue { 378 | // FuncForPC(pc uintptr) *Func 379 | pc := args[0].(uintptr) 380 | var fn *ssa.Function 381 | if pc != 0 { 382 | //fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe! 383 | fn = fr.i.runtimeFunc[pc] 384 | } 385 | var Func Ivalue 386 | Func = structure{fn} // a runtime.Func 387 | return &Func 388 | } 389 | 390 | func ext۰runtime۰environ(fr *frame, args []Ivalue) Ivalue { 391 | // This function also implements syscall.runtime_envs. 392 | return environ 393 | } 394 | 395 | func ext۰runtime۰getgoroot(fr *frame, args []Ivalue) Ivalue { 396 | return os.Getenv("GOROOT") 397 | } 398 | 399 | func ext۰strings۰IndexByte(fr *frame, args []Ivalue) Ivalue { 400 | // func IndexByte(s string, c byte) int 401 | s := args[0].(string) 402 | c := args[1].(byte) 403 | for i := 0; i < len(s); i++ { 404 | if s[i] == c { 405 | return i 406 | } 407 | } 408 | return -1 409 | } 410 | 411 | func ext۰strings۰indexShortStr(fr *frame, args []Ivalue) Ivalue { 412 | return strings.Index(args[0].(string), args[1].(string)) 413 | } 414 | 415 | func ext۰sync۰runtime_Syncsemcheck(fr *frame, args []Ivalue) Ivalue { 416 | // TODO(adonovan): fix: implement. 417 | return nil 418 | } 419 | 420 | func ext۰sync۰runtime_registerPoolCleanup(fr *frame, args []Ivalue) Ivalue { 421 | return nil 422 | } 423 | 424 | func ext۰sync۰runtime_Semacquire(fr *frame, args []Ivalue) Ivalue { 425 | // TODO(adonovan): fix: implement. 426 | return nil 427 | } 428 | 429 | func ext۰sync۰runtime_Semrelease(fr *frame, args []Ivalue) Ivalue { 430 | // TODO(adonovan): fix: implement. 431 | return nil 432 | } 433 | 434 | func ext۰runtime۰GOMAXPROCS(fr *frame, args []Ivalue) Ivalue { 435 | // Ignore args[0]; don't let the interpreted program 436 | // set the interpreter's GOMAXPROCS! 437 | return runtime.GOMAXPROCS(0) 438 | } 439 | 440 | func ext۰runtime۰Goexit(fr *frame, args []Ivalue) Ivalue { 441 | // TODO(adonovan): don't kill the interpreter's main goroutine. 442 | runtime.Goexit() 443 | return nil 444 | } 445 | 446 | func ext۰runtime۰GC(fr *frame, args []Ivalue) Ivalue { 447 | runtime.GC() 448 | return nil 449 | } 450 | 451 | func ext۰runtime۰Gosched(fr *frame, args []Ivalue) Ivalue { 452 | runtime.Gosched() 453 | return nil 454 | } 455 | 456 | func ext۰runtime۰init(fr *frame, args []Ivalue) Ivalue { 457 | return nil 458 | } 459 | 460 | func ext۰runtime۰NumCPU(fr *frame, args []Ivalue) Ivalue { 461 | return runtime.NumCPU() 462 | } 463 | 464 | func ext۰runtime۰ReadMemStats(fr *frame, args []Ivalue) Ivalue { 465 | // TODO(adonovan): populate args[0].(Struct) 466 | return nil 467 | } 468 | 469 | func ext۰atomic۰LoadUint32(fr *frame, args []Ivalue) Ivalue { 470 | // TODO(adonovan): fix: not atomic! 471 | 472 | // Elliott 473 | atomic_mutex.Lock() 474 | defer atomic_mutex.Unlock() 475 | 476 | return (*args[0].(*Ivalue)).(uint32) 477 | } 478 | 479 | func ext۰atomic۰StoreUint32(fr *frame, args []Ivalue) Ivalue { 480 | // TODO(adonovan): fix: not atomic! 481 | 482 | // Elliott 483 | atomic_mutex.Lock() 484 | defer atomic_mutex.Unlock() 485 | 486 | *args[0].(*Ivalue) = args[1].(uint32) 487 | return nil 488 | } 489 | 490 | func ext۰atomic۰LoadInt32(fr *frame, args []Ivalue) Ivalue { 491 | // TODO(adonovan): fix: not atomic! 492 | 493 | // Elliott 494 | atomic_mutex.Lock() 495 | defer atomic_mutex.Unlock() 496 | 497 | return (*args[0].(*Ivalue)).(int32) 498 | } 499 | 500 | func ext۰atomic۰LoadInt64(fr *frame, args []Ivalue) Ivalue { // Elliott 501 | // TODO(adonovan): fix: not atomic! 502 | 503 | // Elliott 504 | atomic_mutex.Lock() 505 | defer atomic_mutex.Unlock() 506 | 507 | return (*args[0].(*Ivalue)).(int64) 508 | } 509 | 510 | func ext۰atomic۰StoreInt32(fr *frame, args []Ivalue) Ivalue { 511 | // TODO(adonovan): fix: not atomic! 512 | // Elliott 513 | atomic_mutex.Lock() 514 | defer atomic_mutex.Unlock() 515 | 516 | *args[0].(*Ivalue) = args[1].(int32) 517 | return nil 518 | } 519 | 520 | func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []Ivalue) Ivalue { 521 | // TODO(adonovan): fix: not atomic! 522 | // Elliott 523 | atomic_mutex.Lock() 524 | defer atomic_mutex.Unlock() 525 | 526 | p := args[0].(*Ivalue) 527 | if (*p).(int32) == args[1].(int32) { 528 | *p = args[2].(int32) 529 | return true 530 | } 531 | return false 532 | } 533 | 534 | func ext۰atomic۰AddInt32(fr *frame, args []Ivalue) Ivalue { 535 | // TODO(adonovan): fix: not atomic! 536 | // Elliott 537 | atomic_mutex.Lock() 538 | defer atomic_mutex.Unlock() 539 | 540 | p := args[0].(*Ivalue) 541 | newv := (*p).(int32) + args[1].(int32) 542 | *p = newv 543 | return newv 544 | } 545 | 546 | func ext۰atomic۰AddUint32(fr *frame, args []Ivalue) Ivalue { 547 | // TODO(adonovan): fix: not atomic! 548 | // Elliott 549 | atomic_mutex.Lock() 550 | defer atomic_mutex.Unlock() 551 | 552 | p := args[0].(*Ivalue) 553 | newv := (*p).(uint32) + args[1].(uint32) 554 | *p = newv 555 | return newv 556 | } 557 | 558 | func ext۰atomic۰LoadUint64(fr *frame, args []Ivalue) Ivalue { 559 | // func LoadUint64(addr *uint64) (val uint64) 560 | // Elliott 561 | atomic_mutex.Lock() 562 | defer atomic_mutex.Unlock() 563 | p := args[0].(*Ivalue) 564 | //fmt.Printf("DEBUG LoadUint64 %v:%T\n", *p, *p) 565 | if _, isArray := (*p).(array); isArray { 566 | p = &((*p).(array)[0]) 567 | } 568 | if ui64, isUint64 := (*p).(uint64); isUint64 { 569 | return ui64 570 | } 571 | return uint64(0) // TODO correct ??? 572 | } 573 | 574 | func ext۰atomic۰AddUint64(fr *frame, args []Ivalue) Ivalue { 575 | // TODO(adonovan): fix: not atomic! 576 | // Elliott 577 | atomic_mutex.Lock() 578 | defer atomic_mutex.Unlock() 579 | 580 | p := args[0].(*Ivalue) 581 | //fmt.Printf("DEBUG AddUint64 %v:%T %v:%T\n", *p, *p, args[1], args[1]) 582 | if _, isArray := (*p).(array); isArray { 583 | p = &((*p).(array)[0]) 584 | if _, isUint64 := (*p).(uint64); !isUint64 { 585 | *p = uint64(0) // TODO check this works... 586 | } 587 | } 588 | newv := (*p).(uint64) + args[1].(uint64) 589 | *p = newv 590 | return newv 591 | } 592 | 593 | func ext۰atomic۰CompareAndSwapUint64(fr *frame, args []Ivalue) Ivalue { 594 | // func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) 595 | atomic_mutex.Lock() 596 | defer atomic_mutex.Unlock() 597 | p := args[0].(*Ivalue) 598 | //fmt.Printf("DEBUG CompareAndSwapUint64 %v:%T %v:%T %v:%T\n", 599 | // *p, *p, args[1], args[1], args[2], args[2]) 600 | if _, isArray := (*p).(array); isArray { 601 | //fmt.Println("DEBUG isArray") 602 | p = &((*p).(array)[0]) 603 | if _, isUint64 := (*p).(uint64); !isUint64 { 604 | //fmt.Println("DEBUG !isUint64") 605 | *p = uint64(0) // TODO check this works... 606 | } 607 | } 608 | if (*p).(uint64) == args[1].(uint64) { 609 | *p = args[2] 610 | return true 611 | } 612 | return false 613 | } 614 | 615 | var atomic_mutex sync.Mutex // Elliott 616 | 617 | func ext۰atomic۰AddInt64(fr *frame, args []Ivalue) Ivalue { // Elliott 618 | 619 | // Elliott 620 | atomic_mutex.Lock() 621 | defer atomic_mutex.Unlock() 622 | p := args[0].(*Ivalue) 623 | newv := (*p).(int64) + args[1].(int64) 624 | *p = newv 625 | return newv 626 | } 627 | 628 | func ext۰runtime۰SetFinalizer(fr *frame, args []Ivalue) Ivalue { 629 | return nil // ignore 630 | } 631 | 632 | // Pretend: type runtime.Func struct { entry *ssa.Function } 633 | 634 | func ext۰runtime۰Func۰FileLine(fr *frame, args []Ivalue) Ivalue { 635 | // func (*runtime.Func) FileLine(uintptr) (string, int) 636 | f, _ := (*args[0].(*Ivalue)).(structure)[0].(*ssa.Function) 637 | pc := args[1].(uintptr) 638 | _ = pc 639 | if f != nil { 640 | // TODO(adonovan): use position of current instruction, not fn. 641 | posn := f.Prog.Fset.Position(f.Pos()) 642 | return tuple{posn.Filename, posn.Line} 643 | } 644 | return tuple{"", 0} 645 | } 646 | 647 | func ext۰runtime۰Func۰Name(fr *frame, args []Ivalue) Ivalue { 648 | // func (*runtime.Func) Name() string 649 | f, _ := (*args[0].(*Ivalue)).(structure)[0].(*ssa.Function) 650 | if f != nil { 651 | return f.String() 652 | } 653 | return "" 654 | } 655 | 656 | func ext۰runtime۰Func۰Entry(fr *frame, args []Ivalue) Ivalue { 657 | // func (*runtime.Func) Entry() uintptr 658 | f, _ := (*args[0].(*Ivalue)).(structure)[0].(*ssa.Function) 659 | return reflect.ValueOf(f).Pointer() // uintptr(unsafe.Pointer(f)) 660 | } 661 | 662 | func ext۰time۰now(fr *frame, args []Ivalue) Ivalue { 663 | nano := time.Now().UnixNano() 664 | return tuple{int64(nano / 1e9), int32(nano % 1e9)} 665 | } 666 | 667 | func ext۰time۰runtimeNano(fr *frame, args []Ivalue) Ivalue { 668 | return time.Now().UnixNano() 669 | } 670 | 671 | var timers = make(map[*Ivalue]time.Timer) 672 | 673 | func ext۰time۰startTimer(fr *frame, args []Ivalue) Ivalue { 674 | // TODO 675 | fmt.Println("DEBUG time.startTimer TODO") 676 | return nil 677 | } 678 | func ext۰time۰stopTimer(fr *frame, args []Ivalue) Ivalue { 679 | // TODO 680 | fmt.Println("DEBUG time.stopTimer TODO") 681 | return false 682 | } 683 | func ext۰time۰Sleep(fr *frame, args []Ivalue) Ivalue { 684 | time.Sleep(time.Duration(args[0].(int64))) 685 | return nil 686 | } 687 | 688 | func ext۰syscall۰Exit(fr *frame, args []Ivalue) Ivalue { 689 | panic(exitPanic(args[0].(int))) 690 | } 691 | 692 | func ext۰syscall۰Getwd(fr *frame, args []Ivalue) Ivalue { 693 | s, err := syscall.Getwd() 694 | return tuple{s, wrapError(err)} 695 | } 696 | 697 | func ext۰syscall۰Getpid(fr *frame, args []Ivalue) Ivalue { 698 | return syscall.Getpid() 699 | } 700 | 701 | // IvalueToBytes converts an Ivalue containing the interpreter 702 | // internal representation of "[]byte" into a []byte. 703 | func IvalueToBytes(v Ivalue) []byte { 704 | in := v.([]Ivalue) 705 | b := make([]byte, len(in)) 706 | for i := range in { 707 | b[i] = in[i].(byte) 708 | } 709 | return b 710 | } 711 | -------------------------------------------------------------------------------- /interp/interp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package interp defines an interpreter for the SSA 6 | // representation of Go programs. 7 | // 8 | // This interpreter is provided as an adjunct for testing the SSA 9 | // construction algorithm. Its purpose is to provide a minimal 10 | // metacircular implementation of the dynamic semantics of each SSA 11 | // instruction. It is not, and will never be, a production-quality Go 12 | // interpreter. 13 | // 14 | // The following is a partial list of Go features that are currently 15 | // unsupported or incomplete in the interpreter. 16 | // 17 | // * Unsafe operations, including all uses of unsafe.Pointer, are 18 | // impossible to support given the "boxed" Ivalue representation we 19 | // have chosen. 20 | // 21 | // * The reflect package is only partially implemented. 22 | // 23 | // * "sync/atomic" operations are not currently atomic due to the 24 | // "boxed" Ivalue representation: it is not possible to read, modify 25 | // and write an interface Ivalue atomically. As a consequence, Mutexes 26 | // are currently broken. TODO(adonovan): provide a metacircular 27 | // implementation of Mutex avoiding the broken atomic primitives. 28 | // 29 | // * recover is only partially implemented. Also, the interpreter 30 | // makes no attempt to distinguish target panics from interpreter 31 | // crashes. 32 | // 33 | // * map iteration is asymptotically inefficient. 34 | // 35 | // * the sizes of the int, uint and uintptr types in the target 36 | // program are assumed to be the same as those of the interpreter 37 | // itself. 38 | // 39 | // * all Ivalues occupy space, even those of types defined by the spec 40 | // to have zero size, e.g. struct{}. This can cause asymptotic 41 | // performance degradation. 42 | // 43 | // * os.Exit is implemented using panic, causing deferred functions to 44 | // run. 45 | package interp 46 | 47 | // was: import "golang.org/x/tools/go/ssa/interp" 48 | 49 | import ( 50 | "fmt" 51 | "go/token" 52 | "io" 53 | "os" 54 | "reflect" 55 | "runtime" 56 | "sync" 57 | "sync/atomic" 58 | 59 | "go/types" 60 | "golang.org/x/tools/go/ssa" 61 | ) 62 | 63 | type continuation int 64 | 65 | const ( 66 | kNext continuation = iota 67 | kReturn 68 | kJump 69 | ) 70 | 71 | // Mode is a bitmask of options affecting the interpreter. 72 | type Mode uint 73 | 74 | const ( 75 | DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead. 76 | EnableTracing // Print a trace of all instructions as they are interpreted. 77 | ) 78 | 79 | type methodSet map[string]*ssa.Function 80 | 81 | // State shared between all interpreted goroutines. 82 | type interpreter struct { 83 | osArgs []Ivalue // the Ivalue of os.Args 84 | prog *ssa.Program // the SSA program 85 | globals map[ssa.Value]*Ivalue // addresses of global variables (immutable) 86 | mode Mode // interpreter options 87 | reflectPackage *ssa.Package // the fake reflect package 88 | errorMethods methodSet // the method set of reflect.error, which implements the error interface. 89 | rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface. 90 | runtimeErrorString types.Type // the runtime.errorString type 91 | sizes types.Sizes // the effective type-sizing function 92 | goroutines int32 // atomically updated 93 | 94 | externals *Externals // per-interpreter externals (immutable) 95 | /* 96 | constants map[*ssa.Const]Ivalue // constant cache, set during preprocess() 97 | constantsRWMutex sync.RWMutex 98 | zeroes typeutil.Map // zero value cache, early tests show no benefit, TODO retest 99 | zeroesRWMutex sync.RWMutex 100 | */ 101 | functions map[*ssa.Function]functionInfo 102 | functionsRWMutex sync.RWMutex 103 | panicSource *frame 104 | 105 | runtimeFunc map[uintptr]*ssa.Function // required to avoid using the unsafe package 106 | 107 | callTargetCache map[string]*ssa.Function // speed up 2nd calls to specific funcs 108 | 109 | // CapturedOutput is non-nil, all writes by the interpreted program 110 | // to file descriptors 1 and 2 will also be written to CapturedOutput. 111 | // 112 | // (The $GOROOT/test system requires that the test be considered a 113 | // failure if "BUG" appears in the combined stdout/stderr output, even 114 | // if it exits zero. 115 | // 116 | CapturedOutput io.Writer 117 | capturedOutputMu sync.Mutex 118 | } 119 | 120 | type deferred struct { 121 | fn Ivalue 122 | args []Ivalue 123 | instr *ssa.Defer 124 | tail *deferred 125 | } 126 | 127 | type frame struct { 128 | i *interpreter 129 | caller *frame 130 | fn *ssa.Function 131 | block, prevBlock *ssa.BasicBlock 132 | iNum int // the latest instruction number in the block 133 | //env map[ssa.Value]Ivalue // dynamic Ivalues of SSA variables 134 | env []Ivalue // dynamic Ivalues of SSA variables 135 | locals []Ivalue 136 | defers *deferred 137 | result Ivalue 138 | panicking bool 139 | panic interface{} 140 | } 141 | 142 | func (fr *frame) get(key ssa.Value) Ivalue { 143 | switch key := key.(type) { 144 | case nil: 145 | // Hack; simplifies handling of optional attributes 146 | // such as ssa.Slice.{Low,High}. 147 | return nil 148 | case *ssa.Function, *ssa.Builtin: 149 | return key 150 | case *ssa.Const: 151 | return fr.i.constIvalue(key) 152 | case *ssa.Global: 153 | if r, ok := fr.i.globals[key]; ok { 154 | return r 155 | } 156 | } 157 | return fr.env[envEnt(fr, key)] 158 | /* 159 | if r, ok := fr.env[key]; ok { 160 | return r 161 | } 162 | panic(fmt.Sprintf("get: no Ivalue for %T: %v", key, key.Name())) 163 | */ 164 | 165 | } 166 | 167 | // runDefer runs a deferred call d. 168 | // It always returns normally, but may set or clear fr.panic. 169 | // 170 | func (fr *frame) runDefer(d *deferred) { 171 | if fr.i.mode&EnableTracing != 0 { 172 | fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n", 173 | fr.i.prog.Fset.Position(d.instr.Pos())) 174 | } 175 | var ok bool 176 | defer func() { 177 | if !ok { 178 | // Deferred call created a new state of panic. 179 | fr.panicking = true 180 | fr.panic = recover() 181 | if fr.i.panicSource == nil { 182 | fr = fr.i.panicSource 183 | } 184 | } 185 | }() 186 | call(fr.i, fr, d.instr.Pos(), d.fn, d.args) 187 | ok = true 188 | } 189 | 190 | // runDefers executes fr's deferred function calls in LIFO order. 191 | // 192 | // On entry, fr.panicking indicates a state of panic; if 193 | // true, fr.panic contains the panic Ivalue. 194 | // 195 | // On completion, if a deferred call started a panic, or if no 196 | // deferred call recovered from a previous state of panic, then 197 | // runDefers itself panics after the last deferred call has run. 198 | // 199 | // If there was no initial state of panic, or it was recovered from, 200 | // runDefers returns normally. 201 | // 202 | func (fr *frame) runDefers() { 203 | for d := fr.defers; d != nil; d = d.tail { 204 | fr.runDefer(d) 205 | } 206 | fr.defers = nil 207 | if fr.panicking { 208 | if fr.i.panicSource == nil { 209 | fr.i.panicSource = fr 210 | } 211 | panic(fr.panic) // new panic, or still panicking 212 | } 213 | } 214 | 215 | // lookupMethod returns the method set for type typ, which may be one 216 | // of the interpreter's fake types. 217 | func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function { 218 | switch typ { 219 | case rtypeType: 220 | return i.rtypeMethods[meth.Id()] 221 | case errorType: 222 | return i.errorMethods[meth.Id()] 223 | } 224 | return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name()) 225 | } 226 | 227 | // visitInstr interprets a single ssa.Instruction within the activation 228 | // record frame. It returns a continuation Ivalue indicating where to 229 | // read the next instruction from. 230 | func visitInstr(fr *frame, instr ssa.Instruction) continuation { 231 | 232 | if debugStats { 233 | debugMapMutex.Lock() 234 | debugMap[fmt.Sprintf("%T", instr)]++ 235 | debugMapMutex.Unlock() 236 | } 237 | 238 | switch instr := instr.(type) { 239 | case *ssa.DebugRef: 240 | // no-op 241 | 242 | case *ssa.UnOp: 243 | fr.env[envEnt(fr, instr)] = fr.i.unop(instr, fr.get(instr.X)) 244 | 245 | case *ssa.BinOp: 246 | fr.env[envEnt(fr, instr)] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y)) 247 | 248 | case *ssa.Call: 249 | fn, args := prepareCall(fr, &instr.Call) 250 | fr.env[envEnt(fr, instr)] = call(fr.i, fr, instr.Pos(), fn, args) 251 | 252 | case *ssa.ChangeInterface: 253 | fr.env[envEnt(fr, instr)] = fr.get(instr.X) 254 | 255 | case *ssa.ChangeType: 256 | fr.env[envEnt(fr, instr)] = fr.get(instr.X) // (can't fail) 257 | 258 | case *ssa.Convert: 259 | fr.env[envEnt(fr, instr)] = fr.i.conv(instr.Type(), instr.X.Type(), fr.get(instr.X)) 260 | 261 | case *ssa.MakeInterface: 262 | fr.env[envEnt(fr, instr)] = iface{t: instr.X.Type(), v: fr.get(instr.X)} 263 | 264 | case *ssa.Extract: 265 | fr.env[envEnt(fr, instr)] = fr.get(instr.Tuple).(tuple)[instr.Index] 266 | 267 | case *ssa.Slice: 268 | fr.env[envEnt(fr, instr)] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max)) 269 | 270 | case *ssa.Return: 271 | switch len(instr.Results) { 272 | case 0: 273 | case 1: 274 | fr.result = fr.get(instr.Results[0]) 275 | default: 276 | var res []Ivalue 277 | for _, r := range instr.Results { 278 | res = append(res, fr.get(r)) 279 | } 280 | fr.result = tuple(res) 281 | } 282 | fr.block = nil 283 | return kReturn 284 | 285 | case *ssa.RunDefers: 286 | fr.runDefers() 287 | 288 | case *ssa.Panic: 289 | if fr.i.panicSource == nil { 290 | fr.i.panicSource = fr 291 | } 292 | panic(targetPanic{fr.get(instr.X)}) 293 | 294 | case *ssa.Send: 295 | fr.get(instr.Chan).(chan Ivalue) <- fr.get(instr.X) 296 | 297 | case *ssa.Store: 298 | store(deref(instr.Addr.Type()), fr.get(instr.Addr).(*Ivalue), fr.get(instr.Val)) 299 | 300 | case *ssa.If: 301 | succ := 1 302 | if fr.get(instr.Cond).(bool) { 303 | succ = 0 304 | } 305 | fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ] 306 | return kJump 307 | 308 | case *ssa.Jump: 309 | fr.prevBlock, fr.block = fr.block, fr.block.Succs[0] 310 | return kJump 311 | 312 | case *ssa.Defer: 313 | fn, args := prepareCall(fr, &instr.Call) 314 | fr.defers = &deferred{ 315 | fn: fn, 316 | args: args, 317 | instr: instr, 318 | tail: fr.defers, 319 | } 320 | 321 | case *ssa.Go: 322 | fn, args := prepareCall(fr, &instr.Call) 323 | atomic.AddInt32(&fr.i.goroutines, 1) 324 | go func() { 325 | defer func() { 326 | fr.i.userStackIfPanic() 327 | }() 328 | call(fr.i, nil, instr.Pos(), fn, args) 329 | atomic.AddInt32(&fr.i.goroutines, -1) 330 | }() 331 | 332 | case *ssa.MakeChan: 333 | fr.env[envEnt(fr, instr)] = make(chan Ivalue, asInt(fr.get(instr.Size))) 334 | 335 | case *ssa.Alloc: 336 | var addr *Ivalue 337 | if instr.Heap { 338 | // new 339 | addr = new(Ivalue) 340 | fr.env[envEnt(fr, instr)] = addr 341 | } else { 342 | // local 343 | addr = fr.env[envEnt(fr, instr)].(*Ivalue) 344 | } 345 | *addr = fr.i.zero(deref(instr.Type())) 346 | 347 | case *ssa.MakeSlice: 348 | slice := make([]Ivalue, asInt(fr.get(instr.Cap))) 349 | tElt := instr.Type().Underlying().(*types.Slice).Elem() 350 | for i := range slice { 351 | slice[i] = fr.i.zero(tElt) 352 | } 353 | fr.env[envEnt(fr, instr)] = slice[:asInt(fr.get(instr.Len))] 354 | 355 | case *ssa.MakeMap: 356 | reserve := 0 357 | if instr.Reserve != nil { 358 | reserve = asInt(fr.get(instr.Reserve)) 359 | } 360 | fr.env[envEnt(fr, instr)] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve) 361 | 362 | case *ssa.Range: 363 | fr.env[envEnt(fr, instr)] = rangeIter(fr.get(instr.X), instr.X.Type()) 364 | 365 | case *ssa.Next: 366 | fr.env[envEnt(fr, instr)] = fr.get(instr.Iter).(iter).next() 367 | 368 | case *ssa.FieldAddr: 369 | x := fr.get(instr.X) 370 | // FIXME wrong! &global.f must not change if we do *global = zero! 371 | fr.env[envEnt(fr, instr)] = &(*x.(*Ivalue)).(structure)[instr.Field] 372 | 373 | case *ssa.Field: 374 | fr.env[envEnt(fr, instr)] = fr.get(instr.X).(structure)[instr.Field] 375 | 376 | case *ssa.IndexAddr: 377 | x := fr.get(instr.X) 378 | idx := fr.get(instr.Index) 379 | switch x := x.(type) { 380 | case []Ivalue: 381 | fr.env[envEnt(fr, instr)] = &x[asInt(idx)] 382 | case *Ivalue: // *array 383 | fr.env[envEnt(fr, instr)] = &(*x).(array)[asInt(idx)] 384 | default: 385 | panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x)) 386 | } 387 | 388 | case *ssa.Index: 389 | fr.env[envEnt(fr, instr)] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))] 390 | 391 | case *ssa.Lookup: 392 | fr.env[envEnt(fr, instr)] = fr.i.lookup(instr, fr.get(instr.X), fr.get(instr.Index)) 393 | 394 | case *ssa.MapUpdate: 395 | m := fr.get(instr.Map) 396 | key := fr.get(instr.Key) 397 | v := fr.get(instr.Value) 398 | switch m := m.(type) { 399 | case map[Ivalue]Ivalue: 400 | m[key] = v 401 | case *hashmap: 402 | m.insert(key.(hashable), v) 403 | default: 404 | panic(fmt.Sprintf("illegal map type: %T", m)) 405 | } 406 | 407 | case *ssa.TypeAssert: 408 | fr.env[envEnt(fr, instr)] = typeAssert(fr.i, instr, fr.get(instr.X).(iface)) 409 | 410 | case *ssa.MakeClosure: 411 | var bindings []Ivalue 412 | for _, binding := range instr.Bindings { 413 | bindings = append(bindings, fr.get(binding)) 414 | } 415 | fr.env[envEnt(fr, instr)] = &closure{instr.Fn.(*ssa.Function), bindings} 416 | 417 | case *ssa.Phi: 418 | for i, pred := range instr.Block().Preds { 419 | if fr.prevBlock == pred { 420 | fr.env[envEnt(fr, instr)] = fr.get(instr.Edges[i]) 421 | break 422 | } 423 | } 424 | 425 | case *ssa.Select: 426 | var cases []reflect.SelectCase 427 | if !instr.Blocking { 428 | cases = append(cases, reflect.SelectCase{ 429 | Dir: reflect.SelectDefault, 430 | }) 431 | } 432 | for _, state := range instr.States { 433 | var dir reflect.SelectDir 434 | if state.Dir == types.RecvOnly { 435 | dir = reflect.SelectRecv 436 | } else { 437 | dir = reflect.SelectSend 438 | } 439 | var send reflect.Value 440 | if state.Send != nil { 441 | send = reflect.ValueOf(fr.get(state.Send)) 442 | } 443 | cases = append(cases, reflect.SelectCase{ 444 | Dir: dir, 445 | Chan: reflect.ValueOf(fr.get(state.Chan)), 446 | Send: send, 447 | }) 448 | } 449 | chosen, recv, recvOk := reflect.Select(cases) 450 | if !instr.Blocking { 451 | chosen-- // default case should have index -1. 452 | } 453 | r := tuple{chosen, recvOk} 454 | for i, st := range instr.States { 455 | if st.Dir == types.RecvOnly { 456 | var v Ivalue 457 | if i == chosen && recvOk { 458 | // No need to copy since send makes an unaliased copy. 459 | v = recv.Interface().(Ivalue) 460 | } else { 461 | v = fr.i.zero(st.Chan.Type().Underlying().(*types.Chan).Elem()) 462 | } 463 | r = append(r, v) 464 | } 465 | } 466 | fr.env[envEnt(fr, instr)] = r 467 | 468 | default: 469 | panic(fmt.Sprintf("unexpected instruction: %T", instr)) 470 | } 471 | 472 | // if val, ok := instr.(ssa.Value); ok { 473 | // fmt.Println(toString(fr.env[val])) // debugging 474 | // } 475 | 476 | return kNext 477 | } 478 | 479 | // prepareCall determines the function Ivalue and argument Ivalues for a 480 | // function call in a Call, Go or Defer instruction, performing 481 | // interface method lookup if needed. 482 | // 483 | func prepareCall(fr *frame, call *ssa.CallCommon) (fn Ivalue, args []Ivalue) { 484 | v := fr.get(call.Value) 485 | if call.Method == nil { 486 | // Function call. 487 | fn = v 488 | } else { 489 | // Interface method invocation. 490 | recv := v.(iface) 491 | if recv.t == nil { 492 | panic("method invoked on nil interface") 493 | } 494 | if f := lookupMethod(fr.i, recv.t, call.Method); f == nil { 495 | // Unreachable in well-typed programs. 496 | panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method)) 497 | } else { 498 | fn = f 499 | } 500 | args = append(args, recv.v) 501 | } 502 | for _, arg := range call.Args { 503 | args = append(args, fr.get(arg)) 504 | } 505 | return 506 | } 507 | 508 | // call interprets a call to a function (function, builtin or closure) 509 | // fn with arguments args, returning its result. 510 | // callpos is the position of the callsite. 511 | // 512 | func call(i *interpreter, caller *frame, callpos token.Pos, fn Ivalue, args []Ivalue) Ivalue { 513 | switch fn := fn.(type) { 514 | case *ssa.Function: 515 | if fn == nil { 516 | panic("call of nil function") // nil of func type 517 | } 518 | return callSSA(i, caller, callpos, fn, args, nil) 519 | case *closure: 520 | return callSSA(i, caller, callpos, fn.Fn, args, fn.Env) 521 | case *ssa.Builtin: 522 | return callBuiltin(caller, callpos, fn, args) 523 | } 524 | panic(fmt.Sprintf("cannot call %T", fn)) 525 | } 526 | 527 | func loc(fset *token.FileSet, pos token.Pos) string { 528 | if pos == token.NoPos { 529 | return "" 530 | } 531 | return " at " + fset.Position(pos).String() 532 | } 533 | 534 | // callSSA interprets a call to function fn with arguments args, 535 | // and lexical environment env, returning its result. 536 | // callpos is the position of the callsite. 537 | // 538 | func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []Ivalue, env []Ivalue) Ivalue { 539 | if i.mode&EnableTracing != 0 { 540 | fset := fn.Prog.Fset 541 | // TODO(adonovan): fix: loc() lies for external functions. 542 | fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos())) 543 | suffix := "" 544 | if caller != nil { 545 | suffix = ", resuming " + caller.fn.String() + loc(fset, callpos) 546 | } 547 | defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix) 548 | } 549 | fr := &frame{ 550 | i: i, 551 | caller: caller, // for panic/recover 552 | fn: fn, 553 | } 554 | fr.getFnInf() // pre-process the function if required 555 | 556 | if fn.Parent() == nil { 557 | name := fn.String() 558 | if ext := i.externals.funcs[name]; ext != nil { 559 | if i.mode&EnableTracing != 0 { 560 | fmt.Fprintln(os.Stderr, "\t(user-defined external)") 561 | } 562 | return ext(fr, args) 563 | } 564 | if ext := externals[name]; ext != nil { 565 | if i.mode&EnableTracing != 0 { 566 | fmt.Fprintln(os.Stderr, "\t(interpreter external)") 567 | } 568 | return ext(fr, args) 569 | } 570 | if fn.Blocks == nil { 571 | fr.i.panicSource = fr 572 | panic("no code for function: " + name) 573 | } 574 | } 575 | fr.env = make([]Ivalue, len(i.functions[fr.fn].envEntries)) // make(map[ssa.Value]Ivalue) 576 | fr.block = fn.Blocks[0] 577 | fr.locals = make([]Ivalue, len(fn.Locals)) 578 | for i, l := range fn.Locals { // allocate space for locals (used in alloc) 579 | fr.locals[i] = fr.i.zero(deref(l.Type())) 580 | fr.env[envEnt(fr, l)] = &fr.locals[i] 581 | } 582 | for i, p := range fn.Params { 583 | fr.env[envEnt(fr, p)] = args[i] 584 | } 585 | for i, fv := range fn.FreeVars { 586 | fr.env[envEnt(fr, fv)] = env[i] 587 | } 588 | for fr.block != nil { 589 | runFrame(fr) 590 | } 591 | // Destroy the locals to avoid accidental use after return. 592 | for i := range fn.Locals { 593 | fr.locals[i] = bad{} 594 | } 595 | return fr.result 596 | } 597 | 598 | // runFrame executes SSA instructions starting at fr.block and 599 | // continuing until a return, a panic, or a recovered panic. 600 | // 601 | // After a panic, runFrame panics. 602 | // 603 | // After a normal return, fr.result contains the result of the call 604 | // and fr.block is nil. 605 | // 606 | // A recovered panic in a function without named return parameters 607 | // (NRPs) becomes a normal return of the zero Ivalue of the function's 608 | // result type. 609 | // 610 | // After a recovered panic in a function with NRPs, fr.result is 611 | // undefined and fr.block contains the block at which to resume 612 | // control. 613 | // 614 | func runFrame(fr *frame) { 615 | defer func() { 616 | if fr.block == nil { 617 | return // normal return 618 | } 619 | if fr.i.mode&DisableRecover != 0 { 620 | return // let interpreter crash 621 | } 622 | fr.panicking = true 623 | fr.panic = recover() 624 | if fr.i.panicSource == nil { 625 | fr.i.panicSource = fr 626 | } 627 | if fr.i.mode&EnableTracing != 0 { 628 | fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic) 629 | } 630 | fr.runDefers() 631 | fr.block = fr.fn.Recover 632 | }() 633 | 634 | fnInf := fr.getFnInf() 635 | 636 | fnInstrs := fnInf.instrs 637 | blkInstrs := fnInstrs[fr.block.Index] 638 | trace := fr.i.mode&EnableTracing != 0 639 | var instr ssa.Instruction 640 | for { 641 | if trace { 642 | fmt.Fprintf(os.Stderr, ".%s:\n", fr.block) 643 | } 644 | block: 645 | for fr.iNum, instr = range fr.block.Instrs { 646 | if trace { 647 | if v, ok := instr.(ssa.Value); ok { 648 | fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr) 649 | } else { 650 | fmt.Fprintln(os.Stderr, "\t", instr) 651 | } 652 | } 653 | if fun := blkInstrs[fr.iNum]; fun != nil { 654 | fun(fr) 655 | } else { 656 | switch visitInstr(fr, instr) { 657 | case kReturn: 658 | return 659 | case kNext: 660 | // no-op 661 | case kJump: 662 | blkInstrs = fnInstrs[fr.block.Index] 663 | break block 664 | } 665 | } 666 | } 667 | } 668 | } 669 | 670 | // doRecover implements the recover() built-in. 671 | func doRecover(caller *frame) Ivalue { 672 | // recover() must be exactly one level beneath the deferred 673 | // function (two levels beneath the panicking function) to 674 | // have any effect. Thus we ignore both "defer recover()" and 675 | // "defer f() -> g() -> recover()". 676 | if caller.i.mode&DisableRecover == 0 && 677 | caller != nil && !caller.panicking && 678 | caller.caller != nil && caller.caller.panicking { 679 | caller.caller.panicking = false 680 | caller.i.panicSource = caller.caller // Elliott added 681 | p := caller.caller.panic 682 | caller.caller.panic = nil 683 | switch p := p.(type) { 684 | case targetPanic: 685 | // The target program explicitly called panic(). 686 | return p.v 687 | case runtime.Error: 688 | // The interpreter encountered a runtime error. 689 | return iface{caller.i.runtimeErrorString, p.Error()} 690 | case string: 691 | // The interpreter explicitly called panic(). 692 | return iface{caller.i.runtimeErrorString, p} 693 | default: 694 | panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p)) 695 | } 696 | } 697 | return iface{} 698 | } 699 | 700 | // setGlobal sets the Ivalue of a system-initialized global variable. 701 | func setGlobal(i *interpreter, pkg *ssa.Package, name string, v Ivalue) { 702 | if g, ok := i.globals[pkg.Var(name)]; ok { 703 | *g = v 704 | return 705 | } 706 | panic("no global variable: " + pkg.Pkg.Path() + "." + name) 707 | } 708 | 709 | var environ []Ivalue 710 | 711 | func init() { 712 | for _, s := range os.Environ() { 713 | environ = append(environ, s) 714 | } 715 | environ = append(environ, "GOSSAINTERP=1") 716 | environ = append(environ, "GOARCH="+runtime.GOARCH) 717 | } 718 | 719 | // deleteBodies delete the bodies of all standalone functions except the 720 | // specified ones. A missing intrinsic leads to a clear runtime error. 721 | func deleteBodies(pkg *ssa.Package, except ...string) { 722 | keep := make(map[string]bool) 723 | for _, e := range except { 724 | keep[e] = true 725 | } 726 | for _, mem := range pkg.Members { 727 | if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] { 728 | fn.Blocks = nil 729 | } 730 | } 731 | } 732 | 733 | // Context provides the execution context for subsequent calls 734 | type Context struct { 735 | Interp *interpreter 736 | } 737 | 738 | // Interpret interprets the Go program whose main package is mainpkg. 739 | // mode specifies various interpreter options. filename and args are 740 | // the initial Ivalues of os.Args for the target program. sizes is the 741 | // effective type-sizing function for this program. 742 | // 743 | // Interpret returns the exit code of the program: 2 for panic (like 744 | // gc does), or the argument to os.Exit for normal termination. 745 | // 746 | // The SSA program must include the "runtime" package. 747 | // 748 | func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string, ext *Externals, output io.Writer) (context *Context, exitCode int) { 749 | if ext == nil { 750 | ext = NewExternals() 751 | } 752 | i := &interpreter{ 753 | prog: mainpkg.Prog, 754 | globals: make(map[ssa.Value]*Ivalue), 755 | mode: mode, 756 | sizes: sizes, 757 | goroutines: 1, 758 | 759 | //constants: make(map[*ssa.Const]Ivalue), 760 | externals: ext, 761 | functions: make(map[*ssa.Function]functionInfo), 762 | runtimeFunc: make(map[uintptr]*ssa.Function), 763 | 764 | CapturedOutput: output, 765 | } 766 | i.preprocess() 767 | context = &Context{ 768 | Interp: i, 769 | } 770 | runtimePkg := i.prog.ImportedPackage("runtime") 771 | if runtimePkg == nil { 772 | panic("ssa.Program doesn't include runtime package") 773 | } 774 | i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type() 775 | 776 | initReflect(i) 777 | 778 | i.osArgs = append(i.osArgs, filename) 779 | for _, arg := range args { 780 | i.osArgs = append(i.osArgs, arg) 781 | } 782 | 783 | for _, pkg := range i.prog.AllPackages() { 784 | // Initialize global storage. 785 | for _, m := range pkg.Members { 786 | switch v := m.(type) { 787 | case *ssa.Global: 788 | //if gp, ok := i.externals.globVals[v]; ok { 789 | // i.globals[v] = gp.addr 790 | //} else { 791 | cell := i.zero(deref(v.Type())) 792 | i.globals[v] = &cell 793 | //} 794 | } 795 | } 796 | 797 | // Ad-hoc initialization for magic system variables. 798 | switch pkg.Pkg.Path() { 799 | case "syscall": 800 | setGlobal(i, pkg, "envs", environ) 801 | 802 | case "reflect": 803 | deleteBodies(pkg, "DeepEqual", "deepValueEqual") 804 | 805 | case "runtime": 806 | sz := sizes.Sizeof(pkg.Pkg.Scope().Lookup("MemStats").Type()) 807 | setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz)) 808 | deleteBodies(pkg, "GOROOT", "gogetenv") 809 | } 810 | } 811 | 812 | // Top-level error handler. 813 | exitCode = 2 814 | defer func() { 815 | if exitCode != 2 || i.mode&DisableRecover != 0 { 816 | return 817 | } 818 | rec := recover() 819 | switch p := rec.(type) { 820 | case exitPanic: 821 | exitCode = int(p) 822 | return 823 | case targetPanic: 824 | fmt.Fprintln(os.Stderr, "panic:", toString(p.v)) 825 | case runtime.Error: 826 | fmt.Fprintln(os.Stderr, "panic:", p.Error()) 827 | case string: 828 | fmt.Fprintln(os.Stderr, "panic:", p) 829 | default: 830 | fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p) 831 | } 832 | 833 | i.userStackIfPanic() 834 | 835 | fmt.Fprintln(os.Stderr, "INTERPRETER STACK:") 836 | buf := make([]byte, 0x10000) 837 | runtime.Stack(buf, false) 838 | fmt.Fprintln(os.Stderr, string(buf)) 839 | 840 | panic(rec) // to report the panic back 841 | }() 842 | 843 | // Run! 844 | call(i, nil, token.NoPos, mainpkg.Func("init"), nil) 845 | if mainFn := mainpkg.Func("main"); mainFn != nil { 846 | call(i, nil, token.NoPos, mainFn, nil) 847 | exitCode = 0 848 | } else { 849 | fmt.Fprintln(os.Stderr, "No main function.") 850 | exitCode = 1 851 | } 852 | return 853 | } 854 | 855 | func (i *interpreter) userStackIfPanic() { 856 | if i.panicSource != nil { 857 | fmt.Fprintln(os.Stderr, "USER STACK:") 858 | fr := i.panicSource 859 | for fr != nil { 860 | inst := fr.block.Instrs[fr.iNum].(ssa.Instruction) 861 | where := "-" 862 | for ii := fr.iNum; ii >= 0 && where == "-"; ii-- { 863 | where = 864 | fr.i.prog.Fset.Position(fr.block.Instrs[ii].(ssa.Instruction).Pos()).String() 865 | } 866 | fmt.Fprintln(os.Stderr, fr.fn.String(), where, inst.String()) 867 | fr = fr.caller 868 | } 869 | } 870 | } 871 | 872 | // Call a function in the interpreter's execution context 873 | func (cont *Context) Call(name string, args []Ivalue) Ivalue { 874 | fr := &frame{i: cont.Interp} 875 | if cont.Interp.callTargetCache == nil { 876 | cont.Interp.callTargetCache = make(map[string]*ssa.Function) 877 | pkgs := cont.Interp.prog.AllPackages() 878 | for _, pkg := range pkgs { 879 | for _, mem := range pkg.Members { 880 | targetFn, isFn := mem.(*ssa.Function) 881 | if isFn { 882 | sname := targetFn.String() 883 | if sname == name { 884 | cont.Interp.callTargetCache[name] = targetFn 885 | } 886 | } 887 | } 888 | } 889 | } 890 | targetFn := cont.Interp.callTargetCache[name] 891 | if targetFn == nil { 892 | panic("No interpreter function: " + name) 893 | } 894 | return call(cont.Interp, fr, token.NoPos, targetFn, args) 895 | } 896 | 897 | // deref returns a pointer's element type; otherwise it returns typ. 898 | // TODO(adonovan): Import from ssa? 899 | func deref(typ types.Type) types.Type { 900 | if p, ok := typ.Underlying().(*types.Pointer); ok { 901 | return p.Elem() 902 | } 903 | return typ 904 | } 905 | -------------------------------------------------------------------------------- /interp/generated.go: -------------------------------------------------------------------------------- 1 | package interp 2 | 3 | import "go/types" 4 | 5 | func easyConvToIntFromInt(v Ivalue) Ivalue { 6 | return int(v.(int)) 7 | } 8 | 9 | func easyConvToInt8FromInt(v Ivalue) Ivalue { 10 | return int8(v.(int)) 11 | } 12 | 13 | func easyConvToInt16FromInt(v Ivalue) Ivalue { 14 | return int16(v.(int)) 15 | } 16 | 17 | func easyConvToInt32FromInt(v Ivalue) Ivalue { 18 | return int32(v.(int)) 19 | } 20 | 21 | func easyConvToInt64FromInt(v Ivalue) Ivalue { 22 | return int64(v.(int)) 23 | } 24 | 25 | func easyConvToUintFromInt(v Ivalue) Ivalue { 26 | return uint(v.(int)) 27 | } 28 | 29 | func easyConvToUint8FromInt(v Ivalue) Ivalue { 30 | return uint8(v.(int)) 31 | } 32 | 33 | func easyConvToUint16FromInt(v Ivalue) Ivalue { 34 | return uint16(v.(int)) 35 | } 36 | 37 | func easyConvToUint32FromInt(v Ivalue) Ivalue { 38 | return uint32(v.(int)) 39 | } 40 | 41 | func easyConvToUint64FromInt(v Ivalue) Ivalue { 42 | return uint64(v.(int)) 43 | } 44 | 45 | func easyConvToUintptrFromInt(v Ivalue) Ivalue { 46 | return uintptr(v.(int)) 47 | } 48 | 49 | func easyConvToFloat32FromInt(v Ivalue) Ivalue { 50 | return float32(v.(int)) 51 | } 52 | 53 | func easyConvToFloat64FromInt(v Ivalue) Ivalue { 54 | return float64(v.(int)) 55 | } 56 | 57 | func easyConvToIntFromInt8(v Ivalue) Ivalue { 58 | return int(v.(int8)) 59 | } 60 | 61 | func easyConvToInt8FromInt8(v Ivalue) Ivalue { 62 | return int8(v.(int8)) 63 | } 64 | 65 | func easyConvToInt16FromInt8(v Ivalue) Ivalue { 66 | return int16(v.(int8)) 67 | } 68 | 69 | func easyConvToInt32FromInt8(v Ivalue) Ivalue { 70 | return int32(v.(int8)) 71 | } 72 | 73 | func easyConvToInt64FromInt8(v Ivalue) Ivalue { 74 | return int64(v.(int8)) 75 | } 76 | 77 | func easyConvToUintFromInt8(v Ivalue) Ivalue { 78 | return uint(v.(int8)) 79 | } 80 | 81 | func easyConvToUint8FromInt8(v Ivalue) Ivalue { 82 | return uint8(v.(int8)) 83 | } 84 | 85 | func easyConvToUint16FromInt8(v Ivalue) Ivalue { 86 | return uint16(v.(int8)) 87 | } 88 | 89 | func easyConvToUint32FromInt8(v Ivalue) Ivalue { 90 | return uint32(v.(int8)) 91 | } 92 | 93 | func easyConvToUint64FromInt8(v Ivalue) Ivalue { 94 | return uint64(v.(int8)) 95 | } 96 | 97 | func easyConvToUintptrFromInt8(v Ivalue) Ivalue { 98 | return uintptr(v.(int8)) 99 | } 100 | 101 | func easyConvToFloat32FromInt8(v Ivalue) Ivalue { 102 | return float32(v.(int8)) 103 | } 104 | 105 | func easyConvToFloat64FromInt8(v Ivalue) Ivalue { 106 | return float64(v.(int8)) 107 | } 108 | 109 | func easyConvToIntFromInt16(v Ivalue) Ivalue { 110 | return int(v.(int16)) 111 | } 112 | 113 | func easyConvToInt8FromInt16(v Ivalue) Ivalue { 114 | return int8(v.(int16)) 115 | } 116 | 117 | func easyConvToInt16FromInt16(v Ivalue) Ivalue { 118 | return int16(v.(int16)) 119 | } 120 | 121 | func easyConvToInt32FromInt16(v Ivalue) Ivalue { 122 | return int32(v.(int16)) 123 | } 124 | 125 | func easyConvToInt64FromInt16(v Ivalue) Ivalue { 126 | return int64(v.(int16)) 127 | } 128 | 129 | func easyConvToUintFromInt16(v Ivalue) Ivalue { 130 | return uint(v.(int16)) 131 | } 132 | 133 | func easyConvToUint8FromInt16(v Ivalue) Ivalue { 134 | return uint8(v.(int16)) 135 | } 136 | 137 | func easyConvToUint16FromInt16(v Ivalue) Ivalue { 138 | return uint16(v.(int16)) 139 | } 140 | 141 | func easyConvToUint32FromInt16(v Ivalue) Ivalue { 142 | return uint32(v.(int16)) 143 | } 144 | 145 | func easyConvToUint64FromInt16(v Ivalue) Ivalue { 146 | return uint64(v.(int16)) 147 | } 148 | 149 | func easyConvToUintptrFromInt16(v Ivalue) Ivalue { 150 | return uintptr(v.(int16)) 151 | } 152 | 153 | func easyConvToFloat32FromInt16(v Ivalue) Ivalue { 154 | return float32(v.(int16)) 155 | } 156 | 157 | func easyConvToFloat64FromInt16(v Ivalue) Ivalue { 158 | return float64(v.(int16)) 159 | } 160 | 161 | func easyConvToIntFromInt32(v Ivalue) Ivalue { 162 | return int(v.(int32)) 163 | } 164 | 165 | func easyConvToInt8FromInt32(v Ivalue) Ivalue { 166 | return int8(v.(int32)) 167 | } 168 | 169 | func easyConvToInt16FromInt32(v Ivalue) Ivalue { 170 | return int16(v.(int32)) 171 | } 172 | 173 | func easyConvToInt32FromInt32(v Ivalue) Ivalue { 174 | return int32(v.(int32)) 175 | } 176 | 177 | func easyConvToInt64FromInt32(v Ivalue) Ivalue { 178 | return int64(v.(int32)) 179 | } 180 | 181 | func easyConvToUintFromInt32(v Ivalue) Ivalue { 182 | return uint(v.(int32)) 183 | } 184 | 185 | func easyConvToUint8FromInt32(v Ivalue) Ivalue { 186 | return uint8(v.(int32)) 187 | } 188 | 189 | func easyConvToUint16FromInt32(v Ivalue) Ivalue { 190 | return uint16(v.(int32)) 191 | } 192 | 193 | func easyConvToUint32FromInt32(v Ivalue) Ivalue { 194 | return uint32(v.(int32)) 195 | } 196 | 197 | func easyConvToUint64FromInt32(v Ivalue) Ivalue { 198 | return uint64(v.(int32)) 199 | } 200 | 201 | func easyConvToUintptrFromInt32(v Ivalue) Ivalue { 202 | return uintptr(v.(int32)) 203 | } 204 | 205 | func easyConvToFloat32FromInt32(v Ivalue) Ivalue { 206 | return float32(v.(int32)) 207 | } 208 | 209 | func easyConvToFloat64FromInt32(v Ivalue) Ivalue { 210 | return float64(v.(int32)) 211 | } 212 | 213 | func easyConvToIntFromInt64(v Ivalue) Ivalue { 214 | return int(v.(int64)) 215 | } 216 | 217 | func easyConvToInt8FromInt64(v Ivalue) Ivalue { 218 | return int8(v.(int64)) 219 | } 220 | 221 | func easyConvToInt16FromInt64(v Ivalue) Ivalue { 222 | return int16(v.(int64)) 223 | } 224 | 225 | func easyConvToInt32FromInt64(v Ivalue) Ivalue { 226 | return int32(v.(int64)) 227 | } 228 | 229 | func easyConvToInt64FromInt64(v Ivalue) Ivalue { 230 | return int64(v.(int64)) 231 | } 232 | 233 | func easyConvToUintFromInt64(v Ivalue) Ivalue { 234 | return uint(v.(int64)) 235 | } 236 | 237 | func easyConvToUint8FromInt64(v Ivalue) Ivalue { 238 | return uint8(v.(int64)) 239 | } 240 | 241 | func easyConvToUint16FromInt64(v Ivalue) Ivalue { 242 | return uint16(v.(int64)) 243 | } 244 | 245 | func easyConvToUint32FromInt64(v Ivalue) Ivalue { 246 | return uint32(v.(int64)) 247 | } 248 | 249 | func easyConvToUint64FromInt64(v Ivalue) Ivalue { 250 | return uint64(v.(int64)) 251 | } 252 | 253 | func easyConvToUintptrFromInt64(v Ivalue) Ivalue { 254 | return uintptr(v.(int64)) 255 | } 256 | 257 | func easyConvToFloat32FromInt64(v Ivalue) Ivalue { 258 | return float32(v.(int64)) 259 | } 260 | 261 | func easyConvToFloat64FromInt64(v Ivalue) Ivalue { 262 | return float64(v.(int64)) 263 | } 264 | 265 | func easyConvToIntFromUint(v Ivalue) Ivalue { 266 | return int(v.(uint)) 267 | } 268 | 269 | func easyConvToInt8FromUint(v Ivalue) Ivalue { 270 | return int8(v.(uint)) 271 | } 272 | 273 | func easyConvToInt16FromUint(v Ivalue) Ivalue { 274 | return int16(v.(uint)) 275 | } 276 | 277 | func easyConvToInt32FromUint(v Ivalue) Ivalue { 278 | return int32(v.(uint)) 279 | } 280 | 281 | func easyConvToInt64FromUint(v Ivalue) Ivalue { 282 | return int64(v.(uint)) 283 | } 284 | 285 | func easyConvToUintFromUint(v Ivalue) Ivalue { 286 | return uint(v.(uint)) 287 | } 288 | 289 | func easyConvToUint8FromUint(v Ivalue) Ivalue { 290 | return uint8(v.(uint)) 291 | } 292 | 293 | func easyConvToUint16FromUint(v Ivalue) Ivalue { 294 | return uint16(v.(uint)) 295 | } 296 | 297 | func easyConvToUint32FromUint(v Ivalue) Ivalue { 298 | return uint32(v.(uint)) 299 | } 300 | 301 | func easyConvToUint64FromUint(v Ivalue) Ivalue { 302 | return uint64(v.(uint)) 303 | } 304 | 305 | func easyConvToUintptrFromUint(v Ivalue) Ivalue { 306 | return uintptr(v.(uint)) 307 | } 308 | 309 | func easyConvToFloat32FromUint(v Ivalue) Ivalue { 310 | return float32(v.(uint)) 311 | } 312 | 313 | func easyConvToFloat64FromUint(v Ivalue) Ivalue { 314 | return float64(v.(uint)) 315 | } 316 | 317 | func easyConvToIntFromUint8(v Ivalue) Ivalue { 318 | return int(v.(uint8)) 319 | } 320 | 321 | func easyConvToInt8FromUint8(v Ivalue) Ivalue { 322 | return int8(v.(uint8)) 323 | } 324 | 325 | func easyConvToInt16FromUint8(v Ivalue) Ivalue { 326 | return int16(v.(uint8)) 327 | } 328 | 329 | func easyConvToInt32FromUint8(v Ivalue) Ivalue { 330 | return int32(v.(uint8)) 331 | } 332 | 333 | func easyConvToInt64FromUint8(v Ivalue) Ivalue { 334 | return int64(v.(uint8)) 335 | } 336 | 337 | func easyConvToUintFromUint8(v Ivalue) Ivalue { 338 | return uint(v.(uint8)) 339 | } 340 | 341 | func easyConvToUint8FromUint8(v Ivalue) Ivalue { 342 | return uint8(v.(uint8)) 343 | } 344 | 345 | func easyConvToUint16FromUint8(v Ivalue) Ivalue { 346 | return uint16(v.(uint8)) 347 | } 348 | 349 | func easyConvToUint32FromUint8(v Ivalue) Ivalue { 350 | return uint32(v.(uint8)) 351 | } 352 | 353 | func easyConvToUint64FromUint8(v Ivalue) Ivalue { 354 | return uint64(v.(uint8)) 355 | } 356 | 357 | func easyConvToUintptrFromUint8(v Ivalue) Ivalue { 358 | return uintptr(v.(uint8)) 359 | } 360 | 361 | func easyConvToFloat32FromUint8(v Ivalue) Ivalue { 362 | return float32(v.(uint8)) 363 | } 364 | 365 | func easyConvToFloat64FromUint8(v Ivalue) Ivalue { 366 | return float64(v.(uint8)) 367 | } 368 | 369 | func easyConvToIntFromUint16(v Ivalue) Ivalue { 370 | return int(v.(uint16)) 371 | } 372 | 373 | func easyConvToInt8FromUint16(v Ivalue) Ivalue { 374 | return int8(v.(uint16)) 375 | } 376 | 377 | func easyConvToInt16FromUint16(v Ivalue) Ivalue { 378 | return int16(v.(uint16)) 379 | } 380 | 381 | func easyConvToInt32FromUint16(v Ivalue) Ivalue { 382 | return int32(v.(uint16)) 383 | } 384 | 385 | func easyConvToInt64FromUint16(v Ivalue) Ivalue { 386 | return int64(v.(uint16)) 387 | } 388 | 389 | func easyConvToUintFromUint16(v Ivalue) Ivalue { 390 | return uint(v.(uint16)) 391 | } 392 | 393 | func easyConvToUint8FromUint16(v Ivalue) Ivalue { 394 | return uint8(v.(uint16)) 395 | } 396 | 397 | func easyConvToUint16FromUint16(v Ivalue) Ivalue { 398 | return uint16(v.(uint16)) 399 | } 400 | 401 | func easyConvToUint32FromUint16(v Ivalue) Ivalue { 402 | return uint32(v.(uint16)) 403 | } 404 | 405 | func easyConvToUint64FromUint16(v Ivalue) Ivalue { 406 | return uint64(v.(uint16)) 407 | } 408 | 409 | func easyConvToUintptrFromUint16(v Ivalue) Ivalue { 410 | return uintptr(v.(uint16)) 411 | } 412 | 413 | func easyConvToFloat32FromUint16(v Ivalue) Ivalue { 414 | return float32(v.(uint16)) 415 | } 416 | 417 | func easyConvToFloat64FromUint16(v Ivalue) Ivalue { 418 | return float64(v.(uint16)) 419 | } 420 | 421 | func easyConvToIntFromUint32(v Ivalue) Ivalue { 422 | return int(v.(uint32)) 423 | } 424 | 425 | func easyConvToInt8FromUint32(v Ivalue) Ivalue { 426 | return int8(v.(uint32)) 427 | } 428 | 429 | func easyConvToInt16FromUint32(v Ivalue) Ivalue { 430 | return int16(v.(uint32)) 431 | } 432 | 433 | func easyConvToInt32FromUint32(v Ivalue) Ivalue { 434 | return int32(v.(uint32)) 435 | } 436 | 437 | func easyConvToInt64FromUint32(v Ivalue) Ivalue { 438 | return int64(v.(uint32)) 439 | } 440 | 441 | func easyConvToUintFromUint32(v Ivalue) Ivalue { 442 | return uint(v.(uint32)) 443 | } 444 | 445 | func easyConvToUint8FromUint32(v Ivalue) Ivalue { 446 | return uint8(v.(uint32)) 447 | } 448 | 449 | func easyConvToUint16FromUint32(v Ivalue) Ivalue { 450 | return uint16(v.(uint32)) 451 | } 452 | 453 | func easyConvToUint32FromUint32(v Ivalue) Ivalue { 454 | return uint32(v.(uint32)) 455 | } 456 | 457 | func easyConvToUint64FromUint32(v Ivalue) Ivalue { 458 | return uint64(v.(uint32)) 459 | } 460 | 461 | func easyConvToUintptrFromUint32(v Ivalue) Ivalue { 462 | return uintptr(v.(uint32)) 463 | } 464 | 465 | func easyConvToFloat32FromUint32(v Ivalue) Ivalue { 466 | return float32(v.(uint32)) 467 | } 468 | 469 | func easyConvToFloat64FromUint32(v Ivalue) Ivalue { 470 | return float64(v.(uint32)) 471 | } 472 | 473 | func easyConvToIntFromUint64(v Ivalue) Ivalue { 474 | return int(v.(uint64)) 475 | } 476 | 477 | func easyConvToInt8FromUint64(v Ivalue) Ivalue { 478 | return int8(v.(uint64)) 479 | } 480 | 481 | func easyConvToInt16FromUint64(v Ivalue) Ivalue { 482 | return int16(v.(uint64)) 483 | } 484 | 485 | func easyConvToInt32FromUint64(v Ivalue) Ivalue { 486 | return int32(v.(uint64)) 487 | } 488 | 489 | func easyConvToInt64FromUint64(v Ivalue) Ivalue { 490 | return int64(v.(uint64)) 491 | } 492 | 493 | func easyConvToUintFromUint64(v Ivalue) Ivalue { 494 | return uint(v.(uint64)) 495 | } 496 | 497 | func easyConvToUint8FromUint64(v Ivalue) Ivalue { 498 | return uint8(v.(uint64)) 499 | } 500 | 501 | func easyConvToUint16FromUint64(v Ivalue) Ivalue { 502 | return uint16(v.(uint64)) 503 | } 504 | 505 | func easyConvToUint32FromUint64(v Ivalue) Ivalue { 506 | return uint32(v.(uint64)) 507 | } 508 | 509 | func easyConvToUint64FromUint64(v Ivalue) Ivalue { 510 | return uint64(v.(uint64)) 511 | } 512 | 513 | func easyConvToUintptrFromUint64(v Ivalue) Ivalue { 514 | return uintptr(v.(uint64)) 515 | } 516 | 517 | func easyConvToFloat32FromUint64(v Ivalue) Ivalue { 518 | return float32(v.(uint64)) 519 | } 520 | 521 | func easyConvToFloat64FromUint64(v Ivalue) Ivalue { 522 | return float64(v.(uint64)) 523 | } 524 | 525 | func easyConvToIntFromUintptr(v Ivalue) Ivalue { 526 | return int(v.(uintptr)) 527 | } 528 | 529 | func easyConvToInt8FromUintptr(v Ivalue) Ivalue { 530 | return int8(v.(uintptr)) 531 | } 532 | 533 | func easyConvToInt16FromUintptr(v Ivalue) Ivalue { 534 | return int16(v.(uintptr)) 535 | } 536 | 537 | func easyConvToInt32FromUintptr(v Ivalue) Ivalue { 538 | return int32(v.(uintptr)) 539 | } 540 | 541 | func easyConvToInt64FromUintptr(v Ivalue) Ivalue { 542 | return int64(v.(uintptr)) 543 | } 544 | 545 | func easyConvToUintFromUintptr(v Ivalue) Ivalue { 546 | return uint(v.(uintptr)) 547 | } 548 | 549 | func easyConvToUint8FromUintptr(v Ivalue) Ivalue { 550 | return uint8(v.(uintptr)) 551 | } 552 | 553 | func easyConvToUint16FromUintptr(v Ivalue) Ivalue { 554 | return uint16(v.(uintptr)) 555 | } 556 | 557 | func easyConvToUint32FromUintptr(v Ivalue) Ivalue { 558 | return uint32(v.(uintptr)) 559 | } 560 | 561 | func easyConvToUint64FromUintptr(v Ivalue) Ivalue { 562 | return uint64(v.(uintptr)) 563 | } 564 | 565 | func easyConvToUintptrFromUintptr(v Ivalue) Ivalue { 566 | return uintptr(v.(uintptr)) 567 | } 568 | 569 | func easyConvToFloat32FromUintptr(v Ivalue) Ivalue { 570 | return float32(v.(uintptr)) 571 | } 572 | 573 | func easyConvToFloat64FromUintptr(v Ivalue) Ivalue { 574 | return float64(v.(uintptr)) 575 | } 576 | 577 | func easyConvToIntFromFloat32(v Ivalue) Ivalue { 578 | return int(v.(float32)) 579 | } 580 | 581 | func easyConvToInt8FromFloat32(v Ivalue) Ivalue { 582 | return int8(v.(float32)) 583 | } 584 | 585 | func easyConvToInt16FromFloat32(v Ivalue) Ivalue { 586 | return int16(v.(float32)) 587 | } 588 | 589 | func easyConvToInt32FromFloat32(v Ivalue) Ivalue { 590 | return int32(v.(float32)) 591 | } 592 | 593 | func easyConvToInt64FromFloat32(v Ivalue) Ivalue { 594 | return int64(v.(float32)) 595 | } 596 | 597 | func easyConvToUintFromFloat32(v Ivalue) Ivalue { 598 | return uint(v.(float32)) 599 | } 600 | 601 | func easyConvToUint8FromFloat32(v Ivalue) Ivalue { 602 | return uint8(v.(float32)) 603 | } 604 | 605 | func easyConvToUint16FromFloat32(v Ivalue) Ivalue { 606 | return uint16(v.(float32)) 607 | } 608 | 609 | func easyConvToUint32FromFloat32(v Ivalue) Ivalue { 610 | return uint32(v.(float32)) 611 | } 612 | 613 | func easyConvToUint64FromFloat32(v Ivalue) Ivalue { 614 | return uint64(v.(float32)) 615 | } 616 | 617 | func easyConvToUintptrFromFloat32(v Ivalue) Ivalue { 618 | return uintptr(v.(float32)) 619 | } 620 | 621 | func easyConvToFloat32FromFloat32(v Ivalue) Ivalue { 622 | return float32(v.(float32)) 623 | } 624 | 625 | func easyConvToFloat64FromFloat32(v Ivalue) Ivalue { 626 | return float64(v.(float32)) 627 | } 628 | 629 | func easyConvToIntFromFloat64(v Ivalue) Ivalue { 630 | return int(v.(float64)) 631 | } 632 | 633 | func easyConvToInt8FromFloat64(v Ivalue) Ivalue { 634 | return int8(v.(float64)) 635 | } 636 | 637 | func easyConvToInt16FromFloat64(v Ivalue) Ivalue { 638 | return int16(v.(float64)) 639 | } 640 | 641 | func easyConvToInt32FromFloat64(v Ivalue) Ivalue { 642 | return int32(v.(float64)) 643 | } 644 | 645 | func easyConvToInt64FromFloat64(v Ivalue) Ivalue { 646 | return int64(v.(float64)) 647 | } 648 | 649 | func easyConvToUintFromFloat64(v Ivalue) Ivalue { 650 | return uint(v.(float64)) 651 | } 652 | 653 | func easyConvToUint8FromFloat64(v Ivalue) Ivalue { 654 | return uint8(v.(float64)) 655 | } 656 | 657 | func easyConvToUint16FromFloat64(v Ivalue) Ivalue { 658 | return uint16(v.(float64)) 659 | } 660 | 661 | func easyConvToUint32FromFloat64(v Ivalue) Ivalue { 662 | return uint32(v.(float64)) 663 | } 664 | 665 | func easyConvToUint64FromFloat64(v Ivalue) Ivalue { 666 | return uint64(v.(float64)) 667 | } 668 | 669 | func easyConvToUintptrFromFloat64(v Ivalue) Ivalue { 670 | return uintptr(v.(float64)) 671 | } 672 | 673 | func easyConvToFloat32FromFloat64(v Ivalue) Ivalue { 674 | return float32(v.(float64)) 675 | } 676 | 677 | func easyConvToFloat64FromFloat64(v Ivalue) Ivalue { 678 | return float64(v.(float64)) 679 | } 680 | 681 | func easyConvFunc(desT, srcT types.BasicKind) func(Ivalue) Ivalue { 682 | switch srcT { 683 | case types.Int: 684 | switch desT { 685 | case types.Int: 686 | return easyConvToIntFromInt 687 | case types.Int8: 688 | return easyConvToInt8FromInt 689 | case types.Int16: 690 | return easyConvToInt16FromInt 691 | case types.Int32: 692 | return easyConvToInt32FromInt 693 | case types.Int64: 694 | return easyConvToInt64FromInt 695 | case types.Uint: 696 | return easyConvToUintFromInt 697 | case types.Uint8: 698 | return easyConvToUint8FromInt 699 | case types.Uint16: 700 | return easyConvToUint16FromInt 701 | case types.Uint32: 702 | return easyConvToUint32FromInt 703 | case types.Uint64: 704 | return easyConvToUint64FromInt 705 | case types.Uintptr: 706 | return easyConvToUintptrFromInt 707 | case types.Float32: 708 | return easyConvToFloat32FromInt 709 | case types.Float64: 710 | return easyConvToFloat64FromInt 711 | } 712 | case types.Int8: 713 | switch desT { 714 | case types.Int: 715 | return easyConvToIntFromInt8 716 | case types.Int8: 717 | return easyConvToInt8FromInt8 718 | case types.Int16: 719 | return easyConvToInt16FromInt8 720 | case types.Int32: 721 | return easyConvToInt32FromInt8 722 | case types.Int64: 723 | return easyConvToInt64FromInt8 724 | case types.Uint: 725 | return easyConvToUintFromInt8 726 | case types.Uint8: 727 | return easyConvToUint8FromInt8 728 | case types.Uint16: 729 | return easyConvToUint16FromInt8 730 | case types.Uint32: 731 | return easyConvToUint32FromInt8 732 | case types.Uint64: 733 | return easyConvToUint64FromInt8 734 | case types.Uintptr: 735 | return easyConvToUintptrFromInt8 736 | case types.Float32: 737 | return easyConvToFloat32FromInt8 738 | case types.Float64: 739 | return easyConvToFloat64FromInt8 740 | } 741 | case types.Int16: 742 | switch desT { 743 | case types.Int: 744 | return easyConvToIntFromInt16 745 | case types.Int8: 746 | return easyConvToInt8FromInt16 747 | case types.Int16: 748 | return easyConvToInt16FromInt16 749 | case types.Int32: 750 | return easyConvToInt32FromInt16 751 | case types.Int64: 752 | return easyConvToInt64FromInt16 753 | case types.Uint: 754 | return easyConvToUintFromInt16 755 | case types.Uint8: 756 | return easyConvToUint8FromInt16 757 | case types.Uint16: 758 | return easyConvToUint16FromInt16 759 | case types.Uint32: 760 | return easyConvToUint32FromInt16 761 | case types.Uint64: 762 | return easyConvToUint64FromInt16 763 | case types.Uintptr: 764 | return easyConvToUintptrFromInt16 765 | case types.Float32: 766 | return easyConvToFloat32FromInt16 767 | case types.Float64: 768 | return easyConvToFloat64FromInt16 769 | } 770 | case types.Int32: 771 | switch desT { 772 | case types.Int: 773 | return easyConvToIntFromInt32 774 | case types.Int8: 775 | return easyConvToInt8FromInt32 776 | case types.Int16: 777 | return easyConvToInt16FromInt32 778 | case types.Int32: 779 | return easyConvToInt32FromInt32 780 | case types.Int64: 781 | return easyConvToInt64FromInt32 782 | case types.Uint: 783 | return easyConvToUintFromInt32 784 | case types.Uint8: 785 | return easyConvToUint8FromInt32 786 | case types.Uint16: 787 | return easyConvToUint16FromInt32 788 | case types.Uint32: 789 | return easyConvToUint32FromInt32 790 | case types.Uint64: 791 | return easyConvToUint64FromInt32 792 | case types.Uintptr: 793 | return easyConvToUintptrFromInt32 794 | case types.Float32: 795 | return easyConvToFloat32FromInt32 796 | case types.Float64: 797 | return easyConvToFloat64FromInt32 798 | } 799 | case types.Int64: 800 | switch desT { 801 | case types.Int: 802 | return easyConvToIntFromInt64 803 | case types.Int8: 804 | return easyConvToInt8FromInt64 805 | case types.Int16: 806 | return easyConvToInt16FromInt64 807 | case types.Int32: 808 | return easyConvToInt32FromInt64 809 | case types.Int64: 810 | return easyConvToInt64FromInt64 811 | case types.Uint: 812 | return easyConvToUintFromInt64 813 | case types.Uint8: 814 | return easyConvToUint8FromInt64 815 | case types.Uint16: 816 | return easyConvToUint16FromInt64 817 | case types.Uint32: 818 | return easyConvToUint32FromInt64 819 | case types.Uint64: 820 | return easyConvToUint64FromInt64 821 | case types.Uintptr: 822 | return easyConvToUintptrFromInt64 823 | case types.Float32: 824 | return easyConvToFloat32FromInt64 825 | case types.Float64: 826 | return easyConvToFloat64FromInt64 827 | } 828 | case types.Uint: 829 | switch desT { 830 | case types.Int: 831 | return easyConvToIntFromUint 832 | case types.Int8: 833 | return easyConvToInt8FromUint 834 | case types.Int16: 835 | return easyConvToInt16FromUint 836 | case types.Int32: 837 | return easyConvToInt32FromUint 838 | case types.Int64: 839 | return easyConvToInt64FromUint 840 | case types.Uint: 841 | return easyConvToUintFromUint 842 | case types.Uint8: 843 | return easyConvToUint8FromUint 844 | case types.Uint16: 845 | return easyConvToUint16FromUint 846 | case types.Uint32: 847 | return easyConvToUint32FromUint 848 | case types.Uint64: 849 | return easyConvToUint64FromUint 850 | case types.Uintptr: 851 | return easyConvToUintptrFromUint 852 | case types.Float32: 853 | return easyConvToFloat32FromUint 854 | case types.Float64: 855 | return easyConvToFloat64FromUint 856 | } 857 | case types.Uint8: 858 | switch desT { 859 | case types.Int: 860 | return easyConvToIntFromUint8 861 | case types.Int8: 862 | return easyConvToInt8FromUint8 863 | case types.Int16: 864 | return easyConvToInt16FromUint8 865 | case types.Int32: 866 | return easyConvToInt32FromUint8 867 | case types.Int64: 868 | return easyConvToInt64FromUint8 869 | case types.Uint: 870 | return easyConvToUintFromUint8 871 | case types.Uint8: 872 | return easyConvToUint8FromUint8 873 | case types.Uint16: 874 | return easyConvToUint16FromUint8 875 | case types.Uint32: 876 | return easyConvToUint32FromUint8 877 | case types.Uint64: 878 | return easyConvToUint64FromUint8 879 | case types.Uintptr: 880 | return easyConvToUintptrFromUint8 881 | case types.Float32: 882 | return easyConvToFloat32FromUint8 883 | case types.Float64: 884 | return easyConvToFloat64FromUint8 885 | } 886 | case types.Uint16: 887 | switch desT { 888 | case types.Int: 889 | return easyConvToIntFromUint16 890 | case types.Int8: 891 | return easyConvToInt8FromUint16 892 | case types.Int16: 893 | return easyConvToInt16FromUint16 894 | case types.Int32: 895 | return easyConvToInt32FromUint16 896 | case types.Int64: 897 | return easyConvToInt64FromUint16 898 | case types.Uint: 899 | return easyConvToUintFromUint16 900 | case types.Uint8: 901 | return easyConvToUint8FromUint16 902 | case types.Uint16: 903 | return easyConvToUint16FromUint16 904 | case types.Uint32: 905 | return easyConvToUint32FromUint16 906 | case types.Uint64: 907 | return easyConvToUint64FromUint16 908 | case types.Uintptr: 909 | return easyConvToUintptrFromUint16 910 | case types.Float32: 911 | return easyConvToFloat32FromUint16 912 | case types.Float64: 913 | return easyConvToFloat64FromUint16 914 | } 915 | case types.Uint32: 916 | switch desT { 917 | case types.Int: 918 | return easyConvToIntFromUint32 919 | case types.Int8: 920 | return easyConvToInt8FromUint32 921 | case types.Int16: 922 | return easyConvToInt16FromUint32 923 | case types.Int32: 924 | return easyConvToInt32FromUint32 925 | case types.Int64: 926 | return easyConvToInt64FromUint32 927 | case types.Uint: 928 | return easyConvToUintFromUint32 929 | case types.Uint8: 930 | return easyConvToUint8FromUint32 931 | case types.Uint16: 932 | return easyConvToUint16FromUint32 933 | case types.Uint32: 934 | return easyConvToUint32FromUint32 935 | case types.Uint64: 936 | return easyConvToUint64FromUint32 937 | case types.Uintptr: 938 | return easyConvToUintptrFromUint32 939 | case types.Float32: 940 | return easyConvToFloat32FromUint32 941 | case types.Float64: 942 | return easyConvToFloat64FromUint32 943 | } 944 | case types.Uint64: 945 | switch desT { 946 | case types.Int: 947 | return easyConvToIntFromUint64 948 | case types.Int8: 949 | return easyConvToInt8FromUint64 950 | case types.Int16: 951 | return easyConvToInt16FromUint64 952 | case types.Int32: 953 | return easyConvToInt32FromUint64 954 | case types.Int64: 955 | return easyConvToInt64FromUint64 956 | case types.Uint: 957 | return easyConvToUintFromUint64 958 | case types.Uint8: 959 | return easyConvToUint8FromUint64 960 | case types.Uint16: 961 | return easyConvToUint16FromUint64 962 | case types.Uint32: 963 | return easyConvToUint32FromUint64 964 | case types.Uint64: 965 | return easyConvToUint64FromUint64 966 | case types.Uintptr: 967 | return easyConvToUintptrFromUint64 968 | case types.Float32: 969 | return easyConvToFloat32FromUint64 970 | case types.Float64: 971 | return easyConvToFloat64FromUint64 972 | } 973 | case types.Uintptr: 974 | switch desT { 975 | case types.Int: 976 | return easyConvToIntFromUintptr 977 | case types.Int8: 978 | return easyConvToInt8FromUintptr 979 | case types.Int16: 980 | return easyConvToInt16FromUintptr 981 | case types.Int32: 982 | return easyConvToInt32FromUintptr 983 | case types.Int64: 984 | return easyConvToInt64FromUintptr 985 | case types.Uint: 986 | return easyConvToUintFromUintptr 987 | case types.Uint8: 988 | return easyConvToUint8FromUintptr 989 | case types.Uint16: 990 | return easyConvToUint16FromUintptr 991 | case types.Uint32: 992 | return easyConvToUint32FromUintptr 993 | case types.Uint64: 994 | return easyConvToUint64FromUintptr 995 | case types.Uintptr: 996 | return easyConvToUintptrFromUintptr 997 | case types.Float32: 998 | return easyConvToFloat32FromUintptr 999 | case types.Float64: 1000 | return easyConvToFloat64FromUintptr 1001 | } 1002 | case types.Float32: 1003 | switch desT { 1004 | case types.Int: 1005 | return easyConvToIntFromFloat32 1006 | case types.Int8: 1007 | return easyConvToInt8FromFloat32 1008 | case types.Int16: 1009 | return easyConvToInt16FromFloat32 1010 | case types.Int32: 1011 | return easyConvToInt32FromFloat32 1012 | case types.Int64: 1013 | return easyConvToInt64FromFloat32 1014 | case types.Uint: 1015 | return easyConvToUintFromFloat32 1016 | case types.Uint8: 1017 | return easyConvToUint8FromFloat32 1018 | case types.Uint16: 1019 | return easyConvToUint16FromFloat32 1020 | case types.Uint32: 1021 | return easyConvToUint32FromFloat32 1022 | case types.Uint64: 1023 | return easyConvToUint64FromFloat32 1024 | case types.Uintptr: 1025 | return easyConvToUintptrFromFloat32 1026 | case types.Float32: 1027 | return easyConvToFloat32FromFloat32 1028 | case types.Float64: 1029 | return easyConvToFloat64FromFloat32 1030 | } 1031 | case types.Float64: 1032 | switch desT { 1033 | case types.Int: 1034 | return easyConvToIntFromFloat64 1035 | case types.Int8: 1036 | return easyConvToInt8FromFloat64 1037 | case types.Int16: 1038 | return easyConvToInt16FromFloat64 1039 | case types.Int32: 1040 | return easyConvToInt32FromFloat64 1041 | case types.Int64: 1042 | return easyConvToInt64FromFloat64 1043 | case types.Uint: 1044 | return easyConvToUintFromFloat64 1045 | case types.Uint8: 1046 | return easyConvToUint8FromFloat64 1047 | case types.Uint16: 1048 | return easyConvToUint16FromFloat64 1049 | case types.Uint32: 1050 | return easyConvToUint32FromFloat64 1051 | case types.Uint64: 1052 | return easyConvToUint64FromFloat64 1053 | case types.Uintptr: 1054 | return easyConvToUintptrFromFloat64 1055 | case types.Float32: 1056 | return easyConvToFloat32FromFloat64 1057 | case types.Float64: 1058 | return easyConvToFloat64FromFloat64 1059 | } 1060 | } 1061 | 1062 | return nil 1063 | } 1064 | -------------------------------------------------------------------------------- /interp/preprocess.go: -------------------------------------------------------------------------------- 1 | package interp 2 | 3 | import ( 4 | "fmt" 5 | "go/token" 6 | "reflect" 7 | "sync" 8 | 9 | "go/types" 10 | 11 | "golang.org/x/tools/go/ssa" 12 | ) 13 | 14 | //go:generate interpgen 15 | 16 | func (i *interpreter) preprocess() { 17 | /* 18 | i.externals.globVals = make(map[ssa.Value]*globInfo) 19 | for _, pkg := range i.prog.AllPackages() { 20 | for _, mem := range pkg.Members { 21 | //fn, isFunc := mem.(*ssa.Function) 22 | //if isFunc { 23 | // i.preprocessFn(fn) 24 | //} 25 | gl, isGlobal := mem.(*ssa.Global) 26 | if isGlobal { 27 | ai, isAccessed := i.externals.globs[gl.String()] 28 | if isAccessed { 29 | i.externals.globVals[mem.(ssa.Value)] = ai 30 | //println("DEBUG overload global: " + gl.String()) 31 | } 32 | } 33 | } 34 | } 35 | */ 36 | } 37 | 38 | func (fr *frame) getFnInf() functionInfo { 39 | fr.i.functionsRWMutex.RLock() 40 | fnInf, found := fr.i.functions[fr.fn] 41 | fr.i.functionsRWMutex.RUnlock() 42 | if !found { 43 | fr.i.functionsRWMutex.Lock() 44 | fr.i.preprocessFn(fr.fn) 45 | fr.i.functionsRWMutex.Unlock() 46 | fnInf = fr.i.functions[fr.fn] 47 | } 48 | return fnInf 49 | } 50 | 51 | const debugStats = false 52 | 53 | // debugMap allows debugging information to be stored and inspected, not for external use. 54 | var debugMap = make(map[string]int) 55 | var debugMapMutex sync.Mutex 56 | 57 | func (i *interpreter) preprocessFn(fn *ssa.Function) { 58 | //fmt.Println("DEBUG preprocessFn " + fn.Name()) 59 | _, found := i.functions[fn] 60 | if !found { 61 | i.runtimeFunc[reflect.ValueOf(fn).Pointer()] = fn // to avoid using unsafe package 62 | 63 | if _, isExtern := i.externals.funcs[fn.String()]; isExtern { 64 | if fn.Blocks != nil { 65 | fn.Blocks = nil 66 | //fmt.Println("DEBUG overloaded function ", fn.String()) 67 | } 68 | } else { 69 | 70 | i.functions[fn] = functionInfo{ 71 | instrs: make([][]func(*frame), len(fn.Blocks)), 72 | envEntries: make(map[ssa.Value]int), 73 | } 74 | // set-up envEntries 75 | entryNum := 0 76 | for _, param := range fn.Params { 77 | i.functions[fn].envEntries[param] = entryNum 78 | entryNum++ 79 | } 80 | for _, bound := range fn.FreeVars { 81 | i.functions[fn].envEntries[bound] = entryNum 82 | entryNum++ 83 | } 84 | for bNum, blk := range fn.Blocks { 85 | i.functions[fn].instrs[bNum] = make([]func(*frame), len(blk.Instrs)) 86 | for _, ins := range blk.Instrs { 87 | if val, ok := ins.(ssa.Value); ok { 88 | i.functions[fn].envEntries[val] = entryNum 89 | entryNum++ 90 | } 91 | } 92 | } 93 | 94 | // create ops 95 | for bNum, blk := range fn.Blocks { 96 | for iNum, ins := range blk.Instrs { 97 | /* 98 | for _, rand := range ins.Operands(nil) { 99 | val := *rand 100 | switch val.(type) { 101 | case *ssa.Const: 102 | i.preprocessConst(val.(*ssa.Const)) 103 | //case *ssa.Function: 104 | // i.preprocessFn(val.(*ssa.Function)) 105 | } 106 | } 107 | */ 108 | 109 | switch ins.(type) { 110 | case *ssa.UnOp: 111 | op := ins.(*ssa.UnOp) 112 | xFn := i.getFunc(fn, op.X) 113 | val := ins.(ssa.Value) 114 | envTgt := i.functions[fn].envEntries[val] 115 | i.functions[fn].instrs[bNum][iNum] = 116 | func(fr *frame) { // TODO handle simple cases directly 117 | fr.env[envTgt] = fr.i.unop(op, xFn(fr)) 118 | } 119 | 120 | case *ssa.BinOp: 121 | op := ins.(*ssa.BinOp) 122 | boFn := i.binopFunc(op.Op, op.X.Type()) 123 | xFn := i.getFunc(fn, op.X) 124 | yFn := i.getFunc(fn, op.Y) 125 | val := ins.(ssa.Value) 126 | envTgt := i.functions[fn].envEntries[val] 127 | i.functions[fn].instrs[bNum][iNum] = 128 | func(fr *frame) { 129 | fr.env[envTgt] = boFn(xFn(fr), yFn(fr)) 130 | } 131 | 132 | case *ssa.Convert: 133 | op := ins.(*ssa.Convert) 134 | xFn := i.getFunc(fn, op.X) 135 | val := ins.(ssa.Value) 136 | envTgt := i.functions[fn].envEntries[val] 137 | srcT := op.X.Type() 138 | desT := op.Type() 139 | i.functions[fn].instrs[bNum][iNum] = 140 | func(fr *frame) { 141 | fr.env[envTgt] = fr.i.conv(desT, srcT, xFn(fr)) 142 | } // the default postition 143 | desTul := desT.Underlying() 144 | srcTul := srcT.Underlying() 145 | if desBas, ok := desTul.(*types.Basic); ok { 146 | if srcBas, ok := srcTul.(*types.Basic); ok { 147 | ec := easyConvFunc(desBas.Kind(), srcBas.Kind()) 148 | if ec != nil { 149 | i.functions[fn].instrs[bNum][iNum] = 150 | func(fr *frame) { 151 | fr.env[envTgt] = ec(xFn(fr)) 152 | } 153 | } 154 | } 155 | } 156 | 157 | case *ssa.Store: 158 | op := ins.(*ssa.Store) 159 | typ := op.Val.Type() 160 | addr := i.getFunc(fn, op.Addr) 161 | val := i.getFunc(fn, op.Val) 162 | i.functions[fn].instrs[bNum][iNum] = 163 | func(fr *frame) { // TODO break out types 164 | store(typ, addr(fr).(*Ivalue), val(fr)) 165 | } 166 | 167 | case *ssa.IndexAddr: 168 | op := ins.(*ssa.IndexAddr) 169 | val := ins.(ssa.Value) 170 | envTgt := i.functions[fn].envEntries[val] 171 | i.functions[fn].instrs[bNum][iNum] = 172 | i.indexAddrFn(op, envTgt) 173 | 174 | case *ssa.FieldAddr: 175 | op := ins.(*ssa.FieldAddr) 176 | val := ins.(ssa.Value) 177 | envTgt := i.functions[fn].envEntries[val] 178 | i.functions[fn].instrs[bNum][iNum] = 179 | i.fieldAddrFn(op, envTgt) 180 | 181 | case *ssa.Phi: 182 | op := ins.(*ssa.Phi) 183 | val := ins.(ssa.Value) 184 | envTgt := i.functions[fn].envEntries[val] 185 | preds := ins.Block().Preds 186 | var edges []func(*frame) Ivalue 187 | for ii := range preds { 188 | edges = append(edges, i.getFunc(fn, op.Edges[ii])) 189 | } 190 | i.functions[fn].instrs[bNum][iNum] = 191 | func(fr *frame) { 192 | for ii, pred := range preds { 193 | if fr.prevBlock == pred { 194 | fr.env[envTgt] = edges[ii](fr) 195 | break 196 | } 197 | } 198 | } 199 | 200 | default: 201 | if debugStats { 202 | debugMapMutex.Lock() 203 | debugMap[fmt.Sprintf("%T", ins)]++ 204 | debugMapMutex.Unlock() 205 | } 206 | } 207 | } 208 | } 209 | //if len(i.functions[fn].envEntries) > 0 { 210 | // fmt.Printf("DEBUG envEnts %s %#v\n", fn, i.functions[fn].envEntries) 211 | //} 212 | } 213 | } 214 | } 215 | 216 | func (i *interpreter) indexAddrFn(iaInstr *ssa.IndexAddr, envTgt int) func(fr *frame) { 217 | xFn := i.getFunc(iaInstr.Parent(), iaInstr.X) 218 | idxFn := i.getFunc(iaInstr.Parent(), iaInstr.Index) 219 | asIntFn := easyConvFunc(types.Int, 220 | iaInstr.Index.Type().Underlying().(*types.Basic).Kind()) 221 | switch iaInstr.X.Type().Underlying().(type) { 222 | case *types.Slice: 223 | return func(fr *frame) { 224 | fr.env[envTgt] = &(xFn(fr).([]Ivalue)[asIntFn(idxFn(fr)).(int)]) 225 | } 226 | case *types.Pointer: // Array 227 | return func(fr *frame) { 228 | x := xFn(fr).(*Ivalue) 229 | idx := idxFn(fr) 230 | fr.env[envTgt] = &(*x).(array)[asIntFn(idx).(int)] 231 | } 232 | default: 233 | panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", iaInstr.X.Type().Underlying())) 234 | } 235 | } 236 | 237 | func (i *interpreter) fieldAddrFn(op *ssa.FieldAddr, envTgt int) func(fr *frame) { 238 | xFn := i.getFunc(op.Parent(), op.X) 239 | fld := op.Field 240 | return func(fr *frame) { 241 | x := xFn(fr).(*Ivalue) 242 | switch (*x).(type) { 243 | case structure: 244 | // FIXME wrong! &global.f must not change if we do *global = zero! 245 | fr.env[envTgt] = &((*x).(structure)[fld]) 246 | case reflect.Value: 247 | // THIS CODE IS EXPERIMENTAL 248 | //fmt.Println("DEBUG field", fld) 249 | xx := (*x).(reflect.Value) 250 | //fmt.Println("DEBUG reflect.Value", xx) 251 | pseudoItem := Ivalue(xx.Elem().Field(fld).Addr()) 252 | fr.env[envTgt] = &pseudoItem 253 | //fmt.Println("DEBUG address", fr.env[envTgt]) 254 | default: 255 | panic(fmt.Sprintf("unexpected fieldAddress x %v:%T", x, x)) 256 | } 257 | } 258 | } 259 | 260 | func (i *interpreter) getFunc(fn *ssa.Function, key ssa.Value) func(fr *frame) Ivalue { 261 | switch key := key.(type) { 262 | case nil: 263 | // Hack; simplifies handling of optional attributes 264 | // such as ssa.Slice.{Low,High}. 265 | return func(fr *frame) Ivalue { 266 | return nil 267 | } 268 | case *ssa.Function, *ssa.Builtin: 269 | return func(fr *frame) Ivalue { 270 | return key 271 | } 272 | case *ssa.Const: 273 | ret := i.constIvalue(key) 274 | return func(fr *frame) Ivalue { 275 | return ret 276 | } 277 | case *ssa.Global: 278 | return func(fr *frame) Ivalue { 279 | if r, ok := fr.i.globals[key]; ok { 280 | return r 281 | } 282 | panic(fmt.Sprintf("getFunc: no global Ivalue for %T: %v", key, key.Name())) 283 | } 284 | } 285 | envTgt, ok := i.functions[fn].envEntries[key] 286 | if !ok { 287 | panic(fmt.Sprintf("getFunc: no environment Ivalue for %T: %v", key, key.Name())) 288 | } 289 | return func(fr *frame) Ivalue { 290 | return fr.env[envTgt] 291 | } 292 | } 293 | 294 | /* 295 | func (i *interpreter) preprocessConst(c *ssa.Const) { 296 | // NOTE this pre-processing approach is not always faster. 297 | i.constantsRWMutex.RLock() 298 | _, found := i.constants[c] 299 | i.constantsRWMutex.RUnlock() 300 | if found { 301 | return 302 | } 303 | i.constantsRWMutex.Lock() 304 | i.constants[c] = constIvalueEval(c, i) 305 | i.constantsRWMutex.Unlock() 306 | return 307 | } 308 | */ 309 | /* 310 | func (i *interpreter) preprocessZero(t types.Type) { 311 | // NOTE this pre-processing approach is not always faster. 312 | zv := i.zeroes.At(t) 313 | _, isIvalue := zv.(Ivalue) 314 | if isIvalue { 315 | return 316 | } 317 | i.zeroes.Set(t, zeroEval(t, i)) 318 | return 319 | } 320 | */ 321 | 322 | // binopFunc returns a closure that implements all arithmetic and logical binary operators for 323 | // numeric datatypes and strings. Both operands must have identical 324 | // dynamic type. 325 | // 326 | func (i *interpreter) binopFunc(op token.Token, tt types.Type) func(x, y Ivalue) Ivalue { 327 | t := i.zero(tt) 328 | switch op { 329 | case token.ADD: 330 | switch t.(type) { 331 | case int: 332 | return func(x, y Ivalue) Ivalue { 333 | return x.(int) + y.(int) 334 | } 335 | case int8: 336 | return func(x, y Ivalue) Ivalue { 337 | return x.(int8) + y.(int8) 338 | } 339 | case int16: 340 | return func(x, y Ivalue) Ivalue { 341 | return x.(int16) + y.(int16) 342 | } 343 | case int32: 344 | return func(x, y Ivalue) Ivalue { 345 | return x.(int32) + y.(int32) 346 | } 347 | case int64: 348 | return func(x, y Ivalue) Ivalue { 349 | return x.(int64) + y.(int64) 350 | } 351 | case uint: 352 | return func(x, y Ivalue) Ivalue { 353 | return x.(uint) + y.(uint) 354 | } 355 | case uint8: 356 | return func(x, y Ivalue) Ivalue { 357 | return x.(uint8) + y.(uint8) 358 | } 359 | case uint16: 360 | return func(x, y Ivalue) Ivalue { 361 | return x.(uint16) + y.(uint16) 362 | } 363 | case uint32: 364 | return func(x, y Ivalue) Ivalue { 365 | return x.(uint32) + y.(uint32) 366 | } 367 | case uint64: 368 | return func(x, y Ivalue) Ivalue { 369 | return x.(uint64) + y.(uint64) 370 | } 371 | case uintptr: 372 | return func(x, y Ivalue) Ivalue { 373 | return x.(uintptr) + y.(uintptr) 374 | } 375 | case float32: 376 | return func(x, y Ivalue) Ivalue { 377 | return x.(float32) + y.(float32) 378 | } 379 | case float64: 380 | return func(x, y Ivalue) Ivalue { 381 | return x.(float64) + y.(float64) 382 | } 383 | case complex64: 384 | return func(x, y Ivalue) Ivalue { 385 | return x.(complex64) + y.(complex64) 386 | } 387 | case complex128: 388 | return func(x, y Ivalue) Ivalue { 389 | return x.(complex128) + y.(complex128) 390 | } 391 | case string: 392 | return func(x, y Ivalue) Ivalue { 393 | return x.(string) + y.(string) 394 | } 395 | } 396 | 397 | case token.SUB: 398 | switch t.(type) { 399 | case int: 400 | return func(x, y Ivalue) Ivalue { 401 | return x.(int) - y.(int) 402 | } 403 | case int8: 404 | return func(x, y Ivalue) Ivalue { 405 | return x.(int8) - y.(int8) 406 | } 407 | case int16: 408 | return func(x, y Ivalue) Ivalue { 409 | return x.(int16) - y.(int16) 410 | } 411 | case int32: 412 | return func(x, y Ivalue) Ivalue { 413 | return x.(int32) - y.(int32) 414 | } 415 | case int64: 416 | return func(x, y Ivalue) Ivalue { 417 | return x.(int64) - y.(int64) 418 | } 419 | case uint: 420 | return func(x, y Ivalue) Ivalue { 421 | return x.(uint) - y.(uint) 422 | } 423 | case uint8: 424 | return func(x, y Ivalue) Ivalue { 425 | return x.(uint8) - y.(uint8) 426 | } 427 | case uint16: 428 | return func(x, y Ivalue) Ivalue { 429 | return x.(uint16) - y.(uint16) 430 | } 431 | case uint32: 432 | return func(x, y Ivalue) Ivalue { 433 | return x.(uint32) - y.(uint32) 434 | } 435 | case uint64: 436 | return func(x, y Ivalue) Ivalue { 437 | return x.(uint64) - y.(uint64) 438 | } 439 | case uintptr: 440 | return func(x, y Ivalue) Ivalue { 441 | return x.(uintptr) - y.(uintptr) 442 | } 443 | case float32: 444 | return func(x, y Ivalue) Ivalue { 445 | return x.(float32) - y.(float32) 446 | } 447 | case float64: 448 | return func(x, y Ivalue) Ivalue { 449 | return x.(float64) - y.(float64) 450 | } 451 | case complex64: 452 | return func(x, y Ivalue) Ivalue { 453 | return x.(complex64) - y.(complex64) 454 | } 455 | case complex128: 456 | return func(x, y Ivalue) Ivalue { 457 | return x.(complex128) - y.(complex128) 458 | } 459 | } 460 | 461 | case token.MUL: 462 | switch t.(type) { 463 | case int: 464 | return func(x, y Ivalue) Ivalue { 465 | return x.(int) * y.(int) 466 | } 467 | case int8: 468 | return func(x, y Ivalue) Ivalue { 469 | return x.(int8) * y.(int8) 470 | } 471 | case int16: 472 | return func(x, y Ivalue) Ivalue { 473 | return x.(int16) * y.(int16) 474 | } 475 | case int32: 476 | return func(x, y Ivalue) Ivalue { 477 | return x.(int32) * y.(int32) 478 | } 479 | case int64: 480 | return func(x, y Ivalue) Ivalue { 481 | return x.(int64) * y.(int64) 482 | } 483 | case uint: 484 | return func(x, y Ivalue) Ivalue { 485 | return x.(uint) * y.(uint) 486 | } 487 | case uint8: 488 | return func(x, y Ivalue) Ivalue { 489 | return x.(uint8) * y.(uint8) 490 | } 491 | case uint16: 492 | return func(x, y Ivalue) Ivalue { 493 | return x.(uint16) * y.(uint16) 494 | } 495 | case uint32: 496 | return func(x, y Ivalue) Ivalue { 497 | return x.(uint32) * y.(uint32) 498 | } 499 | case uint64: 500 | return func(x, y Ivalue) Ivalue { 501 | return x.(uint64) * y.(uint64) 502 | } 503 | case uintptr: 504 | return func(x, y Ivalue) Ivalue { 505 | return x.(uintptr) * y.(uintptr) 506 | } 507 | case float32: 508 | return func(x, y Ivalue) Ivalue { 509 | return x.(float32) * y.(float32) 510 | } 511 | case float64: 512 | return func(x, y Ivalue) Ivalue { 513 | return x.(float64) * y.(float64) 514 | } 515 | case complex64: 516 | return func(x, y Ivalue) Ivalue { 517 | return x.(complex64) * y.(complex64) 518 | } 519 | case complex128: 520 | return func(x, y Ivalue) Ivalue { 521 | return x.(complex128) * y.(complex128) 522 | } 523 | } 524 | 525 | case token.QUO: 526 | switch t.(type) { 527 | case int: 528 | return func(x, y Ivalue) Ivalue { 529 | return x.(int) / y.(int) 530 | } 531 | case int8: 532 | return func(x, y Ivalue) Ivalue { 533 | return x.(int8) / y.(int8) 534 | } 535 | case int16: 536 | return func(x, y Ivalue) Ivalue { 537 | return x.(int16) / y.(int16) 538 | } 539 | case int32: 540 | return func(x, y Ivalue) Ivalue { 541 | return x.(int32) / y.(int32) 542 | } 543 | case int64: 544 | return func(x, y Ivalue) Ivalue { 545 | return x.(int64) / y.(int64) 546 | } 547 | case uint: 548 | return func(x, y Ivalue) Ivalue { 549 | return x.(uint) / y.(uint) 550 | } 551 | case uint8: 552 | return func(x, y Ivalue) Ivalue { 553 | return x.(uint8) / y.(uint8) 554 | } 555 | case uint16: 556 | return func(x, y Ivalue) Ivalue { 557 | return x.(uint16) / y.(uint16) 558 | } 559 | case uint32: 560 | return func(x, y Ivalue) Ivalue { 561 | return x.(uint32) / y.(uint32) 562 | } 563 | case uint64: 564 | return func(x, y Ivalue) Ivalue { 565 | return x.(uint64) / y.(uint64) 566 | } 567 | case uintptr: 568 | return func(x, y Ivalue) Ivalue { 569 | return x.(uintptr) / y.(uintptr) 570 | } 571 | case float32: 572 | return func(x, y Ivalue) Ivalue { 573 | return x.(float32) / y.(float32) 574 | } 575 | case float64: 576 | return func(x, y Ivalue) Ivalue { 577 | return x.(float64) / y.(float64) 578 | } 579 | case complex64: 580 | return func(x, y Ivalue) Ivalue { 581 | return x.(complex64) / y.(complex64) 582 | } 583 | case complex128: 584 | return func(x, y Ivalue) Ivalue { 585 | return x.(complex128) / y.(complex128) 586 | } 587 | } 588 | 589 | case token.REM: 590 | switch t.(type) { 591 | case int: 592 | return func(x, y Ivalue) Ivalue { 593 | return x.(int) % y.(int) 594 | } 595 | case int8: 596 | return func(x, y Ivalue) Ivalue { 597 | return x.(int8) % y.(int8) 598 | } 599 | case int16: 600 | return func(x, y Ivalue) Ivalue { 601 | return x.(int16) % y.(int16) 602 | } 603 | case int32: 604 | return func(x, y Ivalue) Ivalue { 605 | return x.(int32) % y.(int32) 606 | } 607 | case int64: 608 | return func(x, y Ivalue) Ivalue { 609 | return x.(int64) % y.(int64) 610 | } 611 | case uint: 612 | return func(x, y Ivalue) Ivalue { 613 | return x.(uint) % y.(uint) 614 | } 615 | case uint8: 616 | return func(x, y Ivalue) Ivalue { 617 | return x.(uint8) % y.(uint8) 618 | } 619 | case uint16: 620 | return func(x, y Ivalue) Ivalue { 621 | return x.(uint16) % y.(uint16) 622 | } 623 | case uint32: 624 | return func(x, y Ivalue) Ivalue { 625 | return x.(uint32) % y.(uint32) 626 | } 627 | case uint64: 628 | return func(x, y Ivalue) Ivalue { 629 | return x.(uint64) % y.(uint64) 630 | } 631 | case uintptr: 632 | return func(x, y Ivalue) Ivalue { 633 | return x.(uintptr) % y.(uintptr) 634 | } 635 | } 636 | 637 | case token.AND: 638 | switch t.(type) { 639 | case int: 640 | return func(x, y Ivalue) Ivalue { 641 | return x.(int) & y.(int) 642 | } 643 | case int8: 644 | return func(x, y Ivalue) Ivalue { 645 | return x.(int8) & y.(int8) 646 | } 647 | case int16: 648 | return func(x, y Ivalue) Ivalue { 649 | return x.(int16) & y.(int16) 650 | } 651 | case int32: 652 | return func(x, y Ivalue) Ivalue { 653 | return x.(int32) & y.(int32) 654 | } 655 | case int64: 656 | return func(x, y Ivalue) Ivalue { 657 | return x.(int64) & y.(int64) 658 | } 659 | case uint: 660 | return func(x, y Ivalue) Ivalue { 661 | return x.(uint) & y.(uint) 662 | } 663 | case uint8: 664 | return func(x, y Ivalue) Ivalue { 665 | return x.(uint8) & y.(uint8) 666 | } 667 | case uint16: 668 | return func(x, y Ivalue) Ivalue { 669 | return x.(uint16) & y.(uint16) 670 | } 671 | case uint32: 672 | return func(x, y Ivalue) Ivalue { 673 | return x.(uint32) & y.(uint32) 674 | } 675 | case uint64: 676 | return func(x, y Ivalue) Ivalue { 677 | return x.(uint64) & y.(uint64) 678 | } 679 | case uintptr: 680 | return func(x, y Ivalue) Ivalue { 681 | return x.(uintptr) & y.(uintptr) 682 | } 683 | } 684 | 685 | case token.OR: 686 | switch t.(type) { 687 | case int: 688 | return func(x, y Ivalue) Ivalue { 689 | return x.(int) | y.(int) 690 | } 691 | case int8: 692 | return func(x, y Ivalue) Ivalue { 693 | return x.(int8) | y.(int8) 694 | } 695 | case int16: 696 | return func(x, y Ivalue) Ivalue { 697 | return x.(int16) | y.(int16) 698 | } 699 | case int32: 700 | return func(x, y Ivalue) Ivalue { 701 | return x.(int32) | y.(int32) 702 | } 703 | case int64: 704 | return func(x, y Ivalue) Ivalue { 705 | return x.(int64) | y.(int64) 706 | } 707 | case uint: 708 | return func(x, y Ivalue) Ivalue { 709 | return x.(uint) | y.(uint) 710 | } 711 | case uint8: 712 | return func(x, y Ivalue) Ivalue { 713 | return x.(uint8) | y.(uint8) 714 | } 715 | case uint16: 716 | return func(x, y Ivalue) Ivalue { 717 | return x.(uint16) | y.(uint16) 718 | } 719 | case uint32: 720 | return func(x, y Ivalue) Ivalue { 721 | return x.(uint32) | y.(uint32) 722 | } 723 | case uint64: 724 | return func(x, y Ivalue) Ivalue { 725 | return x.(uint64) | y.(uint64) 726 | } 727 | case uintptr: 728 | return func(x, y Ivalue) Ivalue { 729 | return x.(uintptr) | y.(uintptr) 730 | } 731 | } 732 | 733 | case token.XOR: 734 | switch t.(type) { 735 | case int: 736 | return func(x, y Ivalue) Ivalue { 737 | return x.(int) ^ y.(int) 738 | } 739 | case int8: 740 | return func(x, y Ivalue) Ivalue { 741 | return x.(int8) ^ y.(int8) 742 | } 743 | case int16: 744 | return func(x, y Ivalue) Ivalue { 745 | return x.(int16) ^ y.(int16) 746 | } 747 | case int32: 748 | return func(x, y Ivalue) Ivalue { 749 | return x.(int32) ^ y.(int32) 750 | } 751 | case int64: 752 | return func(x, y Ivalue) Ivalue { 753 | return x.(int64) ^ y.(int64) 754 | } 755 | case uint: 756 | return func(x, y Ivalue) Ivalue { 757 | return x.(uint) ^ y.(uint) 758 | } 759 | case uint8: 760 | return func(x, y Ivalue) Ivalue { 761 | return x.(uint8) ^ y.(uint8) 762 | } 763 | case uint16: 764 | return func(x, y Ivalue) Ivalue { 765 | return x.(uint16) ^ y.(uint16) 766 | } 767 | case uint32: 768 | return func(x, y Ivalue) Ivalue { 769 | return x.(uint32) ^ y.(uint32) 770 | } 771 | case uint64: 772 | return func(x, y Ivalue) Ivalue { 773 | return x.(uint64) ^ y.(uint64) 774 | } 775 | case uintptr: 776 | return func(x, y Ivalue) Ivalue { 777 | return x.(uintptr) ^ y.(uintptr) 778 | } 779 | } 780 | 781 | case token.AND_NOT: 782 | switch t.(type) { 783 | case int: 784 | return func(x, y Ivalue) Ivalue { 785 | return x.(int) &^ y.(int) 786 | } 787 | case int8: 788 | return func(x, y Ivalue) Ivalue { 789 | return x.(int8) &^ y.(int8) 790 | } 791 | case int16: 792 | return func(x, y Ivalue) Ivalue { 793 | return x.(int16) &^ y.(int16) 794 | } 795 | case int32: 796 | return func(x, y Ivalue) Ivalue { 797 | return x.(int32) &^ y.(int32) 798 | } 799 | case int64: 800 | return func(x, y Ivalue) Ivalue { 801 | return x.(int64) &^ y.(int64) 802 | } 803 | case uint: 804 | return func(x, y Ivalue) Ivalue { 805 | return x.(uint) &^ y.(uint) 806 | } 807 | case uint8: 808 | return func(x, y Ivalue) Ivalue { 809 | return x.(uint8) &^ y.(uint8) 810 | } 811 | case uint16: 812 | return func(x, y Ivalue) Ivalue { 813 | return x.(uint16) &^ y.(uint16) 814 | } 815 | case uint32: 816 | return func(x, y Ivalue) Ivalue { 817 | return x.(uint32) &^ y.(uint32) 818 | } 819 | case uint64: 820 | return func(x, y Ivalue) Ivalue { 821 | return x.(uint64) &^ y.(uint64) 822 | } 823 | case uintptr: 824 | return func(x, y Ivalue) Ivalue { 825 | return x.(uintptr) &^ y.(uintptr) 826 | } 827 | } 828 | 829 | case token.SHL: 830 | // TODO pre-process asUint64 831 | switch t.(type) { 832 | case int: 833 | return func(x, y Ivalue) Ivalue { 834 | return x.(int) << asUint64(y) 835 | } 836 | case int8: 837 | return func(x, y Ivalue) Ivalue { 838 | return x.(int8) << asUint64(y) 839 | } 840 | case int16: 841 | return func(x, y Ivalue) Ivalue { 842 | return x.(int16) << asUint64(y) 843 | } 844 | case int32: 845 | return func(x, y Ivalue) Ivalue { 846 | return x.(int32) << asUint64(y) 847 | } 848 | case int64: 849 | return func(x, y Ivalue) Ivalue { 850 | return x.(int64) << asUint64(y) 851 | } 852 | case uint: 853 | return func(x, y Ivalue) Ivalue { 854 | return x.(uint) << asUint64(y) 855 | } 856 | case uint8: 857 | return func(x, y Ivalue) Ivalue { 858 | return x.(uint8) << asUint64(y) 859 | } 860 | case uint16: 861 | return func(x, y Ivalue) Ivalue { 862 | return x.(uint16) << asUint64(y) 863 | } 864 | case uint32: 865 | return func(x, y Ivalue) Ivalue { 866 | return x.(uint32) << asUint64(y) 867 | } 868 | case uint64: 869 | return func(x, y Ivalue) Ivalue { 870 | return x.(uint64) << asUint64(y) 871 | } 872 | case uintptr: 873 | return func(x, y Ivalue) Ivalue { 874 | return x.(uintptr) << asUint64(y) 875 | } 876 | } 877 | 878 | case token.SHR: 879 | // TODO pre-process asUint64 880 | switch t.(type) { 881 | case int: 882 | return func(x, y Ivalue) Ivalue { 883 | return x.(int) >> asUint64(y) 884 | } 885 | case int8: 886 | return func(x, y Ivalue) Ivalue { 887 | return x.(int8) >> asUint64(y) 888 | } 889 | case int16: 890 | return func(x, y Ivalue) Ivalue { 891 | return x.(int16) >> asUint64(y) 892 | } 893 | case int32: 894 | return func(x, y Ivalue) Ivalue { 895 | return x.(int32) >> asUint64(y) 896 | } 897 | case int64: 898 | return func(x, y Ivalue) Ivalue { 899 | return x.(int64) >> asUint64(y) 900 | } 901 | case uint: 902 | return func(x, y Ivalue) Ivalue { 903 | return x.(uint) >> asUint64(y) 904 | } 905 | case uint8: 906 | return func(x, y Ivalue) Ivalue { 907 | return x.(uint8) >> asUint64(y) 908 | } 909 | case uint16: 910 | return func(x, y Ivalue) Ivalue { 911 | return x.(uint16) >> asUint64(y) 912 | } 913 | case uint32: 914 | return func(x, y Ivalue) Ivalue { 915 | return x.(uint32) >> asUint64(y) 916 | } 917 | case uint64: 918 | return func(x, y Ivalue) Ivalue { 919 | return x.(uint64) >> asUint64(y) 920 | } 921 | case uintptr: 922 | return func(x, y Ivalue) Ivalue { 923 | return x.(uintptr) >> asUint64(y) 924 | } 925 | } 926 | 927 | case token.LSS: 928 | switch t.(type) { 929 | case int: 930 | return func(x, y Ivalue) Ivalue { 931 | return x.(int) < y.(int) 932 | } 933 | case int8: 934 | return func(x, y Ivalue) Ivalue { 935 | return x.(int8) < y.(int8) 936 | } 937 | case int16: 938 | return func(x, y Ivalue) Ivalue { 939 | return x.(int16) < y.(int16) 940 | } 941 | case int32: 942 | return func(x, y Ivalue) Ivalue { 943 | return x.(int32) < y.(int32) 944 | } 945 | case int64: 946 | return func(x, y Ivalue) Ivalue { 947 | return x.(int64) < y.(int64) 948 | } 949 | case uint: 950 | return func(x, y Ivalue) Ivalue { 951 | return x.(uint) < y.(uint) 952 | } 953 | case uint8: 954 | return func(x, y Ivalue) Ivalue { 955 | return x.(uint8) < y.(uint8) 956 | } 957 | case uint16: 958 | return func(x, y Ivalue) Ivalue { 959 | return x.(uint16) < y.(uint16) 960 | } 961 | case uint32: 962 | return func(x, y Ivalue) Ivalue { 963 | return x.(uint32) < y.(uint32) 964 | } 965 | case uint64: 966 | return func(x, y Ivalue) Ivalue { 967 | return x.(uint64) < y.(uint64) 968 | } 969 | case uintptr: 970 | return func(x, y Ivalue) Ivalue { 971 | return x.(uintptr) < y.(uintptr) 972 | } 973 | case float32: 974 | return func(x, y Ivalue) Ivalue { 975 | return x.(float32) < y.(float32) 976 | } 977 | case float64: 978 | return func(x, y Ivalue) Ivalue { 979 | return x.(float64) < y.(float64) 980 | } 981 | case string: 982 | return func(x, y Ivalue) Ivalue { 983 | return x.(string) < y.(string) 984 | } 985 | } 986 | 987 | case token.LEQ: 988 | switch t.(type) { 989 | case int: 990 | return func(x, y Ivalue) Ivalue { 991 | return x.(int) <= y.(int) 992 | } 993 | case int8: 994 | return func(x, y Ivalue) Ivalue { 995 | return x.(int8) <= y.(int8) 996 | } 997 | case int16: 998 | return func(x, y Ivalue) Ivalue { 999 | return x.(int16) <= y.(int16) 1000 | } 1001 | case int32: 1002 | return func(x, y Ivalue) Ivalue { 1003 | return x.(int32) <= y.(int32) 1004 | } 1005 | case int64: 1006 | return func(x, y Ivalue) Ivalue { 1007 | return x.(int64) <= y.(int64) 1008 | } 1009 | case uint: 1010 | return func(x, y Ivalue) Ivalue { 1011 | return x.(uint) <= y.(uint) 1012 | } 1013 | case uint8: 1014 | return func(x, y Ivalue) Ivalue { 1015 | return x.(uint8) <= y.(uint8) 1016 | } 1017 | case uint16: 1018 | return func(x, y Ivalue) Ivalue { 1019 | return x.(uint16) <= y.(uint16) 1020 | } 1021 | case uint32: 1022 | return func(x, y Ivalue) Ivalue { 1023 | return x.(uint32) <= y.(uint32) 1024 | } 1025 | case uint64: 1026 | return func(x, y Ivalue) Ivalue { 1027 | return x.(uint64) <= y.(uint64) 1028 | } 1029 | case uintptr: 1030 | return func(x, y Ivalue) Ivalue { 1031 | return x.(uintptr) <= y.(uintptr) 1032 | } 1033 | case float32: 1034 | return func(x, y Ivalue) Ivalue { 1035 | return x.(float32) <= y.(float32) 1036 | } 1037 | case float64: 1038 | return func(x, y Ivalue) Ivalue { 1039 | return x.(float64) <= y.(float64) 1040 | } 1041 | case string: 1042 | return func(x, y Ivalue) Ivalue { 1043 | return x.(string) <= y.(string) 1044 | } 1045 | } 1046 | 1047 | case token.EQL: 1048 | // TODO pre-process simple cases 1049 | return func(x, y Ivalue) Ivalue { 1050 | return eqnil(tt, x, y) 1051 | } 1052 | 1053 | case token.NEQ: 1054 | // TODO pre-process simple cases 1055 | return func(x, y Ivalue) Ivalue { 1056 | return !eqnil(tt, x, y) 1057 | } 1058 | case token.GTR: 1059 | switch t.(type) { 1060 | case int: 1061 | return func(x, y Ivalue) Ivalue { 1062 | return x.(int) > y.(int) 1063 | } 1064 | case int8: 1065 | return func(x, y Ivalue) Ivalue { 1066 | return x.(int8) > y.(int8) 1067 | } 1068 | case int16: 1069 | return func(x, y Ivalue) Ivalue { 1070 | return x.(int16) > y.(int16) 1071 | } 1072 | case int32: 1073 | return func(x, y Ivalue) Ivalue { 1074 | return x.(int32) > y.(int32) 1075 | } 1076 | case int64: 1077 | return func(x, y Ivalue) Ivalue { 1078 | return x.(int64) > y.(int64) 1079 | } 1080 | case uint: 1081 | return func(x, y Ivalue) Ivalue { 1082 | return x.(uint) > y.(uint) 1083 | } 1084 | case uint8: 1085 | return func(x, y Ivalue) Ivalue { 1086 | return x.(uint8) > y.(uint8) 1087 | } 1088 | case uint16: 1089 | return func(x, y Ivalue) Ivalue { 1090 | return x.(uint16) > y.(uint16) 1091 | } 1092 | case uint32: 1093 | return func(x, y Ivalue) Ivalue { 1094 | return x.(uint32) > y.(uint32) 1095 | } 1096 | case uint64: 1097 | return func(x, y Ivalue) Ivalue { 1098 | return x.(uint64) > y.(uint64) 1099 | } 1100 | case uintptr: 1101 | return func(x, y Ivalue) Ivalue { 1102 | return x.(uintptr) > y.(uintptr) 1103 | } 1104 | case float32: 1105 | return func(x, y Ivalue) Ivalue { 1106 | return x.(float32) > y.(float32) 1107 | } 1108 | case float64: 1109 | return func(x, y Ivalue) Ivalue { 1110 | return x.(float64) > y.(float64) 1111 | } 1112 | case string: 1113 | return func(x, y Ivalue) Ivalue { 1114 | return x.(string) > y.(string) 1115 | } 1116 | } 1117 | 1118 | case token.GEQ: 1119 | switch t.(type) { 1120 | case int: 1121 | return func(x, y Ivalue) Ivalue { 1122 | return x.(int) >= y.(int) 1123 | } 1124 | case int8: 1125 | return func(x, y Ivalue) Ivalue { 1126 | return x.(int8) >= y.(int8) 1127 | } 1128 | case int16: 1129 | return func(x, y Ivalue) Ivalue { 1130 | return x.(int16) >= y.(int16) 1131 | } 1132 | case int32: 1133 | return func(x, y Ivalue) Ivalue { 1134 | return x.(int32) >= y.(int32) 1135 | } 1136 | case int64: 1137 | return func(x, y Ivalue) Ivalue { 1138 | return x.(int64) >= y.(int64) 1139 | } 1140 | case uint: 1141 | return func(x, y Ivalue) Ivalue { 1142 | return x.(uint) >= y.(uint) 1143 | } 1144 | case uint8: 1145 | return func(x, y Ivalue) Ivalue { 1146 | return x.(uint8) >= y.(uint8) 1147 | } 1148 | case uint16: 1149 | return func(x, y Ivalue) Ivalue { 1150 | return x.(uint16) >= y.(uint16) 1151 | } 1152 | case uint32: 1153 | return func(x, y Ivalue) Ivalue { 1154 | return x.(uint32) >= y.(uint32) 1155 | } 1156 | case uint64: 1157 | return func(x, y Ivalue) Ivalue { 1158 | return x.(uint64) >= y.(uint64) 1159 | } 1160 | case uintptr: 1161 | return func(x, y Ivalue) Ivalue { 1162 | return x.(uintptr) >= y.(uintptr) 1163 | } 1164 | case float32: 1165 | return func(x, y Ivalue) Ivalue { 1166 | return x.(float32) >= y.(float32) 1167 | } 1168 | case float64: 1169 | return func(x, y Ivalue) Ivalue { 1170 | return x.(float64) >= y.(float64) 1171 | } 1172 | case string: 1173 | return func(x, y Ivalue) Ivalue { 1174 | return x.(string) >= y.(string) 1175 | } 1176 | } 1177 | } 1178 | panic(fmt.Sprintf("invalid binary op: %T %s ", t, op)) 1179 | } 1180 | --------------------------------------------------------------------------------