Skip to content

Commit

Permalink
Merge pull request #553 from solson/rustup
Browse files Browse the repository at this point in the history
Stacked Borrow: Barriers
  • Loading branch information
RalfJung authored Nov 30, 2018
2 parents 559ad2d + 3999db1 commit 8d2bc97
Show file tree
Hide file tree
Showing 14 changed files with 368 additions and 237 deletions.
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

0 comments on commit 8d2bc97

Please sign in to comment.