Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/cpu"
10 "internal/goarch"
11 "unsafe"
12 )
13
14 const (
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
19 func memhash0(p unsafe.Pointer, h uintptr) uintptr {
20 return h
21 }
22
23 func memhash8(p unsafe.Pointer, h uintptr) uintptr {
24 return memhash(p, h, 1)
25 }
26
27 func memhash16(p unsafe.Pointer, h uintptr) uintptr {
28 return memhash(p, h, 2)
29 }
30
31 func memhash128(p unsafe.Pointer, h uintptr) uintptr {
32 return memhash(p, h, 16)
33 }
34
35
36 func 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
43
44
45 var useAeshash bool
46
47
48 func memhash(p unsafe.Pointer, h, s uintptr) uintptr
49 func memhash32(p unsafe.Pointer, h uintptr) uintptr
50 func memhash64(p unsafe.Pointer, h uintptr) uintptr
51 func strhash(p unsafe.Pointer, h uintptr) uintptr
52
53 func strhashFallback(a unsafe.Pointer, h uintptr) uintptr {
54 x := (*stringStruct)(a)
55 return memhashFallback(x.str, h, uintptr(x.len))
56 }
57
58
59
60
61
62
63 func f32hash(p unsafe.Pointer, h uintptr) uintptr {
64 f := *(*float32)(p)
65 switch {
66 case f == 0:
67 return c1 * (c0 ^ h)
68 case f != f:
69 return c1 * (c0 ^ h ^ uintptr(rand()))
70 default:
71 return memhash(p, h, 4)
72 }
73 }
74
75 func f64hash(p unsafe.Pointer, h uintptr) uintptr {
76 f := *(*float64)(p)
77 switch {
78 case f == 0:
79 return c1 * (c0 ^ h)
80 case f != f:
81 return c1 * (c0 ^ h ^ uintptr(rand()))
82 default:
83 return memhash(p, h, 8)
84 }
85 }
86
87 func c64hash(p unsafe.Pointer, h uintptr) uintptr {
88 x := (*[2]float32)(p)
89 return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
90 }
91
92 func c128hash(p unsafe.Pointer, h uintptr) uintptr {
93 x := (*[2]float64)(p)
94 return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
95 }
96
97 func interhash(p unsafe.Pointer, h uintptr) uintptr {
98 a := (*iface)(p)
99 tab := a.tab
100 if tab == nil {
101 return h
102 }
103 t := tab._type
104 if t.Equal == nil {
105
106
107
108
109 panic(errorString("hash of unhashable type " + toRType(t).string()))
110 }
111 if isDirectIface(t) {
112 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
113 } else {
114 return c1 * typehash(t, a.data, h^c0)
115 }
116 }
117
118 func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
119 a := (*eface)(p)
120 t := a._type
121 if t == nil {
122 return h
123 }
124 if t.Equal == nil {
125
126 panic(errorString("hash of unhashable type " + toRType(t).string()))
127 }
128 if isDirectIface(t) {
129 return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
130 } else {
131 return c1 * typehash(t, a.data, h^c0)
132 }
133 }
134
135
136
137
138
139
140
141
142
143
144
145 func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
146 if t.TFlag&abi.TFlagRegularMemory != 0 {
147
148 switch t.Size_ {
149 case 4:
150 return memhash32(p, h)
151 case 8:
152 return memhash64(p, h)
153 default:
154 return memhash(p, h, t.Size_)
155 }
156 }
157 switch t.Kind_ & kindMask {
158 case kindFloat32:
159 return f32hash(p, h)
160 case kindFloat64:
161 return f64hash(p, h)
162 case kindComplex64:
163 return c64hash(p, h)
164 case kindComplex128:
165 return c128hash(p, h)
166 case kindString:
167 return strhash(p, h)
168 case kindInterface:
169 i := (*interfacetype)(unsafe.Pointer(t))
170 if len(i.Methods) == 0 {
171 return nilinterhash(p, h)
172 }
173 return interhash(p, h)
174 case kindArray:
175 a := (*arraytype)(unsafe.Pointer(t))
176 for i := uintptr(0); i < a.Len; i++ {
177 h = typehash(a.Elem, add(p, i*a.Elem.Size_), h)
178 }
179 return h
180 case kindStruct:
181 s := (*structtype)(unsafe.Pointer(t))
182 for _, f := range s.Fields {
183 if f.Name.IsBlank() {
184 continue
185 }
186 h = typehash(f.Typ, add(p, f.Offset), h)
187 }
188 return h
189 default:
190
191
192 panic(errorString("hash of unhashable type " + toRType(t).string()))
193 }
194 }
195
196 func mapKeyError(t *maptype, p unsafe.Pointer) error {
197 if !t.HashMightPanic() {
198 return nil
199 }
200 return mapKeyError2(t.Key, p)
201 }
202
203 func mapKeyError2(t *_type, p unsafe.Pointer) error {
204 if t.TFlag&abi.TFlagRegularMemory != 0 {
205 return nil
206 }
207 switch t.Kind_ & kindMask {
208 case kindFloat32, kindFloat64, kindComplex64, kindComplex128, kindString:
209 return nil
210 case kindInterface:
211 i := (*interfacetype)(unsafe.Pointer(t))
212 var t *_type
213 var pdata *unsafe.Pointer
214 if len(i.Methods) == 0 {
215 a := (*eface)(p)
216 t = a._type
217 if t == nil {
218 return nil
219 }
220 pdata = &a.data
221 } else {
222 a := (*iface)(p)
223 if a.tab == nil {
224 return nil
225 }
226 t = a.tab._type
227 pdata = &a.data
228 }
229
230 if t.Equal == nil {
231 return errorString("hash of unhashable type " + toRType(t).string())
232 }
233
234 if isDirectIface(t) {
235 return mapKeyError2(t, unsafe.Pointer(pdata))
236 } else {
237 return mapKeyError2(t, *pdata)
238 }
239 case kindArray:
240 a := (*arraytype)(unsafe.Pointer(t))
241 for i := uintptr(0); i < a.Len; i++ {
242 if err := mapKeyError2(a.Elem, add(p, i*a.Elem.Size_)); err != nil {
243 return err
244 }
245 }
246 return nil
247 case kindStruct:
248 s := (*structtype)(unsafe.Pointer(t))
249 for _, f := range s.Fields {
250 if f.Name.IsBlank() {
251 continue
252 }
253 if err := mapKeyError2(f.Typ, add(p, f.Offset)); err != nil {
254 return err
255 }
256 }
257 return nil
258 default:
259
260 return errorString("hash of unhashable type " + toRType(t).string())
261 }
262 }
263
264
265 func reflect_typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
266 return typehash(t, p, h)
267 }
268
269 func memequal0(p, q unsafe.Pointer) bool {
270 return true
271 }
272 func memequal8(p, q unsafe.Pointer) bool {
273 return *(*int8)(p) == *(*int8)(q)
274 }
275 func memequal16(p, q unsafe.Pointer) bool {
276 return *(*int16)(p) == *(*int16)(q)
277 }
278 func memequal32(p, q unsafe.Pointer) bool {
279 return *(*int32)(p) == *(*int32)(q)
280 }
281 func memequal64(p, q unsafe.Pointer) bool {
282 return *(*int64)(p) == *(*int64)(q)
283 }
284 func memequal128(p, q unsafe.Pointer) bool {
285 return *(*[2]int64)(p) == *(*[2]int64)(q)
286 }
287 func f32equal(p, q unsafe.Pointer) bool {
288 return *(*float32)(p) == *(*float32)(q)
289 }
290 func f64equal(p, q unsafe.Pointer) bool {
291 return *(*float64)(p) == *(*float64)(q)
292 }
293 func c64equal(p, q unsafe.Pointer) bool {
294 return *(*complex64)(p) == *(*complex64)(q)
295 }
296 func c128equal(p, q unsafe.Pointer) bool {
297 return *(*complex128)(p) == *(*complex128)(q)
298 }
299 func strequal(p, q unsafe.Pointer) bool {
300 return *(*string)(p) == *(*string)(q)
301 }
302 func interequal(p, q unsafe.Pointer) bool {
303 x := *(*iface)(p)
304 y := *(*iface)(q)
305 return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data)
306 }
307 func nilinterequal(p, q unsafe.Pointer) bool {
308 x := *(*eface)(p)
309 y := *(*eface)(q)
310 return x._type == y._type && efaceeq(x._type, x.data, y.data)
311 }
312 func efaceeq(t *_type, x, y unsafe.Pointer) bool {
313 if t == nil {
314 return true
315 }
316 eq := t.Equal
317 if eq == nil {
318 panic(errorString("comparing uncomparable type " + toRType(t).string()))
319 }
320 if isDirectIface(t) {
321
322
323
324 return x == y
325 }
326 return eq(x, y)
327 }
328 func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
329 if tab == nil {
330 return true
331 }
332 t := tab._type
333 eq := t.Equal
334 if eq == nil {
335 panic(errorString("comparing uncomparable type " + toRType(t).string()))
336 }
337 if isDirectIface(t) {
338
339 return x == y
340 }
341 return eq(x, y)
342 }
343
344
345 func stringHash(s string, seed uintptr) uintptr {
346 return strhash(noescape(unsafe.Pointer(&s)), seed)
347 }
348
349 func bytesHash(b []byte, seed uintptr) uintptr {
350 s := (*slice)(unsafe.Pointer(&b))
351 return memhash(s.array, seed, uintptr(s.len))
352 }
353
354 func int32Hash(i uint32, seed uintptr) uintptr {
355 return memhash32(noescape(unsafe.Pointer(&i)), seed)
356 }
357
358 func int64Hash(i uint64, seed uintptr) uintptr {
359 return memhash64(noescape(unsafe.Pointer(&i)), seed)
360 }
361
362 func efaceHash(i any, seed uintptr) uintptr {
363 return nilinterhash(noescape(unsafe.Pointer(&i)), seed)
364 }
365
366 func ifaceHash(i interface {
367 F()
368 }, seed uintptr) uintptr {
369 return interhash(noescape(unsafe.Pointer(&i)), seed)
370 }
371
372 const hashRandomBytes = goarch.PtrSize / 4 * 64
373
374
375 var aeskeysched [hashRandomBytes]byte
376
377
378 var hashkey [4]uintptr
379
380 func alginit() {
381
382 if (GOARCH == "386" || GOARCH == "amd64") &&
383 cpu.X86.HasAES &&
384 cpu.X86.HasSSSE3 &&
385 cpu.X86.HasSSE41 {
386 initAlgAES()
387 return
388 }
389 if GOARCH == "arm64" && cpu.ARM64.HasAES {
390 initAlgAES()
391 return
392 }
393 for i := range hashkey {
394 hashkey[i] = uintptr(bootstrapRand()) | 1
395 }
396 }
397
398 func initAlgAES() {
399 useAeshash = true
400
401 key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched))
402 for i := range key {
403 key[i] = bootstrapRand()
404 }
405 }
406
407
408 func readUnaligned32(p unsafe.Pointer) uint32 {
409 q := (*[4]byte)(p)
410 if goarch.BigEndian {
411 return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24
412 }
413 return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24
414 }
415
416 func readUnaligned64(p unsafe.Pointer) uint64 {
417 q := (*[8]byte)(p)
418 if goarch.BigEndian {
419 return uint64(q[7]) | uint64(q[6])<<8 | uint64(q[5])<<16 | uint64(q[4])<<24 |
420 uint64(q[3])<<32 | uint64(q[2])<<40 | uint64(q[1])<<48 | uint64(q[0])<<56
421 }
422 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
423 }
424
View as plain text