From ac81c5c402ac1023296d4c418287d26aa48061d7 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Mon, 5 Feb 2018 16:55:54 -0500 Subject: [PATCH] cmd/compile/internal/ssa: refactor buildLocationLists Change the closures to methods on debugState, mostly just for aesthetic reasons. Change-Id: I5242807f7300efafc7efb4eb3bd305ac3ec8e826 Reviewed-on: https://go-review.googlesource.com/92403 Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/debug.go | 245 +++++++++++++------------- 1 file changed, 125 insertions(+), 120 deletions(-) diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index 95f7e09231..358edc04d9 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -167,6 +167,7 @@ type debugState struct { slots []*LocalSlot vars []GCNode varSlots [][]SlotID + lists [][]byte // The user variable that each slot rolls up to, indexed by SlotID. slotVars []VarID @@ -176,6 +177,7 @@ type debugState struct { cache *Cache registers []Register stackOffset func(LocalSlot) int32 + ctxt *obj.Link // The names (slots) associated with each value, indexed by Value ID. valueNames [][]SlotID @@ -184,6 +186,9 @@ type debugState struct { currentState stateAtPC liveCount []int changedVars *sparseSet + + // The pending location list entry for each user variable, indexed by VarID. + pendingEntries []pendingEntry } func (state *debugState) initializeCache() { @@ -251,6 +256,7 @@ func (state *debugState) initializeCache() { } freePieceIdx += len(slots) } + state.pendingEntries = pe } func (state *debugState) allocBlock(b *Block) *BlockDebug { @@ -303,6 +309,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu cache: f.Cache, registers: f.Config.registers, stackOffset: stackOffset, + ctxt: ctxt, } // Recompose any decomposed variables, and record the names associated with each value. @@ -327,6 +334,8 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu // Fill in the var<->slot mappings. state.varSlots = make([][]SlotID, len(state.vars)) state.slotVars = make([]VarID, len(state.slots)) + state.lists = make([][]byte, len(state.vars)) + for varID, n := range state.vars { parts := varParts[n] state.varSlots[varID] = parts @@ -347,13 +356,13 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu } blockLocs := state.liveness() - lists := state.buildLocationLists(ctxt, blockLocs) + state.buildLocationLists(blockLocs) return &FuncDebug{ Slots: state.slots, VarSlots: state.varSlots, Vars: state.vars, - LocationLists: lists, + LocationLists: state.lists, } } @@ -717,118 +726,7 @@ func firstReg(set RegisterSet) uint8 { // The returned location lists are not fully complete. They are in terms of // SSA values rather than PCs, and have no base address/end entries. They will // be finished by PutLocationList. -func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDebug) [][]byte { - lists := make([][]byte, len(state.vars)) - pendingEntries := state.cache.pendingEntries - - // writePendingEntry writes out the pending entry for varID, if any, - // terminated at endBlock/Value. - writePendingEntry := func(varID VarID, endBlock, endValue ID) { - list := lists[varID] - pending := pendingEntries[varID] - if !pending.present { - return - } - - // Pack the start/end coordinates into the start/end addresses - // of the entry, for decoding by PutLocationList. - start, startOK := encodeValue(Ctxt, pending.startBlock, pending.startValue) - end, endOK := encodeValue(Ctxt, endBlock, endValue) - if !startOK || !endOK { - // If someone writes a function that uses >65K values, - // they get incomplete debug info on 32-bit platforms. - return - } - list = appendPtr(Ctxt, list, start) - list = appendPtr(Ctxt, list, end) - // Where to write the length of the location description once - // we know how big it is. - sizeIdx := len(list) - list = list[:len(list)+2] - - if state.loggingEnabled { - var partStrs []string - for i, slot := range state.varSlots[varID] { - partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i]))) - } - state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " ")) - } - - for i, slotID := range state.varSlots[varID] { - loc := pending.pieces[i] - slot := state.slots[slotID] - - if !loc.absent() { - if loc.onStack() { - if loc.stackOffsetValue() == 0 { - list = append(list, dwarf.DW_OP_call_frame_cfa) - } else { - list = append(list, dwarf.DW_OP_fbreg) - list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue())) - } - } else { - regnum := Ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()] - if regnum < 32 { - list = append(list, dwarf.DW_OP_reg0+byte(regnum)) - } else { - list = append(list, dwarf.DW_OP_regx) - list = dwarf.AppendUleb128(list, uint64(regnum)) - } - } - } - - if len(state.varSlots[varID]) > 1 { - list = append(list, dwarf.DW_OP_piece) - list = dwarf.AppendUleb128(list, uint64(slot.Type.Size())) - } - } - Ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) - lists[varID] = list - } - - // updateVar updates the pending location list entry for varID to - // reflect the new locations in curLoc, caused by v. - updateVar := func(varID VarID, v *Value, curLoc []VarLoc) { - // Assemble the location list entry with whatever's live. - empty := true - for _, slotID := range state.varSlots[varID] { - if !curLoc[slotID].absent() { - empty = false - break - } - } - pending := &pendingEntries[varID] - if empty { - writePendingEntry(varID, v.Block.ID, v.ID) - pending.clear() - return - } - - // Extend the previous entry if possible. - if pending.present { - merge := true - for i, slotID := range state.varSlots[varID] { - if !canMerge(pending.pieces[i], curLoc[slotID]) { - merge = false - break - } - } - if merge { - return - } - } - - writePendingEntry(varID, v.Block.ID, v.ID) - pending.present = true - pending.startBlock = v.Block.ID - pending.startValue = v.ID - for i, slot := range state.varSlots[varID] { - pending.pieces[i] = curLoc[slot] - } - return - - } - +func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { // Run through the function in program text order, building up location // lists as we go. The heavy lifting has mostly already been done. for _, b := range state.f.Blocks { @@ -853,7 +751,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe phisPending = false for _, varID := range state.changedVars.contents() { - updateVar(VarID(varID), v, state.currentState.slots) + state.updateVar(VarID(varID), v, state.currentState.slots) } state.changedVars.clear() } @@ -865,18 +763,125 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe } // Flush any leftover entries live at the end of the last block. - for varID := range lists { - writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID) - list := lists[varID] + for varID := range state.lists { + state.writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID) + list := state.lists[varID] if len(list) == 0 { continue } if state.loggingEnabled { - state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(lists[varID])) + state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID])) } } - return lists +} + +// updateVar updates the pending location list entry for varID to +// reflect the new locations in curLoc, caused by v. +func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) { + // Assemble the location list entry with whatever's live. + empty := true + for _, slotID := range state.varSlots[varID] { + if !curLoc[slotID].absent() { + empty = false + break + } + } + pending := &state.pendingEntries[varID] + if empty { + state.writePendingEntry(varID, v.Block.ID, v.ID) + pending.clear() + return + } + + // Extend the previous entry if possible. + if pending.present { + merge := true + for i, slotID := range state.varSlots[varID] { + if !canMerge(pending.pieces[i], curLoc[slotID]) { + merge = false + break + } + } + if merge { + return + } + } + + state.writePendingEntry(varID, v.Block.ID, v.ID) + pending.present = true + pending.startBlock = v.Block.ID + pending.startValue = v.ID + for i, slot := range state.varSlots[varID] { + pending.pieces[i] = curLoc[slot] + } + return + +} + +// writePendingEntry writes out the pending entry for varID, if any, +// terminated at endBlock/Value. +func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) { + pending := state.pendingEntries[varID] + if !pending.present { + return + } + + // Pack the start/end coordinates into the start/end addresses + // of the entry, for decoding by PutLocationList. + start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue) + end, endOK := encodeValue(state.ctxt, endBlock, endValue) + if !startOK || !endOK { + // If someone writes a function that uses >65K values, + // they get incomplete debug info on 32-bit platforms. + return + } + list := state.lists[varID] + list = appendPtr(state.ctxt, list, start) + list = appendPtr(state.ctxt, list, end) + // Where to write the length of the location description once + // we know how big it is. + sizeIdx := len(list) + list = list[:len(list)+2] + + if state.loggingEnabled { + var partStrs []string + for i, slot := range state.varSlots[varID] { + partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i]))) + } + state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " ")) + } + + for i, slotID := range state.varSlots[varID] { + loc := pending.pieces[i] + slot := state.slots[slotID] + + if !loc.absent() { + if loc.onStack() { + if loc.stackOffsetValue() == 0 { + list = append(list, dwarf.DW_OP_call_frame_cfa) + } else { + list = append(list, dwarf.DW_OP_fbreg) + list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue())) + } + } else { + regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()] + if regnum < 32 { + list = append(list, dwarf.DW_OP_reg0+byte(regnum)) + } else { + list = append(list, dwarf.DW_OP_regx) + list = dwarf.AppendUleb128(list, uint64(regnum)) + } + } + } + + if len(state.varSlots[varID]) > 1 { + list = append(list, dwarf.DW_OP_piece) + list = dwarf.AppendUleb128(list, uint64(slot.Type.Size())) + } + } + state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) + state.lists[varID] = list } // PutLocationList adds list (a location list in its intermediate representation) to listSym.