Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stacked Borrow: Barriers #553

Merged
merged 14 commits into from
Nov 30, 2018
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2018-11-26
nightly-2018-11-30
42 changes: 33 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl<'tcx> Evaluator<'tcx> {
env_vars: HashMap::default(),
tls: TlsData::default(),
validate,
stacked_borrows: stacked_borrows::State::new(),
stacked_borrows: stacked_borrows::State::default(),
}
}
}
Expand All @@ -301,6 +301,8 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc
impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
type MemoryKinds = MiriMemoryKind;

type FrameExtra = stacked_borrows::CallId;
type MemoryExtra = stacked_borrows::MemoryState;
type AllocExtra = stacked_borrows::Stacks;
type PointerTag = Borrow;

Expand All @@ -317,7 +319,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
// We walk up the stack a few frames to also cover their callees.
const WHITELIST: &[(&str, &str)] = &[
// Uses mem::uninitialized
("std::ptr::read", ""),
("std::sys::windows::mutex::Mutex::", ""),
];
for frame in ecx.stack().iter()
Expand Down Expand Up @@ -405,8 +406,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
}

fn find_foreign_static(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
def_id: DefId,
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
memory_extra: &Self::MemoryExtra,
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Borrow, Self::AllocExtra>>> {
let attrs = tcx.get_attrs(def_id);
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
Expand All @@ -417,8 +419,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
let alloc = match &link_name[..] {
"__cxa_thread_atexit_impl" => {
// This should be all-zero, pointer-sized
let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize];
Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi)
let size = tcx.data_layout.pointer_size;
let data = vec![0; size.bytes() as usize];
let extra = AllocationExtra::memory_allocated(size, memory_extra);
Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra)
}
_ => return err!(Unimplemented(
format!("can't access foreign static: {}", link_name),
Expand All @@ -434,9 +438,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
Ok(())
}

fn adjust_static_allocation(
alloc: &'_ Allocation
) -> Cow<'_, Allocation<Borrow, Self::AllocExtra>> {
fn adjust_static_allocation<'b>(
alloc: &'b Allocation,
memory_extra: &Self::MemoryExtra,
) -> Cow<'b, Allocation<Borrow, Self::AllocExtra>> {
let extra = AllocationExtra::memory_allocated(
Size::from_bytes(alloc.bytes.len() as u64),
memory_extra,
);
let alloc: Allocation<Borrow, Self::AllocExtra> = Allocation {
bytes: alloc.bytes.clone(),
relocations: Relocations::from_presorted(
Expand All @@ -447,7 +456,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
undef_mask: alloc.undef_mask.clone(),
align: alloc.align,
mutability: alloc.mutability,
extra: Self::AllocExtra::default(),
extra,
};
Cow::Owned(alloc)
}
Expand Down Expand Up @@ -529,4 +538,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
ecx.retag(fn_entry, place)
}
}

#[inline(always)]
fn stack_push(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
) -> EvalResult<'tcx, stacked_borrows::CallId> {
Ok(ecx.memory().extra.borrow_mut().new_call())
}

#[inline(always)]
fn stack_pop(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
extra: stacked_borrows::CallId,
) -> EvalResult<'tcx> {
Ok(ecx.memory().extra.borrow_mut().end_call(extra))
}
}
108 changes: 29 additions & 79 deletions src/range_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ pub struct RangeMap<T> {
map: BTreeMap<Range, T>,
}

impl<T> Default for RangeMap<T> {
#[inline(always)]
fn default() -> Self {
RangeMap::new()
}
}

// The derived `Ord` impl sorts first by the first field, then, if the fields are the same,
// by the second field.
// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all
Expand Down Expand Up @@ -73,9 +66,15 @@ impl Range {
}

