// Copyright 2009 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. // Runtime type representation. package runtime import ( "internal/goarch" "runtime/internal/atomic" "unsafe" ) // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: // go/types.cc // reflect/type.go // internal/reflectlite/type.go type tflag uint8 const ( tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes ) // Needs to be in sync with // go/types.cc // ../reflect/type.go:/^type.rtype. // ../internal/reflectlite/type.go:/^type.rtype. type _type struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 // 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 _string *string *uncommontype ptrToThis *_type } func (t *_type) string() string { // For gccgo, try to strip out quoted strings. s := *t._string q := false started := false var start int var end int for i := 0; i < len(s); i++ { if s[i] == '\t' { q = !q } else if !q { if !started { start = i started = true } end = i } } return s[start : end+1] } // pkgpath returns the path of the package where t was defined, if // available. This is not the same as the reflect package's PkgPath // method, in that it returns the package path for struct and interface // types, not just named types. func (t *_type) pkgpath() string { if u := t.uncommontype; u != nil { if u.pkgPath == nil { return "" } return *u.pkgPath } return "" } type method struct { name *string pkgPath *string mtyp *_type typ *_type tfn unsafe.Pointer } type uncommontype struct { name *string pkgPath *string methods []method } type imethod struct { name *string pkgPath *string typ *_type } type interfacetype struct { typ _type methods []imethod } type maptype struct { typ _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 elemsize uint8 // size of elem slot bucketsize uint16 // size of bucket flags uint32 } // Note: flag values must match those used in the TMAP case // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself return mt.flags&1 != 0 } func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself return mt.flags&2 != 0 } func (mt *maptype) reflexivekey() bool { // true if k==k for all keys return mt.flags&4 != 0 } func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite return mt.flags&8 != 0 } func (mt *maptype) hashMightPanic() bool { // true if hash function might panic return mt.flags&16 != 0 } type arraytype struct { typ _type elem *_type slice *_type len uintptr } type chantype struct { typ _type elem *_type dir uintptr } type slicetype struct { typ _type elem *_type } type functype struct { typ _type dotdotdot bool in []*_type out []*_type } type ptrtype struct { typ _type elem *_type } type structfield struct { name *string // nil for embedded fields pkgPath *string // nil for exported Names; otherwise import path typ *_type // type of field tag *string // nil if no tag offsetAnon uintptr // byte offset of field<<1 | isAnonymous } func (f *structfield) offset() uintptr { return f.offsetAnon >> 1 } func (f *structfield) anon() bool { return f.offsetAnon&1 != 0 } type structtype struct { typ _type fields []structfield } // typeDescriptorList holds a list of type descriptors generated // by the compiler. This is used for the compiler to register // type descriptors to the runtime. // The layout is known to the compiler. //go:notinheap type typeDescriptorList struct { count int types [1]uintptr // variable length } // typelist holds all type descriptors generated by the comiler. // This is for the reflect package to deduplicate type descriptors // when it creates a type that is also a compiler-generated type. var typelist struct { initialized uint32 lists []*typeDescriptorList // one element per package types map[string]uintptr // map from a type's string to *_type, lazily populated // TODO: use a sorted array instead? } var typelistLock mutex // The compiler generates a call of this function in the main // package's init function, to register compiler-generated // type descriptors. // p points to a list of *typeDescriptorList, n is the length // of the list. //go:linkname registerTypeDescriptors func registerTypeDescriptors(n int, p unsafe.Pointer) { *(*slice)(unsafe.Pointer(&typelist.lists)) = slice{p, n, n} } // The reflect package uses this function to look up a compiler- // generated type descriptor. //go:linkname reflect_lookupType reflect.lookupType func reflect_lookupType(s string) *_type { // Lazy initialization. We don't need to do this if we never create // types through reflection. if atomic.Load(&typelist.initialized) == 0 { lock(&typelistLock) if atomic.Load(&typelist.initialized) == 0 { n := 0 for _, list := range typelist.lists { n += list.count } typelist.types = make(map[string]uintptr, n) for _, list := range typelist.lists { for i := 0; i < list.count; i++ { typ := *(**_type)(add(unsafe.Pointer(&list.types), uintptr(i)*goarch.PtrSize)) typelist.types[typ.string()] = uintptr(unsafe.Pointer(typ)) } } atomic.Store(&typelist.initialized, 1) } unlock(&typelistLock) } return (*_type)(unsafe.Pointer(typelist.types[s])) }