Browse Source

codec: optimize reflect.{IsNil, SetLen} when using unsafe

Ugorji Nwoke 6 years ago
parent
commit
f3e5d18b86
5 changed files with 77 additions and 289 deletions
  1. 17 17
      codec/decode.go
  2. 7 7
      codec/encode.go
  3. 1 1
      codec/helper.go
  4. 18 12
      codec/helper_not_unsafe.go
  5. 34 252
      codec/helper_unsafe.go

+ 17 - 17
codec/decode.go

@@ -1358,7 +1358,7 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
 
 	// every interface passed here MUST be settable.
 	var rvn reflect.Value
-	if rv.IsNil() || d.h.InterfaceReset {
+	if rvisnil(rv) || d.h.InterfaceReset {
 		// check if mapping to a type: if so, initialize it and move on
 		rvn = d.h.intf2impl(f.ti.rtid)
 		if rvn.IsValid() {
@@ -1558,13 +1558,13 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 	if containerLenS == 0 {
 		if rv.CanSet() {
 			if f.seq == seqTypeSlice {
-				if rv.IsNil() {
+				if rvisnil(rv) {
 					rv.Set(reflect.MakeSlice(frt, 0, 0))
 				} else {
-					rv.SetLen(0)
+					rvssetlen(rv, 0)
 				}
 			} else if f.seq == seqTypeChan {
-				if rv.IsNil() {
+				if rvisnil(rv) {
 					rv.Set(reflect.MakeChan(frt, 0))
 				}
 			}
@@ -1599,7 +1599,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 			rvlen = decInferLen(containerLenS, d.h.MaxInitLen, int(rtelem0.Size()))
 			if rvlen <= rvcap {
 				if rvCanset {
-					rv.SetLen(rvlen)
+					rvssetlen(rv, rvlen)
 				}
 			} else if rvCanset {
 				rv = reflect.MakeSlice(frt, rvlen, rvlen)
@@ -1614,7 +1614,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 		} else if containerLenS != rvlen {
 			rvlen = containerLenS
 			if rvCanset {
-				rv.SetLen(rvlen)
+				rvssetlen(rv, rvlen)
 			}
 			// else {
 			// rv = rv.Slice(0, rvlen)
@@ -1631,7 +1631,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 	var j int
 
 	for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ {
-		if j == 0 && (f.seq == seqTypeSlice || f.seq == seqTypeChan) && rv.IsNil() {
+		if j == 0 && (f.seq == seqTypeSlice || f.seq == seqTypeChan) && rvisnil(rv) {
 			if hasLen {
 				rvlen = decInferLen(containerLenS, d.h.MaxInitLen, rtelem0Size)
 			} else if f.seq == seqTypeSlice {
@@ -1658,7 +1658,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 				rv.Send(reflect.Zero(rtelem0))
 				continue
 			}
-			if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rv9.IsNil()) {
+			if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rvisnil(rv9)) {
 				rv9 = reflect.New(rtelem0).Elem()
 			}
 			if fn == nil {
@@ -1716,13 +1716,13 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 	if f.seq == seqTypeSlice {
 		if j < rvlen {
 			if rv.CanSet() {
-				rv.SetLen(j)
+				rvssetlen(rv, j)
 			} else if rvCanset {
 				rv = rv.Slice(0, j)
 				rvChanged = true
 			} // else { d.errorf("kSlice: cannot change non-settable slice") }
 			rvlen = j
-		} else if j == 0 && rv.IsNil() {
+		} else if j == 0 && rvisnil(rv) {
 			if rvCanset {
 				rv = reflect.MakeSlice(frt, 0, 0)
 				rvChanged = true
@@ -1746,7 +1746,7 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
 	dd := d.d
 	containerLen := d.mapStart()
 	ti := f.ti
-	if rv.IsNil() {
+	if rvisnil(rv) {
 		rvlen := decInferLen(containerLen, d.h.MaxInitLen, int(ti.key.Size()+ti.elem.Size()))
 		rv.Set(makeMapReflect(ti.rt, rvlen))
 	}
@@ -1858,12 +1858,12 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
 			}
 			rvv = mapIndex(rv, rvk, rvva) // reflect.Value{})
 			if vtypeKind == reflect.Ptr {
-				if rvv.IsValid() && !rvv.IsNil() {
+				if rvv.IsValid() && !rvisnil(rvv) {
 					mapSet = false
 				} else {
 					rvv = reflect.New(vtype.Elem())
 				}
-			} else if rvv.IsValid() && vtypeKind == reflect.Interface && !rvv.IsNil() {
+			} else if rvv.IsValid() && vtypeKind == reflect.Interface && !rvisnil(rvv) {
 				rvvn = reflect.New(vtype).Elem()
 				rvvn.Set(rvv)
 				rvv = rvvn
@@ -2771,7 +2771,7 @@ func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn) {
 	if rv.Kind() == reflect.Ptr {
 		rvpValid = true
 		for {
-			if rv.IsNil() {
+			if rvisnil(rv) {
 				rv.Set(reflect.New(rv.Type().Elem()))
 			}
 			rvp = rv
@@ -2826,11 +2826,11 @@ func isDecodeable(rv reflect.Value) (rv2 reflect.Value, canDecode bool) {
 	case reflect.Array:
 		return rv, rv.CanAddr()
 	case reflect.Ptr:
-		if !rv.IsNil() {
+		if !rvisnil(rv) {
 			return rv.Elem(), true
 		}
 	case reflect.Slice, reflect.Chan, reflect.Map:
-		if !rv.IsNil() {
+		if !rvisnil(rv) {
 			return rv, true
 		}
 	}
@@ -3169,7 +3169,7 @@ func expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize,
 	}
 	if l1 <= scap {
 		if s.CanSet() {
-			s.SetLen(l1)
+			rvssetlen(s, l1)
 		} else if canChange {
 			s2 = s.Slice(0, l1)
 			scap2 = scap

+ 7 - 7
codec/encode.go

@@ -521,7 +521,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 	// E.g. type struct S{B [2]byte};
 	//   Encode(S{}) will bomb on "panic: slice of unaddressable array".
 	if f.seq != seqTypeArray {
-		if rv.IsNil() {
+		if rvisnil(rv) {
 			e.e.EncodeNil()
 			return
 		}
@@ -576,7 +576,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 		rv = rvcs // TODO: ensure this doesn't mess up anywhere that rv of kind chan is expected
 	}
 
-	var l = rv.Len()
+	var l = rv.Len() // rv may be slice or array
 	if mbs {
 		if l%2 == 1 {
 			e.errorf("mapBySlice requires even slice length, but got %v", l)
@@ -643,7 +643,7 @@ func (e *Encoder) kSliceBytes(rv reflect.Value, seq seqType) {
 		// for b := range rv2i(rv).(<-chan byte) { bs = append(bs, b) }
 		// ch := rv2i(rv).(<-chan byte) // fix error - that this is a chan byte, not a <-chan byte.
 
-		if rv.IsNil() {
+		if rvisnil(rv) {
 			e.e.EncodeNil()
 			break
 		}
@@ -827,7 +827,7 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 }
 
 func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
-	if rv.IsNil() {
+	if rvisnil(rv) {
 		e.e.EncodeNil()
 		return
 	}
@@ -1653,7 +1653,7 @@ func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn) {
 TOP:
 	switch rv.Kind() {
 	case reflect.Ptr:
-		if rv.IsNil() {
+		if rvisnil(rv) {
 			e.e.EncodeNil()
 			return
 		}
@@ -1666,14 +1666,14 @@ TOP:
 		}
 		goto TOP
 	case reflect.Interface:
-		if rv.IsNil() {
+		if rvisnil(rv) {
 			e.e.EncodeNil()
 			return
 		}
 		rv = rv.Elem()
 		goto TOP
 	case reflect.Slice, reflect.Map:
-		if rv.IsNil() {
+		if rvisnil(rv) {
 			e.e.EncodeNil()
 			return
 		}

+ 1 - 1
codec/helper.go

@@ -1465,7 +1465,7 @@ func (x *structFieldNode) field(si *structFieldInfo) (fv reflect.Value) {
 
 func baseStructRv(v reflect.Value, update bool) (v2 reflect.Value, valid bool) {
 	for v.Kind() == reflect.Ptr {
-		if v.IsNil() {
+		if rvisnil(v) {
 			if !update {
 				return
 			}

+ 18 - 12
codec/helper_not_unsafe.go

@@ -43,14 +43,30 @@ func rv2i(rv reflect.Value) interface{} {
 	return rv.Interface()
 }
 
-func rt2id(rt reflect.Type) uintptr {
-	return reflect.ValueOf(rt).Pointer()
+func rvisnil(rv reflect.Value) bool {
+	return rv.IsNil()
+}
+
+func rvssetlen(rv reflect.Value, length int) {
+	rv.SetLen(length)
 }
 
+// func rvisnilref(rv reflect.Value) bool {
+// 	return rv.IsNil()
+// }
+
+// func rvslen(rv reflect.Value) int {
+// 	return rv.Len()
+// }
+
 // func rv2rtid(rv reflect.Value) uintptr {
 // 	return reflect.ValueOf(rv.Type()).Pointer()
 // }
 
+func rt2id(rt reflect.Type) uintptr {
+	return reflect.ValueOf(rt).Pointer()
+}
+
 func i2rtid(i interface{}) uintptr {
 	return reflect.ValueOf(reflect.TypeOf(i)).Pointer()
 }
@@ -321,16 +337,6 @@ func mapAddressableRV(t reflect.Type) (r reflect.Value) {
 	return // reflect.New(t).Elem()
 }
 
-// // keepAlive4BytesView maintains a reference to the input parameter for bytesView.
-// //
-// // Usage: call this at point where done with the bytes view.
-// func keepAlive4BytesView(v string) {}
-
-// // keepAlive4BytesView maintains a reference to the input parameter for stringView.
-// //
-// // Usage: call this at point where done with the string view.
-// func keepAlive4StringView(v []byte) {}
-
 // func definitelyNil(v interface{}) bool {
 // 	rv := reflect.ValueOf(v)
 // 	switch rv.Kind() {

+ 34 - 252
codec/helper_unsafe.go

@@ -17,6 +17,16 @@ import (
 // This file has unsafe variants of some helper methods.
 // NOTE: See helper_not_unsafe.go for the usage information.
 
+// For reflect.Value code, we decided to do the following:
+//    - if we know the kind, we can elide conditional checks for
+//      - SetXXX (Int, Uint, String, Bool, etc)
+//      - SetLen
+//
+// We can also optimize
+//      - IsNil
+//
+// We cannot do the same for Cap, Len if we still have to do conditional.
+
 // var zeroRTv [4]uintptr
 
 const safeMode = false
@@ -103,14 +113,36 @@ func rv2i(rv reflect.Value) interface{} {
 	return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: rv2ptr(urv)}))
 }
 
-func rt2id(rt reflect.Type) uintptr {
-	return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
+func rvisnil(rv reflect.Value) bool {
+	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
+	if urv.flag&unsafeFlagIndir != 0 {
+		return *(*unsafe.Pointer)(urv.ptr) == nil
+	}
+	return urv.ptr == nil
 }
 
+func rvssetlen(rv reflect.Value, length int) {
+	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
+	(*unsafeString)(urv.ptr).Len = length
+}
+
+// func rvisnilref(rv reflect.Value) bool {
+// 	return (*unsafeReflectValue)(unsafe.Pointer(&rv)).ptr == nil
+// }
+
+// func rvslen(rv reflect.Value) int {
+// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
+// 	return (*unsafeString)(urv.ptr).Len
+// }
+
 // func rv2rtid(rv reflect.Value) uintptr {
 // 	return uintptr((*unsafeReflectValue)(unsafe.Pointer(&rv)).typ)
 // }
 
+func rt2id(rt reflect.Type) uintptr {
+	return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
+}
+
 func i2rtid(i interface{}) uintptr {
 	return uintptr(((*unsafeIntf)(unsafe.Pointer(&i))).typ)
 }
@@ -636,37 +668,6 @@ func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val
 //go:noescape
 func typedmemmove(typ unsafe.Pointer, dst, src unsafe.Pointer)
 
-// func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
-// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-// 	// if urv.flag&unsafeFlagIndir != 0 {
-// 	// 	urv.ptr = *(*unsafe.Pointer)(urv.ptr)
-// 	// }
-// 	*(*[]byte)(urv.ptr) = d.rawBytes()
-// }
-
-// func rv0t(rt reflect.Type) reflect.Value {
-// 	ut := (*unsafeIntf)(unsafe.Pointer(&rt))
-// 	// we need to determine whether ifaceIndir, and then whether to just pass 0 as the ptr
-// 	uv := unsafeReflectValue{ut.word, &zeroRTv, flag(rt.Kind())}
-// 	return *(*reflect.Value)(unsafe.Pointer(&uv})
-// }
-
-// func rv2i(rv reflect.Value) interface{} {
-// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-// 	// true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir
-// 	var ptr unsafe.Pointer
-// 	// kk := reflect.Kind(urv.flag & (1<<5 - 1))
-// 	// if (kk == reflect.Map || kk == reflect.Ptr || kk == reflect.Chan || kk == reflect.Func) && urv.flag&unsafeFlagIndir != 0 {
-// 	if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 {
-// 		ptr = *(*unsafe.Pointer)(urv.ptr)
-// 	} else {
-// 		ptr = urv.ptr
-// 	}
-// 	return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr}))
-// 	// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
-// 	// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// }
-
 // func definitelyNil(v interface{}) bool {
 // 	var ui *unsafeIntf = (*unsafeIntf)(unsafe.Pointer(&v))
 // 	if ui.word == nil {
@@ -677,222 +678,3 @@ func typedmemmove(typ unsafe.Pointer, dst, src unsafe.Pointer)
 // 	fmt.Printf(">>>> definitely nil: isnil: %v, TYPE: \t%T, word: %v, *word: %v, type: %v, nil: %v\n",
 // 	v == nil, v, word, *((*unsafe.Pointer)(word)), ui.typ, nil)
 // }
-
-// func keepAlive4BytesView(v string) {
-// 	runtime.KeepAlive(v)
-// }
-
-// func keepAlive4StringView(v []byte) {
-// 	runtime.KeepAlive(v)
-// }
-
-// func rt2id(rt reflect.Type) uintptr {
-// 	return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
-// 	// var i interface{} = rt
-// 	// // ui := (*unsafeIntf)(unsafe.Pointer(&i))
-// 	// return ((*unsafeIntf)(unsafe.Pointer(&i))).word
-// }
-
-// func rv2i(rv reflect.Value) interface{} {
-// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-// 	// non-reference type: already indir
-// 	// reference type: depend on flagIndir property ('cos maybe was double-referenced)
-// 	// const (unsafeRvFlagKindMask    = 1<<5 - 1 , unsafeRvFlagIndir       = 1 << 7 )
-// 	// rvk := reflect.Kind(urv.flag & (1<<5 - 1))
-// 	// if (rvk == reflect.Chan ||
-// 	// 	rvk == reflect.Func ||
-// 	// 	rvk == reflect.Interface ||
-// 	// 	rvk == reflect.Map ||
-// 	// 	rvk == reflect.Ptr ||
-// 	// 	rvk == reflect.UnsafePointer) && urv.flag&(1<<8) != 0 {
-// 	// 	fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
-// 	// 	return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
-// 	// }
-// 	if urv.flag&(1<<5-1) == uintptr(reflect.Map) && urv.flag&(1<<7) != 0 {
-// 		// fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
-// 		return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
-// 	}
-// 	// fmt.Printf(">>>>> ++++ direct reference: %v, %v\n", rvk, rv.Type())
-// 	return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// }
-
-// const (
-// 	unsafeRvFlagKindMask    = 1<<5 - 1
-// 	unsafeRvKindDirectIface = 1 << 5
-// 	unsafeRvFlagIndir       = 1 << 7
-// 	unsafeRvFlagAddr        = 1 << 8
-// 	unsafeRvFlagMethod      = 1 << 9
-
-// 	_USE_RV_INTERFACE bool = false
-// 	_UNSAFE_RV_DEBUG       = true
-// )
-
-// type unsafeRtype struct {
-// 	_    [2]uintptr
-// 	_    uint32
-// 	_    uint8
-// 	_    uint8
-// 	_    uint8
-// 	kind uint8
-// 	_    [2]uintptr
-// 	_    int32
-// }
-
-// func _rv2i(rv reflect.Value) interface{} {
-// 	// Note: From use,
-// 	//   - it's never an interface
-// 	//   - the only calls here are for ifaceIndir types.
-// 	//     (though that conditional is wrong)
-// 	//     To know for sure, we need the value of t.kind (which is not exposed).
-// 	//
-// 	// Need to validate the path: type is indirect ==> only value is indirect ==> default (value is direct)
-// 	//    - Type indirect, Value indirect: ==> numbers, boolean, slice, struct, array, string
-// 	//    - Type Direct,   Value indirect: ==> map???
-// 	//    - Type Direct,   Value direct:   ==> pointers, unsafe.Pointer, func, chan, map
-// 	//
-// 	// TRANSLATES TO:
-// 	//    if typeIndirect { } else if valueIndirect { } else { }
-// 	//
-// 	// Since we don't deal with funcs, then "flagNethod" is unset, and can be ignored.
-
-// 	if _USE_RV_INTERFACE {
-// 		return rv.Interface()
-// 	}
-// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-
-// 	// if urv.flag&unsafeRvFlagMethod != 0 || urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
-// 	// 	println("***** IS flag method or interface: delegating to rv.Interface()")
-// 	// 	return rv.Interface()
-// 	// }
-
-// 	// if urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
-// 	// 	println("***** IS Interface: delegate to rv.Interface")
-// 	// 	return rv.Interface()
-// 	// }
-// 	// if urv.flag&unsafeRvFlagKindMask&unsafeRvKindDirectIface == 0 {
-// 	// 	if urv.flag&unsafeRvFlagAddr == 0 {
-// 	// 		println("***** IS ifaceIndir typ")
-// 	// 		// ui := unsafeIntf{word: urv.ptr, typ: urv.typ}
-// 	// 		// return *(*interface{})(unsafe.Pointer(&ui))
-// 	// 		// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// 	// 	}
-// 	// } else if urv.flag&unsafeRvFlagIndir != 0 {
-// 	// 	println("***** IS flagindir")
-// 	// 	// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
-// 	// } else {
-// 	// 	println("***** NOT flagindir")
-// 	// 	return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// 	// }
-// 	// println("***** default: delegate to rv.Interface")
-
-// 	urt := (*unsafeRtype)(unsafe.Pointer(urv.typ))
-// 	if _UNSAFE_RV_DEBUG {
-// 		fmt.Printf(">>>> start: %v: ", rv.Type())
-// 		fmt.Printf("%v - %v\n", *urv, *urt)
-// 	}
-// 	if urt.kind&unsafeRvKindDirectIface == 0 {
-// 		if _UNSAFE_RV_DEBUG {
-// 			fmt.Printf("**** +ifaceIndir type: %v\n", rv.Type())
-// 		}
-// 		// println("***** IS ifaceIndir typ")
-// 		// if true || urv.flag&unsafeRvFlagAddr == 0 {
-// 		// 	// println("    ***** IS NOT addr")
-// 		return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// 		// }
-// 	} else if urv.flag&unsafeRvFlagIndir != 0 {
-// 		if _UNSAFE_RV_DEBUG {
-// 			fmt.Printf("**** +flagIndir type: %v\n", rv.Type())
-// 		}
-// 		// println("***** IS flagindir")
-// 		return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
-// 	} else {
-// 		if _UNSAFE_RV_DEBUG {
-// 			fmt.Printf("**** -flagIndir type: %v\n", rv.Type())
-// 		}
-// 		// println("***** NOT flagindir")
-// 		return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
-// 	}
-// 	// println("***** default: delegating to rv.Interface()")
-// 	// return rv.Interface()
-// }
-
-// var staticM0 = make(map[string]uint64)
-// var staticI0 = (int32)(-5)
-
-// func staticRv2iTest() {
-// 	i0 := (int32)(-5)
-// 	m0 := make(map[string]uint16)
-// 	m0["1"] = 1
-// 	for _, i := range []interface{}{
-// 		(int)(7),
-// 		(uint)(8),
-// 		(int16)(-9),
-// 		(uint16)(19),
-// 		(uintptr)(77),
-// 		(bool)(true),
-// 		float32(-32.7),
-// 		float64(64.9),
-// 		complex(float32(19), 5),
-// 		complex(float64(-32), 7),
-// 		[4]uint64{1, 2, 3, 4},
-// 		(chan<- int)(nil), // chan,
-// 		rv2i,              // func
-// 		io.Writer(ioutil.Discard),
-// 		make(map[string]uint),
-// 		(map[string]uint)(nil),
-// 		staticM0,
-// 		m0,
-// 		&m0,
-// 		i0,
-// 		&i0,
-// 		&staticI0,
-// 		&staticM0,
-// 		[]uint32{6, 7, 8},
-// 		"abc",
-// 		Raw{},
-// 		RawExt{},
-// 		&Raw{},
-// 		&RawExt{},
-// 		unsafe.Pointer(&i0),
-// 	} {
-// 		i2 := rv2i(reflect.ValueOf(i))
-// 		eq := reflect.DeepEqual(i, i2)
-// 		fmt.Printf(">>>> %v == %v? %v\n", i, i2, eq)
-// 	}
-// 	// os.Exit(0)
-// }
-
-// func init() {
-// 	staticRv2iTest()
-// }
-
-// func rv2i(rv reflect.Value) interface{} {
-// 	if _USE_RV_INTERFACE || rv.Kind() == reflect.Interface || rv.CanAddr() {
-// 		return rv.Interface()
-// 	}
-// 	// var i interface{}
-// 	// ui := (*unsafeIntf)(unsafe.Pointer(&i))
-// 	var ui unsafeIntf
-// 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-// 	// fmt.Printf("urv: flag: %b, typ: %b, ptr: %b\n", urv.flag, uintptr(urv.typ), uintptr(urv.ptr))
-// 	if (urv.flag&unsafeRvFlagKindMask)&unsafeRvKindDirectIface == 0 {
-// 		if urv.flag&unsafeRvFlagAddr != 0 {
-// 			println("***** indirect and addressable! Needs typed move - delegate to rv.Interface()")
-// 			return rv.Interface()
-// 		}
-// 		println("****** indirect type/kind")
-// 		ui.word = urv.ptr
-// 	} else if urv.flag&unsafeRvFlagIndir != 0 {
-// 		println("****** unsafe rv flag indir")
-// 		ui.word = *(*unsafe.Pointer)(urv.ptr)
-// 	} else {
-// 		println("****** default: assign prt to word directly")
-// 		ui.word = urv.ptr
-// 	}
-// 	// ui.word = urv.ptr
-// 	ui.typ = urv.typ
-// 	// fmt.Printf("(pointers) ui.typ: %p, word: %p\n", ui.typ, ui.word)
-// 	// fmt.Printf("(binary)   ui.typ: %b, word: %b\n", uintptr(ui.typ), uintptr(ui.word))
-// 	return *(*interface{})(unsafe.Pointer(&ui))
-// 	// return i
-// }