about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2017-05-23 14:47:41 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2017-06-15 23:48:30 +0200
commit65d02b26c525c07d47686302a15231b28914fda4 (patch)
treef52625ca2c599abb5bf000f646986152b6ba4529 /src/liballoc
parent1d3bc4e90fab35d4debe7d6cb0468d299b38354c (diff)
downloadrust-65d02b26c525c07d47686302a15231b28914fda4.tar.gz
rust-65d02b26c525c07d47686302a15231b28914fda4.zip
Add impl of `Alloc` for the global rust heap.
Alpha-renamed `HeapAllocator` to `HeapAlloc`.

`<HeapAlloc as Alloc>::alloc_zeroed` is hooked up to `heap::allocate_zeroed`.

`HeapAlloc::realloc` falls back on alloc+copy+realloc on align mismatch.
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/heap.rs79
1 files changed, 78 insertions, 1 deletions
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index 5ff21c86483..d46c6a83ff3 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -15,7 +15,8 @@
                       tracing garbage collector",
             issue = "27700")]
 
-use core::{isize, usize};
+use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout};
+use core::{isize, usize, cmp, ptr};
 use core::intrinsics::{min_align_of_val, size_of_val};
 
 #[allow(improper_ctypes)]
@@ -44,6 +45,82 @@ fn check_size_and_alignment(size: usize, align: usize) {
                   align);
 }
 
+#[derive(Copy, Clone, Default, Debug)]
+pub struct HeapAlloc;
+
+unsafe impl Alloc for HeapAlloc {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        let addr = allocate(layout.size(), layout.align());
+        if addr.is_null() {
+            Err(AllocErr::Exhausted { request: layout })
+        } else {
+            Ok(addr)
+        }
+    }
+
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        let addr = allocate_zeroed(layout.size(), layout.align());
+        if addr.is_null() {
+            Err(AllocErr::Exhausted { request: layout })
+        } else {
+            Ok(addr)
+        }
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        deallocate(ptr, layout.size(), layout.align());
+    }
+
+    fn usable_size(&self, layout: &Layout) -> (usize, usize) {
+        (layout.size(), usable_size(layout.size(), layout.align()))
+    }
+
+    unsafe fn realloc(&mut self,
+                      ptr: *mut u8,
+                      layout: Layout,
+                      new_layout: Layout)
+                      -> Result<*mut u8, AllocErr>
+    {
+        let old_size = layout.size();
+        let new_size = new_layout.size();
+        if layout.align() == new_layout.align() {
+            let new_ptr = reallocate(ptr, old_size, new_size, layout.align());
+            if new_ptr.is_null() {
+                // We assume `reallocate` already tried alloc + copy +
+                // dealloc fallback; thus pointless to repeat effort
+                Err(AllocErr::Exhausted { request: new_layout })
+            } else {
+                Ok(new_ptr)
+            }
+        } else {
+            // if alignments don't match, fall back on alloc + copy + dealloc
+            let result = self.alloc(new_layout);
+            if let Ok(new_ptr) = result {
+                ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size));
+                self.dealloc(ptr, layout);
+            }
+            result
+        }
+    }
+
+    unsafe fn grow_in_place(&mut self,
+                            ptr: *mut u8,
+                            layout: Layout,
+                            new_layout: Layout)
+                            -> Result<(), CannotReallocInPlace>
+    {
+        // grow_in_place spec requires this, and the spec for reallocate_inplace
+        // makes it hard to detect failure if it does not hold.
+        debug_assert!(new_layout.size() >= layout.size());
+
+        if layout.align() != new_layout.align() { // reallocate_inplace requires this.
+            return Err(CannotReallocInPlace);
+        }
+        let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align());
+        if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) }
+    }
+}
+
 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
 
 /// Return a pointer to `size` bytes of memory aligned to `align`.