// 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 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"), } }