Source file
src/runtime/type.go
Documentation: runtime
1
2
3
4
5
6
7 package runtime
8
9 import "unsafe"
10
11
12
13
14
15
16
17
18 type tflag uint8
19
20 const (
21 tflagUncommon tflag = 1 << 0
22 tflagExtraStar tflag = 1 << 1
23 tflagNamed tflag = 1 << 2
24 tflagRegularMemory tflag = 1 << 3
25 )
26
27
28
29
30
31 type _type struct {
32 size uintptr
33 ptrdata uintptr
34 hash uint32
35 tflag tflag
36 align uint8
37 fieldAlign uint8
38 kind uint8
39
40
41 equal func(unsafe.Pointer, unsafe.Pointer) bool
42
43
44
45 gcdata *byte
46 str nameOff
47 ptrToThis typeOff
48 }
49
50 func (t *_type) string() string {
51 s := t.nameOff(t.str).name()
52 if t.tflag&tflagExtraStar != 0 {
53 return s[1:]
54 }
55 return s
56 }
57
58 func (t *_type) uncommon() *uncommontype {
59 if t.tflag&tflagUncommon == 0 {
60 return nil
61 }
62 switch t.kind & kindMask {
63 case kindStruct:
64 type u struct {
65 structtype
66 u uncommontype
67 }
68 return &(*u)(unsafe.Pointer(t)).u
69 case kindPtr:
70 type u struct {
71 ptrtype
72 u uncommontype
73 }
74 return &(*u)(unsafe.Pointer(t)).u
75 case kindFunc:
76 type u struct {
77 functype
78 u uncommontype
79 }
80 return &(*u)(unsafe.Pointer(t)).u
81 case kindSlice:
82 type u struct {
83 slicetype
84 u uncommontype
85 }
86 return &(*u)(unsafe.Pointer(t)).u
87 case kindArray:
88 type u struct {
89 arraytype
90 u uncommontype
91 }
92 return &(*u)(unsafe.Pointer(t)).u
93 case kindChan:
94 type u struct {
95 chantype
96 u uncommontype
97 }
98 return &(*u)(unsafe.Pointer(t)).u
99 case kindMap:
100 type u struct {
101 maptype
102 u uncommontype
103 }
104 return &(*u)(unsafe.Pointer(t)).u
105 case kindInterface:
106 type u struct {
107 interfacetype
108 u uncommontype
109 }
110 return &(*u)(unsafe.Pointer(t)).u
111 default:
112 type u struct {
113 _type
114 u uncommontype
115 }
116 return &(*u)(unsafe.Pointer(t)).u
117 }
118 }
119
120 func (t *_type) name() string {
121 if t.tflag&tflagNamed == 0 {
122 return ""
123 }
124 s := t.string()
125 i := len(s) - 1
126 for i >= 0 && s[i] != '.' {
127 i--
128 }
129 return s[i+1:]
130 }
131
132
133
134
135
136 func (t *_type) pkgpath() string {
137 if u := t.uncommon(); u != nil {
138 return t.nameOff(u.pkgpath).name()
139 }
140 switch t.kind & kindMask {
141 case kindStruct:
142 st := (*structtype)(unsafe.Pointer(t))
143 return st.pkgPath.name()
144 case kindInterface:
145 it := (*interfacetype)(unsafe.Pointer(t))
146 return it.pkgpath.name()
147 }
148 return ""
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 var reflectOffs struct {
165 lock mutex
166 next int32
167 m map[int32]unsafe.Pointer
168 minv map[unsafe.Pointer]int32
169 }
170
171 func reflectOffsLock() {
172 lock(&reflectOffs.lock)
173 if raceenabled {
174 raceacquire(unsafe.Pointer(&reflectOffs.lock))
175 }
176 }
177
178 func reflectOffsUnlock() {
179 if raceenabled {
180 racerelease(unsafe.Pointer(&reflectOffs.lock))
181 }
182 unlock(&reflectOffs.lock)
183 }
184
185 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
186 if off == 0 {
187 return name{}
188 }
189 base := uintptr(ptrInModule)
190 for md := &firstmoduledata; md != nil; md = md.next {
191 if base >= md.types && base < md.etypes {
192 res := md.types + uintptr(off)
193 if res > md.etypes {
194 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
195 throw("runtime: name offset out of range")
196 }
197 return name{(*byte)(unsafe.Pointer(res))}
198 }
199 }
200
201
202 reflectOffsLock()
203 res, found := reflectOffs.m[int32(off)]
204 reflectOffsUnlock()
205 if !found {
206 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
207 for next := &firstmoduledata; next != nil; next = next.next {
208 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
209 }
210 throw("runtime: name offset base pointer out of range")
211 }
212 return name{(*byte)(res)}
213 }
214
215 func (t *_type) nameOff(off nameOff) name {
216 return resolveNameOff(unsafe.Pointer(t), off)
217 }
218
219 func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
220 if off == 0 || off == -1 {
221
222
223 return nil
224 }
225 base := uintptr(ptrInModule)
226 var md *moduledata
227 for next := &firstmoduledata; next != nil; next = next.next {
228 if base >= next.types && base < next.etypes {
229 md = next
230 break
231 }
232 }
233 if md == nil {
234 reflectOffsLock()
235 res := reflectOffs.m[int32(off)]
236 reflectOffsUnlock()
237 if res == nil {
238 println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
239 for next := &firstmoduledata; next != nil; next = next.next {
240 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
241 }
242 throw("runtime: type offset base pointer out of range")
243 }
244 return (*_type)(res)
245 }
246 if t := md.typemap[off]; t != nil {
247 return t
248 }
249 res := md.types + uintptr(off)
250 if res > md.etypes {
251 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
252 throw("runtime: type offset out of range")
253 }
254 return (*_type)(unsafe.Pointer(res))
255 }
256
257 func (t *_type) typeOff(off typeOff) *_type {
258 return resolveTypeOff(unsafe.Pointer(t), off)
259 }
260
261 func (t *_type) textOff(off textOff) unsafe.Pointer {
262 if off == -1 {
263
264
265 return unsafe.Pointer(funcPC(unreachableMethod))
266 }
267 base := uintptr(unsafe.Pointer(t))
268 var md *moduledata
269 for next := &firstmoduledata; next != nil; next = next.next {
270 if base >= next.types && base < next.etypes {
271 md = next
272 break
273 }
274 }
275 if md == nil {
276 reflectOffsLock()
277 res := reflectOffs.m[int32(off)]
278 reflectOffsUnlock()
279 if res == nil {
280 println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
281 for next := &firstmoduledata; next != nil; next = next.next {
282 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
283 }
284 throw("runtime: text offset base pointer out of range")
285 }
286 return res
287 }
288 res := uintptr(0)
289
290
291
292
293
294
295
296
297
298 if len(md.textsectmap) > 1 {
299 for i := range md.textsectmap {
300 sectaddr := md.textsectmap[i].vaddr
301 sectlen := md.textsectmap[i].length
302 if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
303 res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
304 break
305 }
306 }
307 } else {
308
309 res = md.text + uintptr(off)
310 }
311
312 if res > md.etext && GOARCH != "wasm" {
313 println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
314 throw("runtime: text offset out of range")
315 }
316 return unsafe.Pointer(res)
317 }
318
319 func (t *functype) in() []*_type {
320
321 uadd := uintptr(unsafe.Sizeof(functype{}))
322 if t.typ.tflag&tflagUncommon != 0 {
323 uadd += unsafe.Sizeof(uncommontype{})
324 }
325 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
326 }
327
328 func (t *functype) out() []*_type {
329
330 uadd := uintptr(unsafe.Sizeof(functype{}))
331 if t.typ.tflag&tflagUncommon != 0 {
332 uadd += unsafe.Sizeof(uncommontype{})
333 }
334 outCount := t.outCount & (1<<15 - 1)
335 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
336 }
337
338 func (t *functype) dotdotdot() bool {
339 return t.outCount&(1<<15) != 0
340 }
341
342 type nameOff int32
343 type typeOff int32
344 type textOff int32
345
346 type method struct {
347 name nameOff
348 mtyp typeOff
349 ifn textOff
350 tfn textOff
351 }
352
353 type uncommontype struct {
354 pkgpath nameOff
355 mcount uint16
356 xcount uint16
357 moff uint32
358 _ uint32
359 }
360
361 type imethod struct {
362 name nameOff
363 ityp typeOff
364 }
365
366 type interfacetype struct {
367 typ _type
368 pkgpath name
369 mhdr []imethod
370 }
371
372 type maptype struct {
373 typ _type
374 key *_type
375 elem *_type
376 bucket *_type
377
378 hasher func(unsafe.Pointer, uintptr) uintptr
379 keysize uint8
380 elemsize uint8
381 bucketsize uint16
382 flags uint32
383 }
384
385
386
387 func (mt *maptype) indirectkey() bool {
388 return mt.flags&1 != 0
389 }
390 func (mt *maptype) indirectelem() bool {
391 return mt.flags&2 != 0
392 }
393 func (mt *maptype) reflexivekey() bool {
394 return mt.flags&4 != 0
395 }
396 func (mt *maptype) needkeyupdate() bool {
397 return mt.flags&8 != 0
398 }
399 func (mt *maptype) hashMightPanic() bool {
400 return mt.flags&16 != 0
401 }
402
403 type arraytype struct {
404 typ _type
405 elem *_type
406 slice *_type
407 len uintptr
408 }
409
410 type chantype struct {
411 typ _type
412 elem *_type
413 dir uintptr
414 }
415
416 type slicetype struct {
417 typ _type
418 elem *_type
419 }
420
421 type functype struct {
422 typ _type
423 inCount uint16
424 outCount uint16
425 }
426
427 type ptrtype struct {
428 typ _type
429 elem *_type
430 }
431
432 type structfield struct {
433 name name
434 typ *_type
435 offsetAnon uintptr
436 }
437
438 func (f *structfield) offset() uintptr {
439 return f.offsetAnon >> 1
440 }
441
442 type structtype struct {
443 typ _type
444 pkgPath name
445 fields []structfield
446 }
447
448
449
450 type name struct {
451 bytes *byte
452 }
453
454 func (n name) data(off int) *byte {
455 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
456 }
457
458 func (n name) isExported() bool {
459 return (*n.bytes)&(1<<0) != 0
460 }
461
462 func (n name) readvarint(off int) (int, int) {
463 v := 0
464 for i := 0; ; i++ {
465 x := *n.data(off + i)
466 v += int(x&0x7f) << (7 * i)
467 if x&0x80 == 0 {
468 return i + 1, v
469 }
470 }
471 }
472
473 func (n name) name() (s string) {
474 if n.bytes == nil {
475 return ""
476 }
477 i, l := n.readvarint(1)
478 if l == 0 {
479 return ""
480 }
481 hdr := (*stringStruct)(unsafe.Pointer(&s))
482 hdr.str = unsafe.Pointer(n.data(1 + i))
483 hdr.len = l
484 return
485 }
486
487 func (n name) tag() (s string) {
488 if *n.data(0)&(1<<1) == 0 {
489 return ""
490 }
491 i, l := n.readvarint(1)
492 i2, l2 := n.readvarint(1 + i + l)
493 hdr := (*stringStruct)(unsafe.Pointer(&s))
494 hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
495 hdr.len = l2
496 return
497 }
498
499 func (n name) pkgPath() string {
500 if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
501 return ""
502 }
503 i, l := n.readvarint(1)
504 off := 1 + i + l
505 if *n.data(0)&(1<<1) != 0 {
506 i2, l2 := n.readvarint(off)
507 off += i2 + l2
508 }
509 var nameOff nameOff
510 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
511 pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
512 return pkgPathName.name()
513 }
514
515 func (n name) isBlank() bool {
516 if n.bytes == nil {
517 return false
518 }
519 _, l := n.readvarint(1)
520 return l == 1 && *n.data(2) == '_'
521 }
522
523
524
525 func typelinksinit() {
526 if firstmoduledata.next == nil {
527 return
528 }
529 typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
530
531 modules := activeModules()
532 prev := modules[0]
533 for _, md := range modules[1:] {
534
535 collect:
536 for _, tl := range prev.typelinks {
537 var t *_type
538 if prev.typemap == nil {
539 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
540 } else {
541 t = prev.typemap[typeOff(tl)]
542 }
543
544 tlist := typehash[t.hash]
545 for _, tcur := range tlist {
546 if tcur == t {
547 continue collect
548 }
549 }
550 typehash[t.hash] = append(tlist, t)
551 }
552
553 if md.typemap == nil {
554
555
556
557 tm := make(map[typeOff]*_type, len(md.typelinks))
558 pinnedTypemaps = append(pinnedTypemaps, tm)
559 md.typemap = tm
560 for _, tl := range md.typelinks {
561 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
562 for _, candidate := range typehash[t.hash] {
563 seen := map[_typePair]struct{}{}
564 if typesEqual(t, candidate, seen) {
565 t = candidate
566 break
567 }
568 }
569 md.typemap[typeOff(tl)] = t
570 }
571 }
572
573 prev = md
574 }
575 }
576
577 type _typePair struct {
578 t1 *_type
579 t2 *_type
580 }
581
582
583
584
585
586
587
588
589
590
591
592
593
594 func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
595 tp := _typePair{t, v}
596 if _, ok := seen[tp]; ok {
597 return true
598 }
599
600
601
602
603 seen[tp] = struct{}{}
604
605 if t == v {
606 return true
607 }
608 kind := t.kind & kindMask
609 if kind != v.kind&kindMask {
610 return false
611 }
612 if t.string() != v.string() {
613 return false
614 }
615 ut := t.uncommon()
616 uv := v.uncommon()
617 if ut != nil || uv != nil {
618 if ut == nil || uv == nil {
619 return false
620 }
621 pkgpatht := t.nameOff(ut.pkgpath).name()
622 pkgpathv := v.nameOff(uv.pkgpath).name()
623 if pkgpatht != pkgpathv {
624 return false
625 }
626 }
627 if kindBool <= kind && kind <= kindComplex128 {
628 return true
629 }
630 switch kind {
631 case kindString, kindUnsafePointer:
632 return true
633 case kindArray:
634 at := (*arraytype)(unsafe.Pointer(t))
635 av := (*arraytype)(unsafe.Pointer(v))
636 return typesEqual(at.elem, av.elem, seen) && at.len == av.len
637 case kindChan:
638 ct := (*chantype)(unsafe.Pointer(t))
639 cv := (*chantype)(unsafe.Pointer(v))
640 return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
641 case kindFunc:
642 ft := (*functype)(unsafe.Pointer(t))
643 fv := (*functype)(unsafe.Pointer(v))
644 if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
645 return false
646 }
647 tin, vin := ft.in(), fv.in()
648 for i := 0; i < len(tin); i++ {
649 if !typesEqual(tin[i], vin[i], seen) {
650 return false
651 }
652 }
653 tout, vout := ft.out(), fv.out()
654 for i := 0; i < len(tout); i++ {
655 if !typesEqual(tout[i], vout[i], seen) {
656 return false
657 }
658 }
659 return true
660 case kindInterface:
661 it := (*interfacetype)(unsafe.Pointer(t))
662 iv := (*interfacetype)(unsafe.Pointer(v))
663 if it.pkgpath.name() != iv.pkgpath.name() {
664 return false
665 }
666 if len(it.mhdr) != len(iv.mhdr) {
667 return false
668 }
669 for i := range it.mhdr {
670 tm := &it.mhdr[i]
671 vm := &iv.mhdr[i]
672
673
674 tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
675 vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
676 if tname.name() != vname.name() {
677 return false
678 }
679 if tname.pkgPath() != vname.pkgPath() {
680 return false
681 }
682 tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
683 vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
684 if !typesEqual(tityp, vityp, seen) {
685 return false
686 }
687 }
688 return true
689 case kindMap:
690 mt := (*maptype)(unsafe.Pointer(t))
691 mv := (*maptype)(unsafe.Pointer(v))
692 return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
693 case kindPtr:
694 pt := (*ptrtype)(unsafe.Pointer(t))
695 pv := (*ptrtype)(unsafe.Pointer(v))
696 return typesEqual(pt.elem, pv.elem, seen)
697 case kindSlice:
698 st := (*slicetype)(unsafe.Pointer(t))
699 sv := (*slicetype)(unsafe.Pointer(v))
700 return typesEqual(st.elem, sv.elem, seen)
701 case kindStruct:
702 st := (*structtype)(unsafe.Pointer(t))
703 sv := (*structtype)(unsafe.Pointer(v))
704 if len(st.fields) != len(sv.fields) {
705 return false
706 }
707 if st.pkgPath.name() != sv.pkgPath.name() {
708 return false
709 }
710 for i := range st.fields {
711 tf := &st.fields[i]
712 vf := &sv.fields[i]
713 if tf.name.name() != vf.name.name() {
714 return false
715 }
716 if !typesEqual(tf.typ, vf.typ, seen) {
717 return false
718 }
719 if tf.name.tag() != vf.name.tag() {
720 return false
721 }
722 if tf.offsetAnon != vf.offsetAnon {
723 return false
724 }
725 }
726 return true
727 default:
728 println("runtime: impossible type kind", kind)
729 throw("runtime: impossible type kind")
730 return false
731 }
732 }
733
View as plain text