Merge pull request #915 from visualfc/runtime.hash
[WIP] 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
|
||||
}
|
||||
@@ -537,4 +548,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
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user