github.com/letsencrypt/go@v0.0.0-20160714163537-4054769a31f6/src/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/gc/reflect.go 15 // cmd/link/internal/ld/decodesym.go 16 // reflect/type.go 17 type tflag uint8 18 19 const ( 20 tflagUncommon tflag = 1 << 0 21 tflagExtraStar tflag = 1 << 1 22 tflagNamed tflag = 1 << 2 23 ) 24 25 // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize, 26 // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and 27 // ../reflect/type.go:/^type.rtype. 28 type _type struct { 29 size uintptr 30 ptrdata uintptr // size of memory prefix holding all pointers 31 hash uint32 32 tflag tflag 33 align uint8 34 fieldalign uint8 35 kind uint8 36 alg *typeAlg 37 // gcdata stores the GC type data for the garbage collector. 38 // If the KindGCProg bit is set in kind, gcdata is a GC program. 39 // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. 40 gcdata *byte 41 str nameOff 42 ptrToThis typeOff 43 } 44 45 func (t *_type) string() string { 46 s := t.nameOff(t.str).name() 47 if t.tflag&tflagExtraStar != 0 { 48 return s[1:] 49 } 50 return s 51 } 52 53 func (t *_type) uncommon() *uncommontype { 54 if t.tflag&tflagUncommon == 0 { 55 return nil 56 } 57 switch t.kind & kindMask { 58 case kindStruct: 59 type u struct { 60 structtype 61 u uncommontype 62 } 63 return &(*u)(unsafe.Pointer(t)).u 64 case kindPtr: 65 type u struct { 66 ptrtype 67 u uncommontype 68 } 69 return &(*u)(unsafe.Pointer(t)).u 70 case kindFunc: 71 type u struct { 72 functype 73 u uncommontype 74 } 75 return &(*u)(unsafe.Pointer(t)).u 76 case kindSlice: 77 type u struct { 78 slicetype 79 u uncommontype 80 } 81 return &(*u)(unsafe.Pointer(t)).u 82 case kindArray: 83 type u struct { 84 arraytype 85 u uncommontype 86 } 87 return &(*u)(unsafe.Pointer(t)).u 88 case kindChan: 89 type u struct { 90 chantype 91 u uncommontype 92 } 93 return &(*u)(unsafe.Pointer(t)).u 94 case kindMap: 95 type u struct { 96 maptype 97 u uncommontype 98 } 99 return &(*u)(unsafe.Pointer(t)).u 100 case kindInterface: 101 type u struct { 102 interfacetype 103 u uncommontype 104 } 105 return &(*u)(unsafe.Pointer(t)).u 106 default: 107 type u struct { 108 _type 109 u uncommontype 110 } 111 return &(*u)(unsafe.Pointer(t)).u 112 } 113 } 114 115 func hasPrefix(s, prefix string) bool { 116 return len(s) >= len(prefix) && s[:len(prefix)] == prefix 117 } 118 119 func (t *_type) name() string { 120 if t.tflag&tflagNamed == 0 { 121 return "" 122 } 123 s := t.string() 124 i := len(s) - 1 125 for i >= 0 { 126 if s[i] == '.' { 127 break 128 } 129 i-- 130 } 131 return s[i+1:] 132 } 133 134 // reflectOffs holds type offsets defined at run time by the reflect package. 135 // 136 // When a type is defined at run time, its *rtype data lives on the heap. 137 // There are a wide range of possible addresses the heap may use, that 138 // may not be representable as a 32-bit offset. Moreover the GC may 139 // one day start moving heap memory, in which case there is no stable 140 // offset that can be defined. 141 // 142 // To provide stable offsets, we add pin *rtype objects in a global map 143 // and treat the offset as an identifier. We use negative offsets that 144 // do not overlap with any compile-time module offsets. 145 // 146 // Entries are created by reflect.addReflectOff. 147 var reflectOffs struct { 148 lock mutex 149 next int32 150 m map[int32]unsafe.Pointer 151 minv map[unsafe.Pointer]int32 152 } 153 154 func reflectOffsLock() { 155 lock(&reflectOffs.lock) 156 if raceenabled { 157 raceacquire(unsafe.Pointer(&reflectOffs.lock)) 158 } 159 } 160 161 func reflectOffsUnlock() { 162 if raceenabled { 163 racerelease(unsafe.Pointer(&reflectOffs.lock)) 164 } 165 unlock(&reflectOffs.lock) 166 } 167 168 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { 169 if off == 0 { 170 return name{} 171 } 172 base := uintptr(ptrInModule) 173 for md := &firstmoduledata; md != nil; md = md.next { 174 if base >= md.types && base < md.etypes { 175 res := md.types + uintptr(off) 176 if res > md.etypes { 177 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) 178 throw("runtime: name offset out of range") 179 } 180 return name{(*byte)(unsafe.Pointer(res))} 181 } 182 } 183 184 // No module found. see if it is a run time name. 185 reflectOffsLock() 186 res, found := reflectOffs.m[int32(off)] 187 reflectOffsUnlock() 188 if !found { 189 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") 190 for next := &firstmoduledata; next != nil; next = next.next { 191 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 192 } 193 throw("runtime: name offset base pointer out of range") 194 } 195 return name{(*byte)(res)} 196 } 197 198 func (t *_type) nameOff(off nameOff) name { 199 return resolveNameOff(unsafe.Pointer(t), off) 200 } 201 202 func (t *_type) typeOff(off typeOff) *_type { 203 if off == 0 { 204 return nil 205 } 206 base := uintptr(unsafe.Pointer(t)) 207 var md *moduledata 208 for next := &firstmoduledata; next != nil; next = next.next { 209 if base >= next.types && base < next.etypes { 210 md = next 211 break 212 } 213 } 214 if md == nil { 215 reflectOffsLock() 216 res := reflectOffs.m[int32(off)] 217 reflectOffsUnlock() 218 if res == nil { 219 println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") 220 for next := &firstmoduledata; next != nil; next = next.next { 221 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 222 } 223 throw("runtime: type offset base pointer out of range") 224 } 225 return (*_type)(res) 226 } 227 if t := md.typemap[off]; t != nil { 228 return t 229 } 230 res := md.types + uintptr(off) 231 if res > md.etypes { 232 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) 233 throw("runtime: type offset out of range") 234 } 235 return (*_type)(unsafe.Pointer(res)) 236 } 237 238 func (t *_type) textOff(off textOff) unsafe.Pointer { 239 base := uintptr(unsafe.Pointer(t)) 240 var md *moduledata 241 for next := &firstmoduledata; next != nil; next = next.next { 242 if base >= next.types && base < next.etypes { 243 md = next 244 break 245 } 246 } 247 if md == nil { 248 reflectOffsLock() 249 res := reflectOffs.m[int32(off)] 250 reflectOffsUnlock() 251 if res == nil { 252 println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") 253 for next := &firstmoduledata; next != nil; next = next.next { 254 println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) 255 } 256 throw("runtime: text offset base pointer out of range") 257 } 258 return res 259 } 260 res := md.text + uintptr(off) 261 if res > md.etext { 262 println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext)) 263 throw("runtime: text offset out of range") 264 } 265 return unsafe.Pointer(res) 266 } 267 268 func (t *functype) in() []*_type { 269 // See funcType in reflect/type.go for details on data layout. 270 uadd := uintptr(unsafe.Sizeof(functype{})) 271 if t.typ.tflag&tflagUncommon != 0 { 272 uadd += unsafe.Sizeof(uncommontype{}) 273 } 274 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount] 275 } 276 277 func (t *functype) out() []*_type { 278 // See funcType in reflect/type.go for details on data layout. 279 uadd := uintptr(unsafe.Sizeof(functype{})) 280 if t.typ.tflag&tflagUncommon != 0 { 281 uadd += unsafe.Sizeof(uncommontype{}) 282 } 283 outCount := t.outCount & (1<<15 - 1) 284 return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount] 285 } 286 287 func (t *functype) dotdotdot() bool { 288 return t.outCount&(1<<15) != 0 289 } 290 291 type nameOff int32 292 type typeOff int32 293 type textOff int32 294 295 type method struct { 296 name nameOff 297 mtyp typeOff 298 ifn textOff 299 tfn textOff 300 } 301 302 type uncommontype struct { 303 pkgpath nameOff 304 mcount uint16 // number of methods 305 _ uint16 // unused 306 moff uint32 // offset from this uncommontype to [mcount]method 307 _ uint32 // unused 308 } 309 310 type imethod struct { 311 name nameOff 312 ityp typeOff 313 } 314 315 type interfacetype struct { 316 typ _type 317 pkgpath name 318 mhdr []imethod 319 } 320 321 type maptype struct { 322 typ _type 323 key *_type 324 elem *_type 325 bucket *_type // internal type representing a hash bucket 326 hmap *_type // internal type representing a hmap 327 keysize uint8 // size of key slot 328 indirectkey bool // store ptr to key instead of key itself 329 valuesize uint8 // size of value slot 330 indirectvalue bool // store ptr to value instead of value itself 331 bucketsize uint16 // size of bucket 332 reflexivekey bool // true if k==k for all keys 333 needkeyupdate bool // true if we need to update key on an overwrite 334 } 335 336 type arraytype struct { 337 typ _type 338 elem *_type 339 slice *_type 340 len uintptr 341 } 342 343 type chantype struct { 344 typ _type 345 elem *_type 346 dir uintptr 347 } 348 349 type slicetype struct { 350 typ _type 351 elem *_type 352 } 353 354 type functype struct { 355 typ _type 356 inCount uint16 357 outCount uint16 358 } 359 360 type ptrtype struct { 361 typ _type 362 elem *_type 363 } 364 365 type structfield struct { 366 name name 367 typ *_type 368 offset uintptr 369 } 370 371 type structtype struct { 372 typ _type 373 pkgPath name 374 fields []structfield 375 } 376 377 // name is an encoded type name with optional extra data. 378 // See reflect/type.go for details. 379 type name struct { 380 bytes *byte 381 } 382 383 func (n name) data(off int) *byte { 384 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off))) 385 } 386 387 func (n name) isExported() bool { 388 return (*n.bytes)&(1<<0) != 0 389 } 390 391 func (n name) nameLen() int { 392 return int(uint16(*n.data(1))<<8 | uint16(*n.data(2))) 393 } 394 395 func (n name) tagLen() int { 396 if *n.data(0)&(1<<1) == 0 { 397 return 0 398 } 399 off := 3 + n.nameLen() 400 return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1))) 401 } 402 403 func (n name) name() (s string) { 404 if n.bytes == nil { 405 return "" 406 } 407 nl := n.nameLen() 408 if nl == 0 { 409 return "" 410 } 411 hdr := (*stringStruct)(unsafe.Pointer(&s)) 412 hdr.str = unsafe.Pointer(n.data(3)) 413 hdr.len = nl 414 return s 415 } 416 417 func (n name) tag() (s string) { 418 tl := n.tagLen() 419 if tl == 0 { 420 return "" 421 } 422 nl := n.nameLen() 423 hdr := (*stringStruct)(unsafe.Pointer(&s)) 424 hdr.str = unsafe.Pointer(n.data(3 + nl + 2)) 425 hdr.len = tl 426 return s 427 } 428 429 func (n name) pkgPath() string { 430 if n.bytes == nil || *n.data(0)&(1<<2) == 0 { 431 return "" 432 } 433 off := 3 + n.nameLen() 434 if tl := n.tagLen(); tl > 0 { 435 off += 2 + tl 436 } 437 var nameOff nameOff 438 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:]) 439 pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff) 440 return pkgPathName.name() 441 } 442 443 // typelinksinit scans the types from extra modules and builds the 444 // moduledata typemap used to de-duplicate type pointers. 445 func typelinksinit() { 446 if firstmoduledata.next == nil { 447 return 448 } 449 typehash := make(map[uint32][]*_type) 450 451 modules := []*moduledata{} 452 for md := &firstmoduledata; md != nil; md = md.next { 453 modules = append(modules, md) 454 } 455 prev, modules := modules[len(modules)-1], modules[:len(modules)-1] 456 for len(modules) > 0 { 457 // Collect types from the previous module into typehash. 458 collect: 459 for _, tl := range prev.typelinks { 460 var t *_type 461 if prev.typemap == nil { 462 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) 463 } else { 464 t = prev.typemap[typeOff(tl)] 465 } 466 // Add to typehash if not seen before. 467 tlist := typehash[t.hash] 468 for _, tcur := range tlist { 469 if tcur == t { 470 continue collect 471 } 472 } 473 typehash[t.hash] = append(tlist, t) 474 } 475 476 // If any of this module's typelinks match a type from a 477 // prior module, prefer that prior type by adding the offset 478 // to this module's typemap. 479 md := modules[len(modules)-1] 480 md.typemap = make(map[typeOff]*_type, len(md.typelinks)) 481 for _, tl := range md.typelinks { 482 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) 483 for _, candidate := range typehash[t.hash] { 484 if typesEqual(t, candidate) { 485 t = candidate 486 break 487 } 488 } 489 md.typemap[typeOff(tl)] = t 490 } 491 492 prev, modules = md, modules[:len(modules)-1] 493 } 494 } 495 496 // typesEqual reports whether two types are equal. 497 // 498 // Everywhere in the runtime and reflect packages, it is assumed that 499 // there is exactly one *_type per Go type, so that pointer equality 500 // can be used to test if types are equal. There is one place that 501 // breaks this assumption: buildmode=shared. In this case a type can 502 // appear as two different pieces of memory. This is hidden from the 503 // runtime and reflect package by the per-module typemap built in 504 // typelinksinit. It uses typesEqual to map types from later modules 505 // back into earlier ones. 506 // 507 // Only typelinksinit needs this function. 508 func typesEqual(t, v *_type) bool { 509 if t == v { 510 return true 511 } 512 kind := t.kind & kindMask 513 if kind != v.kind&kindMask { 514 return false 515 } 516 if t.string() != v.string() { 517 return false 518 } 519 ut := t.uncommon() 520 uv := v.uncommon() 521 if ut != nil || uv != nil { 522 if ut == nil || uv == nil { 523 return false 524 } 525 pkgpatht := t.nameOff(ut.pkgpath).name() 526 pkgpathv := v.nameOff(uv.pkgpath).name() 527 if pkgpatht != pkgpathv { 528 return false 529 } 530 } 531 if kindBool <= kind && kind <= kindComplex128 { 532 return true 533 } 534 switch kind { 535 case kindString, kindUnsafePointer: 536 return true 537 case kindArray: 538 at := (*arraytype)(unsafe.Pointer(t)) 539 av := (*arraytype)(unsafe.Pointer(v)) 540 return typesEqual(at.elem, av.elem) && at.len == av.len 541 case kindChan: 542 ct := (*chantype)(unsafe.Pointer(t)) 543 cv := (*chantype)(unsafe.Pointer(v)) 544 return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem) 545 case kindFunc: 546 ft := (*functype)(unsafe.Pointer(t)) 547 fv := (*functype)(unsafe.Pointer(v)) 548 if ft.outCount != fv.outCount || ft.inCount != fv.inCount { 549 return false 550 } 551 tin, vin := ft.in(), fv.in() 552 for i := 0; i < len(tin); i++ { 553 if !typesEqual(tin[i], vin[i]) { 554 return false 555 } 556 } 557 tout, vout := ft.out(), fv.out() 558 for i := 0; i < len(tout); i++ { 559 if !typesEqual(tout[i], vout[i]) { 560 return false 561 } 562 } 563 return true 564 case kindInterface: 565 it := (*interfacetype)(unsafe.Pointer(t)) 566 iv := (*interfacetype)(unsafe.Pointer(v)) 567 if it.pkgpath.name() != iv.pkgpath.name() { 568 return false 569 } 570 if len(it.mhdr) != len(iv.mhdr) { 571 return false 572 } 573 for i := range it.mhdr { 574 tm := &it.mhdr[i] 575 vm := &iv.mhdr[i] 576 tname := it.typ.nameOff(tm.name) 577 vname := iv.typ.nameOff(vm.name) 578 if tname.name() != vname.name() { 579 return false 580 } 581 if tname.pkgPath() != vname.pkgPath() { 582 return false 583 } 584 if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) { 585 return false 586 } 587 } 588 return true 589 case kindMap: 590 mt := (*maptype)(unsafe.Pointer(t)) 591 mv := (*maptype)(unsafe.Pointer(v)) 592 return typesEqual(mt.key, mv.key) && typesEqual(mt.elem, mv.elem) 593 case kindPtr: 594 pt := (*ptrtype)(unsafe.Pointer(t)) 595 pv := (*ptrtype)(unsafe.Pointer(v)) 596 return typesEqual(pt.elem, pv.elem) 597 case kindSlice: 598 st := (*slicetype)(unsafe.Pointer(t)) 599 sv := (*slicetype)(unsafe.Pointer(v)) 600 return typesEqual(st.elem, sv.elem) 601 case kindStruct: 602 st := (*structtype)(unsafe.Pointer(t)) 603 sv := (*structtype)(unsafe.Pointer(v)) 604 if len(st.fields) != len(sv.fields) { 605 return false 606 } 607 for i := range st.fields { 608 tf := &st.fields[i] 609 vf := &sv.fields[i] 610 if tf.name.name() != vf.name.name() { 611 return false 612 } 613 if tf.name.pkgPath() != vf.name.pkgPath() { 614 return false 615 } 616 if !typesEqual(tf.typ, vf.typ) { 617 return false 618 } 619 if tf.name.tag() != vf.name.tag() { 620 return false 621 } 622 if tf.offset != vf.offset { 623 return false 624 } 625 } 626 return true 627 default: 628 println("runtime: impossible type kind", kind) 629 throw("runtime: impossible type kind") 630 return false 631 } 632 }