aboutsummaryrefslogtreecommitdiff
path: root/liballoc/heap.rs
diff options
context:
space:
mode:
Diffstat (limited to 'liballoc/heap.rs')
-rw-r--r--liballoc/heap.rs190
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;
+ })
+ }
+}