1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![unstable(feature = "heap_api",
12 reason = "the precise API and guarantees it provides may be tweaked \
13 slightly, especially to possibly take into account the \
14 types being stored to make room for a future \
15 tracing garbage collector",
18 use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout};
19 use core::{isize, usize, cmp, ptr};
20 use core::intrinsics::{min_align_of_val, size_of_val};
22 #[allow(improper_ctypes)]
25 fn __rust_allocate(size: usize, align: usize) -> *mut u8;
26 fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8;
27 fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
28 fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
29 fn __rust_reallocate_inplace(ptr: *mut u8,
34 fn __rust_usable_size(size: usize, align: usize) -> usize;
38 fn check_size_and_alignment(size: usize, align: usize) {
39 debug_assert!(size != 0);
40 debug_assert!(size <= isize::MAX as usize,
41 "Tried to allocate too much: {} bytes",
43 debug_assert!(usize::is_power_of_two(align),
44 "Invalid alignment of allocation: {}",
48 #[derive(Copy, Clone, Default, Debug)]
51 unsafe impl Alloc for HeapAlloc {
52 unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
53 let addr = allocate(layout.size(), layout.align());
55 Err(AllocErr::Exhausted { request: layout })
61 unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
62 let addr = allocate_zeroed(layout.size(), layout.align());
64 Err(AllocErr::Exhausted { request: layout })
70 unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
71 deallocate(ptr, layout.size(), layout.align());
74 fn usable_size(&self, layout: &Layout) -> (usize, usize) {
75 (layout.size(), usable_size(layout.size(), layout.align()))
78 unsafe fn realloc(&mut self,
82 -> Result<*mut u8, AllocErr>
84 let old_size = layout.size();
85 let new_size = new_layout.size();
86 if layout.align() == new_layout.align() {
87 let new_ptr = reallocate(ptr, old_size, new_size, layout.align());
88 if new_ptr.is_null() {
89 // We assume `reallocate` already tried alloc + copy +
90 // dealloc fallback; thus pointless to repeat effort
91 Err(AllocErr::Exhausted { request: new_layout })
96 // if alignments don't match, fall back on alloc + copy + dealloc
97 let result = self.alloc(new_layout);
98 if let Ok(new_ptr) = result {
99 ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size));
100 self.dealloc(ptr, layout);
106 unsafe fn grow_in_place(&mut self,
110 -> Result<(), CannotReallocInPlace>
112 // grow_in_place spec requires this, and the spec for reallocate_inplace
113 // makes it hard to detect failure if it does not hold.
114 debug_assert!(new_layout.size() >= layout.size());
116 if layout.align() != new_layout.align() { // reallocate_inplace requires this.
117 return Err(CannotReallocInPlace);
119 let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align());
120 if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) }
124 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
126 /// Return a pointer to `size` bytes of memory aligned to `align`.
128 /// On failure, return a null pointer.
130 /// Behavior is undefined if the requested size is 0 or the alignment is not a
131 /// power of 2. The alignment must be no larger than the largest supported page
132 /// size on the platform.
134 pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
135 check_size_and_alignment(size, align);
136 __rust_allocate(size, align)
139 /// Return a pointer to `size` bytes of memory aligned to `align` and
140 /// initialized to zeroes.
142 /// On failure, return a null pointer.
144 /// Behavior is undefined if the requested size is 0 or the alignment is not a
145 /// power of 2. The alignment must be no larger than the largest supported page
146 /// size on the platform.
148 pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
149 check_size_and_alignment(size, align);
150 __rust_allocate_zeroed(size, align)
153 /// Resize the allocation referenced by `ptr` to `size` bytes.
155 /// On failure, return a null pointer and leave the original allocation intact.
157 /// If the allocation was relocated, the memory at the passed-in pointer is
158 /// undefined after the call.
160 /// Behavior is undefined if the requested size is 0 or the alignment is not a
161 /// power of 2. The alignment must be no larger than the largest supported page
162 /// size on the platform.
164 /// The `old_size` and `align` parameters are the parameters that were used to
165 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
166 /// any value in range_inclusive(requested_size, usable_size).
168 pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
169 check_size_and_alignment(size, align);
170 __rust_reallocate(ptr, old_size, size, align)
173 /// Resize the allocation referenced by `ptr` to `size` bytes.
175 /// If the operation succeeds, it returns `usable_size(size, align)` and if it
176 /// fails (or is a no-op) it returns `usable_size(old_size, align)`.
178 /// Behavior is undefined if the requested size is 0 or the alignment is not a
179 /// power of 2. The alignment must be no larger than the largest supported page
180 /// size on the platform.
182 /// The `old_size` and `align` parameters are the parameters that were used to
183 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
184 /// any value in range_inclusive(requested_size, usable_size).
186 pub unsafe fn reallocate_inplace(ptr: *mut u8,
191 check_size_and_alignment(size, align);
192 __rust_reallocate_inplace(ptr, old_size, size, align)
195 /// Deallocates the memory referenced by `ptr`.
197 /// The `ptr` parameter must not be null.
199 /// The `old_size` and `align` parameters are the parameters that were used to
200 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
201 /// any value in range_inclusive(requested_size, usable_size).
203 pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
204 __rust_deallocate(ptr, old_size, align)
207 /// Returns the usable size of an allocation created with the specified the
208 /// `size` and `align`.
210 pub fn usable_size(size: usize, align: usize) -> usize {
211 unsafe { __rust_usable_size(size, align) }
214 /// An arbitrary non-null address to represent zero-size allocations.
216 /// This preserves the non-null invariant for types like `Box<T>`. The address
217 /// may overlap with non-zero-size memory allocations.
218 #[rustc_deprecated(since = "1.19", reason = "Use Unique/Shared::empty() instead")]
219 #[unstable(feature = "heap_api", issue = "27700")]
220 pub const EMPTY: *mut () = 1 as *mut ();
222 /// The allocator for unique pointers.
223 // This function must not unwind. If it does, MIR trans will fail.
225 #[lang = "exchange_malloc"]
227 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
231 let ptr = allocate(size, align);
239 #[cfg_attr(not(test), lang = "box_free")]
241 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
242 let size = size_of_val(&*ptr);
243 let align = min_align_of_val(&*ptr);
244 // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
246 deallocate(ptr as *mut u8, size, align);
253 use self::test::Bencher;
258 fn allocate_zeroed() {
261 let ptr = heap::allocate_zeroed(size, 1);
266 let end = ptr.offset(size as isize);
272 heap::deallocate(ptr, size, 1);
277 fn basic_reallocate_inplace_noop() {
280 let ptr = heap::allocate(size, 8);
284 let ret = heap::reallocate_inplace(ptr, size, size, 8);
285 heap::deallocate(ptr, size, 8);
286 assert_eq!(ret, heap::usable_size(size, 8));
291 fn alloc_owned_small(b: &mut Bencher) {
293 let _: Box<_> = box 10;