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