github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/internal/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 // Be careful about accessing this type at build time, as the version 14 // of this type in the compiler/linker may not have the same layout 15 // as the version in the target binary, due to pointer width 16 // differences and any experiments. Use cmd/compile/internal/rttype 17 // or the functions in compiletype.go to access this type instead. 18 // (TODO: this admonition applies to every type in this package. 19 // Put it in some shared location?) 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 // TFlagUnrolledBitmap marks special types that are unrolled-bitmap 116 // versions of types with GC programs. 117 // These types need to be deallocated when the underlying object 118 // is freed. 119 TFlagUnrolledBitmap TFlag = 1 << 4 120 ) 121 122 // NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime. 123 type NameOff int32 124 125 // TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime. 126 type TypeOff int32 127 128 // TextOff is an offset from the top of a text section. See (rtype).textOff in runtime. 129 type TextOff int32 130 131 // String returns the name of k. 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 // Pointers reports whether t contains pointers. 176 func (t *Type) Pointers() bool { return t.PtrBytes != 0 } 177 178 // IfaceIndir reports whether t is stored indirectly in an interface value. 179 func (t *Type) IfaceIndir() bool { 180 return t.Kind_&KindDirectIface == 0 181 } 182 183 // isDirectIface reports whether t is stored directly in an interface value. 184 func (t *Type) IsDirectIface() bool { 185 return t.Kind_&KindDirectIface != 0 186 } 187 188 func (t *Type) GcSlice(begin, end uintptr) []byte { 189 return unsafe.Slice(t.GCData, int(end))[begin:] 190 } 191 192 // Method on non-interface type 193 type Method struct { 194 Name NameOff // name of method 195 Mtyp TypeOff // method type (without receiver) 196 Ifn TextOff // fn used in interface call (one-word receiver) 197 Tfn TextOff // fn used for normal method call 198 } 199 200 // UncommonType is present only for defined types or types with methods 201 // (if T is a defined type, the uncommonTypes for T and *T have methods). 202 // Using a pointer to this struct reduces the overall size required 203 // to describe a non-defined type with no methods. 204 type UncommonType struct { 205 PkgPath NameOff // import path; empty for built-in types like int, string 206 Mcount uint16 // number of methods 207 Xcount uint16 // number of exported methods 208 Moff uint32 // offset from this uncommontype to [mcount]Method 209 _ uint32 // unused 210 } 211 212 func (t *UncommonType) Methods() []Method { 213 if t.Mcount == 0 { 214 return nil 215 } 216 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount] 217 } 218 219 func (t *UncommonType) ExportedMethods() []Method { 220 if t.Xcount == 0 { 221 return nil 222 } 223 return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount] 224 } 225 226 // addChecked returns p+x. 227 // 228 // The whySafe string is ignored, so that the function still inlines 229 // as efficiently as p+x, but all call sites should use the string to 230 // record why the addition is safe, which is to say why the addition 231 // does not cause x to advance to the very end of p's allocation 232 // and therefore point incorrectly at the next block in memory. 233 func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { 234 return unsafe.Pointer(uintptr(p) + x) 235 } 236 237 // Imethod represents a method on an interface type 238 type Imethod struct { 239 Name NameOff // name of method 240 Typ TypeOff // .(*FuncType) underneath 241 } 242 243 // ArrayType represents a fixed array type. 244 type ArrayType struct { 245 Type 246 Elem *Type // array element type 247 Slice *Type // slice type 248 Len uintptr 249 } 250 251 // Len returns the length of t if t is an array type, otherwise 0 252 func (t *Type) Len() int { 253 if t.Kind() == Array { 254 return int((*ArrayType)(unsafe.Pointer(t)).Len) 255 } 256 return 0 257 } 258 259 func (t *Type) Common() *Type { 260 return t 261 } 262 263 type ChanDir int 264 265 const ( 266 RecvDir ChanDir = 1 << iota // <-chan 267 SendDir // chan<- 268 BothDir = RecvDir | SendDir // chan 269 InvalidDir ChanDir = 0 270 ) 271 272 // ChanType represents a channel type 273 type ChanType struct { 274 Type 275 Elem *Type 276 Dir ChanDir 277 } 278 279 type structTypeUncommon struct { 280 StructType 281 u UncommonType 282 } 283 284 // ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0). 285 func (t *Type) ChanDir() ChanDir { 286 if t.Kind() == Chan { 287 ch := (*ChanType)(unsafe.Pointer(t)) 288 return ch.Dir 289 } 290 return InvalidDir 291 } 292 293 // Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil 294 func (t *Type) Uncommon() *UncommonType { 295 if t.TFlag&TFlagUncommon == 0 { 296 return nil 297 } 298 switch t.Kind() { 299 case Struct: 300 return &(*structTypeUncommon)(unsafe.Pointer(t)).u 301 case Pointer: 302 type u struct { 303 PtrType 304 u UncommonType 305 } 306 return &(*u)(unsafe.Pointer(t)).u 307 case Func: 308 type u struct { 309 FuncType 310 u UncommonType 311 } 312 return &(*u)(unsafe.Pointer(t)).u 313 case Slice: 314 type u struct { 315 SliceType 316 u UncommonType 317 } 318 return &(*u)(unsafe.Pointer(t)).u 319 case Array: 320 type u struct { 321 ArrayType 322 u UncommonType 323 } 324 return &(*u)(unsafe.Pointer(t)).u 325 case Chan: 326 type u struct { 327 ChanType 328 u UncommonType 329 } 330 return &(*u)(unsafe.Pointer(t)).u 331 case Map: 332 type u struct { 333 MapType 334 u UncommonType 335 } 336 return &(*u)(unsafe.Pointer(t)).u 337 case Interface: 338 type u struct { 339 InterfaceType 340 u UncommonType 341 } 342 return &(*u)(unsafe.Pointer(t)).u 343 default: 344 type u struct { 345 Type 346 u UncommonType 347 } 348 return &(*u)(unsafe.Pointer(t)).u 349 } 350 } 351 352 // Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil. 353 func (t *Type) Elem() *Type { 354 switch t.Kind() { 355 case Array: 356 tt := (*ArrayType)(unsafe.Pointer(t)) 357 return tt.Elem 358 case Chan: 359 tt := (*ChanType)(unsafe.Pointer(t)) 360 return tt.Elem 361 case Map: 362 tt := (*MapType)(unsafe.Pointer(t)) 363 return tt.Elem 364 case Pointer: 365 tt := (*PtrType)(unsafe.Pointer(t)) 366 return tt.Elem 367 case Slice: 368 tt := (*SliceType)(unsafe.Pointer(t)) 369 return tt.Elem 370 } 371 return nil 372 } 373 374 // StructType returns t cast to a *StructType, or nil if its tag does not match. 375 func (t *Type) StructType() *StructType { 376 if t.Kind() != Struct { 377 return nil 378 } 379 return (*StructType)(unsafe.Pointer(t)) 380 } 381 382 // MapType returns t cast to a *MapType, or nil if its tag does not match. 383 func (t *Type) MapType() *MapType { 384 if t.Kind() != Map { 385 return nil 386 } 387 return (*MapType)(unsafe.Pointer(t)) 388 } 389 390 // ArrayType returns t cast to a *ArrayType, or nil if its tag does not match. 391 func (t *Type) ArrayType() *ArrayType { 392 if t.Kind() != Array { 393 return nil 394 } 395 return (*ArrayType)(unsafe.Pointer(t)) 396 } 397 398 // FuncType returns t cast to a *FuncType, or nil if its tag does not match. 399 func (t *Type) FuncType() *FuncType { 400 if t.Kind() != Func { 401 return nil 402 } 403 return (*FuncType)(unsafe.Pointer(t)) 404 } 405 406 // InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match. 407 func (t *Type) InterfaceType() *InterfaceType { 408 if t.Kind() != Interface { 409 return nil 410 } 411 return (*InterfaceType)(unsafe.Pointer(t)) 412 } 413 414 // Size returns the size of data with type t. 415 func (t *Type) Size() uintptr { return t.Size_ } 416 417 // Align returns the alignment of data with type t. 418 func (t *Type) Align() int { return int(t.Align_) } 419 420 func (t *Type) FieldAlign() int { return int(t.FieldAlign_) } 421 422 type InterfaceType struct { 423 Type 424 PkgPath Name // import path 425 Methods []Imethod // sorted by hash 426 } 427 428 func (t *Type) ExportedMethods() []Method { 429 ut := t.Uncommon() 430 if ut == nil { 431 return nil 432 } 433 return ut.ExportedMethods() 434 } 435 436 func (t *Type) NumMethod() int { 437 if t.Kind() == Interface { 438 tt := (*InterfaceType)(unsafe.Pointer(t)) 439 return tt.NumMethod() 440 } 441 return len(t.ExportedMethods()) 442 } 443 444 // NumMethod returns the number of interface methods in the type's method set. 445 func (t *InterfaceType) NumMethod() int { return len(t.Methods) } 446 447 type MapType struct { 448 Type 449 Key *Type 450 Elem *Type 451 Bucket *Type // internal type representing a hash bucket 452 // function for hashing keys (ptr to key, seed) -> hash 453 Hasher func(unsafe.Pointer, uintptr) uintptr 454 KeySize uint8 // size of key slot 455 ValueSize uint8 // size of elem slot 456 BucketSize uint16 // size of bucket 457 Flags uint32 458 } 459 460 // Note: flag values must match those used in the TMAP case 461 // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. 462 func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself 463 return mt.Flags&1 != 0 464 } 465 func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself 466 return mt.Flags&2 != 0 467 } 468 func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys 469 return mt.Flags&4 != 0 470 } 471 func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite 472 return mt.Flags&8 != 0 473 } 474 func (mt *MapType) HashMightPanic() bool { // true if hash function might panic 475 return mt.Flags&16 != 0 476 } 477 478 func (t *Type) Key() *Type { 479 if t.Kind() == Map { 480 return (*MapType)(unsafe.Pointer(t)).Key 481 } 482 return nil 483 } 484 485 type SliceType struct { 486 Type 487 Elem *Type // slice element type 488 } 489 490 // funcType represents a function type. 491 // 492 // A *Type for each in and out parameter is stored in an array that 493 // directly follows the funcType (and possibly its uncommonType). So 494 // a function type with one method, one input, and one output is: 495 // 496 // struct { 497 // funcType 498 // uncommonType 499 // [2]*rtype // [0] is in, [1] is out 500 // } 501 type FuncType struct { 502 Type 503 InCount uint16 504 OutCount uint16 // top bit is set if last input parameter is ... 505 } 506 507 func (t *FuncType) In(i int) *Type { 508 return t.InSlice()[i] 509 } 510 511 func (t *FuncType) NumIn() int { 512 return int(t.InCount) 513 } 514 515 func (t *FuncType) NumOut() int { 516 return int(t.OutCount & (1<<15 - 1)) 517 } 518 519 func (t *FuncType) Out(i int) *Type { 520 return (t.OutSlice()[i]) 521 } 522 523 func (t *FuncType) InSlice() []*Type { 524 uadd := unsafe.Sizeof(*t) 525 if t.TFlag&TFlagUncommon != 0 { 526 uadd += unsafe.Sizeof(UncommonType{}) 527 } 528 if t.InCount == 0 { 529 return nil 530 } 531 return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.InCount:t.InCount] 532 } 533 func (t *FuncType) OutSlice() []*Type { 534 outCount := uint16(t.NumOut()) 535 if outCount == 0 { 536 return nil 537 } 538 uadd := unsafe.Sizeof(*t) 539 if t.TFlag&TFlagUncommon != 0 { 540 uadd += unsafe.Sizeof(UncommonType{}) 541 } 542 return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(t), uadd, "outCount > 0"))[t.InCount : t.InCount+outCount : t.InCount+outCount] 543 } 544 545 func (t *FuncType) IsVariadic() bool { 546 return t.OutCount&(1<<15) != 0 547 } 548 549 type PtrType struct { 550 Type 551 Elem *Type // pointer element (pointed at) type 552 } 553 554 type StructField struct { 555 Name Name // name is always non-empty 556 Typ *Type // type of field 557 Offset uintptr // byte offset of field 558 } 559 560 func (f *StructField) Embedded() bool { 561 return f.Name.IsEmbedded() 562 } 563 564 type StructType struct { 565 Type 566 PkgPath Name 567 Fields []StructField 568 } 569 570 // Name is an encoded type Name with optional extra data. 571 // 572 // The first byte is a bit field containing: 573 // 574 // 1<<0 the name is exported 575 // 1<<1 tag data follows the name 576 // 1<<2 pkgPath nameOff follows the name and tag 577 // 1<<3 the name is of an embedded (a.k.a. anonymous) field 578 // 579 // Following that, there is a varint-encoded length of the name, 580 // followed by the name itself. 581 // 582 // If tag data is present, it also has a varint-encoded length 583 // followed by the tag itself. 584 // 585 // If the import path follows, then 4 bytes at the end of 586 // the data form a nameOff. The import path is only set for concrete 587 // methods that are defined in a different package than their type. 588 // 589 // If a name starts with "*", then the exported bit represents 590 // whether the pointed to type is exported. 591 // 592 // Note: this encoding must match here and in: 593 // cmd/compile/internal/reflectdata/reflect.go 594 // cmd/link/internal/ld/decodesym.go 595 596 type Name struct { 597 Bytes *byte 598 } 599 600 // DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to 601 // be safe for the reason in whySafe (which can appear in a backtrace, etc.) 602 func (n Name) DataChecked(off int, whySafe string) *byte { 603 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) 604 } 605 606 // Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to 607 // be safe because the runtime made the call (other packages use DataChecked) 608 func (n Name) Data(off int) *byte { 609 return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) 610 } 611 612 // IsExported returns "is n exported?" 613 func (n Name) IsExported() bool { 614 return (*n.Bytes)&(1<<0) != 0 615 } 616 617 // HasTag returns true iff there is tag data following this name 618 func (n Name) HasTag() bool { 619 return (*n.Bytes)&(1<<1) != 0 620 } 621 622 // IsEmbedded returns true iff n is embedded (an anonymous field). 623 func (n Name) IsEmbedded() bool { 624 return (*n.Bytes)&(1<<3) != 0 625 } 626 627 // ReadVarint parses a varint as encoded by encoding/binary. 628 // It returns the number of encoded bytes and the encoded value. 629 func (n Name) ReadVarint(off int) (int, int) { 630 v := 0 631 for i := 0; ; i++ { 632 x := *n.DataChecked(off+i, "read varint") 633 v += int(x&0x7f) << (7 * i) 634 if x&0x80 == 0 { 635 return i + 1, v 636 } 637 } 638 } 639 640 // IsBlank indicates whether n is "_". 641 func (n Name) IsBlank() bool { 642 if n.Bytes == nil { 643 return false 644 } 645 _, l := n.ReadVarint(1) 646 return l == 1 && *n.Data(2) == '_' 647 } 648 649 // writeVarint writes n to buf in varint form. Returns the 650 // number of bytes written. n must be nonnegative. 651 // Writes at most 10 bytes. 652 func writeVarint(buf []byte, n int) int { 653 for i := 0; ; i++ { 654 b := byte(n & 0x7f) 655 n >>= 7 656 if n == 0 { 657 buf[i] = b 658 return i + 1 659 } 660 buf[i] = b | 0x80 661 } 662 } 663 664 // Name returns the tag string for n, or empty if there is none. 665 func (n Name) Name() string { 666 if n.Bytes == nil { 667 return "" 668 } 669 i, l := n.ReadVarint(1) 670 return unsafe.String(n.DataChecked(1+i, "non-empty string"), l) 671 } 672 673 // Tag returns the tag string for n, or empty if there is none. 674 func (n Name) Tag() string { 675 if !n.HasTag() { 676 return "" 677 } 678 i, l := n.ReadVarint(1) 679 i2, l2 := n.ReadVarint(1 + i + l) 680 return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2) 681 } 682 683 func NewName(n, tag string, exported, embedded bool) Name { 684 if len(n) >= 1<<29 { 685 panic("abi.NewName: name too long: " + n[:1024] + "...") 686 } 687 if len(tag) >= 1<<29 { 688 panic("abi.NewName: tag too long: " + tag[:1024] + "...") 689 } 690 var nameLen [10]byte 691 var tagLen [10]byte 692 nameLenLen := writeVarint(nameLen[:], len(n)) 693 tagLenLen := writeVarint(tagLen[:], len(tag)) 694 695 var bits byte 696 l := 1 + nameLenLen + len(n) 697 if exported { 698 bits |= 1 << 0 699 } 700 if len(tag) > 0 { 701 l += tagLenLen + len(tag) 702 bits |= 1 << 1 703 } 704 if embedded { 705 bits |= 1 << 3 706 } 707 708 b := make([]byte, l) 709 b[0] = bits 710 copy(b[1:], nameLen[:nameLenLen]) 711 copy(b[1+nameLenLen:], n) 712 if len(tag) > 0 { 713 tb := b[1+nameLenLen+len(n):] 714 copy(tb, tagLen[:tagLenLen]) 715 copy(tb[tagLenLen:], tag) 716 } 717 718 return Name{Bytes: &b[0]} 719 } 720 721 const ( 722 TraceArgsLimit = 10 // print no more than 10 args/components 723 TraceArgsMaxDepth = 5 // no more than 5 layers of nesting 724 725 // maxLen is a (conservative) upper bound of the byte stream length. For 726 // each arg/component, it has no more than 2 bytes of data (size, offset), 727 // and no more than one {, }, ... at each level (it cannot have both the 728 // data and ... unless it is the last one, just be conservative). Plus 1 729 // for _endSeq. 730 TraceArgsMaxLen = (TraceArgsMaxDepth*3+2)*TraceArgsLimit + 1 731 ) 732 733 // Populate the data. 734 // The data is a stream of bytes, which contains the offsets and sizes of the 735 // non-aggregate arguments or non-aggregate fields/elements of aggregate-typed 736 // arguments, along with special "operators". Specifically, 737 // - for each non-aggregate arg/field/element, its offset from FP (1 byte) and 738 // size (1 byte) 739 // - special operators: 740 // - 0xff - end of sequence 741 // - 0xfe - print { (at the start of an aggregate-typed argument) 742 // - 0xfd - print } (at the end of an aggregate-typed argument) 743 // - 0xfc - print ... (more args/fields/elements) 744 // - 0xfb - print _ (offset too large) 745 const ( 746 TraceArgsEndSeq = 0xff 747 TraceArgsStartAgg = 0xfe 748 TraceArgsEndAgg = 0xfd 749 TraceArgsDotdotdot = 0xfc 750 TraceArgsOffsetTooLarge = 0xfb 751 TraceArgsSpecial = 0xf0 // above this are operators, below this are ordinary offsets 752 ) 753 754 // MaxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, 755 // which holds 1-bit entries describing where pointers are in a given type. 756 // Above this length, the GC information is recorded as a GC program, 757 // which can express repetition compactly. In either form, the 758 // information is used by the runtime to initialize the heap bitmap, 759 // and for large types (like 128 or more words), they are roughly the 760 // same speed. GC programs are never much larger and often more 761 // compact. (If large arrays are involved, they can be arbitrarily 762 // more compact.) 763 // 764 // The cutoff must be large enough that any allocation large enough to 765 // use a GC program is large enough that it does not share heap bitmap 766 // bytes with any other objects, allowing the GC program execution to 767 // assume an aligned start and not use atomic operations. In the current 768 // runtime, this means all malloc size classes larger than the cutoff must 769 // be multiples of four words. On 32-bit systems that's 16 bytes, and 770 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint. 771 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed 772 // for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated 773 // is 32 pointers, the bits for which fit in 4 bytes. So MaxPtrmaskBytes 774 // must be >= 4. 775 // 776 // We used to use 16 because the GC programs do have some constant overhead 777 // to get started, and processing 128 pointers seems to be enough to 778 // amortize that overhead well. 779 // 780 // To make sure that the runtime's chansend can call typeBitsBulkBarrier, 781 // we raised the limit to 2048, so that even 32-bit systems are guaranteed to 782 // use bitmaps for objects up to 64 kB in size. 783 const MaxPtrmaskBytes = 2048