Skip to content

Commit 2093184

Browse files
committed
Auto merge of rust-lang#2566 - saethlin:gc-cleanup, r=oli-obk
Expand VisitMachineValues to cover more pointers in the interpreter Follow-on to rust-lang/miri#2559 This is making me want to write a proc macro 🤔 r? `@RalfJung`
2 parents dec5152 + d2552d2 commit 2093184

File tree

17 files changed

+464
-127
lines changed

17 files changed

+464
-127
lines changed

src/concurrency/data_race.rs

+12
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,12 @@ pub struct VClockAlloc {
696696
alloc_ranges: RefCell<RangeMap<MemoryCellClocks>>,
697697
}
698698

699+
impl VisitTags for VClockAlloc {
700+
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
701+
// No tags here.
702+
}
703+
}
704+
699705
impl VClockAlloc {
700706
/// Create a new data-race detector for newly allocated memory.
701707
pub fn new_allocation(
@@ -1239,6 +1245,12 @@ pub struct GlobalState {
12391245
pub track_outdated_loads: bool,
12401246
}
12411247

1248+
impl VisitTags for GlobalState {
1249+
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
1250+
// We don't have any tags.
1251+
}
1252+
}
1253+
12421254
impl GlobalState {
12431255
/// Create a new global state, setup with just thread-id=0
12441256
/// advanced to timestamp = 1.

src/concurrency/range_object_map.rs

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ impl<T> RangeObjectMap<T> {
132132
pub fn remove_from_pos(&mut self, pos: Position) {
133133
self.v.remove(pos);
134134
}
135+
136+
pub fn iter(&self) -> impl Iterator<Item = &T> {
137+
self.v.iter().map(|e| &e.data)
138+
}
135139
}
136140

137141
impl<T> Index<Position> for RangeObjectMap<T> {

src/concurrency/thread.rs

+69-31
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ pub enum SchedulingAction {
3232

3333
/// Timeout callbacks can be created by synchronization primitives to tell the
3434
/// scheduler that they should be called once some period of time passes.
35-
type TimeoutCallback<'mir, 'tcx> = Box<
36-
dyn FnOnce(&mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx> + 'tcx,
37-
>;
35+
pub trait MachineCallback<'mir, 'tcx>: VisitTags {
36+
fn call(&self, ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx>;
37+
}
38+
39+
type TimeoutCallback<'mir, 'tcx> = Box<dyn MachineCallback<'mir, 'tcx> + 'tcx>;
3840

3941
/// A thread identifier.
4042
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -181,6 +183,46 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
181183
}
182184
}
183185

186+
impl VisitTags for Thread<'_, '_> {
187+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
188+
let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } =
189+
self;
190+
191+
panic_payload.visit_tags(visit);
192+
last_error.visit_tags(visit);
193+
for frame in stack {
194+
frame.visit_tags(visit)
195+
}
196+
}
197+
}
198+
199+
impl VisitTags for Frame<'_, '_, Provenance, FrameData<'_>> {
200+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
201+
let Frame {
202+
return_place,
203+
locals,
204+
extra,
205+
body: _,
206+
instance: _,
207+
return_to_block: _,
208+
loc: _,
209+
// There are some private fields we cannot access; they contain no tags.
210+
..
211+
} = self;
212+
213+
// Return place.
214+
return_place.visit_tags(visit);
215+
// Locals.
216+
for local in locals.iter() {
217+
if let LocalValue::Live(value) = &local.value {
218+
value.visit_tags(visit);
219+
}
220+
}
221+
222+
extra.visit_tags(visit);
223+
}
224+
}
225+
184226
/// A specific moment in time.
185227
#[derive(Debug)]
186228
pub enum Time {
@@ -253,6 +295,29 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
253295
}
254296
}
255297

