diff options
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r-- | libgo/go/reflect/value.go | 455 |
1 files changed, 364 insertions, 91 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 300ef1a..54ebd6f 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -5,6 +5,8 @@ package reflect import ( + "errors" + "internal/goarch" "internal/itoa" "internal/unsafeheader" "math" @@ -12,8 +14,6 @@ import ( "unsafe" ) -const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const - // Value is the reflection interface to a Go value. // // Not all methods apply to all kinds of values. Restrictions, @@ -91,10 +91,10 @@ func (f flag) ro() flag { } // pointer returns the underlying pointer represented by v. -// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer -// if v.Kind() == Ptr, the base type must not be go:notinheap. +// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer +// if v.Kind() == Pointer, the base type must not be go:notinheap. func (v Value) pointer() unsafe.Pointer { - if v.typ.size != ptrSize || !v.typ.pointers() { + if v.typ.size != goarch.PtrSize || !v.typ.pointers() { panic("can't call pointer on a non-pointer Value") } if v.flag&flagIndir != 0 { @@ -104,9 +104,9 @@ func (v Value) pointer() unsafe.Pointer { } // packEface converts v to the empty interface. -func packEface(v Value) interface{} { +func packEface(v Value) any { t := v.typ - var i interface{} + var i any e := (*emptyInterface)(unsafe.Pointer(&i)) // First, fill in the data portion of the interface. switch { @@ -141,7 +141,7 @@ func packEface(v Value) interface{} { } // unpackEface converts the empty interface i to a Value. -func unpackEface(i interface{}) Value { +func unpackEface(i any) Value { e := (*emptyInterface)(unsafe.Pointer(&i)) // NOTE: don't read e.word until we know whether it is really a pointer or not. t := e.typ @@ -272,7 +272,7 @@ func (v Value) Addr() Value { // 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)} + return Value{v.typ.ptrTo(), v.ptr, fl | flag(Pointer)} } // Bool returns v's underlying value. @@ -349,7 +349,7 @@ func (v Value) CallSlice(in []Value) []Value { return v.call("CallSlice", in) } -var callGC bool // for testing; see TestCallMethodJump +var callGC bool // for testing; see TestCallMethodJump and TestCallArgLive const debugReflectCall = false @@ -596,6 +596,16 @@ func (v Value) Close() { chanclose(v.pointer()) } +// CanComplex reports whether Complex can be used without panicking. +func (v Value) CanComplex() bool { + switch v.kind() { + case Complex64, Complex128: + return true + default: + return false + } +} + // Complex returns v's underlying value, as a complex128. // It panics if v's Kind is not Complex64 or Complex128 func (v Value) Complex() complex128 { @@ -611,17 +621,17 @@ func (v Value) Complex() complex128 { // Elem returns the value that the interface v contains // or that the pointer v points to. -// It panics if v's Kind is not Interface or Ptr. +// It panics if v's Kind is not Interface or Pointer. // It returns the zero Value if v is nil. func (v Value) Elem() Value { k := v.kind() switch k { case Interface: - var eface interface{} + var eface any if v.typ.NumMethod() == 0 { - eface = *(*interface{})(v.ptr) + eface = *(*any)(v.ptr) } else { - eface = (interface{})(*(*interface { + eface = (any)(*(*interface { M() })(v.ptr)) } @@ -630,9 +640,24 @@ func (v Value) Elem() Value { x.flag |= v.flag.ro() } return x - case Ptr: + case Pointer: ptr := v.ptr if v.flag&flagIndir != 0 { + if ifaceIndir(v.typ) { + // This is a pointer to a not-in-heap object. ptr points to a uintptr + // in the heap. That uintptr is the address of a not-in-heap object. + // In general, pointers to not-in-heap objects can be total junk. + // But Elem() is asking to dereference it, so the user has asserted + // that at least it is a valid pointer (not just an integer stored in + // a pointer slot). So let's check, to make sure that it isn't a pointer + // that the runtime will crash on if it sees it during GC or write barriers. + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! That makes the test pretty easy. + // See issue 48399. + if !verifyNotInHeapPtr(*(*uintptr)(ptr)) { + panic("reflect: reflect.Value.Elem on an invalid notinheap pointer") + } + } ptr = *(*unsafe.Pointer)(ptr) } // The returned value's address is v's value. @@ -681,7 +706,8 @@ func (v Value) Field(i int) Value { } // FieldByIndex returns the nested field corresponding to index. -// It panics if v's Kind is not struct. +// It panics if evaluation requires stepping through a nil +// pointer or a field that is not a struct. func (v Value) FieldByIndex(index []int) Value { if len(index) == 1 { return v.Field(index[0]) @@ -689,7 +715,7 @@ func (v Value) FieldByIndex(index []int) Value { v.mustBe(Struct) for i, x := range index { if i > 0 { - if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct { + if v.Kind() == Pointer && v.typ.Elem().Kind() == Struct { if v.IsNil() { panic("reflect: indirection through nil pointer to embedded struct") } @@ -701,6 +727,29 @@ func (v Value) FieldByIndex(index []int) Value { return v } +// FieldByIndexErr returns the nested field corresponding to index. +// It returns an error if evaluation requires stepping through a nil +// pointer, but panics if it must step through a field that +// is not a struct. +func (v Value) FieldByIndexErr(index []int) (Value, error) { + if len(index) == 1 { + return v.Field(index[0]), nil + } + v.mustBe(Struct) + for i, x := range index { + if i > 0 { + if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct { + if v.IsNil() { + return Value{}, errors.New("reflect: indirection through nil pointer to embedded struct field " + v.typ.Elem().Name()) + } + v = v.Elem() + } + } + v = v.Field(x) + } + return v, nil +} + // FieldByName returns the struct field with the given name. // It returns the zero Value if no field was found. // It panics if v's Kind is not struct. @@ -723,6 +772,16 @@ func (v Value) FieldByNameFunc(match func(string) bool) Value { return Value{} } +// CanFloat reports whether Float can be used without panicking. +func (v Value) CanFloat() bool { + switch v.kind() { + case Float32, Float64: + return true + default: + return false + } +} + // Float returns v's underlying value, as a float64. // It panics if v's Kind is not Float32 or Float64 func (v Value) Float() float64 { @@ -760,7 +819,7 @@ func (v Value) Index(i int) Value { return Value{typ, val, fl} case Slice: - // Element flag same as Elem of Ptr. + // Element flag same as Elem of Pointer. // Addressable, indirect, possibly read-only. s := (*unsafeheader.Slice)(v.ptr) if uint(i) >= uint(s.Len) { @@ -784,6 +843,16 @@ func (v Value) Index(i int) Value { panic(&ValueError{"reflect.Value.Index", v.kind()}) } +// CanInt reports whether Int can be used without panicking. +func (v Value) CanInt() bool { + switch v.kind() { + case Int, Int8, Int16, Int32, Int64: + return true + default: + return false + } +} + // Int returns v's underlying value, as an int64. // It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64. func (v Value) Int() int64 { @@ -817,11 +886,11 @@ func (v Value) CanInterface() bool { // var i interface{} = (v's underlying value) // It panics if the Value was obtained by accessing // unexported struct fields. -func (v Value) Interface() (i interface{}) { +func (v Value) Interface() (i any) { return valueInterface(v, true) } -func valueInterface(v Value, safe bool) interface{} { +func valueInterface(v Value, safe bool) any { if v.flag == 0 { panic(&ValueError{"reflect.Value.Interface", Invalid}) } @@ -850,7 +919,7 @@ func valueInterface(v Value, safe bool) interface{} { // Empty interface has one layout, all interfaces with // methods have a second layout. if v.NumMethod() == 0 { - return *(*interface{})(v.ptr) + return *(*any)(v.ptr) } return *(*interface { M() @@ -890,7 +959,7 @@ func (v Value) InterfaceData() [2]uintptr { func (v Value) IsNil() bool { k := v.kind() switch k { - case Chan, Func, Map, Ptr, UnsafePointer: + case Chan, Func, Map, Pointer, UnsafePointer: if v.flag&flagMethod != 0 { return false } @@ -938,7 +1007,7 @@ func (v Value) IsZero() bool { } } return true - case Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer: + case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer: return v.IsNil() case String: return v.Len() == 0 @@ -999,15 +1068,21 @@ 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", tt.key, nil) - var k unsafe.Pointer - if key.flag&flagIndir != 0 { - k = key.ptr + var e unsafe.Pointer + if key.kind() == String && tt.key.Kind() == String && tt.elem.size <= maxValSize { + k := *(*string)(key.ptr) + e = mapaccess_faststr(v.typ, v.pointer(), k) } else { - k = unsafe.Pointer(&key.ptr) + key = key.assignTo("reflect.Value.MapIndex", tt.key, nil) + var k unsafe.Pointer + if key.flag&flagIndir != 0 { + k = key.ptr + } else { + k = unsafe.Pointer(&key.ptr) + } + e = mapaccess(v.typ, v.pointer(), k) } - e := mapaccess(v.typ, v.pointer(), k) if e == nil { return Value{} } @@ -1033,11 +1108,12 @@ func (v Value) MapKeys() []Value { if m != nil { mlen = maplen(m) } - it := mapiterinit(v.typ, m) + var it hiter + mapiterinit(v.typ, m, &it) a := make([]Value, mlen) var i int for i = 0; i < len(a); i++ { - key := mapiterkey(it) + key := mapiterkey(&it) if key == nil { // Someone deleted an entry from the map since we // called maplen above. It's a data race, but nothing @@ -1045,59 +1121,154 @@ func (v Value) MapKeys() []Value { break } a[i] = copyVal(keyType, fl, key) - mapiternext(it) + mapiternext(&it) } return a[:i] } +// hiter's structure matches runtime.hiter's structure. +// Having a clone here allows us to embed a map iterator +// inside type MapIter so that MapIters can be re-used +// without doing any allocations. +type hiter struct { + key unsafe.Pointer + elem unsafe.Pointer + t unsafe.Pointer + h unsafe.Pointer + buckets unsafe.Pointer + bptr unsafe.Pointer + overflow *[]unsafe.Pointer + oldoverflow *[]unsafe.Pointer + startBucket uintptr + offset uint8 + wrapped bool + B uint8 + i uint8 + bucket uintptr + checkBucket uintptr +} + +func (h *hiter) initialized() bool { + return h.t != nil +} + // A MapIter is an iterator for ranging over a map. // See Value.MapRange. type MapIter struct { - m Value - it unsafe.Pointer + m Value + hiter hiter } -// Key returns the key of the iterator's current map entry. -func (it *MapIter) Key() Value { - if it.it == nil { +// Key returns the key of iter's current map entry. +func (iter *MapIter) Key() Value { + if !iter.hiter.initialized() { panic("MapIter.Key called before Next") } - if mapiterkey(it.it) == nil { + iterkey := mapiterkey(&iter.hiter) + if iterkey == nil { panic("MapIter.Key called on exhausted iterator") } - t := (*mapType)(unsafe.Pointer(it.m.typ)) + t := (*mapType)(unsafe.Pointer(iter.m.typ)) ktype := t.key - return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), mapiterkey(it.it)) + return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey) } -// Value returns the value of the iterator's current map entry. -func (it *MapIter) Value() Value { - if it.it == nil { +// SetIterKey assigns to v the key of iter's current map entry. +// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value. +// As in Go, the key must be assignable to v's type. +func (v Value) SetIterKey(iter *MapIter) { + if !iter.hiter.initialized() { + panic("reflect: Value.SetIterKey called before Next") + } + iterkey := mapiterkey(&iter.hiter) + if iterkey == nil { + panic("reflect: Value.SetIterKey called on exhausted iterator") + } + + v.mustBeAssignable() + var target unsafe.Pointer + if v.kind() == Interface { + target = v.ptr + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ)) + ktype := t.key + + key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir} + key = key.assignTo("reflect.MapIter.SetKey", v.typ, target) + typedmemmove(v.typ, v.ptr, key.ptr) +} + +// Value returns the value of iter's current map entry. +func (iter *MapIter) Value() Value { + if !iter.hiter.initialized() { panic("MapIter.Value called before Next") } - if mapiterkey(it.it) == nil { + iterelem := mapiterelem(&iter.hiter) + if iterelem == nil { panic("MapIter.Value called on exhausted iterator") } - t := (*mapType)(unsafe.Pointer(it.m.typ)) + t := (*mapType)(unsafe.Pointer(iter.m.typ)) vtype := t.elem - return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it)) + return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem) +} + +// SetIterValue assigns to v the value of iter's current map entry. +// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value. +// As in Go, the value must be assignable to v's type. +func (v Value) SetIterValue(iter *MapIter) { + if !iter.hiter.initialized() { + panic("reflect: Value.SetIterValue called before Next") + } + iterelem := mapiterelem(&iter.hiter) + if iterelem == nil { + panic("reflect: Value.SetIterValue called on exhausted iterator") + } + + v.mustBeAssignable() + var target unsafe.Pointer + if v.kind() == Interface { + target = v.ptr + } + + t := (*mapType)(unsafe.Pointer(iter.m.typ)) + vtype := t.elem + + elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir} + elem = elem.assignTo("reflect.MapIter.SetValue", v.typ, target) + typedmemmove(v.typ, v.ptr, elem.ptr) } // Next advances the map iterator and reports whether there is another -// entry. It returns false when the iterator is exhausted; subsequent +// entry. It returns false when iter is exhausted; subsequent // calls to Key, Value, or Next will panic. -func (it *MapIter) Next() bool { - if it.it == nil { - it.it = mapiterinit(it.m.typ, it.m.pointer()) +func (iter *MapIter) Next() bool { + if !iter.m.IsValid() { + panic("MapIter.Next called on an iterator that does not have an associated map Value") + } + if !iter.hiter.initialized() { + mapiterinit(iter.m.typ, iter.m.pointer(), &iter.hiter) } else { - if mapiterkey(it.it) == nil { + if mapiterkey(&iter.hiter) == nil { panic("MapIter.Next called on exhausted iterator") } - mapiternext(it.it) + mapiternext(&iter.hiter) } - return mapiterkey(it.it) != nil + return mapiterkey(&iter.hiter) != nil +} + +// Reset modifies iter to iterate over v. +// It panics if v's Kind is not Map and v is not the zero Value. +// Reset(Value{}) causes iter to not to refer to any map, +// which may allow the previously iterated-over map to be garbage collected. +func (iter *MapIter) Reset(v Value) { + if v.IsValid() { + v.mustBe(Map) + } + iter.m = v + iter.hiter = hiter{} } // MapRange returns a range iterator for a map. @@ -1260,7 +1431,7 @@ func (v Value) OverflowUint(x uint64) bool { // It returns uintptr instead of unsafe.Pointer so that // 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. +// It panics if v's Kind is not Chan, Func, Map, Pointer, Slice, or UnsafePointer. // // If v's Kind is Func, the returned pointer is an underlying // code pointer, but not necessarily enough to identify a @@ -1270,22 +1441,34 @@ func (v Value) OverflowUint(x uint64) bool { // If v's Kind is Slice, the returned pointer is to the first // element of the slice. If the slice is nil the returned value // is 0. If the slice is empty but non-nil the return value is non-zero. +// +// It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result. func (v Value) Pointer() uintptr { - // TODO: deprecate k := v.kind() switch k { - case Ptr: + case Pointer: if v.typ.ptrdata == 0 { - // Handle pointers to go:notinheap types directly, - // so we never materialize such pointers as an - // unsafe.Pointer. (Such pointers are always indirect.) - // See issue 42076. - return *(*uintptr)(v.ptr) + val := *(*uintptr)(v.ptr) + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! See comment in Value.Elem and issue #48399. + if !verifyNotInHeapPtr(val) { + panic("reflect: reflect.Value.Pointer on an invalid notinheap pointer") + } + return val } fallthrough case Chan, Map, UnsafePointer: return uintptr(v.pointer()) case Func: + if v.flag&flagMethod != 0 { + // 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. + return methodValueCallCodePtr() + } p := v.pointer() // Non-nil func value points at data block. // First word of data block is actual code. @@ -1499,6 +1682,25 @@ func (v Value) SetMapIndex(key, elem Value) { v.mustBeExported() key.mustBeExported() tt := (*mapType)(unsafe.Pointer(v.typ)) + + if key.kind() == String && tt.key.Kind() == String && tt.elem.size <= maxValSize { + k := *(*string)(key.ptr) + if elem.typ == nil { + mapdelete_faststr(v.typ, v.pointer(), k) + return + } + elem.mustBeExported() + elem = elem.assignTo("reflect.Value.SetMapIndex", tt.elem, nil) + var e unsafe.Pointer + if elem.flag&flagIndir != 0 { + e = elem.ptr + } else { + e = unsafe.Pointer(&elem.ptr) + } + mapassign_faststr(v.typ, v.pointer(), k, e) + return + } + key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil) var k unsafe.Pointer if key.flag&flagIndir != 0 { @@ -1744,6 +1946,16 @@ func (v Value) Type() Type { return toType(m.mtyp) } +// CanUint reports whether Uint can be used without panicking. +func (v Value) CanUint() bool { + switch v.kind() { + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + default: + return false + } +} + // Uint returns v's underlying value, as a uint64. // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. func (v Value) Uint() uint64 { @@ -1771,11 +1983,12 @@ func (v Value) Uint() uint64 { // which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr()) // and make an exception. -// UnsafeAddr returns a pointer to v's data. +// UnsafeAddr returns a pointer to v's data, as a uintptr. // It is for advanced clients that also import the "unsafe" package. // It panics if v is not addressable. +// +// It's preferred to use uintptr(Value.Addr().UnsafePointer()) to get the equivalent result. func (v Value) UnsafeAddr() uintptr { - // TODO: deprecate if v.typ == nil { panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid}) } @@ -1785,6 +1998,57 @@ func (v Value) UnsafeAddr() uintptr { return uintptr(v.ptr) } +// UnsafePointer returns v's value as a unsafe.Pointer. +// It panics if v's Kind is not Chan, Func, Map, Pointer, 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. +// +// If v's Kind is Slice, the returned pointer is to the first +// element of the slice. If the slice is nil the returned value +// is nil. If the slice is empty but non-nil the return value is non-nil. +func (v Value) UnsafePointer() unsafe.Pointer { + k := v.kind() + switch k { + case Pointer: + if v.typ.ptrdata == 0 { + // Since it is a not-in-heap pointer, all pointers to the heap are + // forbidden! See comment in Value.Elem and issue #48399. + if !verifyNotInHeapPtr(*(*uintptr)(v.ptr)) { + panic("reflect: reflect.Value.UnsafePointer on an invalid notinheap pointer") + } + return *(*unsafe.Pointer)(v.ptr) + } + fallthrough + case Chan, Map, UnsafePointer: + return v.pointer() + case Func: + if v.flag&flagMethod != 0 { + // 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. + code := methodValueCallCodePtr() + return *(*unsafe.Pointer)(unsafe.Pointer(&code)) + } + p := v.pointer() + // Non-nil func value points at data block. + // First word of data block is actual code. + if p != nil { + p = *(*unsafe.Pointer)(p) + } + return p + + case Slice: + return (*unsafeheader.Slice)(v.ptr).Data + } + panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()}) +} + // StringHeader is the runtime representation of a string. // It cannot be used safely or portably and its representation may // change in a later release. @@ -1840,11 +2104,12 @@ func grow(s Value, extra int) (Value, int, int) { if m == 0 { m = extra } else { + const threshold = 256 for m < i1 { - if i0 < 1024 { + if i0 < threshold { m += m } else { - m += m / 4 + m += (m + 3*threshold) / 4 } } } @@ -2151,7 +2416,7 @@ func MakeMapWithSize(typ Type, n int) Value { // If v is a nil pointer, Indirect returns a zero Value. // If v is not a pointer, Indirect returns v. func Indirect(v Value) Value { - if v.Kind() != Ptr { + if v.Kind() != Pointer { return v } return v.Elem() @@ -2159,7 +2424,7 @@ func Indirect(v Value) Value { // ValueOf returns a new Value initialized to the concrete value // stored in the interface i. ValueOf(nil) returns the zero Value. -func ValueOf(i interface{}) Value { +func ValueOf(i any) Value { if i == nil { return Value{} } @@ -2204,7 +2469,7 @@ const maxZero = 1024 var zeroVal [maxZero]byte // New returns a Value representing a pointer to a new zero value -// for the specified type. That is, the returned Value's Type is PtrTo(typ). +// for the specified type. That is, the returned Value's Type is PointerTo(typ). func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") @@ -2216,14 +2481,14 @@ func New(typ Type) Value { panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)") } ptr := unsafe_New(t) - fl := flag(Ptr) + fl := flag(Pointer) return Value{pt, ptr, fl} } // NewAt returns a Value representing a pointer to a value of the // specified type, using p as that pointer. func NewAt(typ Type, p unsafe.Pointer) Value { - fl := flag(Ptr) + fl := flag(Pointer) t := typ.(*rtype) return Value{t.ptrTo(), p, fl} } @@ -2257,7 +2522,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value } x := valueInterface(v, false) if dst.NumMethod() == 0 { - *(*interface{})(target) = x + *(*any)(target) = x } else { ifaceE2I(dst, x, target) } @@ -2292,10 +2557,9 @@ func (v Value) CanConvert(t Type) bool { // Currently the only conversion that is OK in terms of type // but that can panic depending on the value is converting // from slice to pointer-to-array. - if vt.Kind() == Slice && t.Kind() == Ptr && t.Elem().Kind() == Array { + if vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array { n := t.Elem().Len() - h := (*unsafeheader.Slice)(v.ptr) - if n > h.Len { + if n > v.Len() { return false } } @@ -2363,7 +2627,7 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { } // "x is a slice, T is a pointer-to-array type, // and the slice and array types have identical element types." - if dst.Kind() == Ptr && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() { + if dst.Kind() == Pointer && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() { return cvtSliceArrayPtr } @@ -2379,8 +2643,8 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { } // dst and src are non-defined pointer types with same underlying base type. - if dst.Kind() == Ptr && dst.Name() == "" && - src.Kind() == Ptr && src.Name() == "" && + if dst.Kind() == Pointer && dst.Name() == "" && + src.Kind() == Pointer && src.Name() == "" && haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) { return cvtDirect } @@ -2562,11 +2826,11 @@ func cvtStringRunes(v Value, t Type) Value { // convertOp: []T -> *[N]T func cvtSliceArrayPtr(v Value, t Type) Value { n := t.Elem().Len() - h := (*unsafeheader.Slice)(v.ptr) - if n > h.Len { - panic("reflect: cannot convert slice with length " + itoa.Itoa(h.Len) + " to pointer to array with length " + itoa.Itoa(n)) + if n > v.Len() { + panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to pointer to array with length " + itoa.Itoa(n)) } - return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Ptr)} + h := (*unsafeheader.Slice)(v.ptr) + return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Pointer)} } // convertOp: direct copy @@ -2589,7 +2853,7 @@ func cvtT2I(v Value, typ Type) Value { target := unsafe_New(typ.common()) x := valueInterface(v, false) if typ.NumMethod() == 0 { - *(*interface{})(target) = x + *(*any)(target) = x } else { ifaceE2I(typ.(*rtype), x, target) } @@ -2632,24 +2896,31 @@ func makemap(t *rtype, cap int) (m unsafe.Pointer) func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) //go:noescape +func mapaccess_faststr(t *rtype, m unsafe.Pointer, key string) (val unsafe.Pointer) + +//go:noescape func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) //go:noescape +func mapassign_faststr(t *rtype, m unsafe.Pointer, key string, 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 +func mapdelete_faststr(t *rtype, m unsafe.Pointer, key string) + +//go:noescape +func mapiterinit(t *rtype, m unsafe.Pointer, it *hiter) //go:noescape -func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer) +func mapiterkey(it *hiter) (key unsafe.Pointer) //go:noescape -func mapiterelem(it unsafe.Pointer) (elem unsafe.Pointer) +func mapiterelem(it *hiter) (elem unsafe.Pointer) //go:noescape -func mapiternext(it unsafe.Pointer) +func mapiternext(it *hiter) //go:noescape func maplen(m unsafe.Pointer) int @@ -2657,7 +2928,7 @@ func maplen(m unsafe.Pointer) int //go:linkname call runtime.reflectcall func call(typ *funcType, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) -func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) +func ifaceE2I(t *rtype, src any, dst unsafe.Pointer) // memmove copies size bytes to dst from src. No write barriers are used. //go:noescape @@ -2679,10 +2950,12 @@ func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int //go:noescape func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr +func verifyNotInHeapPtr(p uintptr) bool + // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. -func escapes(x interface{}) { +func escapes(x any) { if dummy.b { dummy.x = x } @@ -2690,5 +2963,5 @@ func escapes(x interface{}) { var dummy struct { b bool - x interface{} + x any } |