github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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 func isExportedField(ft *Field) bool { 498 if ft.Sym != nil && ft.Embedded == 0 { 499 return exportname(ft.Sym.Name) 500 } else { 501 if ft.Type.Sym != nil && 502 (ft.Type.Sym.Pkg == builtinpkg || !exportname(ft.Type.Sym.Name)) { 503 return false 504 } else { 505 return true 506 } 507 } 508 } 509 510 // dnameField dumps a reflect.name for a struct field. 511 func dnameField(s *Sym, ot int, ft *Field) int { 512 var name string 513 if ft.Sym != nil && ft.Embedded == 0 { 514 name = ft.Sym.Name 515 } 516 nsym := dname(name, ft.Note, nil, isExportedField(ft)) 517 return dsymptrLSym(Linksym(s), ot, nsym, 0) 518 } 519 520 // dnameData writes the contents of a reflect.name into s at offset ot. 521 func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) int { 522 if len(name) > 1<<16-1 { 523 Fatalf("name too long: %s", name) 524 } 525 if len(tag) > 1<<16-1 { 526 Fatalf("tag too long: %s", tag) 527 } 528 529 // Encode name and tag. See reflect/type.go for details. 530 var bits byte 531 l := 1 + 2 + len(name) 532 if exported { 533 bits |= 1 << 0 534 } 535 if len(tag) > 0 { 536 l += 2 + len(tag) 537 bits |= 1 << 1 538 } 539 if pkg != nil { 540 bits |= 1 << 2 541 } 542 b := make([]byte, l) 543 b[0] = bits 544 b[1] = uint8(len(name) >> 8) 545 b[2] = uint8(len(name)) 546 copy(b[3:], name) 547 if len(tag) > 0 { 548 tb := b[3+len(name):] 549 tb[0] = uint8(len(tag) >> 8) 550 tb[1] = uint8(len(tag)) 551 copy(tb[2:], tag) 552 } 553 554 ot = int(s.WriteBytes(Ctxt, int64(ot), b)) 555 556 if pkg != nil { 557 ot = dgopkgpathOffLSym(s, ot, pkg) 558 } 559 560 return ot 561 } 562 563 var dnameCount int 564 565 // dname creates a reflect.name for a struct field or method. 566 func dname(name, tag string, pkg *Pkg, exported bool) *obj.LSym { 567 // Write out data as "type.." to signal two things to the 568 // linker, first that when dynamically linking, the symbol 569 // should be moved to a relro section, and second that the 570 // contents should not be decoded as a type. 571 sname := "type..namedata." 572 if pkg == nil { 573 // In the common case, share data with other packages. 574 if name == "" { 575 if exported { 576 sname += "-noname-exported." + tag 577 } else { 578 sname += "-noname-unexported." + tag 579 } 580 } else { 581 sname += name + "." + tag 582 } 583 } else { 584 sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount) 585 dnameCount++ 586 } 587 s := obj.Linklookup(Ctxt, sname, 0) 588 if len(s.P) > 0 { 589 return s 590 } 591 ot := dnameData(s, 0, name, tag, pkg, exported) 592 ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA) 593 return s 594 } 595 596 // dextratype dumps the fields of a runtime.uncommontype. 597 // dataAdd is the offset in bytes after the header where the 598 // backing array of the []method field is written (by dextratypeData). 599 func dextratype(s *Sym, ot int, t *Type, dataAdd int) int { 600 m := methods(t) 601 if t.Sym == nil && len(m) == 0 { 602 return ot 603 } 604 noff := int(Rnd(int64(ot), int64(Widthptr))) 605 if noff != ot { 606 Fatalf("unexpected alignment in dextratype for %v", t) 607 } 608 609 for _, a := range m { 610 dtypesym(a.type_) 611 } 612 613 ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t)) 614 615 dataAdd += uncommonSize(t) 616 mcount := len(m) 617 if mcount != int(uint16(mcount)) { 618 Fatalf("too many methods on %v: %d", t, mcount) 619 } 620 if dataAdd != int(uint32(dataAdd)) { 621 Fatalf("methods are too far away on %v: %d", t, dataAdd) 622 } 623 624 ot = duint16(s, ot, uint16(mcount)) 625 ot = duint16(s, ot, 0) 626 ot = duint32(s, ot, uint32(dataAdd)) 627 ot = duint32(s, ot, 0) 628 return ot 629 } 630 631 func typePkg(t *Type) *Pkg { 632 tsym := t.Sym 633 if tsym == nil { 634 switch t.Etype { 635 case TARRAY, TSLICE, TPTR32, TPTR64, TCHAN: 636 if t.Elem() != nil { 637 tsym = t.Elem().Sym 638 } 639 } 640 } 641 if tsym != nil && t != Types[t.Etype] && t != errortype { 642 return tsym.Pkg 643 } 644 return nil 645 } 646 647 // dextratypeData dumps the backing array for the []method field of 648 // runtime.uncommontype. 649 func dextratypeData(s *Sym, ot int, t *Type) int { 650 lsym := Linksym(s) 651 for _, a := range methods(t) { 652 // ../../../../runtime/type.go:/method 653 exported := exportname(a.name) 654 var pkg *Pkg 655 if !exported && a.pkg != typePkg(t) { 656 pkg = a.pkg 657 } 658 nsym := dname(a.name, "", pkg, exported) 659 660 ot = dsymptrOffLSym(lsym, ot, nsym, 0) 661 ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype))) 662 ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym)) 663 ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym)) 664 } 665 return ot 666 } 667 668 func dmethodptrOffLSym(s *obj.LSym, ot int, x *obj.LSym) int { 669 duintxxLSym(s, ot, 0, 4) 670 r := obj.Addrel(s) 671 r.Off = int32(ot) 672 r.Siz = 4 673 r.Sym = x 674 r.Type = obj.R_METHODOFF 675 return ot + 4 676 } 677 678 var kinds = []int{ 679 TINT: obj.KindInt, 680 TUINT: obj.KindUint, 681 TINT8: obj.KindInt8, 682 TUINT8: obj.KindUint8, 683 TINT16: obj.KindInt16, 684 TUINT16: obj.KindUint16, 685 TINT32: obj.KindInt32, 686 TUINT32: obj.KindUint32, 687 TINT64: obj.KindInt64, 688 TUINT64: obj.KindUint64, 689 TUINTPTR: obj.KindUintptr, 690 TFLOAT32: obj.KindFloat32, 691 TFLOAT64: obj.KindFloat64, 692 TBOOL: obj.KindBool, 693 TSTRING: obj.KindString, 694 TPTR32: obj.KindPtr, 695 TPTR64: obj.KindPtr, 696 TSTRUCT: obj.KindStruct, 697 TINTER: obj.KindInterface, 698 TCHAN: obj.KindChan, 699 TMAP: obj.KindMap, 700 TARRAY: obj.KindArray, 701 TSLICE: obj.KindSlice, 702 TFUNC: obj.KindFunc, 703 TCOMPLEX64: obj.KindComplex64, 704 TCOMPLEX128: obj.KindComplex128, 705 TUNSAFEPTR: obj.KindUnsafePointer, 706 } 707 708 func haspointers(t *Type) bool { 709 switch t.Etype { 710 case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, 711 TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL: 712 return false 713 714 case TSLICE: 715 return true 716 717 case TARRAY: 718 at := t.Extra.(*ArrayType) 719 if at.Haspointers != 0 { 720 return at.Haspointers-1 != 0 721 } 722 723 ret := false 724 if t.NumElem() != 0 { // non-empty array 725 ret = haspointers(t.Elem()) 726 } 727 728 at.Haspointers = 1 + uint8(obj.Bool2int(ret)) 729 return ret 730 731 case TSTRUCT: 732 st := t.StructType() 733 if st.Haspointers != 0 { 734 return st.Haspointers-1 != 0 735 } 736 737 ret := false 738 for _, t1 := range t.Fields().Slice() { 739 if haspointers(t1.Type) { 740 ret = true 741 break 742 } 743 } 744 st.Haspointers = 1 + uint8(obj.Bool2int(ret)) 745 return ret 746 } 747 748 return true 749 } 750 751 // typeptrdata returns the length in bytes of the prefix of t 752 // containing pointer data. Anything after this offset is scalar data. 753 func typeptrdata(t *Type) int64 { 754 if !haspointers(t) { 755 return 0 756 } 757 758 switch t.Etype { 759 case TPTR32, 760 TPTR64, 761 TUNSAFEPTR, 762 TFUNC, 763 TCHAN, 764 TMAP: 765 return int64(Widthptr) 766 767 case TSTRING: 768 // struct { byte *str; intgo len; } 769 return int64(Widthptr) 770 771 case TINTER: 772 // struct { Itab *tab; void *data; } or 773 // struct { Type *type; void *data; } 774 return 2 * int64(Widthptr) 775 776 case TSLICE: 777 // struct { byte *array; uintgo len; uintgo cap; } 778 return int64(Widthptr) 779 780 case TARRAY: 781 // haspointers already eliminated t.NumElem() == 0. 782 return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem()) 783 784 case TSTRUCT: 785 // Find the last field that has pointers. 786 var lastPtrField *Field 787 for _, t1 := range t.Fields().Slice() { 788 if haspointers(t1.Type) { 789 lastPtrField = t1 790 } 791 } 792 return lastPtrField.Offset + typeptrdata(lastPtrField.Type) 793 794 default: 795 Fatalf("typeptrdata: unexpected type, %v", t) 796 return 0 797 } 798 } 799 800 // tflag is documented in reflect/type.go. 801 // 802 // tflag values must be kept in sync with copies in: 803 // cmd/compile/internal/gc/reflect.go 804 // cmd/link/internal/ld/decodesym.go 805 // reflect/type.go 806 // runtime/type.go 807 const ( 808 tflagUncommon = 1 << 0 809 tflagExtraStar = 1 << 1 810 tflagNamed = 1 << 2 811 ) 812 813 var dcommontype_algarray *Sym 814 815 // dcommontype dumps the contents of a reflect.rtype (runtime._type). 816 func dcommontype(s *Sym, ot int, t *Type) int { 817 if ot != 0 { 818 Fatalf("dcommontype %d", ot) 819 } 820 821 sizeofAlg := 2 * Widthptr 822 if dcommontype_algarray == nil { 823 dcommontype_algarray = Pkglookup("algarray", Runtimepkg) 824 } 825 dowidth(t) 826 alg := algtype(t) 827 var algsym *Sym 828 if alg == ASPECIAL || alg == AMEM { 829 algsym = dalgsym(t) 830 } 831 832 var sptr *Sym 833 tptr := ptrto(t) 834 if !t.IsPtr() && (t.Sym != nil || methods(tptr) != nil) { 835 sptr = dtypesym(tptr) 836 } 837 838 gcsym, useGCProg, ptrdata := dgcsym(t) 839 840 // ../../../../reflect/type.go:/^type.rtype 841 // actual type structure 842 // type rtype struct { 843 // size uintptr 844 // ptrdata uintptr 845 // hash uint32 846 // tflag tflag 847 // align uint8 848 // fieldAlign uint8 849 // kind uint8 850 // alg *typeAlg 851 // gcdata *byte 852 // str nameOff 853 // ptrToThis typeOff 854 // } 855 ot = duintptr(s, ot, uint64(t.Width)) 856 ot = duintptr(s, ot, uint64(ptrdata)) 857 858 ot = duint32(s, ot, typehash(t)) 859 860 var tflag uint8 861 if uncommonSize(t) != 0 { 862 tflag |= tflagUncommon 863 } 864 if t.Sym != nil && t.Sym.Name != "" { 865 tflag |= tflagNamed 866 } 867 868 exported := false 869 p := t.tconv(FmtLeft | FmtUnsigned) 870 // If we're writing out type T, 871 // we are very likely to write out type *T as well. 872 // Use the string "*T"[1:] for "T", so that the two 873 // share storage. This is a cheap way to reduce the 874 // amount of space taken up by reflect strings. 875 if !strings.HasPrefix(p, "*") { 876 p = "*" + p 877 tflag |= tflagExtraStar 878 if t.Sym != nil { 879 exported = exportname(t.Sym.Name) 880 } 881 } else { 882 if t.Elem() != nil && t.Elem().Sym != nil { 883 exported = exportname(t.Elem().Sym.Name) 884 } 885 } 886 887 ot = duint8(s, ot, tflag) 888 889 // runtime (and common sense) expects alignment to be a power of two. 890 i := int(t.Align) 891 892 if i == 0 { 893 i = 1 894 } 895 if i&(i-1) != 0 { 896 Fatalf("invalid alignment %d for %v", t.Align, t) 897 } 898 ot = duint8(s, ot, t.Align) // align 899 ot = duint8(s, ot, t.Align) // fieldAlign 900 901 i = kinds[t.Etype] 902 if !haspointers(t) { 903 i |= obj.KindNoPointers 904 } 905 if isdirectiface(t) { 906 i |= obj.KindDirectIface 907 } 908 if useGCProg { 909 i |= obj.KindGCProg 910 } 911 ot = duint8(s, ot, uint8(i)) // kind 912 if algsym == nil { 913 ot = dsymptr(s, ot, dcommontype_algarray, int(alg)*sizeofAlg) 914 } else { 915 ot = dsymptr(s, ot, algsym, 0) 916 } 917 ot = dsymptr(s, ot, gcsym, 0) // gcdata 918 919 nsym := dname(p, "", nil, exported) 920 ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) // str 921 if sptr == nil { 922 ot = duint32(s, ot, 0) 923 } else { 924 ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0) // ptrToThis 925 } 926 927 return ot 928 } 929 930 func typesym(t *Type) *Sym { 931 name := t.tconv(FmtLeft) 932 933 // Use a separate symbol name for Noalg types for #17752. 934 if a, bad := algtype1(t); a == ANOEQ && bad.Noalg { 935 name = "noalg." + name 936 } 937 938 return Pkglookup(name, typepkg) 939 } 940 941 // tracksym returns the symbol for tracking use of field/method f, assumed 942 // to be a member of struct/interface type t. 943 func tracksym(t *Type, f *Field) *Sym { 944 return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg) 945 } 946 947 func typesymprefix(prefix string, t *Type) *Sym { 948 p := prefix + "." + t.tconv(FmtLeft) 949 s := Pkglookup(p, typepkg) 950 951 //print("algsym: %s -> %+S\n", p, s); 952 953 return s 954 } 955 956 func typenamesym(t *Type) *Sym { 957 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { 958 Fatalf("typename %v", t) 959 } 960 s := typesym(t) 961 if s.Def == nil { 962 n := newname(s) 963 n.Type = Types[TUINT8] 964 n.Class = PEXTERN 965 n.Typecheck = 1 966 s.Def = n 967 968 signatlist = append(signatlist, typenod(t)) 969 } 970 971 return s.Def.Sym 972 } 973 974 func typename(t *Type) *Node { 975 s := typenamesym(t) 976 n := nod(OADDR, s.Def, nil) 977 n.Type = ptrto(s.Def.Type) 978 n.Addable = true 979 n.Ullman = 2 980 n.Typecheck = 1 981 return n 982 } 983 984 func itabname(t, itype *Type) *Node { 985 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() { 986 Fatalf("itabname(%v, %v)", t, itype) 987 } 988 s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg) 989 Linksym(s).Set(obj.AttrLocal, true) 990 if s.Def == nil { 991 n := newname(s) 992 n.Type = Types[TUINT8] 993 n.Class = PEXTERN 994 n.Typecheck = 1 995 s.Def = n 996 997 itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s}) 998 } 999 1000 n := nod(OADDR, s.Def, nil) 1001 n.Type = ptrto(s.Def.Type) 1002 n.Addable = true 1003 n.Ullman = 2 1004 n.Typecheck = 1 1005 return n 1006 } 1007 1008 // isreflexive reports whether t has a reflexive equality operator. 1009 // That is, if x==x for all x of type t. 1010 func isreflexive(t *Type) bool { 1011 switch t.Etype { 1012 case TBOOL, 1013 TINT, 1014 TUINT, 1015 TINT8, 1016 TUINT8, 1017 TINT16, 1018 TUINT16, 1019 TINT32, 1020 TUINT32, 1021 TINT64, 1022 TUINT64, 1023 TUINTPTR, 1024 TPTR32, 1025 TPTR64, 1026 TUNSAFEPTR, 1027 TSTRING, 1028 TCHAN: 1029 return true 1030 1031 case TFLOAT32, 1032 TFLOAT64, 1033 TCOMPLEX64, 1034 TCOMPLEX128, 1035 TINTER: 1036 return false 1037 1038 case TARRAY: 1039 return isreflexive(t.Elem()) 1040 1041 case TSTRUCT: 1042 for _, t1 := range t.Fields().Slice() { 1043 if !isreflexive(t1.Type) { 1044 return false 1045 } 1046 } 1047 return true 1048 1049 default: 1050 Fatalf("bad type for map key: %v", t) 1051 return false 1052 } 1053 } 1054 1055 // needkeyupdate reports whether map updates with t as a key 1056 // need the key to be updated. 1057 func needkeyupdate(t *Type) bool { 1058 switch t.Etype { 1059 case TBOOL, 1060 TINT, 1061 TUINT, 1062 TINT8, 1063 TUINT8, 1064 TINT16, 1065 TUINT16, 1066 TINT32, 1067 TUINT32, 1068 TINT64, 1069 TUINT64, 1070 TUINTPTR, 1071 TPTR32, 1072 TPTR64, 1073 TUNSAFEPTR, 1074 TCHAN: 1075 return false 1076 1077 case TFLOAT32, // floats can be +0/-0 1078 TFLOAT64, 1079 TCOMPLEX64, 1080 TCOMPLEX128, 1081 TINTER, 1082 TSTRING: // strings might have smaller backing stores 1083 return true 1084 1085 case TARRAY: 1086 return needkeyupdate(t.Elem()) 1087 1088 case TSTRUCT: 1089 for _, t1 := range t.Fields().Slice() { 1090 if needkeyupdate(t1.Type) { 1091 return true 1092 } 1093 } 1094 return false 1095 1096 default: 1097 Fatalf("bad type for map key: %v", t) 1098 return true 1099 } 1100 } 1101 1102 func dtypesym(t *Type) *Sym { 1103 // Replace byte, rune aliases with real type. 1104 // They've been separate internally to make error messages 1105 // better, but we have to merge them in the reflect tables. 1106 if t == bytetype || t == runetype { 1107 t = Types[t.Etype] 1108 } 1109 1110 if t.IsUntyped() { 1111 Fatalf("dtypesym %v", t) 1112 } 1113 1114 s := typesym(t) 1115 if s.Flags&SymSiggen != 0 { 1116 return s 1117 } 1118 s.Flags |= SymSiggen 1119 1120 // special case (look for runtime below): 1121 // when compiling package runtime, 1122 // emit the type structures for int, float, etc. 1123 tbase := t 1124 1125 if t.IsPtr() && t.Sym == nil && t.Elem().Sym != nil { 1126 tbase = t.Elem() 1127 } 1128 dupok := 0 1129 if tbase.Sym == nil { 1130 dupok = obj.DUPOK 1131 } 1132 1133 if myimportpath == "runtime" && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc 1134 goto ok 1135 } 1136 1137 // named types from other files are defined only by those files 1138 if tbase.Sym != nil && !tbase.Local { 1139 return s 1140 } 1141 if isforw[tbase.Etype] { 1142 return s 1143 } 1144 1145 ok: 1146 ot := 0 1147 switch t.Etype { 1148 default: 1149 ot = dcommontype(s, ot, t) 1150 ot = dextratype(s, ot, t, 0) 1151 1152 case TARRAY: 1153 // ../../../../runtime/type.go:/arrayType 1154 s1 := dtypesym(t.Elem()) 1155 t2 := typSlice(t.Elem()) 1156 s2 := dtypesym(t2) 1157 ot = dcommontype(s, ot, t) 1158 ot = dsymptr(s, ot, s1, 0) 1159 ot = dsymptr(s, ot, s2, 0) 1160 ot = duintptr(s, ot, uint64(t.NumElem())) 1161 ot = dextratype(s, ot, t, 0) 1162 1163 case TSLICE: 1164 // ../../../../runtime/type.go:/sliceType 1165 s1 := dtypesym(t.Elem()) 1166 ot = dcommontype(s, ot, t) 1167 ot = dsymptr(s, ot, s1, 0) 1168 ot = dextratype(s, ot, t, 0) 1169 1170 case TCHAN: 1171 // ../../../../runtime/type.go:/chanType 1172 s1 := dtypesym(t.Elem()) 1173 ot = dcommontype(s, ot, t) 1174 ot = dsymptr(s, ot, s1, 0) 1175 ot = duintptr(s, ot, uint64(t.ChanDir())) 1176 ot = dextratype(s, ot, t, 0) 1177 1178 case TFUNC: 1179 for _, t1 := range t.Recvs().Fields().Slice() { 1180 dtypesym(t1.Type) 1181 } 1182 isddd := false 1183 for _, t1 := range t.Params().Fields().Slice() { 1184 isddd = t1.Isddd 1185 dtypesym(t1.Type) 1186 } 1187 for _, t1 := range t.Results().Fields().Slice() { 1188 dtypesym(t1.Type) 1189 } 1190 1191 ot = dcommontype(s, ot, t) 1192 inCount := t.Recvs().NumFields() + t.Params().NumFields() 1193 outCount := t.Results().NumFields() 1194 if isddd { 1195 outCount |= 1 << 15 1196 } 1197 ot = duint16(s, ot, uint16(inCount)) 1198 ot = duint16(s, ot, uint16(outCount)) 1199 if Widthptr == 8 { 1200 ot += 4 // align for *rtype 1201 } 1202 1203 dataAdd := (inCount + t.Results().NumFields()) * Widthptr 1204 ot = dextratype(s, ot, t, dataAdd) 1205 1206 // Array of rtype pointers follows funcType. 1207 for _, t1 := range t.Recvs().Fields().Slice() { 1208 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1209 } 1210 for _, t1 := range t.Params().Fields().Slice() { 1211 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1212 } 1213 for _, t1 := range t.Results().Fields().Slice() { 1214 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1215 } 1216 1217 case TINTER: 1218 m := imethods(t) 1219 n := len(m) 1220 for _, a := range m { 1221 dtypesym(a.type_) 1222 } 1223 1224 // ../../../../runtime/type.go:/interfaceType 1225 ot = dcommontype(s, ot, t) 1226 1227 var tpkg *Pkg 1228 if t.Sym != nil && t != Types[t.Etype] && t != errortype { 1229 tpkg = t.Sym.Pkg 1230 } 1231 ot = dgopkgpath(s, ot, tpkg) 1232 1233 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1234 ot = duintxx(s, ot, uint64(n), Widthint) 1235 ot = duintxx(s, ot, uint64(n), Widthint) 1236 dataAdd := imethodSize() * n 1237 ot = dextratype(s, ot, t, dataAdd) 1238 1239 lsym := Linksym(s) 1240 for _, a := range m { 1241 // ../../../../runtime/type.go:/imethod 1242 exported := exportname(a.name) 1243 var pkg *Pkg 1244 if !exported && a.pkg != tpkg { 1245 pkg = a.pkg 1246 } 1247 nsym := dname(a.name, "", pkg, exported) 1248 1249 ot = dsymptrOffLSym(lsym, ot, nsym, 0) 1250 ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0) 1251 } 1252 1253 // ../../../../runtime/type.go:/mapType 1254 case TMAP: 1255 s1 := dtypesym(t.Key()) 1256 s2 := dtypesym(t.Val()) 1257 s3 := dtypesym(mapbucket(t)) 1258 s4 := dtypesym(hmap(t)) 1259 ot = dcommontype(s, ot, t) 1260 ot = dsymptr(s, ot, s1, 0) 1261 ot = dsymptr(s, ot, s2, 0) 1262 ot = dsymptr(s, ot, s3, 0) 1263 ot = dsymptr(s, ot, s4, 0) 1264 if t.Key().Width > MAXKEYSIZE { 1265 ot = duint8(s, ot, uint8(Widthptr)) 1266 ot = duint8(s, ot, 1) // indirect 1267 } else { 1268 ot = duint8(s, ot, uint8(t.Key().Width)) 1269 ot = duint8(s, ot, 0) // not indirect 1270 } 1271 1272 if t.Val().Width > MAXVALSIZE { 1273 ot = duint8(s, ot, uint8(Widthptr)) 1274 ot = duint8(s, ot, 1) // indirect 1275 } else { 1276 ot = duint8(s, ot, uint8(t.Val().Width)) 1277 ot = duint8(s, ot, 0) // not indirect 1278 } 1279 1280 ot = duint16(s, ot, uint16(mapbucket(t).Width)) 1281 ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key())))) 1282 ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key())))) 1283 ot = dextratype(s, ot, t, 0) 1284 1285 case TPTR32, TPTR64: 1286 if t.Elem().Etype == TANY { 1287 // ../../../../runtime/type.go:/UnsafePointerType 1288 ot = dcommontype(s, ot, t) 1289 ot = dextratype(s, ot, t, 0) 1290 1291 break 1292 } 1293 1294 // ../../../../runtime/type.go:/ptrType 1295 s1 := dtypesym(t.Elem()) 1296 1297 ot = dcommontype(s, ot, t) 1298 ot = dsymptr(s, ot, s1, 0) 1299 ot = dextratype(s, ot, t, 0) 1300 1301 // ../../../../runtime/type.go:/structType 1302 // for security, only the exported fields. 1303 case TSTRUCT: 1304 n := 0 1305 1306 for _, t1 := range t.Fields().Slice() { 1307 dtypesym(t1.Type) 1308 n++ 1309 } 1310 1311 ot = dcommontype(s, ot, t) 1312 pkg := localpkg 1313 if t.Sym != nil { 1314 pkg = t.Sym.Pkg 1315 } else { 1316 // Unnamed type. Grab the package from the first field, if any. 1317 for _, f := range t.Fields().Slice() { 1318 if f.Embedded != 0 { 1319 continue 1320 } 1321 pkg = f.Sym.Pkg 1322 break 1323 } 1324 } 1325 ot = dgopkgpath(s, ot, pkg) 1326 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1327 ot = duintxx(s, ot, uint64(n), Widthint) 1328 ot = duintxx(s, ot, uint64(n), Widthint) 1329 1330 dataAdd := n * structfieldSize() 1331 ot = dextratype(s, ot, t, dataAdd) 1332 1333 for _, f := range t.Fields().Slice() { 1334 // ../../../../runtime/type.go:/structField 1335 ot = dnameField(s, ot, f) 1336 ot = dsymptr(s, ot, dtypesym(f.Type), 0) 1337 ot = duintptr(s, ot, uint64(f.Offset)) 1338 } 1339 } 1340 1341 ot = dextratypeData(s, ot, t) 1342 ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) 1343 1344 // The linker will leave a table of all the typelinks for 1345 // types in the binary, so the runtime can find them. 1346 // 1347 // When buildmode=shared, all types are in typelinks so the 1348 // runtime can deduplicate type pointers. 1349 keep := Ctxt.Flag_dynlink 1350 if !keep && t.Sym == nil { 1351 // For an unnamed type, we only need the link if the type can 1352 // be created at run time by reflect.PtrTo and similar 1353 // functions. If the type exists in the program, those 1354 // functions must return the existing type structure rather 1355 // than creating a new one. 1356 switch t.Etype { 1357 case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT: 1358 keep = true 1359 } 1360 } 1361 s.Lsym.Set(obj.AttrMakeTypelink, keep) 1362 1363 return s 1364 } 1365 1366 func dumptypestructs() { 1367 // copy types from externdcl list to signatlist 1368 for _, n := range externdcl { 1369 if n.Op != OTYPE { 1370 continue 1371 } 1372 signatlist = append(signatlist, n) 1373 } 1374 1375 // Process signatlist. This can't use range, as entries are 1376 // added to the list while it is being processed. 1377 for i := 0; i < len(signatlist); i++ { 1378 n := signatlist[i] 1379 if n.Op != OTYPE { 1380 continue 1381 } 1382 t := n.Type 1383 dtypesym(t) 1384 if t.Sym != nil { 1385 dtypesym(ptrto(t)) 1386 } 1387 } 1388 1389 // process itabs 1390 for _, i := range itabs { 1391 // dump empty itab symbol into i.sym 1392 // type itab struct { 1393 // inter *interfacetype 1394 // _type *_type 1395 // link *itab 1396 // bad int32 1397 // unused int32 1398 // fun [1]uintptr // variable sized 1399 // } 1400 o := dsymptr(i.sym, 0, dtypesym(i.itype), 0) 1401 o = dsymptr(i.sym, o, dtypesym(i.t), 0) 1402 o += Widthptr + 8 // skip link/bad/unused fields 1403 o += len(imethods(i.itype)) * Widthptr // skip fun method pointers 1404 // at runtime the itab will contain pointers to types, other itabs and 1405 // method functions. None are allocated on heap, so we can use obj.NOPTR. 1406 ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR|obj.LOCAL)) 1407 1408 ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg) 1409 dsymptr(ilink, 0, i.sym, 0) 1410 ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA|obj.LOCAL)) 1411 } 1412 1413 // process ptabs 1414 if localpkg.Name == "main" && len(ptabs) > 0 { 1415 ot := 0 1416 s := obj.Linklookup(Ctxt, "go.plugin.tabs", 0) 1417 for _, p := range ptabs { 1418 // Dump ptab symbol into go.pluginsym package. 1419 // 1420 // type ptab struct { 1421 // name nameOff 1422 // typ typeOff // pointer to symbol 1423 // } 1424 nsym := dname(p.s.Name, "", nil, true) 1425 ot = dsymptrOffLSym(s, ot, nsym, 0) 1426 ot = dsymptrOffLSym(s, ot, Linksym(dtypesym(p.t)), 0) 1427 } 1428 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1429 1430 ot = 0 1431 s = obj.Linklookup(Ctxt, "go.plugin.exports", 0) 1432 for _, p := range ptabs { 1433 ot = dsymptrLSym(s, ot, Linksym(p.s), 0) 1434 } 1435 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1436 } 1437 1438 // generate import strings for imported packages 1439 if forceObjFileStability { 1440 // Sorting the packages is not necessary but to compare binaries created 1441 // using textual and binary format we sort by path to reduce differences. 1442 sort.Sort(pkgByPath(pkgs)) 1443 } 1444 for _, p := range pkgs { 1445 if p.Direct { 1446 dimportpath(p) 1447 } 1448 } 1449 1450 // do basic types if compiling package runtime. 1451 // they have to be in at least one package, 1452 // and runtime is always loaded implicitly, 1453 // so this is as good as any. 1454 // another possible choice would be package main, 1455 // but using runtime means fewer copies in .6 files. 1456 if myimportpath == "runtime" { 1457 for i := EType(1); i <= TBOOL; i++ { 1458 dtypesym(ptrto(Types[i])) 1459 } 1460 dtypesym(ptrto(Types[TSTRING])) 1461 dtypesym(ptrto(Types[TUNSAFEPTR])) 1462 1463 // emit type structs for error and func(error) string. 1464 // The latter is the type of an auto-generated wrapper. 1465 dtypesym(ptrto(errortype)) 1466 1467 dtypesym(functype(nil, []*Node{nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{nod(ODCLFIELD, nil, typenod(Types[TSTRING]))})) 1468 1469 // add paths for runtime and main, which 6l imports implicitly. 1470 dimportpath(Runtimepkg) 1471 1472 if flag_race { 1473 dimportpath(racepkg) 1474 } 1475 if flag_msan { 1476 dimportpath(msanpkg) 1477 } 1478 dimportpath(mkpkg("main")) 1479 } 1480 } 1481 1482 type pkgByPath []*Pkg 1483 1484 func (a pkgByPath) Len() int { return len(a) } 1485 func (a pkgByPath) Less(i, j int) bool { return a[i].Path < a[j].Path } 1486 func (a pkgByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1487 1488 func dalgsym(t *Type) *Sym { 1489 var s *Sym 1490 var hashfunc *Sym 1491 var eqfunc *Sym 1492 1493 // dalgsym is only called for a type that needs an algorithm table, 1494 // which implies that the type is comparable (or else it would use ANOEQ). 1495 1496 if algtype(t) == AMEM { 1497 // we use one algorithm table for all AMEM types of a given size 1498 p := fmt.Sprintf(".alg%d", t.Width) 1499 1500 s = Pkglookup(p, typepkg) 1501 1502 if s.Flags&SymAlgGen != 0 { 1503 return s 1504 } 1505 s.Flags |= SymAlgGen 1506 1507 // make hash closure 1508 p = fmt.Sprintf(".hashfunc%d", t.Width) 1509 1510 hashfunc = Pkglookup(p, typepkg) 1511 1512 ot := 0 1513 ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0) 1514 ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure 1515 ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA) 1516 1517 // make equality closure 1518 p = fmt.Sprintf(".eqfunc%d", t.Width) 1519 1520 eqfunc = Pkglookup(p, typepkg) 1521 1522 ot = 0 1523 ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0) 1524 ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr) 1525 ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA) 1526 } else { 1527 // generate an alg table specific to this type 1528 s = typesymprefix(".alg", t) 1529 1530 hash := typesymprefix(".hash", t) 1531 eq := typesymprefix(".eq", t) 1532 hashfunc = typesymprefix(".hashfunc", t) 1533 eqfunc = typesymprefix(".eqfunc", t) 1534 1535 genhash(hash, t) 1536 geneq(eq, t) 1537 1538 // make Go funcs (closures) for calling hash and equal from Go 1539 dsymptr(hashfunc, 0, hash, 0) 1540 1541 ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1542 dsymptr(eqfunc, 0, eq, 0) 1543 ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1544 } 1545 1546 // ../../../../runtime/alg.go:/typeAlg 1547 ot := 0 1548 1549 ot = dsymptr(s, ot, hashfunc, 0) 1550 ot = dsymptr(s, ot, eqfunc, 0) 1551 ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA) 1552 return s 1553 } 1554 1555 // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, 1556 // which holds 1-bit entries describing where pointers are in a given type. 1557 // 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes 1558 // depending on the system. Above this length, the GC information is 1559 // recorded as a GC program, which can express repetition compactly. 1560 // In either form, the information is used by the runtime to initialize the 1561 // heap bitmap, and for large types (like 128 or more words), they are 1562 // roughly the same speed. GC programs are never much larger and often 1563 // more compact. (If large arrays are involved, they can be arbitrarily more 1564 // compact.) 1565 // 1566 // The cutoff must be large enough that any allocation large enough to 1567 // use a GC program is large enough that it does not share heap bitmap 1568 // bytes with any other objects, allowing the GC program execution to 1569 // assume an aligned start and not use atomic operations. In the current 1570 // runtime, this means all malloc size classes larger than the cutoff must 1571 // be multiples of four words. On 32-bit systems that's 16 bytes, and 1572 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint. 1573 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed 1574 // for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated 1575 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes 1576 // must be >= 4. 1577 // 1578 // We used to use 16 because the GC programs do have some constant overhead 1579 // to get started, and processing 128 pointers seems to be enough to 1580 // amortize that overhead well. 1581 // 1582 // To make sure that the runtime's chansend can call typeBitsBulkBarrier, 1583 // we raised the limit to 2048, so that even 32-bit systems are guaranteed to 1584 // use bitmaps for objects up to 64 kB in size. 1585 // 1586 // Also known to reflect/type.go. 1587 // 1588 const maxPtrmaskBytes = 2048 1589 1590 // dgcsym emits and returns a data symbol containing GC information for type t, 1591 // along with a boolean reporting whether the UseGCProg bit should be set in 1592 // the type kind, and the ptrdata field to record in the reflect type information. 1593 func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { 1594 ptrdata = typeptrdata(t) 1595 if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { 1596 sym = dgcptrmask(t) 1597 return 1598 } 1599 1600 useGCProg = true 1601 sym, ptrdata = dgcprog(t) 1602 return 1603 } 1604 1605 // dgcptrmask emits and returns the symbol containing a pointer mask for type t. 1606 func dgcptrmask(t *Type) *Sym { 1607 ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) 1608 fillptrmask(t, ptrmask) 1609 p := fmt.Sprintf("gcbits.%x", ptrmask) 1610 1611 sym := Pkglookup(p, Runtimepkg) 1612 if sym.Flags&SymUniq == 0 { 1613 sym.Flags |= SymUniq 1614 for i, x := range ptrmask { 1615 duint8(sym, i, x) 1616 } 1617 ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) 1618 } 1619 return sym 1620 } 1621 1622 // fillptrmask fills in ptrmask with 1s corresponding to the 1623 // word offsets in t that hold pointers. 1624 // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. 1625 func fillptrmask(t *Type, ptrmask []byte) { 1626 for i := range ptrmask { 1627 ptrmask[i] = 0 1628 } 1629 if !haspointers(t) { 1630 return 1631 } 1632 1633 vec := bvalloc(8 * int32(len(ptrmask))) 1634 xoffset := int64(0) 1635 onebitwalktype1(t, &xoffset, vec) 1636 1637 nptr := typeptrdata(t) / int64(Widthptr) 1638 for i := int64(0); i < nptr; i++ { 1639 if vec.Get(int32(i)) { 1640 ptrmask[i/8] |= 1 << (uint(i) % 8) 1641 } 1642 } 1643 } 1644 1645 // dgcprog emits and returns the symbol containing a GC program for type t 1646 // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). 1647 // In practice, the size is typeptrdata(t) except for non-trivial arrays. 1648 // For non-trivial arrays, the program describes the full t.Width size. 1649 func dgcprog(t *Type) (*Sym, int64) { 1650 dowidth(t) 1651 if t.Width == BADWIDTH { 1652 Fatalf("dgcprog: %v badwidth", t) 1653 } 1654 sym := typesymprefix(".gcprog", t) 1655 var p GCProg 1656 p.init(sym) 1657 p.emit(t, 0) 1658 offset := p.w.BitIndex() * int64(Widthptr) 1659 p.end() 1660 if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { 1661 Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) 1662 } 1663 return sym, offset 1664 } 1665 1666 type GCProg struct { 1667 sym *Sym 1668 symoff int 1669 w gcprog.Writer 1670 } 1671 1672 var Debug_gcprog int // set by -d gcprog 1673 1674 func (p *GCProg) init(sym *Sym) { 1675 p.sym = sym 1676 p.symoff = 4 // first 4 bytes hold program length 1677 p.w.Init(p.writeByte) 1678 if Debug_gcprog > 0 { 1679 fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) 1680 p.w.Debug(os.Stderr) 1681 } 1682 } 1683 1684 func (p *GCProg) writeByte(x byte) { 1685 p.symoff = duint8(p.sym, p.symoff, x) 1686 } 1687 1688 func (p *GCProg) end() { 1689 p.w.End() 1690 duint32(p.sym, 0, uint32(p.symoff-4)) 1691 ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) 1692 if Debug_gcprog > 0 { 1693 fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) 1694 } 1695 } 1696 1697 func (p *GCProg) emit(t *Type, offset int64) { 1698 dowidth(t) 1699 if !haspointers(t) { 1700 return 1701 } 1702 if t.Width == int64(Widthptr) { 1703 p.w.Ptr(offset / int64(Widthptr)) 1704 return 1705 } 1706 switch t.Etype { 1707 default: 1708 Fatalf("GCProg.emit: unexpected type %v", t) 1709 1710 case TSTRING: 1711 p.w.Ptr(offset / int64(Widthptr)) 1712 1713 case TINTER: 1714 p.w.Ptr(offset / int64(Widthptr)) 1715 p.w.Ptr(offset/int64(Widthptr) + 1) 1716 1717 case TSLICE: 1718 p.w.Ptr(offset / int64(Widthptr)) 1719 1720 case TARRAY: 1721 if t.NumElem() == 0 { 1722 // should have been handled by haspointers check above 1723 Fatalf("GCProg.emit: empty array") 1724 } 1725 1726 // Flatten array-of-array-of-array to just a big array by multiplying counts. 1727 count := t.NumElem() 1728 elem := t.Elem() 1729 for elem.IsArray() { 1730 count *= elem.NumElem() 1731 elem = elem.Elem() 1732 } 1733 1734 if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { 1735 // Cheaper to just emit the bits. 1736 for i := int64(0); i < count; i++ { 1737 p.emit(elem, offset+i*elem.Width) 1738 } 1739 return 1740 } 1741 p.emit(elem, offset) 1742 p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) 1743 p.w.Repeat(elem.Width/int64(Widthptr), count-1) 1744 1745 case TSTRUCT: 1746 for _, t1 := range t.Fields().Slice() { 1747 p.emit(t1.Type, offset+t1.Offset) 1748 } 1749 } 1750 } 1751 1752 // zeroaddr returns the address of a symbol with at least 1753 // size bytes of zeros. 1754 func zeroaddr(size int64) *Node { 1755 if size >= 1<<31 { 1756 Fatalf("map value too big %d", size) 1757 } 1758 if zerosize < size { 1759 zerosize = size 1760 } 1761 s := Pkglookup("zero", mappkg) 1762 if s.Def == nil { 1763 x := newname(s) 1764 x.Type = Types[TUINT8] 1765 x.Class = PEXTERN 1766 x.Typecheck = 1 1767 s.Def = x 1768 } 1769 z := nod(OADDR, s.Def, nil) 1770 z.Type = ptrto(Types[TUINT8]) 1771 z.Addable = true 1772 z.Typecheck = 1 1773 return z 1774 }