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