Skip to content

Commit

Permalink
read: cache abbreviations at offset 0
Browse files Browse the repository at this point in the history
This optimises for the case where there is a single set of
abbreviations that is used for all units.
  • Loading branch information
philipc committed Sep 16, 2022
1 parent f1bf29d commit 200fa84
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 16 deletions.
42 changes: 41 additions & 1 deletion 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
Expand Down Expand Up @@ -100,6 +102,44 @@ impl<R> From<R> for DebugAbbrev<R> {
}
}

/// 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<Option<Arc<Abbreviations>>>,
}

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<R: Reader>(
&self,
unit: &UnitHeader<R>,
debug_abbrev: &DebugAbbrev<R>,
) -> Result<Arc<Abbreviations>> {
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
Expand Down
25 changes: 15 additions & 10 deletions src/read/dwarf.rs
Expand Up @@ -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,
};
Expand Down Expand Up @@ -59,6 +59,9 @@ pub struct Dwarf<R> {

/// The DWARF sections for a supplementary object file.
pub sup: Option<Arc<Dwarf<R>>>,

/// A cache of previously parsed abbreviations for units in this file.
pub abbreviations_cache: AbbreviationsCache,
}

impl<T> Dwarf<T> {
Expand Down Expand Up @@ -96,6 +99,7 @@ impl<T> Dwarf<T> {
ranges: RangeLists::new(debug_ranges, debug_rnglists),
file_type: DwarfFileType::Main,
sup: None,
abbreviations_cache: AbbreviationsCache::new(),
})
}

Expand Down Expand Up @@ -157,6 +161,7 @@ impl<T> Dwarf<T> {
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(),
}
}

Expand Down Expand Up @@ -192,10 +197,9 @@ impl<R: Reader> Dwarf<R> {
}

/// Parse the abbreviations for a compilation unit.
// TODO: provide caching of abbreviations
#[inline]
pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Abbreviations> {
unit.abbreviations(&self.debug_abbrev)
pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Arc<Abbreviations>> {
self.abbreviations_cache.get(unit, &self.debug_abbrev)
}

/// Return the string offset at the given index.
Expand Down Expand Up @@ -783,6 +787,7 @@ impl<R: Reader> DwarfPackage<R> {
ranges: RangeLists::new(debug_ranges, debug_rnglists),
file_type: DwarfFileType::Dwo,
sup: None,
abbreviations_cache: AbbreviationsCache::new(),
})
}
}
Expand All @@ -799,7 +804,7 @@ where
pub header: UnitHeader<R, Offset>,

/// The parsed abbreviations for the unit.
pub abbreviations: Abbreviations,
pub abbreviations: Arc<Abbreviations>,

/// The `DW_AT_name` attribute of the unit.
pub name: Option<R>,
Expand Down Expand Up @@ -833,7 +838,7 @@ impl<R: Reader> Unit<R> {
/// Construct a new `Unit` from the given unit header.
#[inline]
pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> {
let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?;
let abbreviations = dwarf.abbreviations(&header)?;
let mut unit = Unit {
abbreviations,
name: None,
Expand Down
3 changes: 2 additions & 1 deletion src/write/loc.rs
Expand Up @@ -436,6 +436,7 @@ mod tests {
};
use crate::LittleEndian;
use std::collections::HashMap;
use std::sync::Arc;

#[test]
fn test_loc_list() {
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/write/op.rs
Expand Up @@ -1071,6 +1071,7 @@ mod tests {
};
use crate::LittleEndian;
use std::collections::HashMap;
use std::sync::Arc;

#[test]
fn test_operation() {
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/write/range.rs
Expand Up @@ -315,6 +315,7 @@ mod tests {
};
use crate::LittleEndian;
use std::collections::HashMap;
use std::sync::Arc;

#[test]
fn test_range() {
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/write/unit.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 200fa84

Please sign in to comment.