]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
62682a34 SL |
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 \ | |
e9174d1e SL |
15 | tracing garbage collector", |
16 | issue = "27700")] | |
62682a34 | 17 | |
d9579d0f AL |
18 | use core::{isize, usize}; |
19 | ||
e9174d1e | 20 | #[allow(improper_ctypes)] |
92a42be0 | 21 | extern "C" { |
e9174d1e SL |
22 | #[allocator] |
23 | fn __rust_allocate(size: usize, align: usize) -> *mut u8; | |
24 | fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); | |
b039eaaf SL |
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; | |
e9174d1e SL |
31 | fn __rust_usable_size(size: usize, align: usize) -> usize; |
32 | } | |
33 | ||
d9579d0f AL |
34 | #[inline(always)] |
35 | fn check_size_and_alignment(size: usize, align: usize) { | |
36 | debug_assert!(size != 0); | |
b039eaaf SL |
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); | |
d9579d0f AL |
43 | } |
44 | ||
1a4d82fc JJ |
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] | |
85aaf69f | 55 | pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { |
d9579d0f | 56 | check_size_and_alignment(size, align); |
e9174d1e | 57 | __rust_allocate(size, align) |
1a4d82fc JJ |
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 | /// | |
c34b1796 AL |
64 | /// If the allocation was relocated, the memory at the passed-in pointer is |
65 | /// undefined after the call. | |
66 | /// | |
1a4d82fc JJ |
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] | |
85aaf69f | 75 | pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { |
d9579d0f | 76 | check_size_and_alignment(size, align); |
e9174d1e | 77 | __rust_reallocate(ptr, old_size, size, align) |
1a4d82fc JJ |
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] | |
b039eaaf SL |
93 | pub unsafe fn reallocate_inplace(ptr: *mut u8, |
94 | old_size: usize, | |
95 | size: usize, | |
96 | align: usize) | |
97 | -> usize { | |
d9579d0f | 98 | check_size_and_alignment(size, align); |
e9174d1e | 99 | __rust_reallocate_inplace(ptr, old_size, size, align) |
1a4d82fc JJ |
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] | |
85aaf69f | 110 | pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) { |
e9174d1e | 111 | __rust_deallocate(ptr, old_size, align) |
1a4d82fc JJ |
112 | } |
113 | ||
114 | /// Returns the usable size of an allocation created with the specified the | |
115 | /// `size` and `align`. | |
116 | #[inline] | |
85aaf69f | 117 | pub fn usable_size(size: usize, align: usize) -> usize { |
e9174d1e | 118 | unsafe { __rust_usable_size(size, align) } |
1a4d82fc JJ |
119 | } |
120 | ||
121 | /// An arbitrary non-null address to represent zero-size allocations. | |
122 | /// | |
e9174d1e SL |
123 | /// This preserves the non-null invariant for types like `Box<T>`. The address |
124 | /// may overlap with non-zero-size memory allocations. | |
1a4d82fc JJ |
125 | pub const EMPTY: *mut () = 0x1 as *mut (); |
126 | ||
127 | /// The allocator for unique pointers. | |
128 | #[cfg(not(test))] | |
d9579d0f | 129 | #[lang = "exchange_malloc"] |
1a4d82fc | 130 | #[inline] |
85aaf69f | 131 | unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { |
1a4d82fc JJ |
132 | if size == 0 { |
133 | EMPTY as *mut u8 | |
134 | } else { | |
135 | let ptr = allocate(size, align); | |
b039eaaf SL |
136 | if ptr.is_null() { |
137 | ::oom() | |
138 | } | |
1a4d82fc JJ |
139 | ptr |
140 | } | |
141 | } | |
142 | ||
143 | #[cfg(not(test))] | |
d9579d0f | 144 | #[lang = "exchange_free"] |
1a4d82fc | 145 | #[inline] |
85aaf69f | 146 | unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { |
1a4d82fc JJ |
147 | deallocate(ptr, old_size, align); |
148 | } | |
149 | ||
1a4d82fc | 150 | #[cfg(test)] |
d9579d0f | 151 | mod tests { |
1a4d82fc JJ |
152 | extern crate test; |
153 | use self::test::Bencher; | |
c34b1796 | 154 | use boxed::Box; |
1a4d82fc JJ |
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); | |
b039eaaf SL |
162 | if ptr.is_null() { |
163 | ::oom() | |
164 | } | |
1a4d82fc JJ |
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(|| { | |
c34b1796 | 174 | let _: Box<_> = box 10; |
1a4d82fc JJ |
175 | }) |
176 | } | |
177 | } |