]> git.lizzy.rs Git - rust.git/blob - src/liballoc/heap.rs
Rollup merge of #31295 - steveklabnik:gh31266, r=alexcrichton
[rust.git] / src / liballoc / heap.rs
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.
4 //
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.
10
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",
16             issue = "27700")]
17
18 use core::{isize, usize};
19
20 #[allow(improper_ctypes)]
21 extern "C" {
22     #[allocator]
23     fn __rust_allocate(size: usize, align: usize) -> *mut u8;
24     fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
25     fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
26     fn __rust_reallocate_inplace(ptr: *mut u8,
27                                  old_size: usize,
28                                  size: usize,
29                                  align: usize)
30                                  -> usize;
31     fn __rust_usable_size(size: usize, align: usize) -> usize;
32 }
33
34 #[inline(always)]
35 fn check_size_and_alignment(size: usize, align: usize) {
36     debug_assert!(size != 0);
37     debug_assert!(size <= isize::MAX as usize,
38                   "Tried to allocate too much: {} bytes",
39                   size);
40     debug_assert!(usize::is_power_of_two(align),
41                   "Invalid alignment of allocation: {}",
42                   align);
43 }
44
45 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
46
47 /// Return a pointer to `size` bytes of memory aligned to `align`.
48 ///
49 /// On failure, return a null pointer.
50 ///
51 /// Behavior is undefined if the requested size is 0 or the alignment is not a
52 /// power of 2. The alignment must be no larger than the largest supported page
53 /// size on the platform.
54 #[inline]
55 pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
56     check_size_and_alignment(size, align);
57     __rust_allocate(size, align)
58 }
59
60 /// Resize the allocation referenced by `ptr` to `size` bytes.
61 ///
62 /// On failure, return a null pointer and leave the original allocation intact.
63 ///
64 /// If the allocation was relocated, the memory at the passed-in pointer is
65 /// undefined after the call.
66 ///
67 /// Behavior is undefined if the requested size is 0 or the alignment is not a
68 /// power of 2. The alignment must be no larger than the largest supported page
69 /// size on the platform.
70 ///
71 /// The `old_size` and `align` parameters are the parameters that were used to
72 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
73 /// any value in range_inclusive(requested_size, usable_size).
74 #[inline]
75 pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
76     check_size_and_alignment(size, align);
77     __rust_reallocate(ptr, old_size, size, align)
78 }
79
80 /// Resize the allocation referenced by `ptr` to `size` bytes.
81 ///
82 /// If the operation succeeds, it returns `usable_size(size, align)` and if it
83 /// fails (or is a no-op) it returns `usable_size(old_size, align)`.
84 ///
85 /// Behavior is undefined if the requested size is 0 or the alignment is not a
86 /// power of 2. The alignment must be no larger than the largest supported page
87 /// size on the platform.
88 ///
89 /// The `old_size` and `align` parameters are the parameters that were used to
90 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
91 /// any value in range_inclusive(requested_size, usable_size).
92 #[inline]
93 pub unsafe fn reallocate_inplace(ptr: *mut u8,
94                                  old_size: usize,
95                                  size: usize,
96                                  align: usize)
97                                  -> usize {
98     check_size_and_alignment(size, align);
99     __rust_reallocate_inplace(ptr, old_size, size, align)
100 }
101
102 /// Deallocates the memory referenced by `ptr`.
103 ///
104 /// The `ptr` parameter must not be null.
105 ///
106 /// The `old_size` and `align` parameters are the parameters that were used to
107 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
108 /// any value in range_inclusive(requested_size, usable_size).
109 #[inline]
110 pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
111     __rust_deallocate(ptr, old_size, align)
112 }
113
114 /// Returns the usable size of an allocation created with the specified the
115 /// `size` and `align`.
116 #[inline]
117 pub fn usable_size(size: usize, align: usize) -> usize {
118     unsafe { __rust_usable_size(size, align) }
119 }
120
121 /// An arbitrary non-null address to represent zero-size allocations.
122 ///
123 /// This preserves the non-null invariant for types like `Box<T>`. The address
124 /// may overlap with non-zero-size memory allocations.
125 pub const EMPTY: *mut () = 0x1 as *mut ();
126
127 /// The allocator for unique pointers.
128 #[cfg(not(test))]
129 #[lang = "exchange_malloc"]
130 #[inline]
131 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
132     if size == 0 {
133         EMPTY as *mut u8
134     } else {
135         let ptr = allocate(size, align);
136         if ptr.is_null() {
137             ::oom()
138         }
139         ptr
140     }
141 }
142
143 #[cfg(not(test))]
144 #[lang = "exchange_free"]
145 #[inline]
146 unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
147     deallocate(ptr, old_size, align);
148 }
149
150 #[cfg(test)]
151 mod tests {
152     extern crate test;
153     use self::test::Bencher;
154     use boxed::Box;
155     use heap;
156
157     #[test]
158     fn basic_reallocate_inplace_noop() {
159         unsafe {
160             let size = 4000;
161             let ptr = heap::allocate(size, 8);
162             if ptr.is_null() {
163                 ::oom()
164             }
165             let ret = heap::reallocate_inplace(ptr, size, size, 8);
166             heap::deallocate(ptr, size, 8);
167             assert_eq!(ret, heap::usable_size(size, 8));
168         }
169     }
170
171     #[bench]
172     fn alloc_owned_small(b: &mut Bencher) {
173         b.iter(|| {
174             let _: Box<_> = box 10;
175         })
176     }
177 }