package runtime
import (
"internal/abi"
"internal/cpu"
"internal/goarch"
"unsafe"
)
const (
c0 = uintptr ((8 -goarch .PtrSize )/4 *2860486313 + (goarch .PtrSize -4 )/4 *33054211828000289 )
c1 = uintptr ((8 -goarch .PtrSize )/4 *3267000013 + (goarch .PtrSize -4 )/4 *23344194077549503 )
)
func memhash0(p unsafe .Pointer , h uintptr ) uintptr {
return h
}
func memhash8(p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 1 )
}
func memhash16(p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 2 )
}
func memhash128(p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 16 )
}
func memhash_varlen(p unsafe .Pointer , h uintptr ) uintptr {
ptr := getclosureptr ()
size := *(*uintptr )(unsafe .Pointer (ptr + unsafe .Sizeof (h )))
return memhash (p , h , size )
}
var useAeshash bool
func memhash(p unsafe .Pointer , h , s uintptr ) uintptr
func memhash32(p unsafe .Pointer , h uintptr ) uintptr
func memhash64(p unsafe .Pointer , h uintptr ) uintptr
func strhash(p unsafe .Pointer , h uintptr ) uintptr
func strhashFallback(a unsafe .Pointer , h uintptr ) uintptr {
x := (*stringStruct )(a )
return memhashFallback (x .str , h , uintptr (x .len ))
}
func f32hash(p unsafe .Pointer , h uintptr ) uintptr {
f := *(*float32 )(p )
switch {
case f == 0 :
return c1 * (c0 ^ h )
case f != f :
return c1 * (c0 ^ h ^ uintptr (rand ()))
default :
return memhash (p , h , 4 )
}
}
func f64hash(p unsafe .Pointer , h uintptr ) uintptr {
f := *(*float64 )(p )
switch {
case f == 0 :
return c1 * (c0 ^ h )
case f != f :
return c1 * (c0 ^ h ^ uintptr (rand ()))
default :
return memhash (p , h , 8 )
}
}
func c64hash(p unsafe .Pointer , h uintptr ) uintptr {
x := (*[2 ]float32 )(p )
return f32hash (unsafe .Pointer (&x [1 ]), f32hash (unsafe .Pointer (&x [0 ]), h ))
}
func c128hash(p unsafe .Pointer , h uintptr ) uintptr {
x := (*[2 ]float64 )(p )
return f64hash (unsafe .Pointer (&x [1 ]), f64hash (unsafe .Pointer (&x [0 ]), h ))
}
func interhash(p unsafe .Pointer , h uintptr ) uintptr {
a := (*iface )(p )
tab := a .tab
if tab == nil {
return h
}
t := tab .Type
if t .Equal == nil {
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return c1 * typehash (t , unsafe .Pointer (&a .data ), h ^c0 )
} else {
return c1 * typehash (t , a .data , h ^c0 )
}
}
func nilinterhash(p unsafe .Pointer , h uintptr ) uintptr {
a := (*eface )(p )
t := a ._type
if t == nil {
return h
}
if t .Equal == nil {
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return c1 * typehash (t , unsafe .Pointer (&a .data ), h ^c0 )
} else {
return c1 * typehash (t , a .data , h ^c0 )
}
}
func typehash(t *_type , p unsafe .Pointer , h uintptr ) uintptr {
if t .TFlag &abi .TFlagRegularMemory != 0 {
switch t .Size_ {
case 4 :
return memhash32 (p , h )
case 8 :
return memhash64 (p , h )
default :
return memhash (p , h , t .Size_ )
}
}
switch t .Kind_ & abi .KindMask {
case abi .Float32 :
return f32hash (p , h )
case abi .Float64 :
return f64hash (p , h )
case abi .Complex64 :
return c64hash (p , h )
case abi .Complex128 :
return c128hash (p , h )
case abi .String :
return strhash (p , h )
case abi .Interface :
i := (*interfacetype )(unsafe .Pointer (t ))
if len (i .Methods ) == 0 {
return nilinterhash (p , h )
}
return interhash (p , h )
case abi .Array :
a := (*arraytype )(unsafe .Pointer (t ))
for i := uintptr (0 ); i < a .Len ; i ++ {
h = typehash (a .Elem , add (p , i *a .Elem .Size_ ), h )
}
return h
case abi .Struct :
s := (*structtype )(unsafe .Pointer (t ))
for _ , f := range s .Fields {
if f .Name .IsBlank () {
continue
}
h = typehash (f .Typ , add (p , f .Offset ), h )
}
return h
default :
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
}
func mapKeyError(t *maptype , p unsafe .Pointer ) error {
if !t .HashMightPanic () {
return nil
}
return mapKeyError2 (t .Key , p )
}
func mapKeyError2(t *_type , p unsafe .Pointer ) error {
if t .TFlag &abi .TFlagRegularMemory != 0 {
return nil
}
switch t .Kind_ & abi .KindMask {
case abi .Float32 , abi .Float64 , abi .Complex64 , abi .Complex128 , abi .String :
return nil
case abi .Interface :
i := (*interfacetype )(unsafe .Pointer (t ))
var t *_type
var pdata *unsafe .Pointer
if len (i .Methods ) == 0 {
a := (*eface )(p )
t = a ._type
if t == nil {
return nil
}
pdata = &a .data
} else {
a := (*iface )(p )
if a .tab == nil {
return nil
}
t = a .tab .Type
pdata = &a .data
}
if t .Equal == nil {
return errorString ("hash of unhashable type " + toRType (t ).string ())
}
if isDirectIface (t ) {
return mapKeyError2 (t , unsafe .Pointer (pdata ))
} else {
return mapKeyError2 (t , *pdata )
}
case abi .Array :
a := (*arraytype )(unsafe .Pointer (t ))
for i := uintptr (0 ); i < a .Len ; i ++ {
if err := mapKeyError2 (a .Elem , add (p , i *a .Elem .Size_ )); err != nil {
return err
}
}
return nil
case abi .Struct :
s := (*structtype )(unsafe .Pointer (t ))
for _ , f := range s .Fields {
if f .Name .IsBlank () {
continue
}
if err := mapKeyError2 (f .Typ , add (p , f .Offset )); err != nil {
return err
}
}
return nil
default :
return errorString ("hash of unhashable type " + toRType (t ).string ())
}
}
func reflect_typehash(t *_type , p unsafe .Pointer , h uintptr ) uintptr {
return typehash (t , p , h )
}
func memequal0(p , q unsafe .Pointer ) bool {
return true
}
func memequal8(p , q unsafe .Pointer ) bool {
return *(*int8 )(p ) == *(*int8 )(q )
}
func memequal16(p , q unsafe .Pointer ) bool {
return *(*int16 )(p ) == *(*int16 )(q )
}
func memequal32(p , q unsafe .Pointer ) bool {
return *(*int32 )(p ) == *(*int32 )(q )
}
func memequal64(p , q unsafe .Pointer ) bool {
return *(*int64 )(p ) == *(*int64 )(q )
}
func memequal128(p , q unsafe .Pointer ) bool {
return *(*[2 ]int64 )(p ) == *(*[2 ]int64 )(q )
}
func f32equal(p , q unsafe .Pointer ) bool {
return *(*float32 )(p ) == *(*float32 )(q )
}
func f64equal(p , q unsafe .Pointer ) bool {
return *(*float64 )(p ) == *(*float64 )(q )
}
func c64equal(p , q unsafe .Pointer ) bool {
return *(*complex64 )(p ) == *(*complex64 )(q )
}
func c128equal(p , q unsafe .Pointer ) bool {
return *(*complex128 )(p ) == *(*complex128 )(q )
}
func strequal(p , q unsafe .Pointer ) bool {
return *(*string )(p ) == *(*string )(q )
}
func interequal(p , q unsafe .Pointer ) bool {
x := *(*iface )(p )
y := *(*iface )(q )
return x .tab == y .tab && ifaceeq (x .tab , x .data , y .data )
}
func nilinterequal(p , q unsafe .Pointer ) bool {
x := *(*eface )(p )
y := *(*eface )(q )
return x ._type == y ._type && efaceeq (x ._type , x .data , y .data )
}
func efaceeq(t *_type , x , y unsafe .Pointer ) bool {
if t == nil {
return true
}
eq := t .Equal
if eq == nil {
panic (errorString ("comparing uncomparable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return x == y
}
return eq (x , y )
}
func ifaceeq(tab *itab , x , y unsafe .Pointer ) bool {
if tab == nil {
return true
}
t := tab .Type
eq := t .Equal
if eq == nil {
panic (errorString ("comparing uncomparable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return x == y
}
return eq (x , y )
}
func stringHash(s string , seed uintptr ) uintptr {
return strhash (noescape (unsafe .Pointer (&s )), seed )
}
func bytesHash(b []byte , seed uintptr ) uintptr {
s := (*slice )(unsafe .Pointer (&b ))
return memhash (s .array , seed , uintptr (s .len ))
}
func int32Hash(i uint32 , seed uintptr ) uintptr {
return memhash32 (noescape (unsafe .Pointer (&i )), seed )
}
func int64Hash(i uint64 , seed uintptr ) uintptr {
return memhash64 (noescape (unsafe .Pointer (&i )), seed )
}
func efaceHash(i any , seed uintptr ) uintptr {
return nilinterhash (noescape (unsafe .Pointer (&i )), seed )
}
func ifaceHash(i interface {
F ()
}, seed uintptr ) uintptr {
return interhash (noescape (unsafe .Pointer (&i )), seed )
}
const hashRandomBytes = goarch .PtrSize / 4 * 64
var aeskeysched [hashRandomBytes ]byte
var hashkey [4 ]uintptr
func alginit() {
if (GOARCH == "386" || GOARCH == "amd64" ) &&
cpu .X86 .HasAES &&
cpu .X86 .HasSSSE3 &&
cpu .X86 .HasSSE41 {
initAlgAES ()
return
}
if GOARCH == "arm64" && cpu .ARM64 .HasAES {
initAlgAES ()
return
}
for i := range hashkey {
hashkey [i ] = uintptr (bootstrapRand ())
}
}
func initAlgAES() {
useAeshash = true
key := (*[hashRandomBytes / 8 ]uint64 )(unsafe .Pointer (&aeskeysched ))
for i := range key {
key [i ] = bootstrapRand ()
}
}
func readUnaligned32(p unsafe .Pointer ) uint32 {
q := (*[4 ]byte )(p )
if goarch .BigEndian {
return uint32 (q [3 ]) | uint32 (q [2 ])<<8 | uint32 (q [1 ])<<16 | uint32 (q [0 ])<<24
}
return uint32 (q [0 ]) | uint32 (q [1 ])<<8 | uint32 (q [2 ])<<16 | uint32 (q [3 ])<<24
}
func readUnaligned64(p unsafe .Pointer ) uint64 {
q := (*[8 ]byte )(p )
if goarch .BigEndian {
return uint64 (q [7 ]) | uint64 (q [6 ])<<8 | uint64 (q [5 ])<<16 | uint64 (q [4 ])<<24 |
uint64 (q [3 ])<<32 | uint64 (q [2 ])<<40 | uint64 (q [1 ])<<48 | uint64 (q [0 ])<<56
}
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
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .