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