Skip to content

Commit cdaed4e

Browse files
authored
write: simplify dependency calculation during conversion (#828)
A single HashMap is sufficient to ensure uniqueness of entries, so we can use Vec elsewhere. This greatly reduces memory usage and execution time.
1 parent 4f640df commit cdaed4e

File tree

1 file changed

+37
-42
lines changed

1 file changed

+37
-42
lines changed

src/write/unit.rs

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,60 +1523,57 @@ pub(crate) mod convert {
15231523
use crate::write::{
15241524
self, ConvertError, ConvertLineProgram, ConvertResult, Dwarf, LocationList, RangeList,
15251525
};
1526-
use fnv::{FnvHashMap as HashMap, FnvHashSet as HashSet};
1526+
use fnv::FnvHashMap as HashMap;
15271527

15281528
#[derive(Debug, Default)]
15291529
struct FilterDependencies {
1530-
edges: HashMap<UnitSectionOffset, HashSet<UnitSectionOffset>>,
1531-
required: HashSet<UnitSectionOffset>,
1530+
edges: HashMap<UnitSectionOffset, Vec<UnitSectionOffset>>,
1531+
required: Vec<UnitSectionOffset>,
15321532
}
15331533

15341534
impl FilterDependencies {
15351535
/// Mark `entry` as a valid offset.
15361536
///
15371537
/// This must be called before adding an edge from an entry.
1538-
fn add_entry(&mut self, entry: UnitSectionOffset) {
1538+
///
1539+
/// Also add edges from `entry` to `deps`.
1540+
fn add_entry(&mut self, entry: UnitSectionOffset, deps: Vec<UnitSectionOffset>) {
15391541
debug_assert!(!self.edges.contains_key(&entry));
1540-
self.edges.insert(entry, HashSet::default());
1542+
self.edges.insert(entry, deps);
15411543
}
15421544

15431545
/// If `from` is reachable then `to` is also reachable.
15441546
///
15451547
/// Must have already called `add_entry(from)`.
15461548
///
1547-
/// The edge will be ignored if `add_entry(to)` is never called
1549+
/// The edge will be ignored if `add_entry` is never called for `to`
15481550
/// (either before or after).
15491551
fn add_edge(&mut self, from: UnitSectionOffset, to: UnitSectionOffset) {
1550-
self.edges.get_mut(&from).unwrap().insert(to);
1552+
self.edges.get_mut(&from).unwrap().push(to);
15511553
}
15521554

15531555
/// Mark `entry` as reachable.
15541556
///
1555-
/// This doesn't depend on `add_entry` being called for the entry
1556-
/// (but you probably should at some stage anyway).
1557+
/// The entry will be ignored if `add_entry` is never called for `entry`
1558+
/// (either before or after).
15571559
fn require_entry(&mut self, entry: UnitSectionOffset) {
1558-
self.required.insert(entry);
1560+
self.required.push(entry);
15591561
}
15601562

15611563
/// Return a sorted list of all reachable entries.
1562-
fn get_reachable(self) -> Vec<UnitSectionOffset> {
1563-
let mut reachable = self.required.clone();
1564-
let mut queue = Vec::new();
1565-
for i in self.required.iter() {
1566-
queue.push(*i);
1567-
}
1568-
while let Some(i) = queue.pop() {
1569-
if let Some(deps) = self.edges.get(&i) {
1570-
for j in deps {
1571-
if self.edges.contains_key(j) && reachable.insert(*j) {
1572-
queue.push(*j);
1573-
}
1564+
fn get_reachable(mut self) -> Vec<UnitSectionOffset> {
1565+
let mut reachable = Vec::new();
1566+
let mut queue = vec![self.required];
1567+
while let Some(entries) = queue.pop() {
1568+
for entry in entries {
1569+
if let Some(deps) = self.edges.remove(&entry) {
1570+
reachable.push(entry);
1571+
queue.push(deps);
15741572
}
15751573
}
15761574
}
1577-
let mut offsets: Vec<_> = reachable.into_iter().collect();
1578-
offsets.sort_unstable();
1579-
offsets
1575+
reachable.sort_unstable();
1576+
reachable
15801577
}
15811578
}
15821579

@@ -1776,8 +1773,6 @@ pub(crate) mod convert {
17761773
}
17771774

17781775
let entry_offset = offset.to_unit_section_offset(&self.unit);
1779-
self.deps.add_entry(entry_offset);
1780-
17811776
let mut entry = FilterUnitEntry {
17821777
unit: self.unit,
17831778
offset,
@@ -1788,16 +1783,18 @@ pub(crate) mod convert {
17881783
parent_tag: parent.map(|p| p.tag),
17891784
};
17901785
Self::read_attributes(&mut entry, &mut self.entries, abbrev.attributes())?;
1786+
let mut deps = Vec::new();
17911787
for attr in &entry.attrs {
1792-
self.add_attribute_refs(entry_offset, attr.value())?;
1788+
self.add_attribute_refs(&mut deps, attr.value())?;
17931789
}
17941790
if let Some(parent) = parent {
17951791
let parent_offset = parent.offset.to_unit_section_offset(&self.unit);
1796-
self.deps.add_edge(entry_offset, parent_offset);
1792+
deps.push(parent_offset);
17971793
if parent.tag != constants::DW_TAG_namespace && entry.has_die_back_edge() {
17981794
self.deps.add_edge(parent_offset, entry_offset);
17991795
}
18001796
}
1797+
self.deps.add_entry(entry_offset, deps);
18011798

18021799
return Ok(Some(entry));
18031800
}
@@ -1831,31 +1828,30 @@ pub(crate) mod convert {
18311828

18321829
fn add_attribute_refs(
18331830
&mut self,
1834-
entry_offset: UnitSectionOffset,
1831+
deps: &mut Vec<UnitSectionOffset>,
18351832
value: read::AttributeValue<R>,
18361833
) -> ConvertResult<()> {
18371834
match value {
18381835
read::AttributeValue::UnitRef(val) => {
18391836
// This checks that the offset is within bounds, but not that it refers to a valid DIE.
18401837
if val.is_in_bounds(&self.unit) {
1841-
self.deps
1842-
.add_edge(entry_offset, val.to_unit_section_offset(&self.unit));
1838+
deps.push(val.to_unit_section_offset(&self.unit));
18431839
}
18441840
}
18451841
read::AttributeValue::DebugInfoRef(val) => {
18461842
let offset = val
18471843
.to_unit_section_offset(&self.unit)
18481844
.ok_or(ConvertError::InvalidDebugInfoRef)?;
1849-
self.deps.add_edge(entry_offset, offset);
1845+
deps.push(offset);
18501846
}
18511847
read::AttributeValue::Exprloc(expression) => {
1852-
self.add_expression_refs(entry_offset, expression.clone())?;
1848+
self.add_expression_refs(deps, expression.clone())?;
18531849
}
18541850
read::AttributeValue::LocationListsRef(val) => {
1855-
self.add_location_refs(entry_offset, val)?;
1851+
self.add_location_refs(deps, val)?;
18561852
}
18571853
read::AttributeValue::DebugLocListsIndex(index) => {
1858-
self.add_location_refs(entry_offset, self.unit.locations_offset(index)?)?;
1854+
self.add_location_refs(deps, self.unit.locations_offset(index)?)?;
18591855
}
18601856
_ => (),
18611857
}
@@ -1864,19 +1860,19 @@ pub(crate) mod convert {
18641860

18651861
fn add_location_refs(
18661862
&mut self,
1867-
entry_offset: UnitSectionOffset,
1863+
deps: &mut Vec<UnitSectionOffset>,
18681864
offset: LocationListsOffset,
18691865
) -> ConvertResult<()> {
18701866
let mut locations = self.unit.locations(offset)?;
18711867
while let Some(location) = locations.next()? {
1872-
self.add_expression_refs(entry_offset, location.data)?;
1868+
self.add_expression_refs(deps, location.data)?;
18731869
}
18741870
Ok(())
18751871
}
18761872

18771873
fn add_expression_refs(
18781874
&mut self,
1879-
entry_offset: UnitSectionOffset,
1875+
deps: &mut Vec<UnitSectionOffset>,
18801876
expression: read::Expression<R>,
18811877
) -> ConvertResult<()> {
18821878
let mut ops = expression.operations(self.unit.encoding());
@@ -1904,8 +1900,7 @@ pub(crate) mod convert {
19041900
..
19051901
} => {
19061902
if offset.is_in_bounds(&self.unit) {
1907-
self.deps
1908-
.add_edge(entry_offset, offset.to_unit_section_offset(&self.unit));
1903+
deps.push(offset.to_unit_section_offset(&self.unit));
19091904
}
19101905
}
19111906
read::Operation::Call {
@@ -1915,7 +1910,7 @@ pub(crate) mod convert {
19151910
let offset = ref_offset
19161911
.to_unit_section_offset(&self.unit)
19171912
.ok_or(ConvertError::InvalidDebugInfoRef)?;
1918-
self.deps.add_edge(entry_offset, offset);
1913+
deps.push(offset);
19191914
}
19201915
_ => {}
19211916
}

0 commit comments

Comments
 (0)