| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // This package defines a reflect.Value-like interface that uses unsafe.Pointers |
| // to reduce the amount of work for each operation, as compared with the |
| // reflect package. |
| // This is possible because the Marshaler is built for a specific type and |
| // therefore the type and structure is known in advance and checks normally |
| // performed by the reflect package are redundant. |
| // ASSUMPTIONS: |
| // - Go's interface implementation is two pointers, type followed by value. |
| // - reflect.Type is an interface with the runtime type as the concrete |
| // implementation. |
| package unsafevalue |
| |
| import ( |
| "reflect" |
| "unsafe" |
| ) |
| |
| // A pointer to a go value. |
| type Value struct{ data unsafe.Pointer } |
| |
| // Construct a Value from an interface. |
| // ValueOf(&x) is identical to ValueOf(x), except the latter will make a |
| // copy of x (when putting it into the interface). |
| func ValueOf(i interface{}) Value { |
| return Value{extractInterface(i).data} |
| } |
| |
| func (v Value) UnsafeAddr() uintptr { |
| return uintptr(v.data) |
| } |
| |
| func (v Value) Bool() bool { |
| return *(*bool)(v.data) |
| } |
| func (v Value) Int8() int8 { |
| return *(*int8)(v.data) |
| } |
| func (v Value) Int16() int16 { |
| return *(*int16)(v.data) |
| } |
| func (v Value) Int32() int32 { |
| return *(*int32)(v.data) |
| } |
| func (v Value) Int64() int64 { |
| return *(*int64)(v.data) |
| } |
| func (v Value) Uint8() uint8 { |
| return *(*uint8)(v.data) |
| } |
| func (v Value) Uint16() uint16 { |
| return *(*uint16)(v.data) |
| } |
| func (v Value) Uint32() uint32 { |
| return *(*uint32)(v.data) |
| } |
| func (v Value) Uint64() uint64 { |
| return *(*uint64)(v.data) |
| } |
| func (v Value) Float32() float32 { |
| return *(*float32)(v.data) |
| } |
| func (v Value) Float64() float64 { |
| return *(*float64)(v.data) |
| } |
| func (v Value) String() string { |
| return *(*string)(v.data) |
| } |
| func (v Value) Bytes() []byte { |
| return *(*[]byte)(v.data) |
| } |
| func (v Value) Interface() interface{} { |
| return *(*interface{})(v.data) |
| } |
| |
| func (v Value) SetBool(b bool) { |
| *(*bool)(v.data) = b |
| } |
| func (v Value) SetInt8(i int8) { |
| *(*int8)(v.data) = i |
| } |
| func (v Value) SetInt16(i int16) { |
| *(*int16)(v.data) = i |
| } |
| func (v Value) SetInt32(i int32) { |
| *(*int32)(v.data) = i |
| } |
| func (v Value) SetInt64(i int64) { |
| *(*int64)(v.data) = i |
| } |
| func (v Value) SetUint8(i uint8) { |
| *(*uint8)(v.data) = i |
| } |
| func (v Value) SetUint16(i uint16) { |
| *(*uint16)(v.data) = i |
| } |
| func (v Value) SetUint32(i uint32) { |
| *(*uint32)(v.data) = i |
| } |
| func (v Value) SetUint64(i uint64) { |
| *(*uint64)(v.data) = i |
| } |
| func (v Value) SetFloat32(i float32) { |
| *(*float32)(v.data) = i |
| } |
| func (v Value) SetFloat64(i float64) { |
| *(*float64)(v.data) = i |
| } |
| func (v Value) SetString(s string) { |
| *(*string)(v.data) = s |
| } |
| func (v Value) SetBytes(b []byte) { |
| *(*[]byte)(v.data) = b |
| } |
| func (v Value) SetInterface(s interface{}) { |
| *(*interface{})(v.data) = s |
| } |
| |
| func (v Value) SliceLen() int { |
| return (*reflect.SliceHeader)(v.data).Len |
| } |
| |
| func (v Value) SliceCap() int { |
| return (*reflect.SliceHeader)(v.data).Cap |
| } |
| |
| func (v Value) SliceIndex(elemSize uintptr, index int) Value { |
| return Value{unsafe.Pointer(uintptr((*reflect.SliceHeader)(v.data).Data) + uintptr(index)*elemSize)} |
| } |
| |
| // Analogous to rv.Set(reflect.MakeSlice(elemType, len, cap)). |
| func (v Value) SliceSetMakeSlice(elemType reflect.Type, len, cap int) { |
| sh := (*reflect.SliceHeader)(v.data) |
| sh.Len = len |
| sh.Cap = cap |
| sh.Data = uintptr(unsafe_NewArray(runtimeTypeFromReflectType(elemType), cap)) |
| } |
| |
| func (v Value) ArrayIndex(elemSize uintptr, index int) Value { |
| return Value{unsafe.Pointer(uintptr(v.data) + uintptr(index)*elemSize)} |
| } |
| |
| func (v Value) StructFieldOffset(offset uintptr) Value { |
| return Value{unsafe.Pointer(uintptr(v.data) + offset)} |
| } |
| |
| func (v Value) PointerElem() Value { |
| return Value{*(*unsafe.Pointer)(v.data)} |
| } |
| |
| func (v Value) PointerIsNil() bool { |
| return *(*unsafe.Pointer)(v.data) == nil |
| } |
| |
| func (v Value) PointerSetNil() { |
| *(*unsafe.Pointer)(v.data) = nil |
| } |
| |
| // Analogous to rv.Set(reflect.New(elemType)). |
| func (v Value) PointerSetNew(elemType reflect.Type) { |
| *(*unsafe.Pointer)(v.data) = unsafeNew(runtimeTypeFromReflectType(elemType)) |
| } |
| |
| // The runtime type of a value in go. |
| // Equivalent to *reflect.rtype. |
| type runtimeType uintptr |
| |
| // A struct representing the in-memory layout of a go interface. |
| type runtimeInterfaceImpl struct { |
| rtype runtimeType |
| data unsafe.Pointer |
| } |
| |
| // Extract the underlying in-memory structure from an interface. |
| func extractInterface(i interface{}) *runtimeInterfaceImpl { |
| // It is also possible to get the data field via |
| // reflect.ValueOf(v).Elem().UnsafeAddr(), but this does |
| // not require a heap allocation and dereferences the |
| // pointer in the interface. |
| return (*runtimeInterfaceImpl)(unsafe.Pointer(&i)) |
| } |
| |
| // Extract the runtime type from a reflect.Type. |
| func runtimeTypeFromReflectType(rt reflect.Type) runtimeType { |
| // A reflect type is an interface with rtype as its data. |
| // (see reflect/type.go)/ |
| return runtimeType(extractInterface(rt).data) |
| } |
| |
| // unsafeNew is equivalent to reflect.New(rt).Elem().UnsafeAddr(). |
| //go:linkname unsafeNew reflect.unsafe_New |
| func unsafeNew(rtype runtimeType) unsafe.Pointer |
| |
| // unsafe_NewArray allocates a new array of the specified type. |
| //go:linkname unsafe_NewArray reflect.unsafe_NewArray |
| func unsafe_NewArray(rtype runtimeType, length int) unsafe.Pointer |