mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
re-architect the tag visitor traits
This commit is contained in:
parent
841d1b24ed
commit
e212af2f65
@ -696,6 +696,12 @@ pub struct VClockAlloc {
|
||||
alloc_ranges: RefCell<RangeMap<MemoryCellClocks>>,
|
||||
}
|
||||
|
||||
impl VisitTags for VClockAlloc {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// No tags here.
|
||||
}
|
||||
}
|
||||
|
||||
impl VClockAlloc {
|
||||
/// Create a new data-race detector for newly allocated memory.
|
||||
pub fn new_allocation(
|
||||
@ -1239,6 +1245,12 @@ pub struct GlobalState {
|
||||
pub track_outdated_loads: bool,
|
||||
}
|
||||
|
||||
impl VisitTags for GlobalState {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// We don't have any tags.
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalState {
|
||||
/// Create a new global state, setup with just thread-id=0
|
||||
/// advanced to timestamp = 1.
|
||||
|
@ -32,7 +32,7 @@ pub enum SchedulingAction {
|
||||
|
||||
/// Timeout callbacks can be created by synchronization primitives to tell the
|
||||
/// scheduler that they should be called once some period of time passes.
|
||||
pub trait MachineCallback<'mir, 'tcx>: VisitMachineValues {
|
||||
pub trait MachineCallback<'mir, 'tcx>: VisitTags {
|
||||
fn call(&self, ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx>;
|
||||
}
|
||||
|
||||
@ -183,25 +183,21 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for Thread<'_, '_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for Thread<'_, '_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } =
|
||||
self;
|
||||
|
||||
if let Some(payload) = panic_payload {
|
||||
visit.visit(*payload);
|
||||
}
|
||||
if let Some(error) = last_error {
|
||||
visit.visit(**error);
|
||||
}
|
||||
panic_payload.visit_tags(visit);
|
||||
last_error.visit_tags(visit);
|
||||
for frame in stack {
|
||||
frame.visit_machine_values(visit)
|
||||
frame.visit_tags(visit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for Frame<'_, '_, Provenance, FrameData<'_>> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Frame {
|
||||
return_place,
|
||||
locals,
|
||||
@ -210,21 +206,20 @@ impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> {
|
||||
instance: _,
|
||||
return_to_block: _,
|
||||
loc: _,
|
||||
// There are some private fields we cannot access; they contain no tags.
|
||||
..
|
||||
} = self;
|
||||
|
||||
// Return place.
|
||||
if let Place::Ptr(mplace) = **return_place {
|
||||
visit.visit(mplace);
|
||||
}
|
||||
return_place.visit_tags(visit);
|
||||
// Locals.
|
||||
for local in locals.iter() {
|
||||
if let LocalValue::Live(value) = &local.value {
|
||||
visit.visit(value);
|
||||
value.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
extra.visit_machine_values(visit);
|
||||
extra.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,8 +295,8 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for ThreadManager<'_, '_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for ThreadManager<'_, '_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let ThreadManager {
|
||||
threads,
|
||||
thread_local_alloc_ids,
|
||||
@ -312,13 +307,13 @@ impl VisitMachineValues for ThreadManager<'_, '_> {
|
||||
} = self;
|
||||
|
||||
for thread in threads {
|
||||
thread.visit_machine_values(visit);
|
||||
thread.visit_tags(visit);
|
||||
}
|
||||
for ptr in thread_local_alloc_ids.borrow().values().copied() {
|
||||
visit.visit(ptr);
|
||||
for ptr in thread_local_alloc_ids.borrow().values() {
|
||||
ptr.visit_tags(visit);
|
||||
}
|
||||
for callback in timeout_callbacks.values() {
|
||||
callback.callback.visit_machine_values(visit);
|
||||
callback.callback.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,15 +108,15 @@ pub struct StoreBufferAlloc {
|
||||
store_buffers: RefCell<RangeObjectMap<StoreBuffer>>,
|
||||
}
|
||||
|
||||
impl VisitMachineValues for StoreBufferAlloc {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
for val in self
|
||||
.store_buffers
|
||||
impl VisitTags for StoreBufferAlloc {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Self { store_buffers } = self;
|
||||
for val in store_buffers
|
||||
.borrow()
|
||||
.iter()
|
||||
.flat_map(|buf| buf.buffer.iter().map(|element| &element.val))
|
||||
{
|
||||
visit.visit(val);
|
||||
val.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,12 @@ pub struct GlobalStateInner {
|
||||
provenance_mode: ProvenanceMode,
|
||||
}
|
||||
|
||||
impl VisitTags for GlobalStateInner {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// Nothing to visit here.
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalStateInner {
|
||||
pub fn new(config: &MiriConfig) -> Self {
|
||||
GlobalStateInner {
|
||||
|
@ -112,7 +112,7 @@ pub use crate::range_map::RangeMap;
|
||||
pub use crate::stacked_borrows::{
|
||||
CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks,
|
||||
};
|
||||
pub use crate::tag_gc::{EvalContextExt as _, ProvenanceVisitor, VisitMachineValues};
|
||||
pub use crate::tag_gc::{EvalContextExt as _, VisitTags};
|
||||
|
||||
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
|
||||
/// set per default, for maximal validation power.
|
||||
|
@ -63,13 +63,12 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for FrameData<'_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
let FrameData { catch_unwind, stacked_borrows: _, timing: _ } = self;
|
||||
impl VisitTags for FrameData<'_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let FrameData { catch_unwind, stacked_borrows, timing: _ } = self;
|
||||
|
||||
if let Some(catch_unwind) = catch_unwind {
|
||||
catch_unwind.visit_machine_values(visit);
|
||||
}
|
||||
catch_unwind.visit_tags(visit);
|
||||
stacked_borrows.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,17 +260,13 @@ pub struct AllocExtra {
|
||||
pub weak_memory: Option<weak_memory::AllocExtra>,
|
||||
}
|
||||
|
||||
impl VisitMachineValues for AllocExtra {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
let AllocExtra { stacked_borrows, data_race: _, weak_memory } = self;
|
||||
impl VisitTags for AllocExtra {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let AllocExtra { stacked_borrows, data_race, weak_memory } = self;
|
||||
|
||||
if let Some(stacked_borrows) = stacked_borrows {
|
||||
stacked_borrows.borrow().visit_machine_values(visit);
|
||||
}
|
||||
|
||||
if let Some(weak_memory) = weak_memory {
|
||||
weak_memory.visit_machine_values(visit);
|
||||
}
|
||||
stacked_borrows.visit_tags(visit);
|
||||
data_race.visit_tags(visit);
|
||||
weak_memory.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -615,8 +610,9 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for MiriMachine<'_, '_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for MiriMachine<'_, '_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
#[rustfmt::skip]
|
||||
let MiriMachine {
|
||||
threads,
|
||||
tls,
|
||||
@ -626,25 +622,52 @@ impl VisitMachineValues for MiriMachine<'_, '_> {
|
||||
cmd_line,
|
||||
extern_statics,
|
||||
dir_handler,
|
||||
..
|
||||
stacked_borrows,
|
||||
data_race,
|
||||
intptrcast,
|
||||
file_handler,
|
||||
tcx: _,
|
||||
isolated_op: _,
|
||||
validate: _,
|
||||
enforce_abi: _,
|
||||
clock: _,
|
||||
layouts: _,
|
||||
static_roots: _,
|
||||
profiler: _,
|
||||
string_cache: _,
|
||||
exported_symbols_cache: _,
|
||||
panic_on_unsupported: _,
|
||||
backtrace_style: _,
|
||||
local_crates: _,
|
||||
rng: _,
|
||||
tracked_alloc_ids: _,
|
||||
check_alignment: _,
|
||||
cmpxchg_weak_failure_rate: _,
|
||||
mute_stdout_stderr: _,
|
||||
weak_memory: _,
|
||||
preemption_rate: _,
|
||||
report_progress: _,
|
||||
basic_block_count: _,
|
||||
#[cfg(unix)]
|
||||
external_so_lib: _,
|
||||
gc_interval: _,
|
||||
since_gc: _,
|
||||
num_cpus: _,
|
||||
} = self;
|
||||
|
||||
threads.visit_machine_values(visit);
|
||||
tls.visit_machine_values(visit);
|
||||
env_vars.visit_machine_values(visit);
|
||||
dir_handler.visit_machine_values(visit);
|
||||
|
||||
if let Some(argc) = argc {
|
||||
visit.visit(argc);
|
||||
}
|
||||
if let Some(argv) = argv {
|
||||
visit.visit(argv);
|
||||
}
|
||||
if let Some(cmd_line) = cmd_line {
|
||||
visit.visit(cmd_line);
|
||||
}
|
||||
for ptr in extern_statics.values().copied() {
|
||||
visit.visit(ptr);
|
||||
threads.visit_tags(visit);
|
||||
tls.visit_tags(visit);
|
||||
env_vars.visit_tags(visit);
|
||||
dir_handler.visit_tags(visit);
|
||||
file_handler.visit_tags(visit);
|
||||
data_race.visit_tags(visit);
|
||||
stacked_borrows.visit_tags(visit);
|
||||
intptrcast.visit_tags(visit);
|
||||
argc.visit_tags(visit);
|
||||
argv.visit_tags(visit);
|
||||
cmd_line.visit_tags(visit);
|
||||
for ptr in extern_statics.values() {
|
||||
ptr.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,15 +36,13 @@ pub struct EnvVars<'tcx> {
|
||||
pub(crate) environ: Option<MPlaceTy<'tcx, Provenance>>,
|
||||
}
|
||||
|
||||
impl VisitMachineValues for EnvVars<'_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for EnvVars<'_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let EnvVars { map, environ } = self;
|
||||
|
||||
environ.visit_tags(visit);
|
||||
for ptr in map.values() {
|
||||
visit.visit(*ptr);
|
||||
}
|
||||
if let Some(env) = environ {
|
||||
visit.visit(**env);
|
||||
ptr.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,12 @@ pub struct CatchUnwindData<'tcx> {
|
||||
ret: mir::BasicBlock,
|
||||
}
|
||||
|
||||
impl VisitMachineValues for CatchUnwindData<'_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
let CatchUnwindData { catch_fn, data, dest: _, ret: _ } = self;
|
||||
visit.visit(catch_fn);
|
||||
visit.visit(data);
|
||||
impl VisitTags for CatchUnwindData<'_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let CatchUnwindData { catch_fn, data, dest, ret: _ } = self;
|
||||
catch_fn.visit_tags(visit);
|
||||
data.visit_tags(visit);
|
||||
dest.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
this.register_timeout_callback(
|
||||
active_thread,
|
||||
Time::Monotonic(timeout_time),
|
||||
Box::new(Callback { active_thread }),
|
||||
Box::new(UnblockCallback { thread_to_unblock: active_thread }),
|
||||
);
|
||||
|
||||
Ok(0)
|
||||
@ -242,24 +242,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
this.register_timeout_callback(
|
||||
active_thread,
|
||||
Time::Monotonic(timeout_time),
|
||||
Box::new(Callback { active_thread }),
|
||||
Box::new(UnblockCallback { thread_to_unblock: active_thread }),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct Callback {
|
||||
active_thread: ThreadId,
|
||||
struct UnblockCallback {
|
||||
thread_to_unblock: ThreadId,
|
||||
}
|
||||
|
||||
impl VisitMachineValues for Callback {
|
||||
fn visit_machine_values(&self, _visit: &mut ProvenanceVisitor) {}
|
||||
impl VisitTags for UnblockCallback {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback {
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for UnblockCallback {
|
||||
fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
ecx.unblock_thread(self.active_thread);
|
||||
ecx.unblock_thread(self.thread_to_unblock);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -235,15 +235,15 @@ impl<'tcx> TlsData<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for TlsData<'_> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for TlsData<'_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let TlsData { keys, macos_thread_dtors, next_key: _, dtors_running: _ } = self;
|
||||
|
||||
for scalar in keys.values().flat_map(|v| v.data.values()) {
|
||||
visit.visit(scalar);
|
||||
scalar.visit_tags(visit);
|
||||
}
|
||||
for (_, scalar) in macos_thread_dtors.values() {
|
||||
visit.visit(scalar);
|
||||
scalar.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,6 +256,12 @@ pub struct FileHandler {
|
||||
handles: BTreeMap<i32, Box<dyn FileDescriptor>>,
|
||||
}
|
||||
|
||||
impl VisitTags for FileHandler {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// All our FileDescriptor do not have any tags.
|
||||
}
|
||||
}
|
||||
|
||||
impl FileHandler {
|
||||
pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler {
|
||||
let mut handles: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new();
|
||||
@ -462,12 +468,12 @@ impl Default for DirHandler {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for DirHandler {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for DirHandler {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let DirHandler { streams, next_id: _ } = self;
|
||||
|
||||
for dir in streams.values() {
|
||||
visit.visit(dir.entry);
|
||||
dir.entry.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +189,31 @@ pub fn futex<'tcx>(
|
||||
// Register a timeout callback if a timeout was specified.
|
||||
// This callback will override the return value when the timeout triggers.
|
||||
if let Some(timeout_time) = timeout_time {
|
||||
struct Callback<'tcx> {
|
||||
thread: ThreadId,
|
||||
addr_usize: u64,
|
||||
dest: PlaceTy<'tcx, Provenance>,
|
||||
}
|
||||
|
||||
impl<'tcx> VisitTags for Callback<'tcx> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Callback { thread: _, addr_usize: _, dest } = self;
|
||||
dest.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
|
||||
fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
this.unblock_thread(self.thread);
|
||||
this.futex_remove_waiter(self.addr_usize, self.thread);
|
||||
let etimedout = this.eval_libc("ETIMEDOUT")?;
|
||||
this.set_last_error(etimedout)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), &self.dest)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let dest = dest.clone();
|
||||
this.register_timeout_callback(
|
||||
thread,
|
||||
@ -252,30 +277,3 @@ pub fn futex<'tcx>(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Callback<'tcx> {
|
||||
thread: ThreadId,
|
||||
addr_usize: u64,
|
||||
dest: PlaceTy<'tcx, Provenance>,
|
||||
}
|
||||
|
||||
impl<'tcx> VisitMachineValues for Callback<'tcx> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
let Callback { thread: _, addr_usize: _, dest } = self;
|
||||
if let Place::Ptr(place) = **dest {
|
||||
visit.visit(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
|
||||
fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
this.unblock_thread(self.thread);
|
||||
this.futex_remove_waiter(self.addr_usize, self.thread);
|
||||
let etimedout = this.eval_libc("ETIMEDOUT")?;
|
||||
this.set_last_error(etimedout)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), &self.dest)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -851,6 +851,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
// We return success for now and override it in the timeout callback.
|
||||
this.write_scalar(Scalar::from_i32(0), dest)?;
|
||||
|
||||
struct Callback<'tcx> {
|
||||
active_thread: ThreadId,
|
||||
mutex_id: MutexId,
|
||||
id: CondvarId,
|
||||
dest: PlaceTy<'tcx, Provenance>,
|
||||
}
|
||||
|
||||
impl<'tcx> VisitTags for Callback<'tcx> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Callback { active_thread: _, mutex_id: _, id: _, dest } = self;
|
||||
dest.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
|
||||
fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
// We are not waiting for the condvar any more, wait for the
|
||||
// mutex instead.
|
||||
reacquire_cond_mutex(ecx, self.active_thread, self.mutex_id)?;
|
||||
|
||||
// Remove the thread from the conditional variable.
|
||||
ecx.condvar_remove_waiter(self.id, self.active_thread);
|
||||
|
||||
// Set the return value: we timed out.
|
||||
let etimedout = ecx.eval_libc("ETIMEDOUT")?;
|
||||
ecx.write_scalar(etimedout, &self.dest)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Register the timeout callback.
|
||||
let dest = dest.clone();
|
||||
this.register_timeout_callback(
|
||||
@ -885,39 +916,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct Callback<'tcx> {
|
||||
active_thread: ThreadId,
|
||||
mutex_id: MutexId,
|
||||
id: CondvarId,
|
||||
dest: PlaceTy<'tcx, Provenance>,
|
||||
}
|
||||
|
||||
impl<'tcx> VisitMachineValues for Callback<'tcx> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
let Callback { active_thread: _, mutex_id: _, id: _, dest } = self;
|
||||
if let Place::Ptr(place) = **dest {
|
||||
visit.visit(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
|
||||
fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
// We are not waiting for the condvar any more, wait for the
|
||||
// mutex instead.
|
||||
reacquire_cond_mutex(ecx, self.active_thread, self.mutex_id)?;
|
||||
|
||||
// Remove the thread from the conditional variable.
|
||||
ecx.condvar_remove_waiter(self.id, self.active_thread);
|
||||
|
||||
// Set the return value: we timed out.
|
||||
let etimedout = ecx.eval_libc("ETIMEDOUT")?;
|
||||
ecx.write_scalar(etimedout, &self.dest)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> {
|
||||
let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None);
|
||||
let ty = tcx.bound_type_of(def_id).subst(*tcx, &[param.into()]);
|
||||
|
@ -71,6 +71,12 @@ pub struct FrameExtra {
|
||||
protected_tags: SmallVec<[SbTag; 2]>,
|
||||
}
|
||||
|
||||
impl VisitTags for FrameExtra {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// `protected_tags` are fine to GC.
|
||||
}
|
||||
}
|
||||
|
||||
/// Extra per-allocation state.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Stacks {
|
||||
@ -109,6 +115,13 @@ pub struct GlobalStateInner {
|
||||
retag_fields: bool,
|
||||
}
|
||||
|
||||
impl VisitTags for GlobalStateInner {
|
||||
fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
|
||||
// The only candidate is base_ptr_tags, and that does not need visiting since we don't ever
|
||||
// GC the bottommost tag.
|
||||
}
|
||||
}
|
||||
|
||||
/// We need interior mutable access to the global state.
|
||||
pub type GlobalState = RefCell<GlobalStateInner>;
|
||||
|
||||
@ -513,10 +526,10 @@ impl Stacks {
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for Stacks {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for Stacks {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
for tag in self.exposed_tags.iter().copied() {
|
||||
visit.visit(tag);
|
||||
visit(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,123 +2,155 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub trait VisitMachineValues {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor);
|
||||
pub trait VisitTags {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag));
|
||||
}
|
||||
|
||||
pub trait MachineValue {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>);
|
||||
}
|
||||
|
||||
pub struct ProvenanceVisitor {
|
||||
tags: FxHashSet<SbTag>,
|
||||
}
|
||||
|
||||
impl ProvenanceVisitor {
|
||||
pub fn visit<V>(&mut self, v: V)
|
||||
where
|
||||
V: MachineValue,
|
||||
{
|
||||
v.visit_provenance(&mut self.tags);
|
||||
impl<T: VisitTags> VisitTags for Option<T> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
if let Some(x) = self {
|
||||
x.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MachineValue> MachineValue for &T {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
(**self).visit_provenance(tags);
|
||||
impl<T: VisitTags> VisitTags for std::cell::RefCell<T> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
self.borrow().visit_tags(visit)
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for Operand<Provenance> {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
impl VisitTags for SbTag {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
visit(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Provenance {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
if let Provenance::Concrete { sb, .. } = self {
|
||||
visit(*sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Pointer<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
prov.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Pointer<Option<Provenance>> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
prov.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Scalar<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
match self {
|
||||
Operand::Immediate(Immediate::Scalar(s)) => {
|
||||
s.visit_provenance(tags);
|
||||
Scalar::Ptr(ptr, _) => ptr.visit_tags(visit),
|
||||
Scalar::Int(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Immediate<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
match self {
|
||||
Immediate::Scalar(s) => {
|
||||
s.visit_tags(visit);
|
||||
}
|
||||
Operand::Immediate(Immediate::ScalarPair(s1, s2)) => {
|
||||
s1.visit_provenance(tags);
|
||||
s2.visit_provenance(tags);
|
||||
Immediate::ScalarPair(s1, s2) => {
|
||||
s1.visit_tags(visit);
|
||||
s2.visit_tags(visit);
|
||||
}
|
||||
Immediate::Uninit => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for MemPlaceMeta<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
match self {
|
||||
MemPlaceMeta::Meta(m) => m.visit_tags(visit),
|
||||
MemPlaceMeta::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for MemPlace<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let MemPlace { ptr, meta } = self;
|
||||
ptr.visit_tags(visit);
|
||||
meta.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for MPlaceTy<'_, Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
(**self).visit_tags(visit)
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Place<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
match self {
|
||||
Place::Ptr(p) => p.visit_tags(visit),
|
||||
Place::Local { .. } => {
|
||||
// Will be visited as part of the stack frame.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for PlaceTy<'_, Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
(**self).visit_tags(visit)
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for Operand<Provenance> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
match self {
|
||||
Operand::Immediate(imm) => {
|
||||
imm.visit_tags(visit);
|
||||
}
|
||||
Operand::Immediate(Immediate::Uninit) => {}
|
||||
Operand::Indirect(p) => {
|
||||
p.visit_provenance(tags);
|
||||
p.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for Scalar<Provenance> {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
if let Scalar::Ptr(ptr, _) = self {
|
||||
if let Provenance::Concrete { sb, .. } = ptr.provenance {
|
||||
tags.insert(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for MemPlace<Provenance> {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
if let Some(Provenance::Concrete { sb, .. }) = self.ptr.provenance {
|
||||
tags.insert(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for SbTag {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
tags.insert(*self);
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for Pointer<Provenance> {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
if let Provenance::Concrete { sb, .. } = prov {
|
||||
tags.insert(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineValue for Pointer<Option<Provenance>> {
|
||||
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
if let Some(Provenance::Concrete { sb, .. }) = prov {
|
||||
tags.insert(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMachineValues for Allocation<Provenance, AllocExtra> {
|
||||
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
|
||||
impl VisitTags for Allocation<Provenance, AllocExtra> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
for (_size, prov) in self.provenance().iter() {
|
||||
if let Provenance::Concrete { sb, .. } = prov {
|
||||
visit.visit(*sb);
|
||||
}
|
||||
prov.visit_tags(visit);
|
||||
}
|
||||
|
||||
self.extra.visit_machine_values(visit);
|
||||
self.extra.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitTags for crate::MiriInterpCx<'_, '_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
// Memory.
|
||||
self.memory.alloc_map().iter(|it| {
|
||||
for (_id, (_kind, alloc)) in it {
|
||||
alloc.visit_tags(visit);
|
||||
}
|
||||
});
|
||||
|
||||
// And all the other machine values.
|
||||
self.machine.visit_tags(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
/// GC helper to visit everything that can store provenance. The `ProvenanceVisitor` knows how
|
||||
/// to extract provenance from the interpreter data types.
|
||||
fn visit_all_machine_values(&self, acc: &mut ProvenanceVisitor) {
|
||||
let this = self.eval_context_ref();
|
||||
|
||||
// Memory.
|
||||
this.memory.alloc_map().iter(|it| {
|
||||
for (_id, (_kind, alloc)) in it {
|
||||
alloc.visit_machine_values(acc);
|
||||
}
|
||||
});
|
||||
|
||||
// And all the other machine values.
|
||||
this.machine.visit_machine_values(acc);
|
||||
}
|
||||
|
||||
fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
// No reason to do anything at all if stacked borrows is off.
|
||||
@ -126,9 +158,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut visitor = ProvenanceVisitor { tags: FxHashSet::default() };
|
||||
this.visit_all_machine_values(&mut visitor);
|
||||
self.remove_unreachable_tags(visitor.tags);
|
||||
let mut tags = FxHashSet::default();
|
||||
this.visit_tags(&mut |tag| {
|
||||
tags.insert(tag);
|
||||
});
|
||||
self.remove_unreachable_tags(tags);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user