251 lines
6.1 KiB
Go
251 lines
6.1 KiB
Go
// 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]))
|
|
}
|