internal/runtime: type hash

This commit is contained in:
visualfc
2024-12-14 19:28:06 +08:00
parent 070d64f365
commit 620cfeabe0
2 changed files with 122 additions and 10 deletions

View File

@@ -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
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -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 FowlerNollVo 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
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------