1
2
3
4
5 package abi
6
7 import (
8 "unsafe"
9 )
10
11
12
13
14
15
16
17
18
19
20 type Type struct {
21 Size_ uintptr
22 PtrBytes uintptr
23 Hash uint32
24 TFlag TFlag
25 Align_ uint8
26 FieldAlign_ uint8
27 Kind_ Kind
28
29
30 Equal func(unsafe.Pointer, unsafe.Pointer) bool
31
32
33
34
35
36
37
38
39
40
41
42 GCData *byte
43 Str NameOff
44 PtrToThis TypeOff
45 }
46
47
48
49 type Kind uint8
50
51 const (
52 Invalid Kind = iota
53 Bool
54 Int
55 Int8
56 Int16
57 Int32
58 Int64
59 Uint
60 Uint8
61 Uint16
62 Uint32
63 Uint64
64 Uintptr
65 Float32
66 Float64
67 Complex64
68 Complex128
69 Array
70 Chan
71 Func
72 Interface
73 Map
74 Pointer
75 Slice
76 String
77 Struct
78 UnsafePointer
79 )
80
81
82
83 type TFlag uint8
84
85 const (
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 TFlagUncommon TFlag = 1 << 0
102
103
104
105
106
107 TFlagExtraStar TFlag = 1 << 1
108
109
110 TFlagNamed TFlag = 1 << 2
111
112
113
114 TFlagRegularMemory TFlag = 1 << 3
115
116
117
118
119
120
121 TFlagGCMaskOnDemand TFlag = 1 << 4
122
123
124
125
126 TFlagDirectIface TFlag = 1 << 5
127
128
129
130 KindDirectIface Kind = 1 << 5
131 )
132
133
134 type NameOff int32
135
136
137 type TypeOff int32
138
139
140 type TextOff int32
141
142
143 func (k Kind) String() string {
144 if int(k) < len(kindNames) {
145 return kindNames[k]
146 }
147 return kindNames[0]
148 }
149
150 var kindNames = []string{
151 Invalid: "invalid",
152 Bool: "bool",
153 Int: "int",
154 Int8: "int8",
155 Int16: "int16",
156 Int32: "int32",
157 Int64: "int64",
158 Uint: "uint",
159 Uint8: "uint8",
160 Uint16: "uint16",
161 Uint32: "uint32",
162 Uint64: "uint64",
163 Uintptr: "uintptr",
164 Float32: "float32",
165 Float64: "float64",
166 Complex64: "complex64",
167 Complex128: "complex128",
168 Array: "array",
169 Chan: "chan",
170 Func: "func",
171 Interface: "interface",
172 Map: "map",
173 Pointer: "ptr",
174 Slice: "slice",
175 String: "string",
176 Struct: "struct",
177 UnsafePointer: "unsafe.Pointer",
178 }
179
180
181 func TypeOf(a any) *Type {
182 eface := *(*EmptyInterface)(unsafe.Pointer(&a))
183
184
185
186
187
188 return (*Type)(NoEscape(unsafe.Pointer(eface.Type)))
189 }
190
191
192 func TypeFor[T any]() *Type {
193 return (*PtrType)(unsafe.Pointer(TypeOf((*T)(nil)))).Elem
194 }
195
196 func (t *Type) Kind() Kind { return t.Kind_ }
197
198 func (t *Type) HasName() bool {
199 return t.TFlag&TFlagNamed != 0
200 }
201
202
203 func (t *Type) Pointers() bool { return t.PtrBytes != 0 }
204
205
206 func (t *Type) IsDirectIface() bool {
207 return t.TFlag&TFlagDirectIface != 0
208 }
209
210 func (t *Type) GcSlice(begin, end uintptr) []byte {
211 if t.TFlag&TFlagGCMaskOnDemand != 0 {
212 panic("GcSlice can't handle on-demand gcdata types")
213 }
214 return unsafe.Slice(t.GCData, int(end))[begin:]
215 }
216
217
218 type Method struct {
219 Name NameOff
220 Mtyp TypeOff
221 Ifn TextOff
222 Tfn TextOff
223 }
224
225
226
227
228
229 type UncommonType struct {
230 PkgPath NameOff
231 Mcount uint16
232 Xcount uint16
233 Moff uint32
234 _ uint32
235 }
236
237 func (t *UncommonType) Methods() []Method {
238 if t.Mcount == 0 {
239 return nil
240 }
241 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount]
242 }
243
244 func (t *UncommonType) ExportedMethods() []Method {
245 if t.Xcount == 0 {
246 return nil
247 }
248 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount]
249 }
250
251
252
253
254
255
256
257
258 func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
259 return unsafe.Pointer(uintptr(p) + x)
260 }
261
262
263 type Imethod struct {
264 Name NameOff
265 Typ TypeOff
266 }
267
268
269 type ArrayType struct {
270 Type
271 Elem *Type
272 Slice *Type
273 Len uintptr
274 }
275
276
277 func (t *Type) Len() int {
278 if t.Kind() == Array {
279 return int((*ArrayType)(unsafe.Pointer(t)).Len)
280 }
281 return 0
282 }
283
284 func (t *Type) Common() *Type {
285 return t
286 }
287
288 type ChanDir int
289
290 const (
291 RecvDir ChanDir = 1 << iota
292 SendDir
293 BothDir = RecvDir | SendDir
294 InvalidDir ChanDir = 0
295 )
296
297
298 type ChanType struct {
299 Type
300 Elem *Type
301 Dir ChanDir
302 }
303
304 type structTypeUncommon struct {
305 StructType
306 u UncommonType
307 }
308
309
310 func (t *Type) ChanDir() ChanDir {
311 if t.Kind() == Chan {
312 ch := (*ChanType)(unsafe.Pointer(t))
313 return ch.Dir
314 }
315 return InvalidDir
316 }
317
318
319 func (t *Type) Uncommon() *UncommonType {
320 if t.TFlag&TFlagUncommon == 0 {
321 return nil
322 }
323 switch t.Kind() {
324 case Struct:
325 return &(*structTypeUncommon)(unsafe.Pointer(t)).u
326 case Pointer:
327 type u struct {
328 PtrType
329 u UncommonType
330 }
331 return &(*u)(unsafe.Pointer(t)).u
332 case Func:
333 type u struct {
334 FuncType
335 u UncommonType
336 }
337 return &(*u)(unsafe.Pointer(t)).u
338 case Slice:
339 type u struct {
340 SliceType
341 u UncommonType
342 }
343 return &(*u)(unsafe.Pointer(t)).u
344 case Array:
345 type u struct {
346 ArrayType
347 u UncommonType
348 }
349 return &(*u)(unsafe.Pointer(t)).u
350 case Chan:
351 type u struct {
352 ChanType
353 u UncommonType
354 }
355 return &(*u)(unsafe.Pointer(t)).u
356 case Map:
357 type u struct {
358 MapType
359 u UncommonType
360 }
361 return &(*u)(unsafe.Pointer(t)).u
362 case Interface:
363 type u struct {
364 InterfaceType
365 u UncommonType
366 }
367 return &(*u)(unsafe.Pointer(t)).u
368 default:
369 type u struct {
370 Type
371 u UncommonType
372 }
373 return &(*u)(unsafe.Pointer(t)).u
374 }
375 }
376
377
378 func (t *Type) Elem() *Type {
379 switch t.Kind() {
380 case Array:
381 tt := (*ArrayType)(unsafe.Pointer(t))
382 return tt.Elem
383 case Chan:
384 tt := (*ChanType)(unsafe.Pointer(t))
385 return tt.Elem
386 case Map:
387 tt := (*MapType)(unsafe.Pointer(t))
388 return tt.Elem
389 case Pointer:
390 tt := (*PtrType)(unsafe.Pointer(t))
391 return tt.Elem
392 case Slice:
393 tt := (*SliceType)(unsafe.Pointer(t))
394 return tt.Elem
395 }
396 return nil
397 }
398
399
400 func (t *Type) StructType() *StructType {
401 if t.Kind() != Struct {
402 return nil
403 }
404 return (*StructType)(unsafe.Pointer(t))
405 }
406
407
408 func (t *Type) MapType() *MapType {
409 if t.Kind() != Map {
410 return nil
411 }
412 return (*MapType)(unsafe.Pointer(t))
413 }
414
415
416 func (t *Type) ArrayType() *ArrayType {
417 if t.Kind() != Array {
418 return nil
419 }
420 return (*ArrayType)(unsafe.Pointer(t))
421 }
422
423
424 func (t *Type) FuncType() *FuncType {
425 if t.Kind() != Func {
426 return nil
427 }
428 return (*FuncType)(unsafe.Pointer(t))
429 }
430
431
432 func (t *Type) InterfaceType() *InterfaceType {
433 if t.Kind() != Interface {
434 return nil
435 }
436 return (*InterfaceType)(unsafe.Pointer(t))
437 }
438
439
440 func (t *Type) Size() uintptr { return t.Size_ }
441
442
443 func (t *Type) Align() int { return int(t.Align_) }
444
445 func (t *Type) FieldAlign() int { return int(t.FieldAlign_) }
446
447 type InterfaceType struct {
448 Type
449 PkgPath Name
450 Methods []Imethod
451 }
452
453 func (t *Type) ExportedMethods() []Method {
454 ut := t.Uncommon()
455 if ut == nil {
456 return nil
457 }
458 return ut.ExportedMethods()
459 }
460
461 func (t *Type) NumMethod() int {
462 if t.Kind() == Interface {
463 tt := (*InterfaceType)(unsafe.Pointer(t))
464 return tt.NumMethod()
465 }
466 return len(t.ExportedMethods())
467 }
468
469
470 func (t *InterfaceType) NumMethod() int { return len(t.Methods) }
471
472 func (t *Type) Key() *Type {
473 if t.Kind() == Map {
474 return (*MapType)(unsafe.Pointer(t)).Key
475 }
476 return nil
477 }
478
479 type SliceType struct {
480 Type
481 Elem *Type
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495 type FuncType struct {
496 Type
497 InCount uint16
498 OutCount uint16
499 }
500
501 func (t *FuncType) In(i int) *Type {
502 return t.InSlice()[i]
503 }
504
505 func (t *FuncType) NumIn() int {
506 return int(t.InCount)
507 }
508
509 func (t *FuncType) NumOut() int {
510 return int(t.OutCount & (1<<15 - 1))
511 }
512
513 func (t *FuncType) Out(i int) *Type {
514 return (t.OutSlice()[i])
515 }
516
517 func (t *FuncType) InSlice() []*Type {
518 uadd := unsafe.Sizeof(*t)
519 if t.TFlag&TFlagUncommon != 0 {
520 uadd += unsafe.Sizeof(UncommonType{})
521 }
522 if t.InCount == 0 {
523 return nil
524 }
525 return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.InCount:t.InCount]
526 }
527 func (t *FuncType) OutSlice() []*Type {
528 outCount := uint16(t.NumOut())
529 if outCount == 0 {
530 return nil
531 }
532 uadd := unsafe.Sizeof(*t)
533 if t.TFlag&TFlagUncommon != 0 {
534 uadd += unsafe.Sizeof(UncommonType{})
535 }
536 return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(t), uadd, "outCount > 0"))[t.InCount : t.InCount+outCount : t.InCount+outCount]
537 }
538
539 func (t *FuncType) IsVariadic() bool {
540 return t.OutCount&(1<<15) != 0
541 }
542
543 type PtrType struct {
544 Type
545 Elem *Type
546 }
547
548 type StructField struct {
549 Name Name
550 Typ *Type
551 Offset uintptr
552 }
553
554 func (f *StructField) Embedded() bool {
555 return f.Name.IsEmbedded()
556 }
557
558 type StructType struct {
559 Type
560 PkgPath Name
561 Fields []StructField
562 }
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590 type Name struct {
591 Bytes *byte
592 }
593
594
595
596 func (n Name) DataChecked(off int, whySafe string) *byte {
597 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe))
598 }
599
600
601
602 func (n Name) Data(off int) *byte {
603 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason"))
604 }
605
606
607 func (n Name) IsExported() bool {
608 return (*n.Bytes)&(1<<0) != 0
609 }
610
611
612 func (n Name) HasTag() bool {
613 return (*n.Bytes)&(1<<1) != 0
614 }
615
616
617 func (n Name) IsEmbedded() bool {
618 return (*n.Bytes)&(1<<3) != 0
619 }
620
621
622
623 func (n Name) ReadVarint(off int) (int, int) {
624 v := 0
625 for i := 0; ; i++ {
626 x := *n.DataChecked(off+i, "read varint")
627 v += int(x&0x7f) << (7 * i)
628 if x&0x80 == 0 {
629 return i + 1, v
630 }
631 }
632 }
633
634
635 func (n Name) IsBlank() bool {
636 if n.Bytes == nil {
637 return false
638 }
639 _, l := n.ReadVarint(1)
640 return l == 1 && *n.Data(2) == '_'
641 }
642
643
644
645
646 func writeVarint(buf []byte, n int) int {
647 for i := 0; ; i++ {
648 b := byte(n & 0x7f)
649 n >>= 7
650 if n == 0 {
651 buf[i] = b
652 return i + 1
653 }
654 buf[i] = b | 0x80
655 }
656 }
657
658
659 func (n Name) Name() string {
660 if n.Bytes == nil {
661 return ""
662 }
663 i, l := n.ReadVarint(1)
664 return unsafe.String(n.DataChecked(1+i, "non-empty string"), l)
665 }
666
667
668 func (n Name) Tag() string {
669 if !n.HasTag() {
670 return ""
671 }
672 i, l := n.ReadVarint(1)
673 i2, l2 := n.ReadVarint(1 + i + l)
674 return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2)
675 }
676
677 func NewName(n, tag string, exported, embedded bool) Name {
678 if len(n) >= 1<<29 {
679 panic("abi.NewName: name too long: " + n[:1024] + "...")
680 }
681 if len(tag) >= 1<<29 {
682 panic("abi.NewName: tag too long: " + tag[:1024] + "...")
683 }
684 var nameLen [10]byte
685 var tagLen [10]byte
686 nameLenLen := writeVarint(nameLen[:], len(n))
687 tagLenLen := writeVarint(tagLen[:], len(tag))
688
689 var bits byte
690 l := 1 + nameLenLen + len(n)
691 if exported {
692 bits |= 1 << 0
693 }
694 if len(tag) > 0 {
695 l += tagLenLen + len(tag)
696 bits |= 1 << 1
697 }
698 if embedded {
699 bits |= 1 << 3
700 }
701
702 b := make([]byte, l)
703 b[0] = bits
704 copy(b[1:], nameLen[:nameLenLen])
705 copy(b[1+nameLenLen:], n)
706 if len(tag) > 0 {
707 tb := b[1+nameLenLen+len(n):]
708 copy(tb, tagLen[:tagLenLen])
709 copy(tb[tagLenLen:], tag)
710 }
711
712 return Name{Bytes: &b[0]}
713 }
714
715 const (
716 TraceArgsLimit = 10
717 TraceArgsMaxDepth = 5
718
719
720
721
722
723
724 TraceArgsMaxLen = (TraceArgsMaxDepth*3+2)*TraceArgsLimit + 1
725 )
726
727
728
729
730
731
732
733
734
735
736
737
738
739 const (
740 TraceArgsEndSeq = 0xff
741 TraceArgsStartAgg = 0xfe
742 TraceArgsEndAgg = 0xfd
743 TraceArgsDotdotdot = 0xfc
744 TraceArgsOffsetTooLarge = 0xfb
745 TraceArgsSpecial = 0xf0
746 )
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777 const MaxPtrmaskBytes = 2048
778
View as plain text