298+
impl VisitTags for ThreadManager<'_, '_> {
299+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
300+
let ThreadManager {
301+
threads,
302+
thread_local_alloc_ids,
303+
timeout_callbacks,
304+
active_thread: _,
305+
yield_active_thread: _,
306+
sync: _,
307+
} = self;
308+
309+
for thread in threads {
310+
thread.visit_tags(visit);
311+
}
312+
for ptr in thread_local_alloc_ids.borrow().values() {
313+
ptr.visit_tags(visit);
314+
}
315+
for callback in timeout_callbacks.values() {
316+
callback.callback.visit_tags(visit);
317+
}
318+
}
319+
}
320+
256321
impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
257322
pub(crate) fn init(ecx: &mut MiriInterpCx<'mir, 'tcx>) {
258323
if ecx.tcx.sess.target.os.as_ref() != "windows" {
@@ -625,33 +690,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
625690
}
626691
}
627692

628-
impl VisitMachineValues for ThreadManager<'_, '_> {
629-
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
630-
// FIXME some other fields also contain machine values
631-
let ThreadManager { threads, .. } = self;
632-
633-
for thread in threads {
634-
// FIXME: implement VisitMachineValues for `Thread` and `Frame` instead.
635-
// In particular we need to visit the `last_error` and `catch_unwind` fields.
636-
if let Some(payload) = thread.panic_payload {
637-
visit(&Operand::Immediate(Immediate::Scalar(payload)))
638-
}
639-
for frame in &thread.stack {
640-
// Return place.
641-
if let Place::Ptr(mplace) = *frame.return_place {
642-
visit(&Operand::Indirect(mplace));
643-
}
644-
// Locals.
645-
for local in frame.locals.iter() {
646-
if let LocalValue::Live(value) = &local.value {
647-
visit(value);
648-
}
649-
}
650-
}
651-
}
652-
}
653-
}
654-
655693
// Public interface to thread management.
656694
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
657695
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
@@ -930,7 +968,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
930968
// 2. Make the scheduler the only place that can change the active
931969
// thread.
932970
let old_thread = this.set_active_thread(thread);
933-
callback(this)?;
971+
callback.call(this)?;
934972
this.set_active_thread(old_thread);
935973
Ok(())
936974
}

src/concurrency/weak_memory.rs

+13
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ pub struct StoreBufferAlloc {
108108
store_buffers: RefCell<RangeObjectMap<StoreBuffer>>,
109109
}
110110

111+
impl VisitTags for StoreBufferAlloc {
112+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
113+
let Self { store_buffers } = self;
114+
for val in store_buffers
115+
.borrow()
116+
.iter()
117+
.flat_map(|buf| buf.buffer.iter().map(|element| &element.val))
118+
{
119+
val.visit_tags(visit);
120+
}
121+
}
122+
}
123+
111124
#[derive(Debug, Clone, PartialEq, Eq)]
112125
pub(super) struct StoreBuffer {
113126
// Stores to this location in modification order

src/intptrcast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ pub struct GlobalStateInner {
4444
provenance_mode: ProvenanceMode,
4545
}
4646

47+
impl VisitTags for GlobalStateInner {
48+
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
49+
// Nothing to visit here.
50+
}
51+
}
52+
4753
impl GlobalStateInner {
4854
pub fn new(config: &MiriConfig) -> Self {
4955
GlobalStateInner {

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub use crate::range_map::RangeMap;
112112
pub use crate::stacked_borrows::{
113113
CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks,
114114
};
115-
pub use crate::tag_gc::{EvalContextExt as _, VisitMachineValues};
115+
pub use crate::tag_gc::{EvalContextExt as _, VisitTags};
116116

117117
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
118118
/// set per default, for maximal validation power.

src/machine.rs

+78-8
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
6363
}
6464
}
6565

66+
impl VisitTags for FrameData<'_> {
67+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
68+
let FrameData { catch_unwind, stacked_borrows, timing: _ } = self;
69+
70+
catch_unwind.visit_tags(visit);
71+
stacked_borrows.visit_tags(visit);
72+
}
73+
}
74+
6675
/// Extra memory kinds
6776
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6877
pub enum MiriMemoryKind {
@@ -251,6 +260,16 @@ pub struct AllocExtra {
251260
pub weak_memory: Option<weak_memory::AllocExtra>,
252261
}
253262

263+
impl VisitTags for AllocExtra {
264+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
265+
let AllocExtra { stacked_borrows, data_race, weak_memory } = self;
266+
267+
stacked_borrows.visit_tags(visit);
268+
data_race.visit_tags(visit);
269+
weak_memory.visit_tags(visit);
270+
}
271+
}
272+
254273
/// Precomputed layouts of primitive types
255274
pub struct PrimitiveLayouts<'tcx> {
256275
pub unit: TyAndLayout<'tcx>,
@@ -591,14 +610,65 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
591610
}
592611
}
593612

