Source file
src/runtime/iface.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/goarch"
10 "internal/runtime/atomic"
11 "internal/runtime/sys"
12 "unsafe"
13 )
14
15 const itabInitSize = 512
16
17 var (
18 itabLock mutex
19 itabTable = &itabTableInit
20 itabTableInit = itabTableType{size: itabInitSize}
21 )
22
23
24 type itabTableType struct {
25 size uintptr
26 count uintptr
27 entries [itabInitSize]*itab
28 }
29
30 func itabHashFunc(inter *interfacetype, typ *_type) uintptr {
31
32 return uintptr(inter.Type.Hash ^ typ.Hash)
33 }
34
35
36
37
38
39
40
41
42
43
44 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
45 if len(inter.Methods) == 0 {
46 throw("internal error - misuse of itab")
47 }
48
49
50 if typ.TFlag&abi.TFlagUncommon == 0 {
51 if canfail {
52 return nil
53 }
54 name := toRType(&inter.Type).nameOff(inter.Methods[0].Name)
55 panic(&TypeAssertionError{nil, typ, &inter.Type, name.Name()})
56 }
57
58 var m *itab
59
60
61
62
63
64 t := (*itabTableType)(atomic.Loadp(unsafe.Pointer(&itabTable)))
65 if m = t.find(inter, typ); m != nil {
66 goto finish
67 }
68
69
70 lock(&itabLock)
71 if m = itabTable.find(inter, typ); m != nil {
72 unlock(&itabLock)
73 goto finish
74 }
75
76
77 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.Methods)-1)*goarch.PtrSize, 0, &memstats.other_sys))
78 m.Inter = inter
79 m.Type = typ
80
81
82
83
84
85 m.Hash = 0
86 itabInit(m, true)
87 itabAdd(m)
88 unlock(&itabLock)
89 finish:
90 if m.Fun[0] != 0 {
91 return m
92 }
93 if canfail {
94 return nil
95 }
96
97
98
99
100
101
102 panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: itabInit(m, false)})
103 }
104
105
106
107 func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab {
108
109
110
111 mask := t.size - 1
112 h := itabHashFunc(inter, typ) & mask
113 for i := uintptr(1); ; i++ {
114 p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize))
115
116
117
118 m := (*itab)(atomic.Loadp(unsafe.Pointer(p)))
119 if m == nil {
120 return nil
121 }
122 if m.Inter == inter && m.Type == typ {
123 return m
124 }
125 h += i
126 h &= mask
127 }
128 }
129
130
131
132 func itabAdd(m *itab) {
133
134
135
136
137 if getg().m.mallocing != 0 {
138 throw("malloc deadlock")
139 }
140
141 t := itabTable
142 if t.count >= 3*(t.size/4) {
143
144
145
146
147 t2 := (*itabTableType)(mallocgc((2+2*t.size)*goarch.PtrSize, nil, true))
148 t2.size = t.size * 2
149
150
151
152
153
154 iterate_itabs(t2.add)
155 if t2.count != t.count {
156 throw("mismatched count during itab table copy")
157 }
158
159 atomicstorep(unsafe.Pointer(&itabTable), unsafe.Pointer(t2))
160
161 t = itabTable
162
163 }
164 t.add(m)
165 }
166
167
168
169 func (t *itabTableType) add(m *itab) {
170
171
172 mask := t.size - 1
173 h := itabHashFunc(m.Inter, m.Type) & mask
174 for i := uintptr(1); ; i++ {
175 p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize))
176 m2 := *p
177 if m2 == m {
178
179
180
181
182 return
183 }
184 if m2 == nil {
185
186
187
188
189 atomic.StorepNoWB(unsafe.Pointer(p), unsafe.Pointer(m))
190 t.count++
191 return
192 }
193 h += i
194 h &= mask
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209 func itabInit(m *itab, firstTime bool) string {
210 inter := m.Inter
211 typ := m.Type
212 x := typ.Uncommon()
213
214
215
216
217
218 ni := len(inter.Methods)
219 nt := int(x.Mcount)
220 xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt]
221 j := 0
222
223
224
225 methods := (*[1 << 16]uintptr)(unsafe.Pointer(&m.Fun[0]))[:ni:ni]
226 var fun0 unsafe.Pointer
227 imethods:
228 for k := 0; k < ni; k++ {
229 i := &inter.Methods[k]
230 itype := toRType(&inter.Type).typeOff(i.Typ)
231 name := toRType(&inter.Type).nameOff(i.Name)
232 iname := name.Name()
233 ipkg := pkgPath(name)
234 if ipkg == "" {
235 ipkg = inter.PkgPath.Name()
236 }
237 for ; j < nt; j++ {
238 t := &xmhdr[j]
239 rtyp := toRType(typ)
240 tname := rtyp.nameOff(t.Name)
241 if rtyp.typeOff(t.Mtyp) == itype && tname.Name() == iname {
242 pkgPath := pkgPath(tname)
243 if pkgPath == "" {
244 pkgPath = rtyp.nameOff(x.PkgPath).Name()
245 }
246 if tname.IsExported() || pkgPath == ipkg {
247 ifn := rtyp.textOff(t.Ifn)
248 if k == 0 {
249 fun0 = ifn
250 } else if firstTime {
251 methods[k] = uintptr(ifn)
252 }
253 continue imethods
254 }
255 }
256 }
257
258
259 return iname
260 }
261 if firstTime {
262 m.Fun[0] = uintptr(fun0)
263 }
264 return ""
265 }
266
267 func itabsinit() {
268 lockInit(&itabLock, lockRankItab)
269 lock(&itabLock)
270 for _, md := range activeModules() {
271 for _, i := range md.itablinks {
272 itabAdd(i)
273 }
274 }
275 unlock(&itabLock)
276 }
277
278
279
280
281
282 func panicdottypeE(have, want, iface *_type) {
283 panic(&TypeAssertionError{iface, have, want, ""})
284 }
285
286
287
288 func panicdottypeI(have *itab, want, iface *_type) {
289 var t *_type
290 if have != nil {
291 t = have.Type
292 }
293 panicdottypeE(t, want, iface)
294 }
295
296
297
298 func panicnildottype(want *_type) {
299 panic(&TypeAssertionError{nil, nil, want, ""})
300
301
302
303 }
304
305
306
307
308
309
310
311 type (
312 uint16InterfacePtr uint16
313 uint32InterfacePtr uint32
314 uint64InterfacePtr uint64
315 stringInterfacePtr string
316 sliceInterfacePtr []byte
317 )
318
319 var (
320 uint16Eface any = uint16InterfacePtr(0)
321 uint32Eface any = uint32InterfacePtr(0)
322 uint64Eface any = uint64InterfacePtr(0)
323 stringEface any = stringInterfacePtr("")
324 sliceEface any = sliceInterfacePtr(nil)
325
326 uint16Type *_type = efaceOf(&uint16Eface)._type
327 uint32Type *_type = efaceOf(&uint32Eface)._type
328 uint64Type *_type = efaceOf(&uint64Eface)._type
329 stringType *_type = efaceOf(&stringEface)._type
330 sliceType *_type = efaceOf(&sliceEface)._type
331 )
332
333
334
335
336
337
338
339
340
341
342 func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
343 if raceenabled {
344 raceReadObjectPC(t, v, sys.GetCallerPC(), abi.FuncPCABIInternal(convT))
345 }
346 if msanenabled {
347 msanread(v, t.Size_)
348 }
349 if asanenabled {
350 asanread(v, t.Size_)
351 }
352 x := mallocgc(t.Size_, t, true)
353 typedmemmove(t, x, v)
354 return x
355 }
356 func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
357
358 if raceenabled {
359 raceReadObjectPC(t, v, sys.GetCallerPC(), abi.FuncPCABIInternal(convTnoptr))
360 }
361 if msanenabled {
362 msanread(v, t.Size_)
363 }
364 if asanenabled {
365 asanread(v, t.Size_)
366 }
367
368 x := mallocgc(t.Size_, t, false)
369 memmove(x, v, t.Size_)
370 return x
371 }
372
373 func convT16(val uint16) (x unsafe.Pointer) {
374 if val < uint16(len(staticuint64s)) {
375 x = unsafe.Pointer(&staticuint64s[val])
376 if goarch.BigEndian {
377 x = add(x, 6)
378 }
379 } else {
380 x = mallocgc(2, uint16Type, false)
381 *(*uint16)(x) = val
382 }
383 return
384 }
385
386 func convT32(val uint32) (x unsafe.Pointer) {
387 if val < uint32(len(staticuint64s)) {
388 x = unsafe.Pointer(&staticuint64s[val])
389 if goarch.BigEndian {
390 x = add(x, 4)
391 }
392 } else {
393 x = mallocgc(4, uint32Type, false)
394 *(*uint32)(x) = val
395 }
396 return
397 }
398
399
400
401
402
403
404
405
406
407
408 func convT64(val uint64) (x unsafe.Pointer) {
409 if val < uint64(len(staticuint64s)) {
410 x = unsafe.Pointer(&staticuint64s[val])
411 } else {
412 x = mallocgc(8, uint64Type, false)
413 *(*uint64)(x) = val
414 }
415 return
416 }
417
418
419
420
421
422
423
424
425
426
427 func convTstring(val string) (x unsafe.Pointer) {
428 if val == "" {
429 x = unsafe.Pointer(&zeroVal[0])
430 } else {
431 x = mallocgc(unsafe.Sizeof(val), stringType, true)
432 *(*string)(x) = val
433 }
434 return
435 }
436
437
438
439
440
441
442
443
444
445
446 func convTslice(val []byte) (x unsafe.Pointer) {
447
448 if (*slice)(unsafe.Pointer(&val)).array == nil {
449 x = unsafe.Pointer(&zeroVal[0])
450 } else {
451 x = mallocgc(unsafe.Sizeof(val), sliceType, true)
452 *(*[]byte)(x) = val
453 }
454 return
455 }
456
457 func assertE2I(inter *interfacetype, t *_type) *itab {
458 if t == nil {
459
460 panic(&TypeAssertionError{nil, nil, &inter.Type, ""})
461 }
462 return getitab(inter, t, false)
463 }
464
465 func assertE2I2(inter *interfacetype, t *_type) *itab {
466 if t == nil {
467 return nil
468 }
469 return getitab(inter, t, true)
470 }
471
472
473
474
475 func typeAssert(s *abi.TypeAssert, t *_type) *itab {
476 var tab *itab
477 if t == nil {
478 if !s.CanFail {
479 panic(&TypeAssertionError{nil, nil, &s.Inter.Type, ""})
480 }
481 } else {
482 tab = getitab(s.Inter, t, s.CanFail)
483 }
484
485 if !abi.UseInterfaceSwitchCache(goarch.ArchFamily) {
486 return tab
487 }
488
489
490
491 if cheaprand()&1023 != 0 {
492
493 return tab
494 }
495
496 oldC := (*abi.TypeAssertCache)(atomic.Loadp(unsafe.Pointer(&s.Cache)))
497
498 if cheaprand()&uint32(oldC.Mask) != 0 {
499
500
501 return tab
502 }
503
504
505 newC := buildTypeAssertCache(oldC, t, tab)
506
507
508
509
510 atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC))
511
512 return tab
513 }
514
515 func buildTypeAssertCache(oldC *abi.TypeAssertCache, typ *_type, tab *itab) *abi.TypeAssertCache {
516 oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1)
517
518
519 n := 1
520 for _, e := range oldEntries {
521 if e.Typ != 0 {
522 n++
523 }
524 }
525
526
527
528
529 newN := n * 2
530 newN = 1 << sys.Len64(uint64(newN-1))
531
532
533 newSize := unsafe.Sizeof(abi.TypeAssertCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.TypeAssertCacheEntry{})
534 newC := (*abi.TypeAssertCache)(mallocgc(newSize, nil, true))
535 newC.Mask = uintptr(newN - 1)
536 newEntries := unsafe.Slice(&newC.Entries[0], newN)
537
538
539 addEntry := func(typ *_type, tab *itab) {
540 h := int(typ.Hash) & (newN - 1)
541 for {
542 if newEntries[h].Typ == 0 {
543 newEntries[h].Typ = uintptr(unsafe.Pointer(typ))
544 newEntries[h].Itab = uintptr(unsafe.Pointer(tab))
545 return
546 }
547 h = (h + 1) & (newN - 1)
548 }
549 }
550 for _, e := range oldEntries {
551 if e.Typ != 0 {
552 addEntry((*_type)(unsafe.Pointer(e.Typ)), (*itab)(unsafe.Pointer(e.Itab)))
553 }
554 }
555 addEntry(typ, tab)
556
557 return newC
558 }
559
560
561
562 var emptyTypeAssertCache = abi.TypeAssertCache{Mask: 0}
563
564
565
566
567
568
569 func interfaceSwitch(s *abi.InterfaceSwitch, t *_type) (int, *itab) {
570 cases := unsafe.Slice(&s.Cases[0], s.NCases)
571
572
573 case_ := len(cases)
574 var tab *itab
575
576
577 for i, c := range cases {
578 tab = getitab(c, t, true)
579 if tab != nil {
580 case_ = i
581 break
582 }
583 }
584
585 if !abi.UseInterfaceSwitchCache(goarch.ArchFamily) {
586 return case_, tab
587 }
588
589
590
591 if cheaprand()&1023 != 0 {
592
593
594
595 return case_, tab
596 }
597
598 oldC := (*abi.InterfaceSwitchCache)(atomic.Loadp(unsafe.Pointer(&s.Cache)))
599
600 if cheaprand()&uint32(oldC.Mask) != 0 {
601
602
603
604 return case_, tab
605 }
606
607
608 newC := buildInterfaceSwitchCache(oldC, t, case_, tab)
609
610
611
612
613 atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC))
614
615 return case_, tab
616 }
617
618
619
620
621 func buildInterfaceSwitchCache(oldC *abi.InterfaceSwitchCache, typ *_type, case_ int, tab *itab) *abi.InterfaceSwitchCache {
622 oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1)
623
624
625 n := 1
626 for _, e := range oldEntries {
627 if e.Typ != 0 {
628 n++
629 }
630 }
631
632
633
634
635 newN := n * 2
636 newN = 1 << sys.Len64(uint64(newN-1))
637
638
639 newSize := unsafe.Sizeof(abi.InterfaceSwitchCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.InterfaceSwitchCacheEntry{})
640 newC := (*abi.InterfaceSwitchCache)(mallocgc(newSize, nil, true))
641 newC.Mask = uintptr(newN - 1)
642 newEntries := unsafe.Slice(&newC.Entries[0], newN)
643
644
645 addEntry := func(typ *_type, case_ int, tab *itab) {
646 h := int(typ.Hash) & (newN - 1)
647 for {
648 if newEntries[h].Typ == 0 {
649 newEntries[h].Typ = uintptr(unsafe.Pointer(typ))
650 newEntries[h].Case = case_
651 newEntries[h].Itab = uintptr(unsafe.Pointer(tab))
652 return
653 }
654 h = (h + 1) & (newN - 1)
655 }
656 }
657 for _, e := range oldEntries {
658 if e.Typ != 0 {
659 addEntry((*_type)(unsafe.Pointer(e.Typ)), e.Case, (*itab)(unsafe.Pointer(e.Itab)))
660 }
661 }
662 addEntry(typ, case_, tab)
663
664 return newC
665 }
666
667
668
669 var emptyInterfaceSwitchCache = abi.InterfaceSwitchCache{Mask: 0}
670
671
672
673
674
675
676
677
678
679
680
681 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
682 *dst = iface{assertE2I(inter, e._type), e.data}
683 }
684
685
686 func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
687 *dst = iface{assertE2I(inter, e._type), e.data}
688 }
689
690 func iterate_itabs(fn func(*itab)) {
691
692
693 t := itabTable
694 for i := uintptr(0); i < t.size; i++ {
695 m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize))
696 if m != nil {
697 fn(m)
698 }
699 }
700 }
701
702
703
704
705 var staticuint64s [256]uint64
706
707
708
709
710
711 func getStaticuint64s() *[256]uint64 {
712 return &staticuint64s
713 }
714
715
716
717
718 func unreachableMethod() {
719 throw("unreachable method called. linker bug?")
720 }
721
View as plain text