Bug 1514122 - Make rust code use mozjemalloc directly. r=froydnj
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 19 Dec 2018 01:47:40 +0000
changeset 451283 f626107995b58eb5453c30f223753ea2ae31aa8b
parent 451282 dcd8195681d70ee47bde2e80846fc62b1e63eb74
child 451284 e1439f07a4a41cc5c750e0892c09ff7024860f7a
push id110646
push userebalazs@mozilla.com
push dateWed, 19 Dec 2018 16:05:18 +0000
treeherdermozilla-inbound@1acd86ad823c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1514122, 1280578
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1514122 - Make rust code use mozjemalloc directly. r=froydnj Until rust 1.28, there was no stable way to change the allocator used by rust code. In bug 1280578, we hooked HeadAlloc/HeapFree/HeapRealloc, that the default rust system allocator uses. On other platforms, rust code just ended up using malloc/free/realloc like everything else. As of rust 1.28, though, it is now possible to use the GlobalAlloc trait and the #[global_allocator] attribute to set an allocator. On Windows, this can allow us to hook mozjemalloc directly, rather than using an indirection through HeapAlloc/etc. (which require an extra call to GetProcessHeap), so let's do this. On other platforms, this just ends up doing the same thing as the default rust system allocator (except for the memalign limit on 32-bits platforms). We still need the HeapAlloc/etc. hooks for some C++ code using it, though. Another benefit is that the HeapAlloc GlobalAlloc implementation needs to do its own memalign, which it does by overallocating and aligning manually. We obviously don't need to do this when we using memalign/_aligned_malloc directly. Differential Revision: https://phabricator.services.mozilla.com/D14820
toolkit/library/rust/shared/lib.rs
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -259,8 +259,89 @@ mod oom_hook {
     }
 }
 
 #[no_mangle]
 pub extern "C" fn install_rust_oom_hook() {
     #[cfg(feature = "oom_with_hook")]
     oom_hook::install();
 }
+
+#[cfg(feature = "moz_memory")]
+mod moz_memory {
+    use std::alloc::{GlobalAlloc, Layout};
+    use std::os::raw::c_void;
+
+    extern "C" {
+        fn malloc(size: usize) -> *mut c_void;
+
+        fn free(ptr: *mut c_void);
+
+        fn calloc(nmemb: usize, size: usize) -> *mut c_void;
+
+        fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
+
+        #[cfg(windows)]
+        fn _aligned_malloc(size: usize, align: usize) -> *mut c_void;
+
+        #[cfg(not(windows))]
+        fn memalign(align: usize, size: usize) -> *mut c_void;
+    }
+
+    #[cfg(windows)]
+    unsafe fn memalign(align: usize, size: usize) -> *mut c_void {
+        _aligned_malloc(size, align)
+    }
+
+    pub struct GeckoAlloc;
+
+    #[inline(always)]
+    fn need_memalign(layout: Layout) -> bool {
+        // mozjemalloc guarantees a minimum alignment of 16 for all sizes, except
+        // for size classes below 16 (4 and 8).
+        layout.align() > layout.size() || layout.align() > 16
+    }
+
+    unsafe impl GlobalAlloc for GeckoAlloc {
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            if need_memalign(layout) {
+                memalign(layout.align(), layout.size()) as *mut u8
+            } else {
+                malloc(layout.size()) as *mut u8
+            }
+        }
+
+        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+            free(ptr as *mut c_void)
+        }
+
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            if need_memalign(layout) {
+                let ptr = self.alloc(layout);
+                if !ptr.is_null() {
+                    std::ptr::write_bytes(ptr, 0, layout.size());
+                }
+                ptr
+            } else {
+                calloc(1, layout.size()) as *mut u8
+            }
+        }
+
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+            if need_memalign(new_layout) {
+                let new_ptr = self.alloc(new_layout);
+                if !new_ptr.is_null() {
+                    let size = std::cmp::min(layout.size(), new_size);
+                    std::ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                    self.dealloc(ptr, layout);
+                }
+                new_ptr
+            } else {
+                realloc(ptr as *mut c_void, new_size) as *mut u8
+            }
+        }
+    }
+}
+
+#[cfg(feature = "moz_memory")]
+#[global_allocator]
+static A: moz_memory::GeckoAlloc = moz_memory::GeckoAlloc;