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