1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Runtime type representation.
6
7package runtime
8
9import (
10	"runtime/internal/atomic"
11	"runtime/internal/sys"
12	"unsafe"
13)
14
15// tflag is documented in reflect/type.go.
16//
17// tflag values must be kept in sync with copies in:
18//	go/types.cc
19//	reflect/type.go
20//      internal/reflectlite/type.go
21type tflag uint8
22
23const (
24	tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
25)
26
27type _type struct {
28	size       uintptr
29	ptrdata    uintptr
30	hash       uint32
31	tflag      tflag
32	align      uint8
33	fieldAlign uint8
34	kind       uint8
35	// function for comparing objects of this type
36	// (ptr to object A, ptr to object B) -> ==?
37	equal func(unsafe.Pointer, unsafe.Pointer) bool
38	// gcdata stores the GC type data for the garbage collector.
39	// If the KindGCProg bit is set in kind, gcdata is a GC program.
40	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
41	gcdata  *byte
42	_string *string
43	*uncommontype
44	ptrToThis *_type
45}
46
47func (t *_type) string() string {
48	return *t._string
49}
50
51// pkgpath returns the path of the package where t was defined, if
52// available. This is not the same as the reflect package's PkgPath
53// method, in that it returns the package path for struct and interface
54// types, not just named types.
55func (t *_type) pkgpath() string {
56	if u := t.uncommontype; u != nil {
57		if u.pkgPath == nil {
58			return ""
59		}
60		return *u.pkgPath
61	}
62	return ""
63}
64
65type method struct {
66	name    *string
67	pkgPath *string
68	mtyp    *_type
69	typ     *_type
70	tfn     unsafe.Pointer
71}
72
73type uncommontype struct {
74	name    *string
75	pkgPath *string
76	methods []method
77}
78
79type imethod struct {
80	name    *string
81	pkgPath *string
82	typ     *_type
83}
84
85type interfacetype struct {
86	typ     _type
87	methods []imethod
88}
89
90type maptype struct {
91	typ    _type
92	key    *_type
93	elem   *_type
94	bucket *_type // internal type representing a hash bucket
95	// function for hashing keys (ptr to key, seed) -> hash
96	hasher     func(unsafe.Pointer, uintptr) uintptr
97	keysize    uint8  // size of key slot
98	elemsize   uint8  // size of elem slot
99	bucketsize uint16 // size of bucket
100	flags      uint32
101}
102
103// Note: flag values must match those used in the TMAP case
104// in ../cmd/compile/internal/gc/reflect.go:dtypesym.
105func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
106	return mt.flags&1 != 0
107}
108func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself
109	return mt.flags&2 != 0
110}
111func (mt *maptype) reflexivekey() bool { // true if k==k for all keys
112	return mt.flags&4 != 0
113}
114func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite
115	return mt.flags&8 != 0
116}
117func (mt *maptype) hashMightPanic() bool { // true if hash function might panic
118	return mt.flags&16 != 0
119}
120
121type arraytype struct {
122	typ   _type
123	elem  *_type
124	slice *_type
125	len   uintptr
126}
127
128type chantype struct {
129	typ  _type
130	elem *_type
131	dir  uintptr
132}
133
134type slicetype struct {
135	typ  _type
136	elem *_type
137}
138
139type functype struct {
140	typ       _type
141	dotdotdot bool
142	in        []*_type
143	out       []*_type
144}
145
146type ptrtype struct {
147	typ  _type
148	elem *_type
149}
150
151type structfield struct {
152	name       *string // nil for embedded fields
153	pkgPath    *string // nil for exported Names; otherwise import path
154	typ        *_type  // type of field
155	tag        *string // nil if no tag
156	offsetAnon uintptr // byte offset of field<<1 | isAnonymous
157}
158
159func (f *structfield) offset() uintptr {
160	return f.offsetAnon >> 1
161}
162
163func (f *structfield) anon() bool {
164	return f.offsetAnon&1 != 0
165}
166
167type structtype struct {
168	typ    _type
169	fields []structfield
170}
171
172// typeDescriptorList holds a list of type descriptors generated
173// by the compiler. This is used for the compiler to register
174// type descriptors to the runtime.
175// The layout is known to the compiler.
176//go:notinheap
177type typeDescriptorList struct {
178	count int
179	types [1]uintptr // variable length
180}
181
182// typelist holds all type descriptors generated by the comiler.
183// This is for the reflect package to deduplicate type descriptors
184// when it creates a type that is also a compiler-generated type.
185var typelist struct {
186	initialized uint32
187	lists       []*typeDescriptorList // one element per package
188	types       map[string]uintptr    // map from a type's string to *_type, lazily populated
189	// TODO: use a sorted array instead?
190}
191var typelistLock mutex
192
193// The compiler generates a call of this function in the main
194// package's init function, to register compiler-generated
195// type descriptors.
196// p points to a list of *typeDescriptorList, n is the length
197// of the list.
198//go:linkname registerTypeDescriptors
199func registerTypeDescriptors(n int, p unsafe.Pointer) {
200	*(*slice)(unsafe.Pointer(&typelist.lists)) = slice{p, n, n}
201}
202
203// The reflect package uses this function to look up a compiler-
204// generated type descriptor.
205//go:linkname reflect_lookupType reflect.lookupType
206func reflect_lookupType(s string) *_type {
207	// Lazy initialization. We don't need to do this if we never create
208	// types through reflection.
209	if atomic.Load(&typelist.initialized) == 0 {
210		lock(&typelistLock)
211		if atomic.Load(&typelist.initialized) == 0 {
212			n := 0
213			for _, list := range typelist.lists {
214				n += list.count
215			}
216			typelist.types = make(map[string]uintptr, n)
217			for _, list := range typelist.lists {
218				for i := 0; i < list.count; i++ {
219					typ := *(**_type)(add(unsafe.Pointer(&list.types), uintptr(i)*sys.PtrSize))
220					typelist.types[typ.string()] = uintptr(unsafe.Pointer(typ))
221				}
222			}
223			atomic.Store(&typelist.initialized, 1)
224		}
225		unlock(&typelistLock)
226	}
227
228	return (*_type)(unsafe.Pointer(typelist.types[s]))
229}
230