Source file src/internal/runtime/maps/runtime_alg.go

     1  // Copyright 2026 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 maps
     6  
     7  import (
     8  	"internal/byteorder"
     9  	"internal/cpu"
    10  	"internal/goarch"
    11  	"unsafe"
    12  )
    13  
    14  // runtime variable to check if the processor we're running on
    15  // actually supports the instructions used by the AES-based
    16  // hash implementation.
    17  var UseAeshash bool
    18  
    19  const hashRandomBytes = goarch.PtrSize / 4 * 64
    20  
    21  // used to seed the hash function
    22  var aeskeysched [hashRandomBytes]byte
    23  
    24  // used in hash{32,64}.go to seed the hash function
    25  var hashkey [4]uintptr
    26  
    27  func AlgInit() {
    28  	// Install AES hash algorithms if the instructions needed are present.
    29  	if (goarch.GOARCH == "386" || goarch.GOARCH == "amd64") &&
    30  		cpu.X86.HasAES && // AESENC
    31  		cpu.X86.HasSSSE3 && // PSHUFB
    32  		cpu.X86.HasSSE41 { // PINSR{D,Q}
    33  
    34  		// In aeshashbody (that is used by memhash & strhash)
    35  		// we have global variables that should be properly aligned.
    36  		//
    37  		// See #12415
    38  		if !checkMasksAndShiftsAlignment() {
    39  			fatal("maps: global variables for AES hashing are not properly aligned!")
    40  		}
    41  		initAlgAES()
    42  		return
    43  	}
    44  	if goarch.GOARCH == "arm64" && cpu.ARM64.HasAES {
    45  		initAlgAES()
    46  		return
    47  	}
    48  	for i := range hashkey {
    49  		hashkey[i] = uintptr(bootstrapRand())
    50  	}
    51  }
    52  
    53  func initAlgAES() {
    54  	UseAeshash = true
    55  	// Initialize with random data so hash collisions will be hard to engineer.
    56  	key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched))
    57  	for i := range key {
    58  		key[i] = bootstrapRand()
    59  	}
    60  }
    61  
    62  func strHashFallback(a unsafe.Pointer, h uintptr) uintptr {
    63  	type stringStruct struct {
    64  		str unsafe.Pointer
    65  		len int
    66  	}
    67  	x := (*stringStruct)(a)
    68  	return memHashFallback(x.str, h, uintptr(x.len))
    69  }
    70  
    71  //go:nosplit
    72  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
    73  	return unsafe.Pointer(uintptr(p) + x)
    74  }
    75  
    76  // Note: These routines perform the read with a native endianness.
    77  func readUnaligned32(p unsafe.Pointer) uint32 {
    78  	q := (*[4]byte)(p)
    79  	if goarch.BigEndian {
    80  		return byteorder.BEUint32(q[:])
    81  	}
    82  	return byteorder.LEUint32(q[:])
    83  }
    84  
    85  func readUnaligned64(p unsafe.Pointer) uint64 {
    86  	q := (*[8]byte)(p)
    87  	if goarch.BigEndian {
    88  		return byteorder.BEUint64(q[:])
    89  	}
    90  	return byteorder.LEUint64(q[:])
    91  }
    92  

View as plain text