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