From 594f1d79da1eebb2acb674b686d98b4fc1ef165f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 30 Jun 2016 16:42:09 +0200 Subject: [PATCH] optimize all ZST allocations into one single allocation --- src/interpreter/terminator.rs | 4 ++-- src/memory.rs | 45 +++++++++++++++++++++++++++++++---- tests/run-pass/zst.rs | 8 +++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/interpreter/terminator.rs b/src/interpreter/terminator.rs index a9bb1fa5317..8f5ec0e1b59 100644 --- a/src/interpreter/terminator.rs +++ b/src/interpreter/terminator.rs @@ -423,8 +423,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "__rust_reallocate" => { let ptr = self.memory.read_ptr(args[0])?; let size = self.memory.read_usize(args[2])?; - self.memory.reallocate(ptr, size as usize)?; - self.memory.write_ptr(dest, ptr)?; + let new_ptr = self.memory.reallocate(ptr, size as usize)?; + self.memory.write_ptr(dest, new_ptr)?; } "memcmp" => { diff --git a/src/memory.rs b/src/memory.rs index 64c105a4e7f..25612c435e2 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -39,8 +39,18 @@ pub struct Pointer { impl Pointer { pub fn offset(self, i: isize) -> Self { + // FIXME: prevent offsetting ZST ptrs in tracing mode Pointer { offset: (self.offset as isize + i) as usize, ..self } } + pub fn points_to_zst(&self) -> bool { + self.alloc_id.0 == 0 + } + fn zst_ptr() -> Self { + Pointer { + alloc_id: AllocId(0), + offset: 0, + } + } } #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] @@ -68,13 +78,25 @@ pub struct Memory<'a, 'tcx> { impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn new(layout: &'a TargetDataLayout) -> Self { - Memory { + let mut mem = Memory { alloc_map: HashMap::new(), functions: HashMap::new(), function_alloc_cache: HashMap::new(), - next_id: AllocId(0), + next_id: AllocId(1), layout: layout, - } + }; + // alloc id 0 is reserved for ZSTs, this is an optimization to prevent ZST + // (e.g. function pointers, (), [], ...) from requiring memory + let alloc = Allocation { + bytes: Vec::new(), + relocations: BTreeMap::new(), + undef_mask: UndefMask::new(0), + }; + mem.alloc_map.insert(AllocId(0), alloc); + // check that additional zst allocs work + debug_assert!(mem.allocate(0).points_to_zst()); + debug_assert!(mem.get(AllocId(0)).is_ok()); + mem } pub fn allocations<'b>(&'b self) -> ::std::collections::hash_map::Iter<'b, AllocId, Allocation> { @@ -105,6 +127,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn allocate(&mut self, size: usize) -> Pointer { + if size == 0 { + return Pointer::zst_ptr(); + } let alloc = Allocation { bytes: vec![0; size], relocations: BTreeMap::new(), @@ -121,7 +146,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { // TODO(solson): Track which allocations were returned from __rust_allocate and report an error // when reallocating/deallocating any others. - pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<'tcx, ()> { + pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<'tcx, Pointer> { + if ptr.points_to_zst() { + if new_size != 0 { + return Ok(self.allocate(new_size)); + } else { + return Ok(ptr); + } + } if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); @@ -141,11 +173,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { alloc.undef_mask.truncate(new_size); } - Ok(()) + Ok(ptr) } // TODO(solson): See comment on `reallocate`. pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<'tcx, ()> { + if ptr.points_to_zst() { + return Ok(()); + } if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index db98e969306..4ebb2001e72 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -1,3 +1,9 @@ +// the following flag prevents this test from running on the host machine +// this should only be run on miri, because rust doesn't (yet?) optimize ZSTs of different types +// into the same memory location +// ignore-test + + #[derive(PartialEq, Debug)] struct A; @@ -13,4 +19,6 @@ fn use_zst() -> A { fn main() { assert_eq!(zst_ret(), A); assert_eq!(use_zst(), A); + assert_eq!(&A as *const A as *const (), &() as *const _); + assert_eq!(&A as *const A, &A as *const A); }