Index: llvm/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/tools/dsymutil/DwarfLinker.cpp +++ llvm/tools/dsymutil/DwarfLinker.cpp @@ -765,6 +765,8 @@ enum class WorklistItemType { LookForDIEsToKeep, LookForChildDIEsToKeep, + LookForRefDIEsToKeep, + LookForParentDIEsToKeep, UpdateChildIncompleteness, UpdateRefIncompleteness, }; @@ -777,6 +779,7 @@ DWARFDie Die; CompileUnit &CU; unsigned Flags; + unsigned AncestorIdx = 0; CompileUnit::DIEInfo *OtherInfo = nullptr; WorklistItem(DWARFDie Die, CompileUnit &CU, unsigned Flags, @@ -786,6 +789,10 @@ WorklistItem(DWARFDie Die, CompileUnit &CU, WorklistItemType T, CompileUnit::DIEInfo *OtherInfo = nullptr) : Type(T), Die(Die), CU(CU), OtherInfo(OtherInfo){}; + + WorklistItem(unsigned AncestorIdx, CompileUnit &CU, unsigned Flags) + : Type(WorklistItemType::LookForParentDIEsToKeep), CU(CU), Flags(Flags), + AncestorIdx(AncestorIdx){}; }; } // namespace @@ -862,6 +869,90 @@ } } +static void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, + unsigned Flags, DwarfLinker &Linker, + const UnitListTy &Units, + const DebugMapObject &DMO, + SmallVectorImpl &Worklist) { + bool UseOdr = (Flags & DwarfLinker::TF_DependencyWalk) + ? (Flags & DwarfLinker::TF_ODR) + : CU.hasODR(); + DWARFUnit &Unit = CU.getOrigUnit(); + DWARFDataExtractor Data = Unit.getDebugInfoExtractor(); + const auto *Abbrev = Die.getAbbreviationDeclarationPtr(); + uint64_t Offset = Die.getOffset() + getULEB128Size(Abbrev->getCode()); + + // Mark all DIEs referenced through attributes as kept. + SmallVector, 4> ReferencedDIEs; + for (const auto &AttrSpec : Abbrev->attributes()) { + DWARFFormValue Val(AttrSpec.Form); + if (!Val.isFormClass(DWARFFormValue::FC_Reference) || + AttrSpec.Attr == dwarf::DW_AT_sibling) { + DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, + Unit.getFormParams()); + continue; + } + + Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); + CompileUnit *ReferencedCU; + if (auto RefDie = + resolveDIEReference(Linker, DMO, Units, Val, Die, ReferencedCU)) { + uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDie); + CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx); + bool IsModuleRef = Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() && + Info.Ctxt->isDefinedInClangModule(); + // If the referenced DIE has a DeclContext that has already been + // emitted, then do not keep the one in this CU. We'll link to + // the canonical DIE in cloneDieReferenceAttribute. + // FIXME: compatibility with dsymutil-classic. UseODR shouldn't + // be necessary and could be advantageously replaced by + // ReferencedCU->hasODR() && CU.hasODR(). + // FIXME: compatibility with dsymutil-classic. There is no + // reason not to unique ref_addr references. + if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && (UseOdr || IsModuleRef) && + Info.Ctxt && + Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt && + Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr)) + continue; + + // Keep a module forward declaration if there is no definition. + if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt && + Info.Ctxt->getCanonicalDIEOffset())) + Info.Prune = false; + ReferencedDIEs.emplace_back(RefDie, *ReferencedCU); + } + } + + unsigned ODRFlag = UseOdr ? DwarfLinker::TF_ODR : 0; + + // Add referenced DIEs in reverse order to the worklist to effectively + // process them in order. + for (auto &P : reverse(ReferencedDIEs)) { + // Add a worklist item before every child to calculate incompleteness right + // after the current child is processed. + uint32_t RefIdx = P.second.getOrigUnit().getDIEIndex(P.first); + CompileUnit::DIEInfo &Info = P.second.getInfo(RefIdx); + Worklist.emplace_back(Die, CU, WorklistItemType::UpdateRefIncompleteness, + &Info); + Worklist.emplace_back(P.first, P.second, + DwarfLinker::TF_Keep | + DwarfLinker::TF_DependencyWalk | ODRFlag); + } +} + +static void lookForParentDIEsToKeep(unsigned AncestorIdx, CompileUnit &CU, + unsigned Flags, + SmallVectorImpl &Worklist) { + // Stop if we encounter an ancestor that's already marked as kept. + if (CU.getInfo(AncestorIdx).Keep) + return; + + DWARFUnit &Unit = CU.getOrigUnit(); + DWARFDie ParentDIE = Unit.getDIEAtIndex(AncestorIdx); + Worklist.emplace_back(CU.getInfo(AncestorIdx).ParentIdx, CU, Flags); + Worklist.emplace_back(ParentDIE, CU, Flags); +} + /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that /// information in \p CU's DIEInfo. /// @@ -900,6 +991,14 @@ case WorklistItemType::LookForChildDIEsToKeep: lookForChildDIEsToKeep(Current.Die, Current.CU, Current.Flags, Worklist); continue; + case WorklistItemType::LookForRefDIEsToKeep: + lookForRefDIEsToKeep(Current.Die, Current.CU, Current.Flags, *this, Units, + DMO, Worklist); + continue; + case WorklistItemType::LookForParentDIEsToKeep: + lookForParentDIEsToKeep(Current.AncestorIdx, Current.CU, Current.Flags, + Worklist); + continue; case WorklistItemType::LookForDIEsToKeep: break; } @@ -933,12 +1032,6 @@ // If it is a newly kept DIE mark it as well as all its dependencies as // kept. - bool UseOdr = (Current.Flags & TF_DependencyWalk) - ? (Current.Flags & TF_ODR) - : Current.CU.hasODR(); - unsigned ODRFlag = UseOdr ? TF_ODR : 0; - - DWARFUnit &Unit = Current.CU.getOrigUnit(); MyInfo.Keep = true; // We're looking for incomplete types. @@ -947,74 +1040,19 @@ Current.Die.getTag() != dwarf::DW_TAG_member && dwarf::toUnsigned(Current.Die.find(dwarf::DW_AT_declaration), 0); - // First mark all the parent chain as kept. - unsigned AncestorIdx = MyInfo.ParentIdx; - while (!Current.CU.getInfo(AncestorIdx).Keep) { - lookForDIEsToKeep( - RelocMgr, Ranges, Units, Unit.getDIEAtIndex(AncestorIdx), DMO, - Current.CU, TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag); - AncestorIdx = Current.CU.getInfo(AncestorIdx).ParentIdx; - } - - // Then we need to mark all the DIEs referenced by this DIE's attributes - // as kept. - DWARFDataExtractor Data = Unit.getDebugInfoExtractor(); - const auto *Abbrev = Current.Die.getAbbreviationDeclarationPtr(); - uint64_t Offset = - Current.Die.getOffset() + getULEB128Size(Abbrev->getCode()); - - // Mark all DIEs referenced through attributes as kept. - SmallVector, 4> ReferencedDIEs; - for (const auto &AttrSpec : Abbrev->attributes()) { - DWARFFormValue Val(AttrSpec.Form); - if (!Val.isFormClass(DWARFFormValue::FC_Reference) || - AttrSpec.Attr == dwarf::DW_AT_sibling) { - DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, - Unit.getFormParams()); - continue; - } - - Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); - CompileUnit *ReferencedCU; - if (auto RefDie = resolveDIEReference(*this, DMO, Units, Val, - Current.Die, ReferencedCU)) { - uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDie); - CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx); - bool IsModuleRef = Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() && - Info.Ctxt->isDefinedInClangModule(); - // If the referenced DIE has a DeclContext that has already been - // emitted, then do not keep the one in this CU. We'll link to - // the canonical DIE in cloneDieReferenceAttribute. - // FIXME: compatibility with dsymutil-classic. UseODR shouldn't - // be necessary and could be advantageously replaced by - // ReferencedCU->hasODR() && CU.hasODR(). - // FIXME: compatibility with dsymutil-classic. There is no - // reason not to unique ref_addr references. - if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && - (UseOdr || IsModuleRef) && Info.Ctxt && - Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt && - Info.Ctxt->getCanonicalDIEOffset() && - isODRAttribute(AttrSpec.Attr)) - continue; + // After looking at the parent chain, look for referenced DIEs. Because of + // the LIFO worklist we need to schedule that work before any subsequent + // items are added to the worklist. + Worklist.emplace_back(Current.Die, Current.CU, Current.Flags, + WorklistItemType::LookForRefDIEsToKeep); - // Keep a module forward declaration if there is no definition. - if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt && - Info.Ctxt->getCanonicalDIEOffset())) - Info.Prune = false; - ReferencedDIEs.emplace_back(RefDie, *ReferencedCU); - } - } + bool UseOdr = (Current.Flags & TF_DependencyWalk) ? (Current.Flags & TF_ODR) + : Current.CU.hasODR(); + unsigned ODRFlag = UseOdr ? TF_ODR : 0; + unsigned ParFlags = TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag; - // Add referenced DIEs in reverse order to the worklist to effectively - // process them in order. - for (auto& P : reverse(ReferencedDIEs)) { - // Add a worklist item before every child to calculate incompleteness right - // after the current child is processed. - uint32_t RefIdx = P.second.getOrigUnit().getDIEIndex(P.first); - CompileUnit::DIEInfo &Info = P.second.getInfo(RefIdx); - Worklist.emplace_back(Current.Die, Current.CU, WorklistItemType::UpdateRefIncompleteness, &Info); - Worklist.emplace_back(P.first, P.second, TF_Keep | TF_DependencyWalk | ODRFlag); - } + // Now schedule the parent walk. + Worklist.emplace_back(MyInfo.ParentIdx, Current.CU, ParFlags); } }