Skip to content

Commit 4f5e73b

Browse files
committed
Build a dummy alloc_jemalloc crate on platforms that don't support it
This is a hack to support building targets that don't support jemalloc alongside hosts that do. The jemalloc build is controlled by a feature of the std crate, and if that feature changes between targets, it invalidates the fingerprint of std's build script (this is a cargo bug); so we must ensure that the feature set used by std is the same across all targets, which means we have to build the alloc_jemalloc crate for targets like emscripten, even if we don't use it.
1 parent 3c038c0 commit 4f5e73b

File tree

3 files changed

+180
-117
lines changed

3 files changed

+180
-117
lines changed

src/bootstrap/sanity.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -104,22 +104,21 @@ pub fn check(build: &mut Build) {
104104
need_cmd(build.cxx(host).as_ref());
105105
}
106106

107+
// The msvc hosts don't use jemalloc, turn it off globally to
108+
// avoid packaging the dummy liballoc_jemalloc on that platform.
109+
for host in build.config.host.iter() {
110+
if host.contains("msvc") {
111+
build.config.use_jemalloc = false;
112+
}
113+
}
114+
107115
// Externally configured LLVM requires FileCheck to exist
108116
let filecheck = build.llvm_filecheck(&build.config.build);
109117
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
110118
panic!("filecheck executable {:?} does not exist", filecheck);
111119
}
112120

