diff options
| author | Dave Collins <[email protected]> | 2014-01-08 02:01:15 -0600 | 
|---|---|---|
| committer | Dave Collins <[email protected]> | 2014-01-08 02:01:15 -0600 | 
| commit | 65ca732a33a40c2a5b9e036f236f975e7e85cf6c (patch) | |
| tree | cb777cc3c5765ea4aa0a552c9e768246c5381da2 | |
| parent | bde46cf02b3187ab268e4d0e10a0c361dc39112c (diff) | |
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.
| -rw-r--r-- | spew/common.go | 52 | ||||
| -rw-r--r-- | spew/internal_test.go | 3 | ||||
| -rw-r--r-- | test_coverage.txt | 57 | 
3 files changed, 78 insertions, 34 deletions
diff --git a/spew/common.go b/spew/common.go index 0e59eca..bc26e7e 100644 --- a/spew/common.go +++ b/spew/common.go @@ -25,13 +25,55 @@ import (  	"unsafe"  ) -// reflectValue mirrors the struct layout of the reflect package Value type. -var reflectValue struct { +// offsetPtr, offsetScalar, and offsetFlag are the offsets for the internal +// 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  	val  unsafe.Pointer  	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  // data or a pointer to the data.  const flagIndir = 1 << 1 @@ -48,11 +90,13 @@ const flagIndir = 1 << 1  func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {  	indirects := 1  	vt := v.Type() -	upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.val)) -	rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.flag))) +	upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) +	rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))  	if rvf&flagIndir != 0 {  		vt = reflect.PtrTo(v.Type())  		indirects++ +	} else if offsetScalar != 0 { +		upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetScalar)  	}  	pv := reflect.NewAt(vt, upv) diff --git a/spew/internal_test.go b/spew/internal_test.go index d8c9761..faac638 100644 --- a/spew/internal_test.go +++ b/spew/internal_test.go @@ -92,8 +92,7 @@ const flagKindWidth = 5  // fallback code which punts to the standard fmt library for new types that  // might get added to the language.  func changeKind(v *reflect.Value, readOnly bool) { -	rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + -		unsafe.Offsetof(reflectValue.flag))) +	rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))  	*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)  	if readOnly {  		*rvf |= flagRO diff --git a/test_coverage.txt b/test_coverage.txt index 37567db..2cd087a 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -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/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	 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/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/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	 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.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/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/format.go	 newFormatter			 100.00% (3/3)  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	 printBool			 100.00% (3/3)  github.com/davecgh/go-spew/spew/common.go	 sortValues			 100.00% (3/3) +github.com/davecgh/go-spew/spew/config.go	 ConfigState.Sdump		 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/config.go	 ConfigState.Dump		 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go		 Sprintln			 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	 NewDefaultConfig		 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.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		 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		 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.Printf		 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.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			 ------------------------------- 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)  | 
