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.
5 // Runtime type representation.
14 // tflag is documented in reflect/type.go.
16 // tflag values must be kept in sync with copies in:
17 // cmd/compile/internal/reflectdata/reflect.go
18 // cmd/link/internal/ld/decodesym.go
20 // internal/reflectlite/type.go
24 tflagUncommon tflag = 1 << 0
25 tflagExtraStar tflag = 1 << 1
26 tflagNamed tflag = 1 << 2
27 tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
30 // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
31 // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
32 // ../reflect/type.go:/^type.rtype.
33 // ../internal/reflectlite/type.go:/^type.rtype.
36 ptrdata uintptr // size of memory prefix holding all pointers
42 // function for comparing objects of this type
43 // (ptr to object A, ptr to object B) -> ==?
44 equal func(unsafe.Pointer, unsafe.Pointer) bool
45 // gcdata stores the GC type data for the garbage collector.
46 // If the KindGCProg bit is set in kind, gcdata is a GC program.
47 // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
53 func (t *_type) string() string {
54 s := t.nameOff(t.str).name()
55 if t.tflag&tflagExtraStar != 0 {
61 func (t *_type) uncommon() *uncommontype {
62 if t.tflag&tflagUncommon == 0 {
65 switch t.kind & kindMask {
71 return &(*u)(unsafe.Pointer(t)).u
77 return &(*u)(unsafe.Pointer(t)).u
83 return &(*u)(unsafe.Pointer(t)).u
89 return &(*u)(unsafe.Pointer(t)).u
95 return &(*u)(unsafe.Pointer(t)).u
101 return &(*u)(unsafe.Pointer(t)).u
107 return &(*u)(unsafe.Pointer(t)).u
113 return &(*u)(unsafe.Pointer(t)).u
119 return &(*u)(unsafe.Pointer(t)).u
123 func (t *_type) name() string {
124 if t.tflag&tflagNamed == 0 {
129 for i >= 0 && s[i] != '.' {
135 // pkgpath returns the path of the package where t was defined, if
136 // available. This is not the same as the reflect package's PkgPath
137 // method, in that it returns the package path for struct and interface
138 // types, not just named types.
139 func (t *_type) pkgpath() string {
140 if u := t.uncommon(); u != nil {
141 return t.nameOff(u.pkgpath).name()
143 switch t.kind & kindMask {
145 st := (*structtype)(unsafe.Pointer(t))
146 return st.pkgPath.name()
148 it := (*interfacetype)(unsafe.Pointer(t))
149 return it.pkgpath.name()
154 // reflectOffs holds type offsets defined at run time by the reflect package.
156 // When a type is defined at run time, its *rtype data lives on the heap.
157 // There are a wide range of possible addresses the heap may use, that
158 // may not be representable as a 32-bit offset. Moreover the GC may
159 // one day start moving heap memory, in which case there is no stable
160 // offset that can be defined.
162 // To provide stable offsets, we add pin *rtype objects in a global map
163 // and treat the offset as an identifier. We use negative offsets that
164 // do not overlap with any compile-time module offsets.
166 // Entries are created by reflect.addReflectOff.
167 var reflectOffs struct {
170 m map[int32]unsafe.Pointer
171 minv map[unsafe.Pointer]int32
174 func reflectOffsLock() {
175 lock(&reflectOffs.lock)
177 raceacquire(unsafe.Pointer(&reflectOffs.lock))
181 func reflectOffsUnlock() {
183 racerelease(unsafe.Pointer(&reflectOffs.lock))
185 unlock(&reflectOffs.lock)
188 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
192 base := uintptr(ptrInModule)
193 for md := &firstmoduledata; md != nil; md = md.next {
194 if base >= md.types && base < md.etypes {
195 res := md.types + uintptr(off)
197 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
198 throw("runtime: name offset out of range")
200 return name{(*byte)(unsafe.Pointer(res))}
204 // No module found. see if it is a run time name.
206 res, found := reflectOffs.m[int32(off)]
209 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
210 for next := &firstmoduledata; next != nil; next = next.next {
211 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
213 throw("runtime: name offset base pointer out of range")
215 return name{(*byte)(res)}
218 func (t *_type) nameOff(off nameOff) name {
219 return resolveNameOff(unsafe.Pointer(t), off)
222 func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
223 if off == 0 || off == -1 {
224 // -1 is the sentinel value for unreachable code.
225 // See cmd/link/internal/ld/data.go:relocsym.
228 base := uintptr(ptrInModule)
230 for next := &firstmoduledata; next != nil; next = next.next {
231 if base >= next.types && base < next.etypes {
238 res := reflectOffs.m[int32(off)]
241 println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
242 for next := &firstmoduledata; next != nil; next = next.next {
243 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
245 throw("runtime: type offset base pointer out of range")
249 if t := md.typemap[off]; t != nil {
252 res := md.types + uintptr(off)
254 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
255 throw("runtime: type offset out of range")
257 return (*_type)(unsafe.Pointer(res))
260 func (t *_type) typeOff(off typeOff) *_type {
261 return resolveTypeOff(unsafe.Pointer(t), off)
264 func (t *_type) textOff(off textOff) unsafe.Pointer {
266 // -1 is the sentinel value for unreachable code.
267 // See cmd/link/internal/ld/data.go:relocsym.
268 return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
270 base := uintptr(unsafe.Pointer(t))
272 for next := &firstmoduledata; next != nil; next = next.next {
273 if base >= next.types && base < next.etypes {
280 res := reflectOffs.m[int32(off)]
283 println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
284 for next := &firstmoduledata; next != nil; next = next.next {
285 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
287 throw("runtime: text offset base pointer out of range")
293 // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is
294 // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if
295 // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split
296 // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr
297 // for each text section is set to its offset within the text. Each method's offset is compared against the section
298 // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's
299 // relocated baseaddr to compute the method addess.
301 if len(md.textsectmap) > 1 {
302 for i := range md.textsectmap {
303 sectaddr := md.textsectmap[i].vaddr
304 sectlen := md.textsectmap[i].length
305 if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
306 res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
311 // single text section
312 res = md.text + uintptr(off)
315 if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
316 println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
317 throw("runtime: text offset out of range")
319 return unsafe.Pointer(res)
322 func (t *functype) in() []*_type {
323 // See funcType in reflect/type.go for details on data layout.
324 uadd := uintptr(unsafe.Sizeof(functype{}))
325 if t.typ.tflag&tflagUncommon != 0 {
326 uadd += unsafe.Sizeof(uncommontype{})
328 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
331 func (t *functype) out() []*_type {
332 // See funcType in reflect/type.go for details on data layout.
333 uadd := uintptr(unsafe.Sizeof(functype{}))
334 if t.typ.tflag&tflagUncommon != 0 {
335 uadd += unsafe.Sizeof(uncommontype{})
337 outCount := t.outCount & (1<<15 - 1)
338 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
341 func (t *functype) dotdotdot() bool {
342 return t.outCount&(1<<15) != 0
356 type uncommontype struct {
358 mcount uint16 // number of methods
359 xcount uint16 // number of exported methods
360 moff uint32 // offset from this uncommontype to [mcount]method
364 type imethod struct {
369 type interfacetype struct {
375 type maptype struct {
379 bucket *_type // internal type representing a hash bucket
380 // function for hashing keys (ptr to key, seed) -> hash
381 hasher func(unsafe.Pointer, uintptr) uintptr
382 keysize uint8 // size of key slot
383 elemsize uint8 // size of elem slot
384 bucketsize uint16 // size of bucket
388 // Note: flag values must match those used in the TMAP case
389 // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
390 func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
391 return mt.flags&1 != 0
393 func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself
394 return mt.flags&2 != 0
396 func (mt *maptype) reflexivekey() bool { // true if k==k for all keys
397 return mt.flags&4 != 0
399 func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite
400 return mt.flags&8 != 0
402 func (mt *maptype) hashMightPanic() bool { // true if hash function might panic
403 return mt.flags&16 != 0
406 type arraytype struct {
413 type chantype struct {
419 type slicetype struct {
424 type functype struct {
430 type ptrtype struct {
435 type structfield struct {
441 func (f *structfield) offset() uintptr {
442 return f.offsetAnon >> 1
445 type structtype struct {
451 // name is an encoded type name with optional extra data.
452 // See reflect/type.go for details.
457 func (n name) data(off int) *byte {
458 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
461 func (n name) isExported() bool {
462 return (*n.bytes)&(1<<0) != 0
465 func (n name) readvarint(off int) (int, int) {
468 x := *n.data(off + i)
469 v += int(x&0x7f) << (7 * i)
476 func (n name) name() (s string) {
480 i, l := n.readvarint(1)
484 hdr := (*stringStruct)(unsafe.Pointer(&s))
485 hdr.str = unsafe.Pointer(n.data(1 + i))
490 func (n name) tag() (s string) {
491 if *n.data(0)&(1<<1) == 0 {
494 i, l := n.readvarint(1)
495 i2, l2 := n.readvarint(1 + i + l)
496 hdr := (*stringStruct)(unsafe.Pointer(&s))
497 hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
502 func (n name) pkgPath() string {
503 if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
506 i, l := n.readvarint(1)
508 if *n.data(0)&(1<<1) != 0 {
509 i2, l2 := n.readvarint(off)
513 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
514 pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
515 return pkgPathName.name()
518 func (n name) isBlank() bool {
522 _, l := n.readvarint(1)
523 return l == 1 && *n.data(2) == '_'
526 // typelinksinit scans the types from extra modules and builds the
527 // moduledata typemap used to de-duplicate type pointers.
528 func typelinksinit() {
529 if firstmoduledata.next == nil {
532 typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
534 modules := activeModules()
536 for _, md := range modules[1:] {
537 // Collect types from the previous module into typehash.
539 for _, tl := range prev.typelinks {
541 if prev.typemap == nil {
542 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
544 t = prev.typemap[typeOff(tl)]
546 // Add to typehash if not seen before.
547 tlist := typehash[t.hash]
548 for _, tcur := range tlist {
553 typehash[t.hash] = append(tlist, t)
556 if md.typemap == nil {
557 // If any of this module's typelinks match a type from a
558 // prior module, prefer that prior type by adding the offset
559 // to this module's typemap.
560 tm := make(map[typeOff]*_type, len(md.typelinks))
561 pinnedTypemaps = append(pinnedTypemaps, tm)
563 for _, tl := range md.typelinks {
564 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
565 for _, candidate := range typehash[t.hash] {
566 seen := map[_typePair]struct{}{}
567 if typesEqual(t, candidate, seen) {
572 md.typemap[typeOff(tl)] = t
580 type _typePair struct {
585 // typesEqual reports whether two types are equal.
587 // Everywhere in the runtime and reflect packages, it is assumed that
588 // there is exactly one *_type per Go type, so that pointer equality
589 // can be used to test if types are equal. There is one place that
590 // breaks this assumption: buildmode=shared. In this case a type can
591 // appear as two different pieces of memory. This is hidden from the
592 // runtime and reflect package by the per-module typemap built in
593 // typelinksinit. It uses typesEqual to map types from later modules
594 // back into earlier ones.
596 // Only typelinksinit needs this function.
597 func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
598 tp := _typePair{t, v}
599 if _, ok := seen[tp]; ok {
603 // mark these types as seen, and thus equivalent which prevents an infinite loop if
604 // the two types are identical, but recursively defined and loaded from
606 seen[tp] = struct{}{}
611 kind := t.kind & kindMask
612 if kind != v.kind&kindMask {
615 if t.string() != v.string() {
620 if ut != nil || uv != nil {
621 if ut == nil || uv == nil {
624 pkgpatht := t.nameOff(ut.pkgpath).name()
625 pkgpathv := v.nameOff(uv.pkgpath).name()
626 if pkgpatht != pkgpathv {
630 if kindBool <= kind && kind <= kindComplex128 {
634 case kindString, kindUnsafePointer:
637 at := (*arraytype)(unsafe.Pointer(t))
638 av := (*arraytype)(unsafe.Pointer(v))
639 return typesEqual(at.elem, av.elem, seen) && at.len == av.len
641 ct := (*chantype)(unsafe.Pointer(t))
642 cv := (*chantype)(unsafe.Pointer(v))
643 return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
645 ft := (*functype)(unsafe.Pointer(t))
646 fv := (*functype)(unsafe.Pointer(v))
647 if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
650 tin, vin := ft.in(), fv.in()
651 for i := 0; i < len(tin); i++ {
652 if !typesEqual(tin[i], vin[i], seen) {
656 tout, vout := ft.out(), fv.out()
657 for i := 0; i < len(tout); i++ {
658 if !typesEqual(tout[i], vout[i], seen) {
664 it := (*interfacetype)(unsafe.Pointer(t))
665 iv := (*interfacetype)(unsafe.Pointer(v))
666 if it.pkgpath.name() != iv.pkgpath.name() {
669 if len(it.mhdr) != len(iv.mhdr) {
672 for i := range it.mhdr {
675 // Note the mhdr array can be relocated from
676 // another module. See #17724.
677 tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
678 vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
679 if tname.name() != vname.name() {
682 if tname.pkgPath() != vname.pkgPath() {
685 tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
686 vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
687 if !typesEqual(tityp, vityp, seen) {
693 mt := (*maptype)(unsafe.Pointer(t))
694 mv := (*maptype)(unsafe.Pointer(v))
695 return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
697 pt := (*ptrtype)(unsafe.Pointer(t))
698 pv := (*ptrtype)(unsafe.Pointer(v))
699 return typesEqual(pt.elem, pv.elem, seen)
701 st := (*slicetype)(unsafe.Pointer(t))
702 sv := (*slicetype)(unsafe.Pointer(v))
703 return typesEqual(st.elem, sv.elem, seen)
705 st := (*structtype)(unsafe.Pointer(t))
706 sv := (*structtype)(unsafe.Pointer(v))
707 if len(st.fields) != len(sv.fields) {
710 if st.pkgPath.name() != sv.pkgPath.name() {
713 for i := range st.fields {
716 if tf.name.name() != vf.name.name() {
719 if !typesEqual(tf.typ, vf.typ, seen) {
722 if tf.name.tag() != vf.name.tag() {
725 if tf.offsetAnon != vf.offsetAnon {
731 println("runtime: impossible type kind", kind)
732 throw("runtime: impossible type kind")