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