]> git.lizzy.rs Git - rust.git/commitdiff
DroplessArena: Allocate objects from the end of memory chunk
authorTomasz Miąsko <tomasz.miasko@gmail.com>
Mon, 21 Sep 2020 00:00:00 +0000 (00:00 +0000)
committerTomasz Miąsko <tomasz.miasko@gmail.com>
Mon, 21 Sep 2020 13:36:45 +0000 (15:36 +0200)
Allocating from the end of memory chunk simplifies the alignment code
and reduces the number of checked arithmetic operations.

compiler/rustc_arena/src/lib.rs

index 6f9cccf58dd01fb165047ca8d8f5cadbd20f6a9f..32783951a313d1c3ea1d54320d7e7be7794f930b 100644 (file)
@@ -299,11 +299,13 @@ fn drop(&mut self) {
 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.
@@ -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(),
         }
@@ -348,7 +350,7 @@ fn grow(&self, additional: usize) {
             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);
         }
@@ -359,24 +361,17 @@ fn grow(&self, additional: usize) {
     /// 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
         }