113121
for target in build.config.target.iter() {
114-
// Either can't build or don't want to run jemalloc on these targets
115-
if target.contains("rumprun") ||
116-
target.contains("bitrig") ||
117-
target.contains("openbsd") ||
118-
target.contains("msvc") ||
119-
target.contains("emscripten") {
120-
build.config.use_jemalloc = false;
121-
}
122-
123122
// Can't compile for iOS unless we're on OSX
124123
if target.contains("apple-ios") &&
125124
!build.config.build.contains("apple-darwin") {

src/liballoc_jemalloc/build.rs

+18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ fn main() {
2727
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
2828
let src_dir = env::current_dir().unwrap();
2929

30+
// FIXME: This is a hack to support building targets that don't
31+
// support jemalloc alongside hosts that do. The jemalloc build is
32+
// controlled by a feature of the std crate, and if that feature
33+
// changes between targets, it invalidates the fingerprint of
34+
// std's build script (this is a cargo bug); so we must ensure
35+
// that the feature set used by std is the same across all
36+
// targets, which means we have to build the alloc_jemalloc crate
37+
// for targets like emscripten, even if we don't use it.
38+
if target.contains("rumprun") ||
39+
target.contains("bitrig") ||
40+
target.contains("openbsd") ||
41+
target.contains("msvc") ||
42+
target.contains("emscripten")
43+
{
44+
println!("cargo:rustc-cfg=dummy_jemalloc");
45+
return;
46+
}
47+
3048
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
3149
let jemalloc = PathBuf::from(jemalloc);
3250
println!("cargo:rustc-link-search=native={}",

src/liballoc_jemalloc/lib.rs

+154-108
Original file line numberDiff line numberDiff line change
@@ -23,124 +23,170 @@
2323

2424
extern crate libc;
2525

26-
use libc::{c_int, c_void, size_t};
26+
pub use imp::*;
2727

28-
// Linkage directives to pull in jemalloc and its dependencies.
29-
//
30-
// On some platforms we need to be sure to link in `pthread` which jemalloc
31-
// depends on, and specifically on android we need to also link to libgcc.
32-
// Currently jemalloc is compiled with gcc which will generate calls to
33-
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
34-
// libcompiler-rt), so link that in to get that support.
35-
#[link(name = "jemalloc", kind = "static")]
36-
#[cfg_attr(target_os = "android", link(name = "gcc"))]
37-
#[cfg_attr(all(not(windows),
38-
not(target_os = "android"),
39-
not(target_env = "musl")),
40-
link(name = "pthread"))]
41-
#[cfg(not(cargobuild))]
42-
extern "C" {}
43-
44-
// Note that the symbols here are prefixed by default on OSX and Windows (we
45-
// don't explicitly request it), and on Android and DragonFly we explicitly
46-
// request it as unprefixing cause segfaults (mismatches in allocators).
47-
extern "C" {
48-
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
49-
target_os = "dragonfly", target_os = "windows"),
50-
link_name = "je_mallocx")]
51-
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
52-
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
53-
target_os = "dragonfly", target_os = "windows"),
54-
link_name = "je_rallocx")]
55-
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
56-
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
57-
target_os = "dragonfly", target_os = "windows"),
58-
link_name = "je_xallocx")]
59-
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
60-
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
61-
target_os = "dragonfly", target_os = "windows"),
62-
link_name = "je_sdallocx")]
63-
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
64-
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
65-
target_os = "dragonfly", target_os = "windows"),
66-
link_name = "je_nallocx")]
67-
fn nallocx(size: size_t, flags: c_int) -> size_t;
68-
}
28+
// See comments in build.rs for why we sometimes build a crate that does nothing
29+
#[cfg(not(dummy_jemalloc))]
30+
mod imp {
31+
use libc::{c_int, c_void, size_t};
6932

70-
// The minimum alignment guaranteed by the architecture. This value is used to
71-
// add fast paths for low alignment values. In practice, the alignment is a
72-
// constant at the call site and the branch will be optimized out.
73-
#[cfg(all(any(target_arch = "arm",
74-
target_arch = "mips",
75-
target_arch = "powerpc")))]
76-
const MIN_ALIGN: usize = 8;
77-
#[cfg(all(any(target_arch = "x86",
78-
target_arch = "x86_64",
79-
target_arch = "aarch64",
80-
target_arch = "powerpc64",
81-
target_arch = "mips64",
82-
target_arch = "s390x")))]
83-
const MIN_ALIGN: usize = 16;
84-
85-
// MALLOCX_ALIGN(a) macro
86-
fn mallocx_align(a: usize) -> c_int {
87-
a.trailing_zeros() as c_int
88-
}
33+
// Linkage directives to pull in jemalloc and its dependencies.
34+
//
35+
// On some platforms we need to be sure to link in `pthread` which jemalloc
36+
// depends on, and specifically on android we need to also link to libgcc.
37+
// Currently jemalloc is compiled with gcc which will generate calls to
38+
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
39+
// libcompiler-rt), so link that in to get that support.
40+
#[link(name = "jemalloc", kind = "static")]
41+
#[cfg_attr(target_os = "android", link(name = "gcc"))]
42+
#[cfg_attr(all(not(windows),
43+
not(target_os = "android"),
44+
not(target_env = "musl")),
45+
link(name = "pthread"))]
46+
#[cfg(not(cargobuild))]
47+
extern "C" {}
48+
49+
// Note that the symbols here are prefixed by default on OSX and Windows (we
50+
// don't explicitly request it), and on Android and DragonFly we explicitly
51+
// request it as unprefixing cause segfaults (mismatches in allocators).
52+
extern "C" {
53+
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
54+
target_os = "dragonfly", target_os = "windows"),
55+
link_name = "je_mallocx")]
56+
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
57+
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
58+
target_os = "dragonfly", target_os = "windows"),
59+
link_name = "je_rallocx")]
60+
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
61+
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
62+
target_os = "dragonfly", target_os = "windows"),
63+
link_name = "je_xallocx")]
64+
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
65+
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
66+
target_os = "dragonfly", target_os = "windows"),
67+
link_name = "je_sdallocx")]
68+
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
69+
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
70+
target_os = "dragonfly", target_os = "windows"),
71+
link_name = "je_nallocx")]
72+
fn nallocx(size: size_t, flags: c_int) -> size_t;
73+
}
74+
75+
// The minimum alignment guaranteed by the architecture. This value is used to
76+
// add fast paths for low alignment values. In practice, the alignment is a
77+
// constant at the call site and the branch will be optimized out.
78+
#[cfg(all(any(target_arch = "arm",
79+
target_arch = "mips",
80+
target_arch = "powerpc")))]
81+
const MIN_ALIGN: usize = 8;
82+
#[cfg(all(any(target_arch = "x86",
83+
target_arch = "x86_64",
84+
target_arch = "aarch64",
85+
target_arch = "powerpc64",
86+
target_arch = "mips64",
87+
target_arch = "s390x")))]
88+
const MIN_ALIGN: usize = 16;
89+
90+
// MALLOCX_ALIGN(a) macro
91+
fn mallocx_align(a: usize) -> c_int {
92+
a.trailing_zeros() as c_int
93+
}
94+
95+
fn align_to_flags(align: usize) -> c_int {
96+
if align <= MIN_ALIGN {
97+
0
98+
} else {
99+
mallocx_align(align)
100+
}
101+
}
102+
103+
#[no_mangle]
104+
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
105+
let flags = align_to_flags(align);
106+
unsafe { mallocx(size as size_t, flags) as *mut u8 }
107+
}
108+
109+
#[no_mangle]
110+
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
111+
_old_size: usize,
112+
size: usize,
113+
align: usize)
114+
-> *mut u8 {
115+
let flags = align_to_flags(align);
116+
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
117+
}
118+
119+
#[no_mangle]
120+
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
121+
_old_size: usize,
122+
size: usize,
123+
align: usize)
124+
-> usize {
125+
let flags = align_to_flags(align);
126+
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
127+
}
89128

