diff options
Diffstat (limited to 'liballoc/heap.rs')
| -rw-r--r-- | liballoc/heap.rs | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/liballoc/heap.rs b/liballoc/heap.rs new file mode 100644 index 0000000..08b403a --- /dev/null +++ b/liballoc/heap.rs @@ -0,0 +1,190 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "heap_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "27700")] + +use core::{isize, usize}; +#[cfg(not(test))] +use core::intrinsics::{size_of, min_align_of}; + +#[allow(improper_ctypes)] +extern "C" { + #[allocator] + fn __rust_allocate(size: usize, align: usize) -> *mut u8; + fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); + fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8; + fn __rust_reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize; + fn __rust_usable_size(size: usize, align: usize) -> usize; +} + +#[inline(always)] +fn check_size_and_alignment(size: usize, align: usize) { + debug_assert!(size != 0); + debug_assert!(size <= isize::MAX as usize, + "Tried to allocate too much: {} bytes", + size); + debug_assert!(usize::is_power_of_two(align), + "Invalid alignment of allocation: {}", + align); +} + +// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` + +/// Return a pointer to `size` bytes of memory aligned to `align`. +/// +/// On failure, return a null pointer. +/// +/// Behavior is undefined if the requested size is 0 or the alignment is not a +/// power of 2. The alignment must be no larger than the largest supported page +/// size on the platform. +#[inline] +pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); + __rust_allocate(size, align) +} + +/// Resize the allocation referenced by `ptr` to `size` bytes. +/// +/// On failure, return a null pointer and leave the original allocation intact. +/// +/// If the allocation was relocated, the memory at the passed-in pointer is +/// undefined after the call. +/// +/// Behavior is undefined if the requested size is 0 or the alignment is not a +/// power of 2. The alignment must be no larger than the largest supported page +/// size on the platform. +/// +/// The `old_size` and `align` parameters are the parameters that were used to +/// create the allocation referenced by `ptr`. The `old_size` parameter may be +/// any value in range_inclusive(requested_size, usable_size). +#[inline] +pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); + __rust_reallocate(ptr, old_size, size, align) +} + +/// Resize the allocation referenced by `ptr` to `size` bytes. +/// +/// If the operation succeeds, it returns `usable_size(size, align)` and if it +/// fails (or is a no-op) it returns `usable_size(old_size, align)`. +/// +/// Behavior is undefined if the requested size is 0 or the alignment is not a +/// power of 2. The alignment must be no larger than the largest supported page +/// size on the platform. +/// +/// The `old_size` and `align` parameters are the parameters that were used to +/// create the allocation referenced by `ptr`. The `old_size` parameter may be +/// any value in range_inclusive(requested_size, usable_size). +#[inline] +pub unsafe fn reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize { + check_size_and_alignment(size, align); + __rust_reallocate_inplace(ptr, old_size, size, align) +} + +/// Deallocates the memory referenced by `ptr`. +/// +/// The `ptr` parameter must not be null. +/// +/// The `old_size` and `align` parameters are the parameters that were used to +/// create the allocation referenced by `ptr`. The `old_size` parameter may be +/// any value in range_inclusive(requested_size, usable_size). +#[inline] +pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) { + __rust_deallocate(ptr, old_size, align) +} + +/// Returns the usable size of an allocation created with the specified the +/// `size` and `align`. +#[inline] +pub fn usable_size(size: usize, align: usize) -> usize { + unsafe { __rust_usable_size(size, align) } +} + +/// An arbitrary non-null address to represent zero-size allocations. +/// +/// This preserves the non-null invariant for types like `Box<T>`. The address +/// may overlap with non-zero-size memory allocations. +pub const EMPTY: *mut () = 0x1 as *mut (); + +/// The allocator for unique pointers. +#[cfg(not(test))] +#[lang = "exchange_malloc"] +#[inline] +unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { + if size == 0 { + EMPTY as *mut u8 + } else { + let ptr = allocate(size, align); + if ptr.is_null() { + ::oom() + } + ptr + } +} + +#[cfg(not(test))] +#[lang = "exchange_free"] +#[inline] +unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { + deallocate(ptr, old_size, align); +} + +#[cfg(not(test))] +#[lang = "box_free"] +#[inline] +unsafe fn box_free<T>(ptr: *mut T) { + let size = size_of::<T>(); + // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. + if size != 0 { + deallocate(ptr as *mut u8, size, min_align_of::<T>()); + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::test::Bencher; + use boxed::Box; + use heap; + + #[test] + fn basic_reallocate_inplace_noop() { + unsafe { + let size = 4000; + let ptr = heap::allocate(size, 8); + if ptr.is_null() { + ::oom() + } + let ret = heap::reallocate_inplace(ptr, size, size, 8); + heap::deallocate(ptr, size, 8); + assert_eq!(ret, heap::usable_size(size, 8)); + } + } + + #[bench] + fn alloc_owned_small(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = box 10; + }) + } +} |