Source File
type.go
Belonging Package
internal/abi
// Copyright 2023 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package abiimport ()// Type is the runtime representation of a Go type.//// Be careful about accessing this type at build time, as the version// of this type in the compiler/linker may not have the same layout// as the version in the target binary, due to pointer width// differences and any experiments. Use cmd/compile/internal/rttype// or the functions in compiletype.go to access this type instead.// (TODO: this admonition applies to every type in this package.// Put it in some shared location?)type Type struct {Size_ uintptrPtrBytes uintptr // number of (prefix) bytes in the type that can contain pointersHash uint32 // hash of type; avoids computation in hash tablesTFlag TFlag // extra type information flagsAlign_ uint8 // alignment of variable with this typeFieldAlign_ uint8 // alignment of struct field with this typeKind_ Kind // enumeration for C// function for comparing objects of this type// (ptr to object A, ptr to object B) -> ==?Equal func(unsafe.Pointer, unsafe.Pointer) bool// GCData stores the GC type data for the garbage collector.// If the KindGCProg bit is set in kind, GCData is a GC program.// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.GCData *byteStr NameOff // string formPtrToThis TypeOff // type for pointer to this type, may be zero}// A Kind represents the specific kind of type that a Type represents.// The zero Kind is not a valid kind.type Kind uint8const (Invalid Kind = iotaBoolIntInt8Int16Int32Int64UintUint8Uint16Uint32Uint64UintptrFloat32Float64Complex64Complex128ArrayChanFuncInterfaceMapPointerSliceStringStructUnsafePointer)const (// TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible.KindDirectIface Kind = 1 << 5KindGCProg Kind = 1 << 6 // Type.gc points to GC programKindMask Kind = (1 << 5) - 1)// TFlag is used by a Type to signal what extra type information is// available in the memory directly following the Type value.type TFlag uint8const (// TFlagUncommon means that there is a data with a type, UncommonType,// just beyond the shared-per-type common data. That is, the data// for struct types will store their UncommonType at one offset, the// data for interface types will store their UncommonType at a different// offset. UncommonType is always accessed via a pointer that is computed// using trust-us-we-are-the-implementors pointer arithmetic.//// For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0,// then t has UncommonType data and it can be accessed as://// type structTypeUncommon struct {// structType// u UncommonType// }// u := &(*structTypeUncommon)(unsafe.Pointer(t)).uTFlagUncommon TFlag = 1 << 0// TFlagExtraStar means the name in the str field has an// extraneous '*' prefix. This is because for most types T in// a program, the type *T also exists and reusing the str data// saves binary size.TFlagExtraStar TFlag = 1 << 1// TFlagNamed means the type has a name.TFlagNamed TFlag = 1 << 2// TFlagRegularMemory means that equal and hash functions can treat// this type as a single region of t.size bytes.TFlagRegularMemory TFlag = 1 << 3// TFlagUnrolledBitmap marks special types that are unrolled-bitmap// versions of types with GC programs.// These types need to be deallocated when the underlying object// is freed.TFlagUnrolledBitmap TFlag = 1 << 4)// NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime.type NameOff int32// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime.type TypeOff int32// TextOff is an offset from the top of a text section. See (rtype).textOff in runtime.type TextOff int32// String returns the name of k.func ( Kind) () string {if int() < len(kindNames) {return kindNames[]}return kindNames[0]}var kindNames = []string{Invalid: "invalid",Bool: "bool",Int: "int",Int8: "int8",Int16: "int16",Int32: "int32",Int64: "int64",Uint: "uint",Uint8: "uint8",Uint16: "uint16",Uint32: "uint32",Uint64: "uint64",Uintptr: "uintptr",Float32: "float32",Float64: "float64",Complex64: "complex64",Complex128: "complex128",Array: "array",Chan: "chan",Func: "func",Interface: "interface",Map: "map",Pointer: "ptr",Slice: "slice",String: "string",Struct: "struct",UnsafePointer: "unsafe.Pointer",}// TypeOf returns the abi.Type of some value.func ( any) *Type {:= *(*EmptyInterface)(unsafe.Pointer(&))// Types are either static (for compiler-created types) or// heap-allocated but always reachable (for reflection-created// types, held in the central map). So there is no need to// escape types. noescape here help avoid unnecessary escape// of v.return (*Type)(NoEscape(unsafe.Pointer(.Type)))}// TypeFor returns the abi.Type for a type parameter.func [ any]() *Type {varif := TypeOf(); != nil {return // optimize for T being a non-interface kind}return TypeOf((*)(nil)).Elem() // only for an interface kind}func ( *Type) () Kind { return .Kind_ & KindMask }func ( *Type) () bool {return .TFlag&TFlagNamed != 0}// Pointers reports whether t contains pointers.func ( *Type) () bool { return .PtrBytes != 0 }// IfaceIndir reports whether t is stored indirectly in an interface value.func ( *Type) () bool {return .Kind_&KindDirectIface == 0}// isDirectIface reports whether t is stored directly in an interface value.func ( *Type) () bool {return .Kind_&KindDirectIface != 0}func ( *Type) (, uintptr) []byte {return unsafe.Slice(.GCData, int())[:]}// Method on non-interface typetype Method struct {Name NameOff // name of methodMtyp TypeOff // method type (without receiver)Ifn TextOff // fn used in interface call (one-word receiver)Tfn TextOff // fn used for normal method call}// UncommonType is present only for defined types or types with methods// (if T is a defined type, the uncommonTypes for T and *T have methods).// Using a pointer to this struct reduces the overall size required// to describe a non-defined type with no methods.type UncommonType struct {PkgPath NameOff // import path; empty for built-in types like int, stringMcount uint16 // number of methodsXcount uint16 // number of exported methodsMoff uint32 // offset from this uncommontype to [mcount]Method_ uint32 // unused}func ( *UncommonType) () []Method {if .Mcount == 0 {return nil}return (*[1 << 16]Method)(addChecked(unsafe.Pointer(), uintptr(.Moff), "t.mcount > 0"))[:.Mcount:.Mcount]}func ( *UncommonType) () []Method {if .Xcount == 0 {return nil}return (*[1 << 16]Method)(addChecked(unsafe.Pointer(), uintptr(.Moff), "t.xcount > 0"))[:.Xcount:.Xcount]}// addChecked returns p+x.//// The whySafe string is ignored, so that the function still inlines// as efficiently as p+x, but all call sites should use the string to// record why the addition is safe, which is to say why the addition// does not cause x to advance to the very end of p's allocation// and therefore point incorrectly at the next block in memory.func ( unsafe.Pointer, uintptr, string) unsafe.Pointer {return unsafe.Pointer(uintptr() + )}// Imethod represents a method on an interface typetype Imethod struct {Name NameOff // name of methodTyp TypeOff // .(*FuncType) underneath}// ArrayType represents a fixed array type.type ArrayType struct {TypeElem *Type // array element typeSlice *Type // slice typeLen uintptr}// Len returns the length of t if t is an array type, otherwise 0func ( *Type) () int {if .Kind() == Array {return int((*ArrayType)(unsafe.Pointer()).Len)}return 0}func ( *Type) () *Type {return}type ChanDir intconst (RecvDir ChanDir = 1 << iota // <-chanSendDir // chan<-BothDir = RecvDir | SendDir // chanInvalidDir ChanDir = 0)// ChanType represents a channel typetype ChanType struct {TypeElem *TypeDir ChanDir}type structTypeUncommon struct {StructTypeu UncommonType}// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0).func ( *Type) () ChanDir {if .Kind() == Chan {:= (*ChanType)(unsafe.Pointer())return .Dir}return InvalidDir}// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nilfunc ( *Type) () *UncommonType {if .TFlag&TFlagUncommon == 0 {return nil}switch .Kind() {case Struct:return &(*structTypeUncommon)(unsafe.Pointer()).ucase Pointer:type struct {PtrTypeUncommonType}return &(*)(unsafe.Pointer()).case Func:type struct {FuncTypeUncommonType}return &(*)(unsafe.Pointer()).case Slice:type struct {SliceTypeUncommonType}return &(*)(unsafe.Pointer()).case Array:type struct {ArrayTypeUncommonType}return &(*)(unsafe.Pointer()).case Chan:type struct {ChanTypeUncommonType}return &(*)(unsafe.Pointer()).case Map:type struct {MapTypeUncommonType}return &(*)(unsafe.Pointer()).case Interface:type struct {InterfaceTypeUncommonType}return &(*)(unsafe.Pointer()).default:type struct {TypeUncommonType}return &(*)(unsafe.Pointer()).}}// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.func ( *Type) () *Type {switch .Kind() {case Array::= (*ArrayType)(unsafe.Pointer())return .Elemcase Chan::= (*ChanType)(unsafe.Pointer())return .Elemcase Map::= (*MapType)(unsafe.Pointer())return .Elemcase Pointer::= (*PtrType)(unsafe.Pointer())return .Elemcase Slice::= (*SliceType)(unsafe.Pointer())return .Elem}return nil}// StructType returns t cast to a *StructType, or nil if its tag does not match.func ( *Type) () *StructType {if .Kind() != Struct {return nil}return (*StructType)(unsafe.Pointer())}// MapType returns t cast to a *MapType, or nil if its tag does not match.func ( *Type) () *MapType {if .Kind() != Map {return nil}return (*MapType)(unsafe.Pointer())}// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match.func ( *Type) () *ArrayType {if .Kind() != Array {return nil}return (*ArrayType)(unsafe.Pointer())}// FuncType returns t cast to a *FuncType, or nil if its tag does not match.func ( *Type) () *FuncType {if .Kind() != Func {return nil}return (*FuncType)(unsafe.Pointer())}// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match.func ( *Type) () *InterfaceType {if .Kind() != Interface {return nil}return (*InterfaceType)(unsafe.Pointer())}// Size returns the size of data with type t.func ( *Type) () uintptr { return .Size_ }// Align returns the alignment of data with type t.func ( *Type) () int { return int(.Align_) }func ( *Type) () int { return int(.FieldAlign_) }type InterfaceType struct {TypePkgPath Name // import pathMethods []Imethod // sorted by hash}func ( *Type) () []Method {:= .Uncommon()if == nil {return nil}return .ExportedMethods()}func ( *Type) () int {if .Kind() == Interface {:= (*InterfaceType)(unsafe.Pointer())return .NumMethod()}return len(.ExportedMethods())}// NumMethod returns the number of interface methods in the type's method set.func ( *InterfaceType) () int { return len(.Methods) }type MapType struct {TypeKey *TypeElem *TypeBucket *Type // internal type representing a hash bucket// function for hashing keys (ptr to key, seed) -> hashHasher func(unsafe.Pointer, uintptr) uintptrKeySize uint8 // size of key slotValueSize uint8 // size of elem slotBucketSize uint16 // size of bucketFlags uint32}// Note: flag values must match those used in the TMAP case// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.func ( *MapType) () bool { // store ptr to key instead of key itselfreturn .Flags&1 != 0}func ( *MapType) () bool { // store ptr to elem instead of elem itselfreturn .Flags&2 != 0}func ( *MapType) () bool { // true if k==k for all keysreturn .Flags&4 != 0}func ( *MapType) () bool { // true if we need to update key on an overwritereturn .Flags&8 != 0}func ( *MapType) () bool { // true if hash function might panicreturn .Flags&16 != 0}func ( *Type) () *Type {if .Kind() == Map {return (*MapType)(unsafe.Pointer()).Key}return nil}type SliceType struct {TypeElem *Type // slice element type}// funcType represents a function type.//// A *Type for each in and out parameter is stored in an array that// directly follows the funcType (and possibly its uncommonType). So// a function type with one method, one input, and one output is://// struct {// funcType// uncommonType// [2]*rtype // [0] is in, [1] is out// }type FuncType struct {TypeInCount uint16OutCount uint16 // top bit is set if last input parameter is ...}func ( *FuncType) ( int) *Type {return .InSlice()[]}func ( *FuncType) () int {return int(.InCount)}func ( *FuncType) () int {return int(.OutCount & (1<<15 - 1))}func ( *FuncType) ( int) *Type {return (.OutSlice()[])}func ( *FuncType) () []*Type {:= unsafe.Sizeof(*)if .TFlag&TFlagUncommon != 0 {+= unsafe.Sizeof(UncommonType{})}if .InCount == 0 {return nil}return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(), , "t.inCount > 0"))[:.InCount:.InCount]}func ( *FuncType) () []*Type {:= uint16(.NumOut())if == 0 {return nil}:= unsafe.Sizeof(*)if .TFlag&TFlagUncommon != 0 {+= unsafe.Sizeof(UncommonType{})}return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(), , "outCount > 0"))[.InCount : .InCount+ : .InCount+]}func ( *FuncType) () bool {return .OutCount&(1<<15) != 0}type PtrType struct {TypeElem *Type // pointer element (pointed at) type}type StructField struct {Name Name // name is always non-emptyTyp *Type // type of fieldOffset uintptr // byte offset of field}func ( *StructField) () bool {return .Name.IsEmbedded()}type StructType struct {TypePkgPath NameFields []StructField}// Name is an encoded type Name with optional extra data.//// The first byte is a bit field containing://// 1<<0 the name is exported// 1<<1 tag data follows the name// 1<<2 pkgPath nameOff follows the name and tag// 1<<3 the name is of an embedded (a.k.a. anonymous) field//// Following that, there is a varint-encoded length of the name,// followed by the name itself.//// If tag data is present, it also has a varint-encoded length// followed by the tag itself.//// If the import path follows, then 4 bytes at the end of// the data form a nameOff. The import path is only set for concrete// methods that are defined in a different package than their type.//// If a name starts with "*", then the exported bit represents// whether the pointed to type is exported.//// Note: this encoding must match here and in:// cmd/compile/internal/reflectdata/reflect.go// cmd/link/internal/ld/decodesym.gotype Name struct {Bytes *byte}// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to// be safe for the reason in whySafe (which can appear in a backtrace, etc.)func ( Name) ( int, string) *byte {return (*byte)(addChecked(unsafe.Pointer(.Bytes), uintptr(), ))}// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to// be safe because the runtime made the call (other packages use DataChecked)func ( Name) ( int) *byte {return (*byte)(addChecked(unsafe.Pointer(.Bytes), uintptr(), "the runtime doesn't need to give you a reason"))}// IsExported returns "is n exported?"func ( Name) () bool {return (*.Bytes)&(1<<0) != 0}// HasTag returns true iff there is tag data following this namefunc ( Name) () bool {return (*.Bytes)&(1<<1) != 0}// IsEmbedded returns true iff n is embedded (an anonymous field).func ( Name) () bool {return (*.Bytes)&(1<<3) != 0}// ReadVarint parses a varint as encoded by encoding/binary.// It returns the number of encoded bytes and the encoded value.func ( Name) ( int) (int, int) {:= 0for := 0; ; ++ {:= *.DataChecked(+, "read varint")+= int(&0x7f) << (7 * )if &0x80 == 0 {return + 1,}}}// IsBlank indicates whether n is "_".func ( Name) () bool {if .Bytes == nil {return false}, := .ReadVarint(1)return == 1 && *.Data(2) == '_'}// writeVarint writes n to buf in varint form. Returns the// number of bytes written. n must be nonnegative.// Writes at most 10 bytes.func ( []byte, int) int {for := 0; ; ++ {:= byte( & 0x7f)>>= 7if == 0 {[] =return + 1}[] = | 0x80}}// Name returns the tag string for n, or empty if there is none.func ( Name) () string {if .Bytes == nil {return ""}, := .ReadVarint(1)return unsafe.String(.DataChecked(1+, "non-empty string"), )}// Tag returns the tag string for n, or empty if there is none.func ( Name) () string {if !.HasTag() {return ""}, := .ReadVarint(1), := .ReadVarint(1 + + )return unsafe.String(.DataChecked(1+++, "non-empty string"), )}func (, string, , bool) Name {if len() >= 1<<29 {panic("abi.NewName: name too long: " + [:1024] + "...")}if len() >= 1<<29 {panic("abi.NewName: tag too long: " + [:1024] + "...")}var [10]bytevar [10]byte:= writeVarint([:], len()):= writeVarint([:], len())var byte:= 1 + + len()if {|= 1 << 0}if len() > 0 {+= + len()|= 1 << 1}if {|= 1 << 3}:= make([]byte, )[0] =copy([1:], [:])copy([1+:], )if len() > 0 {:= [1++len():]copy(, [:])copy([:], )}return Name{Bytes: &[0]}}const (TraceArgsLimit = 10 // print no more than 10 args/componentsTraceArgsMaxDepth = 5 // no more than 5 layers of nesting// maxLen is a (conservative) upper bound of the byte stream length. For// each arg/component, it has no more than 2 bytes of data (size, offset),// and no more than one {, }, ... at each level (it cannot have both the// data and ... unless it is the last one, just be conservative). Plus 1// for _endSeq.TraceArgsMaxLen = (TraceArgsMaxDepth*3+2)*TraceArgsLimit + 1)// Populate the data.// The data is a stream of bytes, which contains the offsets and sizes of the// non-aggregate arguments or non-aggregate fields/elements of aggregate-typed// arguments, along with special "operators". Specifically,// - for each non-aggregate arg/field/element, its offset from FP (1 byte) and// size (1 byte)// - special operators:// - 0xff - end of sequence// - 0xfe - print { (at the start of an aggregate-typed argument)// - 0xfd - print } (at the end of an aggregate-typed argument)// - 0xfc - print ... (more args/fields/elements)// - 0xfb - print _ (offset too large)const (TraceArgsEndSeq = 0xffTraceArgsStartAgg = 0xfeTraceArgsEndAgg = 0xfdTraceArgsDotdotdot = 0xfcTraceArgsOffsetTooLarge = 0xfbTraceArgsSpecial = 0xf0 // above this are operators, below this are ordinary offsets)// MaxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,// which holds 1-bit entries describing where pointers are in a given type.// Above this length, the GC information is recorded as a GC program,// which can express repetition compactly. In either form, the// information is used by the runtime to initialize the heap bitmap,// and for large types (like 128 or more words), they are roughly the// same speed. GC programs are never much larger and often more// compact. (If large arrays are involved, they can be arbitrarily// more compact.)//// The cutoff must be large enough that any allocation large enough to// use a GC program is large enough that it does not share heap bitmap// bytes with any other objects, allowing the GC program execution to// assume an aligned start and not use atomic operations. In the current// runtime, this means all malloc size classes larger than the cutoff must// be multiples of four words. On 32-bit systems that's 16 bytes, and// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated// is 32 pointers, the bits for which fit in 4 bytes. So MaxPtrmaskBytes// must be >= 4.//// We used to use 16 because the GC programs do have some constant overhead// to get started, and processing 128 pointers seems to be enough to// amortize that overhead well.//// To make sure that the runtime's chansend can call typeBitsBulkBarrier,// we raised the limit to 2048, so that even 32-bit systems are guaranteed to// use bitmaps for objects up to 64 kB in size.const MaxPtrmaskBytes = 2048
![]() |
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |