diff --git a/ssa/interp/external.go b/ssa/interp/external.go index cd02be40..38af5355 100644 --- a/ssa/interp/external.go +++ b/ssa/interp/external.go @@ -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 diff --git a/ssa/interp/map.go b/ssa/interp/map.go index b81ffedd..b77bdfe6 100644 --- a/ssa/interp/map.go +++ b/ssa/interp/map.go @@ -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,22 +46,24 @@ func makeMap(kt types.Type, reserve int) value { // delete removes the association for key k, if any. func (m *hashmap) delete(k hashable) { - hash := k.hash() - head := m.table[hash] - if head != nil { - if k.eq(head.key) { - m.table[hash] = head.next - m.length-- - return - } - prev := head - for e := head.next; e != nil; e = e.next { - if k.eq(e.key) { - prev.next = e.next + if m != nil { + hash := k.hash() + head := m.table[hash] + if head != nil { + if k.eq(head.key) { + m.table[hash] = head.next m.length-- return } - prev = e + prev := head + for e := head.next; e != nil; e = e.next { + if k.eq(e.key) { + prev.next = e.next + m.length-- + return + } + prev = e + } } } } @@ -65,10 +71,12 @@ 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 { - hash := k.hash() - for e := m.table[hash]; e != nil; e = e.next { - if k.eq(e.key) { - return e.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 { - return m.length + if m != nil { + return m.length + } + return 0 } diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index 432c5220..34661490 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -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? diff --git a/ssa/interp/reflect.go b/ssa/interp/reflect.go index d8294184..b245bf38 100644 --- a/ssa/interp/reflect.go +++ b/ssa/interp/reflect.go @@ -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) @@ -409,12 +492,16 @@ func initReflect(i *interpreter) { } i.rtypeMethods = methodSet{ - "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), - "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), - "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), - "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"), - "Out": newMethod(i.reflectPackage, rtypeType, "Out"), - "String": newMethod(i.reflectPackage, rtypeType, "String"), + "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{ "Error": newMethod(i.reflectPackage, errorType, "Error"),