/* * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package abi import ( "unsafe" ) // ----------------------------------------------------------------------------- // Type is the runtime representation of a Go type. // // Type is also referenced implicitly // (in the form of expressions involving constants and arch.PtrSize) // in cmd/compile/internal/reflectdata/reflect.go // and cmd/link/internal/ld/decodesym.go // (e.g. data[2*arch.PtrSize+4] references the TFlag field) // unsafe.OffsetOf(Type{}.TFlag) cannot be used directly in those // places because it varies with cross compilation and experiments. type Type struct { Size_ uintptr PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers Hash uint32 // hash of type; avoids computation in hash tables TFlag TFlag // extra type information flags Align_ uint8 // alignment of variable with this type FieldAlign_ uint8 // alignment of struct field with this type Kind_ uint8 // 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 *byte Str NameOff // string form PtrToThis TypeOff // type for pointer to this type, may be zero } func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) } // A Kind represents the specific kind of type that a Type represents. // The zero Kind is not a valid kind. type Kind uint const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Pointer Slice String Struct UnsafePointer ) const ( // TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible. KindDirectIface = 1 << 5 KindGCProg = 1 << 6 // Type.gc points to GC program KindMask = (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 uint8 const ( // 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)).u TFlagUncommon 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 ) // 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 // ----------------------------------------------------------------------------- // ArrayType represents a fixed array type. type ArrayType struct { Type Elem *Type // array element type Slice *Type // slice type Len uintptr } type SliceType struct { Type Elem *Type // slice element type } type MapType struct { Type Key *Type Elem *Type Bucket *Type // internal type representing a hash bucket // function for hashing keys (ptr to key, seed) -> hash Hasher func(unsafe.Pointer, uintptr) uintptr KeySize uint8 // size of key slot ValueSize uint8 // size of elem slot BucketSize uint16 // size of bucket Flags uint32 } type PtrType struct { Type Elem *Type // pointer element (pointed at) type } type ChanDir int const ( RecvDir ChanDir = 1 << iota // <-chan SendDir // chan<- BothDir = RecvDir | SendDir // chan InvalidDir ChanDir = 0 ) // ChanType represents a channel type type ChanType struct { Type Elem *Type Dir ChanDir } // 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 { Type InCount uint16 OutCount uint16 // top bit is set if last input parameter is ... } type StructField struct { Name Name // name is always non-empty Typ *Type // type of field Offset uintptr // byte offset of field } type StructType struct { Type PkgPath Name Fields []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.go type Name struct { Bytes *byte } type InterfaceType struct { Type PkgPath Name // import path Methods []Imethod // sorted by hash } // Imethod represents a method on an interface type type Imethod struct { Name NameOff // name of method Typ TypeOff // .(*FuncType) underneath } func (t *Type) Common() *Type { return t } // Len returns the length of t if t is an array type, otherwise 0 func (t *Type) Len() int { if t.Kind() == Array { return int((*ArrayType)(unsafe.Pointer(t)).Len) } return 0 } // Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil. func (t *Type) Elem() *Type { switch t.Kind() { case Array: tt := (*ArrayType)(unsafe.Pointer(t)) return tt.Elem case Chan: tt := (*ChanType)(unsafe.Pointer(t)) return tt.Elem case Map: tt := (*MapType)(unsafe.Pointer(t)) return tt.Elem case Pointer: tt := (*PtrType)(unsafe.Pointer(t)) return tt.Elem case Slice: tt := (*SliceType)(unsafe.Pointer(t)) return tt.Elem } return nil } // StructType returns t cast to a *StructType, or nil if its tag does not match. func (t *Type) StructType() *StructType { if t.Kind() != Struct { return nil } return (*StructType)(unsafe.Pointer(t)) } // MapType returns t cast to a *MapType, or nil if its tag does not match. func (t *Type) MapType() *MapType { if t.Kind() != Map { return nil } return (*MapType)(unsafe.Pointer(t)) } // ArrayType returns t cast to a *ArrayType, or nil if its tag does not match. func (t *Type) ArrayType() *ArrayType { if t.Kind() != Array { return nil } return (*ArrayType)(unsafe.Pointer(t)) } // FuncType returns t cast to a *FuncType, or nil if its tag does not match. func (t *Type) FuncType() *FuncType { if t.Kind() != Func { return nil } return (*FuncType)(unsafe.Pointer(t)) } // InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match. func (t *Type) InterfaceType() *InterfaceType { if t.Kind() != Interface { return nil } return (*InterfaceType)(unsafe.Pointer(t)) } // -----------------------------------------------------------------------------