]> git.lizzy.rs Git - rust.git/blob - src/liballoc_system/old.rs
rustc: Implement the #[global_allocator] attribute
[rust.git] / src / liballoc_system / old.rs
1 // Copyright 2017 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 #[no_mangle]
12 pub unsafe extern fn __rust_alloc(size: usize,
13                                   align: usize,
14                                   err: *mut u8) -> *mut u8 {
15     let p = imp::allocate(size, align);
16     if p.is_null() {
17         __rust_oom(err);
18     }
19     p
20 }
21
22 #[no_mangle]
23 pub unsafe extern fn __rust_oom(_err: *const u8) -> ! {
24     ::core::intrinsics::abort()
25 }
26
27 #[no_mangle]
28 pub unsafe extern fn __rust_dealloc(ptr: *mut u8,
29                                     size: usize,
30                                     align: usize) {
31     imp::deallocate(ptr, size, align)
32 }
33
34 #[no_mangle]
35 pub unsafe extern fn __rust_usable_size(size: usize,
36                                         _align: usize,
37                                         min: *mut usize,
38                                         max: *mut usize) {
39     *min = size;
40     *max = size;
41 }
42
43 #[no_mangle]
44 pub unsafe extern fn __rust_realloc(ptr: *mut u8,
45                                     old_size: usize,
46                                     old_align: usize,
47                                     new_size: usize,
48                                     new_align: usize,
49                                     err: *mut u8) -> *mut u8 {
50     if new_align != old_align {
51         __rust_oom(err);
52     }
53     let p = imp::reallocate(ptr, old_size, new_size, new_align);
54     if p.is_null() {
55         __rust_oom(err);
56     }
57     p
58 }
59
60 #[no_mangle]
61 pub unsafe extern fn __rust_alloc_zeroed(size: usize,
62                                          align: usize,
63                                          err: *mut u8) -> *mut u8 {
64     let p = imp::allocate_zeroed(size, align);
65     if p.is_null() {
66         __rust_oom(err);
67     }
68     p
69 }
70
71 #[no_mangle]
72 pub unsafe extern fn __rust_alloc_excess(_size: usize,
73                                          _align: usize,
74                                          _excess: *mut usize,
75                                          err: *mut u8) -> *mut u8 {
76     __rust_oom(err);
77 }
78
79 #[no_mangle]
80 pub unsafe extern fn __rust_realloc_excess(_ptr: *mut u8,
81                                            _old_size: usize,
82                                            _old_align: usize,
83                                            _new_size: usize,
84                                            _new_align: usize,
85                                            _excess: *mut usize,
86                                            err: *mut u8) -> *mut u8 {
87     __rust_oom(err);
88 }
89
90 #[no_mangle]
91 pub unsafe extern fn __rust_grow_in_place(_ptr: *mut u8,
92                                           _old_size: usize,
93                                           _old_align: usize,
94                                           _new_size: usize,
95                                           _new_align: usize) -> u8 {
96     0
97 }
98
99 #[no_mangle]
100 pub unsafe extern fn __rust_shrink_in_place(_ptr: *mut u8,
101                                             _old_size: usize,
102                                             _old_align: usize,
103                                             _new_size: usize,
104                                             _new_align: usize) -> u8 {
105     0
106 }
107
108 #[cfg(any(unix, target_os = "redox"))]
109 mod imp {
110     extern crate libc;
111
112     use core::cmp;
113     use core::ptr;
114     use MIN_ALIGN;
115
116     pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
117         if align <= MIN_ALIGN {
118             libc::malloc(size as libc::size_t) as *mut u8
119         } else {
120             aligned_malloc(size, align)
121         }
122     }
123
124     #[cfg(any(target_os = "android", target_os = "redox"))]
125     unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
126         // On android we currently target API level 9 which unfortunately
127         // doesn't have the `posix_memalign` API used below. Instead we use
128         // `memalign`, but this unfortunately has the property on some systems
129         // where the memory returned cannot be deallocated by `free`!
130         //
131         // Upon closer inspection, however, this appears to work just fine with
132         // Android, so for this platform we should be fine to call `memalign`
133         // (which is present in API level 9). Some helpful references could
134         // possibly be chromium using memalign [1], attempts at documenting that
135         // memalign + free is ok [2] [3], or the current source of chromium
136         // which still uses memalign on android [4].
137         //
138         // [1]: https://codereview.chromium.org/10796020/
139         // [2]: https://code.google.com/p/android/issues/detail?id=35391
140         // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
141         // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
142         //                                       /memory/aligned_memory.cc
143         libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
144     }
145
146     #[cfg(not(any(target_os = "android", target_os = "redox")))]
147     unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
148         let mut out = ptr::null_mut();
149         let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
150         if ret != 0 {
151             ptr::null_mut()
152         } else {
153             out as *mut u8
154         }
155     }
156
157     pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
158         if align <= MIN_ALIGN {
159             libc::calloc(size as libc::size_t, 1) as *mut u8
160         } else {
161             let ptr = aligned_malloc(size, align);
162             if !ptr.is_null() {
163                 ptr::write_bytes(ptr, 0, size);
164             }
165             ptr
166         }
167     }
168
169     pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
170         if align <= MIN_ALIGN {
171             libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
172         } else {
173             let new_ptr = allocate(size, align);
174             if !new_ptr.is_null() {
175                 ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
176                 deallocate(ptr, old_size, align);
177             }
178             new_ptr
179         }
180     }
181
182     pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
183         libc::free(ptr as *mut libc::c_void)
184     }
185 }
186
187 #[cfg(windows)]
188 #[allow(bad_style)]
189 mod imp {
190     use core::cmp::min;
191     use core::ptr::copy_nonoverlapping;
192     use MIN_ALIGN;
193
194     type LPVOID = *mut u8;
195     type HANDLE = LPVOID;
196     type SIZE_T = usize;
197     type DWORD = u32;
198     type BOOL = i32;
199
200     extern "system" {
201         fn GetProcessHeap() -> HANDLE;
202         fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
203         fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
204         fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
205         fn GetLastError() -> DWORD;
206     }
207
208     #[repr(C)]
209     struct Header(*mut u8);
210
211
212     const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
213
214     unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
215         &mut *(ptr as *mut Header).offset(-1)
216     }
217
218     unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
219         let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
220         *get_header(aligned) = Header(ptr);
221         aligned
222     }
223
224     #[inline]
225     unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 {
226         if align <= MIN_ALIGN {
227             HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8
228         } else {
229             let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8;
230             if ptr.is_null() {
231                 return ptr;
232             }
233             align_ptr(ptr, align)
234         }
235     }
236
237     pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
238         allocate_with_flags(size, align, 0)
239     }
240
241     pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
242         allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
243     }
244
245     pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
246         if align <= MIN_ALIGN {
247             HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
248         } else {
249             let new = allocate(size, align);
250             if !new.is_null() {
251                 copy_nonoverlapping(ptr, new, min(size, old_size));
252                 deallocate(ptr, old_size, align);
253             }
254             new
255         }
256     }
257
258     pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
259         if align <= MIN_ALIGN {
260             let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
261             debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
262         } else {
263             let header = get_header(ptr);
264             let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
265             debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
266         }
267     }
268 }