]> git.lizzy.rs Git - rust.git/blob - src/liballoc/heap.rs
Removed some unnecessary RefCells from resolve
[rust.git] / src / liballoc / heap.rs
1 // Copyright 2014 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 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
12
13 /// Returns a pointer to `size` bytes of memory.
14 ///
15 /// Behavior is undefined if the requested size is 0 or the alignment is not a
16 /// power of 2. The alignment must be no larger than the largest supported page
17 /// size on the platform.
18 #[inline]
19 pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
20     imp::allocate(size, align)
21 }
22
23 /// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
24 /// memory.
25 ///
26 /// Behavior is undefined if the requested size is 0 or the alignment is not a
27 /// power of 2. The alignment must be no larger than the largest supported page
28 /// size on the platform.
29 ///
30 /// The `old_size` and `align` parameters are the parameters that were used to
31 /// create the allocation referenced by `ptr`. The `old_size` parameter may also
32 /// be the value returned by `usable_size` for the requested size.
33 #[inline]
34 pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
35                          old_size: uint) -> *mut u8 {
36     imp::reallocate(ptr, size, align, old_size)
37 }
38
39 /// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
40 /// memory in-place.
41 ///
42 /// Returns true if successful, otherwise false if the allocation was not
43 /// altered.
44 ///
45 /// Behavior is undefined if the requested size is 0 or the alignment is not a
46 /// power of 2. The alignment must be no larger than the largest supported page
47 /// size on the platform.
48 ///
49 /// The `old_size` and `align` parameters are the parameters that were used to
50 /// create the allocation referenced by `ptr`. The `old_size` parameter may be
51 /// any value in range_inclusive(requested_size, usable_size).
52 #[inline]
53 pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
54                                  old_size: uint) -> bool {
55     imp::reallocate_inplace(ptr, size, align, old_size)
56 }
57
58 /// Deallocates the memory referenced by `ptr`.
59 ///
60 /// The `ptr` parameter must not be null.
61 ///
62 /// The `size` and `align` parameters are the parameters that were used to
63 /// create the allocation referenced by `ptr`. The `size` parameter may also be
64 /// the value returned by `usable_size` for the requested size.
65 #[inline]
66 pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
67     imp::deallocate(ptr, size, align)
68 }
69
70 /// Returns the usable size of an allocation created with the specified the
71 /// `size` and `align`.
72 #[inline]
73 pub fn usable_size(size: uint, align: uint) -> uint {
74     imp::usable_size(size, align)
75 }
76
77 /// Prints implementation-defined allocator statistics.
78 ///
79 /// These statistics may be inconsistent if other threads use the allocator
80 /// during the call.
81 #[unstable]
82 pub fn stats_print() {
83     imp::stats_print();
84 }
85
86 /// An arbitrary non-null address to represent zero-size allocations.
87 ///
88 /// This preserves the non-null invariant for types like `Box<T>`. The address may overlap with
89 /// non-zero-size memory allocations.
90 pub static EMPTY: *mut () = 0x1 as *mut ();
91
92 /// The allocator for unique pointers.
93 #[cfg(not(test))]
94 #[lang="exchange_malloc"]
95 #[inline]
96 unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
97     if size == 0 {
98         EMPTY as *mut u8
99     } else {
100         allocate(size, align)
101     }
102 }
103
104 #[cfg(not(test))]
105 #[lang="exchange_free"]
106 #[inline]
107 unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
108     deallocate(ptr, size, align);
109 }
110
111 // The minimum alignment guaranteed by the architecture. This value is used to
112 // add fast paths for low alignment values. In practice, the alignment is a
113 // constant at the call site and the branch will be optimized out.
114 #[cfg(target_arch = "arm")]
115 #[cfg(target_arch = "mips")]
116 #[cfg(target_arch = "mipsel")]
117 static MIN_ALIGN: uint = 8;
118 #[cfg(target_arch = "x86")]
119 #[cfg(target_arch = "x86_64")]
120 static MIN_ALIGN: uint = 16;
121
122 #[cfg(jemalloc)]
123 mod imp {
124     use core::option::{None, Option};
125     use core::ptr::{RawPtr, null_mut, null};
126     use core::num::Int;
127     use libc::{c_char, c_int, c_void, size_t};
128     use super::MIN_ALIGN;
129
130     #[link(name = "jemalloc", kind = "static")]
131     #[cfg(not(test))]
132     extern {}
133
134     extern {
135         fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
136         fn je_rallocx(ptr: *mut c_void, size: size_t,
137                       flags: c_int) -> *mut c_void;
138         fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
139                       flags: c_int) -> size_t;
140         fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
141         fn je_nallocx(size: size_t, flags: c_int) -> size_t;
142         fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
143                                                                 *const c_char)>,
144                                  cbopaque: *mut c_void,
145                                  opts: *const c_char);
146     }
147
148     // -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
149     #[cfg(not(windows), not(target_os = "android"))]
150     #[link(name = "pthread")]
151     extern {}
152
153     // MALLOCX_ALIGN(a) macro
154     #[inline(always)]
155     fn mallocx_align(a: uint) -> c_int { a.trailing_zeros() as c_int }
156
157     #[inline(always)]
158     fn align_to_flags(align: uint) -> c_int {
159         if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
160     }
161
162     #[inline]
163     pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
164         let flags = align_to_flags(align);
165         let ptr = je_mallocx(size as size_t, flags) as *mut u8;
166         if ptr.is_null() {
167             ::oom()
168         }
169         ptr
170     }
171
172     #[inline]
173     pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
174                              _old_size: uint) -> *mut u8 {
175         let flags = align_to_flags(align);
176         let ptr = je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8;
177         if ptr.is_null() {
178             ::oom()
179         }
180         ptr
181     }
182
183     #[inline]
184     pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
185                                      _old_size: uint) -> bool {
186         let flags = align_to_flags(align);
187         je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) == size as size_t
188     }
189
190     #[inline]
191     pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
192         let flags = align_to_flags(align);
193         je_sdallocx(ptr as *mut c_void, size as size_t, flags)
194     }
195
196     #[inline]
197     pub fn usable_size(size: uint, align: uint) -> uint {
198         let flags = align_to_flags(align);
199         unsafe { je_nallocx(size as size_t, flags) as uint }
200     }
201
202     pub fn stats_print() {
203         unsafe {
204             je_malloc_stats_print(None, null_mut(), null())
205         }
206     }
207 }
208
209 #[cfg(not(jemalloc), unix)]
210 mod imp {
211     use core::cmp;
212     use core::ptr;
213     use libc;
214     use libc_heap;
215     use super::MIN_ALIGN;
216
217     extern {
218         fn posix_memalign(memptr: *mut *mut libc::c_void,
219                           align: libc::size_t,
220                           size: libc::size_t) -> libc::c_int;
221     }
222
223     #[inline]
224     pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
225         if align <= MIN_ALIGN {
226             libc_heap::malloc_raw(size)
227         } else {
228             let mut out = 0 as *mut libc::c_void;
229             let ret = posix_memalign(&mut out,
230                                      align as libc::size_t,
231                                      size as libc::size_t);
232             if ret != 0 {
233                 ::oom();
234             }
235             out as *mut u8
236         }
237     }
238
239     #[inline]
240     pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
241                              old_size: uint) -> *mut u8 {
242         if align <= MIN_ALIGN {
243             libc_heap::realloc_raw(ptr, size)
244         } else {
245             let new_ptr = allocate(size, align);
246             ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
247             deallocate(ptr, old_size, align);
248             new_ptr
249         }
250     }
251
252     #[inline]
253     pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
254                                      _old_size: uint) -> bool {
255         false
256     }
257
258     #[inline]
259     pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
260         libc::free(ptr as *mut libc::c_void)
261     }
262
263     #[inline]
264     pub fn usable_size(size: uint, _align: uint) -> uint {
265         size
266     }
267
268     pub fn stats_print() {}
269 }
270
271 #[cfg(not(jemalloc), windows)]
272 mod imp {
273     use libc::{c_void, size_t};
274     use libc;
275     use libc_heap;
276     use core::ptr::RawPtr;
277     use super::MIN_ALIGN;
278
279     extern {
280         fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
281         fn _aligned_realloc(block: *mut c_void, size: size_t,
282                             align: size_t) -> *mut c_void;
283         fn _aligned_free(ptr: *mut c_void);
284     }
285
286     #[inline]
287     pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
288         if align <= MIN_ALIGN {
289             libc_heap::malloc_raw(size)
290         } else {
291             let ptr = _aligned_malloc(size as size_t, align as size_t);
292             if ptr.is_null() {
293                 ::oom();
294             }
295             ptr as *mut u8
296         }
297     }
298
299     #[inline]
300     pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
301                              _old_size: uint) -> *mut u8 {
302         if align <= MIN_ALIGN {
303             libc_heap::realloc_raw(ptr, size)
304         } else {
305             let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
306                                        align as size_t);
307             if ptr.is_null() {
308                 ::oom();
309             }
310             ptr as *mut u8
311         }
312     }
313
314     #[inline]
315     pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
316                                      _old_size: uint) -> bool {
317         false
318     }
319
320     #[inline]
321     pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
322         if align <= MIN_ALIGN {
323             libc::free(ptr as *mut libc::c_void)
324         } else {
325             _aligned_free(ptr as *mut c_void)
326         }
327     }
328
329     #[inline]
330     pub fn usable_size(size: uint, _align: uint) -> uint {
331         size
332     }
333
334     pub fn stats_print() {}
335 }
336
337 #[cfg(test)]
338 mod bench {
339     extern crate test;
340     use self::test::Bencher;
341
342     #[bench]
343     fn alloc_owned_small(b: &mut Bencher) {
344         b.iter(|| {
345             box 10i
346         })
347     }
348 }