mirror of
https://github.com/golang/go
synced 2024-09-25 09:10:14 -06:00
exp/ssa: a number of bug fixes.
ssadump: - permit naming a package (not just *.go files) on command line. - set BuildSerially flag when setting Log* flags (Q. should instead the logging functions take a lock?) Builder: - fixed bug when calling variadic function with zero '...'-params. Added regression test. interp: - more external functions: the 'error' interface bytes.{Equal,IndexByte} reflect.(Value).{Bool,NumOut,Out} syscall.{Close,Fstat,Read,Open,Stat,Lstat,Fstat, Getdents,ParseDirents,Getwd} - permit comparisons between *Function and *closure. With this CL, ssadump can now interpret ssadump itself (!), loading, parsing, typing, SSA-building, and running println("Hello, World!"). While a fmt-based equivalent still lacks some external routines, e.g. math/big, I think there are diminishing returns in expanding the interpreter (and debugging it is starting to feel like "Inception"). I'm pretty confident this package is now good enough for wider use. R=gri CC=golang-dev https://golang.org/cl/7392053
This commit is contained in:
parent
d1d38c535d
commit
1c5e079600
@ -1077,7 +1077,7 @@ func (b *Builder) setCall(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
|||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
np := len(typ.Params)
|
np := len(typ.Params)
|
||||||
if !c.HasEllipsis {
|
if !c.HasEllipsis {
|
||||||
if typ.IsVariadic && len(args) > np-1 {
|
if typ.IsVariadic {
|
||||||
// case 2: ordinary call of variadic function.
|
// case 2: ordinary call of variadic function.
|
||||||
vt = typ.Params[np-1].Type
|
vt = typ.Params[np-1].Type
|
||||||
args, varargs = args[:np-1], args[np-1:]
|
args, varargs = args[:np-1], args[np-1:]
|
||||||
@ -1216,7 +1216,7 @@ func (b *Builder) setCall(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Common code for varargs.
|
// Common code for varargs.
|
||||||
if len(varargs) > 0 { // case 2
|
if vt != nil { // case 2
|
||||||
at := &types.Array{
|
at := &types.Array{
|
||||||
Elt: vt,
|
Elt: vt,
|
||||||
Len: int64(len(varargs)),
|
Len: int64(len(varargs)),
|
||||||
|
@ -21,6 +21,7 @@ type externalFn func(fn *ssa.Function, args []value) value
|
|||||||
// Key strings are from Function.FullName().
|
// Key strings are from Function.FullName().
|
||||||
// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
|
// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
|
||||||
var externals = map[string]externalFn{
|
var externals = map[string]externalFn{
|
||||||
|
"(reflect.Value).Bool": ext۰reflect۰Value۰Bool,
|
||||||
"(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
|
"(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
|
||||||
"(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
|
"(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
|
||||||
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
|
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
|
||||||
@ -36,10 +37,15 @@ var externals = map[string]externalFn{
|
|||||||
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
|
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
|
||||||
"(reflect.Value).String": ext۰reflect۰Value۰String,
|
"(reflect.Value).String": ext۰reflect۰Value۰String,
|
||||||
"(reflect.Value).Type": ext۰reflect۰Value۰Type,
|
"(reflect.Value).Type": ext۰reflect۰Value۰Type,
|
||||||
|
"(reflect.error).Error": ext۰reflect۰error۰Error,
|
||||||
"(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
|
"(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
|
||||||
"(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
|
"(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
|
||||||
"(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
|
"(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
|
||||||
|
"(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut,
|
||||||
|
"(reflect.rtype).Out": ext۰reflect۰rtype۰Out,
|
||||||
"(reflect.rtype).String": ext۰reflect۰rtype۰String,
|
"(reflect.rtype).String": ext۰reflect۰rtype۰String,
|
||||||
|
"bytes.Equal": ext۰bytes۰Equal,
|
||||||
|
"bytes.IndexByte": ext۰bytes۰IndexByte,
|
||||||
"math.Float32bits": ext۰math۰Float32bits,
|
"math.Float32bits": ext۰math۰Float32bits,
|
||||||
"math.Float32frombits": ext۰math۰Float32frombits,
|
"math.Float32frombits": ext۰math۰Float32frombits,
|
||||||
"math.Float64bits": ext۰math۰Float64bits,
|
"math.Float64bits": ext۰math۰Float64bits,
|
||||||
@ -61,14 +67,58 @@ var externals = map[string]externalFn{
|
|||||||
"sync/atomic.LoadUint32": ext۰atomic۰LoadUint32,
|
"sync/atomic.LoadUint32": ext۰atomic۰LoadUint32,
|
||||||
"sync/atomic.StoreInt32": ext۰atomic۰StoreInt32,
|
"sync/atomic.StoreInt32": ext۰atomic۰StoreInt32,
|
||||||
"sync/atomic.StoreUint32": ext۰atomic۰StoreUint32,
|
"sync/atomic.StoreUint32": ext۰atomic۰StoreUint32,
|
||||||
|
"syscall.Close": ext۰syscall۰Close,
|
||||||
"syscall.Exit": ext۰syscall۰Exit,
|
"syscall.Exit": ext۰syscall۰Exit,
|
||||||
|
"syscall.Fstat": ext۰syscall۰Fstat,
|
||||||
|
"syscall.Getdents": ext۰syscall۰Getdents,
|
||||||
"syscall.Getpid": ext۰syscall۰Getpid,
|
"syscall.Getpid": ext۰syscall۰Getpid,
|
||||||
|
"syscall.Getwd": ext۰syscall۰Getwd,
|
||||||
"syscall.Kill": ext۰syscall۰Kill,
|
"syscall.Kill": ext۰syscall۰Kill,
|
||||||
|
"syscall.Lstat": ext۰syscall۰Lstat,
|
||||||
|
"syscall.Open": ext۰syscall۰Open,
|
||||||
|
"syscall.ParseDirent": ext۰syscall۰ParseDirent,
|
||||||
|
"syscall.Read": ext۰syscall۰Read,
|
||||||
|
"syscall.Stat": ext۰syscall۰Stat,
|
||||||
"syscall.Write": ext۰syscall۰Write,
|
"syscall.Write": ext۰syscall۰Write,
|
||||||
"time.Sleep": ext۰time۰Sleep,
|
"time.Sleep": ext۰time۰Sleep,
|
||||||
"time.now": ext۰time۰now,
|
"time.now": ext۰time۰now,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapError returns an interpreted 'error' interface value for err.
|
||||||
|
func wrapError(err error) value {
|
||||||
|
if err == nil {
|
||||||
|
return iface{}
|
||||||
|
}
|
||||||
|
return iface{t: errorType, v: err.Error()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰bytes۰Equal(fn *ssa.Function, args []value) value {
|
||||||
|
// func Equal(a, b []byte) bool
|
||||||
|
a := args[0].([]value)
|
||||||
|
b := args[1].([]value)
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰bytes۰IndexByte(fn *ssa.Function, args []value) value {
|
||||||
|
// func IndexByte(s []byte, c byte) int
|
||||||
|
s := args[0].([]value)
|
||||||
|
c := args[1].(byte)
|
||||||
|
for i, b := range s {
|
||||||
|
if b.(byte) == c {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰math۰Float64frombits(fn *ssa.Function, args []value) value {
|
func ext۰math۰Float64frombits(fn *ssa.Function, args []value) value {
|
||||||
return math.Float64frombits(args[0].(uint64))
|
return math.Float64frombits(args[0].(uint64))
|
||||||
}
|
}
|
||||||
@ -171,15 +221,17 @@ func ext۰syscall۰Exit(fn *ssa.Function, args []value) value {
|
|||||||
panic(exitPanic(args[0].(int)))
|
panic(exitPanic(args[0].(int)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Getwd(fn *ssa.Function, args []value) value {
|
||||||
|
s, err := syscall.Getwd()
|
||||||
|
return tuple{s, wrapError(err)}
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
|
||||||
// We could emulate syscall.Syscall but it's more effort.
|
|
||||||
return syscall.Getpid()
|
return syscall.Getpid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The set of remaining native functions we need to implement (as needed):
|
// The set of remaining native functions we need to implement (as needed):
|
||||||
|
|
||||||
// bytes/bytes.go:42:func Equal(a, b []byte) bool
|
|
||||||
// bytes/bytes_decl.go:8:func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
|
|
||||||
// crypto/aes/cipher_asm.go:10:func hasAsm() bool
|
// crypto/aes/cipher_asm.go:10:func hasAsm() bool
|
||||||
// crypto/aes/cipher_asm.go:11:func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
// crypto/aes/cipher_asm.go:11:func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
||||||
// crypto/aes/cipher_asm.go:12:func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
// crypto/aes/cipher_asm.go:12:func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
||||||
@ -283,10 +335,6 @@ func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
|
|||||||
// syscall/syscall_linux_amd64.go:60:func Gettimeofday(tv *Timeval) (err error)
|
// syscall/syscall_linux_amd64.go:60:func Gettimeofday(tv *Timeval) (err error)
|
||||||
// syscall/syscall_linux_amd64.go:61:func Time(t *Time_t) (tt Time_t, err error)
|
// syscall/syscall_linux_amd64.go:61:func Time(t *Time_t) (tt Time_t, err error)
|
||||||
// syscall/syscall_linux_arm.go:28:func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
|
// syscall/syscall_linux_arm.go:28:func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
|
||||||
// syscall/syscall_unix.go:23:func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
|
||||||
// syscall/syscall_unix.go:24:func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
|
||||||
// syscall/syscall_unix.go:25:func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
|
||||||
// syscall/syscall_unix.go:26:func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
|
||||||
// time/sleep.go:25:func startTimer(*runtimeTimer)
|
// time/sleep.go:25:func startTimer(*runtimeTimer)
|
||||||
// time/sleep.go:26:func stopTimer(*runtimeTimer) bool
|
// time/sleep.go:26:func stopTimer(*runtimeTimer) bool
|
||||||
// time/time.go:758:func now() (sec int64, nsec int32)
|
// time/time.go:758:func now() (sec int64, nsec int32)
|
||||||
|
@ -9,18 +9,40 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ext۰syscall۰Close(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Close not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Fstat not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Getdents not yet implemented")
|
||||||
|
}
|
||||||
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
||||||
panic("syscall.Kill not yet implemented")
|
panic("syscall.Kill not yet implemented")
|
||||||
}
|
}
|
||||||
|
func ext۰syscall۰Lstat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Lstat not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Open(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Open not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰ParseDirent(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.ParseDirent not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Read(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Read not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Stat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Stat not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
||||||
// We could emulate syscall.Syscall but it's more effort.
|
|
||||||
p := args[1].([]value)
|
p := args[1].([]value)
|
||||||
b := make([]byte, 0, len(p))
|
b := make([]byte, 0, len(p))
|
||||||
for i := range p {
|
for i := range p {
|
||||||
b = append(b, p[i].(byte))
|
b = append(b, p[i].(byte))
|
||||||
}
|
}
|
||||||
n, _ := syscall.Write(args[0].(int), b)
|
n, err := syscall.Write(args[0].(int), b)
|
||||||
err := iface{} // TODO(adonovan): fix: adapt concrete err to interpreted iface.
|
return tuple{n, wrapError(err)}
|
||||||
return tuple{n, err}
|
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,126 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func valueToBytes(v value) []byte {
|
||||||
|
in := v.([]value)
|
||||||
|
b := make([]byte, len(in))
|
||||||
|
for i := range in {
|
||||||
|
b[i] = in[i].(byte)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillStat(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
|
||||||
|
stat[10] = st.Blocks
|
||||||
|
// TODO(adonovan): fix: copy Timespecs.
|
||||||
|
// stat[11] = st.Atim
|
||||||
|
// stat[12] = st.Mtim
|
||||||
|
// stat[13] = st.Ctim
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Close(fn *ssa.Function, args []value) value {
|
||||||
|
// func Close(fd int) (err error)
|
||||||
|
return wrapError(syscall.Close(args[0].(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
|
||||||
|
// func Fstat(fd int, stat *Stat_t) (err error)
|
||||||
|
fd := args[0].(int)
|
||||||
|
stat := (*args[1].(*value)).(structure)
|
||||||
|
|
||||||
|
var st syscall.Stat_t
|
||||||
|
err := syscall.Fstat(fd, &st)
|
||||||
|
fillStat(&st, stat)
|
||||||
|
return wrapError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
|
||||||
|
// func GetDents(fd int, buf []byte) (n int, err error)
|
||||||
|
fd := args[0].(int)
|
||||||
|
p := args[1].([]value)
|
||||||
|
b := make([]byte, len(p))
|
||||||
|
n, err := syscall.Getdents(fd, b)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
p[i] = b[i]
|
||||||
|
}
|
||||||
|
return tuple{n, wrapError(err)}
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
||||||
// We could emulate syscall.Syscall but it's more effort.
|
// func Kill(pid int, sig Signal) (err error)
|
||||||
err := syscall.Kill(args[0].(int), syscall.Signal(args[1].(int)))
|
return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int))))
|
||||||
err = err // TODO(adonovan): fix: adapt concrete err to interpreted iface (e.g. call interpreted errors.New)
|
}
|
||||||
return iface{}
|
|
||||||
|
func ext۰syscall۰Lstat(fn *ssa.Function, args []value) value {
|
||||||
|
// func Lstat(name string, stat *Stat_t) (err error)
|
||||||
|
name := args[0].(string)
|
||||||
|
stat := (*args[1].(*value)).(structure)
|
||||||
|
|
||||||
|
var st syscall.Stat_t
|
||||||
|
err := syscall.Lstat(name, &st)
|
||||||
|
fillStat(&st, stat)
|
||||||
|
return wrapError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Open(fn *ssa.Function, args []value) value {
|
||||||
|
// func Open(path string, mode int, perm uint32) (fd int, err error) {
|
||||||
|
path := args[0].(string)
|
||||||
|
mode := args[1].(int)
|
||||||
|
perm := args[2].(uint32)
|
||||||
|
fd, err := syscall.Open(path, mode, perm)
|
||||||
|
return tuple{fd, wrapError(err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰ParseDirent(fn *ssa.Function, args []value) value {
|
||||||
|
// func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string)
|
||||||
|
max := args[1].(int)
|
||||||
|
var names []string
|
||||||
|
for _, iname := range args[2].([]value) {
|
||||||
|
names = append(names, iname.(string))
|
||||||
|
}
|
||||||
|
consumed, count, newnames := syscall.ParseDirent(valueToBytes(args[0]), max, names)
|
||||||
|
var inewnames []value
|
||||||
|
for _, newname := range newnames {
|
||||||
|
inewnames = append(inewnames, newname)
|
||||||
|
}
|
||||||
|
return tuple{consumed, count, inewnames}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Read(fn *ssa.Function, args []value) value {
|
||||||
|
// func Read(fd int, p []byte) (n int, err error)
|
||||||
|
fd := args[0].(int)
|
||||||
|
p := args[1].([]value)
|
||||||
|
b := make([]byte, len(p))
|
||||||
|
n, err := syscall.Read(fd, b)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
p[i] = b[i]
|
||||||
|
}
|
||||||
|
return tuple{n, wrapError(err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰syscall۰Stat(fn *ssa.Function, args []value) value {
|
||||||
|
// func Stat(name string, stat *Stat_t) (err error)
|
||||||
|
name := args[0].(string)
|
||||||
|
stat := (*args[1].(*value)).(structure)
|
||||||
|
|
||||||
|
var st syscall.Stat_t
|
||||||
|
err := syscall.Stat(name, &st)
|
||||||
|
fillStat(&st, stat)
|
||||||
|
return wrapError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
||||||
// We could emulate syscall.Syscall but it's more effort.
|
// func Write(fd int, p []byte) (n int, err error)
|
||||||
p := args[1].([]value)
|
n, err := syscall.Write(args[0].(int), valueToBytes(args[1]))
|
||||||
b := make([]byte, 0, len(p))
|
return tuple{n, wrapError(err)}
|
||||||
for i := range p {
|
|
||||||
b = append(b, p[i].(byte))
|
|
||||||
}
|
|
||||||
n, _ := syscall.Write(args[0].(int), b)
|
|
||||||
err := iface{} // TODO(adonovan): fix: adapt concrete err to interpreted iface.
|
|
||||||
return tuple{n, err}
|
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,33 @@ import (
|
|||||||
"exp/ssa"
|
"exp/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ext۰syscall۰Close(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Close not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Fstat not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Getdents not yet implemented")
|
||||||
|
}
|
||||||
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
|
||||||
panic("syscall.Kill not yet implemented")
|
panic("syscall.Kill not yet implemented")
|
||||||
}
|
}
|
||||||
|
func ext۰syscall۰Lstat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Lstat not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Open(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Open not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰ParseDirent(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.ParseDirent not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Read(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Read not yet implemented")
|
||||||
|
}
|
||||||
|
func ext۰syscall۰Stat(fn *ssa.Function, args []value) value {
|
||||||
|
panic("syscall.Stat not yet implemented")
|
||||||
|
}
|
||||||
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
func ext۰syscall۰Write(fn *ssa.Function, args []value) value {
|
||||||
panic("syscall.Write not yet implemented")
|
panic("syscall.Write not yet implemented")
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ type interpreter struct {
|
|||||||
globals map[ssa.Value]*value // addresses of global variables (immutable)
|
globals map[ssa.Value]*value // addresses of global variables (immutable)
|
||||||
mode Mode // interpreter options
|
mode Mode // interpreter options
|
||||||
reflectPackage *ssa.Package // the fake reflect package
|
reflectPackage *ssa.Package // the fake reflect package
|
||||||
|
errorMethods ssa.MethodSet // the method set of reflect.error, which implements the error interface.
|
||||||
rtypeMethods ssa.MethodSet // the method set of rtype, which implements the reflect.Type interface.
|
rtypeMethods ssa.MethodSet // the method set of rtype, which implements the reflect.Type interface.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +133,11 @@ func (fr *frame) rundefers() {
|
|||||||
// findMethodSet returns the method set for type typ, which may be one
|
// findMethodSet returns the method set for type typ, which may be one
|
||||||
// of the interpreter's fake types.
|
// of the interpreter's fake types.
|
||||||
func findMethodSet(i *interpreter, typ types.Type) ssa.MethodSet {
|
func findMethodSet(i *interpreter, typ types.Type) ssa.MethodSet {
|
||||||
if typ == rtypeType {
|
switch typ {
|
||||||
|
case rtypeType:
|
||||||
return i.rtypeMethods
|
return i.rtypeMethods
|
||||||
|
case errorType:
|
||||||
|
return i.errorMethods
|
||||||
}
|
}
|
||||||
return i.prog.MethodSet(typ)
|
return i.prog.MethodSet(typ)
|
||||||
}
|
}
|
||||||
@ -211,8 +215,9 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
|
|||||||
return kJump
|
return kJump
|
||||||
|
|
||||||
case *ssa.Defer:
|
case *ssa.Defer:
|
||||||
|
pos := instr.Pos // TODO(gri): workaround for bug in typeswitch+funclit.
|
||||||
fn, args := prepareCall(fr, &instr.CallCommon)
|
fn, args := prepareCall(fr, &instr.CallCommon)
|
||||||
fr.defers = append(fr.defers, func() { call(fr.i, fr, instr.Pos, fn, args) })
|
fr.defers = append(fr.defers, func() { call(fr.i, fr, pos, fn, args) })
|
||||||
|
|
||||||
case *ssa.Go:
|
case *ssa.Go:
|
||||||
fn, args := prepareCall(fr, &instr.CallCommon)
|
fn, args := prepareCall(fr, &instr.CallCommon)
|
||||||
|
@ -28,6 +28,14 @@ var reflectTypesPackage = &types.Package{
|
|||||||
// type rtype <opaque>
|
// type rtype <opaque>
|
||||||
var rtypeType = makeNamedType("rtype", &types.Basic{Name: "rtype"})
|
var rtypeType = makeNamedType("rtype", &types.Basic{Name: "rtype"})
|
||||||
|
|
||||||
|
// error is an (interpreted) named type whose underlying type is string.
|
||||||
|
// The interpreter uses it for all implementations of the built-in error
|
||||||
|
// interface that it creates.
|
||||||
|
// We put it in the "reflect" package for expedience.
|
||||||
|
//
|
||||||
|
// type error string
|
||||||
|
var errorType = makeNamedType("error", &types.Basic{Name: "error"})
|
||||||
|
|
||||||
func makeNamedType(name string, underlying types.Type) *types.NamedType {
|
func makeNamedType(name string, underlying types.Type) *types.NamedType {
|
||||||
nt := &types.NamedType{Underlying: underlying}
|
nt := &types.NamedType{Underlying: underlying}
|
||||||
nt.Obj = &types.TypeName{
|
nt.Obj = &types.TypeName{
|
||||||
@ -123,6 +131,17 @@ func ext۰reflect۰rtype۰Kind(fn *ssa.Function, args []value) value {
|
|||||||
return uint(reflectKind(args[0].(rtype).t))
|
return uint(reflectKind(args[0].(rtype).t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰rtype۰NumOut(fn *ssa.Function, args []value) value {
|
||||||
|
// Signature: func (t reflect.rtype) int
|
||||||
|
return len(args[0].(rtype).t.(*types.Signature).Results)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰rtype۰Out(fn *ssa.Function, args []value) value {
|
||||||
|
// Signature: func (t reflect.rtype, i int) int
|
||||||
|
i := args[1].(int)
|
||||||
|
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results[i].Type})
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰reflect۰rtype۰String(fn *ssa.Function, args []value) value {
|
func ext۰reflect۰rtype۰String(fn *ssa.Function, args []value) value {
|
||||||
// Signature: func (t reflect.rtype) string
|
// Signature: func (t reflect.rtype) string
|
||||||
return args[0].(rtype).t.String()
|
return args[0].(rtype).t.String()
|
||||||
@ -279,6 +298,11 @@ func ext۰reflect۰Value۰Index(fn *ssa.Function, args []value) value {
|
|||||||
return nil // unreachable
|
return nil // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰Value۰Bool(fn *ssa.Function, args []value) value {
|
||||||
|
// Signature: func (reflect.Value) bool
|
||||||
|
return rV2V(args[0]).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰reflect۰Value۰CanAddr(fn *ssa.Function, args []value) value {
|
func ext۰reflect۰Value۰CanAddr(fn *ssa.Function, args []value) value {
|
||||||
// Signature: func (v reflect.Value) bool
|
// Signature: func (v reflect.Value) bool
|
||||||
// Always false for our representation.
|
// Always false for our representation.
|
||||||
@ -373,6 +397,10 @@ func ext۰reflect۰valueInterface(fn *ssa.Function, args []value) value {
|
|||||||
return iface{rV2T(v).t, rV2V(v)}
|
return iface{rV2T(v).t, rV2V(v)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰error۰Error(fn *ssa.Function, args []value) value {
|
||||||
|
return args[0]
|
||||||
|
}
|
||||||
|
|
||||||
// newMethod creates a new method of the specified name, package and receiver type.
|
// newMethod creates a new method of the specified name, package and receiver type.
|
||||||
func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
|
func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
|
||||||
fn := &ssa.Function{
|
fn := &ssa.Function{
|
||||||
@ -402,6 +430,11 @@ func initReflect(i *interpreter) {
|
|||||||
ssa.Id{nil, "Bits"}: newMethod(i.reflectPackage, rtypeType, "Bits"),
|
ssa.Id{nil, "Bits"}: newMethod(i.reflectPackage, rtypeType, "Bits"),
|
||||||
ssa.Id{nil, "Elem"}: newMethod(i.reflectPackage, rtypeType, "Elem"),
|
ssa.Id{nil, "Elem"}: newMethod(i.reflectPackage, rtypeType, "Elem"),
|
||||||
ssa.Id{nil, "Kind"}: newMethod(i.reflectPackage, rtypeType, "Kind"),
|
ssa.Id{nil, "Kind"}: newMethod(i.reflectPackage, rtypeType, "Kind"),
|
||||||
|
ssa.Id{nil, "NumOut"}: newMethod(i.reflectPackage, rtypeType, "NumOut"),
|
||||||
|
ssa.Id{nil, "Out"}: newMethod(i.reflectPackage, rtypeType, "Out"),
|
||||||
ssa.Id{nil, "String"}: newMethod(i.reflectPackage, rtypeType, "String"),
|
ssa.Id{nil, "String"}: newMethod(i.reflectPackage, rtypeType, "String"),
|
||||||
}
|
}
|
||||||
|
i.errorMethods = ssa.MethodSet{
|
||||||
|
ssa.Id{nil, "Error"}: newMethod(i.reflectPackage, errorType, "Error"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
7
src/pkg/exp/ssa/interp/testdata/coverage.go
vendored
7
src/pkg/exp/ssa/interp/testdata/coverage.go
vendored
@ -23,6 +23,13 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Call of variadic function with (implicit) empty slice.
|
||||||
|
if x := fmt.Sprint(); x != "" {
|
||||||
|
panic(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type empty interface{}
|
type empty interface{}
|
||||||
|
|
||||||
type I interface {
|
type I interface {
|
||||||
|
@ -226,10 +226,8 @@ func equals(x, y value) bool {
|
|||||||
return x == y.(*hashmap)
|
return x == y.(*hashmap)
|
||||||
case map[value]value:
|
case map[value]value:
|
||||||
return (x != nil) == (y.(map[value]value) != nil)
|
return (x != nil) == (y.(map[value]value) != nil)
|
||||||
case *ssa.Function:
|
case *ssa.Function, *closure:
|
||||||
return x == y.(*ssa.Function)
|
return x == y
|
||||||
case *closure:
|
|
||||||
return x == y.(*closure)
|
|
||||||
case []value:
|
case []value:
|
||||||
return (x != nil) == (y.([]value) != nil)
|
return (x != nil) == (y.([]value) != nil)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"exp/ssa/interp"
|
"exp/ssa/interp"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
@ -36,7 +37,8 @@ T [T]race execution of the program. Best for single-threaded programs!
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
const usage = `SSA builder and interpreter.
|
const usage = `SSA builder and interpreter.
|
||||||
Usage: ssadump [<flag> ...] <file.go> ...
|
Usage: ssadump [<flag> ...] [<file.go> ...] [<arg> ...]
|
||||||
|
ssadump [<flag> ...] <import/path> [<arg> ...]
|
||||||
Use -help flag to display options.
|
Use -help flag to display options.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@ -56,11 +58,11 @@ func main() {
|
|||||||
for _, c := range *buildFlag {
|
for _, c := range *buildFlag {
|
||||||
switch c {
|
switch c {
|
||||||
case 'P':
|
case 'P':
|
||||||
mode |= ssa.LogPackages
|
mode |= ssa.LogPackages | ssa.BuildSerially
|
||||||
case 'F':
|
case 'F':
|
||||||
mode |= ssa.LogFunctions
|
mode |= ssa.LogFunctions | ssa.BuildSerially
|
||||||
case 'S':
|
case 'S':
|
||||||
mode |= ssa.LogSource
|
mode |= ssa.LogSource | ssa.BuildSerially
|
||||||
case 'C':
|
case 'C':
|
||||||
mode |= ssa.SanityCheckFunctions
|
mode |= ssa.SanityCheckFunctions
|
||||||
case 'N':
|
case 'N':
|
||||||
@ -91,19 +93,6 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Treat all leading consecutive "*.go" arguments as a single package.
|
|
||||||
//
|
|
||||||
// TODO(gri): make it a typechecker error for there to be
|
|
||||||
// duplicate (e.g.) main functions in the same package.
|
|
||||||
var gofiles []string
|
|
||||||
for len(args) > 0 && strings.HasSuffix(args[0], ".go") {
|
|
||||||
gofiles = append(gofiles, args[0])
|
|
||||||
args = args[1:]
|
|
||||||
}
|
|
||||||
if gofiles == nil {
|
|
||||||
log.Fatal("No *.go source files specified.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profiling support.
|
// Profiling support.
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
@ -114,20 +103,46 @@ func main() {
|
|||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(adonovan): permit naming a package directly instead of
|
|
||||||
// a list of .go files.
|
|
||||||
|
|
||||||
// TODO(adonovan/gri): the cascade of errors is confusing due
|
// TODO(adonovan/gri): the cascade of errors is confusing due
|
||||||
// to reentrant control flow. Disable for now and re-think.
|
// to reentrant control flow. Disable for now and re-think.
|
||||||
var errh func(error)
|
var errh func(error)
|
||||||
// errh = func(err error) { fmt.Println(err.Error()) }
|
// errh = func(err error) { fmt.Println(err.Error()) }
|
||||||
|
|
||||||
b := ssa.NewBuilder(mode, ssa.GorootLoader, errh)
|
loader := ssa.GorootLoader
|
||||||
files, err := ssa.ParseFiles(b.Prog.Files, ".", gofiles...)
|
b := ssa.NewBuilder(mode, loader, errh)
|
||||||
|
|
||||||
|
var pkgname string
|
||||||
|
var files []*ast.File
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(args) == 0:
|
||||||
|
log.Fatal("No *.go source files nor package name was specified.")
|
||||||
|
|
||||||
|
case strings.HasSuffix(args[0], ".go"):
|
||||||
|
// % ssadump a.go b.go ...
|
||||||
|
// Leading consecutive *.go arguments constitute main package.
|
||||||
|
i := 1
|
||||||
|
for ; i < len(args) && strings.HasSuffix(args[i], ".go"); i++ {
|
||||||
|
}
|
||||||
|
files, err = ssa.ParseFiles(b.Prog.Files, ".", args[:i]...)
|
||||||
|
pkgname = "main"
|
||||||
|
args = args[i:]
|
||||||
|
|
||||||
|
default:
|
||||||
|
// % ssadump my/package ...
|
||||||
|
// First argument is import path of main package.
|
||||||
|
pkgname = args[0]
|
||||||
|
args = args[1:]
|
||||||
|
files, err = loader(b.Prog.Files, pkgname)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
mainpkg, err := b.CreatePackage("main", files)
|
|
||||||
|
// TODO(gri): make it a typechecker error for there to be
|
||||||
|
// duplicate (e.g.) main functions in the same package.
|
||||||
|
mainpkg, err := b.CreatePackage(pkgname, files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
@ -135,6 +150,6 @@ func main() {
|
|||||||
b = nil // discard Builder
|
b = nil // discard Builder
|
||||||
|
|
||||||
if *runFlag {
|
if *runFlag {
|
||||||
interp.Interpret(mainpkg, interpMode, gofiles[0], args)
|
interp.Interpret(mainpkg, interpMode, pkgname, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user