Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0d0a417

Browse files
committed
Expand Miri's BorTag GC to a Provenance GC
1 parent 82b804c commit 0d0a417

File tree

27 files changed

+395
-296
lines changed

27 files changed

+395
-296
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
107107
FxIndexMap::contains_key(self, k)
108108
}
109109

110+
#[inline(always)]
111+
fn contains_key_ref<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> bool
112+
where
113+
K: Borrow<Q>,
114+
{
115+
FxIndexMap::contains_key(self, k)
116+
}
117+
110118
#[inline(always)]
111119
fn insert(&mut self, k: K, v: V) -> Option<V> {
112120
FxIndexMap::insert(self, k, v)

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ pub trait AllocMap<K: Hash + Eq, V> {
4949
where
5050
K: Borrow<Q>;
5151

52+
/// Callers should prefer [`AllocMap::contains_key`] when it is possible to call because it may
53+
/// be more efficient. This function exists for callers that only have a shared reference
54+
/// (which might make it slightly less efficient than `contains_key`, e.g. if
55+
/// the data is stored inside a `RefCell`).
56+
fn contains_key_ref<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> bool
57+
where
58+
K: Borrow<Q>;
59+
5260
/// Inserts a new entry into the map.
5361
fn insert(&mut self, k: K, v: V) -> Option<V>;
5462

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
692692
Ok((&mut alloc.extra, machine))
693693
}
694694

695+
/// Check whether an allocation is live. This is faster than calling
696+
/// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is
697+
/// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics.
698+
pub fn is_alloc_live(&self, id: AllocId) -> bool {
699+
self.tcx.try_get_global_alloc(id).is_some()
700+
|| self.memory.alloc_map.contains_key_ref(&id)
701+
|| self.memory.extra_fn_ptr_map.contains_key(&id)
702+
}
703+
695704
/// Obtain the size and alignment of an allocation, even if that allocation has
696705
/// been deallocated.
697706
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {

compiler/rustc_middle/src/mir/interpret/mod.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -525,13 +525,6 @@ impl<'tcx> TyCtxt<'tcx> {
525525
self.alloc_map.lock().reserve()
526526
}
527527

528-
/// Miri's provenance GC needs to see all live allocations. The interpreter manages most
529-
/// allocations but some are managed by [`TyCtxt`] and without this method the interpreter
530-
/// doesn't know their [`AllocId`]s are in use.
531-
pub fn iter_allocs<F: FnMut(AllocId)>(self, func: F) {
532-
self.alloc_map.lock().alloc_map.keys().copied().for_each(func)
533-
}
534-
535528
/// Reserves a new ID *if* this allocation has not been dedup-reserved before.
536529
/// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
537530
/// don't want to dedup IDs for "real" memory!

src/tools/miri/src/borrow_tracker/mod.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ pub struct FrameState {
7575
protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
7676
}
7777

78-
impl VisitTags for FrameState {
79-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
78+
impl VisitProvenance for FrameState {
79+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
8080
// `protected_tags` are already recorded by `GlobalStateInner`.
8181
}
8282
}
@@ -110,10 +110,10 @@ pub struct GlobalStateInner {
110110
unique_is_unique: bool,
111111
}
112112

113-
impl VisitTags for GlobalStateInner {
114-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
113+
impl VisitProvenance for GlobalStateInner {
114+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
115115
for &tag in self.protected_tags.keys() {
116-
visit(tag);
116+
visit(None, Some(tag));
117117
}
118118
// The only other candidate is base_ptr_tags, and that does not need visiting since we don't ever
119119
// GC the bottommost/root tag.
@@ -236,6 +236,10 @@ impl GlobalStateInner {
236236
tag
237237
})
238238
}
239+
240+
pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) {
241+
self.base_ptr_tags.retain(|id, _| allocs.is_live(*id));
242+
}
239243
}
240244

241245
/// Which borrow tracking method to use
@@ -503,11 +507,11 @@ impl AllocState {
503507
}
504508
}
505509

506-
impl VisitTags for AllocState {
507-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
510+
impl VisitProvenance for AllocState {
511+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
508512
match self {
509-
AllocState::StackedBorrows(sb) => sb.visit_tags(visit),
510-
AllocState::TreeBorrows(tb) => tb.visit_tags(visit),
513+
AllocState::StackedBorrows(sb) => sb.visit_provenance(visit),
514+
AllocState::TreeBorrows(tb) => tb.visit_provenance(visit),
511515
}
512516
}
513517
}

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,10 @@ impl Stacks {
462462
}
463463
}
464464

465-
impl VisitTags for Stacks {
466-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
465+
impl VisitProvenance for Stacks {
466+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
467467
for tag in self.exposed_tags.iter().copied() {
468-
visit(tag);
468+
visit(None, Some(tag));
469469
}
470470
}
471471
}

src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,11 +742,11 @@ impl Tree {
742742
}
743743
}
744744

745-
impl VisitTags for Tree {
746-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
745+
impl VisitProvenance for Tree {
746+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
747747
// To ensure that the root never gets removed, we visit it
748748
// (the `root` node of `Tree` is not an `Option<_>`)
749-
visit(self.nodes.get(self.root).unwrap().tag)
749+
visit(None, Some(self.nodes.get(self.root).unwrap().tag))
750750
}
751751
}
752752

src/tools/miri/src/concurrency/data_race.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -790,9 +790,9 @@ pub struct VClockAlloc {
790790
alloc_ranges: RefCell<RangeMap<MemoryCellClocks>>,
791791
}
792792

793-
impl VisitTags for VClockAlloc {
794-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
795-
// No tags here.
793+
impl VisitProvenance for VClockAlloc {
794+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
795+
// No tags or allocIds here.
796796
}
797797
}
798798

@@ -1404,8 +1404,8 @@ pub struct GlobalState {
14041404
pub track_outdated_loads: bool,
14051405
}
14061406

1407-
impl VisitTags for GlobalState {
1408-
fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
1407+
impl VisitProvenance for GlobalState {
1408+
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
14091409
// We don't have any tags.
14101410
}
14111411
}

src/tools/miri/src/concurrency/init_once.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ pub(super) struct InitOnce<'mir, 'tcx> {
4545
data_race: VClock,
4646
}
4747

48-
impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> {
49-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
48+
impl<'mir, 'tcx> VisitProvenance for InitOnce<'mir, 'tcx> {
49+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
5050
for waiter in self.waiters.iter() {
51-
waiter.callback.visit_tags(visit);
51+
waiter.callback.visit_provenance(visit);
5252
}
5353
}
5454
}

src/tools/miri/src/concurrency/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ pub(crate) struct SynchronizationState<'mir, 'tcx> {
181181
pub(super) init_onces: IndexVec<InitOnceId, InitOnce<'mir, 'tcx>>,
182182
}
183183

184-
impl<'mir, 'tcx> VisitTags for SynchronizationState<'mir, 'tcx> {
185-
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
184+
impl<'mir, 'tcx> VisitProvenance for SynchronizationState<'mir, 'tcx> {
185+
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
186186
for init_once in self.init_onces.iter() {
187-
init_once.visit_tags(visit);
187+
init_once.visit_provenance(visit);
188188
}
189189
}
190190
}

0 commit comments

Comments
 (0)