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.
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.
11 #![crate_name = "alloc_jemalloc"]
12 #![crate_type = "rlib"]
14 #![unstable(feature = "alloc_jemalloc",
15 reason = "this library is unlikely to be stabilized in its current \
20 #![feature(staged_api)]
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))]
33 extern crate alloc_system;
36 #[cfg(all(not(stage0), not(dummy_jemalloc)))]
38 #[cfg(all(not(stage0), not(dummy_jemalloc)))]
42 use alloc::heap::{Alloc, AllocErr, Layout};
43 use alloc_system::System;
44 use libc::{c_int, c_void, size_t};
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).
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;
76 const MALLOCX_ZERO: c_int = 0x40;
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",
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;
94 // MALLOCX_ALIGN(a) macro
95 fn mallocx_align(a: usize) -> c_int {
96 a.trailing_zeros() as c_int
99 fn align_to_flags(align: usize) -> c_int {
100 if align <= MIN_ALIGN {
107 // for symbol names src/librustc/middle/allocator.rs
108 // for signatures src/librustc_allocator/lib.rs
110 // linkage directives are provided as part of the current compiler allocator
114 #[linkage = "external"]
115 pub unsafe extern fn __rde_alloc(size: 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;
121 let layout = Layout::from_size_align_unchecked(size, align);
122 ptr::write(err as *mut AllocErr,
123 AllocErr::Exhausted { request: layout });
129 #[linkage = "external"]
130 pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
131 System.oom((*(err as *const AllocErr)).clone())
135 #[linkage = "external"]
136 pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
139 let flags = align_to_flags(align);
140 sdallocx(ptr as *mut c_void, size, flags);
144 #[linkage = "external"]
145 pub unsafe extern fn __rde_usable_size(layout: *const u8,
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();
155 *max = layout.size();
160 #[linkage = "external"]
161 pub unsafe extern fn __rde_realloc(ptr: *mut u8,
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" });
173 let flags = align_to_flags(new_align);
174 let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
176 let layout = Layout::from_size_align_unchecked(new_size, new_align);
177 ptr::write(err as *mut AllocErr,
178 AllocErr::Exhausted { request: layout });
184 #[linkage = "external"]
185 pub unsafe extern fn __rde_alloc_zeroed(size: usize,
187 err: *mut u8) -> *mut u8 {
188 let ptr = if align <= MIN_ALIGN {
189 calloc(size as size_t, 1) as *mut u8
191 let flags = align_to_flags(align) | MALLOCX_ZERO;
192 mallocx(size as size_t, flags) as *mut u8
195 let layout = Layout::from_size_align_unchecked(size, align);
196 ptr::write(err as *mut AllocErr,
197 AllocErr::Exhausted { request: layout });
203 #[linkage = "external"]
204 pub unsafe extern fn __rde_alloc_excess(size: usize,
207 err: *mut u8) -> *mut u8 {
208 let p = __rde_alloc(size, align, err);
216 #[linkage = "external"]
217 pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
223 err: *mut u8) -> *mut u8 {
224 let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
232 #[linkage = "external"]
233 pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
237 new_align: usize) -> u8 {
238 __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
242 #[linkage = "external"]
243 pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
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