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 5package runtime 6 7import ( 8 "internal/abi" 9 "internal/cpu" 10 "internal/goarch" 11 "unsafe" 12) 13 14const ( 15 c0 = uintptr((8-goarch.PtrSize)/4*2860486313 + (goarch.PtrSize-4)/4*33054211828000289) 16 c1 = uintptr((8-goarch.PtrSize)/4*3267000013 + (goarch.PtrSize-4)/4*23344194077549503) 17) 18 19func memhash0(p unsafe.Pointer, h uintptr) uintptr { 20 return h 21} 22 23func memhash8(p unsafe.Pointer, h uintptr) uintptr { 24 return memhash(p, h, 1) 25} 26 27func memhash16(p unsafe.Pointer, h uintptr) uintptr { 28 return memhash(p, h, 2) 29} 30 31func memhash128(p unsafe.Pointer, h uintptr) uintptr { 32 return memhash(p, h, 16) 33} 34 35//go:nosplit 36func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr { 37 ptr := getclosureptr() 38 size := *(*uintptr)(unsafe.Pointer(ptr + unsafe.Sizeof(h))) 39 return memhash(p, h, size) 40} 41 42// runtime variable to check if the processor we're running on 43// actually supports the instructions used by the AES-based 44// hash implementation. 45var useAeshash bool 46 47// in asm_*.s 48 49// memhash should be an internal detail, 50// but widely used packages access it using linkname. 51// Notable members of the hall of shame include: 52// - github.com/aacfactory/fns 53// - github.com/dgraph-io/ristretto 54// - github.com/minio/simdjson-go 55// - github.com/nbd-wtf/go-nostr 56// - github.com/outcaste-io/ristretto 57// - github.com/puzpuzpuz/xsync/v2 58// - github.com/puzpuzpuz/xsync/v3 59// - github.com/segmentio/parquet-go 60// - github.com/parquet-go/parquet-go 61// - github.com/authzed/spicedb 62// - github.com/pingcap/badger 63// 64// Do not remove or change the type signature. 65// See go.dev/issue/67401. 66// 67//go:linkname memhash 68func memhash(p unsafe.Pointer, h, s uintptr) uintptr 69 70// memhash32 should be an internal detail, 71// but widely used packages access it using linkname. 72// Notable members of the hall of shame include: 73// - github.com/segmentio/parquet-go 74// - github.com/parquet-go/parquet-go 75// 76// Do not remove or change the type signature. 77// See go.dev/issue/67401. 78// 79//go:linkname memhash32 80func memhash32(p unsafe.Pointer, h uintptr) uintptr 81 82// memhash64 should be an internal detail, 83// but widely used packages access it using linkname. 84// Notable members of the hall of shame include: 85// - github.com/segmentio/parquet-go 86// - github.com/parquet-go/parquet-go 87// 88// Do not remove or change the type signature. 89// See go.dev/issue/67401. 90// 91//go:linkname memhash64 92func memhash64(p unsafe.Pointer, h uintptr) uintptr 93 94// strhash should be an internal detail, 95// but widely used packages access it using linkname. 96// Notable members of the hall of shame include: 97// - github.com/aristanetworks/goarista 98// - github.com/bytedance/sonic 99// - github.com/bytedance/go-tagexpr/v2 100// - github.com/cloudwego/frugal 101// - github.com/cloudwego/dynamicgo 102// - github.com/v2fly/v2ray-core/v5 103// 104// Do not remove or change the type signature. 105// See go.dev/issue/67401. 106// 107//go:linkname strhash 108func strhash(p unsafe.Pointer, h uintptr) uintptr 109 110func strhashFallback(a unsafe.Pointer, h uintptr) uintptr { 111 x := (*stringStruct)(a) 112 return memhashFallback(x.str, h, uintptr(x.len)) 113} 114 115// NOTE: Because NaN != NaN, a map can contain any 116// number of (mostly useless) entries keyed with NaNs. 117// To avoid long hash chains, we assign a random number 118// as the hash value for a NaN. 119 120func f32hash(p unsafe.Pointer, h uintptr) uintptr { 121 f := *(*float32)(p) 122 switch { 123 case f == 0: 124 return c1 * (c0 ^ h) // +0, -0 125 case f != f: 126 return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN 127 default: 128 return memhash(p, h, 4) 129 } 130} 131 132func f64hash(p unsafe.Pointer, h uintptr) uintptr { 133 f := *(*float64)(p) 134 switch { 135 case f == 0: 136 return c1 * (c0 ^ h) // +0, -0 137 case f != f: 138 return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN 139 default: 140 return memhash(p, h, 8) 141 } 142} 143 144func c64hash(p unsafe.Pointer, h uintptr) uintptr { 145 x := (*[2]float32)(p) 146 return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h)) 147} 148 149func c128hash(p unsafe.Pointer, h uintptr) uintptr { 150 x := (*[2]float64)(p) 151 return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h)) 152} 153 154func interhash(p unsafe.Pointer, h uintptr) uintptr { 155 a := (*iface)(p) 156 tab := a.tab 157 if tab == nil { 158 return h 159 } 160 t := tab.Type 161 if t.Equal == nil { 162 // Check hashability here. We could do this check inside 163 // typehash, but we want to report the topmost type in 164 // the error text (e.g. in a struct with a field of slice type 165 // we want to report the struct, not the slice). 166 panic(errorString("hash of unhashable type " + toRType(t).string())) 167 } 168 if isDirectIface(t) { 169 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) 170 } else { 171 return c1 * typehash(t, a.data, h^c0) 172 } 173} 174 175// nilinterhash should be an internal detail, 176// but widely used packages access it using linkname. 177// Notable members of the hall of shame include: 178// - github.com/anacrolix/stm 179// - github.com/aristanetworks/goarista 180// 181// Do not remove or change the type signature. 182// See go.dev/issue/67401. 183// 184//go:linkname nilinterhash 185func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { 186 a := (*eface)(p) 187 t := a._type 188 if t == nil { 189 return h 190 } 191 if t.Equal == nil { 192 // See comment in interhash above. 193 panic(errorString("hash of unhashable type " + toRType(t).string())) 194 } 195 if isDirectIface(t) { 196 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0) 197 } else { 198 return c1 * typehash(t, a.data, h^c0) 199 } 200} 201 202// typehash computes the hash of the object of type t at address p. 203// h is the seed. 204// This function is seldom used. Most maps use for hashing either 205// fixed functions (e.g. f32hash) or compiler-generated functions 206// (e.g. for a type like struct { x, y string }). This implementation 207// is slower but more general and is used for hashing interface types 208// (called from interhash or nilinterhash, above) or for hashing in 209// maps generated by reflect.MapOf (reflect_typehash, below). 210// Note: this function must match the compiler generated 211// functions exactly. See issue 37716. 212// 213// typehash should be an internal detail, 214// but widely used packages access it using linkname. 215// Notable members of the hall of shame include: 216// - github.com/puzpuzpuz/xsync/v2 217// - github.com/puzpuzpuz/xsync/v3 218// 219// Do not remove or change the type signature. 220// See go.dev/issue/67401. 221// 222//go:linkname typehash 223func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { 224 if t.TFlag&abi.TFlagRegularMemory != 0 { 225 // Handle ptr sizes specially, see issue 37086. 226 switch t.Size_ { 227 case 4: 228 return memhash32(p, h) 229 case 8: 230 return memhash64(p, h) 231 default: 232 return memhash(p, h, t.Size_) 233 } 234 } 235 switch t.Kind_ & abi.KindMask { 236 case abi.Float32: 237 return f32hash(p, h) 238 case abi.Float64: 239 return f64hash(p, h) 240 case abi.Complex64: 241 return c64hash(p, h) 242 case abi.Complex128: 243 return c128hash(p, h) 244 case abi.String: 245 return strhash(p, h) 246 case abi.Interface: 247 i := (*interfacetype)(unsafe.Pointer(t)) 248 if len(i.Methods) == 0 { 249 return nilinterhash(p, h) 250 } 251 return interhash(p, h) 252 case abi.Array: 253 a := (*arraytype)(unsafe.Pointer(t)) 254 for i := uintptr(0); i < a.Len; i++ { 255 h = typehash(a.Elem, add(p, i*a.Elem.Size_), h) 256 } 257 return h 258 case abi.Struct: 259 s := (*structtype)(unsafe.Pointer(t)) 260 for _, f := range s.Fields { 261 if f.Name.IsBlank() { 262 continue 263 } 264 h = typehash(f.Typ, add(p, f.Offset), h) 265 } 266 return h 267 default: 268 // Should never happen, as typehash should only be called 269 // with comparable types. 270 panic(errorString("hash of unhashable type " + toRType(t).string())) 271 } 272} 273 274func mapKeyError(t *maptype, p unsafe.Pointer) error { 275 if !t.HashMightPanic() { 276 return nil 277 } 278 return mapKeyError2(t.Key, p) 279} 280 281func mapKeyError2(t *_type, p unsafe.Pointer) error { 282 if t.TFlag&abi.TFlagRegularMemory != 0 { 283 return nil 284 } 285 switch t.Kind_ & abi.KindMask { 286 case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String: 287 return nil 288 case abi.Interface: 289 i := (*interfacetype)(unsafe.Pointer(t)) 290 var t *_type 291 var pdata *unsafe.Pointer 292 if len(i.Methods) == 0 { 293 a := (*eface)(p) 294 t = a._type 295 if t == nil { 296 return nil 297 } 298 pdata = &a.data 299 } else { 300 a := (*iface)(p) 301 if a.tab == nil { 302 return nil 303 } 304 t = a.tab.Type 305 pdata = &a.data 306 } 307 308 if t.Equal == nil { 309 return errorString("hash of unhashable type " + toRType(t).string()) 310 } 311 312 if isDirectIface(t) { 313 return mapKeyError2(t, unsafe.Pointer(pdata)) 314 } else { 315 return mapKeyError2(t, *pdata) 316 } 317 case abi.Array: 318 a := (*arraytype)(unsafe.Pointer(t)) 319 for i := uintptr(0); i < a.Len; i++ { 320 if err := mapKeyError2(a.Elem, add(p, i*a.Elem.Size_)); err != nil { 321 return err 322 } 323 } 324 return nil 325 case abi.Struct: 326 s := (*structtype)(unsafe.Pointer(t)) 327 for _, f := range s.Fields { 328 if f.Name.IsBlank() { 329 continue 330 } 331 if err := mapKeyError2(f.Typ, add(p, f.Offset)); err != nil { 332 return err 333 } 334 } 335 return nil 336 default: 337 // Should never happen, keep this case for robustness. 338 return errorString("hash of unhashable type " + toRType(t).string()) 339 } 340} 341 342//go:linkname reflect_typehash reflect.typehash 343func reflect_typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { 344 return typehash(t, p, h) 345} 346 347func memequal0(p, q unsafe.Pointer) bool { 348 return true 349} 350func memequal8(p, q unsafe.Pointer) bool { 351 return *(*int8)(p) == *(*int8)(q) 352} 353func memequal16(p, q unsafe.Pointer) bool { 354 return *(*int16)(p) == *(*int16)(q) 355} 356func memequal32(p, q unsafe.Pointer) bool { 357 return *(*int32)(p) == *(*int32)(q) 358} 359func memequal64(p, q unsafe.Pointer) bool { 360 return *(*int64)(p) == *(*int64)(q) 361} 362func memequal128(p, q unsafe.Pointer) bool { 363 return *(*[2]int64)(p) == *(*[2]int64)(q) 364} 365func f32equal(p, q unsafe.Pointer) bool { 366 return *(*float32)(p) == *(*float32)(q) 367} 368func f64equal(p, q unsafe.Pointer) bool { 369 return *(*float64)(p) == *(*float64)(q) 370} 371func c64equal(p, q unsafe.Pointer) bool { 372 return *(*complex64)(p) == *(*complex64)(q) 373} 374func c128equal(p, q unsafe.Pointer) bool { 375 return *(*complex128)(p) == *(*complex128)(q) 376} 377func strequal(p, q unsafe.Pointer) bool { 378 return *(*string)(p) == *(*string)(q) 379} 380func interequal(p, q unsafe.Pointer) bool { 381 x := *(*iface)(p) 382 y := *(*iface)(q) 383 return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data) 384} 385func nilinterequal(p, q unsafe.Pointer) bool { 386 x := *(*eface)(p) 387 y := *(*eface)(q) 388 return x._type == y._type && efaceeq(x._type, x.data, y.data) 389} 390func efaceeq(t *_type, x, y unsafe.Pointer) bool { 391 if t == nil { 392 return true 393 } 394 eq := t.Equal 395 if eq == nil { 396 panic(errorString("comparing uncomparable type " + toRType(t).string())) 397 } 398 if isDirectIface(t) { 399 // Direct interface types are ptr, chan, map, func, and single-element structs/arrays thereof. 400 // Maps and funcs are not comparable, so they can't reach here. 401 // Ptrs, chans, and single-element items can be compared directly using ==. 402 return x == y 403 } 404 return eq(x, y) 405} 406func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { 407 if tab == nil { 408 return true 409 } 410 t := tab.Type 411 eq := t.Equal 412 if eq == nil { 413 panic(errorString("comparing uncomparable type " + toRType(t).string())) 414 } 415 if isDirectIface(t) { 416 // See comment in efaceeq. 417 return x == y 418 } 419 return eq(x, y) 420} 421 422// Testing adapters for hash quality tests (see hash_test.go) 423// 424// stringHash should be an internal detail, 425// but widely used packages access it using linkname. 426// Notable members of the hall of shame include: 427// - github.com/k14s/starlark-go 428// 429// Do not remove or change the type signature. 430// See go.dev/issue/67401. 431// 432//go:linkname stringHash 433func stringHash(s string, seed uintptr) uintptr { 434 return strhash(noescape(unsafe.Pointer(&s)), seed) 435} 436 437func bytesHash(b []byte, seed uintptr) uintptr { 438 s := (*slice)(unsafe.Pointer(&b)) 439 return memhash(s.array, seed, uintptr(s.len)) 440} 441 442func int32Hash(i uint32, seed uintptr) uintptr { 443 return memhash32(noescape(unsafe.Pointer(&i)), seed) 444} 445 446func int64Hash(i uint64, seed uintptr) uintptr { 447 return memhash64(noescape(unsafe.Pointer(&i)), seed) 448} 449 450func efaceHash(i any, seed uintptr) uintptr { 451 return nilinterhash(noescape(unsafe.Pointer(&i)), seed) 452} 453 454func ifaceHash(i interface { 455 F() 456}, seed uintptr) uintptr { 457 return interhash(noescape(unsafe.Pointer(&i)), seed) 458} 459 460const hashRandomBytes = goarch.PtrSize / 4 * 64 461 462// used in asm_{386,amd64,arm64}.s to seed the hash function 463var aeskeysched [hashRandomBytes]byte 464 465// used in hash{32,64}.go to seed the hash function 466var hashkey [4]uintptr 467 468func alginit() { 469 // Install AES hash algorithms if the instructions needed are present. 470 if (GOARCH == "386" || GOARCH == "amd64") && 471 cpu.X86.HasAES && // AESENC 472 cpu.X86.HasSSSE3 && // PSHUFB 473 cpu.X86.HasSSE41 { // PINSR{D,Q} 474 initAlgAES() 475 return 476 } 477 if GOARCH == "arm64" && cpu.ARM64.HasAES { 478 initAlgAES() 479 return 480 } 481 for i := range hashkey { 482 hashkey[i] = uintptr(bootstrapRand()) 483 } 484} 485 486func initAlgAES() { 487 useAeshash = true 488 // Initialize with random data so hash collisions will be hard to engineer. 489 key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched)) 490 for i := range key { 491 key[i] = bootstrapRand() 492 } 493} 494 495// Note: These routines perform the read with a native endianness. 496func readUnaligned32(p unsafe.Pointer) uint32 { 497 q := (*[4]byte)(p) 498 if goarch.BigEndian { 499 return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24 500 } 501 return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 502} 503 504func readUnaligned64(p unsafe.Pointer) uint64 { 505 q := (*[8]byte)(p) 506 if goarch.BigEndian { 507 return uint64(q[7]) | uint64(q[6])<<8 | uint64(q[5])<<16 | uint64(q[4])<<24 | 508 uint64(q[3])<<32 | uint64(q[2])<<40 | uint64(q[1])<<48 | uint64(q[0])<<56 509 } 510 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 511} 512