github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/reflect.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 package gc 6 7 import ( 8 "cmd/internal/gcprog" 9 "cmd/internal/obj" 10 "fmt" 11 "os" 12 "sort" 13 "strings" 14 ) 15 16 type itabEntry struct { 17 t, itype *Type 18 sym *Sym 19 } 20 21 // runtime interface and reflection data structures 22 var signatlist []*Node 23 var itabs []itabEntry 24 25 // byMethodNameAndPackagePath sorts method signatures by name, then package path. 26 type byMethodNameAndPackagePath []*Sig 27 28 func (x byMethodNameAndPackagePath) Len() int { return len(x) } 29 func (x byMethodNameAndPackagePath) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 30 func (x byMethodNameAndPackagePath) Less(i, j int) bool { 31 return siglt(x[i], x[j]) 32 } 33 34 // siglt reports whether a < b 35 func siglt(a, b *Sig) bool { 36 if a.name != b.name { 37 return a.name < b.name 38 } 39 if a.pkg == b.pkg { 40 return false 41 } 42 if a.pkg == nil { 43 return true 44 } 45 if b.pkg == nil { 46 return false 47 } 48 return a.pkg.Path < b.pkg.Path 49 } 50 51 // Builds a type representing a Bucket structure for 52 // the given map type. This type is not visible to users - 53 // we include only enough information to generate a correct GC 54 // program for it. 55 // Make sure this stays in sync with ../../../../runtime/hashmap.go! 56 const ( 57 BUCKETSIZE = 8 58 MAXKEYSIZE = 128 59 MAXVALSIZE = 128 60 ) 61 62 func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{}) 63 func imethodSize() int { return 2 * Widthptr } // Sizeof(runtime.imethod{}) 64 func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{}) 65 if t.Sym == nil && len(methods(t)) == 0 { 66 return 0 67 } 68 return 2*Widthptr + 2*Widthint 69 } 70 71 func makefield(name string, t *Type) *Field { 72 f := newField() 73 f.Type = t 74 f.Sym = nopkg.Lookup(name) 75 return f 76 } 77 78 func mapbucket(t *Type) *Type { 79 if t.Bucket != nil { 80 return t.Bucket 81 } 82 83 bucket := typ(TSTRUCT) 84 keytype := t.Key() 85 valtype := t.Val() 86 dowidth(keytype) 87 dowidth(valtype) 88 if keytype.Width > MAXKEYSIZE { 89 keytype = Ptrto(keytype) 90 } 91 if valtype.Width > MAXVALSIZE { 92 valtype = Ptrto(valtype) 93 } 94 95 // The first field is: uint8 topbits[BUCKETSIZE]. 96 arr := typArray(Types[TUINT8], BUCKETSIZE) 97 field := make([]*Field, 0, 5) 98 field = append(field, makefield("topbits", arr)) 99 arr = typArray(keytype, BUCKETSIZE) 100 field = append(field, makefield("keys", arr)) 101 arr = typArray(valtype, BUCKETSIZE) 102 field = append(field, makefield("values", arr)) 103 104 // Make sure the overflow pointer is the last memory in the struct, 105 // because the runtime assumes it can use size-ptrSize as the 106 // offset of the overflow pointer. We double-check that property 107 // below once the offsets and size are computed. 108 // 109 // BUCKETSIZE is 8, so the struct is aligned to 64 bits to this point. 110 // On 32-bit systems, the max alignment is 32-bit, and the 111 // overflow pointer will add another 32-bit field, and the struct 112 // will end with no padding. 113 // On 64-bit systems, the max alignment is 64-bit, and the 114 // overflow pointer will add another 64-bit field, and the struct 115 // will end with no padding. 116 // On nacl/amd64p32, however, the max alignment is 64-bit, 117 // but the overflow pointer will add only a 32-bit field, 118 // so if the struct needs 64-bit padding (because a key or value does) 119 // then it would end with an extra 32-bit padding field. 120 // Preempt that by emitting the padding here. 121 if int(t.Val().Align) > Widthptr || int(t.Key().Align) > Widthptr { 122 field = append(field, makefield("pad", Types[TUINTPTR])) 123 } 124 125 // If keys and values have no pointers, the map implementation 126 // can keep a list of overflow pointers on the side so that 127 // buckets can be marked as having no pointers. 128 // Arrange for the bucket to have no pointers by changing 129 // the type of the overflow field to uintptr in this case. 130 // See comment on hmap.overflow in ../../../../runtime/hashmap.go. 131 otyp := Ptrto(bucket) 132 if !haspointers(t.Val()) && !haspointers(t.Key()) && t.Val().Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE { 133 otyp = Types[TUINTPTR] 134 } 135 ovf := makefield("overflow", otyp) 136 field = append(field, ovf) 137 138 // link up fields 139 bucket.Noalg = true 140 bucket.Local = t.Local 141 bucket.SetFields(field[:]) 142 dowidth(bucket) 143 144 // Double-check that overflow field is final memory in struct, 145 // with no padding at end. See comment above. 146 if ovf.Offset != bucket.Width-int64(Widthptr) { 147 Yyerror("bad math in mapbucket for %v", t) 148 } 149 150 t.Bucket = bucket 151 152 bucket.Map = t 153 return bucket 154 } 155 156 // Builds a type representing a Hmap structure for the given map type. 157 // Make sure this stays in sync with ../../../../runtime/hashmap.go! 158 func hmap(t *Type) *Type { 159 if t.Hmap != nil { 160 return t.Hmap 161 } 162 163 bucket := mapbucket(t) 164 var field [8]*Field 165 field[0] = makefield("count", Types[TINT]) 166 field[1] = makefield("flags", Types[TUINT8]) 167 field[2] = makefield("B", Types[TUINT8]) 168 field[3] = makefield("hash0", Types[TUINT32]) 169 field[4] = makefield("buckets", Ptrto(bucket)) 170 field[5] = makefield("oldbuckets", Ptrto(bucket)) 171 field[6] = makefield("nevacuate", Types[TUINTPTR]) 172 field[7] = makefield("overflow", Types[TUNSAFEPTR]) 173 174 h := typ(TSTRUCT) 175 h.Noalg = true 176 h.Local = t.Local 177 h.SetFields(field[:]) 178 dowidth(h) 179 t.Hmap = h 180 h.Map = t 181 return h 182 } 183 184 func hiter(t *Type) *Type { 185 if t.Hiter != nil { 186 return t.Hiter 187 } 188 189 // build a struct: 190 // hiter { 191 // key *Key 192 // val *Value 193 // t *MapType 194 // h *Hmap 195 // buckets *Bucket 196 // bptr *Bucket 197 // overflow0 unsafe.Pointer 198 // overflow1 unsafe.Pointer 199 // startBucket uintptr 200 // stuff uintptr 201 // bucket uintptr 202 // checkBucket uintptr 203 // } 204 // must match ../../../../runtime/hashmap.go:hiter. 205 var field [12]*Field 206 field[0] = makefield("key", Ptrto(t.Key())) 207 field[1] = makefield("val", Ptrto(t.Val())) 208 field[2] = makefield("t", Ptrto(Types[TUINT8])) 209 field[3] = makefield("h", Ptrto(hmap(t))) 210 field[4] = makefield("buckets", Ptrto(mapbucket(t))) 211 field[5] = makefield("bptr", Ptrto(mapbucket(t))) 212 field[6] = makefield("overflow0", Types[TUNSAFEPTR]) 213 field[7] = makefield("overflow1", Types[TUNSAFEPTR]) 214 field[8] = makefield("startBucket", Types[TUINTPTR]) 215 field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I 216 field[10] = makefield("bucket", Types[TUINTPTR]) 217 field[11] = makefield("checkBucket", Types[TUINTPTR]) 218 219 // build iterator struct holding the above fields 220 i := typ(TSTRUCT) 221 i.Noalg = true 222 i.SetFields(field[:]) 223 dowidth(i) 224 if i.Width != int64(12*Widthptr) { 225 Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr) 226 } 227 t.Hiter = i 228 i.Map = t 229 return i 230 } 231 232 // f is method type, with receiver. 233 // return function type, receiver as first argument (or not). 234 func methodfunc(f *Type, receiver *Type) *Type { 235 var in []*Node 236 if receiver != nil { 237 d := Nod(ODCLFIELD, nil, nil) 238 d.Type = receiver 239 in = append(in, d) 240 } 241 242 var d *Node 243 for _, t := range f.Params().Fields().Slice() { 244 d = Nod(ODCLFIELD, nil, nil) 245 d.Type = t.Type 246 d.Isddd = t.Isddd 247 in = append(in, d) 248 } 249 250 var out []*Node 251 for _, t := range f.Results().Fields().Slice() { 252 d = Nod(ODCLFIELD, nil, nil) 253 d.Type = t.Type 254 out = append(out, d) 255 } 256 257 t := functype(nil, in, out) 258 if f.Nname() != nil { 259 // Link to name of original method function. 260 t.SetNname(f.Nname()) 261 } 262 263 return t 264 } 265 266 // methods returns the methods of the non-interface type t, sorted by name. 267 // Generates stub functions as needed. 268 func methods(t *Type) []*Sig { 269 // method type 270 mt := methtype(t, 0) 271 272 if mt == nil { 273 return nil 274 } 275 expandmeth(mt) 276 277 // type stored in interface word 278 it := t 279 280 if !isdirectiface(it) { 281 it = Ptrto(t) 282 } 283 284 // make list of methods for t, 285 // generating code if necessary. 286 var ms []*Sig 287 for _, f := range mt.AllMethods().Slice() { 288 if f.Type.Etype != TFUNC || f.Type.Recv() == nil { 289 Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f) 290 } 291 if f.Type.Recv() == nil { 292 Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f) 293 } 294 if f.Nointerface { 295 continue 296 } 297 298 method := f.Sym 299 if method == nil { 300 continue 301 } 302 303 // get receiver type for this particular method. 304 // if pointer receiver but non-pointer t and 305 // this is not an embedded pointer inside a struct, 306 // method does not apply. 307 this := f.Type.Recv().Type 308 309 if this.IsPtr() && this.Elem() == t { 310 continue 311 } 312 if this.IsPtr() && !t.IsPtr() && f.Embedded != 2 && !isifacemethod(f.Type) { 313 continue 314 } 315 316 var sig Sig 317 ms = append(ms, &sig) 318 319 sig.name = method.Name 320 if !exportname(method.Name) { 321 if method.Pkg == nil { 322 Fatalf("methods: missing package") 323 } 324 sig.pkg = method.Pkg 325 } 326 327 sig.isym = methodsym(method, it, 1) 328 sig.tsym = methodsym(method, t, 0) 329 sig.type_ = methodfunc(f.Type, t) 330 sig.mtype = methodfunc(f.Type, nil) 331 332 if sig.isym.Flags&SymSiggen == 0 { 333 sig.isym.Flags |= SymSiggen 334 if !Eqtype(this, it) || this.Width < Types[Tptr].Width { 335 compiling_wrappers = 1 336 genwrapper(it, f, sig.isym, 1) 337 compiling_wrappers = 0 338 } 339 } 340 341 if sig.tsym.Flags&SymSiggen == 0 { 342 sig.tsym.Flags |= SymSiggen 343 if !Eqtype(this, t) { 344 compiling_wrappers = 1 345 genwrapper(t, f, sig.tsym, 0) 346 compiling_wrappers = 0 347 } 348 } 349 } 350 351 sort.Sort(byMethodNameAndPackagePath(ms)) 352 return ms 353 } 354 355 // imethods returns the methods of the interface type t, sorted by name. 356 func imethods(t *Type) []*Sig { 357 var methods []*Sig 358 for _, f := range t.Fields().Slice() { 359 if f.Type.Etype != TFUNC || f.Sym == nil { 360 continue 361 } 362 method := f.Sym 363 var sig = Sig{ 364 name: method.Name, 365 } 366 if !exportname(method.Name) { 367 if method.Pkg == nil { 368 Fatalf("imethods: missing package") 369 } 370 sig.pkg = method.Pkg 371 } 372 373 sig.mtype = f.Type 374 sig.offset = 0 375 sig.type_ = methodfunc(f.Type, nil) 376 377 if n := len(methods); n > 0 { 378 last := methods[n-1] 379 if !(siglt(last, &sig)) { 380 Fatalf("sigcmp vs sortinter %s %s", last.name, sig.name) 381 } 382 } 383 methods = append(methods, &sig) 384 385 // Compiler can only refer to wrappers for non-blank methods. 386 if isblanksym(method) { 387 continue 388 } 389 390 // NOTE(rsc): Perhaps an oversight that 391 // IfaceType.Method is not in the reflect data. 392 // Generate the method body, so that compiled 393 // code can refer to it. 394 isym := methodsym(method, t, 0) 395 396 if isym.Flags&SymSiggen == 0 { 397 isym.Flags |= SymSiggen 398 genwrapper(t, f, isym, 0) 399 } 400 } 401 402 return methods 403 } 404 405 var dimportpath_gopkg *Pkg 406 407 func dimportpath(p *Pkg) { 408 if p.Pathsym != nil { 409 return 410 } 411 412 // If we are compiling the runtime package, there are two runtime packages around 413 // -- localpkg and Runtimepkg. We don't want to produce import path symbols for 414 // both of them, so just produce one for localpkg. 415 if myimportpath == "runtime" && p == Runtimepkg { 416 return 417 } 418 419 if dimportpath_gopkg == nil { 420 dimportpath_gopkg = mkpkg("go") 421 dimportpath_gopkg.Name = "go" 422 } 423 424 nam := "importpath." + p.Prefix + "." 425 426 n := Nod(ONAME, nil, nil) 427 n.Sym = Pkglookup(nam, dimportpath_gopkg) 428 429 n.Class = PEXTERN 430 n.Xoffset = 0 431 p.Pathsym = n.Sym 432 433 if p == localpkg { 434 // Note: myimportpath != "", or else dgopkgpath won't call dimportpath. 435 gdatastring(n, myimportpath) 436 } else { 437 gdatastring(n, p.Path) 438 } 439 ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA) 440 } 441 442 func dgopkgpath(s *Sym, ot int, pkg *Pkg) int { 443 return dgopkgpathLSym(Linksym(s), ot, pkg) 444 } 445 446 func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int { 447 if pkg == nil { 448 return duintxxLSym(s, ot, 0, Widthptr) 449 } 450 451 if pkg == localpkg && myimportpath == "" { 452 // If we don't know the full import path of the package being compiled 453 // (i.e. -p was not passed on the compiler command line), emit a reference to 454 // go.importpath.""., which the linker will rewrite using the correct import path. 455 // Every package that imports this one directly defines the symbol. 456 // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ. 457 ns := obj.Linklookup(Ctxt, `go.importpath."".`, 0) 458 return dsymptrLSym(s, ot, ns, 0) 459 } 460 461 dimportpath(pkg) 462 return dsymptrLSym(s, ot, Linksym(pkg.Pathsym), 0) 463 } 464 465 // isExportedField reports whether a struct field is exported. 466 func isExportedField(ft *Field) bool { 467 if ft.Sym != nil && ft.Embedded == 0 { 468 return exportname(ft.Sym.Name) 469 } else { 470 if ft.Type.Sym != nil && 471 (ft.Type.Sym.Pkg == builtinpkg || !exportname(ft.Type.Sym.Name)) { 472 return false 473 } else { 474 return true 475 } 476 } 477 } 478 479 // dnameField dumps a reflect.name for a struct field. 480 func dnameField(s *Sym, ot int, ft *Field) int { 481 var name, tag string 482 if ft.Sym != nil && ft.Embedded == 0 { 483 name = ft.Sym.Name 484 } 485 if ft.Note != nil { 486 tag = *ft.Note 487 } 488 return dname(s, ot, name, tag, nil, isExportedField(ft)) 489 } 490 491 var dnameCount int 492 493 // dname dumps a reflect.name for a struct field or method. 494 func dname(s *Sym, ot int, name, tag string, pkg *Pkg, exported bool) int { 495 if len(name) > 1<<16-1 { 496 Fatalf("name too long: %s", name) 497 } 498 if len(tag) > 1<<16-1 { 499 Fatalf("tag too long: %s", tag) 500 } 501 502 // Encode name and tag. See reflect/type.go for details. 503 var bits byte 504 l := 1 + 2 + len(name) 505 if exported { 506 bits |= 1 << 0 507 } 508 if len(tag) > 0 { 509 l += 2 + len(tag) 510 bits |= 1 << 1 511 } 512 if pkg != nil { 513 bits |= 1 << 2 514 } 515 b := make([]byte, l) 516 b[0] = bits 517 b[1] = uint8(len(name) >> 8) 518 b[2] = uint8(len(name)) 519 copy(b[3:], name) 520 if len(tag) > 0 { 521 tb := b[3+len(name):] 522 tb[0] = uint8(len(tag) >> 8) 523 tb[1] = uint8(len(tag)) 524 copy(tb[2:], tag) 525 } 526 527 // Very few names require a pkgPath *string (only those 528 // defined in a different package than their type). So if 529 // there is no pkgPath, we treat the name contents as string 530 // data that duplicates across packages. 531 var bsym *obj.LSym 532 if pkg == nil { 533 _, bsym = stringsym(string(b)) 534 } else { 535 // Write out data as "type.." to signal two things to the 536 // linker, first that when dynamically linking, the symbol 537 // should be moved to a relro section, and second that the 538 // contents should not be decoded as a type. 539 bsymname := fmt.Sprintf(`type..methodname."".%d`, dnameCount) 540 dnameCount++ 541 bsym = obj.Linklookup(Ctxt, bsymname, 0) 542 bsym.P = b 543 boff := len(b) 544 boff = int(Rnd(int64(boff), int64(Widthptr))) 545 boff = dgopkgpathLSym(bsym, boff, pkg) 546 ggloblLSym(bsym, int32(boff), obj.RODATA|obj.LOCAL) 547 } 548 549 ot = dsymptrLSym(Linksym(s), ot, bsym, 0) 550 551 return ot 552 } 553 554 // dextratype dumps the fields of a runtime.uncommontype. 555 // dataAdd is the offset in bytes after the header where the 556 // backing array of the []method field is written (by dextratypeData). 557 func dextratype(s *Sym, ot int, t *Type, dataAdd int) int { 558 m := methods(t) 559 if t.Sym == nil && len(m) == 0 { 560 return ot 561 } 562 noff := int(Rnd(int64(ot), int64(Widthptr))) 563 if noff != ot { 564 Fatalf("unexpected alignment in dextratype for %s", t) 565 } 566 567 for _, a := range m { 568 dtypesym(a.type_) 569 } 570 571 ot = dgopkgpath(s, ot, typePkg(t)) 572 573 // slice header 574 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd) 575 576 n := len(m) 577 ot = duintxx(s, ot, uint64(n), Widthint) 578 ot = duintxx(s, ot, uint64(n), Widthint) 579 580 return ot 581 } 582 583 func typePkg(t *Type) *Pkg { 584 tsym := t.Sym 585 if tsym == nil { 586 switch t.Etype { 587 case TARRAY, TPTR32, TPTR64, TCHAN: 588 if t.Elem() != nil { 589 tsym = t.Elem().Sym 590 } 591 } 592 } 593 if tsym != nil && t != Types[t.Etype] && t != errortype { 594 return tsym.Pkg 595 } 596 return nil 597 } 598 599 // dextratypeData dumps the backing array for the []method field of 600 // runtime.uncommontype. 601 func dextratypeData(s *Sym, ot int, t *Type) int { 602 for _, a := range methods(t) { 603 // ../../../../runtime/type.go:/method 604 exported := exportname(a.name) 605 var pkg *Pkg 606 if !exported && a.pkg != typePkg(t) { 607 pkg = a.pkg 608 } 609 ot = dname(s, ot, a.name, "", pkg, exported) 610 ot = dmethodptr(s, ot, dtypesym(a.mtype)) 611 ot = dmethodptr(s, ot, a.isym) 612 ot = dmethodptr(s, ot, a.tsym) 613 } 614 return ot 615 } 616 617 func dmethodptr(s *Sym, off int, x *Sym) int { 618 duintptr(s, off, 0) 619 r := obj.Addrel(Linksym(s)) 620 r.Off = int32(off) 621 r.Siz = uint8(Widthptr) 622 r.Sym = Linksym(x) 623 r.Type = obj.R_METHOD 624 return off + Widthptr 625 } 626 627 var kinds = []int{ 628 TINT: obj.KindInt, 629 TUINT: obj.KindUint, 630 TINT8: obj.KindInt8, 631 TUINT8: obj.KindUint8, 632 TINT16: obj.KindInt16, 633 TUINT16: obj.KindUint16, 634 TINT32: obj.KindInt32, 635 TUINT32: obj.KindUint32, 636 TINT64: obj.KindInt64, 637 TUINT64: obj.KindUint64, 638 TUINTPTR: obj.KindUintptr, 639 TFLOAT32: obj.KindFloat32, 640 TFLOAT64: obj.KindFloat64, 641 TBOOL: obj.KindBool, 642 TSTRING: obj.KindString, 643 TPTR32: obj.KindPtr, 644 TPTR64: obj.KindPtr, 645 TSTRUCT: obj.KindStruct, 646 TINTER: obj.KindInterface, 647 TCHAN: obj.KindChan, 648 TMAP: obj.KindMap, 649 TARRAY: obj.KindArray, 650 TFUNC: obj.KindFunc, 651 TCOMPLEX64: obj.KindComplex64, 652 TCOMPLEX128: obj.KindComplex128, 653 TUNSAFEPTR: obj.KindUnsafePointer, 654 } 655 656 func haspointers(t *Type) bool { 657 if t.Haspointers != 0 { 658 return t.Haspointers-1 != 0 659 } 660 661 var ret bool 662 switch t.Etype { 663 case TINT, 664 TUINT, 665 TINT8, 666 TUINT8, 667 TINT16, 668 TUINT16, 669 TINT32, 670 TUINT32, 671 TINT64, 672 TUINT64, 673 TUINTPTR, 674 TFLOAT32, 675 TFLOAT64, 676 TCOMPLEX64, 677 TCOMPLEX128, 678 TBOOL: 679 ret = false 680 681 case TARRAY: 682 if t.IsSlice() { 683 ret = true 684 break 685 } 686 687 if t.NumElem() == 0 { // empty array 688 ret = false 689 break 690 } 691 692 ret = haspointers(t.Elem()) 693 694 case TSTRUCT: 695 ret = false 696 for _, t1 := range t.Fields().Slice() { 697 if haspointers(t1.Type) { 698 ret = true 699 break 700 } 701 } 702 703 case TSTRING, 704 TPTR32, 705 TPTR64, 706 TUNSAFEPTR, 707 TINTER, 708 TCHAN, 709 TMAP, 710 TFUNC: 711 fallthrough 712 default: 713 ret = true 714 } 715 716 t.Haspointers = 1 + uint8(obj.Bool2int(ret)) 717 return ret 718 } 719 720 // typeptrdata returns the length in bytes of the prefix of t 721 // containing pointer data. Anything after this offset is scalar data. 722 func typeptrdata(t *Type) int64 { 723 if !haspointers(t) { 724 return 0 725 } 726 727 switch t.Etype { 728 case TPTR32, 729 TPTR64, 730 TUNSAFEPTR, 731 TFUNC, 732 TCHAN, 733 TMAP: 734 return int64(Widthptr) 735 736 case TSTRING: 737 // struct { byte *str; intgo len; } 738 return int64(Widthptr) 739 740 case TINTER: 741 // struct { Itab *tab; void *data; } or 742 // struct { Type *type; void *data; } 743 return 2 * int64(Widthptr) 744 745 case TARRAY: 746 if t.IsSlice() { 747 // struct { byte *array; uintgo len; uintgo cap; } 748 return int64(Widthptr) 749 } 750 // haspointers already eliminated t.NumElem() == 0. 751 return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem()) 752 753 case TSTRUCT: 754 // Find the last field that has pointers. 755 var lastPtrField *Field 756 for _, t1 := range t.Fields().Slice() { 757 if haspointers(t1.Type) { 758 lastPtrField = t1 759 } 760 } 761 return lastPtrField.Offset + typeptrdata(lastPtrField.Type) 762 763 default: 764 Fatalf("typeptrdata: unexpected type, %v", t) 765 return 0 766 } 767 } 768 769 // tflag is documented in ../../../../reflect/type.go. 770 const tflagUncommon = 1 771 772 // commonType 773 // ../../../../runtime/type.go:/commonType 774 775 var dcommontype_algarray *Sym 776 777 func dcommontype(s *Sym, ot int, t *Type) int { 778 if ot != 0 { 779 Fatalf("dcommontype %d", ot) 780 } 781 782 sizeofAlg := 2 * Widthptr 783 if dcommontype_algarray == nil { 784 dcommontype_algarray = Pkglookup("algarray", Runtimepkg) 785 } 786 dowidth(t) 787 alg := algtype(t) 788 var algsym *Sym 789 if alg == ASPECIAL || alg == AMEM { 790 algsym = dalgsym(t) 791 } 792 793 tptr := Ptrto(t) 794 if !t.IsPtr() && (t.Sym != nil || methods(tptr) != nil) { 795 sptr := dtypesym(tptr) 796 r := obj.Addrel(Linksym(s)) 797 r.Off = 0 798 r.Siz = 0 799 r.Sym = sptr.Lsym 800 r.Type = obj.R_USETYPE 801 } 802 803 gcsym, useGCProg, ptrdata := dgcsym(t) 804 805 // ../../../../reflect/type.go:/^type.rtype 806 // actual type structure 807 // type rtype struct { 808 // size uintptr 809 // ptrdata uintptr 810 // hash uint32 811 // tflag tflag 812 // align uint8 813 // fieldAlign uint8 814 // kind uint8 815 // alg *typeAlg 816 // gcdata *byte 817 // string *string 818 // } 819 ot = duintptr(s, ot, uint64(t.Width)) 820 ot = duintptr(s, ot, uint64(ptrdata)) 821 822 ot = duint32(s, ot, typehash(t)) 823 824 var tflag uint8 825 if uncommonSize(t) != 0 { 826 tflag |= tflagUncommon 827 } 828 ot = duint8(s, ot, tflag) 829 830 // runtime (and common sense) expects alignment to be a power of two. 831 i := int(t.Align) 832 833 if i == 0 { 834 i = 1 835 } 836 if i&(i-1) != 0 { 837 Fatalf("invalid alignment %d for %v", t.Align, t) 838 } 839 ot = duint8(s, ot, t.Align) // align 840 ot = duint8(s, ot, t.Align) // fieldAlign 841 842 i = kinds[t.Etype] 843 if t.IsSlice() { 844 i = obj.KindSlice 845 } 846 if !haspointers(t) { 847 i |= obj.KindNoPointers 848 } 849 if isdirectiface(t) { 850 i |= obj.KindDirectIface 851 } 852 if useGCProg { 853 i |= obj.KindGCProg 854 } 855 ot = duint8(s, ot, uint8(i)) // kind 856 if algsym == nil { 857 ot = dsymptr(s, ot, dcommontype_algarray, int(alg)*sizeofAlg) 858 } else { 859 ot = dsymptr(s, ot, algsym, 0) 860 } 861 ot = dsymptr(s, ot, gcsym, 0) // gcdata 862 863 p := Tconv(t, FmtLeft|FmtUnsigned) 864 865 // If we're writing out type T, 866 // we are very likely to write out type *T as well. 867 // Use the string "*T"[1:] for "T", so that the two 868 // share storage. This is a cheap way to reduce the 869 // amount of space taken up by reflect strings. 870 prefix := 0 871 if !strings.HasPrefix(p, "*") { 872 p = "*" + p 873 prefix = 1 874 } 875 _, symdata := stringsym(p) // string 876 ot = dsymptrLSym(Linksym(s), ot, symdata, prefix) 877 ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint) 878 879 return ot 880 } 881 882 func typesym(t *Type) *Sym { 883 return Pkglookup(Tconv(t, FmtLeft), typepkg) 884 } 885 886 // tracksym returns the symbol for tracking use of field/method f, assumed 887 // to be a member of struct/interface type t. 888 func tracksym(t *Type, f *Field) *Sym { 889 return Pkglookup(Tconv(t, FmtLeft)+"."+f.Sym.Name, trackpkg) 890 } 891 892 func typelinksym(t *Type) *Sym { 893 // %-uT is what the generated Type's string field says. 894 // It uses (ambiguous) package names instead of import paths. 895 // %-T is the complete, unambiguous type name. 896 // We want the types to end up sorted by string field, 897 // so use that first in the name, and then add :%-T to 898 // disambiguate. We use a tab character as the separator to 899 // ensure the types appear sorted by their string field. The 900 // names are a little long but they are discarded by the linker 901 // and do not end up in the symbol table of the final binary. 902 p := Tconv(t, FmtLeft|FmtUnsigned) + "\t" + Tconv(t, FmtLeft) 903 904 s := Pkglookup(p, typelinkpkg) 905 906 //print("typelinksym: %s -> %+S\n", p, s); 907 908 return s 909 } 910 911 func typesymprefix(prefix string, t *Type) *Sym { 912 p := prefix + "." + Tconv(t, FmtLeft) 913 s := Pkglookup(p, typepkg) 914 915 //print("algsym: %s -> %+S\n", p, s); 916 917 return s 918 } 919 920 func typenamesym(t *Type) *Sym { 921 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { 922 Fatalf("typename %v", t) 923 } 924 s := typesym(t) 925 if s.Def == nil { 926 n := newname(s) 927 n.Type = Types[TUINT8] 928 n.Class = PEXTERN 929 n.Typecheck = 1 930 s.Def = n 931 932 signatlist = append(signatlist, typenod(t)) 933 } 934 935 return s.Def.Sym 936 } 937 938 func typename(t *Type) *Node { 939 s := typenamesym(t) 940 n := Nod(OADDR, s.Def, nil) 941 n.Type = Ptrto(s.Def.Type) 942 n.Addable = true 943 n.Ullman = 2 944 n.Typecheck = 1 945 return n 946 } 947 948 func itabname(t, itype *Type) *Node { 949 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { 950 Fatalf("itabname %v", t) 951 } 952 s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itabpkg) 953 if s.Def == nil { 954 n := newname(s) 955 n.Type = Types[TUINT8] 956 n.Class = PEXTERN 957 n.Typecheck = 1 958 s.Def = n 959 960 itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s}) 961 } 962 963 n := Nod(OADDR, s.Def, nil) 964 n.Type = Ptrto(s.Def.Type) 965 n.Addable = true 966 n.Ullman = 2 967 n.Typecheck = 1 968 return n 969 } 970 971 // isreflexive reports whether t has a reflexive equality operator. 972 // That is, if x==x for all x of type t. 973 func isreflexive(t *Type) bool { 974 switch t.Etype { 975 case TBOOL, 976 TINT, 977 TUINT, 978 TINT8, 979 TUINT8, 980 TINT16, 981 TUINT16, 982 TINT32, 983 TUINT32, 984 TINT64, 985 TUINT64, 986 TUINTPTR, 987 TPTR32, 988 TPTR64, 989 TUNSAFEPTR, 990 TSTRING, 991 TCHAN: 992 return true 993 994 case TFLOAT32, 995 TFLOAT64, 996 TCOMPLEX64, 997 TCOMPLEX128, 998 TINTER: 999 return false 1000 1001 case TARRAY: 1002 if t.IsSlice() { 1003 Fatalf("slice can't be a map key: %v", t) 1004 } 1005 return isreflexive(t.Elem()) 1006 1007 case TSTRUCT: 1008 for _, t1 := range t.Fields().Slice() { 1009 if !isreflexive(t1.Type) { 1010 return false 1011 } 1012 } 1013 return true 1014 1015 default: 1016 Fatalf("bad type for map key: %v", t) 1017 return false 1018 } 1019 } 1020 1021 // needkeyupdate reports whether map updates with t as a key 1022 // need the key to be updated. 1023 func needkeyupdate(t *Type) bool { 1024 switch t.Etype { 1025 case TBOOL, 1026 TINT, 1027 TUINT, 1028 TINT8, 1029 TUINT8, 1030 TINT16, 1031 TUINT16, 1032 TINT32, 1033 TUINT32, 1034 TINT64, 1035 TUINT64, 1036 TUINTPTR, 1037 TPTR32, 1038 TPTR64, 1039 TUNSAFEPTR, 1040 TCHAN: 1041 return false 1042 1043 case TFLOAT32, // floats can be +0/-0 1044 TFLOAT64, 1045 TCOMPLEX64, 1046 TCOMPLEX128, 1047 TINTER, 1048 TSTRING: // strings might have smaller backing stores 1049 return true 1050 1051 case TARRAY: 1052 if t.IsSlice() { 1053 Fatalf("slice can't be a map key: %v", t) 1054 } 1055 return needkeyupdate(t.Elem()) 1056 1057 case TSTRUCT: 1058 for _, t1 := range t.Fields().Slice() { 1059 if needkeyupdate(t1.Type) { 1060 return true 1061 } 1062 } 1063 return false 1064 1065 default: 1066 Fatalf("bad type for map key: %v", t) 1067 return true 1068 } 1069 } 1070 1071 func dtypesym(t *Type) *Sym { 1072 // Replace byte, rune aliases with real type. 1073 // They've been separate internally to make error messages 1074 // better, but we have to merge them in the reflect tables. 1075 if t == bytetype || t == runetype { 1076 t = Types[t.Etype] 1077 } 1078 1079 if t.IsUntyped() { 1080 Fatalf("dtypesym %v", t) 1081 } 1082 1083 s := typesym(t) 1084 if s.Flags&SymSiggen != 0 { 1085 return s 1086 } 1087 s.Flags |= SymSiggen 1088 1089 // special case (look for runtime below): 1090 // when compiling package runtime, 1091 // emit the type structures for int, float, etc. 1092 tbase := t 1093 1094 if t.IsPtr() && t.Sym == nil && t.Elem().Sym != nil { 1095 tbase = t.Elem() 1096 } 1097 dupok := 0 1098 if tbase.Sym == nil { 1099 dupok = obj.DUPOK 1100 } 1101 1102 if myimportpath == "runtime" && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc 1103 goto ok 1104 } 1105 1106 // named types from other files are defined only by those files 1107 if tbase.Sym != nil && !tbase.Local { 1108 return s 1109 } 1110 if isforw[tbase.Etype] { 1111 return s 1112 } 1113 1114 ok: 1115 ot := 0 1116 switch t.Etype { 1117 default: 1118 ot = dcommontype(s, ot, t) 1119 ot = dextratype(s, ot, t, 0) 1120 1121 case TARRAY: 1122 if t.IsArray() { 1123 // ../../../../runtime/type.go:/arrayType 1124 s1 := dtypesym(t.Elem()) 1125 t2 := typSlice(t.Elem()) 1126 s2 := dtypesym(t2) 1127 ot = dcommontype(s, ot, t) 1128 ot = dsymptr(s, ot, s1, 0) 1129 ot = dsymptr(s, ot, s2, 0) 1130 ot = duintptr(s, ot, uint64(t.NumElem())) 1131 } else { 1132 // ../../../../runtime/type.go:/sliceType 1133 s1 := dtypesym(t.Elem()) 1134 1135 ot = dcommontype(s, ot, t) 1136 ot = dsymptr(s, ot, s1, 0) 1137 } 1138 ot = dextratype(s, ot, t, 0) 1139 1140 // ../../../../runtime/type.go:/chanType 1141 case TCHAN: 1142 s1 := dtypesym(t.Elem()) 1143 1144 ot = dcommontype(s, ot, t) 1145 ot = dsymptr(s, ot, s1, 0) 1146 ot = duintptr(s, ot, uint64(t.ChanDir())) 1147 ot = dextratype(s, ot, t, 0) 1148 1149 case TFUNC: 1150 for _, t1 := range t.Recvs().Fields().Slice() { 1151 dtypesym(t1.Type) 1152 } 1153 isddd := false 1154 for _, t1 := range t.Params().Fields().Slice() { 1155 isddd = t1.Isddd 1156 dtypesym(t1.Type) 1157 } 1158 for _, t1 := range t.Results().Fields().Slice() { 1159 dtypesym(t1.Type) 1160 } 1161 1162 ot = dcommontype(s, ot, t) 1163 inCount := t.Recvs().NumFields() + t.Params().NumFields() 1164 outCount := t.Results().NumFields() 1165 if isddd { 1166 outCount |= 1 << 15 1167 } 1168 ot = duint16(s, ot, uint16(inCount)) 1169 ot = duint16(s, ot, uint16(outCount)) 1170 if Widthptr == 8 { 1171 ot += 4 // align for *rtype 1172 } 1173 1174 dataAdd := (inCount + t.Results().NumFields()) * Widthptr 1175 ot = dextratype(s, ot, t, dataAdd) 1176 1177 // Array of rtype pointers follows funcType. 1178 for _, t1 := range t.Recvs().Fields().Slice() { 1179 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1180 } 1181 for _, t1 := range t.Params().Fields().Slice() { 1182 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1183 } 1184 for _, t1 := range t.Results().Fields().Slice() { 1185 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1186 } 1187 1188 case TINTER: 1189 m := imethods(t) 1190 n := len(m) 1191 for _, a := range m { 1192 dtypesym(a.type_) 1193 } 1194 1195 // ../../../../runtime/type.go:/interfaceType 1196 ot = dcommontype(s, ot, t) 1197 1198 var tpkg *Pkg 1199 if t.Sym != nil && t != Types[t.Etype] && t != errortype { 1200 tpkg = t.Sym.Pkg 1201 } 1202 ot = dgopkgpath(s, ot, tpkg) 1203 1204 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1205 ot = duintxx(s, ot, uint64(n), Widthint) 1206 ot = duintxx(s, ot, uint64(n), Widthint) 1207 dataAdd := imethodSize() * n 1208 ot = dextratype(s, ot, t, dataAdd) 1209 1210 for _, a := range m { 1211 // ../../../../runtime/type.go:/imethod 1212 exported := exportname(a.name) 1213 var pkg *Pkg 1214 if !exported && a.pkg != tpkg { 1215 pkg = a.pkg 1216 } 1217 ot = dname(s, ot, a.name, "", pkg, exported) 1218 ot = dsymptr(s, ot, dtypesym(a.type_), 0) 1219 } 1220 1221 // ../../../../runtime/type.go:/mapType 1222 case TMAP: 1223 s1 := dtypesym(t.Key()) 1224 s2 := dtypesym(t.Val()) 1225 s3 := dtypesym(mapbucket(t)) 1226 s4 := dtypesym(hmap(t)) 1227 ot = dcommontype(s, ot, t) 1228 ot = dsymptr(s, ot, s1, 0) 1229 ot = dsymptr(s, ot, s2, 0) 1230 ot = dsymptr(s, ot, s3, 0) 1231 ot = dsymptr(s, ot, s4, 0) 1232 if t.Key().Width > MAXKEYSIZE { 1233 ot = duint8(s, ot, uint8(Widthptr)) 1234 ot = duint8(s, ot, 1) // indirect 1235 } else { 1236 ot = duint8(s, ot, uint8(t.Key().Width)) 1237 ot = duint8(s, ot, 0) // not indirect 1238 } 1239 1240 if t.Val().Width > MAXVALSIZE { 1241 ot = duint8(s, ot, uint8(Widthptr)) 1242 ot = duint8(s, ot, 1) // indirect 1243 } else { 1244 ot = duint8(s, ot, uint8(t.Val().Width)) 1245 ot = duint8(s, ot, 0) // not indirect 1246 } 1247 1248 ot = duint16(s, ot, uint16(mapbucket(t).Width)) 1249 ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key())))) 1250 ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key())))) 1251 ot = dextratype(s, ot, t, 0) 1252 1253 case TPTR32, TPTR64: 1254 if t.Elem().Etype == TANY { 1255 // ../../../../runtime/type.go:/UnsafePointerType 1256 ot = dcommontype(s, ot, t) 1257 ot = dextratype(s, ot, t, 0) 1258 1259 break 1260 } 1261 1262 // ../../../../runtime/type.go:/ptrType 1263 s1 := dtypesym(t.Elem()) 1264 1265 ot = dcommontype(s, ot, t) 1266 ot = dsymptr(s, ot, s1, 0) 1267 ot = dextratype(s, ot, t, 0) 1268 1269 // ../../../../runtime/type.go:/structType 1270 // for security, only the exported fields. 1271 case TSTRUCT: 1272 n := 0 1273 1274 for _, t1 := range t.Fields().Slice() { 1275 dtypesym(t1.Type) 1276 n++ 1277 } 1278 1279 ot = dcommontype(s, ot, t) 1280 pkg := localpkg 1281 if t.Sym != nil { 1282 pkg = t.Sym.Pkg 1283 } 1284 ot = dgopkgpath(s, ot, pkg) 1285 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1286 ot = duintxx(s, ot, uint64(n), Widthint) 1287 ot = duintxx(s, ot, uint64(n), Widthint) 1288 1289 dataAdd := n * structfieldSize() 1290 ot = dextratype(s, ot, t, dataAdd) 1291 1292 for _, f := range t.Fields().Slice() { 1293 // ../../../../runtime/type.go:/structField 1294 ot = dnameField(s, ot, f) 1295 ot = dsymptr(s, ot, dtypesym(f.Type), 0) 1296 ot = duintptr(s, ot, uint64(f.Offset)) 1297 } 1298 } 1299 1300 ot = dextratypeData(s, ot, t) 1301 ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) 1302 1303 // generate typelink.foo pointing at s = type.foo. 1304 // The linker will leave a table of all the typelinks for 1305 // types in the binary, so reflect can find them. 1306 // We only need the link for unnamed composites that 1307 // we want be able to find. 1308 if t.Sym == nil { 1309 switch t.Etype { 1310 case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSTRUCT: 1311 slink := typelinksym(t) 1312 dsymptr(slink, 0, s, 0) 1313 ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA)) 1314 } 1315 } 1316 1317 return s 1318 } 1319 1320 func dumptypestructs() { 1321 // copy types from externdcl list to signatlist 1322 for _, n := range externdcl { 1323 if n.Op != OTYPE { 1324 continue 1325 } 1326 signatlist = append(signatlist, n) 1327 } 1328 1329 // Process signatlist. This can't use range, as entries are 1330 // added to the list while it is being processed. 1331 for i := 0; i < len(signatlist); i++ { 1332 n := signatlist[i] 1333 if n.Op != OTYPE { 1334 continue 1335 } 1336 t := n.Type 1337 dtypesym(t) 1338 if t.Sym != nil { 1339 dtypesym(Ptrto(t)) 1340 } 1341 } 1342 1343 // process itabs 1344 for _, i := range itabs { 1345 // dump empty itab symbol into i.sym 1346 // type itab struct { 1347 // inter *interfacetype 1348 // _type *_type 1349 // link *itab 1350 // bad int32 1351 // unused int32 1352 // fun [1]uintptr // variable sized 1353 // } 1354 o := dsymptr(i.sym, 0, dtypesym(i.itype), 0) 1355 o = dsymptr(i.sym, o, dtypesym(i.t), 0) 1356 o += Widthptr + 8 // skip link/bad/unused fields 1357 o += len(imethods(i.itype)) * Widthptr // skip fun method pointers 1358 // at runtime the itab will contain pointers to types, other itabs and 1359 // method functions. None are allocated on heap, so we can use obj.NOPTR. 1360 ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR)) 1361 1362 ilink := Pkglookup(Tconv(i.t, FmtLeft)+","+Tconv(i.itype, FmtLeft), itablinkpkg) 1363 dsymptr(ilink, 0, i.sym, 0) 1364 ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA)) 1365 } 1366 1367 // generate import strings for imported packages 1368 for _, p := range pkgs { 1369 if p.Direct { 1370 dimportpath(p) 1371 } 1372 } 1373 1374 // do basic types if compiling package runtime. 1375 // they have to be in at least one package, 1376 // and runtime is always loaded implicitly, 1377 // so this is as good as any. 1378 // another possible choice would be package main, 1379 // but using runtime means fewer copies in .6 files. 1380 if myimportpath == "runtime" { 1381 for i := EType(1); i <= TBOOL; i++ { 1382 dtypesym(Ptrto(Types[i])) 1383 } 1384 dtypesym(Ptrto(Types[TSTRING])) 1385 dtypesym(Ptrto(Types[TUNSAFEPTR])) 1386 1387 // emit type structs for error and func(error) string. 1388 // The latter is the type of an auto-generated wrapper. 1389 dtypesym(Ptrto(errortype)) 1390 1391 dtypesym(functype(nil, []*Node{Nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{Nod(ODCLFIELD, nil, typenod(Types[TSTRING]))})) 1392 1393 // add paths for runtime and main, which 6l imports implicitly. 1394 dimportpath(Runtimepkg) 1395 1396 if flag_race != 0 { 1397 dimportpath(racepkg) 1398 } 1399 if flag_msan != 0 { 1400 dimportpath(msanpkg) 1401 } 1402 dimportpath(mkpkg("main")) 1403 } 1404 } 1405 1406 func dalgsym(t *Type) *Sym { 1407 var s *Sym 1408 var hashfunc *Sym 1409 var eqfunc *Sym 1410 1411 // dalgsym is only called for a type that needs an algorithm table, 1412 // which implies that the type is comparable (or else it would use ANOEQ). 1413 1414 if algtype(t) == AMEM { 1415 // we use one algorithm table for all AMEM types of a given size 1416 p := fmt.Sprintf(".alg%d", t.Width) 1417 1418 s = Pkglookup(p, typepkg) 1419 1420 if s.Flags&SymAlgGen != 0 { 1421 return s 1422 } 1423 s.Flags |= SymAlgGen 1424 1425 // make hash closure 1426 p = fmt.Sprintf(".hashfunc%d", t.Width) 1427 1428 hashfunc = Pkglookup(p, typepkg) 1429 1430 ot := 0 1431 ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0) 1432 ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure 1433 ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA) 1434 1435 // make equality closure 1436 p = fmt.Sprintf(".eqfunc%d", t.Width) 1437 1438 eqfunc = Pkglookup(p, typepkg) 1439 1440 ot = 0 1441 ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0) 1442 ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr) 1443 ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA) 1444 } else { 1445 // generate an alg table specific to this type 1446 s = typesymprefix(".alg", t) 1447 1448 hash := typesymprefix(".hash", t) 1449 eq := typesymprefix(".eq", t) 1450 hashfunc = typesymprefix(".hashfunc", t) 1451 eqfunc = typesymprefix(".eqfunc", t) 1452 1453 genhash(hash, t) 1454 geneq(eq, t) 1455 1456 // make Go funcs (closures) for calling hash and equal from Go 1457 dsymptr(hashfunc, 0, hash, 0) 1458 1459 ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1460 dsymptr(eqfunc, 0, eq, 0) 1461 ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1462 } 1463 1464 // ../../../../runtime/alg.go:/typeAlg 1465 ot := 0 1466 1467 ot = dsymptr(s, ot, hashfunc, 0) 1468 ot = dsymptr(s, ot, eqfunc, 0) 1469 ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA) 1470 return s 1471 } 1472 1473 // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, 1474 // which holds 1-bit entries describing where pointers are in a given type. 1475 // 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes 1476 // depending on the system. Above this length, the GC information is 1477 // recorded as a GC program, which can express repetition compactly. 1478 // In either form, the information is used by the runtime to initialize the 1479 // heap bitmap, and for large types (like 128 or more words), they are 1480 // roughly the same speed. GC programs are never much larger and often 1481 // more compact. (If large arrays are involved, they can be arbitrarily more 1482 // compact.) 1483 // 1484 // The cutoff must be large enough that any allocation large enough to 1485 // use a GC program is large enough that it does not share heap bitmap 1486 // bytes with any other objects, allowing the GC program execution to 1487 // assume an aligned start and not use atomic operations. In the current 1488 // runtime, this means all malloc size classes larger than the cutoff must 1489 // be multiples of four words. On 32-bit systems that's 16 bytes, and 1490 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint. 1491 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed 1492 // for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated 1493 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes 1494 // must be >= 4. 1495 // 1496 // We used to use 16 because the GC programs do have some constant overhead 1497 // to get started, and processing 128 pointers seems to be enough to 1498 // amortize that overhead well. 1499 // 1500 // To make sure that the runtime's chansend can call typeBitsBulkBarrier, 1501 // we raised the limit to 2048, so that even 32-bit systems are guaranteed to 1502 // use bitmaps for objects up to 64 kB in size. 1503 // 1504 // Also known to reflect/type.go. 1505 // 1506 const maxPtrmaskBytes = 2048 1507 1508 // dgcsym emits and returns a data symbol containing GC information for type t, 1509 // along with a boolean reporting whether the UseGCProg bit should be set in 1510 // the type kind, and the ptrdata field to record in the reflect type information. 1511 func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { 1512 ptrdata = typeptrdata(t) 1513 if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { 1514 sym = dgcptrmask(t) 1515 return 1516 } 1517 1518 useGCProg = true 1519 sym, ptrdata = dgcprog(t) 1520 return 1521 } 1522 1523 // dgcptrmask emits and returns the symbol containing a pointer mask for type t. 1524 func dgcptrmask(t *Type) *Sym { 1525 ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) 1526 fillptrmask(t, ptrmask) 1527 p := fmt.Sprintf("gcbits.%x", ptrmask) 1528 1529 sym := Pkglookup(p, Runtimepkg) 1530 if sym.Flags&SymUniq == 0 { 1531 sym.Flags |= SymUniq 1532 for i, x := range ptrmask { 1533 duint8(sym, i, x) 1534 } 1535 ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) 1536 } 1537 return sym 1538 } 1539 1540 // fillptrmask fills in ptrmask with 1s corresponding to the 1541 // word offsets in t that hold pointers. 1542 // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. 1543 func fillptrmask(t *Type, ptrmask []byte) { 1544 for i := range ptrmask { 1545 ptrmask[i] = 0 1546 } 1547 if !haspointers(t) { 1548 return 1549 } 1550 1551 vec := bvalloc(8 * int32(len(ptrmask))) 1552 xoffset := int64(0) 1553 onebitwalktype1(t, &xoffset, vec) 1554 1555 nptr := typeptrdata(t) / int64(Widthptr) 1556 for i := int64(0); i < nptr; i++ { 1557 if bvget(vec, int32(i)) == 1 { 1558 ptrmask[i/8] |= 1 << (uint(i) % 8) 1559 } 1560 } 1561 } 1562 1563 // dgcprog emits and returns the symbol containing a GC program for type t 1564 // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). 1565 // In practice, the size is typeptrdata(t) except for non-trivial arrays. 1566 // For non-trivial arrays, the program describes the full t.Width size. 1567 func dgcprog(t *Type) (*Sym, int64) { 1568 dowidth(t) 1569 if t.Width == BADWIDTH { 1570 Fatalf("dgcprog: %v badwidth", t) 1571 } 1572 sym := typesymprefix(".gcprog", t) 1573 var p GCProg 1574 p.init(sym) 1575 p.emit(t, 0) 1576 offset := p.w.BitIndex() * int64(Widthptr) 1577 p.end() 1578 if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { 1579 Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) 1580 } 1581 return sym, offset 1582 } 1583 1584 type GCProg struct { 1585 sym *Sym 1586 symoff int 1587 w gcprog.Writer 1588 } 1589 1590 var Debug_gcprog int // set by -d gcprog 1591 1592 func (p *GCProg) init(sym *Sym) { 1593 p.sym = sym 1594 p.symoff = 4 // first 4 bytes hold program length 1595 p.w.Init(p.writeByte) 1596 if Debug_gcprog > 0 { 1597 fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) 1598 p.w.Debug(os.Stderr) 1599 } 1600 } 1601 1602 func (p *GCProg) writeByte(x byte) { 1603 p.symoff = duint8(p.sym, p.symoff, x) 1604 } 1605 1606 func (p *GCProg) end() { 1607 p.w.End() 1608 duint32(p.sym, 0, uint32(p.symoff-4)) 1609 ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) 1610 if Debug_gcprog > 0 { 1611 fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) 1612 } 1613 } 1614 1615 func (p *GCProg) emit(t *Type, offset int64) { 1616 dowidth(t) 1617 if !haspointers(t) { 1618 return 1619 } 1620 if t.Width == int64(Widthptr) { 1621 p.w.Ptr(offset / int64(Widthptr)) 1622 return 1623 } 1624 switch t.Etype { 1625 default: 1626 Fatalf("GCProg.emit: unexpected type %v", t) 1627 1628 case TSTRING: 1629 p.w.Ptr(offset / int64(Widthptr)) 1630 1631 case TINTER: 1632 p.w.Ptr(offset / int64(Widthptr)) 1633 p.w.Ptr(offset/int64(Widthptr) + 1) 1634 1635 case TARRAY: 1636 if t.IsSlice() { 1637 p.w.Ptr(offset / int64(Widthptr)) 1638 return 1639 } 1640 if t.NumElem() == 0 { 1641 // should have been handled by haspointers check above 1642 Fatalf("GCProg.emit: empty array") 1643 } 1644 1645 // Flatten array-of-array-of-array to just a big array by multiplying counts. 1646 count := t.NumElem() 1647 elem := t.Elem() 1648 for elem.IsArray() { 1649 count *= elem.NumElem() 1650 elem = elem.Elem() 1651 } 1652 1653 if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { 1654 // Cheaper to just emit the bits. 1655 for i := int64(0); i < count; i++ { 1656 p.emit(elem, offset+i*elem.Width) 1657 } 1658 return 1659 } 1660 p.emit(elem, offset) 1661 p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) 1662 p.w.Repeat(elem.Width/int64(Widthptr), count-1) 1663 1664 case TSTRUCT: 1665 for _, t1 := range t.Fields().Slice() { 1666 p.emit(t1.Type, offset+t1.Offset) 1667 } 1668 } 1669 }