diff options
Diffstat (limited to 'libgo/go/runtime/alg.go')
-rw-r--r-- | libgo/go/runtime/alg.go | 89 |
1 files changed, 76 insertions, 13 deletions
diff --git a/libgo/go/runtime/alg.go b/libgo/go/runtime/alg.go index f96a75d..e802fdd 100644 --- a/libgo/go/runtime/alg.go +++ b/libgo/go/runtime/alg.go @@ -69,6 +69,9 @@ func memhash128(p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, 16) } +// runtime variable to check if the processor we're running on +// actually supports the instructions used by the AES-based +// hash implementation. var useAeshash bool // in C code @@ -134,14 +137,17 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { return h } t := *(**_type)(tab) - fn := t.hashfn - if fn == nil { + if t.equal == nil { + // Check hashability here. We could do this check inside + // typehash, but we want to report the topmost type in + // the error text (e.g. in a struct with a field of slice type + // we want to report the struct, not the slice). panic(errorString("hash of unhashable type " + t.string())) } if isDirectIface(t) { - return c1 * fn(unsafe.Pointer(&a.data), h^c0) + return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) } else { - return c1 * fn(a.data, h^c0) + return c1 * typehash(t, a.data, h^c0) } } @@ -151,17 +157,74 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { if t == nil { return h } - fn := t.hashfn - if fn == nil { + if t.equal == nil { + // See comment in interhash above. panic(errorString("hash of unhashable type " + t.string())) } if isDirectIface(t) { - return c1 * fn(unsafe.Pointer(&a.data), h^c0) + return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) } else { - return c1 * fn(a.data, h^c0) + return c1 * typehash(t, a.data, h^c0) + } +} + +// typehash computes the hash of the object of type t at address p. +// h is the seed. +// This function is seldom used. Most maps use for hashing either +// fixed functions (e.g. f32hash) or compiler-generated functions +// (e.g. for a type like struct { x, y string }). This implementation +// is slower but more general and is used for hashing interface types +// (called from interhash or nilinterhash, above) or for hashing in +// maps generated by reflect.MapOf (reflect_typehash, below). +func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { + if t.tflag&tflagRegularMemory != 0 { + return memhash(p, h, t.size) + } + switch t.kind & kindMask { + case kindFloat32: + return f32hash(p, h) + case kindFloat64: + return f64hash(p, h) + case kindComplex64: + return c64hash(p, h) + case kindComplex128: + return c128hash(p, h) + case kindString: + return strhash(p, h) + case kindInterface: + i := (*interfacetype)(unsafe.Pointer(t)) + if len(i.methods) == 0 { + return nilinterhash(p, h) + } + return interhash(p, h) + case kindArray: + a := (*arraytype)(unsafe.Pointer(t)) + for i := uintptr(0); i < a.len; i++ { + h = typehash(a.elem, add(p, i*a.elem.size), h) + } + return h + case kindStruct: + s := (*structtype)(unsafe.Pointer(t)) + for _, f := range s.fields { + // TODO: maybe we could hash several contiguous fields all at once. + if f.name != nil && *f.name == "_" { + continue + } + h = typehash(f.typ, add(p, f.offset()), h) + } + return h + default: + // Should never happen, as typehash should only be called + // with comparable types. + panic(errorString("hash of unhashable type " + t.string())) } } +//go:linkname reflect_typehash reflect.typehash +func reflect_typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { + return typehash(t, p, h) +} + func memequal0(p, q unsafe.Pointer) bool { return true } @@ -209,7 +272,7 @@ func efaceeq(x, y eface) bool { if t == nil { return true } - eq := t.equalfn + eq := t.equal if eq == nil { panic(errorString("comparing uncomparable type " + t.string())) } @@ -230,7 +293,7 @@ func ifaceeq(x, y iface) bool { if t != *(**_type)(y.tab) { return false } - eq := t.equalfn + eq := t.equal if eq == nil { panic(errorString("comparing uncomparable type " + t.string())) } @@ -251,7 +314,7 @@ func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool { if xt != t { return false } - eq := t.equalfn + eq := t.equal if eq == nil { panic(errorString("comparing uncomparable type " + t.string())) } @@ -272,7 +335,7 @@ func ifaceefaceeq(x iface, y eface) bool { if xt != y._type { return false } - eq := xt.equalfn + eq := xt.equal if eq == nil { panic(errorString("comparing uncomparable type " + xt.string())) } @@ -289,7 +352,7 @@ func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool { if x._type != t { return false } - eq := t.equalfn + eq := t.equal if eq == nil { panic(errorString("comparing uncomparable type " + t.string())) } |