Skip to content

Commit d7c5a45

Browse files
authored
Merge pull request #689 from workingjubilee/formalize-lru
Use a custom container for Cache's cache
2 parents 154a0ea + c88b038 commit d7c5a45

File tree

4 files changed

+91
-26
lines changed

4 files changed

+91
-26
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ jobs:
256256
with:
257257
submodules: true
258258
- name: Install Rust
259-
run: rustup update 1.73.0 --no-self-update && rustup default 1.73.0
259+
run: rustup update 1.79.0 --no-self-update && rustup default 1.79.0
260260
- run: cargo build
261261

262262
miri:

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ autoexamples = true
1414
autotests = true
1515
edition = "2021"
1616
exclude = ["/ci/"]
17-
rust-version = "1.65.0"
17+
rust-version = "1.79.0"
1818

1919
[workspace]
2020
members = ['crates/cpp_smoke_test', 'crates/as-if-std']

src/symbolize/gimli.rs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ cfg_if::cfg_if! {
5252
}
5353
}
5454

55+
mod lru;
5556
mod stash;
5657

58+
use lru::Lru;
59+
5760
const MAPPINGS_CACHE_SIZE: usize = 4;
5861

5962
struct Mapping {
@@ -263,7 +266,7 @@ struct Cache {
263266
///
264267
/// Note that this is basically an LRU cache and we'll be shifting things
265268
/// around in here as we symbolize addresses.
266-
mappings: Vec<(usize, Mapping)>,
269+
mappings: Lru<(usize, Mapping), MAPPINGS_CACHE_SIZE>,
267270
}
268271

269272
struct Library {
@@ -344,7 +347,7 @@ pub unsafe fn clear_symbol_cache() {
344347
impl Cache {
345348
fn new() -> Cache {
346349
Cache {
347-
mappings: Vec::with_capacity(MAPPINGS_CACHE_SIZE),
350+
mappings: Lru::default(),
348351
libraries: native_libraries(),
349352
}
350353
}
@@ -403,31 +406,18 @@ impl Cache {
403406
}
404407

405408
fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> {
406-
let idx = self.mappings.iter().position(|(idx, _)| *idx == lib);
407-
408-
// Invariant: after this conditional completes without early returning
409-
// from an error, the cache entry for this path is at index 0.
409+
let cache_idx = self.mappings.iter().position(|(lib_id, _)| *lib_id == lib);
410410

411-
if let Some(idx) = idx {
412-
// When the mapping is already in the cache, move it to the front.
413-
if idx != 0 {
414-
let entry = self.mappings.remove(idx);
415-
self.mappings.insert(0, entry);
416-
}
411+
let cache_entry = if let Some(idx) = cache_idx {
412+
self.mappings.move_to_front(idx)
417413
} else {
418-
// When the mapping is not in the cache, create a new mapping,
419-
// insert it into the front of the cache, and evict the oldest cache
420-
// entry if necessary.
421-
let mapping = create_mapping(&self.libraries[lib])?;
422-
423-
if self.mappings.len() == MAPPINGS_CACHE_SIZE {
424-
self.mappings.pop();
425-
}
426-
427-
self.mappings.insert(0, (lib, mapping));
428-
}
414+
// When the mapping is not in the cache, create a new mapping and insert it,
415+
// which will also evict the oldest entry.
416+
create_mapping(&self.libraries[lib])
417+
.and_then(|mapping| self.mappings.push_front((lib, mapping)))
418+
};
429419

430-
let mapping = &mut self.mappings[0].1;
420+
let (_, mapping) = cache_entry?;
431421
let cx: &'a mut Context<'static> = &mut mapping.cx;
432422
let stash: &'a Stash = &mapping.stash;
433423
// don't leak the `'static` lifetime, make sure it's scoped to just

src/symbolize/gimli/lru.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use core::mem::{self, MaybeUninit};
2+
use core::ptr;
3+
4+
/// least-recently-used cache with static size
5+
pub(crate) struct Lru<T, const N: usize> {
6+
// SAFETY: len <= initialized values
7+
len: usize,
8+
arr: [MaybeUninit<T>; N],
9+
}
10+
11+
impl<T, const N: usize> Default for Lru<T, N> {
12+
fn default() -> Self {
13+
Lru {
14+
len: 0,
15+
arr: [const { MaybeUninit::uninit() }; N],
16+
}
17+
}
18+
}
19+
20+
impl<T, const N: usize> Lru<T, N> {
21+
#[inline]
22+
pub fn clear(&mut self) {
23+
let len = self.len;
24+
self.len = 0;
25+
// SAFETY: we can't touch these values again due to setting self.len = 0
26+
unsafe { ptr::drop_in_place(ptr::addr_of_mut!(self.arr[0..len]) as *mut [T]) }
27+
}
28+
29+
#[inline]
30+
pub fn iter(&self) -> impl Iterator<Item = &T> {
31+
self.arr[0..self.len]
32+
.iter()
33+
// SAFETY: we only iterate initialized values due to our len invariant
34+
.map(|init| unsafe { init.assume_init_ref() })
35+
}
36+
37+
#[inline]
38+
pub fn push_front(&mut self, value: T) -> Option<&mut T> {
39+
if N == 0 {
40+
return None;
41+
} else if self.len == N {
42+
self.len = N - 1;
43+
// SAFETY: we maintain len invariant and bail on N == 0
44+
unsafe { ptr::drop_in_place(self.arr.as_mut_ptr().cast::<T>().add(N - 1)) };
45+
};
46+
let len_to_init = self.len + 1;
47+
let mut last = MaybeUninit::new(value);
48+
for elem in self.arr[0..len_to_init].iter_mut() {
49+
// OPT(size): using `mem::swap` allows surprising size regressions
50+
last = mem::replace(elem, last);
51+
}
52+
self.len = len_to_init;
53+
54+
self.arr
55+
.first_mut()
56+
// SAFETY: we just pushed it
57+
.map(|elem| unsafe { elem.assume_init_mut() })
58+
}
59+
60+
#[inline]
61+
pub fn move_to_front(&mut self, idx: usize) -> Option<&mut T> {
62+
let elem = self.arr[0..self.len].get_mut(idx)?;
63+
// SAFETY: we already bailed if the index is bad, so our slicing will be infallible,
64+
// so it is permissible to allow the len invariant to decay, as we always restore it
65+
let mut last = mem::replace(elem, MaybeUninit::uninit());
66+
for elem in self.arr[0..=idx].iter_mut() {
67+
// OPT(size): using `mem::swap` allows surprising size regressions
68+
last = mem::replace(elem, last);
69+
}
70+
self.arr
71+
.first_mut()
72+
// SAFETY: we have restored the len invariant
73+
.map(|elem| unsafe { elem.assume_init_mut() })
74+
}
75+
}

0 commit comments

Comments
 (0)