|  | @@ -1,44 +1,162 @@
 | 
	
		
			
				|  |  | -//! Memory primitives.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -use core::cmp;
 | 
	
		
			
				|  |  | -use core::ptr::Unique;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/// A contigious memory block.
 | 
	
		
			
				|  |  | +//! Memory blocks.
 | 
	
		
			
				|  |  | +//!
 | 
	
		
			
				|  |  | +//! Blocks are the main unit for the memory bookkeeping. A block is a simple construct with a
 | 
	
		
			
				|  |  | +//! `Pointer` pointer and a size. Occupied (non-free) blocks are represented by a zero-sized block.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +use core::{ptr, cmp, mem, fmt};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +use ptr::Pointer;
 | 
	
		
			
				|  |  | +use sys;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// A contiguous memory block.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// This provides a number of guarantees,
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// 1. The inner pointer is never aliased. No byte in the block is contained in another block
 | 
	
		
			
				|  |  | +///    (aliased in this case is defined purely based on liveliness).
 | 
	
		
			
				|  |  | +/// 2. The buffer is valid, but not necessarily initialized.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// All this is enforced through the type system.
 | 
	
		
			
				|  |  |  pub struct Block {
 | 
	
		
			
				|  |  |      /// The size of this block, in bytes.
 | 
	
		
			
				|  |  | -    pub size: usize,
 | 
	
		
			
				|  |  | +    size: usize,
 | 
	
		
			
				|  |  |      /// The pointer to the start of this block.
 | 
	
		
			
				|  |  | -    pub ptr: Unique<u8>,
 | 
	
		
			
				|  |  | +    ptr: Pointer<u8>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl Block {
 | 
	
		
			
				|  |  | -    /// Get a pointer to the end of this block, not inclusive.
 | 
	
		
			
				|  |  | -    pub fn end(&self) -> Unique<u8> {
 | 
	
		
			
				|  |  | -        // TODO, this might trigger an overflow, which could imply creating a null-pointer.
 | 
	
		
			
				|  |  | -        let ptr = (self.size + *self.ptr as usize) as *mut _;
 | 
	
		
			
				|  |  | -        debug_assert!(!ptr.is_null(), "Pointer is null.");
 | 
	
		
			
				|  |  | +    /// Create an empty block starting at `ptr`.
 | 
	
		
			
				|  |  | +    pub fn empty(ptr: &Pointer<u8>) -> Block {
 | 
	
		
			
				|  |  | +        Block {
 | 
	
		
			
				|  |  | +            size: 0,
 | 
	
		
			
				|  |  | +            // This won't alias `ptr`, since the block is empty.
 | 
	
		
			
				|  |  | +            ptr: unsafe { Pointer::new(**ptr) },
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        unsafe {
 | 
	
		
			
				|  |  | -            Unique::new(ptr)
 | 
	
		
			
				|  |  | +    /// Construct a block from its raw parts (pointer and size).
 | 
	
		
			
				|  |  | +    pub unsafe fn from_raw_parts(ptr: Pointer<u8>, size: usize) ->  Block {
 | 
	
		
			
				|  |  | +        Block {
 | 
	
		
			
				|  |  | +            size: size,
 | 
	
		
			
				|  |  | +            ptr: ptr,
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Get the size of the block.
 | 
	
		
			
				|  |  | +    pub fn size(&self) -> usize {
 | 
	
		
			
				|  |  | +        self.size
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// BRK allocate a block.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// This is unsafe due to the allocator assuming that only it makes use of BRK.
 | 
	
		
			
				|  |  | +   pub unsafe fn brk(size: usize) -> Block {
 | 
	
		
			
				|  |  | +        Block {
 | 
	
		
			
				|  |  | +            size: size,
 | 
	
		
			
				|  |  | +            ptr: sys::inc_brk(size).unwrap_or_else(|x| x.handle()),
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// Is this block free?
 | 
	
		
			
				|  |  | -    pub fn is_free(&self) -> bool {
 | 
	
		
			
				|  |  | +    /// Merge this block with a block to the right.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// This will simply extend the block, adding the size of the block, and then set the size to
 | 
	
		
			
				|  |  | +    /// zero. The return value is `Ok(())` on success, and `Err(())` on failure (e.g., the blocks
 | 
	
		
			
				|  |  | +    /// are not adjacent).
 | 
	
		
			
				|  |  | +    pub fn merge_right(&mut self, block: &mut Block) -> Result<(), ()> {
 | 
	
		
			
				|  |  | +        if self.left_to(&block) {
 | 
	
		
			
				|  |  | +            // Since the end of `block` is bounded by the address space, adding them cannot
 | 
	
		
			
				|  |  | +            // overflow.
 | 
	
		
			
				|  |  | +            self.size += block.pop().size;
 | 
	
		
			
				|  |  | +            // We pop it to make sure it isn't aliased.
 | 
	
		
			
				|  |  | +            Ok(())
 | 
	
		
			
				|  |  | +        } else { Err(()) }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Is this block empty/free?
 | 
	
		
			
				|  |  | +    pub fn is_empty(&self) -> bool {
 | 
	
		
			
				|  |  |          self.size != 0
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// Set this block as free.
 | 
	
		
			
				|  |  | +    /// Is this block aligned to `align`?
 | 
	
		
			
				|  |  | +    pub fn aligned_to(&self, align: usize) -> bool {
 | 
	
		
			
				|  |  | +        *self.ptr as usize % align == 0
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Get the inner pointer.
 | 
	
		
			
				|  |  | +    pub fn into_ptr(self) -> Pointer<u8> {
 | 
	
		
			
				|  |  | +        self.ptr
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// memcpy the block to another pointer.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// # Panics
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// This will panic if the target block is smaller than the source.
 | 
	
		
			
				|  |  | +    pub fn copy_to(&self, block: &mut Block) {
 | 
	
		
			
				|  |  | +        // Bound check.
 | 
	
		
			
				|  |  | +        assert!(self.size <= block.size, "Block too small.");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        unsafe {
 | 
	
		
			
				|  |  | +            ptr::copy_nonoverlapping(*self.ptr, *block.ptr, self.size);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// "Pop" this block.
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  | -    /// This will not deallocate, but it will simply set the size to zero, which is the
 | 
	
		
			
				|  |  | -    /// representation of a freeed block.
 | 
	
		
			
				|  |  | -    pub fn set_free(&mut self) {
 | 
	
		
			
				|  |  | -        self.size = 0;
 | 
	
		
			
				|  |  | +    /// This marks it as free, and returns the old value.
 | 
	
		
			
				|  |  | +    pub fn pop(&mut self) -> Block {
 | 
	
		
			
				|  |  | +        let empty = Block::empty(&self.ptr);
 | 
	
		
			
				|  |  | +        mem::replace(self, empty)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Is this block placed left to the given other block?
 | 
	
		
			
				|  |  | -    pub fn left_to(&self, to: *mut u8) -> bool {
 | 
	
		
			
				|  |  | -        self.size + *self.ptr as usize == to as usize
 | 
	
		
			
				|  |  | +    pub fn left_to(&self, to: &Block) -> bool {
 | 
	
		
			
				|  |  | +        // This won't overflow due to the end being bounded by the address space.
 | 
	
		
			
				|  |  | +        self.size + *self.ptr as usize == *to.ptr as usize
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Split the block at some position.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// # Panics
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// Panics if `pos` is out of bound.
 | 
	
		
			
				|  |  | +    pub fn split(self, pos: usize) -> (Block, Block) {
 | 
	
		
			
				|  |  | +        assert!(pos <= self.size, "Split {} out of bound (size is {})!", pos, self.size);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        (
 | 
	
		
			
				|  |  | +            Block {
 | 
	
		
			
				|  |  | +                size: pos,
 | 
	
		
			
				|  |  | +                ptr: self.ptr.duplicate(),
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            Block {
 | 
	
		
			
				|  |  | +                size: self.size - pos,
 | 
	
		
			
				|  |  | +                ptr: unsafe { self.ptr.offset(pos as isize) },
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Split this block, such that the second block is aligned to `align`.
 | 
	
		
			
				|  |  | +    ///
 | 
	
		
			
				|  |  | +    /// Returns an `None` holding the intact block if `align` is out of bounds.
 | 
	
		
			
				|  |  | +    pub fn align(&mut self, align: usize) -> Option<(Block, Block)> {
 | 
	
		
			
				|  |  | +        let aligner = align - *self.ptr as usize % align;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Bound check.
 | 
	
		
			
				|  |  | +        if aligner < self.size {
 | 
	
		
			
				|  |  | +            // Invalidate the old block.
 | 
	
		
			
				|  |  | +            let old = self.pop();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Some((
 | 
	
		
			
				|  |  | +                Block {
 | 
	
		
			
				|  |  | +                    size: aligner,
 | 
	
		
			
				|  |  | +                    ptr: old.ptr.duplicate(),
 | 
	
		
			
				|  |  | +                },
 | 
	
		
			
				|  |  | +                Block {
 | 
	
		
			
				|  |  | +                    size: old.size - aligner,
 | 
	
		
			
				|  |  | +                    ptr: unsafe { old.ptr.offset(aligner as isize) },
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            ))
 | 
	
		
			
				|  |  | +        } else { None }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -48,6 +166,7 @@ impl PartialOrd for Block {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// Compare the blocks address.
 | 
	
		
			
				|  |  |  impl Ord for Block {
 | 
	
		
			
				|  |  |      fn cmp(&self, other: &Block) -> cmp::Ordering {
 | 
	
		
			
				|  |  |          self.ptr.cmp(&other.ptr)
 | 
	
	
		
			
				|  | @@ -62,77 +181,64 @@ impl cmp::PartialEq for Block {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl cmp::Eq for Block {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +impl fmt::Debug for Block {
 | 
	
		
			
				|  |  | +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
	
		
			
				|  |  | +        write!(f, "0x{:x}[0x{:x}]", *self.ptr as usize, self.size)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #[cfg(test)]
 | 
	
		
			
				|  |  |  mod test {
 | 
	
		
			
				|  |  |      use super::*;
 | 
	
		
			
				|  |  | -    use core::ptr::Unique;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    use ptr::Pointer;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  | -    fn test_end() {
 | 
	
		
			
				|  |  | -        let a = Block {
 | 
	
		
			
				|  |  | -            size: 10,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(15 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let b = Block {
 | 
	
		
			
				|  |  | -            size: 15,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(25 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let c = Block {
 | 
	
		
			
				|  |  | -            size: 75,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(40 as *mut _) },
 | 
	
		
			
				|  |  | +    fn test_array() {
 | 
	
		
			
				|  |  | +        let arr = b"Lorem ipsum dolor sit amet";
 | 
	
		
			
				|  |  | +        let block = unsafe {
 | 
	
		
			
				|  |  | +            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        assert_eq!(*a.end(), *b.ptr);
 | 
	
		
			
				|  |  | -        assert_eq!(*b.end(), *c.ptr);
 | 
	
		
			
				|  |  | +        // Test split.
 | 
	
		
			
				|  |  | +        let (mut lorem, mut rest) = block.split(5);
 | 
	
		
			
				|  |  | +        assert_eq!(lorem.size(), 5);
 | 
	
		
			
				|  |  | +        assert_eq!(lorem.size() + rest.size(), arr.len());
 | 
	
		
			
				|  |  | +        assert!(lorem < rest);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /* TODO
 | 
	
		
			
				|  |  | +        assert_eq!(unsafe {
 | 
	
		
			
				|  |  | +            slice::from_raw_parts(*lorem.into_ptr() as *const _, lorem.size())
 | 
	
		
			
				|  |  | +        }, b"Lorem");
 | 
	
		
			
				|  |  | +        */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        assert_eq!(lorem, lorem);
 | 
	
		
			
				|  |  | +        assert!(rest.is_empty());
 | 
	
		
			
				|  |  | +        assert!(lorem.align(2).unwrap().1.aligned_to(2));
 | 
	
		
			
				|  |  | +        assert!(rest.align(16).unwrap().1.aligned_to(16));
 | 
	
		
			
				|  |  | +        assert_eq!(*lorem.into_ptr() as usize + 5, *rest.into_ptr() as usize);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  | -    fn test_left_to() {
 | 
	
		
			
				|  |  | -        let a = Block {
 | 
	
		
			
				|  |  | -            size: 10,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(15 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let b = Block {
 | 
	
		
			
				|  |  | -            size: 15,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(25 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let c = Block {
 | 
	
		
			
				|  |  | -            size: 75,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(40 as *mut _) },
 | 
	
		
			
				|  |  | +    fn test_merge() {
 | 
	
		
			
				|  |  | +        let arr = b"Lorem ipsum dolor sit amet";
 | 
	
		
			
				|  |  | +        let block = unsafe {
 | 
	
		
			
				|  |  | +            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        assert!(a.left_to(*b.ptr));
 | 
	
		
			
				|  |  | -        assert!(b.left_to(*c.ptr));
 | 
	
		
			
				|  |  | -        assert!(!c.left_to(*a.ptr));
 | 
	
		
			
				|  |  | -        assert!(!a.left_to(*c.ptr));
 | 
	
		
			
				|  |  | -        assert!(!b.left_to(*b.ptr));
 | 
	
		
			
				|  |  | -        assert!(!b.left_to(*a.ptr));
 | 
	
		
			
				|  |  | +        let (mut lorem, mut rest) = block.split(5);
 | 
	
		
			
				|  |  | +        lorem.merge_right(&mut rest).unwrap();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  | -    fn test_cmp() {
 | 
	
		
			
				|  |  | -        let a = Block {
 | 
	
		
			
				|  |  | -            size: 10,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(10 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let b = Block {
 | 
	
		
			
				|  |  | -            size: 15,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(25 as *mut _) },
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        let c = Block {
 | 
	
		
			
				|  |  | -            size: 75,
 | 
	
		
			
				|  |  | -            ptr: unsafe { Unique::new(40 as *mut _) },
 | 
	
		
			
				|  |  | +    #[should_panic]
 | 
	
		
			
				|  |  | +    fn test_oob() {
 | 
	
		
			
				|  |  | +        let arr = b"lorem";
 | 
	
		
			
				|  |  | +        let block = unsafe {
 | 
	
		
			
				|  |  | +            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        assert!(a < b);
 | 
	
		
			
				|  |  | -        assert!(b < c);
 | 
	
		
			
				|  |  | -        assert!(c > a);
 | 
	
		
			
				|  |  | -        assert!(a == a);
 | 
	
		
			
				|  |  | -        assert!(b == b);
 | 
	
		
			
				|  |  | -        assert!(c == c);
 | 
	
		
			
				|  |  | -        assert!(c >= c);
 | 
	
		
			
				|  |  | -        assert!(c <= c);
 | 
	
		
			
				|  |  | -        assert!(a <= c);
 | 
	
		
			
				|  |  | -        assert!(b >= a);
 | 
	
		
			
				|  |  | +        // Test OOB.
 | 
	
		
			
				|  |  | +        block.split(6);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |