util/deephash: move pointer and interface logic to separate function
This helps pprof better identify which Go kinds take the most time
since the kind is always in the function name.
@@ -255,42 +255,9 @@ func genTypeHasher(ti *typeInfo) typeHasherFunc {
case reflect.Map:
return makeMapHasher(t)
case reflect.Pointer:
- et := t.Elem()
- eti := getTypeInfo(et)
- return func(h *hasher, p pointer) {
- pe := p.pointerElem()
- if pe.isNil() {
- h.HashUint8(0) // indicates nil
- return
- }
- if ti.isRecursive {
- if idx, ok := h.visitStack.seen(pe.p); ok {
- h.HashUint8(2) // indicates cycle
- h.HashUint64(uint64(idx))
- return
- }
- h.visitStack.push(pe.p)
- defer h.visitStack.pop(pe.p)
- }
- h.HashUint8(1) // indicates visiting a pointer
- eti.hasher()(h, pe)
- }
+ return makePointerHasher(t)
case reflect.Interface:
- return func(h *hasher, p pointer) {
- v := p.asValue(t).Elem() // reflect.Interface kind
- if v.IsNil() {
- h.HashUint8(0) // indicates nil
- return
- }
- h.HashUint8(1) // visiting interface
- v = v.Elem()
- t := v.Type()
- h.hashType(t)
- va := reflect.New(t).Elem()
- va.Set(v)
- ti := getTypeInfo(t)
- ti.hasher()(h, pointerOf(va.Addr()))
- }
+ return makeInterfaceHasher(t)
default: // Func, Chan, UnsafePointer
return func(*hasher, pointer) {}
}
@@ -490,6 +457,53 @@ func makeMapHasher(t reflect.Type) typeHasherFunc {
}
}
+func makePointerHasher(t reflect.Type) typeHasherFunc {
+ var once sync.Once
+ var hashElem typeHasherFunc
+ var isRecursive bool
+ init := func() {
+ hashElem = getTypeInfo(t.Elem()).hasher()
+ isRecursive = typeIsRecursive(t)
+ }
+ return func(h *hasher, p pointer) {
+ pe := p.pointerElem()
+ if pe.isNil() {
+ h.HashUint8(0) // indicates nil
+ return
+ }
+ once.Do(init)
+ if isRecursive {
+ if idx, ok := h.visitStack.seen(pe.p); ok {
+ h.HashUint8(2) // indicates cycle
+ h.HashUint64(uint64(idx))
+ return
+ }
+ h.visitStack.push(pe.p)
+ defer h.visitStack.pop(pe.p)
+ }
+ h.HashUint8(1) // indicates visiting a pointer element
+ hashElem(h, pe)
+ }
+}
+
+func makeInterfaceHasher(t reflect.Type) typeHasherFunc {
+ return func(h *hasher, p pointer) {
+ v := p.asValue(t).Elem() // reflect.Interface kind
+ if v.IsNil() {
+ h.HashUint8(0) // indicates nil
+ return
+ }
+ h.HashUint8(1) // indicates visiting an interface value
+ v = v.Elem()
+ t := v.Type()
+ h.hashType(t)
+ va := reflect.New(t).Elem()
+ va.Set(v)
+ hashElem := getTypeInfo(t).hasher()
+ hashElem(h, pointerOf(va.Addr()))
+ }
+}
+
func getTypeInfo(t reflect.Type) *typeInfo {
if f, ok := typeInfoMap.Load(t); ok {
return f.(*typeInfo)
