summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/type.go
blob: 94abbb8e9f89cf8d07b2afd8b64b3254248d0987 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// 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 {
	return *t._string
}

// 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]))
}