From 6aff92a7d2095d7de1121d48d70e14e4ec680c9b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Mar 2020 00:57:30 +0100 Subject: [PATCH] move DropArena -> libarena --- src/libarena/lib.rs | 81 ++++++++++++++++++++++++++++++++++++++++ src/librustc/arena.rs | 87 +------------------------------------------ 2 files changed, 82 insertions(+), 86 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 2a3d92edc495..0fb06601914a 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -488,5 +488,86 @@ impl DroplessArena { } } +/// Calls the destructor for an object when dropped. +struct DropType { + drop_fn: unsafe fn(*mut u8), + obj: *mut u8, +} + +unsafe fn drop_for_type(to_drop: *mut u8) { + std::ptr::drop_in_place(to_drop as *mut T) +} + +impl Drop for DropType { + fn drop(&mut self) { + unsafe { (self.drop_fn)(self.obj) } + } +} + +/// An arena which can be used to allocate any type. +/// Allocating in this arena is unsafe since the type system +/// doesn't know which types it contains. In order to +/// allocate safely, you must store a PhantomData +/// alongside this arena for each type T you allocate. +#[derive(Default)] +pub struct DropArena { + /// A list of destructors to run when the arena drops. + /// Ordered so `destructors` gets dropped before the arena + /// since its destructor can reference memory in the arena. + destructors: RefCell>, + arena: DroplessArena, +} + +impl DropArena { + #[inline] + pub unsafe fn alloc(&self, object: T) -> &mut T { + let mem = + self.arena.alloc_raw(mem::size_of::(), mem::align_of::()) as *mut _ as *mut T; + // Write into uninitialized memory. + ptr::write(mem, object); + let result = &mut *mem; + // Record the destructor after doing the allocation as that may panic + // and would cause `object`'s destuctor to run twice if it was recorded before + self.destructors + .borrow_mut() + .push(DropType { drop_fn: drop_for_type::, obj: result as *mut T as *mut u8 }); + result + } + + #[inline] + pub unsafe fn alloc_from_iter>(&self, iter: I) -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); + if vec.is_empty() { + return &mut []; + } + let len = vec.len(); + + let start_ptr = self + .arena + .alloc_raw(len.checked_mul(mem::size_of::()).unwrap(), mem::align_of::()) + as *mut _ as *mut T; + + let mut destructors = self.destructors.borrow_mut(); + // Reserve space for the destructors so we can't panic while adding them + destructors.reserve(len); + + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + mem::forget(vec.drain(..)); + + // Record the destructors after doing the allocation as that may panic + // and would cause `object`'s destuctor to run twice if it was recorded before + for i in 0..len { + destructors.push(DropType { + drop_fn: drop_for_type::, + obj: start_ptr.offset(i as isize) as *mut u8, + }); + } + + slice::from_raw_parts_mut(start_ptr, len) + } +} + #[cfg(test)] mod tests; diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index bbac5dfd2b8d..2f73566920d0 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -1,10 +1,6 @@ -use arena::{DroplessArena, TypedArena}; -use smallvec::SmallVec; -use std::cell::RefCell; +use arena::{DropArena, DroplessArena, TypedArena}; use std::marker::PhantomData; use std::mem; -use std::ptr; -use std::slice; /// This declares a list of types which can be allocated by `Arena`. /// @@ -275,84 +271,3 @@ impl<'tcx> Arena<'tcx> { } } } - -/// Calls the destructor for an object when dropped. -struct DropType { - drop_fn: unsafe fn(*mut u8), - obj: *mut u8, -} - -unsafe fn drop_for_type(to_drop: *mut u8) { - std::ptr::drop_in_place(to_drop as *mut T) -} - -impl Drop for DropType { - fn drop(&mut self) { - unsafe { (self.drop_fn)(self.obj) } - } -} - -/// An arena which can be used to allocate any type. -/// Allocating in this arena is unsafe since the type system -/// doesn't know which types it contains. In order to -/// allocate safely, you must store a PhantomData -/// alongside this arena for each type T you allocate. -#[derive(Default)] -struct DropArena { - /// A list of destructors to run when the arena drops. - /// Ordered so `destructors` gets dropped before the arena - /// since its destructor can reference memory in the arena. - destructors: RefCell>, - arena: DroplessArena, -} - -impl DropArena { - #[inline] - unsafe fn alloc(&self, object: T) -> &mut T { - let mem = - self.arena.alloc_raw(mem::size_of::(), mem::align_of::()) as *mut _ as *mut T; - // Write into uninitialized memory. - ptr::write(mem, object); - let result = &mut *mem; - // Record the destructor after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before - self.destructors - .borrow_mut() - .push(DropType { drop_fn: drop_for_type::, obj: result as *mut T as *mut u8 }); - result - } - - #[inline] - unsafe fn alloc_from_iter>(&self, iter: I) -> &mut [T] { - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); - if vec.is_empty() { - return &mut []; - } - let len = vec.len(); - - let start_ptr = self - .arena - .alloc_raw(len.checked_mul(mem::size_of::()).unwrap(), mem::align_of::()) - as *mut _ as *mut T; - - let mut destructors = self.destructors.borrow_mut(); - // Reserve space for the destructors so we can't panic while adding them - destructors.reserve(len); - - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - mem::forget(vec.drain(..)); - - // Record the destructors after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before - for i in 0..len { - destructors.push(DropType { - drop_fn: drop_for_type::, - obj: start_ptr.offset(i as isize) as *mut u8, - }); - } - - slice::from_raw_parts_mut(start_ptr, len) - } -}