diff options
| author | Felix S. Klock II <pnkfelix@pnkfx.org> | 2017-05-23 14:47:41 +0200 |
|---|---|---|
| committer | Felix S. Klock II <pnkfelix@pnkfx.org> | 2017-06-15 23:48:30 +0200 |
| commit | 65d02b26c525c07d47686302a15231b28914fda4 (patch) | |
| tree | f52625ca2c599abb5bf000f646986152b6ba4529 /src/liballoc | |
| parent | 1d3bc4e90fab35d4debe7d6cb0468d299b38354c (diff) | |
| download | rust-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.rs | 79 |
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`. |
