Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions src/symbolize/gimli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,12 +414,19 @@ impl Cache {
.next()
}

fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> {
fn mapping_for_lib<'a>(
&'a mut self,
lib: usize,
) -> Option<(&'a mut Context<'a>, &'a Stash, Option<(usize, Mapping)>)> {
let mut evicted = None;
let cache_idx = self.mappings.iter().position(|(lib_id, _)| *lib_id == lib);

let cache_entry = if let Some(idx) = cache_idx {
self.mappings.move_to_front(idx)
} else {
if self.mappings.is_full() {
evicted = self.mappings.pop_back();
}
// When the mapping is not in the cache, create a new mapping and insert it,
// which will also evict the oldest entry.
create_mapping(&self.libraries[lib])
Expand All @@ -434,6 +441,7 @@ impl Cache {
Some((
unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) },
stash,
evicted,
))
}
}
Expand All @@ -456,10 +464,26 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
None => return,
};

// If the cache needs to evict an entry to add a new one, we store
// the evicted entry so we can restore it in case of recursion.
struct CacheGuard<'a>(&'a mut Cache, Option<(usize, Mapping)>);
impl Drop for CacheGuard<'_> {
fn drop(&mut self) {
if let Some(entry) = self.1.take() {
self.0.mappings.push_back(entry);
}
}
}
let mut guard = CacheGuard(cache, None);
let cache = &mut guard.0;

// Finally, get a cached mapping or create a new mapping for this file, and
// evaluate the DWARF info to find the file/line/name for this address.
let (cx, stash) = match cache.mapping_for_lib(lib) {
Some((cx, stash)) => (cx, stash),
Some((cx, stash, evicted)) => {
guard.1 = evicted;
(cx, stash)
}
None => return,
};
let mut any_frames = false;
Expand Down
35 changes: 35 additions & 0 deletions src/symbolize/gimli/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,41 @@ impl<T, const N: usize> Lru<T, N> {
.map(|init| unsafe { init.assume_init_ref() })
}

#[inline]
pub fn is_full(&self) -> bool {
self.len == N
}

#[inline]
pub fn pop_back(&mut self) -> Option<T> {
if self.len == 0 {
None
} else {
self.len -= 1;
// SAFETY: we maintain len invariant and bail if len was equal to 0
Some(unsafe { mem::transmute_copy(&self.arr[self.len]) })
}
}

#[inline]
pub fn push_back(&mut self, value: T) {
if N == 0 {
return;
} else if self.len == N {
self.len = N - 1;
// SAFETY: we bail on N == 0 but the first entry will be invalid
// until the loop below rotates the array.
unsafe { ptr::drop_in_place(self.arr.as_mut_ptr().cast::<T>()) };
}
let len_to_init = self.len + 1;
let mut last = MaybeUninit::new(value);
for elem in self.arr[0..len_to_init].iter_mut().rev() {
// OPT(size): using `mem::swap` allows surprising size regressions
last = mem::replace(elem, last);
}
self.len = len_to_init;
}

#[inline]
pub fn push_front(&mut self, value: T) -> Option<&mut T> {
if N == 0 {
Expand Down
Loading