]> git.lizzy.rs Git - rust.git/blob - src/liballoc/heap.rs
Do not show `::constructor` on tuple struct diagnostics
[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 #[cfg(not(test))]
20 use core::intrinsics::{min_align_of_val, size_of_val};
21
22 #[allow(improper_ctypes)]
23 extern "C" {
24     #[allocator]
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,
30                                  old_size: usize,
31                                  size: usize,
32                                  align: usize)
33                                  -> usize;
34     fn __rust_usable_size(size: usize, align: usize) -> usize;
35 }
36
37 #[inline(always)]
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",
42                   size);
43     debug_assert!(usize::is_power_of_two(align),
44                   "Invalid alignment of allocation: {}",
45                   align);
46 }
47
48 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
49
50 /// Return a pointer to `size` bytes of memory aligned to `align`.
51 ///
52 /// On failure, return a null pointer.
53 ///
54 /// Behavior is undefined if the requested size is 0 or the alignment is not a
55 /// power of 2. The alignment must be no larger than the largest supported page
56 /// size on the platform.
57 #[inline]
58 pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
59     check_size_and_alignment(size, align);
60     __rust_allocate(size, align)
61 }
62
63 /// Return a pointer to `size` bytes of memory aligned to `align` and
64 /// initialized to zeroes.
65 ///
66 /// On failure, return a null pointer.
67 ///
68 /// Behavior is undefined if the requested size is 0 or the alignment is not a
69 /// power of 2. The alignment must be no larger than the largest supported page
70 /// size on the platform.
71 #[inline]
72 pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
73     check_size_and_alignment(size, align);
74     __rust_allocate_zeroed(size, align)
75 }
76
77 /// Resize the allocation referenced by `ptr` to `size` bytes.
78 ///
79 /// On failure, return a null pointer and leave the original allocation intact.
80 ///
81 /// If the allocation was relocated, the memory at the passed-in pointer is
82 /// undefined after the call.
83 ///
84 /// Behavior is undefined if the requested size is 0 or the alignment is not a
85 /// power of 2. The alignment must be no larger than the largest supported page
86 /// size on the platform.
87 ///
88 /// The `old_size` and `align` parameters are the parameters that were used to
89 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
90 /// any value in range_inclusive(requested_size, usable_size).
91 #[inline]
92 pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
93     check_size_and_alignment(size, align);
94     __rust_reallocate(ptr, old_size, size, align)
95 }
96
97 /// Resize the allocation referenced by `ptr` to `size` bytes.
98 ///
99 /// If the operation succeeds, it returns `usable_size(size, align)` and if it
100 /// fails (or is a no-op) it returns `usable_size(old_size, align)`.
101 ///
102 /// Behavior is undefined if the requested size is 0 or the alignment is not a
103 /// power of 2. The alignment must be no larger than the largest supported page
104 /// size on the platform.
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 reallocate_inplace(ptr: *mut u8,
111                                  old_size: usize,
112                                  size: usize,
113                                  align: usize)
114                                  -> usize {
115     check_size_and_alignment(size, align);
116     __rust_reallocate_inplace(ptr, old_size, size, align)
117 }
118
119 /// Deallocates the memory referenced by `ptr`.
120 ///
121 /// The `ptr` parameter must not be null.
122 ///
123 /// The `old_size` and `align` parameters are the parameters that were used to
124 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
125 /// any value in range_inclusive(requested_size, usable_size).
126 #[inline]
127 pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
128     __rust_deallocate(ptr, old_size, align)
129 }
130
131 /// Returns the usable size of an allocation created with the specified the
132 /// `size` and `align`.
133 #[inline]
134 pub fn usable_size(size: usize, align: usize) -> usize {
135     unsafe { __rust_usable_size(size, align) }
136 }
137
138 /// An arbitrary non-null address to represent zero-size allocations.
139 ///
140 /// This preserves the non-null invariant for types like `Box<T>`. The address
141 /// may overlap with non-zero-size memory allocations.
142 pub const EMPTY: *mut () = 0x1 as *mut ();
143
144 /// The allocator for unique pointers.
145 // This function must not unwind. If it does, MIR trans will fail.
146 #[cfg(not(test))]
147 #[lang = "exchange_malloc"]
148 #[inline]
149 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
150     if size == 0 {
151         EMPTY as *mut u8
152     } else {
153         let ptr = allocate(size, align);
154         if ptr.is_null() {
155             ::oom()
156         }
157         ptr
158     }
159 }
160
161 #[cfg(not(test))]
162 #[lang = "box_free"]
163 #[inline]
164 unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
165     let size = size_of_val(&*ptr);
166     let align = min_align_of_val(&*ptr);
167     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
168     if size != 0 {
169         deallocate(ptr as *mut u8, size, align);
170     }
171 }
172
173 #[cfg(test)]
174 mod tests {
175     extern crate test;
176     use self::test::Bencher;
177     use boxed::Box;
178     use heap;
179
180     #[test]
181     fn allocate_zeroed() {
182         unsafe {
183             let size = 1024;
184             let ptr = heap::allocate_zeroed(size, 1);
185             if ptr.is_null() {
186                 ::oom()
187             }
188
189             let end = ptr.offset(size as isize);
190             let mut i = ptr;
191             while i < end {
192                 assert_eq!(*i, 0);
193                 i = i.offset(1);
194             }
195             heap::deallocate(ptr, size, 1);
196         }
197     }
198
199     #[test]
200     fn basic_reallocate_inplace_noop() {
201         unsafe {
202             let size = 4000;
203             let ptr = heap::allocate(size, 8);
204             if ptr.is_null() {
205                 ::oom()
206             }
207             let ret = heap::reallocate_inplace(ptr, size, size, 8);
208             heap::deallocate(ptr, size, 8);
209             assert_eq!(ret, heap::usable_size(size, 8));
210         }
211     }
212
213     #[bench]
214     fn alloc_owned_small(b: &mut Bencher) {
215         b.iter(|| {
216             let _: Box<_> = box 10;
217         })
218     }
219 }