diff options
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r-- | libgo/go/reflect/value.go | 114 |
1 files changed, 73 insertions, 41 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 7cc4f7f8bfd..a924d8639a2 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -10,7 +10,7 @@ import ( "unsafe" ) -const ptrSize = unsafe.Sizeof((*byte)(nil)) +const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const const cannotSet = "cannot set value obtained from unexported struct field" // Value is the reflection interface to a Go value. @@ -30,6 +30,10 @@ const cannotSet = "cannot set value obtained from unexported struct field" // A Value can be used concurrently by multiple goroutines provided that // the underlying Go value can be used concurrently for the equivalent // direct operations. +// +// Using == on two Values does not compare the underlying values +// they represent, but rather the contents of the Value structs. +// To compare two Values, compare the results of the Interface method. type Value struct { // typ holds the type of the value represented by a Value. typ *rtype @@ -104,7 +108,7 @@ func packEface(v Value) interface{} { // TODO: pass safe boolean from valueInterface so // we don't need to copy if safe==true? c := unsafe_New(t) - memmove(c, ptr, t.size) + typedmemmove(t, c, ptr) ptr = c } e.word = ptr @@ -173,7 +177,7 @@ type emptyInterface struct { // nonEmptyInterface is the header for a interface value with methods. type nonEmptyInterface struct { - // see ../runtime/iface.c:/Itab + // see ../runtime/iface.go:/Itab itab *struct { typ *rtype // dynamic concrete type fun [100000]unsafe.Pointer // method table @@ -261,7 +265,7 @@ func (v Value) runes() []rune { return *(*[]rune)(v.ptr) } -// CanAddr returns true if the value's address can be obtained with Addr. +// CanAddr reports whether 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, // a field of an addressable struct, or the result of dereferencing a pointer. @@ -270,11 +274,11 @@ func (v Value) CanAddr() bool { return v.flag&flagAddr != 0 } -// CanSet returns true if the value of v can be changed. +// CanSet reports whether the value of v can be changed. // A Value can be changed only if it is addressable and was not // obtained by the use of unexported struct fields. // If CanSet returns false, calling Set or any type-specific -// setter (e.g., SetBool, SetInt64) will panic. +// setter (e.g., SetBool, SetInt) will panic. func (v Value) CanSet() bool { return v.flag&(flagAddr|flagRO) == flagAddr } @@ -295,8 +299,8 @@ 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. -// 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. +// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...). +// CallSlice panics if v's Kind is not Func or if v is not variadic. // It returns the output results as Values. // As in Go, each input argument must be assignable to the // type of the function's corresponding input parameter. @@ -622,7 +626,7 @@ func (v Value) Field(i int) Value { // Either flagIndir is set and v.ptr points at struct, // or flagIndir is not set and v.ptr is the actual struct data. // In the former case, we want v.ptr + offset. - // In the latter case, we must be have field.offset = 0, + // In the latter case, we must have field.offset = 0, // so v.ptr + field.offset is still okay. ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset) return Value{typ, ptr, fl} @@ -716,7 +720,7 @@ func (v Value) Index(i int) Value { } tt := (*sliceType)(unsafe.Pointer(v.typ)) typ := tt.elem - val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size) + val := arrayAt(s.Data, i, typ.size) fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind()) return Value{typ, val, fl} @@ -725,7 +729,7 @@ func (v Value) Index(i int) Value { if uint(i) >= uint(s.Len) { panic("reflect: string index out of range") } - p := unsafe.Pointer(uintptr(s.Data) + uintptr(i)) + p := arrayAt(s.Data, i, 1) fl := v.flag&flagRO | flag(Uint8) | flagIndir return Value{uint8Type, p, fl} } @@ -752,7 +756,7 @@ func (v Value) Int() int64 { panic(&ValueError{"reflect.Value.Int", v.kind()}) } -// CanInterface returns true if Interface can be used without panicking. +// CanInterface reports whether Interface can be used without panicking. func (v Value) CanInterface() bool { if v.flag == 0 { panic(&ValueError{"reflect.Value.CanInterface", Invalid}) @@ -849,7 +853,7 @@ func (v Value) IsNil() bool { panic(&ValueError{"reflect.Value.IsNil", v.kind()}) } -// IsValid returns true if v represents a value. +// IsValid reports whether v represents a value. // It returns false if v is the zero Value. // If IsValid returns false, all other methods except String panic. // Most functions and methods never return an invalid value. @@ -920,7 +924,7 @@ func (v Value) MapIndex(key Value) Value { // Copy result so future changes to the map // won't change the underlying value. c := unsafe_New(typ) - memmove(c, e, typ.size) + typedmemmove(typ, c, e) return Value{typ, c, fl | flagIndir} } else { return Value{typ, *(*unsafe.Pointer)(e), fl} @@ -958,7 +962,7 @@ func (v Value) MapKeys() []Value { // Copy result so future changes to the map // won't change the underlying value. c := unsafe_New(keyType) - memmove(c, key, keyType.size) + typedmemmove(keyType, c, key) a[i] = Value{keyType, c, fl | flagIndir} } else { a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl} @@ -1026,7 +1030,7 @@ func (v Value) NumField() int { return len(tt.fields) } -// OverflowComplex returns true if the complex128 x cannot be represented by v's type. +// OverflowComplex reports whether the complex128 x cannot be represented by v's type. // It panics if v's Kind is not Complex64 or Complex128. func (v Value) OverflowComplex(x complex128) bool { k := v.kind() @@ -1039,7 +1043,7 @@ func (v Value) OverflowComplex(x complex128) bool { panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()}) } -// OverflowFloat returns true if the float64 x cannot be represented by v's type. +// OverflowFloat reports whether the float64 x cannot be represented by v's type. // It panics if v's Kind is not Float32 or Float64. func (v Value) OverflowFloat(x float64) bool { k := v.kind() @@ -1059,7 +1063,7 @@ func overflowFloat32(x float64) bool { return math.MaxFloat32 < x && x <= math.MaxFloat64 } -// OverflowInt returns true if the int64 x cannot be represented by v's type. +// OverflowInt reports whether the int64 x cannot be represented by v's type. // It panics if v's Kind is not Int, Int8, int16, Int32, or Int64. func (v Value) OverflowInt(x int64) bool { k := v.kind() @@ -1072,7 +1076,7 @@ func (v Value) OverflowInt(x int64) bool { panic(&ValueError{"reflect.Value.OverflowInt", v.kind()}) } -// OverflowUint returns true if the uint64 x cannot be represented by v's type. +// OverflowUint reports whether the uint64 x cannot be represented by v's type. // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. func (v Value) OverflowUint(x uint64) bool { k := v.kind() @@ -1194,7 +1198,7 @@ func (v Value) Set(x Value) { } x = x.assignTo("reflect.Set", v.typ, target) if x.flag&flagIndir != 0 { - memmove(v.ptr, x.ptr, v.typ.size) + typedmemmove(v.typ, v.ptr, x.ptr) } else { *(*unsafe.Pointer)(v.ptr) = x.ptr } @@ -1408,7 +1412,7 @@ func (v Value) Slice(i, j int) Value { if i < 0 || j < i || j > s.Len { panic("reflect.Value.Slice: string slice index out of bounds") } - t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i} + t := stringHeader{arrayAt(s.Data, i, 1), j - i} return Value{v.typ, unsafe.Pointer(&t), v.flag} } @@ -1424,7 +1428,7 @@ func (v Value) Slice(i, j int) Value { s.Len = j - i s.Cap = cap - i if cap-i > 0 { - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size()) } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base @@ -1476,7 +1480,7 @@ func (v Value) Slice3(i, j, k int) Value { s.Len = j - i s.Cap = k - i if k-i > 0 { - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size()) } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base @@ -1490,6 +1494,8 @@ func (v Value) Slice3(i, j, k int) Value { // String is a special case because of Go's String method convention. // Unlike the other getters, it does not panic if v's Kind is not String. // Instead, it returns a string of the form "<T value>" where T is v's type. +// The fmt package treats Values specially. It does not call their String +// method implicitly but instead prints the concrete values they hold. func (v Value) String() string { switch k := v.kind(); k { case Invalid: @@ -1515,7 +1521,7 @@ func (v Value) TryRecv() (x Value, ok bool) { // TrySend attempts to send x on the channel v but will not block. // It panics if v's Kind is not Chan. -// It returns true if the value was sent, false otherwise. +// It reports whether the value was sent. // As in Go, x's value must be assignable to the channel's element type. func (v Value) TrySend(x Value) bool { v.mustBe(Chan) @@ -1633,6 +1639,12 @@ func typesMustMatch(what string, t1, t2 Type) { } } +// arrayAt returns the i-th element of p, a C-array whose elements are +// eltSize wide (in bytes). +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize) +} + // grow grows the slice s so that it can hold extra more values, allocating // more capacity if needed. It also returns the old and new slice lengths. func grow(s Value, extra int) (Value, int, int) { @@ -1708,27 +1720,23 @@ func Copy(dst, src Value) int { se := src.typ.Elem() typesMustMatch("reflect.Copy", de, se) - n := dst.Len() - if sn := src.Len(); n > sn { - n = sn - } - - // Copy via memmove. - var da, sa unsafe.Pointer + var ds, ss sliceHeader if dk == Array { - da = dst.ptr + ds.Data = dst.ptr + ds.Len = dst.Len() + ds.Cap = ds.Len } else { - da = (*sliceHeader)(dst.ptr).Data + ds = *(*sliceHeader)(dst.ptr) } - if src.flag&flagIndir == 0 { - sa = unsafe.Pointer(&src.ptr) - } else if sk == Array { - sa = src.ptr + if sk == Array { + ss.Data = src.ptr + ss.Len = src.Len() + ss.Cap = ss.Len } else { - sa = (*sliceHeader)(src.ptr).Data + ss = *(*sliceHeader)(src.ptr) } - memmove(da, sa, uintptr(n)*de.Size()) - return n + + return typedslicecopy(de.common(), ds, ss) } // A runtimeSelect is a single case passed to rselect. @@ -2269,7 +2277,7 @@ func cvtDirect(v Value, typ Type) Value { if f&flagAddr != 0 { // indirect, mutable word - make a copy c := unsafe_New(t) - memmove(c, ptr, t.size) + typedmemmove(t, c, ptr) ptr = c f &^= flagAddr } @@ -2311,17 +2319,41 @@ func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool func makechan(typ *rtype, size uint64) (ch unsafe.Pointer) func makemap(t *rtype) (m unsafe.Pointer) + +//go:noescape func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) + func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) + +//go:noescape func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer) + +// m escapes into the return value, but the caller of mapiterinit +// doesn't let the return value escape. +//go:noescape func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer + +//go:noescape func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer) + +//go:noescape func mapiternext(it unsafe.Pointer) + +//go:noescape func maplen(m unsafe.Pointer) int func call(typ *rtype, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) +// typedmemmove copies a value of type t to dst from src. +//go:noescape +func typedmemmove(t *rtype, dst, src unsafe.Pointer) + +// typedslicecopy copies a slice of elemType values from src to dst, +// returning the number of elements copied. +//go:noescape +func typedslicecopy(elemType *rtype, dst, src sliceHeader) int + //go:noescape //extern memmove func memmove(adst, asrc unsafe.Pointer, n uintptr) |