diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7346404731988..e91898548533c 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -39,17 +39,18 @@ use std::mem; use std::num; use std::ptr; use std::rc::Rc; -use std::rt::heap::allocate; +use std::rt::heap::{allocate, deallocate}; // The way arena uses arrays is really deeply awful. The arrays are // allocated, and have capacities reserved, but the fill for the array // will always stay at 0. #[deriving(Clone, PartialEq)] struct Chunk { - data: Rc >>, + data: Rc>>, fill: Cell, is_copy: Cell, } + impl Chunk { fn capacity(&self) -> uint { self.data.borrow().capacity() @@ -357,13 +358,12 @@ pub struct TypedArena { end: Cell<*const T>, /// A pointer to the first arena segment. - first: RefCell>, + first: RefCell<*mut TypedArenaChunk>, } -type TypedArenaChunkRef = Option>>; struct TypedArenaChunk { /// Pointer to the next arena segment. - next: TypedArenaChunkRef, + next: *mut TypedArenaChunk, /// The number of elements that this chunk can hold. capacity: uint, @@ -371,24 +371,24 @@ struct TypedArenaChunk { // Objects follow here, suitably aligned. } +fn calculate_size(capacity: uint) -> uint { + let mut size = mem::size_of::>(); + size = round_up(size, mem::min_align_of::()); + let elem_size = mem::size_of::(); + let elems_size = elem_size.checked_mul(&capacity).unwrap(); + size = size.checked_add(&elems_size).unwrap(); + size +} + impl TypedArenaChunk { #[inline] - fn new(next: Option>>, capacity: uint) - -> Box> { - let mut size = mem::size_of::>(); - size = round_up(size, mem::min_align_of::()); - let elem_size = mem::size_of::(); - let elems_size = elem_size.checked_mul(&capacity).unwrap(); - size = size.checked_add(&elems_size).unwrap(); - - let mut chunk = unsafe { - let chunk = allocate(size, mem::min_align_of::>()); - let mut chunk: Box> = mem::transmute(chunk); - ptr::write(&mut chunk.next, next); - chunk - }; - - chunk.capacity = capacity; + unsafe fn new(next: *mut TypedArenaChunk, capacity: uint) + -> *mut TypedArenaChunk { + let size = calculate_size::(capacity); + let chunk = allocate(size, mem::min_align_of::>()) + as *mut TypedArenaChunk; + (*chunk).next = next; + (*chunk).capacity = capacity; chunk } @@ -406,14 +406,13 @@ impl TypedArenaChunk { } // Destroy the next chunk. - let next_opt = mem::replace(&mut self.next, None); - match next_opt { - None => {} - Some(mut next) => { - // We assume that the next chunk is completely filled. - let capacity = next.capacity; - next.destroy(capacity) - } + let next = self.next; + let size = calculate_size::(self.capacity); + deallocate(self as *mut TypedArenaChunk as *mut u8, size, + mem::min_align_of::>()); + if next.is_not_null() { + let capacity = (*next).capacity; + (*next).destroy(capacity); } } @@ -448,11 +447,13 @@ impl TypedArena { /// objects. #[inline] pub fn with_capacity(capacity: uint) -> TypedArena { - let chunk = TypedArenaChunk::::new(None, capacity); - TypedArena { - ptr: Cell::new(chunk.start() as *const T), - end: Cell::new(chunk.end() as *const T), - first: RefCell::new(Some(chunk)), + unsafe { + let chunk = TypedArenaChunk::::new(ptr::mut_null(), capacity); + TypedArena { + ptr: Cell::new((*chunk).start() as *const T), + end: Cell::new((*chunk).end() as *const T), + first: RefCell::new(chunk), + } } } @@ -476,26 +477,28 @@ impl TypedArena { /// Grows the arena. #[inline(never)] fn grow(&self) { - let chunk = self.first.borrow_mut().take().unwrap(); - let new_capacity = chunk.capacity.checked_mul(&2).unwrap(); - let chunk = TypedArenaChunk::::new(Some(chunk), new_capacity); - self.ptr.set(chunk.start() as *const T); - self.end.set(chunk.end() as *const T); - *self.first.borrow_mut() = Some(chunk) + unsafe { + let chunk = *self.first.borrow_mut(); + let new_capacity = (*chunk).capacity.checked_mul(&2).unwrap(); + let chunk = TypedArenaChunk::::new(chunk, new_capacity); + self.ptr.set((*chunk).start() as *const T); + self.end.set((*chunk).end() as *const T); + *self.first.borrow_mut() = chunk + } } } #[unsafe_destructor] impl Drop for TypedArena { fn drop(&mut self) { - // Determine how much was filled. - let start = self.first.borrow().as_ref().unwrap().start() as uint; - let end = self.ptr.get() as uint; - let diff = (end - start) / mem::size_of::(); - - // Pass that to the `destroy` method. unsafe { - self.first.borrow_mut().as_mut().unwrap().destroy(diff) + // Determine how much was filled. + let start = self.first.borrow().as_ref().unwrap().start() as uint; + let end = self.ptr.get() as uint; + let diff = (end - start) / mem::size_of::(); + + // Pass that to the `destroy` method. + (**self.first.borrow_mut()).destroy(diff) } } }