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	"internal/abi"
11	"unsafe"
12)
13
14type nameOff = abi.NameOff
15type typeOff = abi.TypeOff
16type textOff = abi.TextOff
17
18type _type = abi.Type
19
20// rtype is a wrapper that allows us to define additional methods.
21type rtype struct {
22	*abi.Type // embedding is okay here (unlike reflect) because none of this is public
23}
24
25func (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
33func (t rtype) uncommon() *uncommontype {
34	return t.Uncommon()
35}
36
37func (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// pkgpath returns the path of the package where t was defined, if
57// available. This is not the same as the reflect package's PkgPath
58// method, in that it returns the package path for struct and interface
59// types, not just named types.
60func (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// reflectOffs holds type offsets defined at run time by the reflect package.
76//
77// When a type is defined at run time, its *rtype data lives on the heap.
78// There are a wide range of possible addresses the heap may use, that
79// may not be representable as a 32-bit offset. Moreover the GC may
80// one day start moving heap memory, in which case there is no stable
81// offset that can be defined.
82//
83// To provide stable offsets, we add pin *rtype objects in a global map
84// and treat the offset as an identifier. We use negative offsets that
85// do not overlap with any compile-time module offsets.
86//
87// Entries are created by reflect.addReflectOff.
88var reflectOffs struct {
89	lock mutex
90	next int32
91	m    map[int32]unsafe.Pointer
92	minv map[unsafe.Pointer]int32
93}
94
95func reflectOffsLock() {
96	lock(&reflectOffs.lock)
97	if raceenabled {
98		raceacquire(unsafe.Pointer(&reflectOffs.lock))
99	}
100}
101
102func reflectOffsUnlock() {
103	if raceenabled {
104		racerelease(unsafe.Pointer(&reflectOffs.lock))
105	}
106	unlock(&reflectOffs.lock)
107}
108
109// resolveNameOff should be an internal detail,
110// but widely used packages access it using linkname.
111// Notable members of the hall of shame include:
112//   - github.com/cloudwego/frugal
113//
114// Do not remove or change the type signature.
115// See go.dev/issue/67401.
116//
117//go:linkname resolveNameOff
118func 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	// No module found. see if it is a run time name.
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
148func (t rtype) nameOff(off nameOff) name {
149	return resolveNameOff(unsafe.Pointer(t.Type), off)
150}
151
152// resolveTypeOff should be an internal detail,
153// but widely used packages access it using linkname.
154// Notable members of the hall of shame include:
155//   - github.com/cloudwego/frugal
156//
157// Do not remove or change the type signature.
158// See go.dev/issue/67401.
159//
160//go:linkname resolveTypeOff
161func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
162	if off == 0 || off == -1 {
163		// -1 is the sentinel value for unreachable code.
164		// See cmd/link/internal/ld/data.go:relocsym.
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
199func (t rtype) typeOff(off typeOff) *_type {
200	return resolveTypeOff(unsafe.Pointer(t.Type), off)
201}
202
203func (t rtype) textOff(off textOff) unsafe.Pointer {
204	if off == -1 {
205		// -1 is the sentinel value for unreachable code.
206		// See cmd/link/internal/ld/data.go:relocsym.
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
234type uncommontype = abi.UncommonType
235
236type interfacetype = abi.InterfaceType
237
238type maptype = abi.MapType
239
240type arraytype = abi.ArrayType
241
242type chantype = abi.ChanType
243
244type slicetype = abi.SliceType
245
246type functype = abi.FuncType
247
248type ptrtype = abi.PtrType
249
250type name = abi.Name
251
252type structtype = abi.StructType
253
254func 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// typelinksinit scans the types from extra modules and builds the
271// moduledata typemap used to de-duplicate type pointers.
272func 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		// Collect types from the previous module into typehash.
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			// Add to typehash if not seen before.
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			// If any of this module's typelinks match a type from a
302			// prior module, prefer that prior type by adding the offset
303			// to this module's typemap.
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
324type _typePair struct {
325	t1 *_type
326	t2 *_type
327}
328
329func toRType(t *abi.Type) rtype {
330	return rtype{t}
331}
332
333// typesEqual reports whether two types are equal.
334//
335// Everywhere in the runtime and reflect packages, it is assumed that
336// there is exactly one *_type per Go type, so that pointer equality
337// can be used to test if types are equal. There is one place that
338// breaks this assumption: buildmode=shared. In this case a type can
339// appear as two different pieces of memory. This is hidden from the
340// runtime and reflect package by the per-module typemap built in
341// typelinksinit. It uses typesEqual to map types from later modules
342// back into earlier ones.
343//
344// Only typelinksinit needs this function.
345func 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	// mark these types as seen, and thus equivalent which prevents an infinite loop if
352	// the two types are identical, but recursively defined and loaded from
353	// different modules
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			// Note the mhdr array can be relocated from
425			// another module. See #17724.
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