90-
fn align_to_flags(align: usize) -> c_int {
91-
if align <= MIN_ALIGN {
129+
#[no_mangle]
130+
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
131+
let flags = align_to_flags(align);
132+
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
133+
}
134+
135+
#[no_mangle]
136+
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
137+
let flags = align_to_flags(align);
138+
unsafe { nallocx(size as size_t, flags) as usize }
139+
}
140+
141+
// These symbols are used by jemalloc on android but the really old android
142+
// we're building on doesn't have them defined, so just make sure the symbols
143+
// are available.
144+
#[no_mangle]
145+
#[cfg(target_os = "android")]
146+
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
147+
_postfork_parent: *mut u8,
148+
_postfork_child: *mut u8)
149+
-> i32 {
92150
0
93-
} else {
94-
mallocx_align(align)
95151
}
96152
}
97153

98-
#[no_mangle]
99-
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
100-
let flags = align_to_flags(align);
101-
unsafe { mallocx(size as size_t, flags) as *mut u8 }
102-
}
154+
#[cfg(dummy_jemalloc)]
155+
mod imp {
156+
fn bogus() -> ! {
157+
panic!("jemalloc is not implemented for this platform");
158+
}
103159

104-
#[no_mangle]
105-
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
106-
_old_size: usize,
107-
size: usize,
108-
align: usize)
109-
-> *mut u8 {
110-
let flags = align_to_flags(align);
111-
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
112-
}
160+
#[no_mangle]
161+
pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
162+
bogus()
163+
}
113164

114-
#[no_mangle]
115-
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
116-
_old_size: usize,
117-
size: usize,
118-
align: usize)
119-
-> usize {
120-
let flags = align_to_flags(align);
121-
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
122-
}
165+
#[no_mangle]
166+
pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
167+
_old_size: usize,
168+
_size: usize,
169+
_align: usize)
170+
-> *mut u8 {
171+
bogus()
172+
}
123173

124-
#[no_mangle]
125-
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
126-
let flags = align_to_flags(align);
127-
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
128-
}
174+
#[no_mangle]
175+
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
176+
_old_size: usize,
177+
_size: usize,
178+
_align: usize)
179+
-> usize {
180+
bogus()
181+
}
129182

130-
#[no_mangle]
131-
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
132-
let flags = align_to_flags(align);
133-
unsafe { nallocx(size as size_t, flags) as usize }
134-
}
183+
#[no_mangle]
184+
pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
185+
bogus()
186+
}
135187

136-
// These symbols are used by jemalloc on android but the really old android
137-
// we're building on doesn't have them defined, so just make sure the symbols
138-
// are available.
139-
#[no_mangle]
140-
#[cfg(target_os = "android")]
141-
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
142-
_postfork_parent: *mut u8,
143-
_postfork_child: *mut u8)
144-
-> i32 {
145-
0
188+
#[no_mangle]
189+
pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
190+
bogus()
191+
}
146192
}

0 commit comments

Comments
 (0)