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