blob: 56b4fe6a111c34103ba5972565b6544d1469fa71 [file] [log] [blame]
// 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 (
"runtime/internal/atomic"
"runtime/internal/sys"
"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
)
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/gc/reflect.go:dtypesym.
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)*sys.PtrSize))
typelist.types[typ.string()] = uintptr(unsafe.Pointer(typ))
}
}
atomic.Store(&typelist.initialized, 1)
}
unlock(&typelistLock)
}
return (*_type)(unsafe.Pointer(typelist.types[s]))
}