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