github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 && ft.Embedded == 0 { 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 ot = duintptr(s, ot, uint64(f.Offset)) 1349 } 1350 } 1351 1352 ot = dextratypeData(s, ot, t) 1353 ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) 1354 1355 // The linker will leave a table of all the typelinks for 1356 // types in the binary, so the runtime can find them. 1357 // 1358 // When buildmode=shared, all types are in typelinks so the 1359 // runtime can deduplicate type pointers. 1360 keep := Ctxt.Flag_dynlink 1361 if !keep && t.Sym == nil { 1362 // For an unnamed type, we only need the link if the type can 1363 // be created at run time by reflect.PtrTo and similar 1364 // functions. If the type exists in the program, those 1365 // functions must return the existing type structure rather 1366 // than creating a new one. 1367 switch t.Etype { 1368 case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT: 1369 keep = true 1370 } 1371 } 1372 s.Lsym.Set(obj.AttrMakeTypelink, keep) 1373 1374 return s 1375 } 1376 1377 func dumptypestructs() { 1378 // copy types from externdcl list to signatlist 1379 for _, n := range externdcl { 1380 if n.Op != OTYPE { 1381 continue 1382 } 1383 signatlist = append(signatlist, n) 1384 } 1385 1386 // Process signatlist. This can't use range, as entries are 1387 // added to the list while it is being processed. 1388 for i := 0; i < len(signatlist); i++ { 1389 n := signatlist[i] 1390 if n.Op != OTYPE { 1391 continue 1392 } 1393 t := n.Type 1394 dtypesym(t) 1395 if t.Sym != nil { 1396 dtypesym(ptrto(t)) 1397 } 1398 } 1399 1400 // process itabs 1401 for _, i := range itabs { 1402 // dump empty itab symbol into i.sym 1403 // type itab struct { 1404 // inter *interfacetype 1405 // _type *_type 1406 // link *itab 1407 // bad int32 1408 // unused int32 1409 // fun [1]uintptr // variable sized 1410 // } 1411 o := dsymptr(i.sym, 0, dtypesym(i.itype), 0) 1412 o = dsymptr(i.sym, o, dtypesym(i.t), 0) 1413 o += Widthptr + 8 // skip link/bad/inhash fields 1414 o += len(imethods(i.itype)) * Widthptr // skip fun method pointers 1415 // at runtime the itab will contain pointers to types, other itabs and 1416 // method functions. None are allocated on heap, so we can use obj.NOPTR. 1417 ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR)) 1418 1419 ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg) 1420 dsymptr(ilink, 0, i.sym, 0) 1421 ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA)) 1422 } 1423 1424 // process ptabs 1425 if localpkg.Name == "main" && len(ptabs) > 0 { 1426 ot := 0 1427 s := obj.Linklookup(Ctxt, "go.plugin.tabs", 0) 1428 for _, p := range ptabs { 1429 // Dump ptab symbol into go.pluginsym package. 1430 // 1431 // type ptab struct { 1432 // name nameOff 1433 // typ typeOff // pointer to symbol 1434 // } 1435 nsym := dname(p.s.Name, "", nil, true) 1436 ot = dsymptrOffLSym(s, ot, nsym, 0) 1437 ot = dsymptrOffLSym(s, ot, Linksym(dtypesym(p.t)), 0) 1438 } 1439 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1440 1441 ot = 0 1442 s = obj.Linklookup(Ctxt, "go.plugin.exports", 0) 1443 for _, p := range ptabs { 1444 ot = dsymptrLSym(s, ot, Linksym(p.s), 0) 1445 } 1446 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1447 } 1448 1449 // generate import strings for imported packages 1450 if forceObjFileStability { 1451 // Sorting the packages is not necessary but to compare binaries created 1452 // using textual and binary format we sort by path to reduce differences. 1453 sort.Sort(pkgByPath(pkgs)) 1454 } 1455 for _, p := range pkgs { 1456 if p.Direct { 1457 dimportpath(p) 1458 } 1459 } 1460 1461 // do basic types if compiling package runtime. 1462 // they have to be in at least one package, 1463 // and runtime is always loaded implicitly, 1464 // so this is as good as any. 1465 // another possible choice would be package main, 1466 // but using runtime means fewer copies in .6 files. 1467 if myimportpath == "runtime" { 1468 for i := EType(1); i <= TBOOL; i++ { 1469 dtypesym(ptrto(Types[i])) 1470 } 1471 dtypesym(ptrto(Types[TSTRING])) 1472 dtypesym(ptrto(Types[TUNSAFEPTR])) 1473 1474 // emit type structs for error and func(error) string. 1475 // The latter is the type of an auto-generated wrapper. 1476 dtypesym(ptrto(errortype)) 1477 1478 dtypesym(functype(nil, []*Node{nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{nod(ODCLFIELD, nil, typenod(Types[TSTRING]))})) 1479 1480 // add paths for runtime and main, which 6l imports implicitly. 1481 dimportpath(Runtimepkg) 1482 1483 if flag_race { 1484 dimportpath(racepkg) 1485 } 1486 if flag_msan { 1487 dimportpath(msanpkg) 1488 } 1489 dimportpath(mkpkg("main")) 1490 } 1491 } 1492 1493 type pkgByPath []*Pkg 1494 1495 func (a pkgByPath) Len() int { return len(a) } 1496 func (a pkgByPath) Less(i, j int) bool { return a[i].Path < a[j].Path } 1497 func (a pkgByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1498 1499 func dalgsym(t *Type) *Sym { 1500 var s *Sym 1501 var hashfunc *Sym 1502 var eqfunc *Sym 1503 1504 // dalgsym is only called for a type that needs an algorithm table, 1505 // which implies that the type is comparable (or else it would use ANOEQ). 1506 1507 if algtype(t) == AMEM { 1508 // we use one algorithm table for all AMEM types of a given size 1509 p := fmt.Sprintf(".alg%d", t.Width) 1510 1511 s = Pkglookup(p, typepkg) 1512 1513 if s.Flags&SymAlgGen != 0 { 1514 return s 1515 } 1516 s.Flags |= SymAlgGen 1517 1518 // make hash closure 1519 p = fmt.Sprintf(".hashfunc%d", t.Width) 1520 1521 hashfunc = Pkglookup(p, typepkg) 1522 1523 ot := 0 1524 ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0) 1525 ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure 1526 ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA) 1527 1528 // make equality closure 1529 p = fmt.Sprintf(".eqfunc%d", t.Width) 1530 1531 eqfunc = Pkglookup(p, typepkg) 1532 1533 ot = 0 1534 ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0) 1535 ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr) 1536 ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA) 1537 } else { 1538 // generate an alg table specific to this type 1539 s = typesymprefix(".alg", t) 1540 1541 hash := typesymprefix(".hash", t) 1542 eq := typesymprefix(".eq", t) 1543 hashfunc = typesymprefix(".hashfunc", t) 1544 eqfunc = typesymprefix(".eqfunc", t) 1545 1546 genhash(hash, t) 1547 geneq(eq, t) 1548 1549 // make Go funcs (closures) for calling hash and equal from Go 1550 dsymptr(hashfunc, 0, hash, 0) 1551 1552 ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1553 dsymptr(eqfunc, 0, eq, 0) 1554 ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1555 } 1556 1557 // ../../../../runtime/alg.go:/typeAlg 1558 ot := 0 1559 1560 ot = dsymptr(s, ot, hashfunc, 0) 1561 ot = dsymptr(s, ot, eqfunc, 0) 1562 ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA) 1563 return s 1564 } 1565 1566 // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, 1567 // which holds 1-bit entries describing where pointers are in a given type. 1568 // 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes 1569 // depending on the system. Above this length, the GC information is 1570 // recorded as a GC program, which can express repetition compactly. 1571 // In either form, the information is used by the runtime to initialize the 1572 // heap bitmap, and for large types (like 128 or more words), they are 1573 // roughly the same speed. GC programs are never much larger and often 1574 // more compact. (If large arrays are involved, they can be arbitrarily more 1575 // compact.) 1576 // 1577 // The cutoff must be large enough that any allocation large enough to 1578 // use a GC program is large enough that it does not share heap bitmap 1579 // bytes with any other objects, allowing the GC program execution to 1580 // assume an aligned start and not use atomic operations. In the current 1581 // runtime, this means all malloc size classes larger than the cutoff must 1582 // be multiples of four words. On 32-bit systems that's 16 bytes, and 1583 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint. 1584 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed 1585 // for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated 1586 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes 1587 // must be >= 4. 1588 // 1589 // We used to use 16 because the GC programs do have some constant overhead 1590 // to get started, and processing 128 pointers seems to be enough to 1591 // amortize that overhead well. 1592 // 1593 // To make sure that the runtime's chansend can call typeBitsBulkBarrier, 1594 // we raised the limit to 2048, so that even 32-bit systems are guaranteed to 1595 // use bitmaps for objects up to 64 kB in size. 1596 // 1597 // Also known to reflect/type.go. 1598 // 1599 const maxPtrmaskBytes = 2048 1600 1601 // dgcsym emits and returns a data symbol containing GC information for type t, 1602 // along with a boolean reporting whether the UseGCProg bit should be set in 1603 // the type kind, and the ptrdata field to record in the reflect type information. 1604 func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { 1605 ptrdata = typeptrdata(t) 1606 if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { 1607 sym = dgcptrmask(t) 1608 return 1609 } 1610 1611 useGCProg = true 1612 sym, ptrdata = dgcprog(t) 1613 return 1614 } 1615 1616 // dgcptrmask emits and returns the symbol containing a pointer mask for type t. 1617 func dgcptrmask(t *Type) *Sym { 1618 ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) 1619 fillptrmask(t, ptrmask) 1620 p := fmt.Sprintf("gcbits.%x", ptrmask) 1621 1622 sym := Pkglookup(p, Runtimepkg) 1623 if sym.Flags&SymUniq == 0 { 1624 sym.Flags |= SymUniq 1625 for i, x := range ptrmask { 1626 duint8(sym, i, x) 1627 } 1628 ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) 1629 } 1630 return sym 1631 } 1632 1633 // fillptrmask fills in ptrmask with 1s corresponding to the 1634 // word offsets in t that hold pointers. 1635 // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. 1636 func fillptrmask(t *Type, ptrmask []byte) { 1637 for i := range ptrmask { 1638 ptrmask[i] = 0 1639 } 1640 if !haspointers(t) { 1641 return 1642 } 1643 1644 vec := bvalloc(8 * int32(len(ptrmask))) 1645 xoffset := int64(0) 1646 onebitwalktype1(t, &xoffset, vec) 1647 1648 nptr := typeptrdata(t) / int64(Widthptr) 1649 for i := int64(0); i < nptr; i++ { 1650 if vec.Get(int32(i)) { 1651 ptrmask[i/8] |= 1 << (uint(i) % 8) 1652 } 1653 } 1654 } 1655 1656 // dgcprog emits and returns the symbol containing a GC program for type t 1657 // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). 1658 // In practice, the size is typeptrdata(t) except for non-trivial arrays. 1659 // For non-trivial arrays, the program describes the full t.Width size. 1660 func dgcprog(t *Type) (*Sym, int64) { 1661 dowidth(t) 1662 if t.Width == BADWIDTH { 1663 Fatalf("dgcprog: %v badwidth", t) 1664 } 1665 sym := typesymprefix(".gcprog", t) 1666 var p GCProg 1667 p.init(sym) 1668 p.emit(t, 0) 1669 offset := p.w.BitIndex() * int64(Widthptr) 1670 p.end() 1671 if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { 1672 Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) 1673 } 1674 return sym, offset 1675 } 1676 1677 type GCProg struct { 1678 sym *Sym 1679 symoff int 1680 w gcprog.Writer 1681 } 1682 1683 var Debug_gcprog int // set by -d gcprog 1684 1685 func (p *GCProg) init(sym *Sym) { 1686 p.sym = sym 1687 p.symoff = 4 // first 4 bytes hold program length 1688 p.w.Init(p.writeByte) 1689 if Debug_gcprog > 0 { 1690 fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) 1691 p.w.Debug(os.Stderr) 1692 } 1693 } 1694 1695 func (p *GCProg) writeByte(x byte) { 1696 p.symoff = duint8(p.sym, p.symoff, x) 1697 } 1698 1699 func (p *GCProg) end() { 1700 p.w.End() 1701 duint32(p.sym, 0, uint32(p.symoff-4)) 1702 ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) 1703 if Debug_gcprog > 0 { 1704 fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) 1705 } 1706 } 1707 1708 func (p *GCProg) emit(t *Type, offset int64) { 1709 dowidth(t) 1710 if !haspointers(t) { 1711 return 1712 } 1713 if t.Width == int64(Widthptr) { 1714 p.w.Ptr(offset / int64(Widthptr)) 1715 return 1716 } 1717 switch t.Etype { 1718 default: 1719 Fatalf("GCProg.emit: unexpected type %v", t) 1720 1721 case TSTRING: 1722 p.w.Ptr(offset / int64(Widthptr)) 1723 1724 case TINTER: 1725 p.w.Ptr(offset / int64(Widthptr)) 1726 p.w.Ptr(offset/int64(Widthptr) + 1) 1727 1728 case TSLICE: 1729 p.w.Ptr(offset / int64(Widthptr)) 1730 1731 case TARRAY: 1732 if t.NumElem() == 0 { 1733 // should have been handled by haspointers check above 1734 Fatalf("GCProg.emit: empty array") 1735 } 1736 1737 // Flatten array-of-array-of-array to just a big array by multiplying counts. 1738 count := t.NumElem() 1739 elem := t.Elem() 1740 for elem.IsArray() { 1741 count *= elem.NumElem() 1742 elem = elem.Elem() 1743 } 1744 1745 if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { 1746 // Cheaper to just emit the bits. 1747 for i := int64(0); i < count; i++ { 1748 p.emit(elem, offset+i*elem.Width) 1749 } 1750 return 1751 } 1752 p.emit(elem, offset) 1753 p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) 1754 p.w.Repeat(elem.Width/int64(Widthptr), count-1) 1755 1756 case TSTRUCT: 1757 for _, t1 := range t.Fields().Slice() { 1758 p.emit(t1.Type, offset+t1.Offset) 1759 } 1760 } 1761 } 1762 1763 // zeroaddr returns the address of a symbol with at least 1764 // size bytes of zeros. 1765 func zeroaddr(size int64) *Node { 1766 if size >= 1<<31 { 1767 Fatalf("map value too big %d", size) 1768 } 1769 if zerosize < size { 1770 zerosize = size 1771 } 1772 s := Pkglookup("zero", mappkg) 1773 if s.Def == nil { 1774 x := newname(s) 1775 x.Type = Types[TUINT8] 1776 x.Class = PEXTERN 1777 x.Typecheck = 1 1778 s.Def = x 1779 } 1780 z := nod(OADDR, s.Def, nil) 1781 z.Type = ptrto(Types[TUINT8]) 1782 z.Addable = true 1783 z.Typecheck = 1 1784 return z 1785 }