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