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