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