Source file
src/reflect/type.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package reflect
17
18 import (
19 "internal/goarch"
20 "internal/unsafeheader"
21 "strconv"
22 "sync"
23 "unicode"
24 "unicode/utf8"
25 "unsafe"
26 )
27
28
29
30
31
32
33
34
35
36
37
38
39 type Type interface {
40
41
42
43
44 Align() int
45
46
47
48 FieldAlign() int
49
50
51
52
53
54
55
56
57
58
59
60
61 Method(int) Method
62
63
64
65
66
67
68
69
70
71 MethodByName(string) (Method, bool)
72
73
74
75
76 NumMethod() int
77
78
79
80 Name() string
81
82
83
84
85
86
87 PkgPath() string
88
89
90
91 Size() uintptr
92
93
94
95
96
97
98 String() string
99
100
101 Kind() Kind
102
103
104 Implements(u Type) bool
105
106
107 AssignableTo(u Type) bool
108
109
110
111
112
113 ConvertibleTo(u Type) bool
114
115
116
117
118
119 Comparable() bool
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 Bits() int
137
138
139
140 ChanDir() ChanDir
141
142
143
144
145
146
147
148
149
150
151
152
153
154 IsVariadic() bool
155
156
157
158 Elem() Type
159
160
161
162
163 Field(i int) StructField
164
165
166
167
168
169 FieldByIndex(index []int) StructField
170
171
172
173 FieldByName(name string) (StructField, bool)
174
175
176
177
178
179
180
181
182
183
184
185
186
187 FieldByNameFunc(match func(string) bool) (StructField, bool)
188
189
190
191
192 In(i int) Type
193
194
195
196 Key() Type
197
198
199
200 Len() int
201
202
203
204 NumField() int
205
206
207
208 NumIn() int
209
210
211
212 NumOut() int
213
214
215
216
217 Out(i int) Type
218
219 common() *rtype
220 uncommon() *uncommonType
221 }
222
223
224
225
226
227
228
229
230
231
236
237
238
239 type Kind uint
240
241 const (
242 Invalid Kind = iota
243 Bool
244 Int
245 Int8
246 Int16
247 Int32
248 Int64
249 Uint
250 Uint8
251 Uint16
252 Uint32
253 Uint64
254 Uintptr
255 Float32
256 Float64
257 Complex64
258 Complex128
259 Array
260 Chan
261 Func
262 Interface
263 Map
264 Pointer
265 Slice
266 String
267 Struct
268 UnsafePointer
269 )
270
271
272 const Ptr = Pointer
273
274
275
276
277
278
279
280
281 type tflag uint8
282
283 const (
284
285
286
287
288
289
290
291
292
293
294
295 tflagUncommon tflag = 1 << 0
296
297
298
299
300
301 tflagExtraStar tflag = 1 << 1
302
303
304 tflagNamed tflag = 1 << 2
305
306
307
308 tflagRegularMemory tflag = 1 << 3
309 )
310
311
312
313
314
315 type rtype struct {
316 size uintptr
317 ptrdata uintptr
318 hash uint32
319 tflag tflag
320 align uint8
321 fieldAlign uint8
322 kind uint8
323
324
325 equal func(unsafe.Pointer, unsafe.Pointer) bool
326 gcdata *byte
327 str nameOff
328 ptrToThis typeOff
329 }
330
331
332 type method struct {
333 name nameOff
334 mtyp typeOff
335 ifn textOff
336 tfn textOff
337 }
338
339
340
341
342
343 type uncommonType struct {
344 pkgPath nameOff
345 mcount uint16
346 xcount uint16
347 moff uint32
348 _ uint32
349 }
350
351
352 type ChanDir int
353
354 const (
355 RecvDir ChanDir = 1 << iota
356 SendDir
357 BothDir = RecvDir | SendDir
358 )
359
360
361 type arrayType struct {
362 rtype
363 elem *rtype
364 slice *rtype
365 len uintptr
366 }
367
368
369 type chanType struct {
370 rtype
371 elem *rtype
372 dir uintptr
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 type funcType struct {
387 rtype
388 inCount uint16
389 outCount uint16
390 }
391
392
393 type imethod struct {
394 name nameOff
395 typ typeOff
396 }
397
398
399 type interfaceType struct {
400 rtype
401 pkgPath name
402 methods []imethod
403 }
404
405
406 type mapType struct {
407 rtype
408 key *rtype
409 elem *rtype
410 bucket *rtype
411
412 hasher func(unsafe.Pointer, uintptr) uintptr
413 keysize uint8
414 valuesize uint8
415 bucketsize uint16
416 flags uint32
417 }
418
419
420 type ptrType struct {
421 rtype
422 elem *rtype
423 }
424
425
426 type sliceType struct {
427 rtype
428 elem *rtype
429 }
430
431
432 type structField struct {
433 name name
434 typ *rtype
435 offsetEmbed uintptr
436 }
437
438 func (f *structField) offset() uintptr {
439 return f.offsetEmbed >> 1
440 }
441
442 func (f *structField) embedded() bool {
443 return f.offsetEmbed&1 != 0
444 }
445
446
447 type structType struct {
448 rtype
449 pkgPath name
450 fields []structField
451 }
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 type name struct {
481 bytes *byte
482 }
483
484 func (n name) data(off int, whySafe string) *byte {
485 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off), whySafe))
486 }
487
488 func (n name) isExported() bool {
489 return (*n.bytes)&(1<<0) != 0
490 }
491
492 func (n name) hasTag() bool {
493 return (*n.bytes)&(1<<1) != 0
494 }
495
496
497
498 func (n name) readVarint(off int) (int, int) {
499 v := 0
500 for i := 0; ; i++ {
501 x := *n.data(off+i, "read varint")
502 v += int(x&0x7f) << (7 * i)
503 if x&0x80 == 0 {
504 return i + 1, v
505 }
506 }
507 }
508
509
510
511
512 func writeVarint(buf []byte, n int) int {
513 for i := 0; ; i++ {
514 b := byte(n & 0x7f)
515 n >>= 7
516 if n == 0 {
517 buf[i] = b
518 return i + 1
519 }
520 buf[i] = b | 0x80
521 }
522 }
523
524 func (n name) name() (s string) {
525 if n.bytes == nil {
526 return
527 }
528 i, l := n.readVarint(1)
529 hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
530 hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string"))
531 hdr.Len = l
532 return
533 }
534
535 func (n name) tag() (s string) {
536 if !n.hasTag() {
537 return ""
538 }
539 i, l := n.readVarint(1)
540 i2, l2 := n.readVarint(1 + i + l)
541 hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
542 hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string"))
543 hdr.Len = l2
544 return
545 }
546
547 func (n name) pkgPath() string {
548 if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 {
549 return ""
550 }
551 i, l := n.readVarint(1)
552 off := 1 + i + l
553 if n.hasTag() {
554 i2, l2 := n.readVarint(off)
555 off += i2 + l2
556 }
557 var nameOff int32
558
559
560 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off, "name offset field")))[:])
561 pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))}
562 return pkgPathName.name()
563 }
564
565 func newName(n, tag string, exported bool) name {
566 if len(n) >= 1<<29 {
567 panic("reflect.nameFrom: name too long: " + n[:1024] + "...")
568 }
569 if len(tag) >= 1<<29 {
570 panic("reflect.nameFrom: tag too long: " + tag[:1024] + "...")
571 }
572 var nameLen [10]byte
573 var tagLen [10]byte
574 nameLenLen := writeVarint(nameLen[:], len(n))
575 tagLenLen := writeVarint(tagLen[:], len(tag))
576
577 var bits byte
578 l := 1 + nameLenLen + len(n)
579 if exported {
580 bits |= 1 << 0
581 }
582 if len(tag) > 0 {
583 l += tagLenLen + len(tag)
584 bits |= 1 << 1
585 }
586
587 b := make([]byte, l)
588 b[0] = bits
589 copy(b[1:], nameLen[:nameLenLen])
590 copy(b[1+nameLenLen:], n)
591 if len(tag) > 0 {
592 tb := b[1+nameLenLen+len(n):]
593 copy(tb, tagLen[:tagLenLen])
594 copy(tb[tagLenLen:], tag)
595 }
596
597 return name{bytes: &b[0]}
598 }
599
600
604
605
606 type Method struct {
607
608 Name string
609
610
611
612
613
614
615 PkgPath string
616
617 Type Type
618 Func Value
619 Index int
620 }
621
622
623 func (m Method) IsExported() bool {
624 return m.PkgPath == ""
625 }
626
627 const (
628 kindDirectIface = 1 << 5
629 kindGCProg = 1 << 6
630 kindMask = (1 << 5) - 1
631 )
632
633
634 func (k Kind) String() string {
635 if int(k) < len(kindNames) {
636 return kindNames[k]
637 }
638 return "kind" + strconv.Itoa(int(k))
639 }
640
641 var kindNames = []string{
642 Invalid: "invalid",
643 Bool: "bool",
644 Int: "int",
645 Int8: "int8",
646 Int16: "int16",
647 Int32: "int32",
648 Int64: "int64",
649 Uint: "uint",
650 Uint8: "uint8",
651 Uint16: "uint16",
652 Uint32: "uint32",
653 Uint64: "uint64",
654 Uintptr: "uintptr",
655 Float32: "float32",
656 Float64: "float64",
657 Complex64: "complex64",
658 Complex128: "complex128",
659 Array: "array",
660 Chan: "chan",
661 Func: "func",
662 Interface: "interface",
663 Map: "map",
664 Pointer: "ptr",
665 Slice: "slice",
666 String: "string",
667 Struct: "struct",
668 UnsafePointer: "unsafe.Pointer",
669 }
670
671 func (t *uncommonType) methods() []method {
672 if t.mcount == 0 {
673 return nil
674 }
675 return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.mcount > 0"))[:t.mcount:t.mcount]
676 }
677
678 func (t *uncommonType) exportedMethods() []method {
679 if t.xcount == 0 {
680 return nil
681 }
682 return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.xcount > 0"))[:t.xcount:t.xcount]
683 }
684
685
686
687
688 func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer
689
690
691
692
693 func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
694
695
696
697
698 func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
699
700
701
702
703 func addReflectOff(ptr unsafe.Pointer) int32
704
705
706
707 func resolveReflectName(n name) nameOff {
708 return nameOff(addReflectOff(unsafe.Pointer(n.bytes)))
709 }
710
711
712
713 func resolveReflectType(t *rtype) typeOff {
714 return typeOff(addReflectOff(unsafe.Pointer(t)))
715 }
716
717
718
719
720 func resolveReflectText(ptr unsafe.Pointer) textOff {
721 return textOff(addReflectOff(ptr))
722 }
723
724 type nameOff int32
725 type typeOff int32
726 type textOff int32
727
728 func (t *rtype) nameOff(off nameOff) name {
729 return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
730 }
731
732 func (t *rtype) typeOff(off typeOff) *rtype {
733 return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off)))
734 }
735
736 func (t *rtype) textOff(off textOff) unsafe.Pointer {
737 return resolveTextOff(unsafe.Pointer(t), int32(off))
738 }
739
740 func (t *rtype) uncommon() *uncommonType {
741 if t.tflag&tflagUncommon == 0 {
742 return nil
743 }
744 switch t.Kind() {
745 case Struct:
746 return &(*structTypeUncommon)(unsafe.Pointer(t)).u
747 case Pointer:
748 type u struct {
749 ptrType
750 u uncommonType
751 }
752 return &(*u)(unsafe.Pointer(t)).u
753 case Func:
754 type u struct {
755 funcType
756 u uncommonType
757 }
758 return &(*u)(unsafe.Pointer(t)).u
759 case Slice:
760 type u struct {
761 sliceType
762 u uncommonType
763 }
764 return &(*u)(unsafe.Pointer(t)).u
765 case Array:
766 type u struct {
767 arrayType
768 u uncommonType
769 }
770 return &(*u)(unsafe.Pointer(t)).u
771 case Chan:
772 type u struct {
773 chanType
774 u uncommonType
775 }
776 return &(*u)(unsafe.Pointer(t)).u
777 case Map:
778 type u struct {
779 mapType
780 u uncommonType
781 }
782 return &(*u)(unsafe.Pointer(t)).u
783 case Interface:
784 type u struct {
785 interfaceType
786 u uncommonType
787 }
788 return &(*u)(unsafe.Pointer(t)).u
789 default:
790 type u struct {
791 rtype
792 u uncommonType
793 }
794 return &(*u)(unsafe.Pointer(t)).u
795 }
796 }
797
798 func (t *rtype) String() string {
799 s := t.nameOff(t.str).name()
800 if t.tflag&tflagExtraStar != 0 {
801 return s[1:]
802 }
803 return s
804 }
805
806 func (t *rtype) Size() uintptr { return t.size }
807
808 func (t *rtype) Bits() int {
809 if t == nil {
810 panic("reflect: Bits of nil Type")
811 }
812 k := t.Kind()
813 if k < Int || k > Complex128 {
814 panic("reflect: Bits of non-arithmetic Type " + t.String())
815 }
816 return int(t.size) * 8
817 }
818
819 func (t *rtype) Align() int { return int(t.align) }
820
821 func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
822
823 func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
824
825 func (t *rtype) pointers() bool { return t.ptrdata != 0 }
826
827 func (t *rtype) common() *rtype { return t }
828
829 func (t *rtype) exportedMethods() []method {
830 ut := t.uncommon()
831 if ut == nil {
832 return nil
833 }
834 return ut.exportedMethods()
835 }
836
837 func (t *rtype) NumMethod() int {
838 if t.Kind() == Interface {
839 tt := (*interfaceType)(unsafe.Pointer(t))
840 return tt.NumMethod()
841 }
842 return len(t.exportedMethods())
843 }
844
845 func (t *rtype) Method(i int) (m Method) {
846 if t.Kind() == Interface {
847 tt := (*interfaceType)(unsafe.Pointer(t))
848 return tt.Method(i)
849 }
850 methods := t.exportedMethods()
851 if i < 0 || i >= len(methods) {
852 panic("reflect: Method index out of range")
853 }
854 p := methods[i]
855 pname := t.nameOff(p.name)
856 m.Name = pname.name()
857 fl := flag(Func)
858 mtyp := t.typeOff(p.mtyp)
859 ft := (*funcType)(unsafe.Pointer(mtyp))
860 in := make([]Type, 0, 1+len(ft.in()))
861 in = append(in, t)
862 for _, arg := range ft.in() {
863 in = append(in, arg)
864 }
865 out := make([]Type, 0, len(ft.out()))
866 for _, ret := range ft.out() {
867 out = append(out, ret)
868 }
869 mt := FuncOf(in, out, ft.IsVariadic())
870 m.Type = mt
871 tfn := t.textOff(p.tfn)
872 fn := unsafe.Pointer(&tfn)
873 m.Func = Value{mt.(*rtype), fn, fl}
874
875 m.Index = i
876 return m
877 }
878
879 func (t *rtype) MethodByName(name string) (m Method, ok bool) {
880 if t.Kind() == Interface {
881 tt := (*interfaceType)(unsafe.Pointer(t))
882 return tt.MethodByName(name)
883 }
884 ut := t.uncommon()
885 if ut == nil {
886 return Method{}, false
887 }
888
889 for i, p := range ut.exportedMethods() {
890 if t.nameOff(p.name).name() == name {
891 return t.Method(i), true
892 }
893 }
894 return Method{}, false
895 }
896
897 func (t *rtype) PkgPath() string {
898 if t.tflag&tflagNamed == 0 {
899 return ""
900 }
901 ut := t.uncommon()
902 if ut == nil {
903 return ""
904 }
905 return t.nameOff(ut.pkgPath).name()
906 }
907
908 func (t *rtype) hasName() bool {
909 return t.tflag&tflagNamed != 0
910 }
911
912 func (t *rtype) Name() string {
913 if !t.hasName() {
914 return ""
915 }
916 s := t.String()
917 i := len(s) - 1
918 sqBrackets := 0
919 for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
920 switch s[i] {
921 case ']':
922 sqBrackets++
923 case '[':
924 sqBrackets--
925 }
926 i--
927 }
928 return s[i+1:]
929 }
930
931 func (t *rtype) ChanDir() ChanDir {
932 if t.Kind() != Chan {
933 panic("reflect: ChanDir of non-chan type " + t.String())
934 }
935 tt := (*chanType)(unsafe.Pointer(t))
936 return ChanDir(tt.dir)
937 }
938
939 func (t *rtype) IsVariadic() bool {
940 if t.Kind() != Func {
941 panic("reflect: IsVariadic of non-func type " + t.String())
942 }
943 tt := (*funcType)(unsafe.Pointer(t))
944 return tt.outCount&(1<<15) != 0
945 }
946
947 func (t *rtype) Elem() Type {
948 switch t.Kind() {
949 case Array:
950 tt := (*arrayType)(unsafe.Pointer(t))
951 return toType(tt.elem)
952 case Chan:
953 tt := (*chanType)(unsafe.Pointer(t))
954 return toType(tt.elem)
955 case Map:
956 tt := (*mapType)(unsafe.Pointer(t))
957 return toType(tt.elem)
958 case Pointer:
959 tt := (*ptrType)(unsafe.Pointer(t))
960 return toType(tt.elem)
961 case Slice:
962 tt := (*sliceType)(unsafe.Pointer(t))
963 return toType(tt.elem)
964 }
965 panic("reflect: Elem of invalid type " + t.String())
966 }
967
968 func (t *rtype) Field(i int) StructField {
969 if t.Kind() != Struct {
970 panic("reflect: Field of non-struct type " + t.String())
971 }
972 tt := (*structType)(unsafe.Pointer(t))
973 return tt.Field(i)
974 }
975
976 func (t *rtype) FieldByIndex(index []int) StructField {
977 if t.Kind() != Struct {
978 panic("reflect: FieldByIndex of non-struct type " + t.String())
979 }
980 tt := (*structType)(unsafe.Pointer(t))
981 return tt.FieldByIndex(index)
982 }
983
984 func (t *rtype) FieldByName(name string) (StructField, bool) {
985 if t.Kind() != Struct {
986 panic("reflect: FieldByName of non-struct type " + t.String())
987 }
988 tt := (*structType)(unsafe.Pointer(t))
989 return tt.FieldByName(name)
990 }
991
992 func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) {
993 if t.Kind() != Struct {
994 panic("reflect: FieldByNameFunc of non-struct type " + t.String())
995 }
996 tt := (*structType)(unsafe.Pointer(t))
997 return tt.FieldByNameFunc(match)
998 }
999
1000 func (t *rtype) In(i int) Type {
1001 if t.Kind() != Func {
1002 panic("reflect: In of non-func type " + t.String())
1003 }
1004 tt := (*funcType)(unsafe.Pointer(t))
1005 return toType(tt.in()[i])
1006 }
1007
1008 func (t *rtype) Key() Type {
1009 if t.Kind() != Map {
1010 panic("reflect: Key of non-map type " + t.String())
1011 }
1012 tt := (*mapType)(unsafe.Pointer(t))
1013 return toType(tt.key)
1014 }
1015
1016 func (t *rtype) Len() int {
1017 if t.Kind() != Array {
1018 panic("reflect: Len of non-array type " + t.String())
1019 }
1020 tt := (*arrayType)(unsafe.Pointer(t))
1021 return int(tt.len)
1022 }
1023
1024 func (t *rtype) NumField() int {
1025 if t.Kind() != Struct {
1026 panic("reflect: NumField of non-struct type " + t.String())
1027 }
1028 tt := (*structType)(unsafe.Pointer(t))
1029 return len(tt.fields)
1030 }
1031
1032 func (t *rtype) NumIn() int {
1033 if t.Kind() != Func {
1034 panic("reflect: NumIn of non-func type " + t.String())
1035 }
1036 tt := (*funcType)(unsafe.Pointer(t))
1037 return int(tt.inCount)
1038 }
1039
1040 func (t *rtype) NumOut() int {
1041 if t.Kind() != Func {
1042 panic("reflect: NumOut of non-func type " + t.String())
1043 }
1044 tt := (*funcType)(unsafe.Pointer(t))
1045 return len(tt.out())
1046 }
1047
1048 func (t *rtype) Out(i int) Type {
1049 if t.Kind() != Func {
1050 panic("reflect: Out of non-func type " + t.String())
1051 }
1052 tt := (*funcType)(unsafe.Pointer(t))
1053 return toType(tt.out()[i])
1054 }
1055
1056 func (t *funcType) in() []*rtype {
1057 uadd := unsafe.Sizeof(*t)
1058 if t.tflag&tflagUncommon != 0 {
1059 uadd += unsafe.Sizeof(uncommonType{})
1060 }
1061 if t.inCount == 0 {
1062 return nil
1063 }
1064 return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.inCount:t.inCount]
1065 }
1066
1067 func (t *funcType) out() []*rtype {
1068 uadd := unsafe.Sizeof(*t)
1069 if t.tflag&tflagUncommon != 0 {
1070 uadd += unsafe.Sizeof(uncommonType{})
1071 }
1072 outCount := t.outCount & (1<<15 - 1)
1073 if outCount == 0 {
1074 return nil
1075 }
1076 return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "outCount > 0"))[t.inCount : t.inCount+outCount : t.inCount+outCount]
1077 }
1078
1079
1080
1081
1082
1083
1084
1085
1086 func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
1087 return unsafe.Pointer(uintptr(p) + x)
1088 }
1089
1090 func (d ChanDir) String() string {
1091 switch d {
1092 case SendDir:
1093 return "chan<-"
1094 case RecvDir:
1095 return "<-chan"
1096 case BothDir:
1097 return "chan"
1098 }
1099 return "ChanDir" + strconv.Itoa(int(d))
1100 }
1101
1102
1103 func (t *interfaceType) Method(i int) (m Method) {
1104 if i < 0 || i >= len(t.methods) {
1105 return
1106 }
1107 p := &t.methods[i]
1108 pname := t.nameOff(p.name)
1109 m.Name = pname.name()
1110 if !pname.isExported() {
1111 m.PkgPath = pname.pkgPath()
1112 if m.PkgPath == "" {
1113 m.PkgPath = t.pkgPath.name()
1114 }
1115 }
1116 m.Type = toType(t.typeOff(p.typ))
1117 m.Index = i
1118 return
1119 }
1120
1121
1122 func (t *interfaceType) NumMethod() int { return len(t.methods) }
1123
1124
1125 func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
1126 if t == nil {
1127 return
1128 }
1129 var p *imethod
1130 for i := range t.methods {
1131 p = &t.methods[i]
1132 if t.nameOff(p.name).name() == name {
1133 return t.Method(i), true
1134 }
1135 }
1136 return
1137 }
1138
1139
1140 type StructField struct {
1141
1142 Name string
1143
1144
1145
1146
1147 PkgPath string
1148
1149 Type Type
1150 Tag StructTag
1151 Offset uintptr
1152 Index []int
1153 Anonymous bool
1154 }
1155
1156
1157 func (f StructField) IsExported() bool {
1158 return f.PkgPath == ""
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169 type StructTag string
1170
1171
1172
1173
1174
1175
1176 func (tag StructTag) Get(key string) string {
1177 v, _ := tag.Lookup(key)
1178 return v
1179 }
1180
1181
1182
1183
1184
1185
1186
1187 func (tag StructTag) Lookup(key string) (value string, ok bool) {
1188
1189
1190
1191 for tag != "" {
1192
1193 i := 0
1194 for i < len(tag) && tag[i] == ' ' {
1195 i++
1196 }
1197 tag = tag[i:]
1198 if tag == "" {
1199 break
1200 }
1201
1202
1203
1204
1205
1206 i = 0
1207 for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
1208 i++
1209 }
1210 if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
1211 break
1212 }
1213 name := string(tag[:i])
1214 tag = tag[i+1:]
1215
1216
1217 i = 1
1218 for i < len(tag) && tag[i] != '"' {
1219 if tag[i] == '\\' {
1220 i++
1221 }
1222 i++
1223 }
1224 if i >= len(tag) {
1225 break
1226 }
1227 qvalue := string(tag[:i+1])
1228 tag = tag[i+1:]
1229
1230 if key == name {
1231 value, err := strconv.Unquote(qvalue)
1232 if err != nil {
1233 break
1234 }
1235 return value, true
1236 }
1237 }
1238 return "", false
1239 }
1240
1241
1242 func (t *structType) Field(i int) (f StructField) {
1243 if i < 0 || i >= len(t.fields) {
1244 panic("reflect: Field index out of bounds")
1245 }
1246 p := &t.fields[i]
1247 f.Type = toType(p.typ)
1248 f.Name = p.name.name()
1249 f.Anonymous = p.embedded()
1250 if !p.name.isExported() {
1251 f.PkgPath = t.pkgPath.name()
1252 }
1253 if tag := p.name.tag(); tag != "" {
1254 f.Tag = StructTag(tag)
1255 }
1256 f.Offset = p.offset()
1257
1258
1259
1260
1261
1262
1263
1264
1265 f.Index = []int{i}
1266 return
1267 }
1268
1269
1270
1271
1272
1273 func (t *structType) FieldByIndex(index []int) (f StructField) {
1274 f.Type = toType(&t.rtype)
1275 for i, x := range index {
1276 if i > 0 {
1277 ft := f.Type
1278 if ft.Kind() == Pointer && ft.Elem().Kind() == Struct {
1279 ft = ft.Elem()
1280 }
1281 f.Type = ft
1282 }
1283 f = f.Type.Field(x)
1284 }
1285 return
1286 }
1287
1288
1289 type fieldScan struct {
1290 typ *structType
1291 index []int
1292 }
1293
1294
1295
1296 func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) {
1297
1298
1299
1300
1301
1302
1303
1304
1305 current := []fieldScan{}
1306 next := []fieldScan{{typ: t}}
1307
1308
1309
1310
1311
1312
1313
1314 var nextCount map[*structType]int
1315
1316
1317
1318
1319
1320
1321 visited := map[*structType]bool{}
1322
1323 for len(next) > 0 {
1324 current, next = next, current[:0]
1325 count := nextCount
1326 nextCount = nil
1327
1328
1329
1330
1331
1332 for _, scan := range current {
1333 t := scan.typ
1334 if visited[t] {
1335
1336
1337
1338 continue
1339 }
1340 visited[t] = true
1341 for i := range t.fields {
1342 f := &t.fields[i]
1343
1344 fname := f.name.name()
1345 var ntyp *rtype
1346 if f.embedded() {
1347
1348 ntyp = f.typ
1349 if ntyp.Kind() == Pointer {
1350 ntyp = ntyp.Elem().common()
1351 }
1352 }
1353
1354
1355 if match(fname) {
1356
1357 if count[t] > 1 || ok {
1358
1359 return StructField{}, false
1360 }
1361 result = t.Field(i)
1362 result.Index = nil
1363 result.Index = append(result.Index, scan.index...)
1364 result.Index = append(result.Index, i)
1365 ok = true
1366 continue
1367 }
1368
1369
1370
1371
1372 if ok || ntyp == nil || ntyp.Kind() != Struct {
1373 continue
1374 }
1375 styp := (*structType)(unsafe.Pointer(ntyp))
1376 if nextCount[styp] > 0 {
1377 nextCount[styp] = 2
1378 continue
1379 }
1380 if nextCount == nil {
1381 nextCount = map[*structType]int{}
1382 }
1383 nextCount[styp] = 1
1384 if count[t] > 1 {
1385 nextCount[styp] = 2
1386 }
1387 var index []int
1388 index = append(index, scan.index...)
1389 index = append(index, i)
1390 next = append(next, fieldScan{styp, index})
1391 }
1392 }
1393 if ok {
1394 break
1395 }
1396 }
1397 return
1398 }
1399
1400
1401
1402 func (t *structType) FieldByName(name string) (f StructField, present bool) {
1403
1404 hasEmbeds := false
1405 if name != "" {
1406 for i := range t.fields {
1407 tf := &t.fields[i]
1408 if tf.name.name() == name {
1409 return t.Field(i), true
1410 }
1411 if tf.embedded() {
1412 hasEmbeds = true
1413 }
1414 }
1415 }
1416 if !hasEmbeds {
1417 return
1418 }
1419 return t.FieldByNameFunc(func(s string) bool { return s == name })
1420 }
1421
1422
1423
1424 func TypeOf(i any) Type {
1425 eface := *(*emptyInterface)(unsafe.Pointer(&i))
1426 return toType(eface.typ)
1427 }
1428
1429
1430 var ptrMap sync.Map
1431
1432
1433
1434
1435
1436
1437 func PtrTo(t Type) Type { return PointerTo(t) }
1438
1439
1440
1441 func PointerTo(t Type) Type {
1442 return t.(*rtype).ptrTo()
1443 }
1444
1445 func (t *rtype) ptrTo() *rtype {
1446 if t.ptrToThis != 0 {
1447 return t.typeOff(t.ptrToThis)
1448 }
1449
1450
1451 if pi, ok := ptrMap.Load(t); ok {
1452 return &pi.(*ptrType).rtype
1453 }
1454
1455
1456 s := "*" + t.String()
1457 for _, tt := range typesByString(s) {
1458 p := (*ptrType)(unsafe.Pointer(tt))
1459 if p.elem != t {
1460 continue
1461 }
1462 pi, _ := ptrMap.LoadOrStore(t, p)
1463 return &pi.(*ptrType).rtype
1464 }
1465
1466
1467
1468 var iptr any = (*unsafe.Pointer)(nil)
1469 prototype := *(**ptrType)(unsafe.Pointer(&iptr))
1470 pp := *prototype
1471
1472 pp.str = resolveReflectName(newName(s, "", false))
1473 pp.ptrToThis = 0
1474
1475
1476
1477
1478
1479
1480 pp.hash = fnv1(t.hash, '*')
1481
1482 pp.elem = t
1483
1484 pi, _ := ptrMap.LoadOrStore(t, &pp)
1485 return &pi.(*ptrType).rtype
1486 }
1487
1488
1489 func fnv1(x uint32, list ...byte) uint32 {
1490 for _, b := range list {
1491 x = x*16777619 ^ uint32(b)
1492 }
1493 return x
1494 }
1495
1496 func (t *rtype) Implements(u Type) bool {
1497 if u == nil {
1498 panic("reflect: nil type passed to Type.Implements")
1499 }
1500 if u.Kind() != Interface {
1501 panic("reflect: non-interface type passed to Type.Implements")
1502 }
1503 return implements(u.(*rtype), t)
1504 }
1505
1506 func (t *rtype) AssignableTo(u Type) bool {
1507 if u == nil {
1508 panic("reflect: nil type passed to Type.AssignableTo")
1509 }
1510 uu := u.(*rtype)
1511 return directlyAssignable(uu, t) || implements(uu, t)
1512 }
1513
1514 func (t *rtype) ConvertibleTo(u Type) bool {
1515 if u == nil {
1516 panic("reflect: nil type passed to Type.ConvertibleTo")
1517 }
1518 uu := u.(*rtype)
1519 return convertOp(uu, t) != nil
1520 }
1521
1522 func (t *rtype) Comparable() bool {
1523 return t.equal != nil
1524 }
1525
1526
1527 func implements(T, V *rtype) bool {
1528 if T.Kind() != Interface {
1529 return false
1530 }
1531 t := (*interfaceType)(unsafe.Pointer(T))
1532 if len(t.methods) == 0 {
1533 return true
1534 }
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548 if V.Kind() == Interface {
1549 v := (*interfaceType)(unsafe.Pointer(V))
1550 i := 0
1551 for j := 0; j < len(v.methods); j++ {
1552 tm := &t.methods[i]
1553 tmName := t.nameOff(tm.name)
1554 vm := &v.methods[j]
1555 vmName := V.nameOff(vm.name)
1556 if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
1557 if !tmName.isExported() {
1558 tmPkgPath := tmName.pkgPath()
1559 if tmPkgPath == "" {
1560 tmPkgPath = t.pkgPath.name()
1561 }
1562 vmPkgPath := vmName.pkgPath()
1563 if vmPkgPath == "" {
1564 vmPkgPath = v.pkgPath.name()
1565 }
1566 if tmPkgPath != vmPkgPath {
1567 continue
1568 }
1569 }
1570 if i++; i >= len(t.methods) {
1571 return true
1572 }
1573 }
1574 }
1575 return false
1576 }
1577
1578 v := V.uncommon()
1579 if v == nil {
1580 return false
1581 }
1582 i := 0
1583 vmethods := v.methods()
1584 for j := 0; j < int(v.mcount); j++ {
1585 tm := &t.methods[i]
1586 tmName := t.nameOff(tm.name)
1587 vm := vmethods[j]
1588 vmName := V.nameOff(vm.name)
1589 if vmName.name() == tmName.name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
1590 if !tmName.isExported() {
1591 tmPkgPath := tmName.pkgPath()
1592 if tmPkgPath == "" {
1593 tmPkgPath = t.pkgPath.name()
1594 }
1595 vmPkgPath := vmName.pkgPath()
1596 if vmPkgPath == "" {
1597 vmPkgPath = V.nameOff(v.pkgPath).name()
1598 }
1599 if tmPkgPath != vmPkgPath {
1600 continue
1601 }
1602 }
1603 if i++; i >= len(t.methods) {
1604 return true
1605 }
1606 }
1607 }
1608 return false
1609 }
1610
1611
1612
1613
1614
1615 func specialChannelAssignability(T, V *rtype) bool {
1616
1617
1618
1619
1620 return V.ChanDir() == BothDir && (T.Name() == "" || V.Name() == "") && haveIdenticalType(T.Elem(), V.Elem(), true)
1621 }
1622
1623
1624
1625
1626
1627
1628 func directlyAssignable(T, V *rtype) bool {
1629
1630 if T == V {
1631 return true
1632 }
1633
1634
1635
1636 if T.hasName() && V.hasName() || T.Kind() != V.Kind() {
1637 return false
1638 }
1639
1640 if T.Kind() == Chan && specialChannelAssignability(T, V) {
1641 return true
1642 }
1643
1644
1645 return haveIdenticalUnderlyingType(T, V, true)
1646 }
1647
1648 func haveIdenticalType(T, V Type, cmpTags bool) bool {
1649 if cmpTags {
1650 return T == V
1651 }
1652
1653 if T.Name() != V.Name() || T.Kind() != V.Kind() || T.PkgPath() != V.PkgPath() {
1654 return false
1655 }
1656
1657 return haveIdenticalUnderlyingType(T.common(), V.common(), false)
1658 }
1659
1660 func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
1661 if T == V {
1662 return true
1663 }
1664
1665 kind := T.Kind()
1666 if kind != V.Kind() {
1667 return false
1668 }
1669
1670
1671
1672 if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
1673 return true
1674 }
1675
1676
1677 switch kind {
1678 case Array:
1679 return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
1680
1681 case Chan:
1682 return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
1683
1684 case Func:
1685 t := (*funcType)(unsafe.Pointer(T))
1686 v := (*funcType)(unsafe.Pointer(V))
1687 if t.outCount != v.outCount || t.inCount != v.inCount {
1688 return false
1689 }
1690 for i := 0; i < t.NumIn(); i++ {
1691 if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
1692 return false
1693 }
1694 }
1695 for i := 0; i < t.NumOut(); i++ {
1696 if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
1697 return false
1698 }
1699 }
1700 return true
1701
1702 case Interface:
1703 t := (*interfaceType)(unsafe.Pointer(T))
1704 v := (*interfaceType)(unsafe.Pointer(V))
1705 if len(t.methods) == 0 && len(v.methods) == 0 {
1706 return true
1707 }
1708
1709
1710 return false
1711
1712 case Map:
1713 return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
1714
1715 case Pointer, Slice:
1716 return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
1717
1718 case Struct:
1719 t := (*structType)(unsafe.Pointer(T))
1720 v := (*structType)(unsafe.Pointer(V))
1721 if len(t.fields) != len(v.fields) {
1722 return false
1723 }
1724 if t.pkgPath.name() != v.pkgPath.name() {
1725 return false
1726 }
1727 for i := range t.fields {
1728 tf := &t.fields[i]
1729 vf := &v.fields[i]
1730 if tf.name.name() != vf.name.name() {
1731 return false
1732 }
1733 if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
1734 return false
1735 }
1736 if cmpTags && tf.name.tag() != vf.name.tag() {
1737 return false
1738 }
1739 if tf.offsetEmbed != vf.offsetEmbed {
1740 return false
1741 }
1742 }
1743 return true
1744 }
1745
1746 return false
1747 }
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768 func typelinks() (sections []unsafe.Pointer, offset [][]int32)
1769
1770 func rtypeOff(section unsafe.Pointer, off int32) *rtype {
1771 return (*rtype)(add(section, uintptr(off), "sizeof(rtype) > 0"))
1772 }
1773
1774
1775
1776
1777
1778 func typesByString(s string) []*rtype {
1779 sections, offset := typelinks()
1780 var ret []*rtype
1781
1782 for offsI, offs := range offset {
1783 section := sections[offsI]
1784
1785
1786
1787 i, j := 0, len(offs)
1788 for i < j {
1789 h := i + (j-i)>>1
1790
1791 if !(rtypeOff(section, offs[h]).String() >= s) {
1792 i = h + 1
1793 } else {
1794 j = h
1795 }
1796 }
1797
1798
1799
1800
1801
1802 for j := i; j < len(offs); j++ {
1803 typ := rtypeOff(section, offs[j])
1804 if typ.String() != s {
1805 break
1806 }
1807 ret = append(ret, typ)
1808 }
1809 }
1810 return ret
1811 }
1812
1813
1814 var lookupCache sync.Map
1815
1816
1817
1818
1819 type cacheKey struct {
1820 kind Kind
1821 t1 *rtype
1822 t2 *rtype
1823 extra uintptr
1824 }
1825
1826
1827
1828
1829 var funcLookupCache struct {
1830 sync.Mutex
1831
1832
1833
1834 m sync.Map
1835 }
1836
1837
1838
1839
1840
1841
1842 func ChanOf(dir ChanDir, t Type) Type {
1843 typ := t.(*rtype)
1844
1845
1846 ckey := cacheKey{Chan, typ, nil, uintptr(dir)}
1847 if ch, ok := lookupCache.Load(ckey); ok {
1848 return ch.(*rtype)
1849 }
1850
1851
1852 if typ.size >= 1<<16 {
1853 panic("reflect.ChanOf: element size too large")
1854 }
1855
1856
1857 var s string
1858 switch dir {
1859 default:
1860 panic("reflect.ChanOf: invalid dir")
1861 case SendDir:
1862 s = "chan<- " + typ.String()
1863 case RecvDir:
1864 s = "<-chan " + typ.String()
1865 case BothDir:
1866 typeStr := typ.String()
1867 if typeStr[0] == '<' {
1868
1869
1870
1871
1872 s = "chan (" + typeStr + ")"
1873 } else {
1874 s = "chan " + typeStr
1875 }
1876 }
1877 for _, tt := range typesByString(s) {
1878 ch := (*chanType)(unsafe.Pointer(tt))
1879 if ch.elem == typ && ch.dir == uintptr(dir) {
1880 ti, _ := lookupCache.LoadOrStore(ckey, tt)
1881 return ti.(Type)
1882 }
1883 }
1884
1885
1886 var ichan any = (chan unsafe.Pointer)(nil)
1887 prototype := *(**chanType)(unsafe.Pointer(&ichan))
1888 ch := *prototype
1889 ch.tflag = tflagRegularMemory
1890 ch.dir = uintptr(dir)
1891 ch.str = resolveReflectName(newName(s, "", false))
1892 ch.hash = fnv1(typ.hash, 'c', byte(dir))
1893 ch.elem = typ
1894
1895 ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
1896 return ti.(Type)
1897 }
1898
1899
1900
1901
1902
1903
1904
1905 func MapOf(key, elem Type) Type {
1906 ktyp := key.(*rtype)
1907 etyp := elem.(*rtype)
1908
1909 if ktyp.equal == nil {
1910 panic("reflect.MapOf: invalid key type " + ktyp.String())
1911 }
1912
1913
1914 ckey := cacheKey{Map, ktyp, etyp, 0}
1915 if mt, ok := lookupCache.Load(ckey); ok {
1916 return mt.(Type)
1917 }
1918
1919
1920 s := "map[" + ktyp.String() + "]" + etyp.String()
1921 for _, tt := range typesByString(s) {
1922 mt := (*mapType)(unsafe.Pointer(tt))
1923 if mt.key == ktyp && mt.elem == etyp {
1924 ti, _ := lookupCache.LoadOrStore(ckey, tt)
1925 return ti.(Type)
1926 }
1927 }
1928
1929
1930
1931
1932 var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
1933 mt := **(**mapType)(unsafe.Pointer(&imap))
1934 mt.str = resolveReflectName(newName(s, "", false))
1935 mt.tflag = 0
1936 mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
1937 mt.key = ktyp
1938 mt.elem = etyp
1939 mt.bucket = bucketOf(ktyp, etyp)
1940 mt.hasher = func(p unsafe.Pointer, seed uintptr) uintptr {
1941 return typehash(ktyp, p, seed)
1942 }
1943 mt.flags = 0
1944 if ktyp.size > maxKeySize {
1945 mt.keysize = uint8(goarch.PtrSize)
1946 mt.flags |= 1
1947 } else {
1948 mt.keysize = uint8(ktyp.size)
1949 }
1950 if etyp.size > maxValSize {
1951 mt.valuesize = uint8(goarch.PtrSize)
1952 mt.flags |= 2
1953 } else {
1954 mt.valuesize = uint8(etyp.size)
1955 }
1956 mt.bucketsize = uint16(mt.bucket.size)
1957 if isReflexive(ktyp) {
1958 mt.flags |= 4
1959 }
1960 if needKeyUpdate(ktyp) {
1961 mt.flags |= 8
1962 }
1963 if hashMightPanic(ktyp) {
1964 mt.flags |= 16
1965 }
1966 mt.ptrToThis = 0
1967
1968 ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
1969 return ti.(Type)
1970 }
1971
1972
1973
1974 type funcTypeFixed4 struct {
1975 funcType
1976 args [4]*rtype
1977 }
1978 type funcTypeFixed8 struct {
1979 funcType
1980 args [8]*rtype
1981 }
1982 type funcTypeFixed16 struct {
1983 funcType
1984 args [16]*rtype
1985 }
1986 type funcTypeFixed32 struct {
1987 funcType
1988 args [32]*rtype
1989 }
1990 type funcTypeFixed64 struct {
1991 funcType
1992 args [64]*rtype
1993 }
1994 type funcTypeFixed128 struct {
1995 funcType
1996 args [128]*rtype
1997 }
1998
1999
2000
2001
2002
2003
2004
2005
2006 func FuncOf(in, out []Type, variadic bool) Type {
2007 if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
2008 panic("reflect.FuncOf: last arg of variadic func must be slice")
2009 }
2010
2011
2012 var ifunc any = (func())(nil)
2013 prototype := *(**funcType)(unsafe.Pointer(&ifunc))
2014 n := len(in) + len(out)
2015
2016 var ft *funcType
2017 var args []*rtype
2018 switch {
2019 case n <= 4:
2020 fixed := new(funcTypeFixed4)
2021 args = fixed.args[:0:len(fixed.args)]
2022 ft = &fixed.funcType
2023 case n <= 8:
2024 fixed := new(funcTypeFixed8)
2025 args = fixed.args[:0:len(fixed.args)]
2026 ft = &fixed.funcType
2027 case n <= 16:
2028 fixed := new(funcTypeFixed16)
2029 args = fixed.args[:0:len(fixed.args)]
2030 ft = &fixed.funcType
2031 case n <= 32:
2032 fixed := new(funcTypeFixed32)
2033 args = fixed.args[:0:len(fixed.args)]
2034 ft = &fixed.funcType
2035 case n <= 64:
2036 fixed := new(funcTypeFixed64)
2037 args = fixed.args[:0:len(fixed.args)]
2038 ft = &fixed.funcType
2039 case n <= 128:
2040 fixed := new(funcTypeFixed128)
2041 args = fixed.args[:0:len(fixed.args)]
2042 ft = &fixed.funcType
2043 default:
2044 panic("reflect.FuncOf: too many arguments")
2045 }
2046 *ft = *prototype
2047
2048
2049 var hash uint32
2050 for _, in := range in {
2051 t := in.(*rtype)
2052 args = append(args, t)
2053 hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
2054 }
2055 if variadic {
2056 hash = fnv1(hash, 'v')
2057 }
2058 hash = fnv1(hash, '.')
2059 for _, out := range out {
2060 t := out.(*rtype)
2061 args = append(args, t)
2062 hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
2063 }
2064 if len(args) > 50 {
2065 panic("reflect.FuncOf does not support more than 50 arguments")
2066 }
2067 ft.tflag = 0
2068 ft.hash = hash
2069 ft.inCount = uint16(len(in))
2070 ft.outCount = uint16(len(out))
2071 if variadic {
2072 ft.outCount |= 1 << 15
2073 }
2074
2075
2076 if ts, ok := funcLookupCache.m.Load(hash); ok {
2077 for _, t := range ts.([]*rtype) {
2078 if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
2079 return t
2080 }
2081 }
2082 }
2083
2084
2085 funcLookupCache.Lock()
2086 defer funcLookupCache.Unlock()
2087 if ts, ok := funcLookupCache.m.Load(hash); ok {
2088 for _, t := range ts.([]*rtype) {
2089 if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
2090 return t
2091 }
2092 }
2093 }
2094
2095 addToCache := func(tt *rtype) Type {
2096 var rts []*rtype
2097 if rti, ok := funcLookupCache.m.Load(hash); ok {
2098 rts = rti.([]*rtype)
2099 }
2100 funcLookupCache.m.Store(hash, append(rts, tt))
2101 return tt
2102 }
2103
2104
2105 str := funcStr(ft)
2106 for _, tt := range typesByString(str) {
2107 if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
2108 return addToCache(tt)
2109 }
2110 }
2111
2112
2113 ft.str = resolveReflectName(newName(str, "", false))
2114 ft.ptrToThis = 0
2115 return addToCache(&ft.rtype)
2116 }
2117
2118
2119 func funcStr(ft *funcType) string {
2120 repr := make([]byte, 0, 64)
2121 repr = append(repr, "func("...)
2122 for i, t := range ft.in() {
2123 if i > 0 {
2124 repr = append(repr, ", "...)
2125 }
2126 if ft.IsVariadic() && i == int(ft.inCount)-1 {
2127 repr = append(repr, "..."...)
2128 repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.String()...)
2129 } else {
2130 repr = append(repr, t.String()...)
2131 }
2132 }
2133 repr = append(repr, ')')
2134 out := ft.out()
2135 if len(out) == 1 {
2136 repr = append(repr, ' ')
2137 } else if len(out) > 1 {
2138 repr = append(repr, " ("...)
2139 }
2140 for i, t := range out {
2141 if i > 0 {
2142 repr = append(repr, ", "...)
2143 }
2144 repr = append(repr, t.String()...)
2145 }
2146 if len(out) > 1 {
2147 repr = append(repr, ')')
2148 }
2149 return string(repr)
2150 }
2151
2152
2153
2154 func isReflexive(t *rtype) bool {
2155 switch t.Kind() {
2156 case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer:
2157 return true
2158 case Float32, Float64, Complex64, Complex128, Interface:
2159 return false
2160 case Array:
2161 tt := (*arrayType)(unsafe.Pointer(t))
2162 return isReflexive(tt.elem)
2163 case Struct:
2164 tt := (*structType)(unsafe.Pointer(t))
2165 for _, f := range tt.fields {
2166 if !isReflexive(f.typ) {
2167 return false
2168 }
2169 }
2170 return true
2171 default:
2172
2173 panic("isReflexive called on non-key type " + t.String())
2174 }
2175 }
2176
2177
2178 func needKeyUpdate(t *rtype) bool {
2179 switch t.Kind() {
2180 case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer:
2181 return false
2182 case Float32, Float64, Complex64, Complex128, Interface, String:
2183
2184
2185
2186 return true
2187 case Array:
2188 tt := (*arrayType)(unsafe.Pointer(t))
2189 return needKeyUpdate(tt.elem)
2190 case Struct:
2191 tt := (*structType)(unsafe.Pointer(t))
2192 for _, f := range tt.fields {
2193 if needKeyUpdate(f.typ) {
2194 return true
2195 }
2196 }
2197 return false
2198 default:
2199
2200 panic("needKeyUpdate called on non-key type " + t.String())
2201 }
2202 }
2203
2204
2205 func hashMightPanic(t *rtype) bool {
2206 switch t.Kind() {
2207 case Interface:
2208 return true
2209 case Array:
2210 tt := (*arrayType)(unsafe.Pointer(t))
2211 return hashMightPanic(tt.elem)
2212 case Struct:
2213 tt := (*structType)(unsafe.Pointer(t))
2214 for _, f := range tt.fields {
2215 if hashMightPanic(f.typ) {
2216 return true
2217 }
2218 }
2219 return false
2220 default:
2221 return false
2222 }
2223 }
2224
2225
2226
2227
2228
2229 const (
2230 bucketSize uintptr = 8
2231 maxKeySize uintptr = 128
2232 maxValSize uintptr = 128
2233 )
2234
2235 func bucketOf(ktyp, etyp *rtype) *rtype {
2236 if ktyp.size > maxKeySize {
2237 ktyp = PointerTo(ktyp).(*rtype)
2238 }
2239 if etyp.size > maxValSize {
2240 etyp = PointerTo(etyp).(*rtype)
2241 }
2242
2243
2244
2245
2246
2247
2248 var gcdata *byte
2249 var ptrdata uintptr
2250 var overflowPad uintptr
2251
2252 size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + goarch.PtrSize
2253 if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
2254 panic("reflect: bad size computation in MapOf")
2255 }
2256
2257 if ktyp.ptrdata != 0 || etyp.ptrdata != 0 {
2258 nptr := (bucketSize*(1+ktyp.size+etyp.size) + goarch.PtrSize) / goarch.PtrSize
2259 mask := make([]byte, (nptr+7)/8)
2260 base := bucketSize / goarch.PtrSize
2261
2262 if ktyp.ptrdata != 0 {
2263 emitGCMask(mask, base, ktyp, bucketSize)
2264 }
2265 base += bucketSize * ktyp.size / goarch.PtrSize
2266
2267 if etyp.ptrdata != 0 {
2268 emitGCMask(mask, base, etyp, bucketSize)
2269 }
2270 base += bucketSize * etyp.size / goarch.PtrSize
2271 base += overflowPad / goarch.PtrSize
2272
2273 word := base
2274 mask[word/8] |= 1 << (word % 8)
2275 gcdata = &mask[0]
2276 ptrdata = (word + 1) * goarch.PtrSize
2277
2278
2279 if ptrdata != size {
2280 panic("reflect: bad layout computation in MapOf")
2281 }
2282 }
2283
2284 b := &rtype{
2285 align: goarch.PtrSize,
2286 size: size,
2287 kind: uint8(Struct),
2288 ptrdata: ptrdata,
2289 gcdata: gcdata,
2290 }
2291 if overflowPad > 0 {
2292 b.align = 8
2293 }
2294 s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
2295 b.str = resolveReflectName(newName(s, "", false))
2296 return b
2297 }
2298
2299 func (t *rtype) gcSlice(begin, end uintptr) []byte {
2300 return (*[1 << 30]byte)(unsafe.Pointer(t.gcdata))[begin:end:end]
2301 }
2302
2303
2304
2305 func emitGCMask(out []byte, base uintptr, typ *rtype, n uintptr) {
2306 if typ.kind&kindGCProg != 0 {
2307 panic("reflect: unexpected GC program")
2308 }
2309 ptrs := typ.ptrdata / goarch.PtrSize
2310 words := typ.size / goarch.PtrSize
2311 mask := typ.gcSlice(0, (ptrs+7)/8)
2312 for j := uintptr(0); j < ptrs; j++ {
2313 if (mask[j/8]>>(j%8))&1 != 0 {
2314 for i := uintptr(0); i < n; i++ {
2315 k := base + i*words + j
2316 out[k/8] |= 1 << (k % 8)
2317 }
2318 }
2319 }
2320 }
2321
2322
2323
2324 func appendGCProg(dst []byte, typ *rtype) []byte {
2325 if typ.kind&kindGCProg != 0 {
2326
2327 n := uintptr(*(*uint32)(unsafe.Pointer(typ.gcdata)))
2328 prog := typ.gcSlice(4, 4+n-1)
2329 return append(dst, prog...)
2330 }
2331
2332
2333 ptrs := typ.ptrdata / goarch.PtrSize
2334 mask := typ.gcSlice(0, (ptrs+7)/8)
2335
2336
2337 for ; ptrs > 120; ptrs -= 120 {
2338 dst = append(dst, 120)
2339 dst = append(dst, mask[:15]...)
2340 mask = mask[15:]
2341 }
2342
2343 dst = append(dst, byte(ptrs))
2344 dst = append(dst, mask...)
2345 return dst
2346 }
2347
2348
2349
2350 func SliceOf(t Type) Type {
2351 typ := t.(*rtype)
2352
2353
2354 ckey := cacheKey{Slice, typ, nil, 0}
2355 if slice, ok := lookupCache.Load(ckey); ok {
2356 return slice.(Type)
2357 }
2358
2359
2360 s := "[]" + typ.String()
2361 for _, tt := range typesByString(s) {
2362 slice := (*sliceType)(unsafe.Pointer(tt))
2363 if slice.elem == typ {
2364 ti, _ := lookupCache.LoadOrStore(ckey, tt)
2365 return ti.(Type)
2366 }
2367 }
2368
2369
2370 var islice any = ([]unsafe.Pointer)(nil)
2371 prototype := *(**sliceType)(unsafe.Pointer(&islice))
2372 slice := *prototype
2373 slice.tflag = 0
2374 slice.str = resolveReflectName(newName(s, "", false))
2375 slice.hash = fnv1(typ.hash, '[')
2376 slice.elem = typ
2377 slice.ptrToThis = 0
2378
2379 ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
2380 return ti.(Type)
2381 }
2382
2383
2384
2385
2386 var structLookupCache struct {
2387 sync.Mutex
2388
2389
2390
2391 m sync.Map
2392 }
2393
2394 type structTypeUncommon struct {
2395 structType
2396 u uncommonType
2397 }
2398
2399
2400 func isLetter(ch rune) bool {
2401 return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
2402 }
2403
2404
2405
2406
2407
2408
2409
2410 func isValidFieldName(fieldName string) bool {
2411 for i, c := range fieldName {
2412 if i == 0 && !isLetter(c) {
2413 return false
2414 }
2415
2416 if !(isLetter(c) || unicode.IsDigit(c)) {
2417 return false
2418 }
2419 }
2420
2421 return len(fieldName) > 0
2422 }
2423
2424
2425
2426
2427
2428
2429
2430
2431 func StructOf(fields []StructField) Type {
2432 var (
2433 hash = fnv1(0, []byte("struct {")...)
2434 size uintptr
2435 typalign uint8
2436 comparable = true
2437 methods []method
2438
2439 fs = make([]structField, len(fields))
2440 repr = make([]byte, 0, 64)
2441 fset = map[string]struct{}{}
2442
2443 hasGCProg = false
2444 )
2445
2446 lastzero := uintptr(0)
2447 repr = append(repr, "struct {"...)
2448 pkgpath := ""
2449 for i, field := range fields {
2450 if field.Name == "" {
2451 panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
2452 }
2453 if !isValidFieldName(field.Name) {
2454 panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name")
2455 }
2456 if field.Type == nil {
2457 panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
2458 }
2459 f, fpkgpath := runtimeStructField(field)
2460 ft := f.typ
2461 if ft.kind&kindGCProg != 0 {
2462 hasGCProg = true
2463 }
2464 if fpkgpath != "" {
2465 if pkgpath == "" {
2466 pkgpath = fpkgpath
2467 } else if pkgpath != fpkgpath {
2468 panic("reflect.Struct: fields with different PkgPath " + pkgpath + " and " + fpkgpath)
2469 }
2470 }
2471
2472
2473 name := f.name.name()
2474 hash = fnv1(hash, []byte(name)...)
2475 repr = append(repr, (" " + name)...)
2476 if f.embedded() {
2477
2478 if f.typ.Kind() == Pointer {
2479
2480 elem := ft.Elem()
2481 if k := elem.Kind(); k == Pointer || k == Interface {
2482 panic("reflect.StructOf: illegal embedded field type " + ft.String())
2483 }
2484 }
2485
2486 switch f.typ.Kind() {
2487 case Interface:
2488 ift := (*interfaceType)(unsafe.Pointer(ft))
2489 for im, m := range ift.methods {
2490 if ift.nameOff(m.name).pkgPath() != "" {
2491
2492 panic("reflect: embedded interface with unexported method(s) not implemented")
2493 }
2494
2495 var (
2496 mtyp = ift.typeOff(m.typ)
2497 ifield = i
2498 imethod = im
2499 ifn Value
2500 tfn Value
2501 )
2502
2503 if ft.kind&kindDirectIface != 0 {
2504 tfn = MakeFunc(mtyp, func(in []Value) []Value {
2505 var args []Value
2506 var recv = in[0]
2507 if len(in) > 1 {
2508 args = in[1:]
2509 }
2510 return recv.Field(ifield).Method(imethod).Call(args)
2511 })
2512 ifn = MakeFunc(mtyp, func(in []Value) []Value {
2513 var args []Value
2514 var recv = in[0]
2515 if len(in) > 1 {
2516 args = in[1:]
2517 }
2518 return recv.Field(ifield).Method(imethod).Call(args)
2519 })
2520 } else {
2521 tfn = MakeFunc(mtyp, func(in []Value) []Value {
2522 var args []Value
2523 var recv = in[0]
2524 if len(in) > 1 {
2525 args = in[1:]
2526 }
2527 return recv.Field(ifield).Method(imethod).Call(args)
2528 })
2529 ifn = MakeFunc(mtyp, func(in []Value) []Value {
2530 var args []Value
2531 var recv = Indirect(in[0])
2532 if len(in) > 1 {
2533 args = in[1:]
2534 }
2535 return recv.Field(ifield).Method(imethod).Call(args)
2536 })
2537 }
2538
2539 methods = append(methods, method{
2540 name: resolveReflectName(ift.nameOff(m.name)),
2541 mtyp: resolveReflectType(mtyp),
2542 ifn: resolveReflectText(unsafe.Pointer(&ifn)),
2543 tfn: resolveReflectText(unsafe.Pointer(&tfn)),
2544 })
2545 }
2546 case Pointer:
2547 ptr := (*ptrType)(unsafe.Pointer(ft))
2548 if unt := ptr.uncommon(); unt != nil {
2549 if i > 0 && unt.mcount > 0 {
2550
2551 panic("reflect: embedded type with methods not implemented if type is not first field")
2552 }
2553 if len(fields) > 1 {
2554 panic("reflect: embedded type with methods not implemented if there is more than one field")
2555 }
2556 for _, m := range unt.methods() {
2557 mname := ptr.nameOff(m.name)
2558 if mname.pkgPath() != "" {
2559
2560
2561 panic("reflect: embedded interface with unexported method(s) not implemented")
2562 }
2563 methods = append(methods, method{
2564 name: resolveReflectName(mname),
2565 mtyp: resolveReflectType(ptr.typeOff(m.mtyp)),
2566 ifn: resolveReflectText(ptr.textOff(m.ifn)),
2567 tfn: resolveReflectText(ptr.textOff(m.tfn)),
2568 })
2569 }
2570 }
2571 if unt := ptr.elem.uncommon(); unt != nil {
2572 for _, m := range unt.methods() {
2573 mname := ptr.nameOff(m.name)
2574 if mname.pkgPath() != "" {
2575
2576
2577 panic("reflect: embedded interface with unexported method(s) not implemented")
2578 }
2579 methods = append(methods, method{
2580 name: resolveReflectName(mname),
2581 mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)),
2582 ifn: resolveReflectText(ptr.elem.textOff(m.ifn)),
2583 tfn: resolveReflectText(ptr.elem.textOff(m.tfn)),
2584 })
2585 }
2586 }
2587 default:
2588 if unt := ft.uncommon(); unt != nil {
2589 if i > 0 && unt.mcount > 0 {
2590
2591 panic("reflect: embedded type with methods not implemented if type is not first field")
2592 }
2593 if len(fields) > 1 && ft.kind&kindDirectIface != 0 {
2594 panic("reflect: embedded type with methods not implemented for non-pointer type")
2595 }
2596 for _, m := range unt.methods() {
2597 mname := ft.nameOff(m.name)
2598 if mname.pkgPath() != "" {
2599
2600
2601 panic("reflect: embedded interface with unexported method(s) not implemented")
2602 }
2603 methods = append(methods, method{
2604 name: resolveReflectName(mname),
2605 mtyp: resolveReflectType(ft.typeOff(m.mtyp)),
2606 ifn: resolveReflectText(ft.textOff(m.ifn)),
2607 tfn: resolveReflectText(ft.textOff(m.tfn)),
2608 })
2609
2610 }
2611 }
2612 }
2613 }
2614 if _, dup := fset[name]; dup && name != "_" {
2615 panic("reflect.StructOf: duplicate field " + name)
2616 }
2617 fset[name] = struct{}{}
2618
2619 hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash))
2620
2621 repr = append(repr, (" " + ft.String())...)
2622 if f.name.hasTag() {
2623 hash = fnv1(hash, []byte(f.name.tag())...)
2624 repr = append(repr, (" " + strconv.Quote(f.name.tag()))...)
2625 }
2626 if i < len(fields)-1 {
2627 repr = append(repr, ';')
2628 }
2629
2630 comparable = comparable && (ft.equal != nil)
2631
2632 offset := align(size, uintptr(ft.align))
2633 if ft.align > typalign {
2634 typalign = ft.align
2635 }
2636 size = offset + ft.size
2637 f.offsetEmbed |= offset << 1
2638
2639 if ft.size == 0 {
2640 lastzero = size
2641 }
2642
2643 fs[i] = f
2644 }
2645
2646 if size > 0 && lastzero == size {
2647
2648
2649
2650
2651
2652 size++
2653 }
2654
2655 var typ *structType
2656 var ut *uncommonType
2657
2658 if len(methods) == 0 {
2659 t := new(structTypeUncommon)
2660 typ = &t.structType
2661 ut = &t.u
2662 } else {
2663
2664
2665
2666
2667
2668 tt := New(StructOf([]StructField{
2669 {Name: "S", Type: TypeOf(structType{})},
2670 {Name: "U", Type: TypeOf(uncommonType{})},
2671 {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
2672 }))
2673
2674 typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer())
2675 ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer())
2676
2677 copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods)
2678 }
2679
2680
2681
2682
2683 ut.mcount = uint16(len(methods))
2684 ut.xcount = ut.mcount
2685 ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
2686
2687 if len(fs) > 0 {
2688 repr = append(repr, ' ')
2689 }
2690 repr = append(repr, '}')
2691 hash = fnv1(hash, '}')
2692 str := string(repr)
2693
2694
2695 size = align(size, uintptr(typalign))
2696
2697
2698 var istruct any = struct{}{}
2699 prototype := *(**structType)(unsafe.Pointer(&istruct))
2700 *typ = *prototype
2701 typ.fields = fs
2702 if pkgpath != "" {
2703 typ.pkgPath = newName(pkgpath, "", false)
2704 }
2705
2706
2707 if ts, ok := structLookupCache.m.Load(hash); ok {
2708 for _, st := range ts.([]Type) {
2709 t := st.common()
2710 if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
2711 return t
2712 }
2713 }
2714 }
2715
2716
2717 structLookupCache.Lock()
2718 defer structLookupCache.Unlock()
2719 if ts, ok := structLookupCache.m.Load(hash); ok {
2720 for _, st := range ts.([]Type) {
2721 t := st.common()
2722 if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
2723 return t
2724 }
2725 }
2726 }
2727
2728 addToCache := func(t Type) Type {
2729 var ts []Type
2730 if ti, ok := structLookupCache.m.Load(hash); ok {
2731 ts = ti.([]Type)
2732 }
2733 structLookupCache.m.Store(hash, append(ts, t))
2734 return t
2735 }
2736
2737
2738 for _, t := range typesByString(str) {
2739 if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
2740
2741
2742
2743 return addToCache(t)
2744 }
2745 }
2746
2747 typ.str = resolveReflectName(newName(str, "", false))
2748 typ.tflag = 0
2749 typ.hash = hash
2750 typ.size = size
2751 typ.ptrdata = typeptrdata(typ.common())
2752 typ.align = typalign
2753 typ.fieldAlign = typalign
2754 typ.ptrToThis = 0
2755 if len(methods) > 0 {
2756 typ.tflag |= tflagUncommon
2757 }
2758
2759 if hasGCProg {
2760 lastPtrField := 0
2761 for i, ft := range fs {
2762 if ft.typ.pointers() {
2763 lastPtrField = i
2764 }
2765 }
2766 prog := []byte{0, 0, 0, 0}
2767 var off uintptr
2768 for i, ft := range fs {
2769 if i > lastPtrField {
2770
2771
2772 break
2773 }
2774 if !ft.typ.pointers() {
2775
2776 continue
2777 }
2778
2779 if ft.offset() > off {
2780 n := (ft.offset() - off) / goarch.PtrSize
2781 prog = append(prog, 0x01, 0x00)
2782 if n > 1 {
2783 prog = append(prog, 0x81)
2784 prog = appendVarint(prog, n-1)
2785 }
2786 off = ft.offset()
2787 }
2788
2789 prog = appendGCProg(prog, ft.typ)
2790 off += ft.typ.ptrdata
2791 }
2792 prog = append(prog, 0)
2793 *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
2794 typ.kind |= kindGCProg
2795 typ.gcdata = &prog[0]
2796 } else {
2797 typ.kind &^= kindGCProg
2798 bv := new(bitVector)
2799 addTypeBits(bv, 0, typ.common())
2800 if len(bv.data) > 0 {
2801 typ.gcdata = &bv.data[0]
2802 }
2803 }
2804 typ.equal = nil
2805 if comparable {
2806 typ.equal = func(p, q unsafe.Pointer) bool {
2807 for _, ft := range typ.fields {
2808 pi := add(p, ft.offset(), "&x.field safe")
2809 qi := add(q, ft.offset(), "&x.field safe")
2810 if !ft.typ.equal(pi, qi) {
2811 return false
2812 }
2813 }
2814 return true
2815 }
2816 }
2817
2818 switch {
2819 case len(fs) == 1 && !ifaceIndir(fs[0].typ):
2820
2821 typ.kind |= kindDirectIface
2822 default:
2823 typ.kind &^= kindDirectIface
2824 }
2825
2826 return addToCache(&typ.rtype)
2827 }
2828
2829
2830
2831
2832 func runtimeStructField(field StructField) (structField, string) {
2833 if field.Anonymous && field.PkgPath != "" {
2834 panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set")
2835 }
2836
2837 if field.IsExported() {
2838
2839
2840 c := field.Name[0]
2841 if 'a' <= c && c <= 'z' || c == '_' {
2842 panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
2843 }
2844 }
2845
2846 offsetEmbed := uintptr(0)
2847 if field.Anonymous {
2848 offsetEmbed |= 1
2849 }
2850
2851 resolveReflectType(field.Type.common())
2852 f := structField{
2853 name: newName(field.Name, string(field.Tag), field.IsExported()),
2854 typ: field.Type.common(),
2855 offsetEmbed: offsetEmbed,
2856 }
2857 return f, field.PkgPath
2858 }
2859
2860
2861
2862
2863 func typeptrdata(t *rtype) uintptr {
2864 switch t.Kind() {
2865 case Struct:
2866 st := (*structType)(unsafe.Pointer(t))
2867
2868 field := -1
2869 for i := range st.fields {
2870 ft := st.fields[i].typ
2871 if ft.pointers() {
2872 field = i
2873 }
2874 }
2875 if field == -1 {
2876 return 0
2877 }
2878 f := st.fields[field]
2879 return f.offset() + f.typ.ptrdata
2880
2881 default:
2882 panic("reflect.typeptrdata: unexpected type, " + t.String())
2883 }
2884 }
2885
2886
2887 const maxPtrmaskBytes = 2048
2888
2889
2890
2891
2892
2893
2894 func ArrayOf(length int, elem Type) Type {
2895 if length < 0 {
2896 panic("reflect: negative length passed to ArrayOf")
2897 }
2898
2899 typ := elem.(*rtype)
2900
2901
2902 ckey := cacheKey{Array, typ, nil, uintptr(length)}
2903 if array, ok := lookupCache.Load(ckey); ok {
2904 return array.(Type)
2905 }
2906
2907
2908 s := "[" + strconv.Itoa(length) + "]" + typ.String()
2909 for _, tt := range typesByString(s) {
2910 array := (*arrayType)(unsafe.Pointer(tt))
2911 if array.elem == typ {
2912 ti, _ := lookupCache.LoadOrStore(ckey, tt)
2913 return ti.(Type)
2914 }
2915 }
2916
2917
2918 var iarray any = [1]unsafe.Pointer{}
2919 prototype := *(**arrayType)(unsafe.Pointer(&iarray))
2920 array := *prototype
2921 array.tflag = typ.tflag & tflagRegularMemory
2922 array.str = resolveReflectName(newName(s, "", false))
2923 array.hash = fnv1(typ.hash, '[')
2924 for n := uint32(length); n > 0; n >>= 8 {
2925 array.hash = fnv1(array.hash, byte(n))
2926 }
2927 array.hash = fnv1(array.hash, ']')
2928 array.elem = typ
2929 array.ptrToThis = 0
2930 if typ.size > 0 {
2931 max := ^uintptr(0) / typ.size
2932 if uintptr(length) > max {
2933 panic("reflect.ArrayOf: array size would exceed virtual address space")
2934 }
2935 }
2936 array.size = typ.size * uintptr(length)
2937 if length > 0 && typ.ptrdata != 0 {
2938 array.ptrdata = typ.size*uintptr(length-1) + typ.ptrdata
2939 }
2940 array.align = typ.align
2941 array.fieldAlign = typ.fieldAlign
2942 array.len = uintptr(length)
2943 array.slice = SliceOf(elem).(*rtype)
2944
2945 switch {
2946 case typ.ptrdata == 0 || array.size == 0:
2947
2948 array.gcdata = nil
2949 array.ptrdata = 0
2950
2951 case length == 1:
2952
2953 array.kind |= typ.kind & kindGCProg
2954 array.gcdata = typ.gcdata
2955 array.ptrdata = typ.ptrdata
2956
2957 case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*goarch.PtrSize:
2958
2959
2960
2961 mask := make([]byte, (array.ptrdata/goarch.PtrSize+7)/8)
2962 emitGCMask(mask, 0, typ, array.len)
2963 array.gcdata = &mask[0]
2964
2965 default:
2966
2967
2968 prog := []byte{0, 0, 0, 0}
2969 prog = appendGCProg(prog, typ)
2970
2971 elemPtrs := typ.ptrdata / goarch.PtrSize
2972 elemWords := typ.size / goarch.PtrSize
2973 if elemPtrs < elemWords {
2974
2975 prog = append(prog, 0x01, 0x00)
2976 if elemPtrs+1 < elemWords {
2977 prog = append(prog, 0x81)
2978 prog = appendVarint(prog, elemWords-elemPtrs-1)
2979 }
2980 }
2981
2982 if elemWords < 0x80 {
2983 prog = append(prog, byte(elemWords|0x80))
2984 } else {
2985 prog = append(prog, 0x80)
2986 prog = appendVarint(prog, elemWords)
2987 }
2988 prog = appendVarint(prog, uintptr(length)-1)
2989 prog = append(prog, 0)
2990 *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
2991 array.kind |= kindGCProg
2992 array.gcdata = &prog[0]
2993 array.ptrdata = array.size
2994 }
2995
2996 etyp := typ.common()
2997 esize := etyp.Size()
2998
2999 array.equal = nil
3000 if eequal := etyp.equal; eequal != nil {
3001 array.equal = func(p, q unsafe.Pointer) bool {
3002 for i := 0; i < length; i++ {
3003 pi := arrayAt(p, i, esize, "i < length")
3004 qi := arrayAt(q, i, esize, "i < length")
3005 if !eequal(pi, qi) {
3006 return false
3007 }
3008
3009 }
3010 return true
3011 }
3012 }
3013
3014 switch {
3015 case length == 1 && !ifaceIndir(typ):
3016
3017 array.kind |= kindDirectIface
3018 default:
3019 array.kind &^= kindDirectIface
3020 }
3021
3022 ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
3023 return ti.(Type)
3024 }
3025
3026 func appendVarint(x []byte, v uintptr) []byte {
3027 for ; v >= 0x80; v >>= 7 {
3028 x = append(x, byte(v|0x80))
3029 }
3030 x = append(x, byte(v))
3031 return x
3032 }
3033
3034
3035
3036
3037
3038
3039 func toType(t *rtype) Type {
3040 if t == nil {
3041 return nil
3042 }
3043 return t
3044 }
3045
3046 type layoutKey struct {
3047 ftyp *funcType
3048 rcvr *rtype
3049 }
3050
3051 type layoutType struct {
3052 t *rtype
3053 framePool *sync.Pool
3054 abi abiDesc
3055 }
3056
3057 var layoutCache sync.Map
3058
3059
3060
3061
3062
3063
3064
3065
3066 func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, framePool *sync.Pool, abi abiDesc) {
3067 if t.Kind() != Func {
3068 panic("reflect: funcLayout of non-func type " + t.String())
3069 }
3070 if rcvr != nil && rcvr.Kind() == Interface {
3071 panic("reflect: funcLayout with interface receiver " + rcvr.String())
3072 }
3073 k := layoutKey{t, rcvr}
3074 if lti, ok := layoutCache.Load(k); ok {
3075 lt := lti.(layoutType)
3076 return lt.t, lt.framePool, lt.abi
3077 }
3078
3079
3080 abi = newAbiDesc(t, rcvr)
3081
3082
3083 x := &rtype{
3084 align: goarch.PtrSize,
3085
3086
3087
3088
3089 size: align(abi.retOffset+abi.ret.stackBytes, goarch.PtrSize),
3090 ptrdata: uintptr(abi.stackPtrs.n) * goarch.PtrSize,
3091 }
3092 if abi.stackPtrs.n > 0 {
3093 x.gcdata = &abi.stackPtrs.data[0]
3094 }
3095
3096 var s string
3097 if rcvr != nil {
3098 s = "methodargs(" + rcvr.String() + ")(" + t.String() + ")"
3099 } else {
3100 s = "funcargs(" + t.String() + ")"
3101 }
3102 x.str = resolveReflectName(newName(s, "", false))
3103
3104
3105 framePool = &sync.Pool{New: func() any {
3106 return unsafe_New(x)
3107 }}
3108 lti, _ := layoutCache.LoadOrStore(k, layoutType{
3109 t: x,
3110 framePool: framePool,
3111 abi: abi,
3112 })
3113 lt := lti.(layoutType)
3114 return lt.t, lt.framePool, lt.abi
3115 }
3116
3117
3118 func ifaceIndir(t *rtype) bool {
3119 return t.kind&kindDirectIface == 0
3120 }
3121
3122
3123 type bitVector struct {
3124 n uint32
3125 data []byte
3126 }
3127
3128
3129 func (bv *bitVector) append(bit uint8) {
3130 if bv.n%8 == 0 {
3131 bv.data = append(bv.data, 0)
3132 }
3133 bv.data[bv.n/8] |= bit << (bv.n % 8)
3134 bv.n++
3135 }
3136
3137 func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
3138 if t.ptrdata == 0 {
3139 return
3140 }
3141
3142 switch Kind(t.kind & kindMask) {
3143 case Chan, Func, Map, Pointer, Slice, String, UnsafePointer:
3144
3145 for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
3146 bv.append(0)
3147 }
3148 bv.append(1)
3149
3150 case Interface:
3151
3152 for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
3153 bv.append(0)
3154 }
3155 bv.append(1)
3156 bv.append(1)
3157
3158 case Array:
3159
3160 tt := (*arrayType)(unsafe.Pointer(t))
3161 for i := 0; i < int(tt.len); i++ {
3162 addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem)
3163 }
3164
3165 case Struct:
3166
3167 tt := (*structType)(unsafe.Pointer(t))
3168 for i := range tt.fields {
3169 f := &tt.fields[i]
3170 addTypeBits(bv, offset+f.offset(), f.typ)
3171 }
3172 }
3173 }
3174
View as plain text