github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/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 ( 8 "github.com/c12o16h1/go/src/internal/cpu" 9 "runtime/internal/sys" 10 "unsafe" 11 ) 12 13 const ( 14 c0 = uintptr((8-sys.PtrSize)/4*2860486313 + (sys.PtrSize-4)/4*33054211828000289) 15 c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503) 16 ) 17 18 // type algorithms - known to compiler 19 const ( 20 alg_NOEQ = iota 21 alg_MEM0 22 alg_MEM8 23 alg_MEM16 24 alg_MEM32 25 alg_MEM64 26 alg_MEM128 27 alg_STRING 28 alg_INTER 29 alg_NILINTER 30 alg_FLOAT32 31 alg_FLOAT64 32 alg_CPLX64 33 alg_CPLX128 34 alg_max 35 ) 36 37 func memhash0(p unsafe.Pointer, h uintptr) uintptr { 38 return h 39 } 40 41 func memhash8(p unsafe.Pointer, h uintptr) uintptr { 42 return memhash(p, h, 1) 43 } 44 45 func memhash16(p unsafe.Pointer, h uintptr) uintptr { 46 return memhash(p, h, 2) 47 } 48 49 func memhash128(p unsafe.Pointer, h uintptr) uintptr { 50 return memhash(p, h, 16) 51 } 52 53 //go:nosplit 54 func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr { 55 ptr := getclosureptr() 56 size := *(*uintptr)(unsafe.Pointer(ptr + unsafe.Sizeof(h))) 57 return memhash(p, h, size) 58 } 59 60 // runtime variable to check if the processor we're running on 61 // actually supports the instructions used by the AES-based 62 // hash implementation. 63 var useAeshash bool 64 65 // in asm_*.s 66 func memhash(p unsafe.Pointer, h, s uintptr) uintptr 67 func memhash32(p unsafe.Pointer, h uintptr) uintptr 68 func memhash64(p unsafe.Pointer, h uintptr) uintptr 69 func strhash(p unsafe.Pointer, h uintptr) uintptr 70 71 func strhashFallback(a unsafe.Pointer, h uintptr) uintptr { 72 x := (*stringStruct)(a) 73 return memhashFallback(x.str, h, uintptr(x.len)) 74 } 75 76 // NOTE: Because NaN != NaN, a map can contain any 77 // number of (mostly useless) entries keyed with NaNs. 78 // To avoid long hash chains, we assign a random number 79 // as the hash value for a NaN. 80 81 func f32hash(p unsafe.Pointer, h uintptr) uintptr { 82 f := *(*float32)(p) 83 switch { 84 case f == 0: 85 return c1 * (c0 ^ h) // +0, -0 86 case f != f: 87 return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN 88 default: 89 return memhash(p, h, 4) 90 } 91 } 92 93 func f64hash(p unsafe.Pointer, h uintptr) uintptr { 94 f := *(*float64)(p) 95 switch { 96 case f == 0: 97 return c1 * (c0 ^ h) // +0, -0 98 case f != f: 99 return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN 100 default: 101 return memhash(p, h, 8) 102 } 103 } 104 105 func c64hash(p unsafe.Pointer, h uintptr) uintptr { 106 x := (*[2]float32)(p) 107 return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h)) 108 } 109 110 func c128hash(p unsafe.Pointer, h uintptr) uintptr { 111 x := (*[2]float64)(p) 112 return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h)) 113 } 114 115 func interhash(p unsafe.Pointer, h uintptr) uintptr { 116 a := (*iface)(p) 117 tab := a.tab 118 if tab == nil { 119 return h 120 } 121 t := tab._type 122 if t.equal == nil { 123 // Check hashability here. We could do this check inside 124 // typehash, but we want to report the topmost type in 125 // the error text (e.g. in a struct with a field of slice type 126 // we want to report the struct, not the slice). 127 panic(errorString("hash of unhashable type " + t.string())) 128 } 129 if isDirectIface(t) { 130 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) 131 } else { 132 return c1 * typehash(t, a.data, h^c0) 133 } 134 } 135 136 func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { 137 a := (*eface)(p) 138 t := a._type 139 if t == nil { 140 return h 141 } 142 if t.equal == nil { 143 // See comment in interhash above. 144 panic(errorString("hash of unhashable type " + t.string())) 145 } 146 if isDirectIface(t) { 147 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) 148 } else { 149 return c1 * typehash(t, a.data, h^c0) 150 } 151 } 152 153 // typehash computes the hash of the object of type t at address p. 154 // h is the seed. 155 // This function is seldom used. Most maps use for hashing either 156 // fixed functions (e.g. f32hash) or compiler-generated functions 157 // (e.g. for a type like struct { x, y string }). This implementation 158 // is slower but more general and is used for hashing interface types 159 // (called from interhash or nilinterhash, above) or for hashing in 160 // maps generated by reflect.MapOf (reflect_typehash, below). 161 func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { 162 if t.tflag&tflagRegularMemory != 0 { 163 return memhash(p, h, t.size) 164 } 165 switch t.kind & kindMask { 166 case kindFloat32: 167 return f32hash(p, h) 168 case kindFloat64: 169 return f64hash(p, h) 170 case kindComplex64: 171 return c64hash(p, h) 172 case kindComplex128: 173 return c128hash(p, h) 174 case kindString: 175 return strhash(p, h) 176 case kindInterface: 177 i := (*interfacetype)(unsafe.Pointer(t)) 178 if len(i.mhdr) == 0 { 179 return nilinterhash(p, h) 180 } 181 return interhash(p, h) 182 case kindArray: 183 a := (*arraytype)(unsafe.Pointer(t)) 184 for i := uintptr(0); i < a.len; i++ { 185 h = typehash(a.elem, add(p, i*a.elem.size), h) 186 } 187 return h 188 case kindStruct: 189 s := (*structtype)(unsafe.Pointer(t)) 190 for _, f := range s.fields { 191 // TODO: maybe we could hash several contiguous fields all at once. 192 if f.name.isBlank() { 193 continue 194 } 195 h = typehash(f.typ, add(p, f.offset()), h) 196 } 197 return h 198 default: 199 // Should never happen, as typehash should only be called 200 // with comparable types. 201 panic(errorString("hash of unhashable type " + t.string())) 202 } 203 } 204 205 //go:linkname reflect_typehash reflect.typehash 206 func reflect_typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { 207 return typehash(t, p, h) 208 } 209 210 func memequal0(p, q unsafe.Pointer) bool { 211 return true 212 } 213 func memequal8(p, q unsafe.Pointer) bool { 214 return *(*int8)(p) == *(*int8)(q) 215 } 216 func memequal16(p, q unsafe.Pointer) bool { 217 return *(*int16)(p) == *(*int16)(q) 218 } 219 func memequal32(p, q unsafe.Pointer) bool { 220 return *(*int32)(p) == *(*int32)(q) 221 } 222 func memequal64(p, q unsafe.Pointer) bool { 223 return *(*int64)(p) == *(*int64)(q) 224 } 225 func memequal128(p, q unsafe.Pointer) bool { 226 return *(*[2]int64)(p) == *(*[2]int64)(q) 227 } 228 func f32equal(p, q unsafe.Pointer) bool { 229 return *(*float32)(p) == *(*float32)(q) 230 } 231 func f64equal(p, q unsafe.Pointer) bool { 232 return *(*float64)(p) == *(*float64)(q) 233 } 234 func c64equal(p, q unsafe.Pointer) bool { 235 return *(*complex64)(p) == *(*complex64)(q) 236 } 237 func c128equal(p, q unsafe.Pointer) bool { 238 return *(*complex128)(p) == *(*complex128)(q) 239 } 240 func strequal(p, q unsafe.Pointer) bool { 241 return *(*string)(p) == *(*string)(q) 242 } 243 func interequal(p, q unsafe.Pointer) bool { 244 x := *(*iface)(p) 245 y := *(*iface)(q) 246 return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data) 247 } 248 func nilinterequal(p, q unsafe.Pointer) bool { 249 x := *(*eface)(p) 250 y := *(*eface)(q) 251 return x._type == y._type && efaceeq(x._type, x.data, y.data) 252 } 253 func efaceeq(t *_type, x, y unsafe.Pointer) bool { 254 if t == nil { 255 return true 256 } 257 eq := t.equal 258 if eq == nil { 259 panic(errorString("comparing uncomparable type " + t.string())) 260 } 261 if isDirectIface(t) { 262 // Direct interface types are ptr, chan, map, func, and single-element structs/arrays thereof. 263 // Maps and funcs are not comparable, so they can't reach here. 264 // Ptrs, chans, and single-element items can be compared directly using ==. 265 return x == y 266 } 267 return eq(x, y) 268 } 269 func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { 270 if tab == nil { 271 return true 272 } 273 t := tab._type 274 eq := t.equal 275 if eq == nil { 276 panic(errorString("comparing uncomparable type " + t.string())) 277 } 278 if isDirectIface(t) { 279 // See comment in efaceeq. 280 return x == y 281 } 282 return eq(x, y) 283 } 284 285 // Testing adapters for hash quality tests (see hash_test.go) 286 func stringHash(s string, seed uintptr) uintptr { 287 return strhash(noescape(unsafe.Pointer(&s)), seed) 288 } 289 290 func bytesHash(b []byte, seed uintptr) uintptr { 291 s := (*slice)(unsafe.Pointer(&b)) 292 return memhash(s.array, seed, uintptr(s.len)) 293 } 294 295 func int32Hash(i uint32, seed uintptr) uintptr { 296 return memhash32(noescape(unsafe.Pointer(&i)), seed) 297 } 298 299 func int64Hash(i uint64, seed uintptr) uintptr { 300 return memhash64(noescape(unsafe.Pointer(&i)), seed) 301 } 302 303 func efaceHash(i interface{}, seed uintptr) uintptr { 304 return nilinterhash(noescape(unsafe.Pointer(&i)), seed) 305 } 306 307 func ifaceHash(i interface { 308 F() 309 }, seed uintptr) uintptr { 310 return interhash(noescape(unsafe.Pointer(&i)), seed) 311 } 312 313 const hashRandomBytes = sys.PtrSize / 4 * 64 314 315 // used in asm_{386,amd64,arm64}.s to seed the hash function 316 var aeskeysched [hashRandomBytes]byte 317 318 // used in hash{32,64}.go to seed the hash function 319 var hashkey [4]uintptr 320 321 func alginit() { 322 // Install AES hash algorithms if the instructions needed are present. 323 if (GOARCH == "386" || GOARCH == "amd64") && 324 cpu.X86.HasAES && // AESENC 325 cpu.X86.HasSSSE3 && // PSHUFB 326 cpu.X86.HasSSE41 { // PINSR{D,Q} 327 initAlgAES() 328 return 329 } 330 if GOARCH == "arm64" && cpu.ARM64.HasAES { 331 initAlgAES() 332 return 333 } 334 getRandomData((*[len(hashkey) * sys.PtrSize]byte)(unsafe.Pointer(&hashkey))[:]) 335 hashkey[0] |= 1 // make sure these numbers are odd 336 hashkey[1] |= 1 337 hashkey[2] |= 1 338 hashkey[3] |= 1 339 } 340 341 func initAlgAES() { 342 useAeshash = true 343 // Initialize with random data so hash collisions will be hard to engineer. 344 getRandomData(aeskeysched[:]) 345 } 346 347 // Note: These routines perform the read with a native endianness. 348 func readUnaligned32(p unsafe.Pointer) uint32 { 349 q := (*[4]byte)(p) 350 if sys.BigEndian { 351 return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24 352 } 353 return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 354 } 355 356 func readUnaligned64(p unsafe.Pointer) uint64 { 357 q := (*[8]byte)(p) 358 if sys.BigEndian { 359 return uint64(q[7]) | uint64(q[6])<<8 | uint64(q[5])<<16 | uint64(q[4])<<24 | 360 uint64(q[3])<<32 | uint64(q[2])<<40 | uint64(q[1])<<48 | uint64(q[0])<<56 361 } 362 return uint64(q[0]) | uint64(q[1])<<8 | uint64(q[2])<<16 | uint64(q[3])<<24 | uint64(q[4])<<32 | uint64(q[5])<<40 | uint64(q[6])<<48 | uint64(q[7])<<56 363 }