github.com/AndrienkoAleksandr/go@v0.0.19/src/intern/abi/type.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package abi 6 7 import ( 8 "unsafe" 9 ) 10 11 // Type is the runtime representation of a Go type. 12 // 13 // Type is also referenced implicitly 14 // (in the form of expressions involving constants and arch.PtrSize) 15 // in cmd/compile/internal/reflectdata/reflect.go 16 // and cmd/link/internal/ld/decodesym.go 17 // (e.g. data[2*arch.PtrSize+4] references the TFlag field) 18 // unsafe.OffsetOf(Type{}.TFlag) cannot be used directly in those 19 // places because it varies with cross compilation and experiments. 20 type Type struct { 21 Size_ uintptr 22 PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers 23 Hash uint32 // hash of type; avoids computation in hash tables 24 TFlag TFlag // extra type information flags 25 Align_ uint8 // alignment of variable with this type 26 FieldAlign_ uint8 // alignment of struct field with this type 27 Kind_ uint8 // enumeration for C 28 // function for comparing objects of this type 29 // (ptr to object A, ptr to object B) -> ==? 30 Equal func(unsafe.Pointer, unsafe.Pointer) bool 31 // GCData stores the GC type data for the garbage collector. 32 // If the KindGCProg bit is set in kind, GCData is a GC program. 33 // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. 34 GCData *byte 35 Str NameOff // string form 36 PtrToThis TypeOff // type for pointer to this type, may be zero 37 } 38 39 // A Kind represents the specific kind of type that a Type represents. 40 // The zero Kind is not a valid kind. 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 // TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible. 75 KindDirectIface = 1 << 5 76 KindGCProg = 1 << 6 // Type.gc points to GC program 77 KindMask = (1 << 5) - 1 78 ) 79 80 // TFlag is used by a Type to signal what extra type information is 81 // available in the memory directly following the Type value. 82 type TFlag uint8 83 84 const ( 85 // TFlagUncommon means that there is a data with a type, UncommonType, 86 // just beyond the shared-per-type common data. That is, the data 87 // for struct types will store their UncommonType at one offset, the 88 // data for interface types will store their UncommonType at a different 89 // offset. UncommonType is always accessed via a pointer that is computed 90 // using trust-us-we-are-the-implementors pointer arithmetic. 91 // 92 // For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0, 93 // then t has UncommonType data and it can be accessed as: 94 // 95 // type structTypeUncommon struct { 96 // structType 97 // u UncommonType 98 // } 99 // u := &(*structTypeUncommon)(unsafe.Pointer(t)).u 100 TFlagUncommon TFlag = 1 << 0 101 102 // TFlagExtraStar means the name in the str field has an 103 // extraneous '*' prefix. This is because for most types T in 104 // a program, the type *T also exists and reusing the str data 105 // saves binary size. 106 TFlagExtraStar TFlag = 1 << 1 107 108 // TFlagNamed means the type has a name. 109 TFlagNamed TFlag = 1 << 2 110 111 // TFlagRegularMemory means that equal and hash functions can treat 112 // this type as a single region of t.size bytes. 113 TFlagRegularMemory TFlag = 1 << 3 114 ) 115 116 // NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime. 117 type NameOff int32 118 119 // TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime. 120 type TypeOff int32 121 122 // TextOff is an offset from the top of a text section. See (rtype).textOff in runtime. 123 type TextOff int32 124 125 // String returns the name of k. 126 func (k Kind) String() string { 127 if int(k) < len(kindNames) { 128 return kindNames[k] 129 } 130 return kindNames[0] 131 } 132 133 var kindNames = []string{ 134 Invalid: "invalid", 135 Bool: "bool", 136 Int: "int", 137 Int8: "int8", 138 Int16: "int16", 139 Int32: "int32", 140 Int64: "int64", 141 Uint: "uint", 142 Uint8: "uint8", 143 Uint16: "uint16", 144 Uint32: "uint32", 145 Uint64: "uint64", 146 Uintptr: "uintptr", 147 Float32: "float32", 148 Float64: "float64", 149 Complex64: "complex64", 150 Complex128: "complex128", 151 Array: "array", 152 Chan: "chan", 153 Func: "func", 154 Interface: "interface", 155 Map: "map", 156 Pointer: "ptr", 157 Slice: "slice", 158 String: "string", 159 Struct: "struct", 160 UnsafePointer: "unsafe.Pointer", 161 } 162 163 func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) } 164 165 func (t *Type) HasName() bool { 166 return t.TFlag&TFlagNamed != 0 167 } 168 169 func (t *Type) Pointers() bool { return t.PtrBytes != 0 } 170 171 // IfaceIndir reports whether t is stored indirectly in an interface value. 172 func (t *Type) IfaceIndir() bool { 173 return t.Kind_&KindDirectIface == 0 174 } 175 176 // isDirectIface reports whether t is stored directly in an interface value. 177 func (t *Type) IsDirectIface() bool { 178 return t.Kind_&KindDirectIface != 0 179 } 180 181 func (t *Type) GcSlice(begin, end uintptr) []byte { 182 return unsafeSliceFor(t.GCData, int(end))[begin:] 183 } 184 185 // Method on non-interface type 186 type Method struct { 187 Name NameOff // name of method 188 Mtyp TypeOff // method type (without receiver) 189 Ifn TextOff // fn used in interface call (one-word receiver) 190 Tfn TextOff // fn used for normal method call 191 } 192 193 // UncommonType is present only for defined types or types with methods 194 // (if T is a defined type, the uncommonTypes for T and *T have methods). 195 // Using a pointer to this struct reduces the overall size required 196 // to describe a non-defined type with no methods. 197 type UncommonType struct { 198 PkgPath NameOff // import path; empty for built-in types like int, string 199 Mcount uint16 // number of methods 200 Xcount uint16 // number of exported methods 201 Moff uint32 // offset from this uncommontype to [mcount]Method 202 _ uint32 // unused 203 } 204 205 func (t *UncommonType) Methods() []Method { 206 if t.Mcount == 0 { 207 return nil 208 } 209 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount] 210 } 211 212 func (t *UncommonType) ExportedMethods() []Method { 213 if t.Xcount == 0 { 214 return nil 215 } 216 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount] 217 } 218 219 // addChecked returns p+x. 220 // 221 // The whySafe string is ignored, so that the function still inlines 222 // as efficiently as p+x, but all call sites should use the string to 223 // record why the addition is safe, which is to say why the addition 224 // does not cause x to advance to the very end of p's allocation 225 // and therefore point incorrectly at the next block in memory. 226 func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { 227 return unsafe.Pointer(uintptr(p) + x) 228 } 229 230 // Imethod represents a method on an interface type 231 type Imethod struct { 232 Name NameOff // name of method 233 Typ TypeOff // .(*FuncType) underneath 234 } 235 236 // ArrayType represents a fixed array type. 237 type ArrayType struct { 238 Type 239 Elem *Type // array element type 240 Slice *Type // slice type 241 Len uintptr 242 } 243 244 // Len returns the length of t if t is an array type, otherwise 0 245 func (t *Type) Len() int { 246 if t.Kind() == Array { 247 return int((*ArrayType)(unsafe.Pointer(t)).Len) 248 } 249 return 0 250 } 251 252 func (t *Type) Common() *Type { 253 return t 254 } 255 256 type ChanDir int 257 258 const ( 259 RecvDir ChanDir = 1 << iota // <-chan 260 SendDir // chan<- 261 BothDir = RecvDir | SendDir // chan 262 InvalidDir ChanDir = 0 263 ) 264 265 // ChanType represents a channel type 266 type ChanType struct { 267 Type 268 Elem *Type 269 Dir ChanDir 270 } 271 272 type structTypeUncommon struct { 273 StructType 274 u UncommonType 275 } 276 277 // ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0). 278 func (t *Type) ChanDir() ChanDir { 279 if t.Kind() == Chan { 280 ch := (*ChanType)(unsafe.Pointer(t)) 281 return ch.Dir 282 } 283 return InvalidDir 284 } 285 286 // Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil 287 func (t *Type) Uncommon() *UncommonType { 288 if t.TFlag&TFlagUncommon == 0 { 289 return nil 290 } 291 switch t.Kind() { 292 case Struct: 293 return &(*structTypeUncommon)(unsafe.Pointer(t)).u 294 case Pointer: 295 type u struct { 296 PtrType 297 u UncommonType 298 } 299 return &(*u)(unsafe.Pointer(t)).u 300 case Func: 301 type u struct { 302 FuncType 303 u UncommonType 304 } 305 return &(*u)(unsafe.Pointer(t)).u 306 case Slice: 307 type u struct { 308 SliceType 309 u UncommonType 310 } 311 return &(*u)(unsafe.Pointer(t)).u 312 case Array: 313 type u struct { 314 ArrayType 315 u UncommonType 316 } 317 return &(*u)(unsafe.Pointer(t)).u 318 case Chan: 319 type u struct { 320 ChanType 321 u UncommonType 322 } 323 return &(*u)(unsafe.Pointer(t)).u 324 case Map: 325 type u struct { 326 MapType 327 u UncommonType 328 } 329 return &(*u)(unsafe.Pointer(t)).u 330 case Interface: 331 type u struct { 332 InterfaceType 333 u UncommonType 334 } 335 return &(*u)(unsafe.Pointer(t)).u 336 default: 337 type u struct { 338 Type 339 u UncommonType 340 } 341 return &(*u)(unsafe.Pointer(t)).u 342 } 343 } 344 345 // Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil. 346 func (t *Type) Elem() *Type { 347 switch t.Kind() { 348 case Array: 349 tt := (*ArrayType)(unsafe.Pointer(t)) 350 return tt.Elem 351 case Chan: 352 tt := (*ChanType)(unsafe.Pointer(t)) 353 return tt.Elem 354 case Map: 355 tt := (*MapType)(unsafe.Pointer(t)) 356 return tt.Elem 357 case Pointer: 358 tt := (*PtrType)(unsafe.Pointer(t)) 359 return tt.Elem 360 case Slice: 361 tt := (*SliceType)(unsafe.Pointer(t)) 362 return tt.Elem 363 } 364 return nil 365 } 366 367 // StructType returns t cast to a *StructType, or nil if its tag does not match. 368 func (t *Type) StructType() *StructType { 369 if t.Kind() != Struct { 370 return nil 371 } 372 return (*StructType)(unsafe.Pointer(t)) 373 } 374 375 // MapType returns t cast to a *MapType, or nil if its tag does not match. 376 func (t *Type) MapType() *MapType { 377 if t.Kind() != Map { 378 return nil 379 } 380 return (*MapType)(unsafe.Pointer(t)) 381 } 382 383 // ArrayType returns t cast to a *ArrayType, or nil if its tag does not match. 384 func (t *Type) ArrayType() *ArrayType { 385 if t.Kind() != Array { 386 return nil 387 } 388 return (*ArrayType)(unsafe.Pointer(t)) 389 } 390 391 // FuncType returns t cast to a *FuncType, or nil if its tag does not match. 392 func (t *Type) FuncType() *FuncType { 393 if t.Kind() != Func { 394 return nil 395 } 396 return (*FuncType)(unsafe.Pointer(t)) 397 } 398 399 // InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match. 400 func (t *Type) InterfaceType() *InterfaceType { 401 if t.Kind() != Interface { 402 return nil 403 } 404 return (*InterfaceType)(unsafe.Pointer(t)) 405 } 406 407 // Size returns the size of data with type t. 408 func (t *Type) Size() uintptr { return t.Size_ } 409 410 // Align returns the alignment of data with type t. 411 func (t *Type) Align() int { return int(t.Align_) } 412 413 func (t *Type) FieldAlign() int { return int(t.FieldAlign_) } 414 415 type InterfaceType struct { 416 Type 417 PkgPath Name // import path 418 Methods []Imethod // sorted by hash 419 } 420 421 func (t *Type) ExportedMethods() []Method { 422 ut := t.Uncommon() 423 if ut == nil { 424 return nil 425 } 426 return ut.ExportedMethods() 427 } 428 429 func (t *Type) NumMethod() int { 430 if t.Kind() == Interface { 431 tt := (*InterfaceType)(unsafe.Pointer(t)) 432 return tt.NumMethod() 433 } 434 return len(t.ExportedMethods()) 435 } 436 437 // NumMethod returns the number of interface methods in the type's method set. 438 func (t *InterfaceType) NumMethod() int { return len(t.Methods) } 439 440 type MapType struct { 441 Type 442 Key *Type 443 Elem *Type 444 Bucket *Type // internal type representing a hash bucket 445 // function for hashing keys (ptr to key, seed) -> hash 446 Hasher func(unsafe.Pointer, uintptr) uintptr 447 KeySize uint8 // size of key slot 448 ValueSize uint8 // size of elem slot 449 BucketSize uint16 // size of bucket 450 Flags uint32 451 } 452 453 // Note: flag values must match those used in the TMAP case 454 // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. 455 func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself 456 return mt.Flags&1 != 0 457 } 458 func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself 459 return mt.Flags&2 != 0 460 } 461 func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys 462 return mt.Flags&4 != 0 463 } 464 func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite 465 return mt.Flags&8 != 0 466 } 467 func (mt *MapType) HashMightPanic() bool { // true if hash function might panic 468 return mt.Flags&16 != 0 469 } 470 471 func (t *Type) Key() *Type { 472 if t.Kind() == Map { 473 return (*MapType)(unsafe.Pointer(t)).Key 474 } 475 return nil 476 } 477 478 type SliceType struct { 479 Type 480 Elem *Type // slice element type 481 } 482 483 // funcType represents a function type. 484 // 485 // A *Type for each in and out parameter is stored in an array that 486 // directly follows the funcType (and possibly its uncommonType). So 487 // a function type with one method, one input, and one output is: 488 // 489 // struct { 490 // funcType 491 // uncommonType 492 // [2]*rtype // [0] is in, [1] is out 493 // } 494 type FuncType struct { 495 Type 496 InCount uint16 497 OutCount uint16 // top bit is set if last input parameter is ... 498 } 499 500 func (t *FuncType) In(i int) *Type { 501 return t.InSlice()[i] 502 } 503 504 func (t *FuncType) NumIn() int { 505 return int(t.InCount) 506 } 507 508 func (t *FuncType) NumOut() int { 509 return int(t.OutCount & (1<<15 - 1)) 510 } 511 512 func (t *FuncType) Out(i int) *Type { 513 return (t.OutSlice()[i]) 514 } 515 516 func (t *FuncType) InSlice() []*Type { 517 uadd := unsafe.Sizeof(*t) 518 if t.TFlag&TFlagUncommon != 0 { 519 uadd += unsafe.Sizeof(UncommonType{}) 520 } 521 if t.InCount == 0 { 522 return nil 523 } 524 return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.InCount:t.InCount] 525 } 526 func (t *FuncType) OutSlice() []*Type { 527 outCount := uint16(t.NumOut()) 528 if outCount == 0 { 529 return nil 530 } 531 uadd := unsafe.Sizeof(*t) 532 if t.TFlag&TFlagUncommon != 0 { 533 uadd += unsafe.Sizeof(UncommonType{}) 534 } 535 return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(t), uadd, "outCount > 0"))[t.InCount : t.InCount+outCount : t.InCount+outCount] 536 } 537 538 func (t *FuncType) IsVariadic() bool { 539 return t.OutCount&(1<<15) != 0 540 } 541 542 type PtrType struct { 543 Type 544 Elem *Type // pointer element (pointed at) type 545 } 546 547 type StructField struct { 548 Name Name // name is always non-empty 549 Typ *Type // type of field 550 Offset uintptr // byte offset of field 551 } 552 553 func (f *StructField) Embedded() bool { 554 return f.Name.IsEmbedded() 555 } 556 557 type StructType struct { 558 Type 559 PkgPath Name 560 Fields []StructField 561 } 562 563 // Name is an encoded type Name with optional extra data. 564 // 565 // The first byte is a bit field containing: 566 // 567 // 1<<0 the name is exported 568 // 1<<1 tag data follows the name 569 // 1<<2 pkgPath nameOff follows the name and tag 570 // 1<<3 the name is of an embedded (a.k.a. anonymous) field 571 // 572 // Following that, there is a varint-encoded length of the name, 573 // followed by the name itself. 574 // 575 // If tag data is present, it also has a varint-encoded length 576 // followed by the tag itself. 577 // 578 // If the import path follows, then 4 bytes at the end of 579 // the data form a nameOff. The import path is only set for concrete 580 // methods that are defined in a different package than their type. 581 // 582 // If a name starts with "*", then the exported bit represents 583 // whether the pointed to type is exported. 584 // 585 // Note: this encoding must match here and in: 586 // cmd/compile/internal/reflectdata/reflect.go 587 // cmd/link/internal/ld/decodesym.go 588 589 type Name struct { 590 Bytes *byte 591 } 592 593 // DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to 594 // be safe for the reason in whySafe (which can appear in a backtrace, etc.) 595 func (n Name) DataChecked(off int, whySafe string) *byte { 596 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) 597 } 598 599 // Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to 600 // be safe because the runtime made the call (other packages use DataChecked) 601 func (n Name) Data(off int) *byte { 602 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) 603 } 604 605 // IsExported returns "is n exported?" 606 func (n Name) IsExported() bool { 607 return (*n.Bytes)&(1<<0) != 0 608 } 609 610 // HasTag returns true iff there is tag data following this name 611 func (n Name) HasTag() bool { 612 return (*n.Bytes)&(1<<1) != 0 613 } 614 615 // IsEmbedded returns true iff n is embedded (an anonymous field). 616 func (n Name) IsEmbedded() bool { 617 return (*n.Bytes)&(1<<3) != 0 618 } 619 620 // ReadVarint parses a varint as encoded by encoding/binary. 621 // It returns the number of encoded bytes and the encoded value. 622 func (n Name) ReadVarint(off int) (int, int) { 623 v := 0 624 for i := 0; ; i++ { 625 x := *n.DataChecked(off+i, "read varint") 626 v += int(x&0x7f) << (7 * i) 627 if x&0x80 == 0 { 628 return i + 1, v 629 } 630 } 631 } 632 633 // IsBlank indicates whether n is "_". 634 func (n Name) IsBlank() bool { 635 if n.Bytes == nil { 636 return false 637 } 638 _, l := n.ReadVarint(1) 639 return l == 1 && *n.Data(2) == '_' 640 } 641 642 // writeVarint writes n to buf in varint form. Returns the 643 // number of bytes written. n must be nonnegative. 644 // Writes at most 10 bytes. 645 func writeVarint(buf []byte, n int) int { 646 for i := 0; ; i++ { 647 b := byte(n & 0x7f) 648 n >>= 7 649 if n == 0 { 650 buf[i] = b 651 return i + 1 652 } 653 buf[i] = b | 0x80 654 } 655 } 656 657 // Name returns the tag string for n, or empty if there is none. 658 func (n Name) Name() string { 659 if n.Bytes == nil { 660 return "" 661 } 662 i, l := n.ReadVarint(1) 663 return unsafeStringFor(n.DataChecked(1+i, "non-empty string"), l) 664 } 665 666 // Tag returns the tag string for n, or empty if there is none. 667 func (n Name) Tag() string { 668 if !n.HasTag() { 669 return "" 670 } 671 i, l := n.ReadVarint(1) 672 i2, l2 := n.ReadVarint(1 + i + l) 673 return unsafeStringFor(n.DataChecked(1+i+l+i2, "non-empty string"), l2) 674 } 675 676 func NewName(n, tag string, exported, embedded bool) Name { 677 if len(n) >= 1<<29 { 678 panic("abi.NewName: name too long: " + n[:1024] + "...") 679 } 680 if len(tag) >= 1<<29 { 681 panic("abi.NewName: tag too long: " + tag[:1024] + "...") 682 } 683 var nameLen [10]byte 684 var tagLen [10]byte 685 nameLenLen := writeVarint(nameLen[:], len(n)) 686 tagLenLen := writeVarint(tagLen[:], len(tag)) 687 688 var bits byte 689 l := 1 + nameLenLen + len(n) 690 if exported { 691 bits |= 1 << 0 692 } 693 if len(tag) > 0 { 694 l += tagLenLen + len(tag) 695 bits |= 1 << 1 696 } 697 if embedded { 698 bits |= 1 << 3 699 } 700 701 b := make([]byte, l) 702 b[0] = bits 703 copy(b[1:], nameLen[:nameLenLen]) 704 copy(b[1+nameLenLen:], n) 705 if len(tag) > 0 { 706 tb := b[1+nameLenLen+len(n):] 707 copy(tb, tagLen[:tagLenLen]) 708 copy(tb[tagLenLen:], tag) 709 } 710 711 return Name{Bytes: &b[0]} 712 }