diff --git a/usr/austin/eval/bridge.go b/usr/austin/eval/bridge.go new file mode 100644 index 0000000000..aed763fc64 --- /dev/null +++ b/usr/austin/eval/bridge.go @@ -0,0 +1,168 @@ +// Copyright 2009 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 eval + +import ( + "log"; + "go/token"; + "reflect"; +) + +/* + * Type bridging + */ + +var ( + evalTypes = make(map[reflect.Type] Type); + nativeTypes = make(map[Type] reflect.Type); +) + +// TypeFromNative converts a regular Go type into a the corresponding +// interpreter Type. +func TypeFromNative(t reflect.Type) Type { + if et, ok := evalTypes[t]; ok { + return et; + } + + var nt *NamedType; + if t.Name() != "" { + name := t.PkgPath() + "ยท" + t.Name(); + nt = &NamedType{token.Position{}, name, nil, true, make(map[string] Method)}; + evalTypes[t] = nt; + } + + var et Type; + switch t := t.(type) { + case *reflect.BoolType: + et = BoolType; + case *reflect.Float32Type: + et = Float32Type; + case *reflect.Float64Type: + et = Float64Type; + case *reflect.FloatType: + et = FloatType; + case *reflect.Int16Type: + et = Int16Type; + case *reflect.Int32Type: + et = Int32Type; + case *reflect.Int64Type: + et = Int64Type; + case *reflect.Int8Type: + et = Int8Type; + case *reflect.IntType: + et = IntType; + case *reflect.StringType: + et = StringType; + case *reflect.Uint16Type: + et = Uint16Type; + case *reflect.Uint32Type: + et = Uint32Type; + case *reflect.Uint64Type: + et = Uint64Type; + case *reflect.Uint8Type: + et = Uint8Type; + case *reflect.UintType: + et = UintType; + case *reflect.UintptrType: + et = UintptrType; + + case *reflect.ArrayType: + et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem())); + case *reflect.ChanType: + log.Crashf("%T not implemented", t); + case *reflect.FuncType: + nin := t.NumIn(); + // Variadic functions have DotDotDotType at the end + varidic := false; + if nin > 0 { + if _, ok := t.In(nin - 1).(*reflect.DotDotDotType); ok { + varidic = true; + nin--; + } + } + in := make([]Type, nin); + for i := range in { + in[i] = TypeFromNative(t.In(i)); + } + out := make([]Type, t.NumOut()); + for i := range out { + out[i] = TypeFromNative(t.Out(i)); + } + et = NewFuncType(in, varidic, out); + case *reflect.InterfaceType: + log.Crashf("%T not implemented", t); + case *reflect.MapType: + log.Crashf("%T not implemented", t); + case *reflect.PtrType: + et = NewPtrType(TypeFromNative(t.Elem())); + case *reflect.SliceType: + et = NewSliceType(TypeFromNative(t.Elem())); + case *reflect.StructType: + n := t.NumField(); + fields := make([]StructField, n); + for i := 0; i < n; i++ { + sf := t.Field(i); + // TODO(austin) What to do about private fields? + fields[i].Name = sf.Name; + fields[i].Type = TypeFromNative(sf.Type); + fields[i].Anonymous = sf.Anonymous; + } + et = NewStructType(fields); + case *reflect.UnsafePointerType: + log.Crashf("%T not implemented", t); + default: + log.Crashf("unexpected reflect.Type: %T", t); + } + + if nt != nil { + nt.def = et; + et = nt; + } + + nativeTypes[et] = t; + evalTypes[t] = et; + + return et; +} + +// TypeOfNative returns the interpreter Type of a regular Go value. +func TypeOfNative(v interface {}) Type { + return TypeFromNative(reflect.Typeof(v)); +} + +/* + * Function bridging + */ + +type nativeFunc struct { + fn func([]Value, []Value); + in, out int; +} + +func (f *nativeFunc) NewFrame() *Frame { + vars := make([]Value, f.in + f.out); + return &Frame{nil, vars}; +} + +func (f *nativeFunc) Call(fr *Frame) { + f.fn(fr.Vars[0:f.in], fr.Vars[f.in:f.in+f.out]); +} + +// FuncFromNative creates an interpreter function from a native +// function that takes its in and out arguments as slices of +// interpreter Value's. While somewhat inconvenient, this avoids +// value marshalling. +func FuncFromNative(fn func([]Value, []Value), t *FuncType) FuncValue { + return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}}; +} + +// FuncFromNativeTyped is like FuncFromNative, but constructs the +// function type from a function pointer using reflection. Typically, +// the type will be given as a nil pointer to a function with the +// desired signature. +func FuncFromNativeTyped(fn func([]Value, []Value), t interface{}) (*FuncType, FuncValue) { + ft := TypeOfNative(t).(*FuncType); + return ft, FuncFromNative(fn, ft); +} diff --git a/usr/austin/eval/value.go b/usr/austin/eval/value.go index 5f533c0d67..af67c25684 100644 --- a/usr/austin/eval/value.go +++ b/usr/austin/eval/value.go @@ -433,6 +433,9 @@ type ptrV struct { } func (v *ptrV) String() string { + if v.target == nil { + return ""; + } return "&" + v.target.String(); } @@ -482,6 +485,9 @@ type sliceV struct { } func (v *sliceV) String() string { + if v.Base == nil { + return ""; + } res := "{"; for i := int64(0); i < v.Len; i++ { if i > 0 { @@ -513,6 +519,9 @@ type mapV struct { } func (v *mapV) String() string { + if v.target == nil { + return ""; + } res := "map["; i := 0; v.target.Iter(func(key interface{}, val Value) bool {