Add logic to deal with reflect pkg changes on tip.
This commit adds logic to gracefully handle the new internal reflect.Value structure on tip as of golang commit ecccf07e7f9d. It accomplishes this by doing some inspection at init time and choosing the appropriate offsets as well as modifying which offset is used for the value accordingly. As a result, this allows spew to work properly with both the current release version of Go as well as tip. Fixes #15.
This commit is contained in:
parent
bde46cf02b
commit
65ca732a33
|
@ -25,13 +25,55 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// reflectValue mirrors the struct layout of the reflect package Value type.
|
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the internal
|
||||||
var reflectValue struct {
|
// reflect.Value fields.
|
||||||
|
var offsetPtr, offsetScalar, offsetFlag uintptr
|
||||||
|
|
||||||
|
// reflectValueOld mirrors the struct layout of the reflect package Value type
|
||||||
|
// before golang commit ecccf07e7f9d.
|
||||||
|
var reflectValueOld struct {
|
||||||
typ unsafe.Pointer
|
typ unsafe.Pointer
|
||||||
val unsafe.Pointer
|
val unsafe.Pointer
|
||||||
flag uintptr
|
flag uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reflectValueNew mirrors the struct layout of the reflect package Value type
|
||||||
|
// after golang commit ecccf07e7f9d.
|
||||||
|
var reflectValueNew struct {
|
||||||
|
typ unsafe.Pointer
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
scalar uintptr
|
||||||
|
flag uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Older versions of reflect.Value stored small integers directly in the
|
||||||
|
// ptr field (which is named val in the older versions). Newer versions
|
||||||
|
// added a new field named scalar for this purpose which unfortuantely
|
||||||
|
// comes before the flag field. Further the new field is before the
|
||||||
|
// flag field, so the offset of the flag field is different as well.
|
||||||
|
// This code constructs a new reflect.Value from a known small integer
|
||||||
|
// and checks if the val field within it matches. When it matches, the
|
||||||
|
// old style reflect.Value is being used. Otherwise it's the new style.
|
||||||
|
v := 0xf00
|
||||||
|
vv := reflect.ValueOf(v)
|
||||||
|
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) +
|
||||||
|
unsafe.Offsetof(reflectValueOld.val))
|
||||||
|
|
||||||
|
// Assume the old style by default.
|
||||||
|
offsetPtr = unsafe.Offsetof(reflectValueOld.val)
|
||||||
|
offsetScalar = 0
|
||||||
|
offsetFlag = unsafe.Offsetof(reflectValueOld.flag)
|
||||||
|
|
||||||
|
// Use the new style offsets if the ptr field doesn't match the value
|
||||||
|
// since it must be in the new scalar field.
|
||||||
|
if int(*(*uintptr)(upv)) != v {
|
||||||
|
offsetPtr = unsafe.Offsetof(reflectValueNew.ptr)
|
||||||
|
offsetScalar = unsafe.Offsetof(reflectValueNew.scalar)
|
||||||
|
offsetFlag = unsafe.Offsetof(reflectValueNew.flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// flagIndir indicates whether the value field of a reflect.Value is the actual
|
// flagIndir indicates whether the value field of a reflect.Value is the actual
|
||||||
// data or a pointer to the data.
|
// data or a pointer to the data.
|
||||||
const flagIndir = 1 << 1
|
const flagIndir = 1 << 1
|
||||||
|
@ -48,11 +90,13 @@ const flagIndir = 1 << 1
|
||||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
||||||
indirects := 1
|
indirects := 1
|
||||||
vt := v.Type()
|
vt := v.Type()
|
||||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.val))
|
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
||||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.flag)))
|
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
||||||
if rvf&flagIndir != 0 {
|
if rvf&flagIndir != 0 {
|
||||||
vt = reflect.PtrTo(v.Type())
|
vt = reflect.PtrTo(v.Type())
|
||||||
indirects++
|
indirects++
|
||||||
|
} else if offsetScalar != 0 {
|
||||||
|
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetScalar)
|
||||||
}
|
}
|
||||||
|
|
||||||
pv := reflect.NewAt(vt, upv)
|
pv := reflect.NewAt(vt, upv)
|
||||||
|
|
|
@ -92,8 +92,7 @@ const flagKindWidth = 5
|
||||||
// fallback code which punts to the standard fmt library for new types that
|
// fallback code which punts to the standard fmt library for new types that
|
||||||
// might get added to the language.
|
// might get added to the language.
|
||||||
func changeKind(v *reflect.Value, readOnly bool) {
|
func changeKind(v *reflect.Value, readOnly bool) {
|
||||||
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) +
|
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
|
||||||
unsafe.Offsetof(reflectValue.flag)))
|
|
||||||
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
|
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
|
||||||
if readOnly {
|
if readOnly {
|
||||||
*rvf |= flagRO
|
*rvf |= flagRO
|
||||||
|
|
|
@ -6,48 +6,40 @@ github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44)
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39)
|
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39)
|
||||||
github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30)
|
github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30)
|
||||||
github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18)
|
github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13)
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12)
|
github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12)
|
||||||
github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (12/12)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11)
|
github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11)
|
||||||
|
github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10)
|
||||||
github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9)
|
github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9)
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8)
|
github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8)
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7)
|
github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7)
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5)
|
github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5)
|
||||||
github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4)
|
github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4)
|
||||||
github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4)
|
github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4)
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4)
|
github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4)
|
||||||
github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3)
|
github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1)
|
||||||
|
@ -56,5 +48,14 @@ github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1)
|
||||||
github.com/davecgh/go-spew/spew ------------------------------- 100.00% (494/494)
|
github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1)
|
||||||
|
github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue