| // 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. |
| // |
| // We completely replace the built-in "reflect" package. |
| // The only thing clients can depend upon are that reflect.Type is an |
| // interface and reflect.Value is an (opaque) struct. |
| |
| import ( |
| "fmt" |
| "go/token" |
| "go/types" |
| "reflect" |
| "unsafe" |
| |
| "golang.org/x/tools/go/ssa" |
| ) |
| |
| type opaqueType struct { |
| types.Type |
| name string |
| } |
| |
| func (t *opaqueType) String() string { return t.name } |
| |
| // A bogus "reflect" type-checker package. Shared across interpreters. |
| var reflectTypesPackage = types.NewPackage("reflect", "reflect") |
| |
| // rtype is the concrete type the interpreter uses to implement the |
| // reflect.Type interface. |
| // |
| // type rtype <opaque> |
| var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"}) |
| |
| // error is an (interpreted) named type whose underlying type is string. |
| // The interpreter uses it for all implementations of the built-in error |
| // interface that it creates. |
| // We put it in the "reflect" package for expedience. |
| // |
| // type error string |
| var errorType = makeNamedType("error", &opaqueType{nil, "error"}) |
| |
| func makeNamedType(name string, underlying types.Type) *types.Named { |
| obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil) |
| return types.NewNamed(obj, underlying, nil) |
| } |
| |
| func makeReflectValue(t types.Type, v value) value { |
| return structure{rtype{t}, v} |
| } |
| |
| // Given a reflect.Value, returns its rtype. |
| func rV2T(v value) rtype { |
| return v.(structure)[0].(rtype) |
| } |
| |
| // Given a reflect.Value, returns the underlying interpreter value. |
| func rV2V(v value) value { |
| return v.(structure)[1] |
| } |
| |
| // makeReflectType boxes up an rtype in a reflect.Type interface. |
| func makeReflectType(rt rtype) value { |
| return iface{rtypeType, rt} |
| } |
| |
| func ext۰reflect۰rtype۰Bits(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) int |
| rt := args[0].(rtype).t |
| basic, ok := rt.Underlying().(*types.Basic) |
| if !ok { |
| panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt)) |
| } |
| return int(fr.i.sizes.Sizeof(basic)) * 8 |
| } |
| |
| func ext۰reflect۰rtype۰Elem(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) reflect.Type |
| return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface { |
| Elem() types.Type |
| }).Elem()}) |
| } |
| |
| func ext۰reflect۰rtype۰Field(fr *frame, 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۰In(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype, i int) int |
| i := args[1].(int) |
| return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()}) |
| } |
| |
| func ext۰reflect۰rtype۰Kind(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) uint |
| return uint(reflectKind(args[0].(rtype).t)) |
| } |
| |
| func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) int |
| return args[0].(rtype).t.Underlying().(*types.Struct).NumFields() |
| } |
| |
| func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) int |
| return args[0].(rtype).t.(*types.Signature).Params().Len() |
| } |
| |
| func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) int |
| return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len() |
| } |
| |
| func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) int |
| return args[0].(rtype).t.(*types.Signature).Results().Len() |
| } |
| |
| func ext۰reflect۰rtype۰Out(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype, i int) int |
| i := args[1].(int) |
| return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()}) |
| } |
| |
| func ext۰reflect۰rtype۰Size(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) uintptr |
| return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t)) |
| } |
| |
| func ext۰reflect۰rtype۰String(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) string |
| return args[0].(rtype).t.String() |
| } |
| |
| func ext۰reflect۰New(fr *frame, 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۰SliceOf(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) Type |
| return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)}) |
| } |
| |
| func ext۰reflect۰TypeOf(fr *frame, args []value) value { |
| // Signature: func (t reflect.rtype) Type |
| return makeReflectType(rtype{args[0].(iface).t}) |
| } |
| |
| func ext۰reflect۰ValueOf(fr *frame, args []value) value { |
| // Signature: func (interface{}) reflect.Value |
| itf := args[0].(iface) |
| return makeReflectValue(itf.t, itf.v) |
| } |
| |
| func ext۰reflect۰Zero(fr *frame, args []value) value { |
| // Signature: func (t reflect.Type) reflect.Value |
| t := args[0].(iface).v.(rtype).t |
| return makeReflectValue(t, zero(t)) |
| } |
| |
| func reflectKind(t types.Type) reflect.Kind { |
| switch t := t.(type) { |
| case *types.Named: |
| return reflectKind(t.Underlying()) |
| case *types.Basic: |
| switch t.Kind() { |
| case types.Bool: |
| return reflect.Bool |
| case types.Int: |
| return reflect.Int |
| case types.Int8: |
| return reflect.Int8 |
| case types.Int16: |
| return reflect.Int16 |
| case types.Int32: |
| return reflect.Int32 |
| case types.Int64: |
| return reflect.Int64 |
| case types.Uint: |
| return reflect.Uint |
| case types.Uint8: |
| return reflect.Uint8 |
| case types.Uint16: |
| return reflect.Uint16 |
| case types.Uint32: |
| return reflect.Uint32 |
| case types.Uint64: |
| return reflect.Uint64 |
| case types.Uintptr: |
| return reflect.Uintptr |
| case types.Float32: |
| return reflect.Float32 |
| case types.Float64: |
| return reflect.Float64 |
| case types.Complex64: |
| return reflect.Complex64 |
| case types.Complex128: |
| return reflect.Complex128 |
| case types.String: |
| return reflect.String |
| case types.UnsafePointer: |
| return reflect.UnsafePointer |
| } |
| case *types.Array: |
| return reflect.Array |
| case *types.Chan: |
| return reflect.Chan |
| case *types.Signature: |
| return reflect.Func |
| case *types.Interface: |
| return reflect.Interface |
| case *types.Map: |
| return reflect.Map |
| case *types.Pointer: |
| return reflect.Ptr |
| case *types.Slice: |
| return reflect.Slice |
| case *types.Struct: |
| return reflect.Struct |
| } |
| panic(fmt.Sprint("unexpected type: ", t)) |
| } |
| |
| func ext۰reflect۰Value۰Kind(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) uint |
| return uint(reflectKind(rV2T(args[0]).t)) |
| } |
| |
| func ext۰reflect۰Value۰String(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) string |
| return toString(rV2V(args[0])) |
| } |
| |
| func ext۰reflect۰Value۰Type(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) reflect.Type |
| return makeReflectType(rV2T(args[0])) |
| } |
| |
| func ext۰reflect۰Value۰Uint(fr *frame, 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(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) int |
| switch v := rV2V(args[0]).(type) { |
| case string: |
| return len(v) |
| case array: |
| return len(v) |
| case chan value: |
| return cap(v) |
| case []value: |
| return len(v) |
| case *hashmap: |
| return v.len() |
| case map[value]value: |
| return len(v) |
| default: |
| panic(fmt.Sprintf("reflect.(Value).Len(%v)", v)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰MapIndex(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) Value |
| tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key() |
| k := rV2V(args[1]) |
| switch m := rV2V(args[0]).(type) { |
| case map[value]value: |
| if v, ok := m[k]; ok { |
| return makeReflectValue(tValue, v) |
| } |
| |
| case *hashmap: |
| if v := m.lookup(k.(hashable)); v != nil { |
| return makeReflectValue(tValue, v) |
| } |
| |
| default: |
| panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k)) |
| } |
| return makeReflectValue(nil, nil) |
| } |
| |
| func ext۰reflect۰Value۰MapKeys(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) []Value |
| var keys []value |
| tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key() |
| switch v := rV2V(args[0]).(type) { |
| case map[value]value: |
| for k := range v { |
| keys = append(keys, makeReflectValue(tKey, k)) |
| } |
| |
| case *hashmap: |
| for _, e := range v.entries() { |
| for ; e != nil; e = e.next { |
| keys = append(keys, makeReflectValue(tKey, e.key)) |
| } |
| } |
| |
| default: |
| panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v)) |
| } |
| return keys |
| } |
| |
| func ext۰reflect۰Value۰NumField(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) int |
| return len(rV2V(args[0]).(structure)) |
| } |
| |
| func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) int |
| return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len() |
| } |
| |
| func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value) uintptr |
| switch v := rV2V(args[0]).(type) { |
| case *value: |
| return uintptr(unsafe.Pointer(v)) |
| case chan value: |
| return reflect.ValueOf(v).Pointer() |
| case []value: |
| return reflect.ValueOf(v).Pointer() |
| case *hashmap: |
| return reflect.ValueOf(v.entries()).Pointer() |
| case map[value]value: |
| return reflect.ValueOf(v).Pointer() |
| case *ssa.Function: |
| return uintptr(unsafe.Pointer(v)) |
| case *closure: |
| return uintptr(unsafe.Pointer(v)) |
| default: |
| panic(fmt.Sprintf("reflect.(Value).Pointer(%T)", v)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰Index(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value, i int) Value |
| i := args[1].(int) |
| t := rV2T(args[0]).t.Underlying() |
| switch v := rV2V(args[0]).(type) { |
| case array: |
| return makeReflectValue(t.(*types.Array).Elem(), v[i]) |
| case []value: |
| return makeReflectValue(t.(*types.Slice).Elem(), v[i]) |
| default: |
| panic(fmt.Sprintf("reflect.(Value).Index(%T)", v)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰Bool(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) bool |
| return rV2V(args[0]).(bool) |
| } |
| |
| func ext۰reflect۰Value۰CanAddr(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value) bool |
| // Always false for our representation. |
| return false |
| } |
| |
| func ext۰reflect۰Value۰CanInterface(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value) bool |
| // Always true for our representation. |
| return true |
| } |
| |
| func ext۰reflect۰Value۰Elem(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value) reflect.Value |
| switch x := rV2V(args[0]).(type) { |
| case iface: |
| return makeReflectValue(x.t, x.v) |
| case *value: |
| return makeReflectValue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x) |
| default: |
| panic(fmt.Sprintf("reflect.(Value).Elem(%T)", x)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰Field(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value, i int) reflect.Value |
| v := args[0] |
| i := args[1].(int) |
| return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i]) |
| } |
| |
| func ext۰reflect۰Value۰Float(fr *frame, 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(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value) interface{} |
| return ext۰reflect۰valueInterface(fr, args) |
| } |
| |
| func ext۰reflect۰Value۰Int(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) int64 |
| switch x := rV2V(args[0]).(type) { |
| case int: |
| return int64(x) |
| case int8: |
| return int64(x) |
| case int16: |
| return int64(x) |
| case int32: |
| return int64(x) |
| case int64: |
| return x |
| default: |
| panic(fmt.Sprintf("reflect.(Value).Int(%T)", x)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰IsNil(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) bool |
| switch x := rV2V(args[0]).(type) { |
| case *value: |
| return x == nil |
| case chan value: |
| return x == nil |
| case map[value]value: |
| return x == nil |
| case *hashmap: |
| return x == nil |
| case iface: |
| return x.t == nil |
| case []value: |
| return x == nil |
| case *ssa.Function: |
| return x == nil |
| case *ssa.Builtin: |
| return x == nil |
| case *closure: |
| return x == nil |
| default: |
| panic(fmt.Sprintf("reflect.(Value).IsNil(%T)", x)) |
| } |
| } |
| |
| func ext۰reflect۰Value۰IsValid(fr *frame, args []value) value { |
| // Signature: func (reflect.Value) bool |
| return rV2V(args[0]) != nil |
| } |
| |
| func ext۰reflect۰Value۰Set(fr *frame, args []value) value { |
| // TODO(adonovan): implement. |
| return nil |
| } |
| |
| func ext۰reflect۰valueInterface(fr *frame, args []value) value { |
| // Signature: func (v reflect.Value, safe bool) interface{} |
| v := args[0].(structure) |
| return iface{rV2T(v).t, rV2V(v)} |
| } |
| |
| func ext۰reflect۰error۰Error(fr *frame, args []value) value { |
| return args[0] |
| } |
| |
| // newMethod creates a new method of the specified name, package and receiver type. |
| func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function { |
| // TODO(adonovan): fix: hack: currently the only part of Signature |
| // that is needed is the "pointerness" of Recv.Type, and for |
| // now, we'll set it to always be false since we're only |
| // concerned with rtype. Encapsulate this better. |
| sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) |
| fn := pkg.Prog.NewFunction(name, sig, "fake reflect method") |
| fn.Pkg = pkg |
| return fn |
| } |
| |
| func initReflect(i *interpreter) { |
| i.reflectPackage = &ssa.Package{ |
| Prog: i.prog, |
| Pkg: reflectTypesPackage, |
| Members: make(map[string]ssa.Member), |
| } |
| |
| // Clobber the type-checker's notion of reflect.Value's |
| // underlying type so that it more closely matches the fake one |
| // (at least in the number of fields---we lie about the type of |
| // the rtype field). |
| // |
| // We must ensure that calls to (ssa.Value).Type() return the |
| // fake type so that correct "shape" is used when allocating |
| // variables, making zero values, loading, and storing. |
| // |
| // TODO(adonovan): obviously this is a hack. We need a cleaner |
| // way to fake the reflect package (almost---DeepEqual is fine). |
| // One approach would be not to even load its source code, but |
| // provide fake source files. This would guarantee that no bad |
| // information leaks into other packages. |
| if r := i.prog.ImportedPackage("reflect"); r != nil { |
| rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named) |
| |
| // delete bodies of the old methods |
| mset := i.prog.MethodSets.MethodSet(rV) |
| for j := 0; j < mset.Len(); j++ { |
| i.prog.MethodValue(mset.At(j)).Blocks = nil |
| } |
| |
| tEface := types.NewInterface(nil, nil).Complete() |
| rV.SetUnderlying(types.NewStruct([]*types.Var{ |
| types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie |
| types.NewField(token.NoPos, r.Pkg, "v", tEface, false), |
| }, nil)) |
| } |
| |
| i.rtypeMethods = methodSet{ |
| "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), |
| "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), |
| "Field": newMethod(i.reflectPackage, rtypeType, "Field"), |
| "In": newMethod(i.reflectPackage, rtypeType, "In"), |
| "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), |
| "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"), |
| "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"), |
| "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"), |
| } |
| } |