]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/example/alloc_system.rs
5f66ca67f2d409e9699c49a9fcda047c1e8c6ca9
[rust.git] / compiler / rustc_codegen_gcc / example / alloc_system.rs
1 // Copyright 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 #![no_std]
11 #![feature(allocator_api, rustc_private)]
12 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
13
14 // The minimum alignment guaranteed by the architecture. This value is used to
15 // add fast paths for low alignment values.
16 #[cfg(all(any(target_arch = "x86",
17               target_arch = "arm",
18               target_arch = "mips",
19               target_arch = "powerpc",
20               target_arch = "powerpc64")))]
21 const MIN_ALIGN: usize = 8;
22 #[cfg(all(any(target_arch = "x86_64",
23               target_arch = "aarch64",
24               target_arch = "mips64",
25               target_arch = "s390x",
26               target_arch = "sparc64")))]
27 const MIN_ALIGN: usize = 16;
28
29 pub struct System;
30 #[cfg(any(windows, unix, target_os = "redox"))]
31 mod realloc_fallback {
32     use core::alloc::{GlobalAlloc, Layout};
33     use core::cmp;
34     use core::ptr;
35     impl super::System {
36         pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
37                                               new_size: usize) -> *mut u8 {
38             // Docs for GlobalAlloc::realloc require this to be valid:
39             let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
40             let new_ptr = GlobalAlloc::alloc(self, new_layout);
41             if !new_ptr.is_null() {
42                 let size = cmp::min(old_layout.size(), new_size);
43                 ptr::copy_nonoverlapping(ptr, new_ptr, size);
44                 GlobalAlloc::dealloc(self, ptr, old_layout);
45             }
46             new_ptr
47         }
48     }
49 }
50 #[cfg(any(unix, target_os = "redox"))]
51 mod platform {
52     extern crate libc;
53     use core::ptr;
54     use MIN_ALIGN;
55     use System;
56     use core::alloc::{GlobalAlloc, Layout};
57     unsafe impl GlobalAlloc for System {
58         #[inline]
59         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
60             if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
61                 libc::malloc(layout.size()) as *mut u8
62             } else {
63                 #[cfg(target_os = "macos")]
64                 {
65                     if layout.align() > (1 << 31) {
66                         return ptr::null_mut()
67                     }
68                 }
69                 aligned_malloc(&layout)
70             }
71         }
72         #[inline]
73         unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
74             if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
75                 libc::calloc(layout.size(), 1) as *mut u8
76             } else {
77                 let ptr = self.alloc(layout.clone());
78                 if !ptr.is_null() {
79                     ptr::write_bytes(ptr, 0, layout.size());
80                 }
81                 ptr
82             }
83         }
84         #[inline]
85         unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
86             libc::free(ptr as *mut libc::c_void)
87         }
88         #[inline]
89         unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
90             if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
91                 libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
92             } else {
93                 self.realloc_fallback(ptr, layout, new_size)
94             }
95         }
96     }
97     #[cfg(any(target_os = "android",
98               target_os = "hermit",
99               target_os = "redox",
100               target_os = "solaris"))]
101     #[inline]
102     unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
103         // On android we currently target API level 9 which unfortunately
104         // doesn't have the `posix_memalign` API used below. Instead we use
105         // `memalign`, but this unfortunately has the property on some systems
106         // where the memory returned cannot be deallocated by `free`!
107         //
108         // Upon closer inspection, however, this appears to work just fine with
109         // Android, so for this platform we should be fine to call `memalign`
110         // (which is present in API level 9). Some helpful references could
111         // possibly be chromium using memalign [1], attempts at documenting that
112         // memalign + free is ok [2] [3], or the current source of chromium
113         // which still uses memalign on android [4].
114         //
115         // [1]: https://codereview.chromium.org/10796020/
116         // [2]: https://code.google.com/p/android/issues/detail?id=35391
117         // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
118         // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
119         //                                       /memory/aligned_memory.cc
120         libc::memalign(layout.align(), layout.size()) as *mut u8
121     }
122     #[cfg(not(any(target_os = "android",
123                   target_os = "hermit",
124                   target_os = "redox",
125                   target_os = "solaris")))]
126     #[inline]
127     unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
128         let mut out = ptr::null_mut();
129         let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
130         if ret != 0 {
131             ptr::null_mut()
132         } else {
133             out as *mut u8
134         }
135     }
136 }
137 #[cfg(windows)]
138 #[allow(nonstandard_style)]
139 mod platform {
140     use MIN_ALIGN;
141     use System;
142     use core::alloc::{GlobalAlloc, Layout};
143     type LPVOID = *mut u8;
144     type HANDLE = LPVOID;
145     type SIZE_T = usize;
146     type DWORD = u32;
147     type BOOL = i32;
148     extern "system" {
149         fn GetProcessHeap() -> HANDLE;
150         fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
151         fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
152         fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
153         fn GetLastError() -> DWORD;
154     }
155     #[repr(C)]
156     struct Header(*mut u8);
157     const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
158     unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
159         &mut *(ptr as *mut Header).offset(-1)
160     }
161     unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
162         let aligned = ptr.add(align - (ptr as usize & (align - 1)));
163         *get_header(aligned) = Header(ptr);
164         aligned
165     }
166     #[inline]
167     unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
168         let ptr = if layout.align() <= MIN_ALIGN {
169             HeapAlloc(GetProcessHeap(), flags, layout.size())
170         } else {
171             let size = layout.size() + layout.align();
172             let ptr = HeapAlloc(GetProcessHeap(), flags, size);
173             if ptr.is_null() {
174                 ptr
175             } else {
176                 align_ptr(ptr, layout.align())
177             }
178         };
179         ptr as *mut u8
180     }
181     unsafe impl GlobalAlloc for System {
182         #[inline]
183         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
184             allocate_with_flags(layout, 0)
185         }
186         #[inline]
187         unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
188             allocate_with_flags(layout, HEAP_ZERO_MEMORY)
189         }
190         #[inline]
191         unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
192             if layout.align() <= MIN_ALIGN {
193                 let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
194                 debug_assert!(err != 0, "Failed to free heap memory: {}",
195                               GetLastError());
196             } else {
197                 let header = get_header(ptr);
198                 let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
199                 debug_assert!(err != 0, "Failed to free heap memory: {}",
200                               GetLastError());
201             }
202         }
203         #[inline]
204         unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
205             if layout.align() <= MIN_ALIGN {
206                 HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
207             } else {
208                 self.realloc_fallback(ptr, layout, new_size)
209             }
210         }
211     }
212 }