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