1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 c0 = uintptr((8-sys.PtrSize)/4*2860486313 + (sys.PtrSize-4)/4*33054211828000289)
14 c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503)
17 // type algorithms - known to compiler
44 // typeAlg is also copied/used in reflect/type.go.
47 // function for hashing objects of this type
48 // (ptr to object, seed) -> hash
49 hash func(unsafe.Pointer, uintptr) uintptr
50 // function for comparing objects of this type
51 // (ptr to object A, ptr to object B) -> ==?
52 equal func(unsafe.Pointer, unsafe.Pointer) bool
55 func memhash0(p unsafe.Pointer, h uintptr) uintptr {
58 func memhash8(p unsafe.Pointer, h uintptr) uintptr {
59 return memhash(p, h, 1)
61 func memhash16(p unsafe.Pointer, h uintptr) uintptr {
62 return memhash(p, h, 2)
64 func memhash32(p unsafe.Pointer, h uintptr) uintptr {
65 return memhash(p, h, 4)
67 func memhash64(p unsafe.Pointer, h uintptr) uintptr {
68 return memhash(p, h, 8)
70 func memhash128(p unsafe.Pointer, h uintptr) uintptr {
71 return memhash(p, h, 16)
74 // memhash_varlen is defined in assembly because it needs access
75 // to the closure. It appears here to provide an argument
76 // signature for the assembly routine.
77 func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
79 var algarray = [alg_max]typeAlg{
80 alg_MEM: {nil, nil}, // not used
81 alg_MEM0: {memhash0, memequal0},
82 alg_MEM8: {memhash8, memequal8},
83 alg_MEM16: {memhash16, memequal16},
84 alg_MEM32: {memhash32, memequal32},
85 alg_MEM64: {memhash64, memequal64},
86 alg_MEM128: {memhash128, memequal128},
88 alg_NOEQ0: {nil, nil},
89 alg_NOEQ8: {nil, nil},
90 alg_NOEQ16: {nil, nil},
91 alg_NOEQ32: {nil, nil},
92 alg_NOEQ64: {nil, nil},
93 alg_NOEQ128: {nil, nil},
94 alg_STRING: {strhash, strequal},
95 alg_INTER: {interhash, interequal},
96 alg_NILINTER: {nilinterhash, nilinterequal},
97 alg_SLICE: {nil, nil},
98 alg_FLOAT32: {f32hash, f32equal},
99 alg_FLOAT64: {f64hash, f64equal},
100 alg_CPLX64: {c64hash, c64equal},
101 alg_CPLX128: {c128hash, c128equal},
107 func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
108 func aeshash32(p unsafe.Pointer, h uintptr) uintptr
109 func aeshash64(p unsafe.Pointer, h uintptr) uintptr
110 func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
112 func strhash(a unsafe.Pointer, h uintptr) uintptr {
113 x := (*stringStruct)(a)
114 return memhash(x.str, h, uintptr(x.len))
117 // NOTE: Because NaN != NaN, a map can contain any
118 // number of (mostly useless) entries keyed with NaNs.
119 // To avoid long hash chains, we assign a random number
120 // as the hash value for a NaN.
122 func f32hash(p unsafe.Pointer, h uintptr) uintptr {
126 return c1 * (c0 ^ h) // +0, -0
128 return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
130 return memhash(p, h, 4)
134 func f64hash(p unsafe.Pointer, h uintptr) uintptr {
138 return c1 * (c0 ^ h) // +0, -0
140 return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
142 return memhash(p, h, 8)
146 func c64hash(p unsafe.Pointer, h uintptr) uintptr {
147 x := (*[2]float32)(p)
148 return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
151 func c128hash(p unsafe.Pointer, h uintptr) uintptr {
152 x := (*[2]float64)(p)
153 return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
156 func interhash(p unsafe.Pointer, h uintptr) uintptr {
165 panic(errorString("hash of unhashable type " + *t._string))
167 if isDirectIface(t) {
168 return c1 * fn(unsafe.Pointer(&a.data), h^c0)
170 return c1 * fn(a.data, h^c0)
174 func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
182 panic(errorString("hash of unhashable type " + *t._string))
184 if isDirectIface(t) {
185 return c1 * fn(unsafe.Pointer(&a.data), h^c0)
187 return c1 * fn(a.data, h^c0)
191 func memequal(p, q unsafe.Pointer, size uintptr) bool {
195 return memeq(p, q, size)
198 func memequal0(p, q unsafe.Pointer) bool {
201 func memequal8(p, q unsafe.Pointer) bool {
202 return *(*int8)(p) == *(*int8)(q)
204 func memequal16(p, q unsafe.Pointer) bool {
205 return *(*int16)(p) == *(*int16)(q)
207 func memequal32(p, q unsafe.Pointer) bool {
208 return *(*int32)(p) == *(*int32)(q)
210 func memequal64(p, q unsafe.Pointer) bool {
211 return *(*int64)(p) == *(*int64)(q)
213 func memequal128(p, q unsafe.Pointer) bool {
214 return *(*[2]int64)(p) == *(*[2]int64)(q)
216 func f32equal(p, q unsafe.Pointer) bool {
217 return *(*float32)(p) == *(*float32)(q)
219 func f64equal(p, q unsafe.Pointer) bool {
220 return *(*float64)(p) == *(*float64)(q)
222 func c64equal(p, q unsafe.Pointer) bool {
223 return *(*complex64)(p) == *(*complex64)(q)
225 func c128equal(p, q unsafe.Pointer) bool {
226 return *(*complex128)(p) == *(*complex128)(q)
228 func strequal(p, q unsafe.Pointer) bool {
229 return *(*string)(p) == *(*string)(q)
231 func interequal(p, q unsafe.Pointer) bool {
232 return ifaceeq(*(*iface)(p), *(*iface)(q))
234 func nilinterequal(p, q unsafe.Pointer) bool {
235 return efaceeq(*(*eface)(p), *(*eface)(q))
237 func efaceeq(x, y eface) bool {
247 panic(errorString("comparing uncomparable type " + *t._string))
249 if isDirectIface(t) {
250 return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
252 return eq(x.data, y.data)
254 func ifaceeq(x, y iface) bool {
265 panic(errorString("comparing uncomparable type " + *t._string))
267 if isDirectIface(t) {
268 return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
270 return eq(x.data, y.data)
273 // Testing adapters for hash quality tests (see hash_test.go)
274 func stringHash(s string, seed uintptr) uintptr {
275 return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
278 func bytesHash(b []byte, seed uintptr) uintptr {
279 s := (*slice)(unsafe.Pointer(&b))
280 return memhash(s.array, seed, uintptr(s.len))
283 func int32Hash(i uint32, seed uintptr) uintptr {
284 return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
287 func int64Hash(i uint64, seed uintptr) uintptr {
288 return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
291 func efaceHash(i interface{}, seed uintptr) uintptr {
292 return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
295 func ifaceHash(i interface {
297 }, seed uintptr) uintptr {
298 return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
301 // Testing adapter for memclr
302 func memclrBytes(b []byte) {
303 s := (*slice)(unsafe.Pointer(&b))
304 memclr(s.array, uintptr(s.len))
307 const hashRandomBytes = sys.PtrSize / 4 * 64
309 // used in asm_{386,amd64}.s to seed the hash function
310 var aeskeysched [hashRandomBytes]byte
312 // used in hash{32,64}.go to seed the hash function
313 var hashkey [4]uintptr
316 // Install aes hash algorithm if we have the instructions we need
317 if (GOARCH == "386" || GOARCH == "amd64") &&
319 cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
320 cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
321 cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
323 algarray[alg_MEM32].hash = aeshash32
324 algarray[alg_MEM64].hash = aeshash64
325 algarray[alg_STRING].hash = aeshashstr
326 // Initialize with random data so hash collisions will be hard to engineer.
327 getRandomData(aeskeysched[:])
330 getRandomData((*[len(hashkey) * sys.PtrSize]byte)(unsafe.Pointer(&hashkey))[:])
331 hashkey[0] |= 1 // make sure these numbers are odd