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