internal/runtime: type hash
This commit is contained in:
@@ -116,6 +116,7 @@ func NewNamed(pkgPath string, name string, kind abi.Kind, size uintptr, methods,
|
||||
}
|
||||
ret := allocUncommonType(kind, size, methods, abi.TFlagUninited|abi.TFlagNamed|abi.TFlagUncommon, pkgPath)
|
||||
ret.Str_ = name
|
||||
ret.Hash = 9157 + hashString(pkgPath) + hashString(name)
|
||||
if ptrMethods == 0 {
|
||||
ret.PtrToThis_ = newPointer(ret)
|
||||
} else {
|
||||
@@ -210,7 +211,6 @@ func Func(in, out []*Type, variadic bool) *FuncType {
|
||||
Type: Type{
|
||||
Size_: 2 * unsafe.Sizeof(uintptr(0)),
|
||||
PtrBytes: 2 * pointerSize,
|
||||
Hash: uint32(abi.Func), // TODO(xsw): hash
|
||||
Align_: uint8(pointerAlign),
|
||||
FieldAlign_: uint8(pointerAlign),
|
||||
Kind_: uint8(abi.Func),
|
||||
@@ -218,9 +218,13 @@ func Func(in, out []*Type, variadic bool) *FuncType {
|
||||
In: in,
|
||||
Out: out,
|
||||
}
|
||||
var hash uint32 = 9091
|
||||
if variadic {
|
||||
hash *= 8863
|
||||
ret.TFlag |= abi.TFlagVariadic
|
||||
}
|
||||
hash += 3*hashTuple(in) + 5*hashTuple(out)
|
||||
ret.Hash = hash
|
||||
ret.Str_ = funcStr(ret)
|
||||
rtypeList.addType(&ret.Type)
|
||||
return ret
|
||||
@@ -243,7 +247,7 @@ func NewNamedInterface(pkgPath, name string) *InterfaceType {
|
||||
Type: Type{
|
||||
Size_: unsafe.Sizeof(eface{}),
|
||||
PtrBytes: 2 * pointerSize,
|
||||
Hash: uint32(abi.Interface), // TODO(xsw): hash
|
||||
Hash: 9157 + hashString(pkgPath) + hashString(name),
|
||||
Align_: uint8(pointerAlign),
|
||||
FieldAlign_: uint8(pointerAlign),
|
||||
Kind_: uint8(abi.Interface),
|
||||
@@ -277,7 +281,6 @@ func Interface(pkgPath string, methods []Imethod) *InterfaceType {
|
||||
Type: Type{
|
||||
Size_: unsafe.Sizeof(eface{}),
|
||||
PtrBytes: 2 * pointerSize,
|
||||
Hash: uint32(abi.Interface), // TODO(xsw): hash
|
||||
Align_: uint8(pointerAlign),
|
||||
FieldAlign_: uint8(pointerAlign),
|
||||
Kind_: uint8(abi.Interface),
|
||||
@@ -291,6 +294,14 @@ func Interface(pkgPath string, methods []Imethod) *InterfaceType {
|
||||
ret.Equal = interequal
|
||||
}
|
||||
ret.Str_ = interfaceStr(ret)
|
||||
var hash uint32 = 9103
|
||||
// Hash methods.
|
||||
for _, m := range methods {
|
||||
// Use shallow hash on method signature to
|
||||
// avoid anonymous interface cycles.
|
||||
hash += 3*hashString(m.Name()) + 5*shallowHash(&m.Typ_.Type)
|
||||
}
|
||||
ret.Hash = hash
|
||||
rtypeList.addType(&ret.Type)
|
||||
return ret
|
||||
}
|
||||
@@ -541,4 +552,88 @@ func funcStr(ft *abi.FuncType) string {
|
||||
return string(repr)
|
||||
}
|
||||
|
||||
func hashTuple(tuple []*Type) uint32 {
|
||||
// See go/types.identicalTypes for rationale.
|
||||
n := len(tuple)
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := 0; i < n; i++ {
|
||||
hash += 3 * tuple[i].Hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// shallowHash computes a hash of t without looking at any of its
|
||||
// element Types, to avoid potential anonymous cycles in the types of
|
||||
// interface methods.
|
||||
//
|
||||
// When an unnamed non-empty interface type appears anywhere among the
|
||||
// arguments or results of an interface method, there is a potential
|
||||
// for endless recursion. Consider:
|
||||
//
|
||||
// type X interface { m() []*interface { X } }
|
||||
//
|
||||
// The problem is that the Methods of the interface in m's result type
|
||||
// include m itself; there is no mention of the named type X that
|
||||
// might help us break the cycle.
|
||||
// (See comment in go/types.identical, case *Interface, for more.)
|
||||
func shallowHash(t *abi.Type) uint32 {
|
||||
// t is the type of an interface method (Signature),
|
||||
// its params or results (Tuples), or their immediate
|
||||
// elements (mostly Slice, Pointer, Basic, Named),
|
||||
// so there's no need to optimize anything else.
|
||||
|
||||
if t.HasName() {
|
||||
return 9157 + hashString(t.Uncommon().PkgPath_) + hashString(t.Str_)
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64,
|
||||
abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr,
|
||||
abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String, abi.UnsafePointer:
|
||||
return 45212177 * uint32(t.Kind())
|
||||
|
||||
case abi.Func:
|
||||
t := t.FuncType()
|
||||
var hash uint32 = 604171
|
||||
if t.Variadic() {
|
||||
hash *= 971767
|
||||
}
|
||||
// The Signature/Tuple recursion is always finite
|
||||
// and invariably shallow.
|
||||
return hash + 1062599*shallowHashTuple(t.In) + 1282529*shallowHashTuple(t.Out)
|
||||
|
||||
case abi.Array:
|
||||
return 1524181 + 2*uint32(t.ArrayType().Len)
|
||||
|
||||
case abi.Slice:
|
||||
return 2690201
|
||||
|
||||
case abi.Struct:
|
||||
return 3326489
|
||||
|
||||
case abi.Pointer:
|
||||
return 4393139
|
||||
|
||||
case abi.Interface:
|
||||
return 2124679 // no recursion here
|
||||
|
||||
case abi.Map:
|
||||
return 9109
|
||||
|
||||
case abi.Chan:
|
||||
return 9127
|
||||
}
|
||||
|
||||
panic("shallowHash:" + t.String())
|
||||
}
|
||||
|
||||
func shallowHashTuple(tuple []*Type) uint32 {
|
||||
n := len(tuple)
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := 0; i < n; i++ {
|
||||
hash += 53471161 * shallowHash(tuple[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -79,7 +79,7 @@ func Basic(_kind Kind) *Type {
|
||||
tyBasic[kind] = &Type{
|
||||
Size_: size,
|
||||
PtrBytes: bytes,
|
||||
Hash: uint32(kind), // TODO(xsw): hash
|
||||
Hash: uint32(kind),
|
||||
Align_: uint8(align),
|
||||
FieldAlign_: uint8(align),
|
||||
Kind_: uint8(_kind),
|
||||
@@ -154,13 +154,13 @@ func Struct(pkgPath string, size uintptr, fields ...abi.StructField) *Type {
|
||||
ret := &abi.StructType{
|
||||
Type: Type{
|
||||
Size_: size,
|
||||
Hash: uint32(abi.Struct), // TODO(xsw): hash
|
||||
Kind_: uint8(abi.Struct),
|
||||
Str_: structStr(fields),
|
||||
},
|
||||
PkgPath_: pkgPath,
|
||||
Fields: fields,
|
||||
}
|
||||
var hash uint32 = 9059
|
||||
var comparable bool = true
|
||||
var typalign uint8
|
||||
for _, f := range fields {
|
||||
@@ -172,7 +172,14 @@ func Struct(pkgPath string, size uintptr, fields ...abi.StructField) *Type {
|
||||
ret.PtrBytes = f.Offset + f.Typ.PtrBytes
|
||||
}
|
||||
comparable = comparable && (ft.Equal != nil)
|
||||
if f.Embedded_ {
|
||||
hash += 8861
|
||||
}
|
||||
hash += hashString(f.Tag_)
|
||||
hash += hashString(f.Name_)
|
||||
hash += f.Typ.Hash
|
||||
}
|
||||
ret.Hash = hash
|
||||
ret.Align_ = typalign
|
||||
ret.FieldAlign_ = typalign
|
||||
if comparable {
|
||||
@@ -220,7 +227,7 @@ func newPointer(elem *Type) *Type {
|
||||
Type: Type{
|
||||
Size_: unsafe.Sizeof(uintptr(0)),
|
||||
PtrBytes: pointerSize,
|
||||
Hash: uint32(abi.Pointer), // TODO(xsw): hash
|
||||
Hash: 9067 + 2*elem.Hash,
|
||||
Align_: pointerAlign,
|
||||
FieldAlign_: pointerAlign,
|
||||
Kind_: uint8(abi.Pointer),
|
||||
@@ -259,7 +266,7 @@ func SliceOf(elem *Type) *Type {
|
||||
Type: Type{
|
||||
Size_: unsafe.Sizeof([]int{}),
|
||||
PtrBytes: pointerSize,
|
||||
Hash: uint32(abi.Slice),
|
||||
Hash: 9049 + 2*elem.Hash,
|
||||
Align_: pointerAlign,
|
||||
FieldAlign_: pointerAlign,
|
||||
Kind_: uint8(abi.Slice),
|
||||
@@ -279,7 +286,7 @@ func ArrayOf(length uintptr, elem *Type) *Type {
|
||||
ret := &abi.ArrayType{
|
||||
Type: Type{
|
||||
Size_: length * elem.Size_,
|
||||
Hash: uint32(abi.Array),
|
||||
Hash: 9043 + 2*uint32(length) + 3*elem.Hash,
|
||||
Align_: elem.Align_,
|
||||
FieldAlign_: elem.FieldAlign_,
|
||||
Kind_: uint8(abi.Array),
|
||||
@@ -326,7 +333,7 @@ func ChanOf(dir int, strChan string, elem *Type) *Type {
|
||||
Type: Type{
|
||||
Size_: pointerSize,
|
||||
PtrBytes: pointerSize,
|
||||
Hash: uint32(abi.Chan),
|
||||
Hash: 9127 + 2*uint32(dir) + 3*elem.Hash,
|
||||
Align_: pointerAlign,
|
||||
TFlag: abi.TFlagRegularMemory,
|
||||
FieldAlign_: pointerAlign,
|
||||
@@ -349,7 +356,7 @@ func MapOf(key, elem *Type, bucket *Type, flags int) *Type {
|
||||
Type: Type{
|
||||
Size_: unsafe.Sizeof(uintptr(0)),
|
||||
PtrBytes: pointerSize,
|
||||
Hash: uint32(abi.Map),
|
||||
Hash: 9109 + 2*key.Hash + 3*elem.Hash,
|
||||
Align_: pointerAlign,
|
||||
FieldAlign_: pointerAlign,
|
||||
Kind_: uint8(abi.Map),
|
||||
@@ -567,4 +574,14 @@ func (r *rtypes) addType(typ *Type) {
|
||||
|
||||
var rtypeList rtypes
|
||||
|
||||
// hashString computes the Fowler–Noll–Vo hash of s.
|
||||
func hashString(s string) uint32 {
|
||||
var h uint32
|
||||
for i := 0; i < len(s); i++ {
|
||||
h ^= uint32(s[i])
|
||||
h *= 16777619
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user