]> git.lizzy.rs Git - rust.git/blob - src/liballoc_jemalloc/lib.rs
rustc: Implement the #[global_allocator] attribute
[rust.git] / src / liballoc_jemalloc / lib.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
11 #![crate_name = "alloc_jemalloc"]
12 #![crate_type = "rlib"]
13 #![no_std]
14 #![unstable(feature = "alloc_jemalloc",
15             reason = "this library is unlikely to be stabilized in its current \
16                       form or name",
17             issue = "27783")]
18 #![deny(warnings)]
19 #![feature(libc)]
20 #![feature(staged_api)]
21 #![feature(linkage)]
22 #![cfg_attr(stage0, allocator)]
23 #![cfg_attr(stage0, feature(allocator))]
24 #![cfg_attr(not(stage0), feature(global_allocator))]
25 #![cfg_attr(all(not(stage0), not(dummy_jemalloc)), feature(allocator_api))]
26 #![cfg_attr(not(stage0), feature(alloc))]
27 #![cfg_attr(not(stage0), feature(alloc_system))]
28 #![cfg_attr(dummy_jemalloc, allow(dead_code))]
29
30 #[cfg(not(stage0))]
31 extern crate alloc;
32 #[cfg(not(stage0))]
33 extern crate alloc_system;
34 extern crate libc;
35
36 #[cfg(all(not(stage0), not(dummy_jemalloc)))]
37 pub use contents::*;
38 #[cfg(all(not(stage0), not(dummy_jemalloc)))]
39 mod contents {
40     use core::ptr;
41
42     use alloc::heap::{Alloc, AllocErr, Layout};
43     use alloc_system::System;
44     use libc::{c_int, c_void, size_t};
45
46     // Note that the symbols here are prefixed by default on macOS and Windows (we
47     // don't explicitly request it), and on Android and DragonFly we explicitly
48     // request it as unprefixing cause segfaults (mismatches in allocators).
49     extern "C" {
50         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
51                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
52                    link_name = "je_mallocx")]
53         fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
54         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
55                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
56                    link_name = "je_calloc")]
57         fn calloc(size: size_t, flags: c_int) -> *mut c_void;
58         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
59                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
60                    link_name = "je_rallocx")]
61         fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
62         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
63                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
64                    link_name = "je_xallocx")]
65         fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
66         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
67                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
68                    link_name = "je_sdallocx")]
69         fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
70         #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
71                        target_os = "dragonfly", target_os = "windows", target_env = "musl"),
72                    link_name = "je_nallocx")]
73         fn nallocx(size: size_t, flags: c_int) -> size_t;
74     }
75
76     const MALLOCX_ZERO: c_int = 0x40;
77
78     // The minimum alignment guaranteed by the architecture. This value is used to
79     // add fast paths for low alignment values. In practice, the alignment is a
80     // constant at the call site and the branch will be optimized out.
81     #[cfg(all(any(target_arch = "arm",
82                   target_arch = "mips",
83                   target_arch = "powerpc")))]
84     const MIN_ALIGN: usize = 8;
85     #[cfg(all(any(target_arch = "x86",
86                   target_arch = "x86_64",
87                   target_arch = "aarch64",
88                   target_arch = "powerpc64",
89                   target_arch = "mips64",
90                   target_arch = "s390x",
91                   target_arch = "sparc64")))]
92     const MIN_ALIGN: usize = 16;
93
94     // MALLOCX_ALIGN(a) macro
95     fn mallocx_align(a: usize) -> c_int {
96         a.trailing_zeros() as c_int
97     }
98
99     fn align_to_flags(align: usize) -> c_int {
100         if align <= MIN_ALIGN {
101             0
102         } else {
103             mallocx_align(align)
104         }
105     }
106
107     // for symbol names src/librustc/middle/allocator.rs
108     // for signatures src/librustc_allocator/lib.rs
109
110     // linkage directives are provided as part of the current compiler allocator
111     // ABI
112
113     #[no_mangle]
114     #[linkage = "external"]
115     pub unsafe extern fn __rde_alloc(size: usize,
116                                      align: usize,
117                                      err: *mut u8) -> *mut u8 {
118         let flags = align_to_flags(align);
119         let ptr = mallocx(size as size_t, flags) as *mut u8;
120         if ptr.is_null() {
121             let layout = Layout::from_size_align_unchecked(size, align);
122             ptr::write(err as *mut AllocErr,
123                        AllocErr::Exhausted { request: layout });
124         }
125         ptr
126     }
127
128     #[no_mangle]
129     #[linkage = "external"]
130     pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
131         System.oom((*(err as *const AllocErr)).clone())
132     }
133
134     #[no_mangle]
135     #[linkage = "external"]
136     pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
137                                        size: usize,
138                                        align: usize) {
139         let flags = align_to_flags(align);
140         sdallocx(ptr as *mut c_void, size, flags);
141     }
142
143     #[no_mangle]
144     #[linkage = "external"]
145     pub unsafe extern fn __rde_usable_size(layout: *const u8,
146                                            min: *mut usize,
147                                            max: *mut usize) {
148         let layout = &*(layout as *const Layout);
149         let flags = align_to_flags(layout.align());
150         let size = nallocx(layout.size(), flags) as usize;
151         *min = layout.size();
152         if size > 0 {
153             *max = size;
154         } else {
155             *max = layout.size();
156         }
157     }
158
159     #[no_mangle]
160     #[linkage = "external"]
161     pub unsafe extern fn __rde_realloc(ptr: *mut u8,
162                                        _old_size: usize,
163                                        old_align: usize,
164                                        new_size: usize,
165                                        new_align: usize,
166                                        err: *mut u8) -> *mut u8 {
167         if new_align != old_align {
168             ptr::write(err as *mut AllocErr,
169                        AllocErr::Unsupported { details: "can't change alignments" });
170             return 0 as *mut u8
171         }
172
173         let flags = align_to_flags(new_align);
174         let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
175         if ptr.is_null() {
176             let layout = Layout::from_size_align_unchecked(new_size, new_align);
177             ptr::write(err as *mut AllocErr,
178                        AllocErr::Exhausted { request: layout });
179         }
180         ptr
181     }
182
183     #[no_mangle]
184     #[linkage = "external"]
185     pub unsafe extern fn __rde_alloc_zeroed(size: usize,
186                                             align: usize,
187                                             err: *mut u8) -> *mut u8 {
188         let ptr = if align <= MIN_ALIGN {
189             calloc(size as size_t, 1) as *mut u8
190         } else {
191             let flags = align_to_flags(align) | MALLOCX_ZERO;
192             mallocx(size as size_t, flags) as *mut u8
193         };
194         if ptr.is_null() {
195             let layout = Layout::from_size_align_unchecked(size, align);
196             ptr::write(err as *mut AllocErr,
197                        AllocErr::Exhausted { request: layout });
198         }
199         ptr
200     }
201
202     #[no_mangle]
203     #[linkage = "external"]
204     pub unsafe extern fn __rde_alloc_excess(size: usize,
205                                             align: usize,
206                                             excess: *mut usize,
207                                             err: *mut u8) -> *mut u8 {
208         let p = __rde_alloc(size, align, err);
209         if !p.is_null() {
210             *excess = size;
211         }
212         return p
213     }
214
215     #[no_mangle]
216     #[linkage = "external"]
217     pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
218                                               old_size: usize,
219                                               old_align: usize,
220                                               new_size: usize,
221                                               new_align: usize,
222                                               excess: *mut usize,
223                                               err: *mut u8) -> *mut u8 {
224         let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
225         if !p.is_null() {
226             *excess = new_size;
227         }
228         return p
229     }
230
231     #[no_mangle]
232     #[linkage = "external"]
233     pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
234                                              old_size: usize,
235                                              old_align: usize,
236                                              new_size: usize,
237                                              new_align: usize) -> u8 {
238         __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
239     }
240
241     #[no_mangle]
242     #[linkage = "external"]
243     pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
244                                                _old_size: usize,
245                                                old_align: usize,
246                                                new_size: usize,
247                                                new_align: usize) -> u8 {
248         if old_align == new_align {
249             let flags = align_to_flags(new_align);
250             (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
251         } else {
252             0
253         }
254     }
255 }