go/ssa/interp: add several intrinsics for Darwin
Also: drop all pretense of support for platforms other than darwin and linux.
This package is just a test of go/ssa, not a portable interpreter, and these
are the only platforms to which I have easy access.
Builds on: freebsd darwin plan9 linux windows
Change-Id: I965abc67b1280d33e933b83607a4372d65e070cf
Reviewed-on: https://go-review.googlesource.com/33163
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go
index 8b33f25..d31d2b3 100644
--- a/go/ssa/interp/external.go
+++ b/go/ssa/interp/external.go
@@ -16,7 +16,6 @@
"runtime"
"strings"
"sync/atomic"
- "syscall"
"time"
"unsafe"
@@ -30,11 +29,11 @@
// 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 @@
"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 @@
"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 @@
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 4974ad6..4713009 100644
--- a/go/ssa/interp/external_darwin.go
+++ b/go/ssa/interp/external_darwin.go
@@ -10,6 +10,23 @@
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 5203303..0000000
--- 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 81bedcf..0000000
--- 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 be12586..bfa39f6 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 24d1a87..0000000
--- 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 730d0f5..bc1bd1b 100644
--- a/go/ssa/interp/interp.go
+++ b/go/ssa/interp/interp.go
@@ -604,6 +604,8 @@
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 @@
// 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 d51c2fd..f622666 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 2de2fa8..e37ed5f 100644
--- a/go/ssa/interp/ops.go
+++ b/go/ssa/interp/ops.go
@@ -933,6 +933,8 @@
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 {