diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-07-16 06:54:42 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-07-16 06:54:42 +0000 |
commit | be47d6eceffd2c5dbbc1566d5eea490527fb2bd4 (patch) | |
tree | 0e8fda573576bb4181dba29d0e88380a8c38fafd /libgo/go/reflect/value.go | |
parent | efb30cdeb003fd7c585ee0d7657340086abcbd9e (diff) | |
download | gcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.zip gcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.tar.gz gcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.tar.bz2 |
libgo: Update to Go 1.1.1.
From-SVN: r200974
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r-- | libgo/go/reflect/value.go | 196 |
1 files changed, 137 insertions, 59 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index f8126e6..6bf66c8 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -245,7 +245,7 @@ func (f flag) mustBeExported() { panic(&ValueError{methodName(), 0}) } if f&flagRO != 0 { - panic(methodName() + " using value obtained using unexported field") + panic("reflect: " + methodName() + " using value obtained using unexported field") } } @@ -258,10 +258,10 @@ func (f flag) mustBeAssignable() { } // Assignable if addressable and not read-only. if f&flagRO != 0 { - panic(methodName() + " using value obtained using unexported field") + panic("reflect: " + methodName() + " using value obtained using unexported field") } if f&flagAddr == 0 { - panic(methodName() + " using unaddressable value") + panic("reflect: " + methodName() + " using unaddressable value") } } @@ -354,7 +354,7 @@ func (v Value) CallSlice(in []Value) []Value { return v.call("CallSlice", in) } -func (v Value) call(method string, in []Value) []Value { +func (v Value) call(op string, in []Value) []Value { // Get function pointer, type. t := v.typ var ( @@ -362,36 +362,7 @@ func (v Value) call(method string, in []Value) []Value { rcvr iword ) if v.flag&flagMethod != 0 { - i := int(v.flag) >> flagMethodShift - if v.typ.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(v.typ)) - if i < 0 || i >= len(tt.methods) { - panic("reflect: broken Value") - } - m := &tt.methods[i] - if m.pkgPath != nil { - panic(method + " of unexported method") - } - t = m.typ - iface := (*nonEmptyInterface)(v.val) - if iface.itab == nil { - panic(method + " of method on nil interface value") - } - fn = unsafe.Pointer(&iface.itab.fun[i]) - rcvr = iface.word - } else { - ut := v.typ.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { - panic("reflect: broken Value") - } - m := &ut.methods[i] - if m.pkgPath != nil { - panic(method + " of unexported method") - } - fn = unsafe.Pointer(&m.tfn) - t = m.mtyp - rcvr = v.iword() - } + t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift) } else if v.flag&flagIndir != 0 { fn = *(*unsafe.Pointer)(v.val) } else { @@ -402,7 +373,7 @@ func (v Value) call(method string, in []Value) []Value { panic("reflect.Value.Call: call of nil function") } - isSlice := method == "CallSlice" + isSlice := op == "CallSlice" n := t.NumIn() if isSlice { if !t.IsVariadic() { @@ -427,12 +398,12 @@ func (v Value) call(method string, in []Value) []Value { } for _, x := range in { if x.Kind() == Invalid { - panic("reflect: " + method + " using zero Value argument") + panic("reflect: " + op + " using zero Value argument") } } for i := 0; i < n; i++ { if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) { - panic("reflect: " + method + " using " + xt.String() + " as type " + targ.String()) + panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String()) } } if !isSlice && t.IsVariadic() { @@ -443,7 +414,7 @@ func (v Value) call(method string, in []Value) []Value { for i := 0; i < m; i++ { x := in[n+i] if xt := x.Type(); !xt.AssignableTo(elem) { - panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + method) + panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op) } slice.Index(i).Set(x) } @@ -553,7 +524,10 @@ func isMethod(t *rtype) bool { // 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(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) { +func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { + ftyp := ctxt.typ + f := ctxt.fn + // Copy argument frame into Values. ptr := frame off := uintptr(0) @@ -611,6 +585,91 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) } } +// methodReceiver returns information about the receiver +// described by v. The Value v may or may not have the +// flagMethod bit set, so the kind cached in v.flag should +// not be used. +func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer, rcvr iword) { + i := methodIndex + if v.typ.Kind() == Interface { + tt := (*interfaceType)(unsafe.Pointer(v.typ)) + if i < 0 || i >= len(tt.methods) { + panic("reflect: internal error: invalid method index") + } + m := &tt.methods[i] + if m.pkgPath != nil { + panic("reflect: " + op + " of unexported method") + } + t = m.typ + iface := (*nonEmptyInterface)(v.val) + if iface.itab == nil { + panic("reflect: " + op + " of method on nil interface value") + } + fn = unsafe.Pointer(&iface.itab.fun[i]) + rcvr = iface.word + } else { + ut := v.typ.uncommon() + if ut == nil || i < 0 || i >= len(ut.methods) { + panic("reflect: internal error: invalid method index") + } + m := &ut.methods[i] + if m.pkgPath != nil { + panic("reflect: " + op + " of unexported method") + } + fn = unsafe.Pointer(&m.tfn) + t = m.mtyp + rcvr = v.iword() + } + return +} + +// align returns the result of rounding x up to a multiple of n. +// n must be a power of two. +func align(x, n uintptr) uintptr { + return (x + n - 1) &^ (n - 1) +} + +// frameSize returns the sizes of the argument and result frame +// for a function of the given type. The rcvr bool specifies whether +// a one-word receiver should be included in the total. +func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) { + if rcvr { + // extra word for receiver interface word + total += ptrSize + } + + nin := t.NumIn() + in = -total + for i := 0; i < nin; i++ { + tv := t.In(i) + total = align(total, uintptr(tv.Align())) + total += tv.Size() + } + in += total + total = align(total, ptrSize) + nout := t.NumOut() + outOffset = total + out = -total + for i := 0; i < nout; i++ { + tv := t.Out(i) + total = align(total, uintptr(tv.Align())) + total += tv.Size() + } + out += total + + // total must be > 0 in order for &args[0] to be valid. + // the argument copying is going to round it up to + // a multiple of ptrSize anyway, so make it ptrSize to begin with. + if total < ptrSize { + total = ptrSize + } + + // round to pointer + total = align(total, ptrSize) + + return +} + // funcName returns the name of f, for use in error messages. func funcName(f func([]Value) []Value) string { pc := *(*uintptr)(unsafe.Pointer(&f)) @@ -897,7 +956,7 @@ func (v Value) CanInterface() bool { if v.flag == 0 { panic(&ValueError{"reflect.Value.CanInterface", Invalid}) } - return v.flag&(flagMethod|flagRO) == 0 + return v.flag&flagRO == 0 } // Interface returns v's current value as an interface{}. @@ -916,16 +975,15 @@ func valueInterface(v Value, safe bool) interface{} { if v.flag == 0 { panic(&ValueError{"reflect.Value.Interface", 0}) } - if v.flag&flagMethod != 0 { - panic("reflect.Value.Interface: cannot create interface value for method with bound receiver") - } - if safe && v.flag&flagRO != 0 { // Do not allow access to unexported values via Interface, // 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") } + if v.flag&flagMethod != 0 { + v = makeMethodValue("Interface", v) + } k := v.kind() if k == Interface { @@ -980,7 +1038,7 @@ func (v Value) IsNil() bool { switch k { case Chan, Func, Map, Ptr: if v.flag&flagMethod != 0 { - panic("reflect: IsNil of method Value") + return false } ptr := v.val if v.flag&flagIndir != 0 { @@ -1099,7 +1157,7 @@ func (v Value) MapKeys() []Value { // Method returns a function value corresponding to v's i'th method. // The arguments to a Call on the returned function should not include // a receiver; the returned function will always use v as the receiver. -// Method panics if i is out of range. +// Method panics if i is out of range or if v is a nil interface value. func (v Value) Method(i int) Value { if v.typ == nil { panic(&ValueError{"reflect.Value.Method", Invalid}) @@ -1107,7 +1165,10 @@ func (v Value) Method(i int) Value { if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() { panic("reflect: Method index out of range") } - fl := v.flag & (flagRO | flagAddr | flagIndir) + if v.typ.Kind() == Interface && v.IsNil() { + panic("reflect: Method on nil interface value") + } + fl := v.flag & (flagRO | flagIndir) fl |= flag(Func) << flagKindShift fl |= flag(i)<<flagMethodShift | flagMethod return Value{v.typ, v.val, fl} @@ -1231,7 +1292,15 @@ func (v Value) Pointer() uintptr { return uintptr(p) case Func: if v.flag&flagMethod != 0 { - panic("reflect.Value.Pointer of method Value") + // As the doc comment says, the returned pointer is an + // underlying code pointer but not necessarily enough to + // identify a single function uniquely. All method expressions + // created via reflect have the same underlying code pointer, + // so their Pointers are equal. The function used here must + // match the one used in makeMethodValue. + // This is not properly implemented for gccgo. + f := Zero + return **(**uintptr)(unsafe.Pointer(&f)) } p := v.val if v.flag&flagIndir != 0 { @@ -1266,7 +1335,7 @@ func (v Value) Recv() (x Value, ok bool) { func (v Value) recv(nb bool) (val Value, ok bool) { tt := (*chanType)(unsafe.Pointer(v.typ)) if ChanDir(tt.dir)&RecvDir == 0 { - panic("recv on send-only channel") + panic("reflect: recv on send-only channel") } word, selected, ok := chanrecv(v.typ, *(*iword)(v.iword()), nb) if selected { @@ -1294,7 +1363,7 @@ func (v Value) Send(x Value) { func (v Value) send(x Value, nb bool) (selected bool) { tt := (*chanType)(unsafe.Pointer(v.typ)) if ChanDir(tt.dir)&SendDir == 0 { - panic("send on recv-only channel") + panic("reflect: send on recv-only channel") } x.mustBeExported() x = x.assignTo("reflect.Value.Send", tt.elem, nil) @@ -1467,7 +1536,7 @@ func (v Value) SetString(x string) { } // Slice returns a slice of v. -// It panics if v's Kind is not Array, Slice, or String. +// 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 @@ -1577,7 +1646,7 @@ func (v Value) Type() Type { // Method on interface. tt := (*interfaceType)(unsafe.Pointer(v.typ)) if i < 0 || i >= len(tt.methods) { - panic("reflect: broken Value") + panic("reflect: internal error: invalid method index") } m := &tt.methods[i] return toType(m.typ) @@ -1585,7 +1654,7 @@ func (v Value) Type() Type { // Method on concrete type. ut := v.typ.uncommon() if ut == nil || i < 0 || i >= len(ut.methods) { - panic("reflect: broken Value") + panic("reflect: internal error: invalid method index") } m := &ut.methods[i] return toType(m.mtyp) @@ -1634,14 +1703,22 @@ func (v Value) UnsafeAddr() uintptr { } // StringHeader is the runtime representation of a string. -// It cannot be used safely or portably. +// It cannot be used safely or portably and its representation may +// change in a later release. +// Moreover, the Data field is not sufficient to guarantee the data +// it references will not be garbage collected, so programs must keep +// a separate, correctly typed pointer to the underlying data. type StringHeader struct { Data uintptr Len int } // SliceHeader is the runtime representation of a slice. -// It cannot be used safely or portably. +// It cannot be used safely or portably and its representation may +// change in a later release. +// Moreover, the Data field is not sufficient to guarantee the data +// it references will not be garbage collected, so programs must keep +// a separate, correctly typed pointer to the underlying data. type SliceHeader struct { Data uintptr Len int @@ -1810,8 +1887,9 @@ type SelectCase struct { } // Select executes a select operation described by the list of cases. -// Like the Go select statement, it blocks until one of the cases can -// proceed and then executes that case. It returns the index of the chosen case +// 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). @@ -2028,7 +2106,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value { // For a conversion to an interface type, target is a suggested scratch space to use. 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()) + v = makeMethodValue(context, v) } switch { @@ -2062,7 +2140,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { // 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") + v = makeMethodValue("Convert", v) } op := convertOp(t.common(), v.typ) if op == nil { |