go.tools/ssa/interp: fixes to enable running tests of package "encoding".

Running the interpreter on (most of) the tests package in
"encoding" unearthed a couple of ssa.builder bugs, already
fixed.  This CL contains the interpreter fixes that were
required.  (The "encoding" tests aren't added to the suite
since they're slow.)

Added intrinsics for:
        math.Exp
        math.Min
        hash/crc32.haveSSE42
        (reflect.Type).Field
        (reflect.Type).NumField
        (reflect.Type).NumMethod
        reflect.New
        (reflect.Value).NumMethod
        syscall.RawSyscall (returns ENOSYS)
        reflect.Set (a no-op)

Treat unsafe.Pointer -> *T conversions by returning new(T).
This is incorrect but at least preserves type-safety,
which is sufficient for these tests.

hashmap: treat nil *hashmap as an empty map.

R=gri
CC=golang-dev
https://golang.org/cl/12901046
This commit is contained in:
Alan Donovan 2013-09-12 11:00:31 -04:00
parent daa44ab970
commit 7e7d99b4c9
4 changed files with 218 additions and 27 deletions

View File

@ -26,11 +26,15 @@ type externalFn func(fn *ssa.Function, args []value) value
// Key strings are from Function.FullName().
// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
var externals = map[string]externalFn{
"(*runtime.Func).Entry": ext۰runtime۰Func۰Entry,
"(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine,
"(*runtime.Func).Name": ext۰runtime۰Func۰Name,
"(reflect.Value).Bool": ext۰reflect۰Value۰Bool,
"(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
"(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
"(reflect.Value).Field": ext۰reflect۰Value۰Field,
"(reflect.Value).Float": ext۰reflect۰Value۰Float,
"(reflect.Value).Index": ext۰reflect۰Value۰Index,
"(reflect.Value).Int": ext۰reflect۰Value۰Int,
"(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
@ -39,27 +43,41 @@ var externals = map[string]externalFn{
"(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
"(reflect.Value).Len": ext۰reflect۰Value۰Len,
"(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
"(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
"(reflect.Value).Set": ext۰reflect۰Value۰Set,
"(reflect.Value).String": ext۰reflect۰Value۰String,
"(reflect.Value).Type": ext۰reflect۰Value۰Type,
"(reflect.Value).Uint": ext۰reflect۰Value۰Uint,
"(reflect.error).Error": ext۰reflect۰error۰Error,
"(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
"(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
"(reflect.rtype).Field": ext۰reflect۰rtype۰Field,
"(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
"(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField,
"(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod,
"(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut,
"(reflect.rtype).Out": ext۰reflect۰rtype۰Out,
"(reflect.rtype).Size": ext۰reflect۰rtype۰Size,
"(reflect.rtype).String": ext۰reflect۰rtype۰String,
"bytes.Equal": ext۰bytes۰Equal,
"bytes.IndexByte": ext۰bytes۰IndexByte,
"hash/crc32.haveSSE42": ext۰crc32۰haveSSE42,
"math.Abs": ext۰math۰Abs,
"math.Exp": ext۰math۰Exp,
"math.Float32bits": ext۰math۰Float32bits,
"math.Float32frombits": ext۰math۰Float32frombits,
"math.Float64bits": ext۰math۰Float64bits,
"math.Float64frombits": ext۰math۰Float64frombits,
"math.Min": ext۰math۰Min,
"reflect.New": ext۰reflect۰New,
"reflect.TypeOf": ext۰reflect۰TypeOf,
"reflect.ValueOf": ext۰reflect۰ValueOf,
"reflect.init": ext۰reflect۰Init,
"reflect.valueInterface": ext۰reflect۰valueInterface,
"runtime.Breakpoint": ext۰runtime۰Breakpoint,
"runtime.Caller": ext۰runtime۰Caller,
"runtime.FuncForPC": ext۰runtime۰FuncForPC,
"runtime.GC": ext۰runtime۰GC,
"runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS,
"runtime.Gosched": ext۰runtime۰Gosched,
@ -67,6 +85,7 @@ var externals = map[string]externalFn{
"runtime.ReadMemStats": ext۰runtime۰ReadMemStats,
"runtime.SetFinalizer": ext۰runtime۰SetFinalizer,
"runtime.getgoroot": ext۰runtime۰getgoroot,
"strings.IndexByte": ext۰strings۰IndexByte,
"sync.runtime_Syncsemcheck": ext۰sync۰runtime_Syncsemcheck,
"sync/atomic.AddInt32": ext۰atomic۰AddInt32,
"sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32,
@ -83,6 +102,7 @@ var externals = map[string]externalFn{
"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.Stat": ext۰syscall۰Stat,
@ -99,6 +119,18 @@ func wrapError(err error) value {
return iface{t: errorType, v: err.Error()}
}
func ext۰runtime۰Func۰Entry(fn *ssa.Function, args []value) value {
return 0
}
func ext۰runtime۰Func۰FileLine(fn *ssa.Function, args []value) value {
return tuple{"unknown.go", -1}
}
func ext۰runtime۰Func۰Name(fn *ssa.Function, args []value) value {
return "unknown"
}
func ext۰bytes۰Equal(fn *ssa.Function, args []value) value {
// func Equal(a, b []byte) bool
a := args[0].([]value)
@ -126,6 +158,10 @@ func ext۰bytes۰IndexByte(fn *ssa.Function, args []value) value {
return -1
}
func ext۰crc32۰haveSSE42(fn *ssa.Function, args []value) value {
return false
}
func ext۰math۰Float64frombits(fn *ssa.Function, args []value) value {
return math.Float64frombits(args[0].(uint64))
}
@ -138,19 +174,56 @@ func ext۰math۰Float32frombits(fn *ssa.Function, args []value) value {
return math.Float32frombits(args[0].(uint32))
}
func ext۰math۰Abs(fn *ssa.Function, args []value) value {
return math.Abs(args[0].(float64))
}
func ext۰math۰Exp(fn *ssa.Function, args []value) value {
return math.Exp(args[0].(float64))
}
func ext۰math۰Float32bits(fn *ssa.Function, args []value) value {
return math.Float32bits(args[0].(float32))
}
func ext۰math۰Min(fn *ssa.Function, args []value) value {
return math.Min(args[0].(float64), args[1].(float64))
}
func ext۰runtime۰Breakpoint(fn *ssa.Function, args []value) value {
runtime.Breakpoint()
return nil
}
func ext۰runtime۰Caller(fn *ssa.Function, args []value) value {
// TODO(adonovan): actually inspect the stack.
return tuple{0, "somefile.go", 42, true}
}
func ext۰runtime۰FuncForPC(fn *ssa.Function, args []value) value {
// TODO(adonovan): actually inspect the stack.
return (*value)(nil)
//tuple{0, "somefile.go", 42, true}
//
//func FuncForPC(pc uintptr) *Func
}
func ext۰runtime۰getgoroot(fn *ssa.Function, args []value) value {
return os.Getenv("GOROOT")
}
func ext۰strings۰IndexByte(fn *ssa.Function, args []value) value {
// func IndexByte(s string, c byte) int
s := args[0].(string)
c := args[1].(byte)
for i := 0; i < len(s); i++ {
if s[i] == c {
return i
}
}
return -1
}
func ext۰sync۰runtime_Syncsemcheck(fn *ssa.Function, args []value) value {
return nil
}
@ -222,6 +295,14 @@ func ext۰runtime۰SetFinalizer(fn *ssa.Function, args []value) value {
return nil // ignore
}
func ext۰runtime۰funcname_go(fn *ssa.Function, args []value) value {
// TODO(adonovan): actually inspect the stack.
return (*value)(nil)
//tuple{0, "somefile.go", 42, true}
//
//func FuncForPC(pc uintptr) *Func
}
func ext۰time۰now(fn *ssa.Function, args []value) value {
nano := time.Now().UnixNano()
return tuple{int64(nano / 1e9), int32(nano % 1e9)}
@ -245,6 +326,10 @@ func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
return syscall.Getpid()
}
func ext۰syscall۰RawSyscall(fn *ssa.Function, args []value) value {
return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
}
// The set of remaining native functions we need to implement (as needed):
// crypto/aes/cipher_asm.go:10:func hasAsm() bool
@ -272,7 +357,6 @@ func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
// math/big/arith_decl.go:19:func bitLen(x Word) (n int)
// math/dim.go:13:func Dim(x, y float64) float64
// math/dim.go:26:func Max(x, y float64) float64
// math/dim.go:53:func Min(x, y float64) float64
// math/exp.go:14:func Exp(x float64) float64
// math/exp.go:135:func Exp2(x float64) float64
// math/expm1.go:124:func Expm1(x float64) float64

View File

@ -1,3 +1,7 @@
// 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
// Custom hashtable atop map.
@ -42,6 +46,7 @@ func makeMap(kt types.Type, reserve int) value {
// delete removes the association for key k, if any.
func (m *hashmap) delete(k hashable) {
if m != nil {
hash := k.hash()
head := m.table[hash]
if head != nil {
@ -61,16 +66,19 @@ func (m *hashmap) delete(k hashable) {
}
}
}
}
// lookup returns the value associated with key k, if present, or
// value(nil) otherwise.
func (m *hashmap) lookup(k hashable) value {
if m != nil {
hash := k.hash()
for e := m.table[hash]; e != nil; e = e.next {
if k.eq(e.key) {
return e.value
}
}
}
return nil
}
@ -97,5 +105,8 @@ func (m *hashmap) insert(k hashable, v value) {
// len returns the number of key/value associations in the map.
func (m *hashmap) len() int {
if m != nil {
return m.length
}
return 0
}

View File

@ -1,3 +1,7 @@
// 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 (
@ -1205,7 +1209,8 @@ func conv(t_dst, t_src types.Type, x value) value {
// TODO(adonovan): this is wrong and cannot
// really be fixed with the current design.
//
// It creates a new pointer of a different
// return (*value)(x.(unsafe.Pointer))
// creates a new pointer of a different
// type but the underlying interface value
// knows its "true" type and so cannot be
// meaningfully used through the new pointer.
@ -1213,7 +1218,11 @@ func conv(t_dst, t_src types.Type, x value) value {
// To make this work, the interpreter needs to
// simulate the memory layout of a real
// compiled implementation.
return (*value)(x.(unsafe.Pointer))
//
// To at least preserve type-safety, we'll
// just return the zero value of the
// destination type.
return zero(t_dst)
}
// Conversions between complex numeric types?

View File

@ -1,3 +1,7 @@
// 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
// Emulated "reflect" package.
@ -113,11 +117,37 @@ func ext۰reflect۰rtype۰Elem(fn *ssa.Function, args []value) value {
}).Elem()})
}
func ext۰reflect۰rtype۰Field(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype, i int) reflect.StructField
st := args[0].(rtype).t.Underlying().(*types.Struct)
i := args[1].(int)
f := st.Field(i)
return structure{
f.Name(),
f.Pkg().Path(),
makeReflectType(rtype{f.Type()}),
st.Tag(i),
0, // TODO(adonovan): offset
[]value{}, // TODO(adonovan): indices
f.Anonymous(),
}
}
func ext۰reflect۰rtype۰Kind(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) uint
return uint(reflectKind(args[0].(rtype).t))
}
func ext۰reflect۰rtype۰NumField(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
}
func ext۰reflect۰rtype۰NumMethod(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.MethodSet().Len()
}
func ext۰reflect۰rtype۰NumOut(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.(*types.Signature).Results().Len()
@ -129,11 +159,24 @@ func ext۰reflect۰rtype۰Out(fn *ssa.Function, args []value) value {
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
}
func ext۰reflect۰rtype۰Size(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) uintptr
// (Assumes no custom Sizeof used during SSA construction.)
return uintptr(types.DefaultSizeof(args[0].(rtype).t))
}
func ext۰reflect۰rtype۰String(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) string
return args[0].(rtype).t.String()
}
func ext۰reflect۰New(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.Type) reflect.Value
t := args[0].(iface).v.(rtype).t
alloc := zero(t)
return makeReflectValue(types.NewPointer(t), &alloc)
}
func ext۰reflect۰TypeOf(fn *ssa.Function, args []value) value {
// Signature: func (t reflect.rtype) string
return makeReflectType(rtype{args[0].(iface).t})
@ -223,6 +266,25 @@ func ext۰reflect۰Value۰Type(fn *ssa.Function, args []value) value {
return makeReflectType(rV2T(args[0]))
}
func ext۰reflect۰Value۰Uint(fn *ssa.Function, args []value) value {
// Signature: func (reflect.Value) uint64
switch v := rV2V(args[0]).(type) {
case uint:
return uint64(v)
case uint8:
return uint64(v)
case uint16:
return uint64(v)
case uint32:
return uint64(v)
case uint64:
return uint64(v)
case uintptr:
return uint64(v)
}
panic("reflect.Value.Uint")
}
func ext۰reflect۰Value۰Len(fn *ssa.Function, args []value) value {
// Signature: func (reflect.Value) int
switch v := rV2V(args[0]).(type) {
@ -249,6 +311,11 @@ func ext۰reflect۰Value۰NumField(fn *ssa.Function, args []value) value {
return len(rV2V(args[0]).(structure))
}
func ext۰reflect۰Value۰NumMethod(fn *ssa.Function, args []value) value {
// Signature: func (reflect.Value) int
return rV2T(args[0]).t.MethodSet().Len()
}
func ext۰reflect۰Value۰Pointer(fn *ssa.Function, args []value) value {
// Signature: func (v reflect.Value) uintptr
switch v := rV2V(args[0]).(type) {
@ -322,6 +389,17 @@ func ext۰reflect۰Value۰Field(fn *ssa.Function, args []value) value {
return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
}
func ext۰reflect۰Value۰Float(fn *ssa.Function, args []value) value {
// Signature: func (reflect.Value) float64
switch v := rV2V(args[0]).(type) {
case float32:
return float64(v)
case float64:
return float64(v)
}
panic("reflect.Value.Float")
}
func ext۰reflect۰Value۰Interface(fn *ssa.Function, args []value) value {
// Signature: func (v reflect.Value) interface{}
return ext۰reflect۰valueInterface(fn, args)
@ -378,6 +456,11 @@ func ext۰reflect۰Value۰IsValid(fn *ssa.Function, args []value) value {
return rV2V(args[0]) != nil
}
func ext۰reflect۰Value۰Set(fn *ssa.Function, args []value) value {
// TODO(adonovan): implement.
return nil
}
func ext۰reflect۰valueInterface(fn *ssa.Function, args []value) value {
// Signature: func (v reflect.Value, safe bool) interface{}
v := args[0].(structure)
@ -411,9 +494,13 @@ func initReflect(i *interpreter) {
i.rtypeMethods = methodSet{
"Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
"Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
"Field": newMethod(i.reflectPackage, rtypeType, "Field"),
"Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
"NumField": newMethod(i.reflectPackage, rtypeType, "NumField"),
"NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
"NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
"Out": newMethod(i.reflectPackage, rtypeType, "Out"),
"Size": newMethod(i.reflectPackage, rtypeType, "Size"),
"String": newMethod(i.reflectPackage, rtypeType, "String"),
}
i.errorMethods = methodSet{