diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go index 8b33f25c..d31d2b33 100644 --- a/go/ssa/interp/external.go +++ b/go/ssa/interp/external.go @@ -16,7 +16,6 @@ import ( "runtime" "strings" "sync/atomic" - "syscall" "time" "unsafe" @@ -30,11 +29,11 @@ type externalFn func(fr *frame, args []value) value // We have not captured that correctly here. // Key strings are from Function.String(). -var externals map[string]externalFn +var externals = make(map[string]externalFn) func init() { // That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd]. - externals = map[string]externalFn{ + for k, v := range map[string]externalFn{ "(*sync.Pool).Get": ext۰sync۰Pool۰Get, "(*sync.Pool).Put": ext۰nop, "(reflect.Value).Bool": ext۰reflect۰Value۰Bool, @@ -86,9 +85,9 @@ func init() { "math.Log": ext۰math۰Log, "math.Min": ext۰math۰Min, "math.hasSSE4": ext۰math۰hasSSE4, - "os.Pipe": ext۰os۰Pipe, "os.runtime_args": ext۰os۰runtime_args, "os.runtime_beforeExit": ext۰nop, + "os/signal.init": ext۰nop, "reflect.New": ext۰reflect۰New, "reflect.SliceOf": ext۰reflect۰SliceOf, "reflect.TypeOf": ext۰reflect۰TypeOf, @@ -130,25 +129,11 @@ func init() { "sync/atomic.LoadUint32": ext۰atomic۰LoadUint32, "sync/atomic.StoreInt32": ext۰atomic۰StoreInt32, "sync/atomic.StoreUint32": ext۰atomic۰StoreUint32, - "syscall.Close": ext۰syscall۰Close, - "syscall.Exit": ext۰syscall۰Exit, - "syscall.Fstat": ext۰syscall۰Fstat, - "syscall.Getpid": ext۰syscall۰Getpid, - "syscall.Getwd": ext۰syscall۰Getwd, - "syscall.Kill": ext۰syscall۰Kill, - "syscall.Lstat": ext۰syscall۰Lstat, - "syscall.Open": ext۰syscall۰Open, - "syscall.ParseDirent": ext۰syscall۰ParseDirent, - "syscall.RawSyscall": ext۰syscall۰RawSyscall, - "syscall.Read": ext۰syscall۰Read, - "syscall.ReadDirent": ext۰syscall۰ReadDirent, - "syscall.Readlink": ext۰syscall۰Readlink, - "syscall.Stat": ext۰syscall۰Stat, - "syscall.Write": ext۰syscall۰Write, - "syscall.runtime_envs": ext۰runtime۰environ, "testing.runExample": ext۰testing۰runExample, "time.Sleep": ext۰time۰Sleep, "time.now": ext۰time۰now, + } { + externals[k] = v } } @@ -473,26 +458,6 @@ func ext۰time۰Sleep(fr *frame, args []value) value { return nil } -func ext۰syscall۰Exit(fr *frame, args []value) value { - panic(exitPanic(args[0].(int))) -} - -func ext۰syscall۰Getwd(fr *frame, args []value) value { - s, err := syscall.Getwd() - return tuple{s, wrapError(err)} -} - -func ext۰syscall۰Getpid(fr *frame, args []value) value { - return syscall.Getpid() -} - -func ext۰syscall۰Readlink(fr *frame, args []value) value { - path := args[0].(string) - buf := valueToBytes(args[1]) - n, err := syscall.Readlink(path, buf) - return tuple{n, wrapError(err)} -} - func valueToBytes(v value) []byte { in := v.([]value) b := make([]byte, len(in)) diff --git a/go/ssa/interp/external_darwin.go b/go/ssa/interp/external_darwin.go index 4974ad60..47130093 100644 --- a/go/ssa/interp/external_darwin.go +++ b/go/ssa/interp/external_darwin.go @@ -10,6 +10,23 @@ import "syscall" func init() { externals["syscall.Sysctl"] = ext۰syscall۰Sysctl + + fillStat = func(st *syscall.Stat_t, stat structure) { + stat[0] = st.Dev + stat[1] = st.Mode + stat[2] = st.Nlink + stat[3] = st.Ino + stat[4] = st.Uid + stat[5] = st.Gid + stat[6] = st.Rdev + // TODO(adonovan): fix: copy Timespecs. + // stat[8] = st.Atim + // stat[9] = st.Mtim + // stat[10] = st.Ctim + stat[12] = st.Size + stat[13] = st.Blocks + stat[14] = st.Blksize + } } func ext۰syscall۰Sysctl(fr *frame, args []value) value { diff --git a/go/ssa/interp/external_freebsd.go b/go/ssa/interp/external_freebsd.go deleted file mode 100644 index 52033038..00000000 --- a/go/ssa/interp/external_freebsd.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd - -package interp - -import "syscall" - -func init() { - externals["syscall.Sysctl"] = ext۰syscall۰Sysctl - externals["syscall.SysctlUint32"] = ext۰syscall۰SysctlUint32 -} - -func ext۰syscall۰Sysctl(fr *frame, args []value) value { - r, err := syscall.Sysctl(args[0].(string)) - return tuple{r, wrapError(err)} -} - -func ext۰syscall۰SysctlUint32(fr *frame, args []value) value { - r, err := syscall.SysctlUint32(args[0].(string)) - return tuple{r, wrapError(err)} -} diff --git a/go/ssa/interp/external_plan9.go b/go/ssa/interp/external_plan9.go deleted file mode 100644 index 81bedcf0..00000000 --- a/go/ssa/interp/external_plan9.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package interp - -import "syscall" - -func ext۰os۰Pipe(fr *frame, args []value) value { - panic("os.Pipe not yet implemented") -} -func ext۰syscall۰Close(fr *frame, args []value) value { - panic("syscall.Close not yet implemented") -} -func ext۰syscall۰Fstat(fr *frame, args []value) value { - panic("syscall.Fstat not yet implemented") -} -func ext۰syscall۰Kill(fr *frame, args []value) value { - panic("syscall.Kill not yet implemented") -} -func ext۰syscall۰Lstat(fr *frame, args []value) value { - panic("syscall.Lstat not yet implemented") -} -func ext۰syscall۰Open(fr *frame, args []value) value { - panic("syscall.Open not yet implemented") -} -func ext۰syscall۰ParseDirent(fr *frame, args []value) value { - panic("syscall.ParseDirent not yet implemented") -} -func ext۰syscall۰Read(fr *frame, args []value) value { - panic("syscall.Read not yet implemented") -} -func ext۰syscall۰ReadDirent(fr *frame, args []value) value { - panic("syscall.ReadDirent not yet implemented") -} -func ext۰syscall۰Stat(fr *frame, args []value) value { - panic("syscall.Stat not yet implemented") -} -func ext۰syscall۰Write(fr *frame, args []value) value { - // func Write(fd int, p []byte) (n int, err error) - n, err := write(args[0].(int), valueToBytes(args[1])) - return tuple{n, wrapError(err)} -} -func ext۰syscall۰RawSyscall(fr *frame, args []value) value { - return tuple{^uintptr(0), uintptr(0), uintptr(0)} -} - -func syswrite(fd int, b []byte) (int, error) { - return syscall.Write(fd, b) -} diff --git a/go/ssa/interp/external_unix.go b/go/ssa/interp/external_unix.go index be125866..bfa39f68 100644 --- a/go/ssa/interp/external_unix.go +++ b/go/ssa/interp/external_unix.go @@ -2,12 +2,49 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!plan9 +// +build darwin linux package interp import "syscall" +func init() { + for k, v := range map[string]externalFn{ + "os.Pipe": ext۰os۰Pipe, + "syscall.Close": ext۰syscall۰Close, + "syscall.Exit": ext۰syscall۰Exit, + "syscall.Fchown": ext۰syscall۰Fchown, + "syscall.Fstat": ext۰syscall۰Fstat, + "syscall.Ftruncate": ext۰syscall۰Ftruncate, + "syscall.Getpid": ext۰syscall۰Getpid, + "syscall.Getwd": ext۰syscall۰Getwd, + "syscall.Kill": ext۰syscall۰Kill, + "syscall.Link": ext۰syscall۰Link, + "syscall.Lstat": ext۰syscall۰Lstat, + "syscall.Mkdir": ext۰syscall۰Mkdir, + "syscall.Open": ext۰syscall۰Open, + "syscall.ParseDirent": ext۰syscall۰ParseDirent, + "syscall.RawSyscall": ext۰syscall۰RawSyscall, + "syscall.Read": ext۰syscall۰Read, + "syscall.ReadDirent": ext۰syscall۰ReadDirent, + "syscall.Readlink": ext۰syscall۰Readlink, + "syscall.Rmdir": ext۰syscall۰Rmdir, + "syscall.Seek": ext۰syscall۰Seek, + "syscall.Stat": ext۰syscall۰Stat, + "syscall.Symlink": ext۰syscall۰Symlink, + "syscall.Write": ext۰syscall۰Write, + "syscall.Unlink": ext۰syscall۰Unlink, + "syscall۰UtimesNano": ext۰syscall۰UtimesNano, + "syscall.setenv_c": ext۰nop, + "syscall.unsetenv_c": ext۰nop, + "syscall.runtime_envs": ext۰runtime۰environ, + } { + externals[k] = v + } + + syswrite = syscall.Write +} + func ext۰os۰Pipe(fr *frame, args []value) value { // func os.Pipe() (r *File, w *File, err error) @@ -24,14 +61,14 @@ func ext۰os۰Pipe(fr *frame, args []value) value { return tuple{r, w, wrapError(nil)} } -func fillStat(st *syscall.Stat_t, stat structure) { +// overridden on darwin +var fillStat = func(st *syscall.Stat_t, stat structure) { stat[0] = st.Dev stat[1] = st.Ino stat[2] = st.Nlink stat[3] = st.Mode stat[4] = st.Uid stat[5] = st.Gid - stat[7] = st.Rdev stat[8] = st.Size stat[9] = st.Blksize @@ -47,6 +84,17 @@ func ext۰syscall۰Close(fr *frame, args []value) value { return wrapError(syscall.Close(args[0].(int))) } +func ext۰syscall۰Exit(fr *frame, args []value) value { + panic(exitPanic(args[0].(int))) +} + +func ext۰syscall۰Fchown(fr *frame, args []value) value { + fd := args[0].(int) + uid := args[1].(int) + gid := args[2].(int) + return wrapError(syscall.Fchown(fd, uid, gid)) +} + func ext۰syscall۰Fstat(fr *frame, args []value) value { // func Fstat(fd int, stat *Stat_t) (err error) fd := args[0].(int) @@ -58,16 +106,19 @@ func ext۰syscall۰Fstat(fr *frame, args []value) value { return wrapError(err) } -func ext۰syscall۰ReadDirent(fr *frame, args []value) value { - // func ReadDirent(fd int, buf []byte) (n int, err error) +func ext۰syscall۰Ftruncate(fr *frame, args []value) value { fd := args[0].(int) - p := args[1].([]value) - b := make([]byte, len(p)) - n, err := syscall.ReadDirent(fd, b) - for i := 0; i < n; i++ { - p[i] = b[i] - } - return tuple{n, wrapError(err)} + length := args[1].(int64) + return wrapError(syscall.Ftruncate(fd, length)) +} + +func ext۰syscall۰Getpid(fr *frame, args []value) value { + return syscall.Getpid() +} + +func ext۰syscall۰Getwd(fr *frame, args []value) value { + s, err := syscall.Getwd() + return tuple{s, wrapError(err)} } func ext۰syscall۰Kill(fr *frame, args []value) value { @@ -75,6 +126,12 @@ func ext۰syscall۰Kill(fr *frame, args []value) value { return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int)))) } +func ext۰syscall۰Link(fr *frame, args []value) value { + path := args[0].(string) + link := args[1].(string) + return wrapError(syscall.Link(path, link)) +} + func ext۰syscall۰Lstat(fr *frame, args []value) value { // func Lstat(name string, stat *Stat_t) (err error) name := args[0].(string) @@ -86,6 +143,12 @@ func ext۰syscall۰Lstat(fr *frame, args []value) value { return wrapError(err) } +func ext۰syscall۰Mkdir(fr *frame, args []value) value { + path := args[0].(string) + mode := args[1].(uint32) + return wrapError(syscall.Mkdir(path, mode)) +} + func ext۰syscall۰Open(fr *frame, args []value) value { // func Open(path string, mode int, perm uint32) (fd int, err error) { path := args[0].(string) @@ -110,6 +173,10 @@ func ext۰syscall۰ParseDirent(fr *frame, args []value) value { return tuple{consumed, count, inewnames} } +func ext۰syscall۰RawSyscall(fr *frame, args []value) value { + return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)} +} + func ext۰syscall۰Read(fr *frame, args []value) value { // func Read(fd int, p []byte) (n int, err error) fd := args[0].(int) @@ -122,6 +189,37 @@ func ext۰syscall۰Read(fr *frame, args []value) value { return tuple{n, wrapError(err)} } +func ext۰syscall۰ReadDirent(fr *frame, args []value) value { + // func ReadDirent(fd int, buf []byte) (n int, err error) + fd := args[0].(int) + p := args[1].([]value) + b := make([]byte, len(p)) + n, err := syscall.ReadDirent(fd, b) + for i := 0; i < n; i++ { + p[i] = b[i] + } + return tuple{n, wrapError(err)} +} + +func ext۰syscall۰Readlink(fr *frame, args []value) value { + path := args[0].(string) + buf := valueToBytes(args[1]) + n, err := syscall.Readlink(path, buf) + return tuple{n, wrapError(err)} +} + +func ext۰syscall۰Rmdir(fr *frame, args []value) value { + return wrapError(syscall.Rmdir(args[0].(string))) +} + +func ext۰syscall۰Seek(fr *frame, args []value) value { + fd := args[0].(int) + offset := args[1].(int64) + whence := args[2].(int) + new, err := syscall.Seek(fd, offset, whence) + return tuple{new, wrapError(err)} +} + func ext۰syscall۰Stat(fr *frame, args []value) value { // func Stat(name string, stat *Stat_t) (err error) name := args[0].(string) @@ -133,16 +231,26 @@ func ext۰syscall۰Stat(fr *frame, args []value) value { return wrapError(err) } +func ext۰syscall۰Symlink(fr *frame, args []value) value { + path := args[0].(string) + link := args[1].(string) + return wrapError(syscall.Symlink(path, link)) +} + +func ext۰syscall۰Unlink(fr *frame, args []value) value { + return wrapError(syscall.Unlink(args[0].(string))) +} + +func ext۰syscall۰UtimesNano(fr *frame, args []value) value { + path := args[0].(string) + var ts [2]syscall.Timespec + err := syscall.UtimesNano(path, ts[:]) + // TODO(adonovan): copy the Timespecs into args[1] + return wrapError(err) +} + func ext۰syscall۰Write(fr *frame, args []value) value { // func Write(fd int, p []byte) (n int, err error) n, err := write(args[0].(int), valueToBytes(args[1])) return tuple{n, wrapError(err)} } - -func ext۰syscall۰RawSyscall(fr *frame, args []value) value { - return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)} -} - -func syswrite(fd int, b []byte) (int, error) { - return syscall.Write(fd, b) -} diff --git a/go/ssa/interp/external_windows.go b/go/ssa/interp/external_windows.go deleted file mode 100644 index 24d1a876..00000000 --- a/go/ssa/interp/external_windows.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package interp - -import "syscall" - -func ext۰os۰Pipe(fr *frame, args []value) value { - panic("os.Pipe not yet implemented") -} -func ext۰syscall۰Close(fr *frame, args []value) value { - panic("syscall.Close not yet implemented") -} -func ext۰syscall۰Fstat(fr *frame, args []value) value { - panic("syscall.Fstat not yet implemented") -} -func ext۰syscall۰Kill(fr *frame, args []value) value { - panic("syscall.Kill not yet implemented") -} -func ext۰syscall۰Lstat(fr *frame, args []value) value { - panic("syscall.Lstat not yet implemented") -} -func ext۰syscall۰Open(fr *frame, args []value) value { - panic("syscall.Open not yet implemented") -} -func ext۰syscall۰ParseDirent(fr *frame, args []value) value { - panic("syscall.ParseDirent not yet implemented") -} -func ext۰syscall۰Read(fr *frame, args []value) value { - panic("syscall.Read not yet implemented") -} -func ext۰syscall۰ReadDirent(fr *frame, args []value) value { - panic("syscall.ReadDirent not yet implemented") -} -func ext۰syscall۰Stat(fr *frame, args []value) value { - panic("syscall.Stat not yet implemented") -} -func ext۰syscall۰Write(fr *frame, args []value) value { - panic("syscall.Write not yet implemented") -} -func ext۰syscall۰RawSyscall(fr *frame, args []value) value { - return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)} -} -func syswrite(fd int, b []byte) (int, error) { - panic("syswrite not yet implemented") -} diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go index 730d0f55..bc1bd1b1 100644 --- a/go/ssa/interp/interp.go +++ b/go/ssa/interp/interp.go @@ -604,6 +604,8 @@ func doRecover(caller *frame) value { caller.caller.panicking = false p := caller.caller.panic caller.caller.panic = nil + + // TODO(adonovan): support runtime.Goexit. switch p := p.(type) { case targetPanic: // The target program explicitly called panic(). @@ -665,6 +667,11 @@ func deleteBodies(pkg *ssa.Package, except ...string) { // The SSA program must include the "runtime" package. // func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) { + if syswrite == nil { + fmt.Fprintln(os.Stderr, "Interpret: unsupported platform.") + return 1 + } + i := &interpreter{ prog: mainpkg.Prog, globals: make(map[ssa.Value]*value), diff --git a/go/ssa/interp/interp_test.go b/go/ssa/interp/interp_test.go index d51c2fd9..f6226661 100644 --- a/go/ssa/interp/interp_test.go +++ b/go/ssa/interp/interp_test.go @@ -4,7 +4,7 @@ // +build go1.5 -// +build !android,!windows,!plan9 +// +build linux darwin package interp_test diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go index 2de2fa86..e37ed5f1 100644 --- a/go/ssa/interp/ops.go +++ b/go/ssa/interp/ops.go @@ -933,6 +933,8 @@ func write(fd int, b []byte) (int, error) { return syswrite(fd, b) } +var syswrite func(int, []byte) (int, error) // set on darwin/linux only + // callBuiltin interprets a call to builtin fn with arguments args, // returning its result. func callBuiltin(caller *frame, callpos token.Pos, fn *ssa.Builtin, args []value) value {