1
0
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:
Alan Donovan 2015-12-28 13:35:57 -05:00
parent e3e5aae018
commit 8463610142
3 changed files with 56 additions and 9 deletions

View File

@ -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)}

View File

@ -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 {

View File

@ -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)