impl<T> RangeMap<T> {
/// Create a new RangeMap for the given size, and with the given initial value used for
/// the entire range.
#[inline(always)]
pub fn new() -> RangeMap<T> {
RangeMap { map: BTreeMap::new() }
pub fn new(size: Size, init: T) -> RangeMap<T> {
let mut map = RangeMap { map: BTreeMap::new() };
if size.bytes() > 0 {
map.map.insert(Range { start: 0, end: size.bytes() }, init);
}
map
}

fn iter_with_range<'a>(
Expand All @@ -95,6 +94,9 @@ impl<T> RangeMap<T> {
)
}

/// Provide read-only iteration over everything in the given range. This does
/// *not* split items if they overlap with the edges. Do not use this to mutate
/// through interior mutability.
pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = &'a T> + 'a {
self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data)
}
Expand Down Expand Up @@ -140,8 +142,7 @@ impl<T> RangeMap<T> {
/// Provide mutable iteration over everything in the given range. As a side-effect,
/// this will split entries in the map that are only partially hit by the given range,
/// to make sure that when they are mutated, the effect is constrained to the given range.
/// If there are gaps, leave them be.
pub fn iter_mut_with_gaps<'a>(
pub fn iter_mut<'a>(
&'a mut self,
offset: Size,
len: Size,
Expand Down Expand Up @@ -174,93 +175,34 @@ impl<T> RangeMap<T> {
},
)
}

/// Provide a mutable iterator over everything in the given range, with the same side-effects as
/// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default
/// before yielding them in the iterator.
/// This is also how you insert.
pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator<Item = &'a mut T> + 'a
where
T: Clone + Default,
{
if len.bytes() > 0 {
let offset = offset.bytes();
let len = len.bytes();

// Do a first iteration to collect the gaps
let mut gaps = Vec::new();
let mut last_end = offset;
for (range, _) in self.iter_with_range(offset, len) {
if last_end < range.start {
gaps.push(Range {
start: last_end,
end: range.start,
});
}
last_end = range.end;
}
if last_end < offset + len {
gaps.push(Range {
start: last_end,
end: offset + len,
});
}

// Add default for all gaps
for gap in gaps {
let old = self.map.insert(gap, Default::default());
assert!(old.is_none());
}
}

// Now provide mutable iteration
self.iter_mut_with_gaps(offset, len)
}

pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
let mut remove = Vec::new();
for (range, data) in &self.map {
if !f(data) {
remove.push(*range);
}
}

for range in remove {
self.map.remove(&range);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

/// Query the map at every offset in the range and collect the results.
fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64, default: Option<T>) -> Vec<T> {
fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
(offset..offset + len)
.into_iter()
.map(|i| map
.iter(Size::from_bytes(i), Size::from_bytes(1))
.next()
.map(|&t| t)
.or(default)
.unwrap()
)
.collect()
}

#[test]
fn basic_insert() {
let mut map = RangeMap::<i32>::new();
let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
// Insert
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
*x = 42;
}
// Check
assert_eq!(to_vec(&map, 10, 1, None), vec![42]);
assert_eq!(to_vec(&map, 10, 1), vec![42]);

// Insert with size 0
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
Expand All @@ -269,34 +211,42 @@ mod tests {
for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
*x = 19;
}
assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]);
assert_eq!(to_vec(&map, 10, 2), vec![42, -1]);
}

#[test]
fn gaps() {
let mut map = RangeMap::<i32>::new();
let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
*x = 42;
}
for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
*x = 43;
}
assert_eq!(
to_vec(&map, 10, 10, Some(-1)),
to_vec(&map, 10, 10),
vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]
);

// Now request a range that needs three gaps filled
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
if *x < 42 {
*x = 23;
}
}

assert_eq!(
to_vec(&map, 10, 10, None),
to_vec(&map, 10, 10),
vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]
);
assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]);
assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]);

// Now request a range that goes beyond the initial size
for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) {
*x = 19;
}
assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1))
.map(|&t| t).collect::<Vec<_>>(), vec![19]);
assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1))
.map(|&t| t).collect::<Vec<_>>(), vec![]);
}
}
Loading