Source file
src/runtime/type.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/abi"
11 "unsafe"
12 )
13
14 type nameOff = abi.NameOff
15 type typeOff = abi.TypeOff
16 type textOff = abi.TextOff
17
18 type _type = abi.Type
19
20
21 type rtype struct {
22 *abi.Type
23 }
24
25 func (t rtype) string() string {
26 s := t.nameOff(t.Str).Name()
27 if t.TFlag&abi.TFlagExtraStar != 0 {
28 return s[1:]
29 }
30 return s
31 }
32
33 func (t rtype) uncommon() *uncommontype {
34 return t.Uncommon()
35 }
36
37 func (t rtype) name() string {
38 if t.TFlag&abi.TFlagNamed == 0 {
39 return ""
40 }
41 s := t.string()
42 i := len(s) - 1
43 sqBrackets := 0
44 for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
45 switch s[i] {
46 case ']':
47 sqBrackets++
48 case '[':
49 sqBrackets--
50 }
51 i--
52 }
53 return s[i+1:]
54 }
55
56
57
58
59
60 func (t rtype) pkgpath() string {
61 if u := t.uncommon(); u != nil {
62 return t.nameOff(u.PkgPath).Name()
63 }
64 switch t.Kind_ & abi.KindMask {
65 case abi.Struct:
66 st := (*structtype)(unsafe.Pointer(t.Type))
67 return st.PkgPath.Name()
68 case abi.Interface:
69 it := (*interfacetype)(unsafe.Pointer(t.Type))
70 return it.PkgPath.Name()
71 }
72 return ""
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 var reflectOffs struct {
89 lock mutex
90 next int32
91 m map[int32]unsafe.Pointer
92 minv map[unsafe.Pointer]int32
93 }
94
95 func reflectOffsLock() {
96 lock(&reflectOffs.lock)
97 if raceenabled {
98 raceacquire(unsafe.Pointer(&reflectOffs.lock))
99 }
100 }
101
102 func reflectOffsUnlock() {
103 if raceenabled {
104 racerelease(unsafe.Pointer(&reflectOffs.lock))
105 }
106 unlock(&reflectOffs.lock)
107 }
108
109
110
111
112
113
114
115
116
117
118 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
119 if off == 0 {
120 return name{}
121 }
122 base := uintptr(ptrInModule)
123 for md := &firstmoduledata; md != nil; md = md.next {
124 if base >= md.types && base < md.etypes {
125 res := md.types + uintptr(off)
126 if res > md.etypes {
127 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
128 throw("runtime: name offset out of range")
129 }
130 return name{Bytes: (*byte)(unsafe.Pointer(res))}
131 }
132 }
133
134
135 reflectOffsLock()
136 res, found := reflectOffs.m[int32(off)]
137 reflectOffsUnlock()
138 if !found {
139 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
140 for next := &firstmoduledata; next != nil; next = next.next {
141 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
142 }
143 throw("runtime: name offset base pointer out of range")
144 }
145 return name{Bytes: (*byte)(res)}
146 }
147
148 func (t rtype) nameOff(off nameOff) name {
149 return resolveNameOff(unsafe.Pointer(t.Type), off)
150 }
151
152
153
154
155
156
157
158
159
160
161 func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
162 if off == 0 || off == -1 {
163
164
165 return nil
166 }
167 base := uintptr(ptrInModule)
168 var md *moduledata
169 for next := &firstmoduledata; next != nil; next = next.next {
170 if base >= next.types && base < next.etypes {
171 md = next
172 break
173 }
174 }
175 if md == nil {
176 reflectOffsLock()
177 res := reflectOffs.m[int32(off)]
178 reflectOffsUnlock()
179 if res == nil {
180 println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
181 for next := &firstmoduledata; next != nil; next = next.next {
182 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
183 }
184 throw("runtime: type offset base pointer out of range")
185 }
186 return (*_type)(res)
187 }
188 if t := md.typemap[off]; t != nil {
189 return t
190 }
191 res := md.types + uintptr(off)
192 if res > md.etypes {
193 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
194 throw("runtime: type offset out of range")
195 }
196 return (*_type)(unsafe.Pointer(res))
197 }
198
199 func (t rtype) typeOff(off typeOff) *_type {
200 return resolveTypeOff(unsafe.Pointer(t.Type), off)
201 }
202
203 func (t rtype) textOff(off textOff) unsafe.Pointer {
204 if off == -1 {
205
206
207 return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
208 }
209 base := uintptr(unsafe.Pointer(t.Type))
210 var md *moduledata
211 for next := &firstmoduledata; next != nil; next = next.next {
212 if base >= next.types && base < next.etypes {
213 md = next
214 break
215 }
216 }
217 if md == nil {
218 reflectOffsLock()
219 res := reflectOffs.m[int32(off)]
220 reflectOffsUnlock()
221 if res == nil {
222 println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
223 for next := &firstmoduledata; next != nil; next = next.next {
224 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
225 }
226 throw("runtime: text offset base pointer out of range")
227 }
228 return res
229 }
230 res := md.textAddr(uint32(off))
231 return unsafe.Pointer(res)
232 }
233
234 type uncommontype = abi.UncommonType
235
236 type interfacetype = abi.InterfaceType
237
238 type maptype = abi.MapType
239
240 type arraytype = abi.ArrayType
241
242 type chantype = abi.ChanType
243
244 type slicetype = abi.SliceType
245
246 type functype = abi.FuncType
247
248 type ptrtype = abi.PtrType
249
250 type name = abi.Name
251
252 type structtype = abi.StructType
253
254 func pkgPath(n name) string {
255 if n.Bytes == nil || *n.Data(0)&(1<<2) == 0 {
256 return ""
257 }
258 i, l := n.ReadVarint(1)
259 off := 1 + i + l
260 if *n.Data(0)&(1<<1) != 0 {
261 i2, l2 := n.ReadVarint(off)
262 off += i2 + l2
263 }
264 var nameOff nameOff
265 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.Data(off)))[:])
266 pkgPathName := resolveNameOff(unsafe.Pointer(n.Bytes), nameOff)
267 return pkgPathName.Name()
268 }
269
270
271
272 func typelinksinit() {
273 if firstmoduledata.next == nil {
274 return
275 }
276 typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
277
278 modules := activeModules()
279 prev := modules[0]
280 for _, md := range modules[1:] {
281
282 collect:
283 for _, tl := range prev.typelinks {
284 var t *_type
285 if prev.typemap == nil {
286 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
287 } else {
288 t = prev.typemap[typeOff(tl)]
289 }
290
291 tlist := typehash[t.Hash]
292 for _, tcur := range tlist {
293 if tcur == t {
294 continue collect
295 }
296 }
297 typehash[t.Hash] = append(tlist, t)
298 }
299
300 if md.typemap == nil {
301
302
303
304 tm := make(map[typeOff]*_type, len(md.typelinks))
305 pinnedTypemaps = append(pinnedTypemaps, tm)
306 md.typemap = tm
307 for _, tl := range md.typelinks {
308 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
309 for _, candidate := range typehash[t.Hash] {
310 seen := map[_typePair]struct{}{}
311 if typesEqual(t, candidate, seen) {
312 t = candidate
313 break
314 }
315 }
316 md.typemap[typeOff(tl)] = t
317 }
318 }
319
320 prev = md
321 }
322 }
323
324 type _typePair struct {
325 t1 *_type
326 t2 *_type
327 }
328
329 func toRType(t *abi.Type) rtype {
330 return rtype{t}
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344
345 func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
346 tp := _typePair{t, v}
347 if _, ok := seen[tp]; ok {
348 return true
349 }
350
351
352
353
354 seen[tp] = struct{}{}
355
356 if t == v {
357 return true
358 }
359 kind := t.Kind_ & abi.KindMask
360 if kind != v.Kind_&abi.KindMask {
361 return false
362 }
363 rt, rv := toRType(t), toRType(v)
364 if rt.string() != rv.string() {
365 return false
366 }
367 ut := t.Uncommon()
368 uv := v.Uncommon()
369 if ut != nil || uv != nil {
370 if ut == nil || uv == nil {
371 return false
372 }
373 pkgpatht := rt.nameOff(ut.PkgPath).Name()
374 pkgpathv := rv.nameOff(uv.PkgPath).Name()
375 if pkgpatht != pkgpathv {
376 return false
377 }
378 }
379 if abi.Bool <= kind && kind <= abi.Complex128 {
380 return true
381 }
382 switch kind {
383 case abi.String, abi.UnsafePointer:
384 return true
385 case abi.Array:
386 at := (*arraytype)(unsafe.Pointer(t))
387 av := (*arraytype)(unsafe.Pointer(v))
388 return typesEqual(at.Elem, av.Elem, seen) && at.Len == av.Len
389 case abi.Chan:
390 ct := (*chantype)(unsafe.Pointer(t))
391 cv := (*chantype)(unsafe.Pointer(v))
392 return ct.Dir == cv.Dir && typesEqual(ct.Elem, cv.Elem, seen)
393 case abi.Func:
394 ft := (*functype)(unsafe.Pointer(t))
395 fv := (*functype)(unsafe.Pointer(v))
396 if ft.OutCount != fv.OutCount || ft.InCount != fv.InCount {
397 return false
398 }
399 tin, vin := ft.InSlice(), fv.InSlice()
400 for i := 0; i < len(tin); i++ {
401 if !typesEqual(tin[i], vin[i], seen) {
402 return false
403 }
404 }
405 tout, vout := ft.OutSlice(), fv.OutSlice()
406 for i := 0; i < len(tout); i++ {
407 if !typesEqual(tout[i], vout[i], seen) {
408 return false
409 }
410 }
411 return true
412 case abi.Interface:
413 it := (*interfacetype)(unsafe.Pointer(t))
414 iv := (*interfacetype)(unsafe.Pointer(v))
415 if it.PkgPath.Name() != iv.PkgPath.Name() {
416 return false
417 }
418 if len(it.Methods) != len(iv.Methods) {
419 return false
420 }
421 for i := range it.Methods {
422 tm := &it.Methods[i]
423 vm := &iv.Methods[i]
424
425
426 tname := resolveNameOff(unsafe.Pointer(tm), tm.Name)
427 vname := resolveNameOff(unsafe.Pointer(vm), vm.Name)
428 if tname.Name() != vname.Name() {
429 return false
430 }
431 if pkgPath(tname) != pkgPath(vname) {
432 return false
433 }
434 tityp := resolveTypeOff(unsafe.Pointer(tm), tm.Typ)
435 vityp := resolveTypeOff(unsafe.Pointer(vm), vm.Typ)
436 if !typesEqual(tityp, vityp, seen) {
437 return false
438 }
439 }
440 return true
441 case abi.Map:
442 mt := (*maptype)(unsafe.Pointer(t))
443 mv := (*maptype)(unsafe.Pointer(v))
444 return typesEqual(mt.Key, mv.Key, seen) && typesEqual(mt.Elem, mv.Elem, seen)
445 case abi.Pointer:
446 pt := (*ptrtype)(unsafe.Pointer(t))
447 pv := (*ptrtype)(unsafe.Pointer(v))
448 return typesEqual(pt.Elem, pv.Elem, seen)
449 case abi.Slice:
450 st := (*slicetype)(unsafe.Pointer(t))
451 sv := (*slicetype)(unsafe.Pointer(v))
452 return typesEqual(st.Elem, sv.Elem, seen)
453 case abi.Struct:
454 st := (*structtype)(unsafe.Pointer(t))
455 sv := (*structtype)(unsafe.Pointer(v))
456 if len(st.Fields) != len(sv.Fields) {
457 return false
458 }
459 if st.PkgPath.Name() != sv.PkgPath.Name() {
460 return false
461 }
462 for i := range st.Fields {
463 tf := &st.Fields[i]
464 vf := &sv.Fields[i]
465 if tf.Name.Name() != vf.Name.Name() {
466 return false
467 }
468 if !typesEqual(tf.Typ, vf.Typ, seen) {
469 return false
470 }
471 if tf.Name.Tag() != vf.Name.Tag() {
472 return false
473 }
474 if tf.Offset != vf.Offset {
475 return false
476 }
477 if tf.Name.IsEmbedded() != vf.Name.IsEmbedded() {
478 return false
479 }
480 }
481 return true
482 default:
483 println("runtime: impossible type kind", kind)
484 throw("runtime: impossible type kind")
485 return false
486 }
487 }
488
View as plain text