diff options
Diffstat (limited to 'src/pkg/reflect/value.go')
-rw-r--r-- | src/pkg/reflect/value.go | 716 |
1 files changed, 645 insertions, 71 deletions
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index 79476ad22..c87812c46 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -60,7 +60,7 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) { // direct operations. type Value struct { // typ holds the type of the value represented by a Value. - typ *commonType + typ *rtype // val holds the 1-word representation of the value. // If flag's flagIndir bit is set, then val is a pointer to the data. @@ -211,7 +211,7 @@ func storeIword(p unsafe.Pointer, w iword, n uintptr) { // emptyInterface is the header for an interface{} value. type emptyInterface struct { - typ *runtimeType + typ *rtype word iword } @@ -219,8 +219,8 @@ type emptyInterface struct { type nonEmptyInterface struct { // see ../runtime/iface.c:/Itab itab *struct { - ityp *runtimeType // static interface type - typ *runtimeType // dynamic concrete type + ityp *rtype // static interface type + typ *rtype // dynamic concrete type link unsafe.Pointer bad int32 unused int32 @@ -302,6 +302,17 @@ func (v Value) Bytes() []byte { return *(*[]byte)(v.val) } +// runes returns v's underlying value. +// It panics if v's underlying value is not a slice of runes (int32s). +func (v Value) runes() []rune { + v.mustBe(Slice) + if v.typ.Elem().Kind() != Int32 { + panic("reflect.Value.Bytes of non-rune slice") + } + // Slice is always bigger than a word; assume flagIndir. + return *(*[]rune)(v.val) +} + // CanAddr returns true if the value's address can be obtained with Addr. // Such values are called addressable. A value is addressable if it is // an element of a slice, an element of an addressable array, @@ -335,7 +346,7 @@ func (v Value) Call(in []Value) []Value { } // CallSlice calls the variadic function v with the input arguments in, -// assigning the slice in[len(in)-1] to v's final variadic argument. +// assigning the slice in[len(in)-1] to v's final variadic argument. // For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...). // Call panics if v's Kind is not Func or if v is not variadic. // It returns the output results as Values. @@ -365,12 +376,12 @@ func (v Value) call(method string, in []Value) []Value { if m.pkgPath != nil { panic(method + " of unexported method") } - t = toCommonType(m.typ) + t = m.typ iface := (*nonEmptyInterface)(v.val) if iface.itab == nil { panic(method + " of method on nil interface value") } - fn = iface.itab.fun[i] + fn = unsafe.Pointer(&iface.itab.fun[i]) rcvr = iface.word } else { ut := v.typ.uncommon() @@ -381,8 +392,8 @@ func (v Value) call(method string, in []Value) []Value { if m.pkgPath != nil { panic(method + " of unexported method") } - fn = m.ifn - t = toCommonType(m.mtyp) + fn = unsafe.Pointer(&m.ifn) + t = m.mtyp rcvr = v.iword() } } else if v.flag&flagIndir != 0 { @@ -490,9 +501,9 @@ func (v Value) call(method string, in []Value) []Value { // TODO(rsc): revisit when reference counting happens. // The values are holding up the in references for us, // but something must be done for the out references. - // For now make everything look like a pointer by pretending - // to allocate a []*int. - args := make([]*int, size/ptrSize) + // For now make everything look like a pointer by allocating + // a []unsafe.Pointer. + args := make([]unsafe.Pointer, size/ptrSize) ptr := uintptr(unsafe.Pointer(&args[0])) off := uintptr(0) if v.flag&flagMethod != 0 { @@ -502,7 +513,7 @@ func (v Value) call(method string, in []Value) []Value { } for i, v := range in { v.mustBeExported() - targ := t.In(i).(*commonType) + targ := t.In(i).(*rtype) a := uintptr(targ.align) off = (off + a - 1) &^ (a - 1) n := targ.size @@ -536,6 +547,85 @@ func (v Value) call(method string, in []Value) []Value { return ret } +// callReflect is the call implementation used by a function +// returned by MakeFunc. In many ways it is the opposite of the +// method Value.call above. The method above converts a call using Values +// into a call of a function with a concrete argument frame, while +// callReflect converts a call of a function with a concrete argument +// frame into a call using Values. +// It is in this file so that it can be next to the call method above. +// The remainder of the MakeFunc implementation is in makefunc.go. +func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { + ftyp := ctxt.typ + f := ctxt.fn + + // Copy argument frame into Values. + ptr := frame + off := uintptr(0) + in := make([]Value, 0, len(ftyp.in)) + for _, arg := range ftyp.in { + typ := arg + off += -off & uintptr(typ.align-1) + v := Value{typ, nil, flag(typ.Kind()) << flagKindShift} + if typ.size <= ptrSize { + // value fits in word. + v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size)) + } else { + // value does not fit in word. + // Must make a copy, because f might keep a reference to it, + // and we cannot let f keep a reference to the stack frame + // after this function returns, not even a read-only reference. + v.val = unsafe_New(typ) + memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size) + v.flag |= flagIndir + } + in = append(in, v) + off += typ.size + } + + // Call underlying function. + out := f(in) + if len(out) != len(ftyp.out) { + panic("reflect: wrong return count from function created by MakeFunc") + } + + // Copy results back into argument frame. + if len(ftyp.out) > 0 { + off += -off & (ptrSize - 1) + for i, arg := range ftyp.out { + typ := arg + v := out[i] + if v.typ != typ { + panic("reflect: function created by MakeFunc using " + funcName(f) + + " returned wrong type: have " + + out[i].typ.String() + " for " + typ.String()) + } + if v.flag&flagRO != 0 { + panic("reflect: function created by MakeFunc using " + funcName(f) + + " returned value obtained from unexported field") + } + off += -off & uintptr(typ.align-1) + addr := unsafe.Pointer(uintptr(ptr) + off) + if v.flag&flagIndir == 0 { + storeIword(addr, iword(v.val), typ.size) + } else { + memmove(addr, v.val, typ.size) + } + off += typ.size + } + } +} + +// funcName returns the name of f, for use in error messages. +func funcName(f func([]Value) []Value) string { + pc := *(*uintptr)(unsafe.Pointer(&f)) + rf := runtime.FuncForPC(pc) + if rf != nil { + return rf.Name() + } + return "closure" +} + // Cap returns v's capacity. // It panics if v's Kind is not Array, Chan, or Slice. func (v Value) Cap() int { @@ -586,7 +676,7 @@ func (v Value) Elem() Value { switch k { case Interface: var ( - typ *commonType + typ *rtype val unsafe.Pointer ) if v.typ.NumMethod() == 0 { @@ -595,7 +685,7 @@ func (v Value) Elem() Value { // nil interface value return Value{} } - typ = toCommonType(eface.typ) + typ = eface.typ val = unsafe.Pointer(eface.word) } else { iface := (*nonEmptyInterface)(v.val) @@ -603,7 +693,7 @@ func (v Value) Elem() Value { // nil interface value return Value{} } - typ = toCommonType(iface.itab.typ) + typ = iface.itab.typ val = unsafe.Pointer(iface.word) } fl := v.flag & flagRO @@ -623,7 +713,7 @@ func (v Value) Elem() Value { return Value{} } tt := (*ptrType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag&flagRO | flagIndir | flagAddr fl |= flag(typ.Kind() << flagKindShift) return Value{typ, val, fl} @@ -640,7 +730,7 @@ func (v Value) Field(i int) Value { panic("reflect: Field index out of range") } field := &tt.fields[i] - typ := toCommonType(field.typ) + typ := field.typ // Inherit permission bits from v. fl := v.flag & (flagRO | flagIndir | flagAddr) @@ -723,8 +813,10 @@ func (v Value) Float() float64 { panic(&ValueError{"reflect.Value.Float", k}) } +var uint8Type = TypeOf(uint8(0)).(*rtype) + // Index returns v's i'th element. -// It panics if v's Kind is not Array or Slice or i is out of range. +// It panics if v's Kind is not Array, Slice, or String or i is out of range. func (v Value) Index(i int) Value { k := v.kind() switch k { @@ -733,7 +825,7 @@ func (v Value) Index(i int) Value { if i < 0 || i > int(tt.len) { panic("reflect: array index out of range") } - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array fl |= flag(typ.Kind()) << flagKindShift offset := uintptr(i) * typ.size @@ -761,10 +853,19 @@ func (v Value) Index(i int) Value { panic("reflect: slice index out of range") } tt := (*sliceType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl |= flag(typ.Kind()) << flagKindShift val := unsafe.Pointer(s.Data + uintptr(i)*typ.size) return Value{typ, val, fl} + + case String: + fl := v.flag&flagRO | flag(Uint8<<flagKindShift) + s := (*StringHeader)(v.val) + if i < 0 || i >= s.Len { + panic("reflect: string index out of range") + } + val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i))) + return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl} } panic(&ValueError{"reflect.Value.Index", k}) } @@ -826,7 +927,7 @@ func valueInterface(v Value, safe bool) interface{} { if safe && v.flag&flagRO != 0 { // Do not allow access to unexported values via Interface, - // because they might be pointers that should not be + // because they might be pointers that should not be // writable or methods or function that should not be callable. panic("reflect.Value.Interface: cannot return value obtained from unexported field or method") } @@ -846,7 +947,7 @@ func valueInterface(v Value, safe bool) interface{} { // Non-interface value. var eface emptyInterface - eface.typ = v.typ.runtimeType() + eface.typ = v.typ eface.word = v.iword() if v.flag&flagIndir != 0 && v.typ.size > ptrSize { @@ -919,9 +1020,9 @@ func (v Value) Len() int { tt := (*arrayType)(unsafe.Pointer(v.typ)) return int(tt.len) case Chan: - return int(chanlen(v.iword())) + return chanlen(v.iword()) case Map: - return int(maplen(v.iword())) + return maplen(v.iword()) case Slice: // Slice is bigger than a word; assume flagIndir. return (*SliceHeader)(v.val).Len @@ -947,13 +1048,13 @@ func (v Value) MapIndex(key Value) Value { // considered unexported. This is consistent with the // behavior for structs, which allow read but not write // of unexported fields. - key = key.assignTo("reflect.Value.MapIndex", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.MapIndex", tt.key, nil) - word, ok := mapaccess(v.typ.runtimeType(), v.iword(), key.iword()) + word, ok := mapaccess(v.typ, v.iword(), key.iword()) if !ok { return Value{} } - typ := toCommonType(tt.elem) + typ := tt.elem fl := (v.flag | key.flag) & flagRO if typ.size > ptrSize { fl |= flagIndir @@ -969,7 +1070,7 @@ func (v Value) MapIndex(key Value) Value { func (v Value) MapKeys() []Value { v.mustBe(Map) tt := (*mapType)(unsafe.Pointer(v.typ)) - keyType := toCommonType(tt.key) + keyType := tt.key fl := v.flag & flagRO fl |= flag(keyType.Kind()) << flagKindShift @@ -978,11 +1079,11 @@ func (v Value) MapKeys() []Value { } m := v.iword() - mlen := int32(0) + mlen := int(0) if m != nil { mlen = maplen(m) } - it := mapiterinit(v.typ.runtimeType(), m) + it := mapiterinit(v.typ, m) a := make([]Value, mlen) var i int for i = 0; i < len(a); i++ { @@ -1081,7 +1182,7 @@ func overflowFloat32(x float64) bool { if x < 0 { x = -x } - return math.MaxFloat32 <= x && x <= math.MaxFloat64 + return math.MaxFloat32 < x && x <= math.MaxFloat64 } // OverflowInt returns true if the int64 x cannot be represented by v's type. @@ -1115,18 +1216,35 @@ func (v Value) OverflowUint(x uint64) bool { // code using reflect cannot obtain unsafe.Pointers // without importing the unsafe package explicitly. // It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer. +// +// If v's Kind is Func, the returned pointer is an underlying +// code pointer, but not necessarily enough to identify a +// single function uniquely. The only guarantee is that the +// result is zero if and only if v is a nil func Value. func (v Value) Pointer() uintptr { k := v.kind() switch k { - case Chan, Func, Map, Ptr, UnsafePointer: - if k == Func && v.flag&flagMethod != 0 { + case Chan, Map, Ptr, UnsafePointer: + p := v.val + if v.flag&flagIndir != 0 { + p = *(*unsafe.Pointer)(p) + } + return uintptr(p) + case Func: + if v.flag&flagMethod != 0 { panic("reflect.Value.Pointer of method Value") } p := v.val if v.flag&flagIndir != 0 { p = *(*unsafe.Pointer)(p) } + // Non-nil func value points at data block. + // First word of data block is actual code. + if p != nil { + p = *(*unsafe.Pointer)(p) + } return uintptr(p) + case Slice: return (*SliceHeader)(v.val).Data } @@ -1151,9 +1269,9 @@ func (v Value) recv(nb bool) (val Value, ok bool) { if ChanDir(tt.dir)&RecvDir == 0 { panic("recv on send-only channel") } - word, selected, ok := chanrecv(v.typ.runtimeType(), v.iword(), nb) + word, selected, ok := chanrecv(v.typ, v.iword(), nb) if selected { - typ := toCommonType(tt.elem) + typ := tt.elem fl := flag(typ.Kind()) << flagKindShift if typ.size > ptrSize { fl |= flagIndir @@ -1180,8 +1298,8 @@ func (v Value) send(x Value, nb bool) (selected bool) { panic("send on recv-only channel") } x.mustBeExported() - x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil) - return chansend(v.typ.runtimeType(), v.iword(), x.iword(), nb) + x = x.assignTo("reflect.Value.Send", tt.elem, nil) + return chansend(v.typ, v.iword(), x.iword(), nb) } // Set assigns x to the value v. @@ -1221,6 +1339,17 @@ func (v Value) SetBytes(x []byte) { *(*[]byte)(v.val) = x } +// setRunes sets v's underlying value. +// It panics if v's underlying value is not a slice of runes (int32s). +func (v Value) setRunes(x []rune) { + v.mustBeAssignable() + v.mustBe(Slice) + if v.typ.Elem().Kind() != Int32 { + panic("reflect.Value.setRunes of non-rune slice") + } + *(*[]rune)(v.val) = x +} + // SetComplex sets v's underlying value to x. // It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false. func (v Value) SetComplex(x complex128) { @@ -1292,12 +1421,12 @@ func (v Value) SetMapIndex(key, val Value) { v.mustBeExported() key.mustBeExported() tt := (*mapType)(unsafe.Pointer(v.typ)) - key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil) if val.typ != nil { val.mustBeExported() - val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil) + val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil) } - mapassign(v.typ.runtimeType(), v.iword(), key.iword(), val.iword(), val.typ != nil) + mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil) } // SetUint sets v's underlying value to x. @@ -1339,7 +1468,7 @@ func (v Value) SetString(x string) { } // Slice returns a slice of v. -// It panics if v's Kind is not Array or Slice. +// It panics if v's Kind is not Array, Slice or String, or if v is an unaddressable array. func (v Value) Slice(beg, end int) Value { var ( cap int @@ -1349,31 +1478,44 @@ func (v Value) Slice(beg, end int) Value { switch k := v.kind(); k { default: panic(&ValueError{"reflect.Value.Slice", k}) + case Array: if v.flag&flagAddr == 0 { panic("reflect.Value.Slice: slice of unaddressable array") } tt := (*arrayType)(unsafe.Pointer(v.typ)) cap = int(tt.len) - typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice))) + typ = (*sliceType)(unsafe.Pointer(tt.slice)) base = v.val + case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) s := (*SliceHeader)(v.val) base = unsafe.Pointer(s.Data) cap = s.Cap + case String: + s := (*StringHeader)(v.val) + if beg < 0 || end < beg || end > s.Len { + panic("reflect.Value.Slice: string slice index out of bounds") + } + var x string + val := (*StringHeader)(unsafe.Pointer(&x)) + val.Data = s.Data + uintptr(beg) + val.Len = end - beg + return Value{v.typ, unsafe.Pointer(&x), v.flag} } + if beg < 0 || end < beg || end > cap { panic("reflect.Value.Slice: slice index out of bounds") } // Declare slice so that gc can see the base pointer in it. - var x []byte + var x []unsafe.Pointer // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size() + s.Data = uintptr(base) + uintptr(beg)*typ.elem.Size() s.Len = end - beg s.Cap = cap - beg @@ -1439,7 +1581,7 @@ func (v Value) Type() Type { panic("reflect: broken Value") } m := &tt.methods[i] - return toCommonType(m.typ) + return m.typ } // Method on concrete type. ut := v.typ.uncommon() @@ -1447,7 +1589,7 @@ func (v Value) Type() Type { panic("reflect: broken Value") } m := &ut.methods[i] - return toCommonType(m.mtyp) + return m.mtyp } // Uint returns v's underlying value, as a uint64. @@ -1618,13 +1760,148 @@ func Copy(dst, src Value) int { return n } +// A runtimeSelect is a single case passed to rselect. +// This must match ../runtime/chan.c:/runtimeSelect +type runtimeSelect struct { + dir uintptr // 0, SendDir, or RecvDir + typ *rtype // channel type + ch iword // interface word for channel + val iword // interface word for value (for SendDir) +} + +// rselect runs a select. It returns the index of the chosen case, +// and if the case was a receive, the interface word of the received +// value and the conventional OK bool to indicate whether the receive +// corresponds to a sent value. +func rselect([]runtimeSelect) (chosen int, recv iword, recvOK bool) + +// A SelectDir describes the communication direction of a select case. +type SelectDir int + +// NOTE: These values must match ../runtime/chan.c:/SelectDir. + +const ( + _ SelectDir = iota + SelectSend // case Chan <- Send + SelectRecv // case <-Chan: + SelectDefault // default +) + +// A SelectCase describes a single case in a select operation. +// The kind of case depends on Dir, the communication direction. +// +// If Dir is SelectDefault, the case represents a default case. +// Chan and Send must be zero Values. +// +// If Dir is SelectSend, the case represents a send operation. +// Normally Chan's underlying value must be a channel, and Send's underlying value must be +// assignable to the channel's element type. As a special case, if Chan is a zero Value, +// then the case is ignored, and the field Send will also be ignored and may be either zero +// or non-zero. +// +// If Dir is SelectRecv, the case represents a receive operation. +// Normally Chan's underlying value must be a channel and Send must be a zero Value. +// If Chan is a zero Value, then the case is ignored, but Send must still be a zero Value. +// When a receive operation is selected, the received Value is returned by Select. +// +type SelectCase struct { + Dir SelectDir // direction of case + Chan Value // channel to use (for send or receive) + Send Value // value to send (for send) +} + +// Select executes a select operation described by the list of cases. +// Like the Go select statement, it blocks until at least one of the cases +// can proceed, makes a uniform pseudo-random choice, +// and then executes that case. It returns the index of the chosen case +// and, if that case was a receive operation, the value received and a +// boolean indicating whether the value corresponds to a send on the channel +// (as opposed to a zero value received because the channel is closed). +func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { + // NOTE: Do not trust that caller is not modifying cases data underfoot. + // The range is safe because the caller cannot modify our copy of the len + // and each iteration makes its own copy of the value c. + runcases := make([]runtimeSelect, len(cases)) + haveDefault := false + for i, c := range cases { + rc := &runcases[i] + rc.dir = uintptr(c.Dir) + switch c.Dir { + default: + panic("reflect.Select: invalid Dir") + + case SelectDefault: // default + if haveDefault { + panic("reflect.Select: multiple default cases") + } + haveDefault = true + if c.Chan.IsValid() { + panic("reflect.Select: default case has Chan value") + } + if c.Send.IsValid() { + panic("reflect.Select: default case has Send value") + } + + case SelectSend: + ch := c.Chan + if !ch.IsValid() { + break + } + ch.mustBe(Chan) + ch.mustBeExported() + tt := (*chanType)(unsafe.Pointer(ch.typ)) + if ChanDir(tt.dir)&SendDir == 0 { + panic("reflect.Select: SendDir case using recv-only channel") + } + rc.ch = ch.iword() + rc.typ = &tt.rtype + v := c.Send + if !v.IsValid() { + panic("reflect.Select: SendDir case missing Send value") + } + v.mustBeExported() + v = v.assignTo("reflect.Select", tt.elem, nil) + rc.val = v.iword() + + case SelectRecv: + if c.Send.IsValid() { + panic("reflect.Select: RecvDir case has Send value") + } + ch := c.Chan + if !ch.IsValid() { + break + } + ch.mustBe(Chan) + ch.mustBeExported() + tt := (*chanType)(unsafe.Pointer(ch.typ)) + rc.typ = &tt.rtype + if ChanDir(tt.dir)&RecvDir == 0 { + panic("reflect.Select: RecvDir case using send-only channel") + } + rc.ch = ch.iword() + } + } + + chosen, word, recvOK := rselect(runcases) + if runcases[chosen].dir == uintptr(SelectRecv) { + tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) + typ := tt.elem + fl := flag(typ.Kind()) << flagKindShift + if typ.size > ptrSize { + fl |= flagIndir + } + recv = Value{typ, unsafe.Pointer(word), fl} + } + return chosen, recv, recvOK +} + /* * constructors */ // implemented in package runtime -func unsafe_New(Type) unsafe.Pointer -func unsafe_NewArray(Type, int) unsafe.Pointer +func unsafe_New(*rtype) unsafe.Pointer +func unsafe_NewArray(*rtype, int) unsafe.Pointer // MakeSlice creates a new zero-initialized slice value // for the specified slice type, length, and capacity. @@ -1643,11 +1920,11 @@ func MakeSlice(typ Type, len, cap int) Value { } // Declare slice so that gc can see the base pointer in it. - var x []byte + var x []unsafe.Pointer // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap)) + s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap)) s.Len = len s.Cap = cap @@ -1665,7 +1942,7 @@ func MakeChan(typ Type, buffer int) Value { if typ.ChanDir() != BothDir { panic("reflect.MakeChan: unidirectional channel type") } - ch := makechan(typ.runtimeType(), uint32(buffer)) + ch := makechan(typ.(*rtype), uint64(buffer)) return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift} } @@ -1674,7 +1951,7 @@ func MakeMap(typ Type) Value { if typ.Kind() != Map { panic("reflect.MakeMap of non-map type") } - m := makemap(typ.runtimeType()) + m := makemap(typ.(*rtype)) return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift} } @@ -1705,7 +1982,7 @@ func ValueOf(i interface{}) Value { // For an interface value with the noAddr bit set, // the representation is identical to an empty interface. eface := *(*emptyInterface)(unsafe.Pointer(&i)) - typ := toCommonType(eface.typ) + typ := eface.typ fl := flag(typ.Kind()) << flagKindShift if typ.size > ptrSize { fl |= flagIndir @@ -1713,10 +1990,11 @@ func ValueOf(i interface{}) Value { return Value{typ, unsafe.Pointer(eface.word), fl} } -// Zero returns a Value representing a zero value for the specified type. +// Zero returns a Value representing the zero value for the specified type. // The result is different from the zero value of the Value struct, // which represents no value at all. // For example, Zero(TypeOf(42)) returns a Value with Kind Int and value 0. +// The returned value is neither addressable nor settable. func Zero(typ Type) Value { if typ == nil { panic("reflect: Zero(nil)") @@ -1726,7 +2004,7 @@ func Zero(typ Type) Value { if t.size <= ptrSize { return Value{t, nil, fl} } - return Value{t, unsafe_New(typ), fl | flagIndir} + return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir} } // New returns a Value representing a pointer to a new zero value @@ -1735,7 +2013,7 @@ func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } - ptr := unsafe_New(typ) + ptr := unsafe_New(typ.(*rtype)) fl := flag(Ptr) << flagKindShift return Value{typ.common().ptrTo(), ptr, fl} } @@ -1750,7 +2028,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value { // assignTo returns a value v that can be assigned directly to typ. // It panics if v is not assignable to typ. // For a conversion to an interface type, target is a suggested scratch space to use. -func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value { +func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { if v.flag&flagMethod != 0 { panic(context + ": cannot assign method value to type " + dst.String()) } @@ -1772,7 +2050,7 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va if dst.NumMethod() == 0 { *target = x } else { - ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target)) + ifaceE2I(dst, x, unsafe.Pointer(target)) } return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift} } @@ -1781,24 +2059,320 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String()) } +// Convert returns the value v converted to type t. +// If the usual Go conversion rules do not allow conversion +// of the value v to type t, Convert panics. +func (v Value) Convert(t Type) Value { + if v.flag&flagMethod != 0 { + panic("reflect.Value.Convert: cannot convert method values") + } + op := convertOp(t.common(), v.typ) + if op == nil { + panic("reflect.Value.Convert: value of type " + v.typ.String() + " cannot be converted to type " + t.String()) + } + return op(v, t) +} + +// convertOp returns the function to convert a value of type src +// to a value of type dst. If the conversion is illegal, convertOp returns nil. +func convertOp(dst, src *rtype) func(Value, Type) Value { + switch src.Kind() { + case Int, Int8, Int16, Int32, Int64: + switch dst.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtInt + case Float32, Float64: + return cvtIntFloat + case String: + return cvtIntString + } + + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + switch dst.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtUint + case Float32, Float64: + return cvtUintFloat + case String: + return cvtUintString + } + + case Float32, Float64: + switch dst.Kind() { + case Int, Int8, Int16, Int32, Int64: + return cvtFloatInt + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtFloatUint + case Float32, Float64: + return cvtFloat + } + + case Complex64, Complex128: + switch dst.Kind() { + case Complex64, Complex128: + return cvtComplex + } + + case String: + if dst.Kind() == Slice && dst.Elem().PkgPath() == "" { + switch dst.Elem().Kind() { + case Uint8: + return cvtStringBytes + case Int32: + return cvtStringRunes + } + } + + case Slice: + if dst.Kind() == String && src.Elem().PkgPath() == "" { + switch src.Elem().Kind() { + case Uint8: + return cvtBytesString + case Int32: + return cvtRunesString + } + } + } + + // dst and src have same underlying type. + if haveIdenticalUnderlyingType(dst, src) { + return cvtDirect + } + + // dst and src are unnamed pointer types with same underlying base type. + if dst.Kind() == Ptr && dst.Name() == "" && + src.Kind() == Ptr && src.Name() == "" && + haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) { + return cvtDirect + } + + if implements(dst, src) { + if src.Kind() == Interface { + return cvtI2I + } + return cvtT2I + } + + return nil +} + +// makeInt returns a Value of type t equal to bits (possibly truncated), +// where t is a signed or unsigned int type. +func makeInt(f flag, bits uint64, t Type) Value { + typ := t.common() + if typ.size > ptrSize { + // Assume ptrSize >= 4, so this must be uint64. + ptr := unsafe_New(typ) + *(*uint64)(unsafe.Pointer(ptr)) = bits + return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + } + var w iword + switch typ.size { + case 1: + *(*uint8)(unsafe.Pointer(&w)) = uint8(bits) + case 2: + *(*uint16)(unsafe.Pointer(&w)) = uint16(bits) + case 4: + *(*uint32)(unsafe.Pointer(&w)) = uint32(bits) + case 8: + *(*uint64)(unsafe.Pointer(&w)) = uint64(bits) + } + return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift} +} + +// makeFloat returns a Value of type t equal to v (possibly truncated to float32), +// where t is a float32 or float64 type. +func makeFloat(f flag, v float64, t Type) Value { + typ := t.common() + if typ.size > ptrSize { + // Assume ptrSize >= 4, so this must be float64. + ptr := unsafe_New(typ) + *(*float64)(unsafe.Pointer(ptr)) = v + return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + } + + var w iword + switch typ.size { + case 4: + *(*float32)(unsafe.Pointer(&w)) = float32(v) + case 8: + *(*float64)(unsafe.Pointer(&w)) = v + } + return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift} +} + +// makeComplex returns a Value of type t equal to v (possibly truncated to complex64), +// where t is a complex64 or complex128 type. +func makeComplex(f flag, v complex128, t Type) Value { + typ := t.common() + if typ.size > ptrSize { + ptr := unsafe_New(typ) + switch typ.size { + case 8: + *(*complex64)(unsafe.Pointer(ptr)) = complex64(v) + case 16: + *(*complex128)(unsafe.Pointer(ptr)) = v + } + return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + } + + // Assume ptrSize <= 8 so this must be complex64. + var w iword + *(*complex64)(unsafe.Pointer(&w)) = complex64(v) + return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift} +} + +func makeString(f flag, v string, t Type) Value { + ret := New(t).Elem() + ret.SetString(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +func makeBytes(f flag, v []byte, t Type) Value { + ret := New(t).Elem() + ret.SetBytes(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +func makeRunes(f flag, v []rune, t Type) Value { + ret := New(t).Elem() + ret.setRunes(v) + ret.flag = ret.flag&^flagAddr | f + return ret +} + +// These conversion functions are returned by convertOp +// for classes of conversions. For example, the first function, cvtInt, +// takes any value v of signed int type and returns the value converted +// to type t, where t is any signed or unsigned int type. + +// convertOp: intXX -> [u]intXX +func cvtInt(v Value, t Type) Value { + return makeInt(v.flag&flagRO, uint64(v.Int()), t) +} + +// convertOp: uintXX -> [u]intXX +func cvtUint(v Value, t Type) Value { + return makeInt(v.flag&flagRO, v.Uint(), t) +} + +// convertOp: floatXX -> intXX +func cvtFloatInt(v Value, t Type) Value { + return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t) +} + +// convertOp: floatXX -> uintXX +func cvtFloatUint(v Value, t Type) Value { + return makeInt(v.flag&flagRO, uint64(v.Float()), t) +} + +// convertOp: intXX -> floatXX +func cvtIntFloat(v Value, t Type) Value { + return makeFloat(v.flag&flagRO, float64(v.Int()), t) +} + +// convertOp: uintXX -> floatXX +func cvtUintFloat(v Value, t Type) Value { + return makeFloat(v.flag&flagRO, float64(v.Uint()), t) +} + +// convertOp: floatXX -> floatXX +func cvtFloat(v Value, t Type) Value { + return makeFloat(v.flag&flagRO, v.Float(), t) +} + +// convertOp: complexXX -> complexXX +func cvtComplex(v Value, t Type) Value { + return makeComplex(v.flag&flagRO, v.Complex(), t) +} + +// convertOp: intXX -> string +func cvtIntString(v Value, t Type) Value { + return makeString(v.flag&flagRO, string(v.Int()), t) +} + +// convertOp: uintXX -> string +func cvtUintString(v Value, t Type) Value { + return makeString(v.flag&flagRO, string(v.Uint()), t) +} + +// convertOp: []byte -> string +func cvtBytesString(v Value, t Type) Value { + return makeString(v.flag&flagRO, string(v.Bytes()), t) +} + +// convertOp: string -> []byte +func cvtStringBytes(v Value, t Type) Value { + return makeBytes(v.flag&flagRO, []byte(v.String()), t) +} + +// convertOp: []rune -> string +func cvtRunesString(v Value, t Type) Value { + return makeString(v.flag&flagRO, string(v.runes()), t) +} + +// convertOp: string -> []rune +func cvtStringRunes(v Value, t Type) Value { + return makeRunes(v.flag&flagRO, []rune(v.String()), t) +} + +// convertOp: direct copy +func cvtDirect(v Value, typ Type) Value { + f := v.flag + t := typ.common() + val := v.val + if f&flagAddr != 0 { + // indirect, mutable word - make a copy + ptr := unsafe_New(t) + memmove(ptr, val, t.size) + val = ptr + f &^= flagAddr + } + return Value{t, val, v.flag&flagRO | f} +} + +// convertOp: concrete -> interface +func cvtT2I(v Value, typ Type) Value { + target := new(interface{}) + x := valueInterface(v, false) + if typ.NumMethod() == 0 { + *target = x + } else { + ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target)) + } + return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift} +} + +// convertOp: interface -> interface +func cvtI2I(v Value, typ Type) Value { + if v.IsNil() { + ret := Zero(typ) + ret.flag |= v.flag & flagRO + return ret + } + return cvtT2I(v.Elem(), typ) +} + // implemented in ../pkg/runtime -func chancap(ch iword) int32 +func chancap(ch iword) int func chanclose(ch iword) -func chanlen(ch iword) int32 -func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool) -func chansend(t *runtimeType, ch iword, val iword, nb bool) bool - -func makechan(typ *runtimeType, size uint32) (ch iword) -func makemap(t *runtimeType) (m iword) -func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool) -func mapassign(t *runtimeType, m iword, key, val iword, ok bool) -func mapiterinit(t *runtimeType, m iword) *byte +func chanlen(ch iword) int +func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool) +func chansend(t *rtype, ch iword, val iword, nb bool) bool + +func makechan(typ *rtype, size uint64) (ch iword) +func makemap(t *rtype) (m iword) +func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool) +func mapassign(t *rtype, m iword, key, val iword, ok bool) +func mapiterinit(t *rtype, m iword) *byte func mapiterkey(it *byte) (key iword, ok bool) func mapiternext(it *byte) -func maplen(m iword) int32 +func maplen(m iword) int func call(fn, arg unsafe.Pointer, n uint32) -func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer) +func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that |