diff --git a/src/read/abbrev.rs b/src/read/abbrev.rs index 1a24835a..386a8a9d 100644 --- a/src/read/abbrev.rs +++ b/src/read/abbrev.rs @@ -1,16 +1,18 @@ //! Functions for parsing DWARF debugging abbreviations. use alloc::collections::btree_map; +use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryFrom; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::Deref; +use std::sync::Mutex; use crate::common::{DebugAbbrevOffset, Encoding, SectionId}; use crate::constants; use crate::endianity::Endianity; -use crate::read::{EndianSlice, Error, Reader, Result, Section, UnitHeader}; +use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section, UnitHeader}; /// The `DebugAbbrev` struct represents the abbreviations describing /// `DebuggingInformationEntry`s' attribute names and forms found in the @@ -100,6 +102,44 @@ impl From for DebugAbbrev { } } +/// A cache of previously parsed `Abbreviations`. +/// +/// Currently this only caches the abbreviations for offset 0, +/// since this is a common case in which abbreviations are reused. +/// This strategy may change in future if there is sufficient need. +#[derive(Debug, Default)] +pub struct AbbreviationsCache { + abbreviations: Mutex>>, +} + +impl AbbreviationsCache { + /// Create an empty abbreviations cache. + pub fn new() -> Self { + Self::default() + } + + /// Parse a unit's abbreviations. + /// + /// This uses or updates the cache as required. + pub fn get( + &self, + unit: &UnitHeader, + debug_abbrev: &DebugAbbrev, + ) -> Result> { + let offset = unit.debug_abbrev_offset(); + if offset.0 != R::Offset::from_u8(0) { + return debug_abbrev.abbreviations(offset).map(Arc::new); + } + let mut cache = self.abbreviations.lock().unwrap(); + if let Some(abbreviations) = &*cache { + return Ok(abbreviations.clone()); + } + let abbreviations = debug_abbrev.abbreviations(offset).map(Arc::new)?; + *cache = Some(abbreviations.clone()); + Ok(abbreviations) + } +} + /// A set of type abbreviations. /// /// Construct an `Abbreviations` instance with the diff --git a/src/read/dwarf.rs b/src/read/dwarf.rs index b6352694..f28e5868 100644 --- a/src/read/dwarf.rs +++ b/src/read/dwarf.rs @@ -9,11 +9,11 @@ use crate::common::{ }; use crate::constants; use crate::read::{ - Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugAranges, DebugCuIndex, DebugInfo, - DebugInfoUnitHeadersIter, DebugLine, DebugLineStr, DebugLoc, DebugLocLists, DebugRngLists, - DebugStr, DebugStrOffsets, DebugTuIndex, DebugTypes, DebugTypesUnitHeadersIter, - DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error, - IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, RawLocListIter, + Abbreviations, AbbreviationsCache, AttributeValue, DebugAbbrev, DebugAddr, DebugAranges, + DebugCuIndex, DebugInfo, DebugInfoUnitHeadersIter, DebugLine, DebugLineStr, DebugLoc, + DebugLocLists, DebugRngLists, DebugStr, DebugStrOffsets, DebugTuIndex, DebugTypes, + DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, + Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, RawLocListIter, RawRngListIter, Reader, ReaderOffset, ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, UnitOffset, UnitType, }; @@ -59,6 +59,9 @@ pub struct Dwarf { /// The DWARF sections for a supplementary object file. pub sup: Option>>, + + /// A cache of previously parsed abbreviations for units in this file. + pub abbreviations_cache: AbbreviationsCache, } impl Dwarf { @@ -96,6 +99,7 @@ impl Dwarf { ranges: RangeLists::new(debug_ranges, debug_rnglists), file_type: DwarfFileType::Main, sup: None, + abbreviations_cache: AbbreviationsCache::new(), }) } @@ -157,6 +161,7 @@ impl Dwarf { ranges: self.ranges.borrow(&mut borrow), file_type: self.file_type, sup: self.sup().map(|sup| Arc::new(sup.borrow(borrow))), + abbreviations_cache: AbbreviationsCache::new(), } } @@ -192,10 +197,9 @@ impl Dwarf { } /// Parse the abbreviations for a compilation unit. - // TODO: provide caching of abbreviations #[inline] - pub fn abbreviations(&self, unit: &UnitHeader) -> Result { - unit.abbreviations(&self.debug_abbrev) + pub fn abbreviations(&self, unit: &UnitHeader) -> Result> { + self.abbreviations_cache.get(unit, &self.debug_abbrev) } /// Return the string offset at the given index. @@ -783,6 +787,7 @@ impl DwarfPackage { ranges: RangeLists::new(debug_ranges, debug_rnglists), file_type: DwarfFileType::Dwo, sup: None, + abbreviations_cache: AbbreviationsCache::new(), }) } } @@ -799,7 +804,7 @@ where pub header: UnitHeader, /// The parsed abbreviations for the unit. - pub abbreviations: Abbreviations, + pub abbreviations: Arc, /// The `DW_AT_name` attribute of the unit. pub name: Option, @@ -833,7 +838,7 @@ impl Unit { /// Construct a new `Unit` from the given unit header. #[inline] pub fn new(dwarf: &Dwarf, header: UnitHeader) -> Result { - let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?; + let abbreviations = dwarf.abbreviations(&header)?; let mut unit = Unit { abbreviations, name: None, diff --git a/src/write/loc.rs b/src/write/loc.rs index ea0ecb1c..6dfe45a6 100644 --- a/src/write/loc.rs +++ b/src/write/loc.rs @@ -436,6 +436,7 @@ mod tests { }; use crate::LittleEndian; use std::collections::HashMap; + use std::sync::Arc; #[test] fn test_loc_list() { @@ -508,7 +509,7 @@ mod tests { DebugInfoOffset(0).into(), read::EndianSlice::default(), ), - abbreviations: read::Abbreviations::default(), + abbreviations: Arc::new(read::Abbreviations::default()), name: None, comp_dir: None, low_pc: 0, diff --git a/src/write/op.rs b/src/write/op.rs index c70eec2d..1880afaf 100644 --- a/src/write/op.rs +++ b/src/write/op.rs @@ -1071,6 +1071,7 @@ mod tests { }; use crate::LittleEndian; use std::collections::HashMap; + use std::sync::Arc; #[test] fn test_operation() { @@ -1578,7 +1579,7 @@ mod tests { DebugInfoOffset(0).into(), read::EndianSlice::new(&[], LittleEndian), ), - abbreviations: read::Abbreviations::default(), + abbreviations: Arc::new(read::Abbreviations::default()), name: None, comp_dir: None, low_pc: 0, diff --git a/src/write/range.rs b/src/write/range.rs index b44ce1b7..c707e1ea 100644 --- a/src/write/range.rs +++ b/src/write/range.rs @@ -315,6 +315,7 @@ mod tests { }; use crate::LittleEndian; use std::collections::HashMap; + use std::sync::Arc; #[test] fn test_range() { @@ -375,7 +376,7 @@ mod tests { DebugInfoOffset(0).into(), read::EndianSlice::default(), ), - abbreviations: read::Abbreviations::default(), + abbreviations: Arc::new(read::Abbreviations::default()), name: None, comp_dir: None, low_pc: 0, diff --git a/src/write/unit.rs b/src/write/unit.rs index bf85ff42..2f1fad1b 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -1931,6 +1931,7 @@ mod tests { use crate::LittleEndian; use std::collections::HashMap; use std::mem; + use std::sync::Arc; #[test] #[allow(clippy::cyclomatic_complexity)] @@ -2542,7 +2543,7 @@ mod tests { let unit = read::Unit { header: from_unit, - abbreviations: read::Abbreviations::default(), + abbreviations: Arc::new(read::Abbreviations::default()), name: None, comp_dir: None, low_pc: 0, @@ -3015,7 +3016,7 @@ mod tests { let unit = read::Unit { header: from_unit, - abbreviations: read::Abbreviations::default(), + abbreviations: Arc::new(read::Abbreviations::default()), name: None, comp_dir: None, low_pc: 0,