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