| // 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() { | |
| // Always intialize hashkey. | |
| // | |
| // See #78073 | |
| for i := range hashkey { | |
| hashkey[i] = uintptr(bootstrapRand()) | |
| } | |
| // 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 memHashAES 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() | |
| if memHashUsesVAES { | |
| // We are using intrinsics hash implementation. | |
| // Override the UseAeshash in this case, since it uses VAES (AVX) instructions. | |
| // While assembly implementation used AES-NI instructions, | |
| // simd intrinsics only provide access to AVX ones. | |
| UseAeshash = cpu.X86.HasAVX | |
| } | |
| return | |
| } | |
| if goarch.GOARCH == "arm64" && cpu.ARM64.HasAES { | |
| initAlgAES() | |
| return | |
| } | |
| } | |
| 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() | |
| } | |
| } | |
| //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[:]) | |
| } |