github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/alg.go (about) 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. 4 5 package runtime 6 7 import "unsafe" 8 9 const ( 10 c0 = uintptr((8-ptrSize)/4*2860486313 + (ptrSize-4)/4*33054211828000289) 11 c1 = uintptr((8-ptrSize)/4*3267000013 + (ptrSize-4)/4*23344194077549503) 12 ) 13 14 // type algorithms - known to compiler 15 const ( 16 alg_MEM = iota 17 alg_MEM0 18 alg_MEM8 19 alg_MEM16 20 alg_MEM32 21 alg_MEM64 22 alg_MEM128 23 alg_NOEQ 24 alg_NOEQ0 25 alg_NOEQ8 26 alg_NOEQ16 27 alg_NOEQ32 28 alg_NOEQ64 29 alg_NOEQ128 30 alg_STRING 31 alg_INTER 32 alg_NILINTER 33 alg_SLICE 34 alg_FLOAT32 35 alg_FLOAT64 36 alg_CPLX64 37 alg_CPLX128 38 alg_max 39 ) 40 41 type typeAlg struct { 42 // function for hashing objects of this type 43 // (ptr to object, seed) -> hash 44 hash func(unsafe.Pointer, uintptr) uintptr 45 // function for comparing objects of this type 46 // (ptr to object A, ptr to object B) -> ==? 47 equal func(unsafe.Pointer, unsafe.Pointer) bool 48 } 49 50 func memhash0(p unsafe.Pointer, h uintptr) uintptr { 51 return h 52 } 53 func memhash8(p unsafe.Pointer, h uintptr) uintptr { 54 return memhash(p, h, 1) 55 } 56 func memhash16(p unsafe.Pointer, h uintptr) uintptr { 57 return memhash(p, h, 2) 58 } 59 func memhash32(p unsafe.Pointer, h uintptr) uintptr { 60 return memhash(p, h, 4) 61 } 62 func memhash64(p unsafe.Pointer, h uintptr) uintptr { 63 return memhash(p, h, 8) 64 } 65 func memhash128(p unsafe.Pointer, h uintptr) uintptr { 66 return memhash(p, h, 16) 67 } 68 69 // memhash_varlen is defined in assembly because it needs access 70 // to the closure. It appears here to provide an argument 71 // signature for the assembly routine. 72 func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr 73 74 var algarray = [alg_max]typeAlg{ 75 alg_MEM: {nil, nil}, // not used 76 alg_MEM0: {memhash0, memequal0}, 77 alg_MEM8: {memhash8, memequal8}, 78 alg_MEM16: {memhash16, memequal16}, 79 alg_MEM32: {memhash32, memequal32}, 80 alg_MEM64: {memhash64, memequal64}, 81 alg_MEM128: {memhash128, memequal128}, 82 alg_NOEQ: {nil, nil}, 83 alg_NOEQ0: {nil, nil}, 84 alg_NOEQ8: {nil, nil}, 85 alg_NOEQ16: {nil, nil}, 86 alg_NOEQ32: {nil, nil}, 87 alg_NOEQ64: {nil, nil}, 88 alg_NOEQ128: {nil, nil}, 89 alg_STRING: {strhash, strequal}, 90 alg_INTER: {interhash, interequal}, 91 alg_NILINTER: {nilinterhash, nilinterequal}, 92 alg_SLICE: {nil, nil}, 93 alg_FLOAT32: {f32hash, f32equal}, 94 alg_FLOAT64: {f64hash, f64equal}, 95 alg_CPLX64: {c64hash, c64equal}, 96 alg_CPLX128: {c128hash, c128equal}, 97 } 98 99 var useAeshash bool 100 101 // in asm_*.s 102 func aeshash(p unsafe.Pointer, h, s uintptr) uintptr 103 func aeshash32(p unsafe.Pointer, h uintptr) uintptr 104 func aeshash64(p unsafe.Pointer, h uintptr) uintptr 105 func aeshashstr(p unsafe.Pointer, h uintptr) uintptr 106 107 func strhash(a unsafe.Pointer, h uintptr) uintptr { 108 x := (*stringStruct)(a) 109 return memhash(x.str, h, uintptr(x.len)) 110 } 111 112 // NOTE: Because NaN != NaN, a map can contain any 113 // number of (mostly useless) entries keyed with NaNs. 114 // To avoid long hash chains, we assign a random number 115 // as the hash value for a NaN. 116 117 func f32hash(p unsafe.Pointer, h uintptr) uintptr { 118 f := *(*float32)(p) 119 switch { 120 case f == 0: 121 return c1 * (c0 ^ h) // +0, -0 122 case f != f: 123 return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN 124 default: 125 return memhash(p, h, 4) 126 } 127 } 128 129 func f64hash(p unsafe.Pointer, h uintptr) uintptr { 130 f := *(*float64)(p) 131 switch { 132 case f == 0: 133 return c1 * (c0 ^ h) // +0, -0 134 case f != f: 135 return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN 136 default: 137 return memhash(p, h, 8) 138 } 139 } 140 141 func c64hash(p unsafe.Pointer, h uintptr) uintptr { 142 x := (*[2]float32)(p) 143 return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h)) 144 } 145 146 func c128hash(p unsafe.Pointer, h uintptr) uintptr { 147 x := (*[2]float64)(p) 148 return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h)) 149 } 150 151 func interhash(p unsafe.Pointer, h uintptr) uintptr { 152 a := (*iface)(p) 153 tab := a.tab 154 if tab == nil { 155 return h 156 } 157 t := tab._type 158 fn := t.alg.hash 159 if fn == nil { 160 panic(errorString("hash of unhashable type " + *t._string)) 161 } 162 if isDirectIface(t) { 163 return c1 * fn(unsafe.Pointer(&a.data), h^c0) 164 } else { 165 return c1 * fn(a.data, h^c0) 166 } 167 } 168 169 func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { 170 a := (*eface)(p) 171 t := a._type 172 if t == nil { 173 return h 174 } 175 fn := t.alg.hash 176 if fn == nil { 177 panic(errorString("hash of unhashable type " + *t._string)) 178 } 179 if isDirectIface(t) { 180 return c1 * fn(unsafe.Pointer(&a.data), h^c0) 181 } else { 182 return c1 * fn(a.data, h^c0) 183 } 184 } 185 186 func memequal(p, q unsafe.Pointer, size uintptr) bool { 187 if p == q { 188 return true 189 } 190 return memeq(p, q, size) 191 } 192 193 func memequal0(p, q unsafe.Pointer) bool { 194 return true 195 } 196 func memequal8(p, q unsafe.Pointer) bool { 197 return *(*int8)(p) == *(*int8)(q) 198 } 199 func memequal16(p, q unsafe.Pointer) bool { 200 return *(*int16)(p) == *(*int16)(q) 201 } 202 func memequal32(p, q unsafe.Pointer) bool { 203 return *(*int32)(p) == *(*int32)(q) 204 } 205 func memequal64(p, q unsafe.Pointer) bool { 206 return *(*int64)(p) == *(*int64)(q) 207 } 208 func memequal128(p, q unsafe.Pointer) bool { 209 return *(*[2]int64)(p) == *(*[2]int64)(q) 210 } 211 func f32equal(p, q unsafe.Pointer) bool { 212 return *(*float32)(p) == *(*float32)(q) 213 } 214 func f64equal(p, q unsafe.Pointer) bool { 215 return *(*float64)(p) == *(*float64)(q) 216 } 217 func c64equal(p, q unsafe.Pointer) bool { 218 return *(*complex64)(p) == *(*complex64)(q) 219 } 220 func c128equal(p, q unsafe.Pointer) bool { 221 return *(*complex128)(p) == *(*complex128)(q) 222 } 223 func strequal(p, q unsafe.Pointer) bool { 224 return *(*string)(p) == *(*string)(q) 225 } 226 func interequal(p, q unsafe.Pointer) bool { 227 return ifaceeq(*(*interface { 228 f() 229 })(p), *(*interface { 230 f() 231 })(q)) 232 } 233 func nilinterequal(p, q unsafe.Pointer) bool { 234 return efaceeq(*(*interface{})(p), *(*interface{})(q)) 235 } 236 func efaceeq(p, q interface{}) bool { 237 x := (*eface)(unsafe.Pointer(&p)) 238 y := (*eface)(unsafe.Pointer(&q)) 239 t := x._type 240 if t != y._type { 241 return false 242 } 243 if t == nil { 244 return true 245 } 246 eq := t.alg.equal 247 if eq == nil { 248 panic(errorString("comparing uncomparable type " + *t._string)) 249 } 250 if isDirectIface(t) { 251 return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) 252 } 253 return eq(x.data, y.data) 254 } 255 func ifaceeq(p, q interface { 256 f() 257 }) bool { 258 x := (*iface)(unsafe.Pointer(&p)) 259 y := (*iface)(unsafe.Pointer(&q)) 260 xtab := x.tab 261 if xtab != y.tab { 262 return false 263 } 264 if xtab == nil { 265 return true 266 } 267 t := xtab._type 268 eq := t.alg.equal 269 if eq == nil { 270 panic(errorString("comparing uncomparable type " + *t._string)) 271 } 272 if isDirectIface(t) { 273 return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) 274 } 275 return eq(x.data, y.data) 276 } 277 278 // Testing adapters for hash quality tests (see hash_test.go) 279 func stringHash(s string, seed uintptr) uintptr { 280 return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed) 281 } 282 283 func bytesHash(b []byte, seed uintptr) uintptr { 284 s := (*sliceStruct)(unsafe.Pointer(&b)) 285 return memhash(s.array, seed, uintptr(s.len)) 286 } 287 288 func int32Hash(i uint32, seed uintptr) uintptr { 289 return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed) 290 } 291 292 func int64Hash(i uint64, seed uintptr) uintptr { 293 return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed) 294 } 295 296 func efaceHash(i interface{}, seed uintptr) uintptr { 297 return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed) 298 } 299 300 func ifaceHash(i interface { 301 F() 302 }, seed uintptr) uintptr { 303 return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed) 304 } 305 306 // Testing adapter for memclr 307 func memclrBytes(b []byte) { 308 s := (*sliceStruct)(unsafe.Pointer(&b)) 309 memclr(s.array, uintptr(s.len)) 310 } 311 312 const hashRandomBytes = ptrSize / 4 * 64 313 314 // used in asm_{386,amd64}.s to seed the hash function 315 var aeskeysched [hashRandomBytes]byte 316 317 // used in hash{32,64}.go to seed the hash function 318 var hashkey [4]uintptr 319 320 func init() { 321 // Install aes hash algorithm if we have the instructions we need 322 if (GOARCH == "386" || GOARCH == "amd64") && 323 GOOS != "nacl" && 324 cpuid_ecx&(1<<25) != 0 && // aes (aesenc) 325 cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb) 326 cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q}) 327 useAeshash = true 328 algarray[alg_MEM32].hash = aeshash32 329 algarray[alg_MEM64].hash = aeshash64 330 algarray[alg_STRING].hash = aeshashstr 331 // Initialize with random data so hash collisions will be hard to engineer. 332 getRandomData(aeskeysched[:]) 333 return 334 } 335 getRandomData((*[len(hashkey) * ptrSize]byte)(unsafe.Pointer(&hashkey))[:]) 336 hashkey[0] |= 1 // make sure this number is odd 337 }