mirror of
https://github.com/golang/go
synced 2024-11-18 21:54:49 -07:00
go/ssa/interp: enable support for Example tests
1. Added intrinsic for os.Pipe to avoid use of "unsafe". This makes Example tests work in the interpreter, fixing the broken "unicode" package (which recently sprouted some Examples) and allowing us to enable tests for: encoding/csv flag path text/scanner unicode/utf8 The implementation of os.Pipe may require tweaking for non-Linux platforms. 2. Added intrinsic for strings.Index to avoid assembly dependency. 3. Added dumb intrinsic for testing۰runExample to work around a bug in go/ssa/testmain.go that requires an invasive fix (Until then, the output of Example functions will not be checked.) Change-Id: I6374c9c47aa802275b7cdc98525e057f5db0615a Reviewed-on: https://go-review.googlesource.com/18191 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
e3e5aae018
commit
8463610142
@ -11,6 +11,7 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
@ -81,6 +82,7 @@ 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۰os۰runtime_beforeExit,
|
||||
"reflect.New": ext۰reflect۰New,
|
||||
@ -107,6 +109,7 @@ func init() {
|
||||
"(*runtime.Func).Name": ext۰runtime۰Func۰Name,
|
||||
"runtime.environ": ext۰runtime۰environ,
|
||||
"runtime.getgoroot": ext۰runtime۰getgoroot,
|
||||
"strings.Index": ext۰strings۰Index,
|
||||
"strings.IndexByte": ext۰strings۰IndexByte,
|
||||
"sync.runtime_Semacquire": ext۰sync۰runtime_Semacquire,
|
||||
"sync.runtime_Semrelease": ext۰sync۰runtime_Semrelease,
|
||||
@ -135,6 +138,7 @@ func init() {
|
||||
"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,
|
||||
}
|
||||
@ -233,6 +237,21 @@ func ext۰math۰Log(fr *frame, args []value) value {
|
||||
return math.Log(args[0].(float64))
|
||||
}
|
||||
|
||||
func ext۰os۰Pipe(fr *frame, args []value) value {
|
||||
// This is an inlining of linux's os.Pipe.
|
||||
// func os.Pipe() (r *File, w *File, err error)
|
||||
var p [2]int
|
||||
if err := syscall.Pipe2(p[:], syscall.O_CLOEXEC); err != nil {
|
||||
// TODO(adonovan): fix: return an *os.SyscallError.
|
||||
return tuple{nil, nil, wrapError(err)}
|
||||
}
|
||||
|
||||
NewFile := fr.i.prog.ImportedPackage("os").Func("NewFile")
|
||||
r := call(fr.i, fr, 0, NewFile, []value{uintptr(p[0]), "|0"})
|
||||
w := call(fr.i, fr, 0, NewFile, []value{uintptr(p[1]), "|1"})
|
||||
return tuple{r, w, wrapError(nil)}
|
||||
}
|
||||
|
||||
func ext۰os۰runtime_args(fr *frame, args []value) value {
|
||||
return fr.i.osArgs
|
||||
}
|
||||
@ -261,6 +280,7 @@ func ext۰runtime۰Caller(fr *frame, args []value) value {
|
||||
if fr != nil {
|
||||
fn := fr.fn
|
||||
// TODO(adonovan): use pc/posn of current instruction, not start of fn.
|
||||
// (Required to interpret the log package's tests.)
|
||||
pc = uintptr(unsafe.Pointer(fn))
|
||||
posn := fn.Prog.Fset.Position(fn.Pos())
|
||||
file = posn.Filename
|
||||
@ -321,6 +341,11 @@ func ext۰strings۰IndexByte(fr *frame, args []value) value {
|
||||
return -1
|
||||
}
|
||||
|
||||
func ext۰strings۰Index(fr *frame, args []value) value {
|
||||
// Call compiled version to avoid tricky asm dependency.
|
||||
return strings.Index(args[0].(string), args[1].(string))
|
||||
}
|
||||
|
||||
func ext۰sync۰runtime_Syncsemcheck(fr *frame, args []value) value {
|
||||
// TODO(adonovan): fix: implement.
|
||||
return nil
|
||||
@ -465,6 +490,22 @@ func ext۰runtime۰Func۰Entry(fr *frame, args []value) value {
|
||||
return uintptr(unsafe.Pointer(f))
|
||||
}
|
||||
|
||||
// This is a workaround for a bug in go/ssa/testmain.go: it creates
|
||||
// InternalExamples even for Example functions with no Output comment.
|
||||
// TODO(adonovan): fix (and redesign) testmain.go after Go 1.6.
|
||||
func ext۰testing۰runExample(fr *frame, args []value) value {
|
||||
// This is a stripped down runExample that simply calls the function.
|
||||
// It does not capture and compare output nor recover from panic.
|
||||
//
|
||||
// func runExample(eg testing.InternalExample) bool {
|
||||
// eg.F()
|
||||
// return true
|
||||
// }
|
||||
F := args[0].(structure)[1]
|
||||
call(fr.i, fr, 0, F, nil)
|
||||
return true
|
||||
}
|
||||
|
||||
func ext۰time۰now(fr *frame, args []value) value {
|
||||
nano := time.Now().UnixNano()
|
||||
return tuple{int64(nano / 1e9), int32(nano % 1e9)}
|
||||
|
@ -158,20 +158,20 @@ var gorootSrcTests = []string{
|
||||
"encoding/hex",
|
||||
// "encoding/pem", // TODO(adonovan): implement (reflect.Value).SetString
|
||||
// "testing", // TODO(adonovan): implement runtime.Goexit correctly
|
||||
"unicode",
|
||||
// "hash/crc32", // TODO(adonovan): implement hash/crc32.haveCLMUL
|
||||
// "log", // TODO(adonovan): implement runtime.Callers correctly
|
||||
|
||||
// Too slow:
|
||||
// "container/ring",
|
||||
// "hash/adler32",
|
||||
|
||||
// TODO(adonovan): packages with Examples require os.Pipe (unimplemented):
|
||||
// "hash/crc32",
|
||||
// "unicode/utf8",
|
||||
// "log",
|
||||
// "path",
|
||||
// "flag",
|
||||
// "encoding/csv"
|
||||
// "text/scanner"
|
||||
"unicode/utf8",
|
||||
"path",
|
||||
"flag",
|
||||
"encoding/csv",
|
||||
"text/scanner",
|
||||
"unicode",
|
||||
}
|
||||
|
||||
type successPredicate func(exitcode int, output string) error
|
||||
@ -210,7 +210,7 @@ func run(t *testing.T, dir, input string, success successPredicate) bool {
|
||||
interp.CapturedOutput = nil
|
||||
}()
|
||||
|
||||
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
|
||||
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n", input)
|
||||
|
||||
iprog, err := conf.Load()
|
||||
if err != nil {
|
||||
|
@ -241,6 +241,12 @@ func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value
|
||||
tPtrElem := types.NewPointer(tElem)
|
||||
tPtrFunc := types.NewPointer(funcField(slice))
|
||||
|
||||
// TODO(adonovan): fix: populate the
|
||||
// testing.InternalExample.Output field correctly so that tests
|
||||
// work correctly under the interpreter. This requires that we
|
||||
// do this step using ASTs, not *ssa.Functions---quite a
|
||||
// redesign. See also the fake runExample in go/ssa/interp.
|
||||
|
||||
// Emit: array = new [n]testing.InternalTest
|
||||
tArray := types.NewArray(tElem, int64(len(testfuncs)))
|
||||
array := emitNew(fn, tArray, token.NoPos)
|
||||
|
Loading…
Reference in New Issue
Block a user