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