github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/runtime/type.go (about) 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 7 package runtime 8 9 import "unsafe" 10 11 // tflag is documented in reflect/type.go. 12 // 13 // tflag values must be kept in sync with copies in: 14 // cmd/compile/internal/reflectdata/reflect.go 15 // cmd/link/internal/ld/decodesym.go 16 // reflect/type.go 17 // internal/reflectlite/type.go 18 type tflag uint8 19 20 const ( 21 tflagUncommon tflag = 1 << 0 22 tflagExtraStar tflag = 1 << 1 23 tflagNamed tflag = 1 << 2 24 tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes 25 ) 26 27 // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, 28 // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and 29 // ../reflect/type.go:/^type.rtype. 30 // ../internal/reflectlite/type.go:/^type.rtype. 31 type _type struct { 32 size uintptr 33 ptrdata uintptr // size of memory prefix holding all pointers 34 hash uint32 35 tflag tflag 36 align uint8 37 fieldAlign uint8 38 kind uint8 39 // function for comparing objects of this type 40 // (ptr to object A, ptr to object B) -> ==? 41 equal func(unsafe.Pointer, unsafe.Pointer) bool 42 // gcdata stores the GC type data for the garbage collector. 43 // If the KindGCProg bit is set in kind, gcdata is a GC program. 44 // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. 45 gcdata *byte 46 str nameOff 47 ptrToThis typeOff 48 } 49 50 func (t *_type) string() string { 51 s := t.nameOff(t.str).name() 52 if t.tflag&tflagExtraStar != 0 { 53 return s[1:] 54 } 55 return s 56 } 57 58 func (t *_type) uncommon() *uncommontype { 59 if t.tflag&tflagUncommon == 0 { 60 return nil 61 } 62 switch t.kind & kindMask { 63 case kindStruct: 64 type u struct { 65 structtype 66 u uncommontype 67 } 68 return &(*u)(unsafe.Pointer(t)).u 69 case kindPtr: 70 type u struct { 71 ptrtype 72 u uncommontype 73 } 74 return &(*u)(unsafe.Pointer(t)).u 75 case kindFunc: 76 type u struct { 77 functype 78 u uncommontype 79 } 80 return &(*u)(unsafe.Pointer(t)).u 81 case kindSlice: 82 type u struct { 83 slicetype 84 u uncommontype 85 } 86 return &(*u)(unsafe.Pointer(t)).u 87 case kindArray: 88 type u struct { 89 arraytype 90 u uncommontype 91 } 92 return &(*u)(unsafe.Pointer(t)).u 93 case kindChan: 94 type u struct { 95 chantype 96 u uncommontype 97 } 98 return &(*u)(unsafe.Pointer(t)).u 99 case kindMap: 100 type u struct { 101 maptype 102 u uncommontype 103 } 104 return &(*u)(unsafe.Pointer(t)).u 105 case kindInterface: 106 type u struct { 107 interfacetype 108 u uncommontype 109 } 110 return &(*u)(unsafe.Pointer(t)).u 111 default: 112 type u struct { 113 _type 114 u uncommontype 115 } 116 return &(*u)(unsafe.Pointer(t)).u 117 } 118 } 119 120 func (t *_type) name() string { 121 if t.tflag&tflagNamed == 0 { 122 return "" 123 } 124 s := t.string() 125 i := len(s) - 1 126 for i >= 0 && s[i] != '.' { 127 i-- 128 } 129 return s[i+1:] 130 } 131 132 // pkgpath returns the path of the package where t was defined, if 133 // available. This is not the same as the reflect package's PkgPath 134 // method, in that it returns the package path for struct and interface 135 // types, not just named types. 136 func (t *_type) pkgpath() string { 137 if u := t.uncommon(); u != nil { 138 return t.nameOff(u.pkgpath).name() 139 } 140 switch t.kind & kindMask { 141 case kindStruct: 142 st := (*structtype)(unsafe.Pointer(t)) 143 return st.pkgPath.name() 144 case kindInterface: 145 it := (*interfacetype)(unsafe.Pointer(t)) 146 return it.pkgpath.name() 147 } 148 return "" 149 } 150 151 // reflectOffs holds type offsets defined at run time by the reflect package. 152 // 153 // When a type is defined at run time, its *rtype data lives on the heap. 154 // There are a wide range of possible addresses the heap may use, that 155 // may not be representable as a 32-bit offset. Moreover the GC may 156 // one day start moving heap memory, in which case there is no stable 157 // offset that can be defined. 158 // 159 // To provide stable offsets, we add pin *rtype objects in a global map 160 // and treat the offset as an identifier. We use negative offsets that 161 // do not overlap with any compile-time module offsets. 162 // 163 // Entries are created by reflect.addReflectOff. 164 var reflectOffs struct { 165 lock mutex 166 next int32 167 m map[int32]unsafe.Pointer 168 minv map[unsafe.Pointer]int32 169 } 170 171 func reflectOffsLock() { 172 lock(&reflectOffs.lock) 173 if raceenabled { 174 raceacquire(unsafe.Pointer(&reflectOffs.lock)) 175 } 176 } 177 178 func reflectOffsUnlock() { 179 if raceenabled { 180 racerelease(unsafe.Pointer(&reflectOffs.lock)) 181 } 182 unlock(&reflectOffs.lock) 183 } 184 185 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { 186 if off == 0 { 187 return name{} 188 } 189 base := uintptr(ptrInModule) 190 for md := &firstmoduledata; md != nil; md = md.next { 191 if base >= md.types && base < md.etypes { 192 res := md.types + uintptr(off) 193 if res > md.etypes { 194 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) 195 throw("runtime: name offset out of range") 196 } 197 return name{(*byte)(unsafe.Pointer(res))} 198 } 199 } 200 201 // No module found. see if it is a run time name. 202 reflectOffsLock() 203 res, found := reflectOffs.m[int32(off)] 204 reflectOffsUnlock() 205 if !found { 206 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") 207 for next := &firstmoduledata; next != nil; next = next.next { 208 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 209 } 210 throw("runtime: name offset base pointer out of range") 211 } 212 return name{(*byte)(res)} 213 } 214 215 func (t *_type) nameOff(off nameOff) name { 216 return resolveNameOff(unsafe.Pointer(t), off) 217 } 218 219 func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { 220 if off == 0 || off == -1 { 221 // -1 is the sentinel value for unreachable code. 222 // See cmd/link/internal/ld/data.go:relocsym. 223 return nil 224 } 225 base := uintptr(ptrInModule) 226 var md *moduledata 227 for next := &firstmoduledata; next != nil; next = next.next { 228 if base >= next.types && base < next.etypes { 229 md = next 230 break 231 } 232 } 233 if md == nil { 234 reflectOffsLock() 235 res := reflectOffs.m[int32(off)] 236 reflectOffsUnlock() 237 if res == nil { 238 println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") 239 for next := &firstmoduledata; next != nil; next = next.next { 240 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 241 } 242 throw("runtime: type offset base pointer out of range") 243 } 244 return (*_type)(res) 245 } 246 if t := md.typemap[off]; t != nil { 247 return t 248 } 249 res := md.types + uintptr(off) 250 if res > md.etypes { 251 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) 252 throw("runtime: type offset out of range") 253 } 254 return (*_type)(unsafe.Pointer(res)) 255 } 256 257 func (t *_type) typeOff(off typeOff) *_type { 258 return resolveTypeOff(unsafe.Pointer(t), off) 259 } 260 261 func (t *_type) textOff(off textOff) unsafe.Pointer { 262 if off == -1 { 263 // -1 is the sentinel value for unreachable code. 264 // See cmd/link/internal/ld/data.go:relocsym. 265 return unsafe.Pointer(funcPC(unreachableMethod)) 266 } 267 base := uintptr(unsafe.Pointer(t)) 268 var md *moduledata 269 for next := &firstmoduledata; next != nil; next = next.next { 270 if base >= next.types && base < next.etypes { 271 md = next 272 break 273 } 274 } 275 if md == nil { 276 reflectOffsLock() 277 res := reflectOffs.m[int32(off)] 278 reflectOffsUnlock() 279 if res == nil { 280 println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") 281 for next := &firstmoduledata; next != nil; next = next.next { 282 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 283 } 284 throw("runtime: text offset base pointer out of range") 285 } 286 return res 287 } 288 res := uintptr(0) 289 290 // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is 291 // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if 292 // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split 293 // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr 294 // for each text section is set to its offset within the text. Each method's offset is compared against the section 295 // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's 296 // relocated baseaddr to compute the method addess. 297 298 if len(md.textsectmap) > 1 { 299 for i := range md.textsectmap { 300 sectaddr := md.textsectmap[i].vaddr 301 sectlen := md.textsectmap[i].length 302 if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen { 303 res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr) 304 break 305 } 306 } 307 } else { 308 // single text section 309 res = md.text + uintptr(off) 310 } 311 312 if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory 313 println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext)) 314 throw("runtime: text offset out of range") 315 } 316 return unsafe.Pointer(res) 317 } 318 319 func (t *functype) in() []*_type { 320 // See funcType in reflect/type.go for details on data layout. 321 uadd := uintptr(unsafe.Sizeof(functype{})) 322 if t.typ.tflag&tflagUncommon != 0 { 323 uadd += unsafe.Sizeof(uncommontype{}) 324 } 325 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount] 326 } 327 328 func (t *functype) out() []*_type { 329 // See funcType in reflect/type.go for details on data layout. 330 uadd := uintptr(unsafe.Sizeof(functype{})) 331 if t.typ.tflag&tflagUncommon != 0 { 332 uadd += unsafe.Sizeof(uncommontype{}) 333 } 334 outCount := t.outCount & (1<<15 - 1) 335 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount] 336 } 337 338 func (t *functype) dotdotdot() bool { 339 return t.outCount&(1<<15) != 0 340 } 341 342 type nameOff int32 343 type typeOff int32 344 type textOff int32 345 346 type method struct { 347 name nameOff 348 mtyp typeOff 349 ifn textOff 350 tfn textOff 351 } 352 353 type uncommontype struct { 354 pkgpath nameOff 355 mcount uint16 // number of methods 356 xcount uint16 // number of exported methods 357 moff uint32 // offset from this uncommontype to [mcount]method 358 _ uint32 // unused 359 } 360 361 type imethod struct { 362 name nameOff 363 ityp typeOff 364 } 365 366 type interfacetype struct { 367 typ _type 368 pkgpath name 369 mhdr []imethod 370 } 371 372 type maptype struct { 373 typ _type 374 key *_type 375 elem *_type 376 bucket *_type // internal type representing a hash bucket 377 // function for hashing keys (ptr to key, seed) -> hash 378 hasher func(unsafe.Pointer, uintptr) uintptr 379 keysize uint8 // size of key slot 380 elemsize uint8 // size of elem slot 381 bucketsize uint16 // size of bucket 382 flags uint32 383 } 384 385 // Note: flag values must match those used in the TMAP case 386 // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. 387 func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself 388 return mt.flags&1 != 0 389 } 390 func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself 391 return mt.flags&2 != 0 392 } 393 func (mt *maptype) reflexivekey() bool { // true if k==k for all keys 394 return mt.flags&4 != 0 395 } 396 func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite 397 return mt.flags&8 != 0 398 } 399 func (mt *maptype) hashMightPanic() bool { // true if hash function might panic 400 return mt.flags&16 != 0 401 } 402 403 type arraytype struct { 404 typ _type 405 elem *_type 406 slice *_type 407 len uintptr 408 } 409 410 type chantype struct { 411 typ _type 412 elem *_type 413 dir uintptr 414 } 415 416 type slicetype struct { 417 typ _type 418 elem *_type 419 } 420 421 type functype struct { 422 typ _type 423 inCount uint16 424 outCount uint16 425 } 426 427 type ptrtype struct { 428 typ _type 429 elem *_type 430 } 431 432 type structfield struct { 433 name name 434 typ *_type 435 offsetAnon uintptr 436 } 437 438 func (f *structfield) offset() uintptr { 439 return f.offsetAnon >> 1 440 } 441 442 type structtype struct { 443 typ _type 444 pkgPath name 445 fields []structfield 446 } 447 448 // name is an encoded type name with optional extra data. 449 // See reflect/type.go for details. 450 type name struct { 451 bytes *byte 452 } 453 454 func (n name) data(off int) *byte { 455 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off))) 456 } 457 458 func (n name) isExported() bool { 459 return (*n.bytes)&(1<<0) != 0 460 } 461 462 func (n name) readvarint(off int) (int, int) { 463 v := 0 464 for i := 0; ; i++ { 465 x := *n.data(off + i) 466 v += int(x&0x7f) << (7 * i) 467 if x&0x80 == 0 { 468 return i + 1, v 469 } 470 } 471 } 472 473 func (n name) name() (s string) { 474 if n.bytes == nil { 475 return "" 476 } 477 i, l := n.readvarint(1) 478 if l == 0 { 479 return "" 480 } 481 hdr := (*stringStruct)(unsafe.Pointer(&s)) 482 hdr.str = unsafe.Pointer(n.data(1 + i)) 483 hdr.len = l 484 return 485 } 486 487 func (n name) tag() (s string) { 488 if *n.data(0)&(1<<1) == 0 { 489 return "" 490 } 491 i, l := n.readvarint(1) 492 i2, l2 := n.readvarint(1 + i + l) 493 hdr := (*stringStruct)(unsafe.Pointer(&s)) 494 hdr.str = unsafe.Pointer(n.data(1 + i + l + i2)) 495 hdr.len = l2 496 return 497 } 498 499 func (n name) pkgPath() string { 500 if n.bytes == nil || *n.data(0)&(1<<2) == 0 { 501 return "" 502 } 503 i, l := n.readvarint(1) 504 off := 1 + i + l 505 if *n.data(0)&(1<<1) != 0 { 506 i2, l2 := n.readvarint(off) 507 off += i2 + l2 508 } 509 var nameOff nameOff 510 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:]) 511 pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff) 512 return pkgPathName.name() 513 } 514 515 func (n name) isBlank() bool { 516 if n.bytes == nil { 517 return false 518 } 519 _, l := n.readvarint(1) 520 return l == 1 && *n.data(2) == '_' 521 } 522 523 // typelinksinit scans the types from extra modules and builds the 524 // moduledata typemap used to de-duplicate type pointers. 525 func typelinksinit() { 526 if firstmoduledata.next == nil { 527 return 528 } 529 typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks)) 530 531 modules := activeModules() 532 prev := modules[0] 533 for _, md := range modules[1:] { 534 // Collect types from the previous module into typehash. 535 collect: 536 for _, tl := range prev.typelinks { 537 var t *_type 538 if prev.typemap == nil { 539 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) 540 } else { 541 t = prev.typemap[typeOff(tl)] 542 } 543 // Add to typehash if not seen before. 544 tlist := typehash[t.hash] 545 for _, tcur := range tlist { 546 if tcur == t { 547 continue collect 548 } 549 } 550 typehash[t.hash] = append(tlist, t) 551 } 552 553 if md.typemap == nil { 554 // If any of this module's typelinks match a type from a 555 // prior module, prefer that prior type by adding the offset 556 // to this module's typemap. 557 tm := make(map[typeOff]*_type, len(md.typelinks)) 558 pinnedTypemaps = append(pinnedTypemaps, tm) 559 md.typemap = tm 560 for _, tl := range md.typelinks { 561 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) 562 for _, candidate := range typehash[t.hash] { 563 seen := map[_typePair]struct{}{} 564 if typesEqual(t, candidate, seen) { 565 t = candidate 566 break 567 } 568 } 569 md.typemap[typeOff(tl)] = t 570 } 571 } 572 573 prev = md 574 } 575 } 576 577 type _typePair struct { 578 t1 *_type 579 t2 *_type 580 } 581 582 // typesEqual reports whether two types are equal. 583 // 584 // Everywhere in the runtime and reflect packages, it is assumed that 585 // there is exactly one *_type per Go type, so that pointer equality 586 // can be used to test if types are equal. There is one place that 587 // breaks this assumption: buildmode=shared. In this case a type can 588 // appear as two different pieces of memory. This is hidden from the 589 // runtime and reflect package by the per-module typemap built in 590 // typelinksinit. It uses typesEqual to map types from later modules 591 // back into earlier ones. 592 // 593 // Only typelinksinit needs this function. 594 func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { 595 tp := _typePair{t, v} 596 if _, ok := seen[tp]; ok { 597 return true 598 } 599 600 // mark these types as seen, and thus equivalent which prevents an infinite loop if 601 // the two types are identical, but recursively defined and loaded from 602 // different modules 603 seen[tp] = struct{}{} 604 605 if t == v { 606 return true 607 } 608 kind := t.kind & kindMask 609 if kind != v.kind&kindMask { 610 return false 611 } 612 if t.string() != v.string() { 613 return false 614 } 615 ut := t.uncommon() 616 uv := v.uncommon() 617 if ut != nil || uv != nil { 618 if ut == nil || uv == nil { 619 return false 620 } 621 pkgpatht := t.nameOff(ut.pkgpath).name() 622 pkgpathv := v.nameOff(uv.pkgpath).name() 623 if pkgpatht != pkgpathv { 624 return false 625 } 626 } 627 if kindBool <= kind && kind <= kindComplex128 { 628 return true 629 } 630 switch kind { 631 case kindString, kindUnsafePointer: 632 return true 633 case kindArray: 634 at := (*arraytype)(unsafe.Pointer(t)) 635 av := (*arraytype)(unsafe.Pointer(v)) 636 return typesEqual(at.elem, av.elem, seen) && at.len == av.len 637 case kindChan: 638 ct := (*chantype)(unsafe.Pointer(t)) 639 cv := (*chantype)(unsafe.Pointer(v)) 640 return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen) 641 case kindFunc: 642 ft := (*functype)(unsafe.Pointer(t)) 643 fv := (*functype)(unsafe.Pointer(v)) 644 if ft.outCount != fv.outCount || ft.inCount != fv.inCount { 645 return false 646 } 647 tin, vin := ft.in(), fv.in() 648 for i := 0; i < len(tin); i++ { 649 if !typesEqual(tin[i], vin[i], seen) { 650 return false 651 } 652 } 653 tout, vout := ft.out(), fv.out() 654 for i := 0; i < len(tout); i++ { 655 if !typesEqual(tout[i], vout[i], seen) { 656 return false 657 } 658 } 659 return true 660 case kindInterface: 661 it := (*interfacetype)(unsafe.Pointer(t)) 662 iv := (*interfacetype)(unsafe.Pointer(v)) 663 if it.pkgpath.name() != iv.pkgpath.name() { 664 return false 665 } 666 if len(it.mhdr) != len(iv.mhdr) { 667 return false 668 } 669 for i := range it.mhdr { 670 tm := &it.mhdr[i] 671 vm := &iv.mhdr[i] 672 // Note the mhdr array can be relocated from 673 // another module. See #17724. 674 tname := resolveNameOff(unsafe.Pointer(tm), tm.name) 675 vname := resolveNameOff(unsafe.Pointer(vm), vm.name) 676 if tname.name() != vname.name() { 677 return false 678 } 679 if tname.pkgPath() != vname.pkgPath() { 680 return false 681 } 682 tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp) 683 vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp) 684 if !typesEqual(tityp, vityp, seen) { 685 return false 686 } 687 } 688 return true 689 case kindMap: 690 mt := (*maptype)(unsafe.Pointer(t)) 691 mv := (*maptype)(unsafe.Pointer(v)) 692 return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen) 693 case kindPtr: 694 pt := (*ptrtype)(unsafe.Pointer(t)) 695 pv := (*ptrtype)(unsafe.Pointer(v)) 696 return typesEqual(pt.elem, pv.elem, seen) 697 case kindSlice: 698 st := (*slicetype)(unsafe.Pointer(t)) 699 sv := (*slicetype)(unsafe.Pointer(v)) 700 return typesEqual(st.elem, sv.elem, seen) 701 case kindStruct: 702 st := (*structtype)(unsafe.Pointer(t)) 703 sv := (*structtype)(unsafe.Pointer(v)) 704 if len(st.fields) != len(sv.fields) { 705 return false 706 } 707 if st.pkgPath.name() != sv.pkgPath.name() { 708 return false 709 } 710 for i := range st.fields { 711 tf := &st.fields[i] 712 vf := &sv.fields[i] 713 if tf.name.name() != vf.name.name() { 714 return false 715 } 716 if !typesEqual(tf.typ, vf.typ, seen) { 717 return false 718 } 719 if tf.name.tag() != vf.name.tag() { 720 return false 721 } 722 if tf.offsetAnon != vf.offsetAnon { 723 return false 724 } 725 } 726 return true 727 default: 728 println("runtime: impossible type kind", kind) 729 throw("runtime: impossible type kind") 730 return false 731 } 732 }