aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect/value.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r--libgo/go/reflect/value.go119
1 files changed, 74 insertions, 45 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 147a9c4..e60f84f 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -5,6 +5,7 @@
package reflect
import (
+ "internal/unsafeheader"
"math"
"runtime"
"unsafe"
@@ -178,6 +179,17 @@ func methodName() string {
return f.Name()
}
+// methodNameSkip is like methodName, but skips another stack frame.
+// This is a separate function so that reflect.flag.mustBe will be inlined.
+func methodNameSkip() string {
+ pc, _, _, _ := runtime.Caller(3)
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ return "unknown method"
+ }
+ return f.Name()
+}
+
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
@@ -217,10 +229,10 @@ func (f flag) mustBeExported() {
func (f flag) mustBeExportedSlow() {
if f == 0 {
- panic(&ValueError{methodName(), Invalid})
+ panic(&ValueError{methodNameSkip(), Invalid})
}
if f&flagRO != 0 {
- panic("reflect: " + methodName() + " using value obtained using unexported field")
+ panic("reflect: " + methodNameSkip() + " using value obtained using unexported field")
}
}
@@ -235,14 +247,14 @@ func (f flag) mustBeAssignable() {
func (f flag) mustBeAssignableSlow() {
if f == 0 {
- panic(&ValueError{methodName(), Invalid})
+ panic(&ValueError{methodNameSkip(), Invalid})
}
// Assignable if addressable and not read-only.
if f&flagRO != 0 {
- panic("reflect: " + methodName() + " using value obtained using unexported field")
+ panic("reflect: " + methodNameSkip() + " using value obtained using unexported field")
}
if f&flagAddr == 0 {
- panic("reflect: " + methodName() + " using unaddressable value")
+ panic("reflect: " + methodNameSkip() + " using unaddressable value")
}
}
@@ -255,7 +267,10 @@ func (v Value) Addr() Value {
if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)}
+ // Preserve flagRO instead of using v.flag.ro() so that
+ // v.Addr().Elem() is equivalent to v (#32772)
+ fl := v.flag & flagRO
+ return Value{v.typ.ptrTo(), v.ptr, fl | flag(Ptr)}
}
// Bool returns v's underlying value.
@@ -563,7 +578,7 @@ func (v Value) Cap() int {
return chancap(v.pointer())
case Slice:
// Slice is always bigger than a word; assume flagIndir.
- return (*sliceHeader)(v.ptr).Cap
+ return (*unsafeheader.Slice)(v.ptr).Cap
}
panic(&ValueError{"reflect.Value.Cap", v.kind()})
}
@@ -742,7 +757,7 @@ func (v Value) Index(i int) Value {
case Slice:
// Element flag same as Elem of Ptr.
// Addressable, indirect, possibly read-only.
- s := (*sliceHeader)(v.ptr)
+ s := (*unsafeheader.Slice)(v.ptr)
if uint(i) >= uint(s.Len) {
panic("reflect: slice index out of range")
}
@@ -753,7 +768,7 @@ func (v Value) Index(i int) Value {
return Value{typ, val, fl}
case String:
- s := (*stringHeader)(v.ptr)
+ s := (*unsafeheader.String)(v.ptr)
if uint(i) >= uint(s.Len) {
panic("reflect: string index out of range")
}
@@ -950,10 +965,10 @@ func (v Value) Len() int {
return maplen(v.pointer())
case Slice:
// Slice is bigger than a word; assume flagIndir.
- return (*sliceHeader)(v.ptr).Len
+ return (*unsafeheader.Slice)(v.ptr).Len
case String:
// String is bigger than a word; assume flagIndir.
- return (*stringHeader)(v.ptr).Len
+ return (*unsafeheader.String)(v.ptr).Len
}
panic(&ValueError{"reflect.Value.Len", v.kind()})
}
@@ -1122,7 +1137,7 @@ func (v Value) Method(i int) Value {
if v.typ.Kind() == Interface && v.IsNil() {
panic("reflect: Method on nil interface value")
}
- fl := v.flag & (flagStickyRO | flagIndir) // Clear flagEmbedRO
+ fl := v.flag.ro() | (v.flag & flagIndir)
fl |= flag(Func)
fl |= flag(i)<<flagMethodShift | flagMethod
return Value{v.typ, v.ptr, fl}
@@ -1429,7 +1444,7 @@ func (v Value) SetInt(x int64) {
func (v Value) SetLen(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*sliceHeader)(v.ptr)
+ s := (*unsafeheader.Slice)(v.ptr)
if uint(n) > uint(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
@@ -1442,7 +1457,7 @@ func (v Value) SetLen(n int) {
func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*sliceHeader)(v.ptr)
+ s := (*unsafeheader.Slice)(v.ptr)
if n < s.Len || n > s.Cap {
panic("reflect: slice capacity out of range in SetCap")
}
@@ -1544,18 +1559,18 @@ func (v Value) Slice(i, j int) Value {
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*sliceHeader)(v.ptr)
+ s := (*unsafeheader.Slice)(v.ptr)
base = s.Data
cap = s.Cap
case String:
- s := (*stringHeader)(v.ptr)
+ s := (*unsafeheader.String)(v.ptr)
if i < 0 || j < i || j > s.Len {
panic("reflect.Value.Slice: string slice index out of bounds")
}
- var t stringHeader
+ var t unsafeheader.String
if i < s.Len {
- t = stringHeader{arrayAt(s.Data, i, 1, "i < s.Len"), j - i}
+ t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i}
}
return Value{v.typ, unsafe.Pointer(&t), v.flag}
}
@@ -1567,8 +1582,8 @@ func (v Value) Slice(i, j int) Value {
// Declare slice so that gc can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *sliceHeader to edit.
- s := (*sliceHeader)(unsafe.Pointer(&x))
+ // Reinterpret as *unsafeheader.Slice to edit.
+ s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
s.Len = j - i
s.Cap = cap - i
if cap-i > 0 {
@@ -1606,7 +1621,7 @@ func (v Value) Slice3(i, j, k int) Value {
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*sliceHeader)(v.ptr)
+ s := (*unsafeheader.Slice)(v.ptr)
base = s.Data
cap = s.Cap
}
@@ -1619,8 +1634,8 @@ func (v Value) Slice3(i, j, k int) Value {
// can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *sliceHeader to edit.
- s := (*sliceHeader)(unsafe.Pointer(&x))
+ // Reinterpret as *unsafeheader.Slice to edit.
+ s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
s.Len = j - i
s.Cap = k - i
if k-i > 0 {
@@ -1757,12 +1772,6 @@ type StringHeader struct {
Len int
}
-// stringHeader is a safe version of StringHeader used within this package.
-type stringHeader struct {
- Data unsafe.Pointer
- Len int
-}
-
// SliceHeader is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
@@ -1775,13 +1784,6 @@ type SliceHeader struct {
Cap int
}
-// sliceHeader is a safe version of SliceHeader used within this package.
-type sliceHeader struct {
- Data unsafe.Pointer
- Len int
- Cap int
-}
-
func typesMustMatch(what string, t1, t2 Type) {
if t1 != t2 {
panic(what + ": " + t1.String() + " != " + t2.String())
@@ -1882,22 +1884,22 @@ func Copy(dst, src Value) int {
typesMustMatch("reflect.Copy", de, se)
}
- var ds, ss sliceHeader
+ var ds, ss unsafeheader.Slice
if dk == Array {
ds.Data = dst.ptr
ds.Len = dst.Len()
ds.Cap = ds.Len
} else {
- ds = *(*sliceHeader)(dst.ptr)
+ ds = *(*unsafeheader.Slice)(dst.ptr)
}
if sk == Array {
ss.Data = src.ptr
ss.Len = src.Len()
ss.Cap = ss.Len
} else if sk == Slice {
- ss = *(*sliceHeader)(src.ptr)
+ ss = *(*unsafeheader.Slice)(src.ptr)
} else {
- sh := *(*stringHeader)(src.ptr)
+ sh := *(*unsafeheader.String)(src.ptr)
ss.Data = sh.Data
ss.Len = sh.Len
ss.Cap = sh.Len
@@ -1964,11 +1966,23 @@ type SelectCase struct {
// 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).
+// Select supports a maximum of 65536 cases.
func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
+ if len(cases) > 65536 {
+ panic("reflect.Select: too many cases (max 65536)")
+ }
// 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))
+ var runcases []runtimeSelect
+ if len(cases) > 4 {
+ // Slice is heap allocated due to runtime dependent capacity.
+ runcases = make([]runtimeSelect, len(cases))
+ } else {
+ // Slice can be stack allocated due to constant capacity.
+ runcases = make([]runtimeSelect, len(cases), 4)
+ }
+
haveDefault := false
for i, c := range cases {
rc := &runcases[i]
@@ -2073,7 +2087,7 @@ func MakeSlice(typ Type, len, cap int) Value {
panic("reflect.MakeSlice: len > cap")
}
- s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+ s := unsafeheader.Slice{Data: unsafe_NewArray(typ.Elem().(*rtype), cap), Len: len, Cap: cap}
return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)}
}
@@ -2175,6 +2189,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.
+// target must be initialized memory (or nil).
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
if v.flag&flagMethod != 0 {
v = makeMethodValue(context, v)
@@ -2345,6 +2360,14 @@ func makeFloat(f flag, v float64, t Type) Value {
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
+// makeFloat returns a Value of type t equal to v, where t is a float32 type.
+func makeFloat32(f flag, v float32, t Type) Value {
+ typ := t.common()
+ ptr := unsafe_New(typ)
+ *(*float32)(ptr) = v
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
+}
+
// 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 {
@@ -2417,6 +2440,12 @@ func cvtUintFloat(v Value, t Type) Value {
// convertOp: floatXX -> floatXX
func cvtFloat(v Value, t Type) Value {
+ if v.Type().Kind() == Float32 && t.Kind() == Float32 {
+ // Don't do any conversion if both types have underlying type float32.
+ // This avoids converting to float64 and back, which will
+ // convert a signaling NaN to a quiet NaN. See issue 36400.
+ return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t)
+ }
return makeFloat(v.flag.ro(), v.Float(), t)
}
@@ -2427,12 +2456,12 @@ func cvtComplex(v Value, t Type) Value {
// convertOp: intXX -> string
func cvtIntString(v Value, t Type) Value {
- return makeString(v.flag.ro(), string(v.Int()), t)
+ return makeString(v.flag.ro(), string(rune(v.Int())), t)
}
// convertOp: uintXX -> string
func cvtUintString(v Value, t Type) Value {
- return makeString(v.flag.ro(), string(v.Uint()), t)
+ return makeString(v.flag.ro(), string(rune(v.Uint())), t)
}
// convertOp: []byte -> string
@@ -2556,7 +2585,7 @@ 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
+func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int
//go:noescape
func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr