1// Copyright 2014 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
5package runtime
6
7import (
8	"internal/abi"
9	"internal/cpu"
10	"internal/goarch"
11	"unsafe"
12)
13
14const (
15	c0 = uintptr((8-goarch.PtrSize)/4*2860486313 + (goarch.PtrSize-4)/4*33054211828000289)
16	c1 = uintptr((8-goarch.PtrSize)/4*3267000013 + (goarch.PtrSize-4)/4*23344194077549503)
17)
18
19func memhash0(p unsafe.Pointer, h uintptr) uintptr {
20	return h
21}
22
23func memhash8(p unsafe.Pointer, h uintptr) uintptr {
24	return memhash(p, h, 1)
25}
26
27func memhash16(p unsafe.Pointer, h uintptr) uintptr {
28	return memhash(p, h, 2)
29}
30
31func memhash128(p unsafe.Pointer, h uintptr) uintptr {
32	return memhash(p, h, 16)
33}
34
35//go:nosplit
36func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr {
37	ptr := getclosureptr()
38	size := *(*uintptr)(unsafe.Pointer(ptr + unsafe.Sizeof(h)))
39	return memhash(p, h, size)
40}
41
42// runtime variable to check if the processor we're running on
43// actually supports the instructions used by the AES-based
44// hash implementation.
45var useAeshash bool
46
47// in asm_*.s
48
49// memhash should be an internal detail,
50// but widely used packages access it using linkname.
51// Notable members of the hall of shame include:
52//   - github.com/aacfactory/fns
53//   - github.com/dgraph-io/ristretto
54//   - github.com/minio/simdjson-go
55//   - github.com/nbd-wtf/go-nostr
56//   - github.com/outcaste-io/ristretto
57//   - github.com/puzpuzpuz/xsync/v2
58//   - github.com/puzpuzpuz/xsync/v3
59//   - github.com/segmentio/parquet-go
60//   - github.com/parquet-go/parquet-go
61//   - github.com/authzed/spicedb
62//   - github.com/pingcap/badger
63//
64// Do not remove or change the type signature.
65// See go.dev/issue/67401.
66//
67//go:linkname memhash
68func memhash(p unsafe.Pointer, h, s uintptr) uintptr
69
70// memhash32 should be an internal detail,
71// but widely used packages access it using linkname.
72// Notable members of the hall of shame include:
73//   - github.com/segmentio/parquet-go
74//   - github.com/parquet-go/parquet-go
75//
76// Do not remove or change the type signature.
77// See go.dev/issue/67401.
78//
79//go:linkname memhash32
80func memhash32(p unsafe.Pointer, h uintptr) uintptr
81
82// memhash64 should be an internal detail,
83// but widely used packages access it using linkname.
84// Notable members of the hall of shame include:
85//   - github.com/segmentio/parquet-go
86//   - github.com/parquet-go/parquet-go
87//
88// Do not remove or change the type signature.
89// See go.dev/issue/67401.
90//
91//go:linkname memhash64
92func memhash64(p unsafe.Pointer, h uintptr) uintptr
93
94// strhash should be an internal detail,
95// but widely used packages access it using linkname.
96// Notable members of the hall of shame include:
97//   - github.com/aristanetworks/goarista
98//   - github.com/bytedance/sonic
99//   - github.com/bytedance/go-tagexpr/v2
100//   - github.com/cloudwego/frugal
101//   - github.com/cloudwego/dynamicgo
102//   - github.com/v2fly/v2ray-core/v5
103//
104// Do not remove or change the type signature.
105// See go.dev/issue/67401.
106//
107//go:linkname strhash
108func strhash(p unsafe.Pointer, h uintptr) uintptr
109
110func strhashFallback(a unsafe.Pointer, h uintptr) uintptr {
111	x := (*stringStruct)(a)
112	return memhashFallback(x.str, h, uintptr(x.len))
113}
114
115// NOTE: Because NaN != NaN, a map can contain any
116// number of (mostly useless) entries keyed with NaNs.
117// To avoid long hash chains, we assign a random number
118// as the hash value for a NaN.
119
120func f32hash(p unsafe.Pointer, h uintptr) uintptr {
121	f := *(*float32)(p)
122	switch {
123	case f == 0:
124		return c1 * (c0 ^ h) // +0, -0
125	case f != f:
126		return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN
127	default:
128		return memhash(p, h, 4)
129	}
130}
131
132func f64hash(p unsafe.Pointer, h uintptr) uintptr {
133	f := *(*float64)(p)
134	switch {
135	case f == 0:
136		return c1 * (c0 ^ h) // +0, -0
137	case f != f:
138		return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN
139	default:
140		return memhash(p, h, 8)
141	}
142}
143
144func c64hash(p unsafe.Pointer, h uintptr) uintptr {
145	x := (*[2]float32)(p)
146	return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
147}
148
149func c128hash(p unsafe.Pointer, h uintptr) uintptr {
150	x := (*[2]float64)(p)
151	return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
152}
153
154func interhash(p unsafe.Pointer, h uintptr) uintptr {
155	a := (*iface)(p)
156	tab := a.tab
157	if tab == nil {
158		return h
159	}
160	t := tab.Type
161	if t.Equal == nil {
162		// Check hashability here. We could do this check inside
163		// typehash, but we want to report the topmost type in
164		// the error text (e.g. in a struct with a field of slice type
165		// we want to report the struct, not the slice).
166		panic(errorString("hash of unhashable type " + toRType(t).string()))
167	}
168	if isDirectIface(t) {
169		return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
170	} else {
171		return c1 * typehash(t, a.data, h^c0)
172	}
173}
174
175// nilinterhash should be an internal detail,
176// but widely used packages access it using linkname.
177// Notable members of the hall of shame include:
178//   - github.com/anacrolix/stm
179//   - github.com/aristanetworks/goarista
180//
181// Do not remove or change the type signature.
182// See go.dev/issue/67401.
183//
184//go:linkname nilinterhash
185func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
186	a := (*eface)(p)
187	t := a._type
188	if t == nil {
189		return h
190	}
191	if t.Equal == nil {
192		// See comment in interhash above.
193		panic(errorString("hash of unhashable type " + toRType(t).string()))
194	}
195	if isDirectIface(t) {
196		return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
197	} else {
198		return c1 * typehash(t, a.data, h^c0)
199	}
200}
201
202// typehash computes the hash of the object of type t at address p.
203// h is the seed.
204// This function is seldom used. Most maps use for hashing either
205// fixed functions (e.g. f32hash) or compiler-generated functions
206// (e.g. for a type like struct { x, y string }). This implementation
207// is slower but more general and is used for hashing interface types
208// (called from interhash or nilinterhash, above) or for hashing in
209// maps generated by reflect.MapOf (reflect_typehash, below).
210// Note: this function must match the compiler generated
211// functions exactly. See issue 37716.
212//
213// typehash should be an internal detail,
214// but widely used packages access it using linkname.
215// Notable members of the hall of shame include:
216//   - github.com/puzpuzpuz/xsync/v2
217//   - github.com/puzpuzpuz/xsync/v3
218//
219// Do not remove or change the type signature.
220// See go.dev/issue/67401.
221//
222//go:linkname typehash
223func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
224	if t.TFlag&abi.TFlagRegularMemory != 0 {
225		// Handle ptr sizes specially, see issue 37086.
226		switch t.Size_ {
227		case 4:
228			return memhash32(p, h)
229		case 8:
230			return memhash64(p, h)
231		default:
232			return memhash(p, h, t.Size_)
233		}
234	}
235	switch t.Kind_ & abi.KindMask {
236	case abi.Float32:
237		return f32hash(p, h)
238	case abi.Float64:
239		return f64hash(p, h)
240	case abi.Complex64:
241		return c64hash(p, h)
242	case abi.Complex128:
243		return c128hash(p, h)
244	case abi.String:
245		return strhash(p, h)
246	case abi.Interface:
247		i := (*interfacetype)(unsafe.Pointer(t))
248		if len(i.Methods) == 0 {
249			return nilinterhash(p, h)
250		}
251		return interhash(p, h)
252	case abi.Array:
253		a := (*arraytype)(unsafe.Pointer(t))
254		for i := uintptr(0); i < a.Len; i++ {
255			h = typehash(a.Elem, add(p, i*a.Elem.Size_), h)
256		}
257		return h
258	case abi.Struct:
259		s := (*structtype)(unsafe.Pointer(t))
260		for _, f := range s.Fields {
261			if f.Name.IsBlank() {
262				continue
263			}
264			h = typehash(f.Typ, add(p, f.Offset), h)
265		}
266		return h
267	default:
268		// Should never happen, as typehash should only be called
269		// with comparable types.
270		panic(errorString("hash of unhashable type " + toRType(t).string()))
271	}
272}
273
274func mapKeyError(t *maptype, p unsafe.Pointer) error {
275	if !t.HashMightPanic() {
276		return nil
277	}
278	return mapKeyError2(t.Key, p)
279}
280
281func mapKeyError2(t *_type, p unsafe.Pointer) error {
282	if t.TFlag&abi.TFlagRegularMemory != 0 {
283		return nil
284	}
285	switch t.Kind_ & abi.KindMask {
286	case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String:
287		return nil
288	case abi.Interface:
289		i := (*interfacetype)(unsafe.Pointer(t))
290		var t *_type
291		var pdata *unsafe.Pointer
292		if len(i.Methods) == 0 {
293			a := (*eface)(p)
294			t = a._type
295			if t == nil {
296				return nil
297			}
298			pdata = &a.data
299		} else {
300			a := (*iface)(p)
301			if a.tab == nil {
302				return nil
303			}
304			t = a.tab.Type
305			pdata = &a.data
306		}
307
308		if t.Equal == nil {
309			return errorString("hash of unhashable type " + toRType(t).string())
310		}
311
312		if isDirectIface(t) {
313			return mapKeyError2(t, unsafe.Pointer(pdata))
314		} else {
315			return mapKeyError2(t, *pdata)
316		}
317	case abi.Array:
318		a := (*arraytype)(unsafe.Pointer(t))
319		for i := uintptr(0); i < a.Len; i++ {
320			if err := mapKeyError2(a.Elem, add(p, i*a.Elem.Size_)); err != nil {
321				return err
322			}
323		}
324		return nil
325	case abi.Struct:
326		s := (*structtype)(unsafe.Pointer(t))
327		for _, f := range s.Fields {
328			if f.Name.IsBlank() {
329				continue
330			}
331			if err := mapKeyError2(f.Typ, add(p, f.Offset)); err != nil {
332				return err
333			}
334		}
335		return nil
336	default:
337		// Should never happen, keep this case for robustness.
338		return errorString("hash of unhashable type " + toRType(t).string())
339	}
340}
341
342//go:linkname reflect_typehash reflect.typehash
343func reflect_typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
344	return typehash(t, p, h)
345}
346
347func memequal0(p, q unsafe.Pointer) bool {
348	return true
349}
350func memequal8(p, q unsafe.Pointer) bool {
351	return *(*int8)(p) == *(*int8)(q)
352}
353func memequal16(p, q unsafe.Pointer) bool {
354	return *(*int16)(p) == *(*int16)(q)
355}
356func memequal32(p, q unsafe.Pointer) bool {
357	return *(*int32)(p) == *(*int32)(q)
358}
359func memequal64(p, q unsafe.Pointer) bool {
360	return *(*int64)(p) == *(*int64)(q)
361}
362func memequal128(p, q unsafe.Pointer) bool {
363	return *(*[2]int64)(p) == *(*[2]int64)(q)
364}
365func f32equal(p, q unsafe.Pointer) bool {
366	return *(*float32)(p) == *(*float32)(q)
367}
368func f64equal(p, q unsafe.Pointer) bool {
369	return *(*float64)(p) == *(*float64)(q)
370}
371func c64equal(p, q unsafe.Pointer) bool {
372	return *(*complex64)(p) == *(*complex64)(q)
373}
374func c128equal(p, q unsafe.Pointer) bool {
375	return *(*complex128)(p) == *(*complex128)(q)
376}
377func strequal(p, q unsafe.Pointer) bool {
378	return *(*string)(p) == *(*string)(q)
379}
380func interequal(p, q unsafe.Pointer) bool {
381	x := *(*iface)(p)
382	y := *(*iface)(q)
383	return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data)
384}
385func nilinterequal(p, q unsafe.Pointer) bool {
386	x := *(*eface)(p)
387	y := *(*eface)(q)
388	return x._type == y._type && efaceeq(x._type, x.data, y.data)
389}
390func efaceeq(t *_type, x, y unsafe.Pointer) bool {
391	if t == nil {
392		return true
393	}
394	eq := t.Equal
395	if eq == nil {
396		panic(errorString("comparing uncomparable type " + toRType(t).string()))
397	}
398	if isDirectIface(t) {
399		// Direct interface types are ptr, chan, map, func, and single-element structs/arrays thereof.
400		// Maps and funcs are not comparable, so they can't reach here.
401		// Ptrs, chans, and single-element items can be compared directly using ==.
402		return x == y
403	}
404	return eq(x, y)
405}
406func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
407	if tab == nil {
408		return true
409	}
410	t := tab.Type
411	eq := t.Equal
412	if eq == nil {
413		panic(errorString("comparing uncomparable type " + toRType(t).string()))
414	}
415	if isDirectIface(t) {
416		// See comment in efaceeq.
417		return x == y
418	}
419	return eq(x, y)
420}
421
422// Testing adapters for hash quality tests (see hash_test.go)
423//
424// stringHash should be an internal detail,
425// but widely used packages access it using linkname.
426// Notable members of the hall of shame include:
427//   - github.com/k14s/starlark-go
428//
429// Do not remove or change the type signature.
430// See go.dev/issue/67401.
431//
432//go:linkname stringHash
433func stringHash(s string, seed uintptr) uintptr {
434	return strhash(noescape(unsafe.Pointer(&s)), seed)
435}
436
437func bytesHash(b []byte, seed uintptr) uintptr {
438	s := (*slice)(unsafe.Pointer(&b))
439	return memhash(s.array, seed, uintptr(s.len))
440}
441
442func int32Hash(i uint32, seed uintptr) uintptr {
443	return memhash32(noescape(unsafe.Pointer(&i)), seed)
444}
445
446func int64Hash(i uint64, seed uintptr) uintptr {
447	return memhash64(noescape(unsafe.Pointer(&i)), seed)
448}
449
450func efaceHash(i any, seed uintptr) uintptr {
451	return nilinterhash(noescape(unsafe.Pointer(&i)), seed)
452}
453
454func ifaceHash(i interface {
455	F()
456}, seed uintptr) uintptr {
457	return interhash(noescape(unsafe.Pointer(&i)), seed)
458}
459
460const hashRandomBytes = goarch.PtrSize / 4 * 64
461
462// used in asm_{386,amd64,arm64}.s to seed the hash function
463var aeskeysched [hashRandomBytes]byte
464
465// used in hash{32,64}.go to seed the hash function
466var hashkey [4]uintptr
467
468func alginit() {
469	// Install AES hash algorithms if the instructions needed are present.
470	if (GOARCH == "386" || GOARCH == "amd64") &&
471		cpu.X86.HasAES && // AESENC
472		cpu.X86.HasSSSE3 && // PSHUFB
473		cpu.X86.HasSSE41 { // PINSR{D,Q}
474		initAlgAES()
475		return
476	}
477	if GOARCH == "arm64" && cpu.ARM64.HasAES {
478		initAlgAES()
479		return
480	}
481	for i := range hashkey {
482		hashkey[i] = uintptr(bootstrapRand())
483	}
484}
485
486func initAlgAES() {
487	useAeshash = true
488	// Initialize with random data so hash collisions will be hard to engineer.
489	key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched))
490	for i := range key {
491		key[i] = bootstrapRand()
492	}
493}
494
495// Note: These routines perform the read with a native endianness.
496func readUnaligned32(p unsafe.Pointer) uint32 {
497	q := (*[4]byte)(p)
498	if goarch.BigEndian {
499		return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24
500	}
501	return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24
502}
503
504func readUnaligned64(p unsafe.Pointer) uint64 {
505	q := (*[8]byte)(p)
506	if goarch.BigEndian {
507		return uint64(q[7]) | uint64(q[6])<<8 | uint64(q[5])<<16 | uint64(q[4])<<24 |
508			uint64(q[3])<<32 | uint64(q[2])<<40 | uint64(q[1])<<48 | uint64(q[0])<<56
509	}
510	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
511}
512