@@ -759,9 +759,19 @@ unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr,
759
759
namespace {
760
760
// / The distinct types of work performed by the work loop.
761
761
enum class WorklistItemType {
762
+ // / Given a DIE, look for DIEs to be kept.
762
763
LookForDIEsToKeep,
764
+ // / Given a DIE, look for children of this DIE to be kept.
763
765
LookForChildDIEsToKeep,
766
+ // / Given a DIE, look for DIEs referencing this DIE to be kept.
767
+ LookForRefDIEsToKeep,
768
+ // / Given a DIE, look for parent DIEs to be kept.
769
+ LookForParentDIEsToKeep,
770
+ // / Given a DIE, update its incompleteness based on whether its children are
771
+ // / incomplete.
764
772
UpdateChildIncompleteness,
773
+ // / Given a DIE, update its incompleteness based on whether the DIEs it
774
+ // / references are incomplete.
765
775
UpdateRefIncompleteness,
766
776
};
767
777
@@ -773,6 +783,7 @@ struct WorklistItem {
773
783
DWARFDie Die;
774
784
CompileUnit &CU;
775
785
unsigned Flags;
786
+ unsigned AncestorIdx = 0 ;
776
787
CompileUnit::DIEInfo *OtherInfo = nullptr ;
777
788
778
789
WorklistItem (DWARFDie Die, CompileUnit &CU, unsigned Flags,
@@ -782,6 +793,10 @@ struct WorklistItem {
782
793
WorklistItem (DWARFDie Die, CompileUnit &CU, WorklistItemType T,
783
794
CompileUnit::DIEInfo *OtherInfo = nullptr )
784
795
: Type(T), Die(Die), CU(CU), OtherInfo(OtherInfo){};
796
+
797
+ WorklistItem (unsigned AncestorIdx, CompileUnit &CU, unsigned Flags)
798
+ : Type(WorklistItemType::LookForParentDIEsToKeep), CU(CU), Flags(Flags),
799
+ AncestorIdx (AncestorIdx){};
785
800
};
786
801
} // namespace
787
802
@@ -806,8 +821,8 @@ static void updateChildIncompleteness(const DWARFDie &Die, CompileUnit &CU,
806
821
}
807
822
808
823
// / Helper that updates the completeness of the current DIE based on the
809
- // / completeness of the DIEs referencing it . It depends on the incompleteness
810
- // / of the referencing DIE already being computed.
824
+ // / completeness of the DIEs it references . It depends on the incompleteness of
825
+ // / the referenced DIE already being computed.
811
826
static void updateRefIncompleteness (const DWARFDie &Die, CompileUnit &CU,
812
827
CompileUnit::DIEInfo &RefInfo) {
813
828
switch (Die.getTag ()) {
@@ -831,6 +846,8 @@ static void updateRefIncompleteness(const DWARFDie &Die, CompileUnit &CU,
831
846
MyInfo.Incomplete = true ;
832
847
}
833
848
849
+ // / Look at the children of the given DIE and decide whether they should be
850
+ // / kept.
834
851
static void lookForChildDIEsToKeep (const DWARFDie &Die, CompileUnit &CU,
835
852
unsigned Flags,
836
853
SmallVectorImpl<WorklistItem> &Worklist) {
@@ -842,6 +859,8 @@ static void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU,
842
859
if (dieNeedsChildrenToBeMeaningful (Die.getTag ()))
843
860
Flags &= ~DwarfLinker::TF_ParentWalk;
844
861
862
+ // We're finished if this DIE has no children or we're walking the parent
863
+ // chain.
845
864
if (!Die.hasChildren () || (Flags & DwarfLinker::TF_ParentWalk))
846
865
return ;
847
866
@@ -858,6 +877,94 @@ static void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU,
858
877
}
859
878
}
860
879
880
+ // / Look at DIEs referenced by the given DIE and decide whether they should be
881
+ // / kept. All DIEs referenced though attributes should be kept.
882
+ static void lookForRefDIEsToKeep (const DWARFDie &Die, CompileUnit &CU,
883
+ unsigned Flags, DwarfLinker &Linker,
884
+ const UnitListTy &Units,
885
+ const DebugMapObject &DMO,
886
+ SmallVectorImpl<WorklistItem> &Worklist) {
887
+ bool UseOdr = (Flags & DwarfLinker::TF_DependencyWalk)
888
+ ? (Flags & DwarfLinker::TF_ODR)
889
+ : CU.hasODR ();
890
+ DWARFUnit &Unit = CU.getOrigUnit ();
891
+ DWARFDataExtractor Data = Unit.getDebugInfoExtractor ();
892
+ const auto *Abbrev = Die.getAbbreviationDeclarationPtr ();
893
+ uint64_t Offset = Die.getOffset () + getULEB128Size (Abbrev->getCode ());
894
+
895
+ SmallVector<std::pair<DWARFDie, CompileUnit &>, 4 > ReferencedDIEs;
896
+ for (const auto &AttrSpec : Abbrev->attributes ()) {
897
+ DWARFFormValue Val (AttrSpec.Form );
898
+ if (!Val.isFormClass (DWARFFormValue::FC_Reference) ||
899
+ AttrSpec.Attr == dwarf::DW_AT_sibling) {
900
+ DWARFFormValue::skipValue (AttrSpec.Form , Data, &Offset,
901
+ Unit.getFormParams ());
902
+ continue ;
903
+ }
904
+
905
+ Val.extractValue (Data, &Offset, Unit.getFormParams (), &Unit);
906
+ CompileUnit *ReferencedCU;
907
+ if (auto RefDie =
908
+ resolveDIEReference (Linker, DMO, Units, Val, Die, ReferencedCU)) {
909
+ uint32_t RefIdx = ReferencedCU->getOrigUnit ().getDIEIndex (RefDie);
910
+ CompileUnit::DIEInfo &Info = ReferencedCU->getInfo (RefIdx);
911
+ bool IsModuleRef = Info.Ctxt && Info.Ctxt ->getCanonicalDIEOffset () &&
912
+ Info.Ctxt ->isDefinedInClangModule ();
913
+ // If the referenced DIE has a DeclContext that has already been
914
+ // emitted, then do not keep the one in this CU. We'll link to
915
+ // the canonical DIE in cloneDieReferenceAttribute.
916
+ //
917
+ // FIXME: compatibility with dsymutil-classic. UseODR shouldn't
918
+ // be necessary and could be advantageously replaced by
919
+ // ReferencedCU->hasODR() && CU.hasODR().
920
+ //
921
+ // FIXME: compatibility with dsymutil-classic. There is no
922
+ // reason not to unique ref_addr references.
923
+ if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && (UseOdr || IsModuleRef) &&
924
+ Info.Ctxt &&
925
+ Info.Ctxt != ReferencedCU->getInfo (Info.ParentIdx ).Ctxt &&
926
+ Info.Ctxt ->getCanonicalDIEOffset () && isODRAttribute (AttrSpec.Attr ))
927
+ continue ;
928
+
929
+ // Keep a module forward declaration if there is no definition.
930
+ if (!(isODRAttribute (AttrSpec.Attr ) && Info.Ctxt &&
931
+ Info.Ctxt ->getCanonicalDIEOffset ()))
932
+ Info.Prune = false ;
933
+ ReferencedDIEs.emplace_back (RefDie, *ReferencedCU);
934
+ }
935
+ }
936
+
937
+ unsigned ODRFlag = UseOdr ? DwarfLinker::TF_ODR : 0 ;
938
+
939
+ // Add referenced DIEs in reverse order to the worklist to effectively
940
+ // process them in order.
941
+ for (auto &P : reverse (ReferencedDIEs)) {
942
+ // Add a worklist item before every child to calculate incompleteness right
943
+ // after the current child is processed.
944
+ uint32_t RefIdx = P.second .getOrigUnit ().getDIEIndex (P.first );
945
+ CompileUnit::DIEInfo &Info = P.second .getInfo (RefIdx);
946
+ Worklist.emplace_back (Die, CU, WorklistItemType::UpdateRefIncompleteness,
947
+ &Info);
948
+ Worklist.emplace_back (P.first , P.second ,
949
+ DwarfLinker::TF_Keep |
950
+ DwarfLinker::TF_DependencyWalk | ODRFlag);
951
+ }
952
+ }
953
+
954
+ // / Look at the parent of the given DIE and decide whether they should be kept.
955
+ static void lookForParentDIEsToKeep (unsigned AncestorIdx, CompileUnit &CU,
956
+ unsigned Flags,
957
+ SmallVectorImpl<WorklistItem> &Worklist) {
958
+ // Stop if we encounter an ancestor that's already marked as kept.
959
+ if (CU.getInfo (AncestorIdx).Keep )
960
+ return ;
961
+
962
+ DWARFUnit &Unit = CU.getOrigUnit ();
963
+ DWARFDie ParentDIE = Unit.getDIEAtIndex (AncestorIdx);
964
+ Worklist.emplace_back (CU.getInfo (AncestorIdx).ParentIdx , CU, Flags);
965
+ Worklist.emplace_back (ParentDIE, CU, Flags);
966
+ }
967
+
861
968
// / Recursively walk the \p DIE tree and look for DIEs to keep. Store that
862
969
// / information in \p CU's DIEInfo.
863
970
// /
@@ -871,6 +978,17 @@ static void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU,
871
978
// / TF_DependencyWalk flag tells us which kind of traversal we are currently
872
979
// / doing.
873
980
// /
981
+ // / The recursive algorithm is implemented iteratively as a work list because
982
+ // / very deep recursion could exhaust the stack for large projects. The work
983
+ // / list acts as a scheduler for different types of work that need to be
984
+ // / performed.
985
+ // /
986
+ // / The recursive nature of the algorithm is simulated by running the "main"
987
+ // / algorithm (LookForDIEsToKeep) followed by either looking at more DIEs
988
+ // / (LookForChildDIEsToKeep, LookForRefDIEsToKeep, LookForParentDIEsToKeep) or
989
+ // / fixing up a computed property (UpdateChildIncompleteness,
990
+ // / UpdateRefIncompleteness).
991
+ // /
874
992
// / The return value indicates whether the DIE is incomplete.
875
993
void DwarfLinker::lookForDIEsToKeep (RelocationManager &RelocMgr,
876
994
RangesTy &Ranges, const UnitListTy &Units,
@@ -896,6 +1014,14 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
896
1014
case WorklistItemType::LookForChildDIEsToKeep:
897
1015
lookForChildDIEsToKeep (Current.Die , Current.CU , Current.Flags , Worklist);
898
1016
continue ;
1017
+ case WorklistItemType::LookForRefDIEsToKeep:
1018
+ lookForRefDIEsToKeep (Current.Die , Current.CU , Current.Flags , *this , Units,
1019
+ DMO, Worklist);
1020
+ continue ;
1021
+ case WorklistItemType::LookForParentDIEsToKeep:
1022
+ lookForParentDIEsToKeep (Current.AncestorIdx , Current.CU , Current.Flags ,
1023
+ Worklist);
1024
+ continue ;
899
1025
case WorklistItemType::LookForDIEsToKeep:
900
1026
break ;
901
1027
}
@@ -929,12 +1055,6 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
929
1055
930
1056
// If it is a newly kept DIE mark it as well as all its dependencies as
931
1057
// kept.
932
- bool UseOdr = (Current.Flags & TF_DependencyWalk)
933
- ? (Current.Flags & TF_ODR)
934
- : Current.CU .hasODR ();
935
- unsigned ODRFlag = UseOdr ? TF_ODR : 0 ;
936
-
937
- DWARFUnit &Unit = Current.CU .getOrigUnit ();
938
1058
MyInfo.Keep = true ;
939
1059
940
1060
// We're looking for incomplete types.
@@ -943,74 +1063,19 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
943
1063
Current.Die .getTag () != dwarf::DW_TAG_member &&
944
1064
dwarf::toUnsigned (Current.Die .find (dwarf::DW_AT_declaration), 0 );
945
1065
946
- // First mark all the parent chain as kept.
947
- unsigned AncestorIdx = MyInfo.ParentIdx ;
948
- while (!Current.CU .getInfo (AncestorIdx).Keep ) {
949
- lookForDIEsToKeep (
950
- RelocMgr, Ranges, Units, Unit.getDIEAtIndex (AncestorIdx), DMO,
951
- Current.CU , TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag);
952
- AncestorIdx = Current.CU .getInfo (AncestorIdx).ParentIdx ;
953
- }
954
-
955
- // Then we need to mark all the DIEs referenced by this DIE's attributes
956
- // as kept.
957
- DWARFDataExtractor Data = Unit.getDebugInfoExtractor ();
958
- const auto *Abbrev = Current.Die .getAbbreviationDeclarationPtr ();
959
- uint64_t Offset =
960
- Current.Die .getOffset () + getULEB128Size (Abbrev->getCode ());
961
-
962
- // Mark all DIEs referenced through attributes as kept.
963
- SmallVector<std::pair<DWARFDie, CompileUnit &>, 4 > ReferencedDIEs;
964
- for (const auto &AttrSpec : Abbrev->attributes ()) {
965
- DWARFFormValue Val (AttrSpec.Form );
966
- if (!Val.isFormClass (DWARFFormValue::FC_Reference) ||
967
- AttrSpec.Attr == dwarf::DW_AT_sibling) {
968
- DWARFFormValue::skipValue (AttrSpec.Form , Data, &Offset,
969
- Unit.getFormParams ());
970
- continue ;
971
- }
972
-
973
- Val.extractValue (Data, &Offset, Unit.getFormParams (), &Unit);
974
- CompileUnit *ReferencedCU;
975
- if (auto RefDie = resolveDIEReference (*this , DMO, Units, Val,
976
- Current.Die , ReferencedCU)) {
977
- uint32_t RefIdx = ReferencedCU->getOrigUnit ().getDIEIndex (RefDie);
978
- CompileUnit::DIEInfo &Info = ReferencedCU->getInfo (RefIdx);
979
- bool IsModuleRef = Info.Ctxt && Info.Ctxt ->getCanonicalDIEOffset () &&
980
- Info.Ctxt ->isDefinedInClangModule ();
981
- // If the referenced DIE has a DeclContext that has already been
982
- // emitted, then do not keep the one in this CU. We'll link to
983
- // the canonical DIE in cloneDieReferenceAttribute.
984
- // FIXME: compatibility with dsymutil-classic. UseODR shouldn't
985
- // be necessary and could be advantageously replaced by
986
- // ReferencedCU->hasODR() && CU.hasODR().
987
- // FIXME: compatibility with dsymutil-classic. There is no
988
- // reason not to unique ref_addr references.
989
- if (AttrSpec.Form != dwarf::DW_FORM_ref_addr &&
990
- (UseOdr || IsModuleRef) && Info.Ctxt &&
991
- Info.Ctxt != ReferencedCU->getInfo (Info.ParentIdx ).Ctxt &&
992
- Info.Ctxt ->getCanonicalDIEOffset () &&
993
- isODRAttribute (AttrSpec.Attr ))
994
- continue ;
1066
+ // After looking at the parent chain, look for referenced DIEs. Because of
1067
+ // the LIFO worklist we need to schedule that work before any subsequent
1068
+ // items are added to the worklist.
1069
+ Worklist.emplace_back (Current.Die , Current.CU , Current.Flags ,
1070
+ WorklistItemType::LookForRefDIEsToKeep);
995
1071
996
- // Keep a module forward declaration if there is no definition.
997
- if (!(isODRAttribute (AttrSpec.Attr ) && Info.Ctxt &&
998
- Info.Ctxt ->getCanonicalDIEOffset ()))
999
- Info.Prune = false ;
1000
- ReferencedDIEs.emplace_back (RefDie, *ReferencedCU);
1001
- }
1002
- }
1072
+ bool UseOdr = (Current.Flags & TF_DependencyWalk) ? (Current.Flags & TF_ODR)
1073
+ : Current.CU .hasODR ();
1074
+ unsigned ODRFlag = UseOdr ? TF_ODR : 0 ;
1075
+ unsigned ParFlags = TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag;
1003
1076
1004
- // Add referenced DIEs in reverse order to the worklist to effectively
1005
- // process them in order.
1006
- for (auto & P : reverse (ReferencedDIEs)) {
1007
- // Add a worklist item before every child to calculate incompleteness right
1008
- // after the current child is processed.
1009
- uint32_t RefIdx = P.second .getOrigUnit ().getDIEIndex (P.first );
1010
- CompileUnit::DIEInfo &Info = P.second .getInfo (RefIdx);
1011
- Worklist.emplace_back (Current.Die , Current.CU , WorklistItemType::UpdateRefIncompleteness, &Info);
1012
- Worklist.emplace_back (P.first , P.second , TF_Keep | TF_DependencyWalk | ODRFlag);
1013
- }
1077
+ // Now schedule the parent walk.
1078
+ Worklist.emplace_back (MyInfo.ParentIdx , Current.CU , ParFlags);
1014
1079
}
1015
1080
}
1016
1081
0 commit comments