594-
impl VisitMachineValues for MiriMachine<'_, '_> {
595-
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
596-
// FIXME: visit the missing fields: env vars, weak mem, the MemPlace fields in the machine,
597-
// DirHandler, extern_statics, the Stacked Borrows base pointers; maybe more.
598-
let MiriMachine { threads, tls, .. } = self;
599-
600-
threads.visit_machine_values(visit);
601-
tls.visit_machine_values(visit);
613+
impl VisitTags for MiriMachine<'_, '_> {
614+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
615+
#[rustfmt::skip]
616+
let MiriMachine {
617+
threads,
618+
tls,
619+
env_vars,
620+
argc,
621+
argv,
622+
cmd_line,
623+
extern_statics,
624+
dir_handler,
625+
stacked_borrows,
626+
data_race,
627+
intptrcast,
628+
file_handler,
629+
tcx: _,
630+
isolated_op: _,
631+
validate: _,
632+
enforce_abi: _,
633+
clock: _,
634+
layouts: _,
635+
static_roots: _,
636+
profiler: _,
637+
string_cache: _,
638+
exported_symbols_cache: _,
639+
panic_on_unsupported: _,
640+
backtrace_style: _,
641+
local_crates: _,
642+
rng: _,
643+
tracked_alloc_ids: _,
644+
check_alignment: _,
645+
cmpxchg_weak_failure_rate: _,
646+
mute_stdout_stderr: _,
647+
weak_memory: _,
648+
preemption_rate: _,
649+
report_progress: _,
650+
basic_block_count: _,
651+
#[cfg(unix)]
652+
external_so_lib: _,
653+
gc_interval: _,
654+
since_gc: _,
655+
num_cpus: _,
656+
} = self;
657+
658+
threads.visit_tags(visit);
659+
tls.visit_tags(visit);
660+
env_vars.visit_tags(visit);
661+
dir_handler.visit_tags(visit);
662+
file_handler.visit_tags(visit);
663+
data_race.visit_tags(visit);
664+
stacked_borrows.visit_tags(visit);
665+
intptrcast.visit_tags(visit);
666+
argc.visit_tags(visit);
667+
argv.visit_tags(visit);
668+
cmd_line.visit_tags(visit);
669+
for ptr in extern_statics.values() {
670+
ptr.visit_tags(visit);
671+
}
602672
}
603673
}
604674

src/shims/env.rs

+11
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ pub struct EnvVars<'tcx> {
3636
pub(crate) environ: Option<MPlaceTy<'tcx, Provenance>>,
3737
}
3838

39+
impl VisitTags for EnvVars<'_> {
40+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
41+
let EnvVars { map, environ } = self;
42+
43+
environ.visit_tags(visit);
44+
for ptr in map.values() {
45+
ptr.visit_tags(visit);
46+
}
47+
}
48+
}
49+
3950
impl<'tcx> EnvVars<'tcx> {
4051
pub(crate) fn init<'mir>(
4152
ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,

src/shims/panic.rs

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ pub struct CatchUnwindData<'tcx> {
3535
ret: mir::BasicBlock,
3636
}
3737

38+
impl VisitTags for CatchUnwindData<'_> {
39+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
40+
let CatchUnwindData { catch_fn, data, dest, ret: _ } = self;
41+
catch_fn.visit_tags(visit);
42+
data.visit_tags(visit);
43+
dest.visit_tags(visit);
44+
}
45+
}
46+
3847
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
3948
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4049
/// Handles the special `miri_start_panic` intrinsic, which is called

0 commit comments

Comments
 (0)