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 != nil && m2.Inter == m.Inter && m2.Type == m.Type {
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 := unsafe.Slice((*abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff))), nt)
221 j := 0
222
223
224
225 methods := unsafe.Slice(&m.Fun[0], 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 addModuleItabs(md)
272 }
273 unlock(&itabLock)
274 }
275
276
277
278 func addModuleItabs(md *moduledata) {
279 p := md.types + md.itaboffset
280 end := p + md.itabsize
281 for p < end {
282 itab := (*itab)(unsafe.Pointer(p))
283 itabAdd(itab)
284 p += uintptr(itab.Size())
285 }
286 }
287
288
289
290
291
292 func panicdottypeE(have, want, iface *_type) {
293 panic(&TypeAssertionError{iface, have, want, ""})
294 }
295
296
297
298 func panicdottypeI(have *itab, want, iface *_type) {
299 var t *_type
300 if have != nil {
301 t = have.Type
302 }
303 panicdottypeE(t, want, iface)
304 }
305
306
307
308 func panicnildottype(want *_type) {
309 panic(&TypeAssertionError{nil, nil, want, ""})
310
311
312
313 }
314
315
316
317
318
319
320
321 type (
322 uint16InterfacePtr uint16
323 uint32InterfacePtr uint32
324 uint64InterfacePtr uint64
325 stringInterfacePtr string
326 sliceInterfacePtr []byte
327 )
328
329 var (
330 uint16Eface any = uint16InterfacePtr(0)
331 uint32Eface any = uint32InterfacePtr(0)
332 uint64Eface any = uint64InterfacePtr(0)
333 stringEface any = stringInterfacePtr("")
334 sliceEface any = sliceInterfacePtr(nil)
335
336 uint16Type *_type = efaceOf(&uint16Eface)._type
337 uint32Type *_type = efaceOf(&uint32Eface)._type
338 uint64Type *_type = efaceOf(&uint64Eface)._type
339 stringType *_type = efaceOf(&stringEface)._type
340 sliceType *_type = efaceOf(&sliceEface)._type
341 )
342
343
344
345
346
347
348
349
350
351
352 func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
353 if raceenabled {
354 raceReadObjectPC(t, v, sys.GetCallerPC(), abi.FuncPCABIInternal(convT))
355 }
356 if msanenabled {
357 msanread(v, t.Size_)
358 }
359 if asanenabled {
360 asanread(v, t.Size_)
361 }
362 x := mallocgc(t.Size_, t, true)
363 typedmemmove(t, x, v)
364 return x
365 }
366 func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
367
368 if raceenabled {
369 raceReadObjectPC(t, v, sys.GetCallerPC(), abi.FuncPCABIInternal(convTnoptr))
370 }
371 if msanenabled {
372 msanread(v, t.Size_)
373 }
374 if asanenabled {
375 asanread(v, t.Size_)
376 }
377
378 x := mallocgc(t.Size_, t, false)
379 memmove(x, v, t.Size_)
380 return x
381 }
382
383 func convT16(val uint16) (x unsafe.Pointer) {
384 if val < uint16(len(staticuint64s)) {
385 x = unsafe.Pointer(&staticuint64s[val])
386 if goarch.BigEndian {
387 x = add(x, 6)
388 }
389 } else {
390 x = mallocgc(2, uint16Type, false)
391 *(*uint16)(x) = val
392 }
393 return
394 }
395
396 func convT32(val uint32) (x unsafe.Pointer) {
397 if val < uint32(len(staticuint64s)) {
398 x = unsafe.Pointer(&staticuint64s[val])
399 if goarch.BigEndian {
400 x = add(x, 4)
401 }
402 } else {
403 x = mallocgc(4, uint32Type, false)
404 *(*uint32)(x) = val
405 }
406 return
407 }
408
409
410
411
412
413
414
415
416
417
418 func convT64(val uint64) (x unsafe.Pointer) {
419 if val < uint64(len(staticuint64s)) {
420 x = unsafe.Pointer(&staticuint64s[val])
421 } else {
422 x = mallocgc(8, uint64Type, false)
423 *(*uint64)(x) = val
424 }
425 return
426 }
427
428
429
430
431
432
433
434
435
436
437 func convTstring(val string) (x unsafe.Pointer) {
438 if val == "" {
439 x = unsafe.Pointer(&zeroVal[0])
440 } else {
441 x = mallocgc(unsafe.Sizeof(val), stringType, true)
442 *(*string)(x) = val
443 }
444 return
445 }
446
447
448
449
450
451
452
453
454
455
456 func convTslice(val []byte) (x unsafe.Pointer) {
457
458 if (*slice)(unsafe.Pointer(&val)).array == nil {
459 x = unsafe.Pointer(&zeroVal[0])
460 } else {
461 x = mallocgc(unsafe.Sizeof(val), sliceType, true)
462 *(*[]byte)(x) = val
463 }
464 return
465 }
466
467 func assertE2I(inter *interfacetype, t *_type) *itab {
468 if t == nil {
469
470 panic(&TypeAssertionError{nil, nil, &inter.Type, ""})
471 }
472 return getitab(inter, t, false)
473 }
474
475 func assertE2I2(inter *interfacetype, t *_type) *itab {
476 if t == nil {
477 return nil
478 }
479 return getitab(inter, t, true)
480 }
481
482
483
484
485 func typeAssert(s *abi.TypeAssert, t *_type) *itab {
486 var tab *itab
487 if t == nil {
488 if !s.CanFail {
489 panic(&TypeAssertionError{nil, nil, &s.Inter.Type, ""})
490 }
491 } else {
492 tab = getitab(s.Inter, t, s.CanFail)
493 }
494
495 if !abi.UseInterfaceSwitchCache(goarch.ArchFamily) {
496 return tab
497 }
498
499
500
501 if cheaprand()&1023 != 0 {
502
503 return tab
504 }
505
506 oldC := (*abi.TypeAssertCache)(atomic.Loadp(unsafe.Pointer(&s.Cache)))
507
508 if cheaprand()&uint32(oldC.Mask) != 0 {
509
510
511 return tab
512 }
513
514
515 newC := buildTypeAssertCache(oldC, t, tab)
516
517
518
519
520 atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC))
521
522 return tab
523 }
524
525 func buildTypeAssertCache(oldC *abi.TypeAssertCache, typ *_type, tab *itab) *abi.TypeAssertCache {
526 oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1)
527
528
529 n := 1
530 for _, e := range oldEntries {
531 if e.Typ != 0 {
532 n++
533 }
534 }
535
536
537
538
539 newN := n * 2
540 newN = 1 << sys.Len64(uint64(newN-1))
541
542
543 newSize := unsafe.Sizeof(abi.TypeAssertCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.TypeAssertCacheEntry{})
544 newC := (*abi.TypeAssertCache)(mallocgc(newSize, nil, true))
545 newC.Mask = uintptr(newN - 1)
546 newEntries := unsafe.Slice(&newC.Entries[0], newN)
547
548
549 addEntry := func(typ *_type, tab *itab) {
550 h := int(typ.Hash) & (newN - 1)
551 for {
552 if newEntries[h].Typ == 0 {
553 newEntries[h].Typ = uintptr(unsafe.Pointer(typ))
554 newEntries[h].Itab = uintptr(unsafe.Pointer(tab))
555 return
556 }
557 h = (h + 1) & (newN - 1)
558 }
559 }
560 for _, e := range oldEntries {
561 if e.Typ != 0 {
562 addEntry((*_type)(unsafe.Pointer(e.Typ)), (*itab)(unsafe.Pointer(e.Itab)))
563 }
564 }
565 addEntry(typ, tab)
566
567 return newC
568 }
569
570
571
572 var emptyTypeAssertCache = abi.TypeAssertCache{Mask: 0}
573
574
575
576
577
578
579 func interfaceSwitch(s *abi.InterfaceSwitch, t *_type) (int, *itab) {
580 cases := unsafe.Slice(&s.Cases[0], s.NCases)
581
582
583 case_ := len(cases)
584 var tab *itab
585
586
587 for i, c := range cases {
588 tab = getitab(c, t, true)
589 if tab != nil {
590 case_ = i
591 break
592 }
593 }
594
595 if !abi.UseInterfaceSwitchCache(goarch.ArchFamily) {
596 return case_, tab
597 }
598
599
600
601 if cheaprand()&1023 != 0 {
602
603
604
605 return case_, tab
606 }
607
608 oldC := (*abi.InterfaceSwitchCache)(atomic.Loadp(unsafe.Pointer(&s.Cache)))
609
610 if cheaprand()&uint32(oldC.Mask) != 0 {
611
612
613
614 return case_, tab
615 }
616
617
618 newC := buildInterfaceSwitchCache(oldC, t, case_, tab)
619
620
621
622
623 atomic_casPointer((*unsafe.Pointer)(unsafe.Pointer(&s.Cache)), unsafe.Pointer(oldC), unsafe.Pointer(newC))
624
625 return case_, tab
626 }
627
628
629
630
631 func buildInterfaceSwitchCache(oldC *abi.InterfaceSwitchCache, typ *_type, case_ int, tab *itab) *abi.InterfaceSwitchCache {
632 oldEntries := unsafe.Slice(&oldC.Entries[0], oldC.Mask+1)
633
634
635 n := 1
636 for _, e := range oldEntries {
637 if e.Typ != 0 {
638 n++
639 }
640 }
641
642
643
644
645 newN := n * 2
646 newN = 1 << sys.Len64(uint64(newN-1))
647
648
649 newSize := unsafe.Sizeof(abi.InterfaceSwitchCache{}) + uintptr(newN-1)*unsafe.Sizeof(abi.InterfaceSwitchCacheEntry{})
650 newC := (*abi.InterfaceSwitchCache)(mallocgc(newSize, nil, true))
651 newC.Mask = uintptr(newN - 1)
652 newEntries := unsafe.Slice(&newC.Entries[0], newN)
653
654
655 addEntry := func(typ *_type, case_ int, tab *itab) {
656 h := int(typ.Hash) & (newN - 1)
657 for {
658 if newEntries[h].Typ == 0 {
659 newEntries[h].Typ = uintptr(unsafe.Pointer(typ))
660 newEntries[h].Case = case_
661 newEntries[h].Itab = uintptr(unsafe.Pointer(tab))
662 return
663 }
664 h = (h + 1) & (newN - 1)
665 }
666 }
667 for _, e := range oldEntries {
668 if e.Typ != 0 {
669 addEntry((*_type)(unsafe.Pointer(e.Typ)), e.Case, (*itab)(unsafe.Pointer(e.Itab)))
670 }
671 }
672 addEntry(typ, case_, tab)
673
674 return newC
675 }
676
677
678
679 var emptyInterfaceSwitchCache = abi.InterfaceSwitchCache{Mask: 0}
680
681
682
683
684
685
686
687
688
689
690
691 func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
692 *dst = iface{assertE2I(inter, e._type), e.data}
693 }
694
695
696 func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
697 *dst = iface{assertE2I(inter, e._type), e.data}
698 }
699
700 func iterate_itabs(fn func(*itab)) {
701
702
703 t := itabTable
704 for i := uintptr(0); i < t.size; i++ {
705 m := *(**itab)(add(unsafe.Pointer(&t.entries), i*goarch.PtrSize))
706 if m != nil {
707 fn(m)
708 }
709 }
710 }
711
712
713
714
715 var staticuint64s [256]uint64
716
717
718
719
720
721 func getStaticuint64s() *[256]uint64 {
722 return &staticuint64s
723 }
724
725
726
727
728 func unreachableMethod() {
729 throw("unreachable method called. linker bug?")
730 }
731
View as plain text