blob: 4e2da57352338a317fae124d72a2ce8b1e946f71 [file] [edit]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package maps
import (
"internal/byteorder"
"internal/cpu"
"internal/goarch"
"unsafe"
)
// 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
const hashRandomBytes = goarch.PtrSize / 4 * 64
// used to seed the hash function
var aeskeysched [hashRandomBytes]byte
// used in hash{32,64}.go to seed the hash function
var hashkey [4]uintptr
func AlgInit() {
// Install AES hash algorithms if the instructions needed are present.
if (goarch.GOARCH == "386" || goarch.GOARCH == "amd64") &&
cpu.X86.HasAES && // AESENC
cpu.X86.HasSSSE3 && // PSHUFB
cpu.X86.HasSSE41 { // PINSR{D,Q}
// In aeshashbody (that is used by memhash & strhash)
// we have global variables that should be properly aligned.
//
// See #12415
if !checkMasksAndShiftsAlignment() {
fatal("maps: global variables for AES hashing are not properly aligned!")
}
initAlgAES()
return
}
if goarch.GOARCH == "arm64" && cpu.ARM64.HasAES {
initAlgAES()
return
}
for i := range hashkey {
hashkey[i] = uintptr(bootstrapRand())
}
}
func initAlgAES() {
UseAeshash = true
// Initialize with random data so hash collisions will be hard to engineer.
key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched))
for i := range key {
key[i] = bootstrapRand()
}
}
func strHashFallback(a unsafe.Pointer, h uintptr) uintptr {
type stringStruct struct {
str unsafe.Pointer
len int
}
x := (*stringStruct)(a)
return memHashFallback(x.str, h, uintptr(x.len))
}
//go:nosplit
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
// Note: These routines perform the read with a native endianness.
func readUnaligned32(p unsafe.Pointer) uint32 {
q := (*[4]byte)(p)
if goarch.BigEndian {
return byteorder.BEUint32(q[:])
}
return byteorder.LEUint32(q[:])
}
func readUnaligned64(p unsafe.Pointer) uint64 {
q := (*[8]byte)(p)
if goarch.BigEndian {
return byteorder.BEUint64(q[:])
}
return byteorder.LEUint64(q[:])
}