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 := allocUncommonType(kind, size, methods, abi.TFlagUninited|abi.TFlagNamed|abi.TFlagUncommon, pkgPath)
|
||||||
ret.Str_ = name
|
ret.Str_ = name
|
||||||
|
ret.Hash = 9157 + hashString(pkgPath) + hashString(name)
|
||||||
if ptrMethods == 0 {
|
if ptrMethods == 0 {
|
||||||
ret.PtrToThis_ = newPointer(ret)
|
ret.PtrToThis_ = newPointer(ret)
|
||||||
} else {
|
} else {
|
||||||
@@ -210,7 +211,6 @@ func Func(in, out []*Type, variadic bool) *FuncType {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: 2 * unsafe.Sizeof(uintptr(0)),
|
Size_: 2 * unsafe.Sizeof(uintptr(0)),
|
||||||
PtrBytes: 2 * pointerSize,
|
PtrBytes: 2 * pointerSize,
|
||||||
Hash: uint32(abi.Func), // TODO(xsw): hash
|
|
||||||
Align_: uint8(pointerAlign),
|
Align_: uint8(pointerAlign),
|
||||||
FieldAlign_: uint8(pointerAlign),
|
FieldAlign_: uint8(pointerAlign),
|
||||||
Kind_: uint8(abi.Func),
|
Kind_: uint8(abi.Func),
|
||||||
@@ -218,9 +218,13 @@ func Func(in, out []*Type, variadic bool) *FuncType {
|
|||||||
In: in,
|
In: in,
|
||||||
Out: out,
|
Out: out,
|
||||||
}
|
}
|
||||||
|
var hash uint32 = 9091
|
||||||
if variadic {
|
if variadic {
|
||||||
|
hash *= 8863
|
||||||
ret.TFlag |= abi.TFlagVariadic
|
ret.TFlag |= abi.TFlagVariadic
|
||||||
}
|
}
|
||||||
|
hash += 3*hashTuple(in) + 5*hashTuple(out)
|
||||||
|
ret.Hash = hash
|
||||||
ret.Str_ = funcStr(ret)
|
ret.Str_ = funcStr(ret)
|
||||||
rtypeList.addType(&ret.Type)
|
rtypeList.addType(&ret.Type)
|
||||||
return ret
|
return ret
|
||||||
@@ -243,7 +247,7 @@ func NewNamedInterface(pkgPath, name string) *InterfaceType {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: unsafe.Sizeof(eface{}),
|
Size_: unsafe.Sizeof(eface{}),
|
||||||
PtrBytes: 2 * pointerSize,
|
PtrBytes: 2 * pointerSize,
|
||||||
Hash: uint32(abi.Interface), // TODO(xsw): hash
|
Hash: 9157 + hashString(pkgPath) + hashString(name),
|
||||||
Align_: uint8(pointerAlign),
|
Align_: uint8(pointerAlign),
|
||||||
FieldAlign_: uint8(pointerAlign),
|
FieldAlign_: uint8(pointerAlign),
|
||||||
Kind_: uint8(abi.Interface),
|
Kind_: uint8(abi.Interface),
|
||||||
@@ -277,7 +281,6 @@ func Interface(pkgPath string, methods []Imethod) *InterfaceType {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: unsafe.Sizeof(eface{}),
|
Size_: unsafe.Sizeof(eface{}),
|
||||||
PtrBytes: 2 * pointerSize,
|
PtrBytes: 2 * pointerSize,
|
||||||
Hash: uint32(abi.Interface), // TODO(xsw): hash
|
|
||||||
Align_: uint8(pointerAlign),
|
Align_: uint8(pointerAlign),
|
||||||
FieldAlign_: uint8(pointerAlign),
|
FieldAlign_: uint8(pointerAlign),
|
||||||
Kind_: uint8(abi.Interface),
|
Kind_: uint8(abi.Interface),
|
||||||
@@ -291,6 +294,14 @@ func Interface(pkgPath string, methods []Imethod) *InterfaceType {
|
|||||||
ret.Equal = interequal
|
ret.Equal = interequal
|
||||||
}
|
}
|
||||||
ret.Str_ = interfaceStr(ret)
|
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)
|
rtypeList.addType(&ret.Type)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@@ -541,4 +552,88 @@ func funcStr(ft *abi.FuncType) string {
|
|||||||
return string(repr)
|
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{
|
tyBasic[kind] = &Type{
|
||||||
Size_: size,
|
Size_: size,
|
||||||
PtrBytes: bytes,
|
PtrBytes: bytes,
|
||||||
Hash: uint32(kind), // TODO(xsw): hash
|
Hash: uint32(kind),
|
||||||
Align_: uint8(align),
|
Align_: uint8(align),
|
||||||
FieldAlign_: uint8(align),
|
FieldAlign_: uint8(align),
|
||||||
Kind_: uint8(_kind),
|
Kind_: uint8(_kind),
|
||||||
@@ -154,13 +154,13 @@ func Struct(pkgPath string, size uintptr, fields ...abi.StructField) *Type {
|
|||||||
ret := &abi.StructType{
|
ret := &abi.StructType{
|
||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: size,
|
Size_: size,
|
||||||
Hash: uint32(abi.Struct), // TODO(xsw): hash
|
|
||||||
Kind_: uint8(abi.Struct),
|
Kind_: uint8(abi.Struct),
|
||||||
Str_: structStr(fields),
|
Str_: structStr(fields),
|
||||||
},
|
},
|
||||||
PkgPath_: pkgPath,
|
PkgPath_: pkgPath,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
}
|
}
|
||||||
|
var hash uint32 = 9059
|
||||||
var comparable bool = true
|
var comparable bool = true
|
||||||
var typalign uint8
|
var typalign uint8
|
||||||
for _, f := range fields {
|
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
|
ret.PtrBytes = f.Offset + f.Typ.PtrBytes
|
||||||
}
|
}
|
||||||
comparable = comparable && (ft.Equal != nil)
|
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.Align_ = typalign
|
||||||
ret.FieldAlign_ = typalign
|
ret.FieldAlign_ = typalign
|
||||||
if comparable {
|
if comparable {
|
||||||
@@ -220,7 +227,7 @@ func newPointer(elem *Type) *Type {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: unsafe.Sizeof(uintptr(0)),
|
Size_: unsafe.Sizeof(uintptr(0)),
|
||||||
PtrBytes: pointerSize,
|
PtrBytes: pointerSize,
|
||||||
Hash: uint32(abi.Pointer), // TODO(xsw): hash
|
Hash: 9067 + 2*elem.Hash,
|
||||||
Align_: pointerAlign,
|
Align_: pointerAlign,
|
||||||
FieldAlign_: pointerAlign,
|
FieldAlign_: pointerAlign,
|
||||||
Kind_: uint8(abi.Pointer),
|
Kind_: uint8(abi.Pointer),
|
||||||
@@ -259,7 +266,7 @@ func SliceOf(elem *Type) *Type {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: unsafe.Sizeof([]int{}),
|
Size_: unsafe.Sizeof([]int{}),
|
||||||
PtrBytes: pointerSize,
|
PtrBytes: pointerSize,
|
||||||
Hash: uint32(abi.Slice),
|
Hash: 9049 + 2*elem.Hash,
|
||||||
Align_: pointerAlign,
|
Align_: pointerAlign,
|
||||||
FieldAlign_: pointerAlign,
|
FieldAlign_: pointerAlign,
|
||||||
Kind_: uint8(abi.Slice),
|
Kind_: uint8(abi.Slice),
|
||||||
@@ -279,7 +286,7 @@ func ArrayOf(length uintptr, elem *Type) *Type {
|
|||||||
ret := &abi.ArrayType{
|
ret := &abi.ArrayType{
|
||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: length * elem.Size_,
|
Size_: length * elem.Size_,
|
||||||
Hash: uint32(abi.Array),
|
Hash: 9043 + 2*uint32(length) + 3*elem.Hash,
|
||||||
Align_: elem.Align_,
|
Align_: elem.Align_,
|
||||||
FieldAlign_: elem.FieldAlign_,
|
FieldAlign_: elem.FieldAlign_,
|
||||||
Kind_: uint8(abi.Array),
|
Kind_: uint8(abi.Array),
|
||||||
@@ -326,7 +333,7 @@ func ChanOf(dir int, strChan string, elem *Type) *Type {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: pointerSize,
|
Size_: pointerSize,
|
||||||
PtrBytes: pointerSize,
|
PtrBytes: pointerSize,
|
||||||
Hash: uint32(abi.Chan),
|
Hash: 9127 + 2*uint32(dir) + 3*elem.Hash,
|
||||||
Align_: pointerAlign,
|
Align_: pointerAlign,
|
||||||
TFlag: abi.TFlagRegularMemory,
|
TFlag: abi.TFlagRegularMemory,
|
||||||
FieldAlign_: pointerAlign,
|
FieldAlign_: pointerAlign,
|
||||||
@@ -349,7 +356,7 @@ func MapOf(key, elem *Type, bucket *Type, flags int) *Type {
|
|||||||
Type: Type{
|
Type: Type{
|
||||||
Size_: unsafe.Sizeof(uintptr(0)),
|
Size_: unsafe.Sizeof(uintptr(0)),
|
||||||
PtrBytes: pointerSize,
|
PtrBytes: pointerSize,
|
||||||
Hash: uint32(abi.Map),
|
Hash: 9109 + 2*key.Hash + 3*elem.Hash,
|
||||||
Align_: pointerAlign,
|
Align_: pointerAlign,
|
||||||
FieldAlign_: pointerAlign,
|
FieldAlign_: pointerAlign,
|
||||||
Kind_: uint8(abi.Map),
|
Kind_: uint8(abi.Map),
|
||||||
@@ -567,4 +574,14 @@ func (r *rtypes) addType(typ *Type) {
|
|||||||
|
|
||||||
var rtypeList rtypes
|
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