Skip to content

Commit

Permalink
Auto merge of rust-lang#77014 - tmiasko:arena, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
DroplessArena: Allocate objects from the end of memory chunk

Allocating from the end of memory chunk simplifies the alignment code
and reduces the number of checked arithmetic operations.
  • Loading branch information
bors committed Sep 24, 2020
2 parents e599b53 + c7e887c commit 9b5c98f
Showing 1 changed file with 16 additions and 21 deletions.
37 changes: 16 additions & 21 deletions compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,11 +299,13 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
unsafe impl<T: Send> Send for TypedArena<T> {}

pub struct DroplessArena {
/// A pointer to the next object to be allocated.
ptr: Cell<*mut u8>,
/// A pointer to the start of the free space.
start: Cell<*mut u8>,

/// A pointer to the end of the allocated area. When this pointer is
/// reached, a new chunk is allocated.
/// A pointer to the end of free space.
///
/// The allocation proceeds from the end of the chunk towards the start.
/// When this pointer crosses the start pointer, a new chunk is allocated.
end: Cell<*mut u8>,

/// A vector of arena chunks.
Expand All @@ -316,7 +318,7 @@ impl Default for DroplessArena {
#[inline]
fn default() -> DroplessArena {
DroplessArena {
ptr: Cell::new(ptr::null_mut()),
start: Cell::new(ptr::null_mut()),
end: Cell::new(ptr::null_mut()),
chunks: Default::default(),
}
Expand Down Expand Up @@ -348,7 +350,7 @@ impl DroplessArena {
new_cap = cmp::max(additional, new_cap);

let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
self.ptr.set(chunk.start());
self.start.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
}
Expand All @@ -359,24 +361,17 @@ impl DroplessArena {
/// request.
#[inline]
fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
let ptr = self.ptr.get() as usize;
let start = self.start.get() as usize;
let end = self.end.get() as usize;

let align = layout.align();
let bytes = layout.size();
// The allocation request fits into the current chunk iff:
//
// let aligned = align_to(ptr, align);
// ptr <= aligned && aligned + bytes <= end
//
// Except that we work with fixed width integers and need to be careful
// about potential overflow in the calcuation. If the overflow does
// happen, then we definitely don't have enough free and need to grow
// the arena.
let aligned = ptr.checked_add(align - 1)? & !(align - 1);
let new_ptr = aligned.checked_add(bytes)?;
if new_ptr <= end {
self.ptr.set(new_ptr as *mut u8);
Some(aligned as *mut u8)

let new_end = end.checked_sub(bytes)? & !(align - 1);
if start <= new_end {
let new_end = new_end as *mut u8;
self.end.set(new_end);
Some(new_end)
} else {
None
}
Expand Down

0 comments on commit 9b5c98f

Please sign in to comment.