// 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[:]) }