github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/gc/pgen.go (about) 1 // Copyright 2011 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/compile/internal/ssa" 9 "cmd/compile/internal/types" 10 "cmd/internal/dwarf" 11 "cmd/internal/obj" 12 "cmd/internal/objabi" 13 "cmd/internal/src" 14 "cmd/internal/sys" 15 "fmt" 16 "math" 17 "math/rand" 18 "sort" 19 "sync" 20 "time" 21 ) 22 23 // "Portable" code generation. 24 25 var ( 26 nBackendWorkers int // number of concurrent backend workers, set by a compiler flag 27 compilequeue []*Node // functions waiting to be compiled 28 ) 29 30 func emitptrargsmap() { 31 if Curfn.funcname() == "_" { 32 return 33 } 34 sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.funcname())) 35 lsym := sym.Linksym() 36 37 nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr)) 38 bv := bvalloc(int32(nptr) * 2) 39 nbitmap := 1 40 if Curfn.Type.NumResults() > 0 { 41 nbitmap = 2 42 } 43 off := duint32(lsym, 0, uint32(nbitmap)) 44 off = duint32(lsym, off, uint32(bv.n)) 45 46 if Curfn.IsMethod() { 47 onebitwalktype1(Curfn.Type.Recvs(), 0, bv) 48 } 49 if Curfn.Type.NumParams() > 0 { 50 onebitwalktype1(Curfn.Type.Params(), 0, bv) 51 } 52 off = dbvec(lsym, off, bv) 53 54 if Curfn.Type.NumResults() > 0 { 55 onebitwalktype1(Curfn.Type.Results(), 0, bv) 56 off = dbvec(lsym, off, bv) 57 } 58 59 ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL) 60 } 61 62 // cmpstackvarlt reports whether the stack variable a sorts before b. 63 // 64 // Sort the list of stack variables. Autos after anything else, 65 // within autos, unused after used, within used, things with 66 // pointers first, zeroed things first, and then decreasing size. 67 // Because autos are laid out in decreasing addresses 68 // on the stack, pointers first, zeroed things first and decreasing size 69 // really means, in memory, things with pointers needing zeroing at 70 // the top of the stack and increasing in size. 71 // Non-autos sort on offset. 72 func cmpstackvarlt(a, b *Node) bool { 73 if (a.Class() == PAUTO) != (b.Class() == PAUTO) { 74 return b.Class() == PAUTO 75 } 76 77 if a.Class() != PAUTO { 78 return a.Xoffset < b.Xoffset 79 } 80 81 if a.Name.Used() != b.Name.Used() { 82 return a.Name.Used() 83 } 84 85 ap := types.Haspointers(a.Type) 86 bp := types.Haspointers(b.Type) 87 if ap != bp { 88 return ap 89 } 90 91 ap = a.Name.Needzero() 92 bp = b.Name.Needzero() 93 if ap != bp { 94 return ap 95 } 96 97 if a.Type.Width != b.Type.Width { 98 return a.Type.Width > b.Type.Width 99 } 100 101 return a.Sym.Name < b.Sym.Name 102 } 103 104 // byStackvar implements sort.Interface for []*Node using cmpstackvarlt. 105 type byStackVar []*Node 106 107 func (s byStackVar) Len() int { return len(s) } 108 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } 109 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 110 111 func (s *ssafn) AllocFrame(f *ssa.Func) { 112 s.stksize = 0 113 s.stkptrsize = 0 114 fn := s.curfn.Func 115 116 // Mark the PAUTO's unused. 117 for _, ln := range fn.Dcl { 118 if ln.Class() == PAUTO { 119 ln.Name.SetUsed(false) 120 } 121 } 122 123 for _, l := range f.RegAlloc { 124 if ls, ok := l.(ssa.LocalSlot); ok { 125 ls.N.(*Node).Name.SetUsed(true) 126 } 127 } 128 129 scratchUsed := false 130 for _, b := range f.Blocks { 131 for _, v := range b.Values { 132 if n, ok := v.Aux.(*Node); ok { 133 switch n.Class() { 134 case PPARAM, PPARAMOUT: 135 // Don't modify nodfp; it is a global. 136 if n != nodfp { 137 n.Name.SetUsed(true) 138 } 139 case PAUTO: 140 n.Name.SetUsed(true) 141 } 142 } 143 if !scratchUsed { 144 scratchUsed = v.Op.UsesScratch() 145 } 146 147 } 148 } 149 150 if f.Config.NeedsFpScratch && scratchUsed { 151 s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64]) 152 } 153 154 sort.Sort(byStackVar(fn.Dcl)) 155 156 // Reassign stack offsets of the locals that are used. 157 for i, n := range fn.Dcl { 158 if n.Op != ONAME || n.Class() != PAUTO { 159 continue 160 } 161 if !n.Name.Used() { 162 fn.Dcl = fn.Dcl[:i] 163 break 164 } 165 166 dowidth(n.Type) 167 w := n.Type.Width 168 if w >= thearch.MAXWIDTH || w < 0 { 169 Fatalf("bad width") 170 } 171 s.stksize += w 172 s.stksize = Rnd(s.stksize, int64(n.Type.Align)) 173 if types.Haspointers(n.Type) { 174 s.stkptrsize = s.stksize 175 } 176 if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { 177 s.stksize = Rnd(s.stksize, int64(Widthptr)) 178 } 179 n.Xoffset = -s.stksize 180 } 181 182 s.stksize = Rnd(s.stksize, int64(Widthreg)) 183 s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg)) 184 } 185 186 func compile(fn *Node) { 187 Curfn = fn 188 dowidth(fn.Type) 189 190 if fn.Nbody.Len() == 0 { 191 emitptrargsmap() 192 return 193 } 194 195 saveerrors() 196 197 order(fn) 198 if nerrors != 0 { 199 return 200 } 201 202 walk(fn) 203 if nerrors != 0 { 204 return 205 } 206 if instrumenting { 207 instrument(fn) 208 } 209 210 // From this point, there should be no uses of Curfn. Enforce that. 211 Curfn = nil 212 213 // Set up the function's LSym early to avoid data races with the assemblers. 214 fn.Func.initLSym() 215 216 if compilenow() { 217 compileSSA(fn, 0) 218 } else { 219 compilequeue = append(compilequeue, fn) 220 } 221 } 222 223 // compilenow reports whether to compile immediately. 224 // If functions are not compiled immediately, 225 // they are enqueued in compilequeue, 226 // which is drained by compileFunctions. 227 func compilenow() bool { 228 return nBackendWorkers == 1 && Debug_compilelater == 0 229 } 230 231 const maxStackSize = 1 << 30 232 233 // compileSSA builds an SSA backend function, 234 // uses it to generate a plist, 235 // and flushes that plist to machine code. 236 // worker indicates which of the backend workers is doing the processing. 237 func compileSSA(fn *Node, worker int) { 238 f := buildssa(fn, worker) 239 if f.Frontend().(*ssafn).stksize >= maxStackSize { 240 largeStackFramesMu.Lock() 241 largeStackFrames = append(largeStackFrames, fn.Pos) 242 largeStackFramesMu.Unlock() 243 return 244 } 245 pp := newProgs(fn, worker) 246 genssa(f, pp) 247 pp.Flush() 248 // fieldtrack must be called after pp.Flush. See issue 20014. 249 fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack) 250 pp.Free() 251 } 252 253 func init() { 254 if raceEnabled { 255 rand.Seed(time.Now().UnixNano()) 256 } 257 } 258 259 // compileFunctions compiles all functions in compilequeue. 260 // It fans out nBackendWorkers to do the work 261 // and waits for them to complete. 262 func compileFunctions() { 263 if len(compilequeue) != 0 { 264 sizeCalculationDisabled = true // not safe to calculate sizes concurrently 265 if raceEnabled { 266 // Randomize compilation order to try to shake out races. 267 tmp := make([]*Node, len(compilequeue)) 268 perm := rand.Perm(len(compilequeue)) 269 for i, v := range perm { 270 tmp[v] = compilequeue[i] 271 } 272 copy(compilequeue, tmp) 273 } else { 274 // Compile the longest functions first, 275 // since they're most likely to be the slowest. 276 // This helps avoid stragglers. 277 obj.SortSlice(compilequeue, func(i, j int) bool { 278 return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len() 279 }) 280 } 281 var wg sync.WaitGroup 282 c := make(chan *Node, nBackendWorkers) 283 for i := 0; i < nBackendWorkers; i++ { 284 wg.Add(1) 285 go func(worker int) { 286 for fn := range c { 287 compileSSA(fn, worker) 288 } 289 wg.Done() 290 }(i) 291 } 292 for _, fn := range compilequeue { 293 c <- fn 294 } 295 close(c) 296 compilequeue = nil 297 wg.Wait() 298 sizeCalculationDisabled = false 299 } 300 } 301 302 func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope { 303 fn := curfn.(*Node) 304 debugInfo := fn.Func.DebugInfo 305 fn.Func.DebugInfo = nil 306 if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect { 307 Fatalf("unexpected fnsym: %v != %v", fnsym, expect) 308 } 309 310 var automDecls []*Node 311 // Populate Automs for fn. 312 for _, n := range fn.Func.Dcl { 313 if n.Op != ONAME { // might be OTYPE or OLITERAL 314 continue 315 } 316 var name obj.AddrName 317 switch n.Class() { 318 case PAUTO: 319 if !n.Name.Used() { 320 Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)") 321 } 322 name = obj.NAME_AUTO 323 case PPARAM, PPARAMOUT: 324 name = obj.NAME_PARAM 325 default: 326 continue 327 } 328 automDecls = append(automDecls, n) 329 gotype := ngotype(n).Linksym() 330 fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{ 331 Asym: Ctxt.Lookup(n.Sym.Name), 332 Aoffset: int32(n.Xoffset), 333 Name: name, 334 Gotype: gotype, 335 }) 336 } 337 338 var dwarfVars []*dwarf.Var 339 var decls []*Node 340 if Ctxt.Flag_locationlists && Ctxt.Flag_optimize { 341 decls, dwarfVars = createComplexVars(fnsym, debugInfo, automDecls) 342 } else { 343 decls, dwarfVars = createSimpleVars(automDecls) 344 } 345 346 var varScopes []ScopeID 347 for _, decl := range decls { 348 pos := decl.Pos 349 if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) { 350 // It's not clear which position is correct for captured variables here: 351 // * decl.Pos is the wrong position for captured variables, in the inner 352 // function, but it is the right position in the outer function. 353 // * decl.Name.Defn is nil for captured variables that were arguments 354 // on the outer function, however the decl.Pos for those seems to be 355 // correct. 356 // * decl.Name.Defn is the "wrong" thing for variables declared in the 357 // header of a type switch, it's their position in the header, rather 358 // than the position of the case statement. In principle this is the 359 // right thing, but here we prefer the latter because it makes each 360 // instance of the header variable local to the lexical block of its 361 // case statement. 362 // This code is probably wrong for type switch variables that are also 363 // captured. 364 pos = decl.Name.Defn.Pos 365 } 366 varScopes = append(varScopes, findScope(fn.Func.Marks, pos)) 367 } 368 return assembleScopes(fnsym, fn, dwarfVars, varScopes) 369 } 370 371 // createSimpleVars creates a DWARF entry for every variable declared in the 372 // function, claiming that they are permanently on the stack. 373 func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) { 374 var vars []*dwarf.Var 375 var decls []*Node 376 for _, n := range automDecls { 377 if n.IsAutoTmp() { 378 continue 379 } 380 var abbrev int 381 offs := n.Xoffset 382 383 switch n.Class() { 384 case PAUTO: 385 abbrev = dwarf.DW_ABRV_AUTO 386 if Ctxt.FixedFrameSize() == 0 { 387 offs -= int64(Widthptr) 388 } 389 if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { 390 offs -= int64(Widthptr) 391 } 392 393 case PPARAM, PPARAMOUT: 394 abbrev = dwarf.DW_ABRV_PARAM 395 offs += Ctxt.FixedFrameSize() 396 default: 397 Fatalf("createSimpleVars unexpected type %v for node %v", n.Class(), n) 398 } 399 400 typename := dwarf.InfoPrefix + typesymname(n.Type) 401 decls = append(decls, n) 402 vars = append(vars, &dwarf.Var{ 403 Name: n.Sym.Name, 404 IsReturnValue: n.Class() == PPARAMOUT, 405 Abbrev: abbrev, 406 StackOffset: int32(offs), 407 Type: Ctxt.Lookup(typename), 408 DeclLine: n.Pos.Line(), 409 }) 410 } 411 return decls, vars 412 } 413 414 type varPart struct { 415 varOffset int64 416 slot ssa.SlotID 417 } 418 419 func createComplexVars(fnsym *obj.LSym, debugInfo *ssa.FuncDebug, automDecls []*Node) ([]*Node, []*dwarf.Var) { 420 for _, blockDebug := range debugInfo.Blocks { 421 for _, locList := range blockDebug.Variables { 422 for _, loc := range locList.Locations { 423 if loc.StartProg != nil { 424 loc.StartPC = loc.StartProg.Pc 425 } 426 if loc.EndProg != nil { 427 loc.EndPC = loc.EndProg.Pc 428 } else { 429 loc.EndPC = fnsym.Size 430 } 431 if Debug_locationlist == 0 { 432 loc.EndProg = nil 433 loc.StartProg = nil 434 } 435 } 436 } 437 } 438 439 // Group SSA variables by the user variable they were decomposed from. 440 varParts := map[*Node][]varPart{} 441 ssaVars := make(map[*Node]bool) 442 for slotID, slot := range debugInfo.VarSlots { 443 for slot.SplitOf != nil { 444 slot = slot.SplitOf 445 } 446 n := slot.N.(*Node) 447 ssaVars[n] = true 448 varParts[n] = append(varParts[n], varPart{varOffset(slot), ssa.SlotID(slotID)}) 449 } 450 451 // Produce a DWARF variable entry for each user variable. 452 // Don't iterate over the map -- that's nondeterministic, and 453 // createComplexVar has side effects. Instead, go by slot. 454 var decls []*Node 455 var vars []*dwarf.Var 456 for _, slot := range debugInfo.VarSlots { 457 for slot.SplitOf != nil { 458 slot = slot.SplitOf 459 } 460 n := slot.N.(*Node) 461 parts := varParts[n] 462 if parts == nil { 463 continue 464 } 465 // Don't work on this variable again, no matter how many slots it has. 466 delete(varParts, n) 467 468 // Get the order the parts need to be in to represent the memory 469 // of the decomposed user variable. 470 sort.Sort(partsByVarOffset(parts)) 471 472 if dvar := createComplexVar(debugInfo, n, parts); dvar != nil { 473 decls = append(decls, n) 474 vars = append(vars, dvar) 475 } 476 } 477 478 // The machinery above will create a dwarf.Var for only those 479 // variables that are decomposed into SSA names. Fill in the list 480 // with entries for the remaining variables (including things too 481 // big to decompose). Since optimization is enabled, the recipe 482 // below creates a conservative location. The idea here is that we 483 // want to communicate to the user that "yes, there is a variable 484 // named X in this function, but no, I don't have enough 485 // information to reliably report its contents." 486 for _, n := range automDecls { 487 if _, found := ssaVars[n]; found { 488 continue 489 } 490 c := n.Sym.Name[0] 491 if c == '~' || c == '.' { 492 continue 493 } 494 typename := dwarf.InfoPrefix + typesymname(n.Type) 495 decls = append(decls, n) 496 abbrev := dwarf.DW_ABRV_AUTO_LOCLIST 497 if n.Class() == PPARAM || n.Class() == PPARAMOUT { 498 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST 499 } 500 vars = append(vars, &dwarf.Var{ 501 Name: n.Sym.Name, 502 IsReturnValue: n.Class() == PPARAMOUT, 503 Abbrev: abbrev, 504 StackOffset: int32(n.Xoffset), 505 Type: Ctxt.Lookup(typename), 506 DeclLine: n.Pos.Line(), 507 }) 508 } 509 510 return decls, vars 511 } 512 513 // varOffset returns the offset of slot within the user variable it was 514 // decomposed from. This has nothing to do with its stack offset. 515 func varOffset(slot *ssa.LocalSlot) int64 { 516 offset := slot.Off 517 for ; slot.SplitOf != nil; slot = slot.SplitOf { 518 offset += slot.SplitOffset 519 } 520 return offset 521 } 522 523 type partsByVarOffset []varPart 524 525 func (a partsByVarOffset) Len() int { return len(a) } 526 func (a partsByVarOffset) Less(i, j int) bool { return a[i].varOffset < a[j].varOffset } 527 func (a partsByVarOffset) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 528 529 // stackOffset returns the stack location of a LocalSlot relative to the 530 // stack pointer, suitable for use in a DWARF location entry. This has nothing 531 // to do with its offset in the user variable. 532 func stackOffset(slot *ssa.LocalSlot) int32 { 533 n := slot.N.(*Node) 534 var base int64 535 switch n.Class() { 536 case PAUTO: 537 if Ctxt.FixedFrameSize() == 0 { 538 base -= int64(Widthptr) 539 } 540 if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { 541 base -= int64(Widthptr) 542 } 543 case PPARAM, PPARAMOUT: 544 base += Ctxt.FixedFrameSize() 545 } 546 return int32(base + n.Xoffset + slot.Off) 547 } 548 549 // createComplexVar builds a DWARF variable entry and location list representing n. 550 func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf.Var { 551 slots := debugInfo.Slots 552 var offs int64 // base stack offset for this kind of variable 553 var abbrev int 554 switch n.Class() { 555 case PAUTO: 556 abbrev = dwarf.DW_ABRV_AUTO_LOCLIST 557 if Ctxt.FixedFrameSize() == 0 { 558 offs -= int64(Widthptr) 559 } 560 if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { 561 offs -= int64(Widthptr) 562 } 563 564 case PPARAM, PPARAMOUT: 565 abbrev = dwarf.DW_ABRV_PARAM_LOCLIST 566 offs += Ctxt.FixedFrameSize() 567 default: 568 return nil 569 } 570 571 gotype := ngotype(n).Linksym() 572 typename := dwarf.InfoPrefix + gotype.Name[len("type."):] 573 dvar := &dwarf.Var{ 574 Name: n.Sym.Name, 575 Abbrev: abbrev, 576 Type: Ctxt.Lookup(typename), 577 // The stack offset is used as a sorting key, so for decomposed 578 // variables just give it the lowest one. It's not used otherwise. 579 // This won't work well if the first slot hasn't been assigned a stack 580 // location, but it's not obvious how to do better. 581 StackOffset: int32(stackOffset(slots[parts[0].slot])), 582 DeclLine: n.Pos.Line(), 583 } 584 585 if Debug_locationlist != 0 { 586 Ctxt.Logf("Building location list for %+v. Parts:\n", n) 587 for _, part := range parts { 588 Ctxt.Logf("\t%v => %v\n", debugInfo.Slots[part.slot], debugInfo.SlotLocsString(part.slot)) 589 } 590 } 591 592 // Given a variable that's been decomposed into multiple parts, 593 // its location list may need a new entry after the beginning or 594 // end of every location entry for each of its parts. For example: 595 // 596 // [variable] [pc range] 597 // string.ptr |----|-----| |----| 598 // string.len |------------| |--| 599 // ... needs a location list like: 600 // string |----|-----|-| |--|-| 601 // 602 // Note that location entries may or may not line up with each other, 603 // and some of the result will only have one or the other part. 604 // 605 // To build the resulting list: 606 // - keep a "current" pointer for each part 607 // - find the next transition point 608 // - advance the current pointer for each part up to that transition point 609 // - build the piece for the range between that transition point and the next 610 // - repeat 611 612 type locID struct { 613 block int 614 loc int 615 } 616 findLoc := func(part varPart, id locID) *ssa.VarLoc { 617 if id.block >= len(debugInfo.Blocks) { 618 return nil 619 } 620 return debugInfo.Blocks[id.block].Variables[part.slot].Locations[id.loc] 621 } 622 nextLoc := func(part varPart, id locID) (locID, *ssa.VarLoc) { 623 // Check if there's another loc in this block 624 id.loc++ 625 if b := debugInfo.Blocks[id.block]; b != nil && id.loc < len(b.Variables[part.slot].Locations) { 626 return id, findLoc(part, id) 627 } 628 // Find the next block that has a loc for this part. 629 id.loc = 0 630 id.block++ 631 for ; id.block < len(debugInfo.Blocks); id.block++ { 632 if b := debugInfo.Blocks[id.block]; b != nil && len(b.Variables[part.slot].Locations) != 0 { 633 return id, findLoc(part, id) 634 } 635 } 636 return id, nil 637 } 638 curLoc := make([]locID, len(slots)) 639 // Position each pointer at the first entry for its slot. 640 for _, part := range parts { 641 if b := debugInfo.Blocks[0]; b != nil && len(b.Variables[part.slot].Locations) != 0 { 642 // Block 0 has an entry; no need to advance. 643 continue 644 } 645 curLoc[part.slot], _ = nextLoc(part, curLoc[part.slot]) 646 } 647 648 // findBoundaryAfter finds the next beginning or end of a piece after currentPC. 649 findBoundaryAfter := func(currentPC int64) int64 { 650 min := int64(math.MaxInt64) 651 for _, part := range parts { 652 // For each part, find the first PC greater than current. Doesn't 653 // matter if it's a start or an end, since we're looking for any boundary. 654 // If it's the new winner, save it. 655 onePart: 656 for i, loc := curLoc[part.slot], findLoc(part, curLoc[part.slot]); loc != nil; i, loc = nextLoc(part, i) { 657 for _, pc := range [2]int64{loc.StartPC, loc.EndPC} { 658 if pc > currentPC { 659 if pc < min { 660 min = pc 661 } 662 break onePart 663 } 664 } 665 } 666 } 667 return min 668 } 669 var start int64 670 end := findBoundaryAfter(0) 671 for { 672 // Advance to the next chunk. 673 start = end 674 end = findBoundaryAfter(start) 675 if end == math.MaxInt64 { 676 break 677 } 678 679 dloc := dwarf.Location{StartPC: start, EndPC: end} 680 if Debug_locationlist != 0 { 681 Ctxt.Logf("Processing range %x -> %x\n", start, end) 682 } 683 684 // Advance curLoc to the last location that starts before/at start. 685 // After this loop, if there's a location that covers [start, end), it will be current. 686 // Otherwise the current piece will be too early. 687 for _, part := range parts { 688 choice := locID{-1, -1} 689 for i, loc := curLoc[part.slot], findLoc(part, curLoc[part.slot]); loc != nil; i, loc = nextLoc(part, i) { 690 if loc.StartPC > start { 691 break //overshot 692 } 693 choice = i // best yet 694 } 695 if choice.block != -1 { 696 curLoc[part.slot] = choice 697 } 698 if Debug_locationlist != 0 { 699 Ctxt.Logf("\t %v => %v", slots[part.slot], curLoc[part.slot]) 700 } 701 } 702 if Debug_locationlist != 0 { 703 Ctxt.Logf("\n") 704 } 705 // Assemble the location list entry for this chunk. 706 present := 0 707 for _, part := range parts { 708 dpiece := dwarf.Piece{ 709 Length: slots[part.slot].Type.Size(), 710 } 711 loc := findLoc(part, curLoc[part.slot]) 712 if loc == nil || start >= loc.EndPC || end <= loc.StartPC { 713 if Debug_locationlist != 0 { 714 Ctxt.Logf("\t%v: missing", slots[part.slot]) 715 } 716 dpiece.Missing = true 717 dloc.Pieces = append(dloc.Pieces, dpiece) 718 continue 719 } 720 present++ 721 if Debug_locationlist != 0 { 722 Ctxt.Logf("\t%v: %v", slots[part.slot], debugInfo.Blocks[curLoc[part.slot].block].LocString(loc)) 723 } 724 if loc.OnStack { 725 dpiece.OnStack = true 726 dpiece.StackOffset = stackOffset(slots[loc.StackLocation]) 727 } else { 728 for reg := 0; reg < len(debugInfo.Registers); reg++ { 729 if loc.Registers&(1<<uint8(reg)) != 0 { 730 dpiece.RegNum = Ctxt.Arch.DWARFRegisters[debugInfo.Registers[reg].ObjNum()] 731 } 732 } 733 } 734 dloc.Pieces = append(dloc.Pieces, dpiece) 735 } 736 if present == 0 { 737 if Debug_locationlist != 0 { 738 Ctxt.Logf(" -> totally missing\n") 739 } 740 continue 741 } 742 // Extend the previous entry if possible. 743 if len(dvar.LocationList) > 0 { 744 prev := &dvar.LocationList[len(dvar.LocationList)-1] 745 if prev.EndPC == dloc.StartPC && len(prev.Pieces) == len(dloc.Pieces) { 746 equal := true 747 for i := range prev.Pieces { 748 if prev.Pieces[i] != dloc.Pieces[i] { 749 equal = false 750 } 751 } 752 if equal { 753 prev.EndPC = end 754 if Debug_locationlist != 0 { 755 Ctxt.Logf("-> merged with previous, now %#v\n", prev) 756 } 757 continue 758 } 759 } 760 } 761 dvar.LocationList = append(dvar.LocationList, dloc) 762 if Debug_locationlist != 0 { 763 Ctxt.Logf("-> added: %#v\n", dloc) 764 } 765 } 766 return dvar 767 } 768 769 // fieldtrack adds R_USEFIELD relocations to fnsym to record any 770 // struct fields that it used. 771 func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) { 772 if fnsym == nil { 773 return 774 } 775 if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 { 776 return 777 } 778 779 trackSyms := make([]*types.Sym, 0, len(tracked)) 780 for sym := range tracked { 781 trackSyms = append(trackSyms, sym) 782 } 783 sort.Sort(symByName(trackSyms)) 784 for _, sym := range trackSyms { 785 r := obj.Addrel(fnsym) 786 r.Sym = sym.Linksym() 787 r.Type = objabi.R_USEFIELD 788 } 789 } 790 791 type symByName []*types.Sym 792 793 func (a symByName) Len() int { return len(a) } 794 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name } 795 func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }