github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 return Pkglookup(t.tconv(FmtLeft), typepkg) 932 } 933 934 // tracksym returns the symbol for tracking use of field/method f, assumed 935 // to be a member of struct/interface type t. 936 func tracksym(t *Type, f *Field) *Sym { 937 return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg) 938 } 939 940 func typesymprefix(prefix string, t *Type) *Sym { 941 p := prefix + "." + t.tconv(FmtLeft) 942 s := Pkglookup(p, typepkg) 943 944 //print("algsym: %s -> %+S\n", p, s); 945 946 return s 947 } 948 949 func typenamesym(t *Type) *Sym { 950 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { 951 Fatalf("typename %v", t) 952 } 953 s := typesym(t) 954 if s.Def == nil { 955 n := newname(s) 956 n.Type = Types[TUINT8] 957 n.Class = PEXTERN 958 n.Typecheck = 1 959 s.Def = n 960 961 signatlist = append(signatlist, typenod(t)) 962 } 963 964 return s.Def.Sym 965 } 966 967 func typename(t *Type) *Node { 968 s := typenamesym(t) 969 n := nod(OADDR, s.Def, nil) 970 n.Type = ptrto(s.Def.Type) 971 n.Addable = true 972 n.Ullman = 2 973 n.Typecheck = 1 974 return n 975 } 976 977 func itabname(t, itype *Type) *Node { 978 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() { 979 Fatalf("itabname(%v, %v)", t, itype) 980 } 981 s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg) 982 if s.Def == nil { 983 n := newname(s) 984 n.Type = Types[TUINT8] 985 n.Class = PEXTERN 986 n.Typecheck = 1 987 s.Def = n 988 989 itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s}) 990 } 991 992 n := nod(OADDR, s.Def, nil) 993 n.Type = ptrto(s.Def.Type) 994 n.Addable = true 995 n.Ullman = 2 996 n.Typecheck = 1 997 return n 998 } 999 1000 // isreflexive reports whether t has a reflexive equality operator. 1001 // That is, if x==x for all x of type t. 1002 func isreflexive(t *Type) bool { 1003 switch t.Etype { 1004 case TBOOL, 1005 TINT, 1006 TUINT, 1007 TINT8, 1008 TUINT8, 1009 TINT16, 1010 TUINT16, 1011 TINT32, 1012 TUINT32, 1013 TINT64, 1014 TUINT64, 1015 TUINTPTR, 1016 TPTR32, 1017 TPTR64, 1018 TUNSAFEPTR, 1019 TSTRING, 1020 TCHAN: 1021 return true 1022 1023 case TFLOAT32, 1024 TFLOAT64, 1025 TCOMPLEX64, 1026 TCOMPLEX128, 1027 TINTER: 1028 return false 1029 1030 case TARRAY: 1031 return isreflexive(t.Elem()) 1032 1033 case TSTRUCT: 1034 for _, t1 := range t.Fields().Slice() { 1035 if !isreflexive(t1.Type) { 1036 return false 1037 } 1038 } 1039 return true 1040 1041 default: 1042 Fatalf("bad type for map key: %v", t) 1043 return false 1044 } 1045 } 1046 1047 // needkeyupdate reports whether map updates with t as a key 1048 // need the key to be updated. 1049 func needkeyupdate(t *Type) bool { 1050 switch t.Etype { 1051 case TBOOL, 1052 TINT, 1053 TUINT, 1054 TINT8, 1055 TUINT8, 1056 TINT16, 1057 TUINT16, 1058 TINT32, 1059 TUINT32, 1060 TINT64, 1061 TUINT64, 1062 TUINTPTR, 1063 TPTR32, 1064 TPTR64, 1065 TUNSAFEPTR, 1066 TCHAN: 1067 return false 1068 1069 case TFLOAT32, // floats can be +0/-0 1070 TFLOAT64, 1071 TCOMPLEX64, 1072 TCOMPLEX128, 1073 TINTER, 1074 TSTRING: // strings might have smaller backing stores 1075 return true 1076 1077 case TARRAY: 1078 return needkeyupdate(t.Elem()) 1079 1080 case TSTRUCT: 1081 for _, t1 := range t.Fields().Slice() { 1082 if needkeyupdate(t1.Type) { 1083 return true 1084 } 1085 } 1086 return false 1087 1088 default: 1089 Fatalf("bad type for map key: %v", t) 1090 return true 1091 } 1092 } 1093 1094 func dtypesym(t *Type) *Sym { 1095 // Replace byte, rune aliases with real type. 1096 // They've been separate internally to make error messages 1097 // better, but we have to merge them in the reflect tables. 1098 if t == bytetype || t == runetype { 1099 t = Types[t.Etype] 1100 } 1101 1102 if t.IsUntyped() { 1103 Fatalf("dtypesym %v", t) 1104 } 1105 1106 s := typesym(t) 1107 if s.Flags&SymSiggen != 0 { 1108 return s 1109 } 1110 s.Flags |= SymSiggen 1111 1112 // special case (look for runtime below): 1113 // when compiling package runtime, 1114 // emit the type structures for int, float, etc. 1115 tbase := t 1116 1117 if t.IsPtr() && t.Sym == nil && t.Elem().Sym != nil { 1118 tbase = t.Elem() 1119 } 1120 dupok := 0 1121 if tbase.Sym == nil { 1122 dupok = obj.DUPOK 1123 } 1124 1125 if myimportpath == "runtime" && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc 1126 goto ok 1127 } 1128 1129 // named types from other files are defined only by those files 1130 if tbase.Sym != nil && !tbase.Local { 1131 return s 1132 } 1133 if isforw[tbase.Etype] { 1134 return s 1135 } 1136 1137 ok: 1138 ot := 0 1139 switch t.Etype { 1140 default: 1141 ot = dcommontype(s, ot, t) 1142 ot = dextratype(s, ot, t, 0) 1143 1144 case TARRAY: 1145 // ../../../../runtime/type.go:/arrayType 1146 s1 := dtypesym(t.Elem()) 1147 t2 := typSlice(t.Elem()) 1148 s2 := dtypesym(t2) 1149 ot = dcommontype(s, ot, t) 1150 ot = dsymptr(s, ot, s1, 0) 1151 ot = dsymptr(s, ot, s2, 0) 1152 ot = duintptr(s, ot, uint64(t.NumElem())) 1153 ot = dextratype(s, ot, t, 0) 1154 1155 case TSLICE: 1156 // ../../../../runtime/type.go:/sliceType 1157 s1 := dtypesym(t.Elem()) 1158 ot = dcommontype(s, ot, t) 1159 ot = dsymptr(s, ot, s1, 0) 1160 ot = dextratype(s, ot, t, 0) 1161 1162 case TCHAN: 1163 // ../../../../runtime/type.go:/chanType 1164 s1 := dtypesym(t.Elem()) 1165 ot = dcommontype(s, ot, t) 1166 ot = dsymptr(s, ot, s1, 0) 1167 ot = duintptr(s, ot, uint64(t.ChanDir())) 1168 ot = dextratype(s, ot, t, 0) 1169 1170 case TFUNC: 1171 for _, t1 := range t.Recvs().Fields().Slice() { 1172 dtypesym(t1.Type) 1173 } 1174 isddd := false 1175 for _, t1 := range t.Params().Fields().Slice() { 1176 isddd = t1.Isddd 1177 dtypesym(t1.Type) 1178 } 1179 for _, t1 := range t.Results().Fields().Slice() { 1180 dtypesym(t1.Type) 1181 } 1182 1183 ot = dcommontype(s, ot, t) 1184 inCount := t.Recvs().NumFields() + t.Params().NumFields() 1185 outCount := t.Results().NumFields() 1186 if isddd { 1187 outCount |= 1 << 15 1188 } 1189 ot = duint16(s, ot, uint16(inCount)) 1190 ot = duint16(s, ot, uint16(outCount)) 1191 if Widthptr == 8 { 1192 ot += 4 // align for *rtype 1193 } 1194 1195 dataAdd := (inCount + t.Results().NumFields()) * Widthptr 1196 ot = dextratype(s, ot, t, dataAdd) 1197 1198 // Array of rtype pointers follows funcType. 1199 for _, t1 := range t.Recvs().Fields().Slice() { 1200 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1201 } 1202 for _, t1 := range t.Params().Fields().Slice() { 1203 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1204 } 1205 for _, t1 := range t.Results().Fields().Slice() { 1206 ot = dsymptr(s, ot, dtypesym(t1.Type), 0) 1207 } 1208 1209 case TINTER: 1210 m := imethods(t) 1211 n := len(m) 1212 for _, a := range m { 1213 dtypesym(a.type_) 1214 } 1215 1216 // ../../../../runtime/type.go:/interfaceType 1217 ot = dcommontype(s, ot, t) 1218 1219 var tpkg *Pkg 1220 if t.Sym != nil && t != Types[t.Etype] && t != errortype { 1221 tpkg = t.Sym.Pkg 1222 } 1223 ot = dgopkgpath(s, ot, tpkg) 1224 1225 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1226 ot = duintxx(s, ot, uint64(n), Widthint) 1227 ot = duintxx(s, ot, uint64(n), Widthint) 1228 dataAdd := imethodSize() * n 1229 ot = dextratype(s, ot, t, dataAdd) 1230 1231 lsym := Linksym(s) 1232 for _, a := range m { 1233 // ../../../../runtime/type.go:/imethod 1234 exported := exportname(a.name) 1235 var pkg *Pkg 1236 if !exported && a.pkg != tpkg { 1237 pkg = a.pkg 1238 } 1239 nsym := dname(a.name, "", pkg, exported) 1240 1241 ot = dsymptrOffLSym(lsym, ot, nsym, 0) 1242 ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0) 1243 } 1244 1245 // ../../../../runtime/type.go:/mapType 1246 case TMAP: 1247 s1 := dtypesym(t.Key()) 1248 s2 := dtypesym(t.Val()) 1249 s3 := dtypesym(mapbucket(t)) 1250 s4 := dtypesym(hmap(t)) 1251 ot = dcommontype(s, ot, t) 1252 ot = dsymptr(s, ot, s1, 0) 1253 ot = dsymptr(s, ot, s2, 0) 1254 ot = dsymptr(s, ot, s3, 0) 1255 ot = dsymptr(s, ot, s4, 0) 1256 if t.Key().Width > MAXKEYSIZE { 1257 ot = duint8(s, ot, uint8(Widthptr)) 1258 ot = duint8(s, ot, 1) // indirect 1259 } else { 1260 ot = duint8(s, ot, uint8(t.Key().Width)) 1261 ot = duint8(s, ot, 0) // not indirect 1262 } 1263 1264 if t.Val().Width > MAXVALSIZE { 1265 ot = duint8(s, ot, uint8(Widthptr)) 1266 ot = duint8(s, ot, 1) // indirect 1267 } else { 1268 ot = duint8(s, ot, uint8(t.Val().Width)) 1269 ot = duint8(s, ot, 0) // not indirect 1270 } 1271 1272 ot = duint16(s, ot, uint16(mapbucket(t).Width)) 1273 ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key())))) 1274 ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key())))) 1275 ot = dextratype(s, ot, t, 0) 1276 1277 case TPTR32, TPTR64: 1278 if t.Elem().Etype == TANY { 1279 // ../../../../runtime/type.go:/UnsafePointerType 1280 ot = dcommontype(s, ot, t) 1281 ot = dextratype(s, ot, t, 0) 1282 1283 break 1284 } 1285 1286 // ../../../../runtime/type.go:/ptrType 1287 s1 := dtypesym(t.Elem()) 1288 1289 ot = dcommontype(s, ot, t) 1290 ot = dsymptr(s, ot, s1, 0) 1291 ot = dextratype(s, ot, t, 0) 1292 1293 // ../../../../runtime/type.go:/structType 1294 // for security, only the exported fields. 1295 case TSTRUCT: 1296 n := 0 1297 1298 for _, t1 := range t.Fields().Slice() { 1299 dtypesym(t1.Type) 1300 n++ 1301 } 1302 1303 ot = dcommontype(s, ot, t) 1304 pkg := localpkg 1305 if t.Sym != nil { 1306 pkg = t.Sym.Pkg 1307 } else { 1308 // Unnamed type. Grab the package from the first field, if any. 1309 for _, f := range t.Fields().Slice() { 1310 if f.Embedded != 0 { 1311 continue 1312 } 1313 pkg = f.Sym.Pkg 1314 break 1315 } 1316 } 1317 ot = dgopkgpath(s, ot, pkg) 1318 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t)) 1319 ot = duintxx(s, ot, uint64(n), Widthint) 1320 ot = duintxx(s, ot, uint64(n), Widthint) 1321 1322 dataAdd := n * structfieldSize() 1323 ot = dextratype(s, ot, t, dataAdd) 1324 1325 for _, f := range t.Fields().Slice() { 1326 // ../../../../runtime/type.go:/structField 1327 ot = dnameField(s, ot, f) 1328 ot = dsymptr(s, ot, dtypesym(f.Type), 0) 1329 ot = duintptr(s, ot, uint64(f.Offset)) 1330 } 1331 } 1332 1333 ot = dextratypeData(s, ot, t) 1334 ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) 1335 1336 // The linker will leave a table of all the typelinks for 1337 // types in the binary, so the runtime can find them. 1338 // 1339 // When buildmode=shared, all types are in typelinks so the 1340 // runtime can deduplicate type pointers. 1341 keep := Ctxt.Flag_dynlink 1342 if !keep && t.Sym == nil { 1343 // For an unnamed type, we only need the link if the type can 1344 // be created at run time by reflect.PtrTo and similar 1345 // functions. If the type exists in the program, those 1346 // functions must return the existing type structure rather 1347 // than creating a new one. 1348 switch t.Etype { 1349 case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT: 1350 keep = true 1351 } 1352 } 1353 s.Lsym.Set(obj.AttrMakeTypelink, keep) 1354 1355 return s 1356 } 1357 1358 func dumptypestructs() { 1359 // copy types from externdcl list to signatlist 1360 for _, n := range externdcl { 1361 if n.Op != OTYPE { 1362 continue 1363 } 1364 signatlist = append(signatlist, n) 1365 } 1366 1367 // Process signatlist. This can't use range, as entries are 1368 // added to the list while it is being processed. 1369 for i := 0; i < len(signatlist); i++ { 1370 n := signatlist[i] 1371 if n.Op != OTYPE { 1372 continue 1373 } 1374 t := n.Type 1375 dtypesym(t) 1376 if t.Sym != nil { 1377 dtypesym(ptrto(t)) 1378 } 1379 } 1380 1381 // process itabs 1382 for _, i := range itabs { 1383 // dump empty itab symbol into i.sym 1384 // type itab struct { 1385 // inter *interfacetype 1386 // _type *_type 1387 // link *itab 1388 // bad int32 1389 // unused int32 1390 // fun [1]uintptr // variable sized 1391 // } 1392 o := dsymptr(i.sym, 0, dtypesym(i.itype), 0) 1393 o = dsymptr(i.sym, o, dtypesym(i.t), 0) 1394 o += Widthptr + 8 // skip link/bad/unused fields 1395 o += len(imethods(i.itype)) * Widthptr // skip fun method pointers 1396 // at runtime the itab will contain pointers to types, other itabs and 1397 // method functions. None are allocated on heap, so we can use obj.NOPTR. 1398 ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR|obj.LOCAL)) 1399 1400 ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg) 1401 dsymptr(ilink, 0, i.sym, 0) 1402 ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA|obj.LOCAL)) 1403 } 1404 1405 // process ptabs 1406 if localpkg.Name == "main" && len(ptabs) > 0 { 1407 ot := 0 1408 s := obj.Linklookup(Ctxt, "go.plugin.tabs", 0) 1409 for _, p := range ptabs { 1410 // Dump ptab symbol into go.pluginsym package. 1411 // 1412 // type ptab struct { 1413 // name nameOff 1414 // typ typeOff // pointer to symbol 1415 // } 1416 nsym := dname(p.s.Name, "", nil, true) 1417 ot = dsymptrOffLSym(s, ot, nsym, 0) 1418 ot = dsymptrOffLSym(s, ot, Linksym(typesym(p.t)), 0) 1419 } 1420 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1421 1422 ot = 0 1423 s = obj.Linklookup(Ctxt, "go.plugin.exports", 0) 1424 for _, p := range ptabs { 1425 ot = dsymptrLSym(s, ot, Linksym(p.s), 0) 1426 } 1427 ggloblLSym(s, int32(ot), int16(obj.RODATA)) 1428 } 1429 1430 // generate import strings for imported packages 1431 if forceObjFileStability { 1432 // Sorting the packages is not necessary but to compare binaries created 1433 // using textual and binary format we sort by path to reduce differences. 1434 sort.Sort(pkgByPath(pkgs)) 1435 } 1436 for _, p := range pkgs { 1437 if p.Direct { 1438 dimportpath(p) 1439 } 1440 } 1441 1442 // do basic types if compiling package runtime. 1443 // they have to be in at least one package, 1444 // and runtime is always loaded implicitly, 1445 // so this is as good as any. 1446 // another possible choice would be package main, 1447 // but using runtime means fewer copies in .6 files. 1448 if myimportpath == "runtime" { 1449 for i := EType(1); i <= TBOOL; i++ { 1450 dtypesym(ptrto(Types[i])) 1451 } 1452 dtypesym(ptrto(Types[TSTRING])) 1453 dtypesym(ptrto(Types[TUNSAFEPTR])) 1454 1455 // emit type structs for error and func(error) string. 1456 // The latter is the type of an auto-generated wrapper. 1457 dtypesym(ptrto(errortype)) 1458 1459 dtypesym(functype(nil, []*Node{nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{nod(ODCLFIELD, nil, typenod(Types[TSTRING]))})) 1460 1461 // add paths for runtime and main, which 6l imports implicitly. 1462 dimportpath(Runtimepkg) 1463 1464 if flag_race { 1465 dimportpath(racepkg) 1466 } 1467 if flag_msan { 1468 dimportpath(msanpkg) 1469 } 1470 dimportpath(mkpkg("main")) 1471 } 1472 } 1473 1474 type pkgByPath []*Pkg 1475 1476 func (a pkgByPath) Len() int { return len(a) } 1477 func (a pkgByPath) Less(i, j int) bool { return a[i].Path < a[j].Path } 1478 func (a pkgByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1479 1480 func dalgsym(t *Type) *Sym { 1481 var s *Sym 1482 var hashfunc *Sym 1483 var eqfunc *Sym 1484 1485 // dalgsym is only called for a type that needs an algorithm table, 1486 // which implies that the type is comparable (or else it would use ANOEQ). 1487 1488 if algtype(t) == AMEM { 1489 // we use one algorithm table for all AMEM types of a given size 1490 p := fmt.Sprintf(".alg%d", t.Width) 1491 1492 s = Pkglookup(p, typepkg) 1493 1494 if s.Flags&SymAlgGen != 0 { 1495 return s 1496 } 1497 s.Flags |= SymAlgGen 1498 1499 // make hash closure 1500 p = fmt.Sprintf(".hashfunc%d", t.Width) 1501 1502 hashfunc = Pkglookup(p, typepkg) 1503 1504 ot := 0 1505 ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0) 1506 ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure 1507 ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA) 1508 1509 // make equality closure 1510 p = fmt.Sprintf(".eqfunc%d", t.Width) 1511 1512 eqfunc = Pkglookup(p, typepkg) 1513 1514 ot = 0 1515 ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0) 1516 ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr) 1517 ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA) 1518 } else { 1519 // generate an alg table specific to this type 1520 s = typesymprefix(".alg", t) 1521 1522 hash := typesymprefix(".hash", t) 1523 eq := typesymprefix(".eq", t) 1524 hashfunc = typesymprefix(".hashfunc", t) 1525 eqfunc = typesymprefix(".eqfunc", t) 1526 1527 genhash(hash, t) 1528 geneq(eq, t) 1529 1530 // make Go funcs (closures) for calling hash and equal from Go 1531 dsymptr(hashfunc, 0, hash, 0) 1532 1533 ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1534 dsymptr(eqfunc, 0, eq, 0) 1535 ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) 1536 } 1537 1538 // ../../../../runtime/alg.go:/typeAlg 1539 ot := 0 1540 1541 ot = dsymptr(s, ot, hashfunc, 0) 1542 ot = dsymptr(s, ot, eqfunc, 0) 1543 ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA) 1544 return s 1545 } 1546 1547 // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, 1548 // which holds 1-bit entries describing where pointers are in a given type. 1549 // 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes 1550 // depending on the system. Above this length, the GC information is 1551 // recorded as a GC program, which can express repetition compactly. 1552 // In either form, the information is used by the runtime to initialize the 1553 // heap bitmap, and for large types (like 128 or more words), they are 1554 // roughly the same speed. GC programs are never much larger and often 1555 // more compact. (If large arrays are involved, they can be arbitrarily more 1556 // compact.) 1557 // 1558 // The cutoff must be large enough that any allocation large enough to 1559 // use a GC program is large enough that it does not share heap bitmap 1560 // bytes with any other objects, allowing the GC program execution to 1561 // assume an aligned start and not use atomic operations. In the current 1562 // runtime, this means all malloc size classes larger than the cutoff must 1563 // be multiples of four words. On 32-bit systems that's 16 bytes, and 1564 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint. 1565 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed 1566 // for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated 1567 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes 1568 // must be >= 4. 1569 // 1570 // We used to use 16 because the GC programs do have some constant overhead 1571 // to get started, and processing 128 pointers seems to be enough to 1572 // amortize that overhead well. 1573 // 1574 // To make sure that the runtime's chansend can call typeBitsBulkBarrier, 1575 // we raised the limit to 2048, so that even 32-bit systems are guaranteed to 1576 // use bitmaps for objects up to 64 kB in size. 1577 // 1578 // Also known to reflect/type.go. 1579 // 1580 const maxPtrmaskBytes = 2048 1581 1582 // dgcsym emits and returns a data symbol containing GC information for type t, 1583 // along with a boolean reporting whether the UseGCProg bit should be set in 1584 // the type kind, and the ptrdata field to record in the reflect type information. 1585 func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { 1586 ptrdata = typeptrdata(t) 1587 if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { 1588 sym = dgcptrmask(t) 1589 return 1590 } 1591 1592 useGCProg = true 1593 sym, ptrdata = dgcprog(t) 1594 return 1595 } 1596 1597 // dgcptrmask emits and returns the symbol containing a pointer mask for type t. 1598 func dgcptrmask(t *Type) *Sym { 1599 ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) 1600 fillptrmask(t, ptrmask) 1601 p := fmt.Sprintf("gcbits.%x", ptrmask) 1602 1603 sym := Pkglookup(p, Runtimepkg) 1604 if sym.Flags&SymUniq == 0 { 1605 sym.Flags |= SymUniq 1606 for i, x := range ptrmask { 1607 duint8(sym, i, x) 1608 } 1609 ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) 1610 } 1611 return sym 1612 } 1613 1614 // fillptrmask fills in ptrmask with 1s corresponding to the 1615 // word offsets in t that hold pointers. 1616 // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. 1617 func fillptrmask(t *Type, ptrmask []byte) { 1618 for i := range ptrmask { 1619 ptrmask[i] = 0 1620 } 1621 if !haspointers(t) { 1622 return 1623 } 1624 1625 vec := bvalloc(8 * int32(len(ptrmask))) 1626 xoffset := int64(0) 1627 onebitwalktype1(t, &xoffset, vec) 1628 1629 nptr := typeptrdata(t) / int64(Widthptr) 1630 for i := int64(0); i < nptr; i++ { 1631 if vec.Get(int32(i)) { 1632 ptrmask[i/8] |= 1 << (uint(i) % 8) 1633 } 1634 } 1635 } 1636 1637 // dgcprog emits and returns the symbol containing a GC program for type t 1638 // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). 1639 // In practice, the size is typeptrdata(t) except for non-trivial arrays. 1640 // For non-trivial arrays, the program describes the full t.Width size. 1641 func dgcprog(t *Type) (*Sym, int64) { 1642 dowidth(t) 1643 if t.Width == BADWIDTH { 1644 Fatalf("dgcprog: %v badwidth", t) 1645 } 1646 sym := typesymprefix(".gcprog", t) 1647 var p GCProg 1648 p.init(sym) 1649 p.emit(t, 0) 1650 offset := p.w.BitIndex() * int64(Widthptr) 1651 p.end() 1652 if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { 1653 Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) 1654 } 1655 return sym, offset 1656 } 1657 1658 type GCProg struct { 1659 sym *Sym 1660 symoff int 1661 w gcprog.Writer 1662 } 1663 1664 var Debug_gcprog int // set by -d gcprog 1665 1666 func (p *GCProg) init(sym *Sym) { 1667 p.sym = sym 1668 p.symoff = 4 // first 4 bytes hold program length 1669 p.w.Init(p.writeByte) 1670 if Debug_gcprog > 0 { 1671 fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) 1672 p.w.Debug(os.Stderr) 1673 } 1674 } 1675 1676 func (p *GCProg) writeByte(x byte) { 1677 p.symoff = duint8(p.sym, p.symoff, x) 1678 } 1679 1680 func (p *GCProg) end() { 1681 p.w.End() 1682 duint32(p.sym, 0, uint32(p.symoff-4)) 1683 ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) 1684 if Debug_gcprog > 0 { 1685 fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) 1686 } 1687 } 1688 1689 func (p *GCProg) emit(t *Type, offset int64) { 1690 dowidth(t) 1691 if !haspointers(t) { 1692 return 1693 } 1694 if t.Width == int64(Widthptr) { 1695 p.w.Ptr(offset / int64(Widthptr)) 1696 return 1697 } 1698 switch t.Etype { 1699 default: 1700 Fatalf("GCProg.emit: unexpected type %v", t) 1701 1702 case TSTRING: 1703 p.w.Ptr(offset / int64(Widthptr)) 1704 1705 case TINTER: 1706 p.w.Ptr(offset / int64(Widthptr)) 1707 p.w.Ptr(offset/int64(Widthptr) + 1) 1708 1709 case TSLICE: 1710 p.w.Ptr(offset / int64(Widthptr)) 1711 1712 case TARRAY: 1713 if t.NumElem() == 0 { 1714 // should have been handled by haspointers check above 1715 Fatalf("GCProg.emit: empty array") 1716 } 1717 1718 // Flatten array-of-array-of-array to just a big array by multiplying counts. 1719 count := t.NumElem() 1720 elem := t.Elem() 1721 for elem.IsArray() { 1722 count *= elem.NumElem() 1723 elem = elem.Elem() 1724 } 1725 1726 if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { 1727 // Cheaper to just emit the bits. 1728 for i := int64(0); i < count; i++ { 1729 p.emit(elem, offset+i*elem.Width) 1730 } 1731 return 1732 } 1733 p.emit(elem, offset) 1734 p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) 1735 p.w.Repeat(elem.Width/int64(Widthptr), count-1) 1736 1737 case TSTRUCT: 1738 for _, t1 := range t.Fields().Slice() { 1739 p.emit(t1.Type, offset+t1.Offset) 1740 } 1741 } 1742 } 1743 1744 // zeroaddr returns the address of a symbol with at least 1745 // size bytes of zeros. 1746 func zeroaddr(size int64) *Node { 1747 if size >= 1<<31 { 1748 Fatalf("map value too big %d", size) 1749 } 1750 if zerosize < size { 1751 zerosize = size 1752 } 1753 s := Pkglookup("zero", mappkg) 1754 if s.Def == nil { 1755 x := newname(s) 1756 x.Type = Types[TUINT8] 1757 x.Class = PEXTERN 1758 x.Typecheck = 1 1759 s.Def = x 1760 } 1761 z := nod(OADDR, s.Def, nil) 1762 z.Type = ptrto(Types[TUINT8]) 1763 z.Addable = true 1764 z.Typecheck = 1 1765 return z 1766 }