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