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