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