servo_allocator/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Selecting the default global allocator for Servo, and exposing common
6//! allocator introspection APIs for memory profiling.
7
8use std::os::raw::c_void;
9
10#[cfg(not(feature = "allocation-tracking"))]
11#[global_allocator]
12static ALLOC: Allocator = Allocator;
13
14#[cfg(feature = "allocation-tracking")]
15#[global_allocator]
16static ALLOC: crate::tracking::AccountingAlloc<Allocator> =
17    crate::tracking::AccountingAlloc::with_allocator(Allocator);
18
19#[cfg(feature = "allocation-tracking")]
20mod tracking;
21
22pub fn dump_unmeasured() {
23    #[cfg(feature = "allocation-tracking")]
24    ALLOC.dump_unmeasured_allocations();
25}
26
27pub use crate::platform::*;
28
29type EnclosingSizeFn = unsafe extern "C" fn(*const c_void) -> usize;
30
31/// # Safety
32/// No restrictions. The passed pointer is never dereferenced.
33/// This function is only marked unsafe because the MallocSizeOfOps APIs
34/// requires an unsafe function pointer.
35#[cfg(feature = "allocation-tracking")]
36unsafe extern "C" fn enclosing_size_impl(ptr: *const c_void) -> usize {
37    let (adjusted, size) = crate::ALLOC.enclosing_size(ptr);
38    if size != 0 {
39        crate::ALLOC.note_allocation(adjusted, size);
40    }
41    size
42}
43
44#[allow(non_upper_case_globals)]
45#[cfg(feature = "allocation-tracking")]
46pub static enclosing_size: Option<EnclosingSizeFn> = Some(crate::enclosing_size_impl);
47
48#[allow(non_upper_case_globals)]
49#[cfg(not(feature = "allocation-tracking"))]
50pub static enclosing_size: Option<EnclosingSizeFn> = None;
51
52#[cfg(not(any(windows, feature = "use-system-allocator", target_env = "ohos")))]
53mod platform {
54    use std::os::raw::c_void;
55
56    pub use tikv_jemallocator::Jemalloc as Allocator;
57
58    /// Get the size of a heap block.
59    ///
60    /// # Safety
61    ///
62    /// Passing a non-heap allocated pointer to this function results in undefined behavior.
63    pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
64        let size = unsafe { tikv_jemallocator::usable_size(ptr) };
65        #[cfg(feature = "allocation-tracking")]
66        crate::ALLOC.note_allocation(ptr, size);
67        size
68    }
69
70    /// Memory allocation APIs compatible with libc
71    pub mod libc_compat {
72        pub use tikv_jemalloc_sys::{free, malloc, realloc};
73    }
74}
75
76#[cfg(all(
77    not(windows),
78    any(feature = "use-system-allocator", target_env = "ohos")
79))]
80mod platform {
81    pub use std::alloc::System as Allocator;
82    use std::os::raw::c_void;
83
84    /// Get the size of a heap block.
85    ///
86    /// # Safety
87    ///
88    /// Passing a non-heap allocated pointer to this function results in undefined behavior.
89    pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
90        #[cfg(target_vendor = "apple")]
91        unsafe {
92            let size = libc::malloc_size(ptr);
93            #[cfg(feature = "allocation-tracking")]
94            crate::ALLOC.note_allocation(ptr, size);
95            size
96        }
97
98        #[cfg(not(target_vendor = "apple"))]
99        unsafe {
100            let size = libc::malloc_usable_size(ptr as *mut _);
101            #[cfg(feature = "allocation-tracking")]
102            crate::ALLOC.note_allocation(ptr, size);
103            size
104        }
105    }
106
107    pub mod libc_compat {
108        pub use libc::{free, malloc, realloc};
109    }
110}
111
112#[cfg(windows)]
113mod platform {
114    pub use std::alloc::System as Allocator;
115    use std::os::raw::c_void;
116
117    use windows_sys::Win32::Foundation::FALSE;
118    use windows_sys::Win32::System::Memory::{GetProcessHeap, HeapSize, HeapValidate};
119
120    /// Get the size of a heap block.
121    ///
122    /// # Safety
123    ///
124    /// Passing a non-heap allocated pointer to this function results in undefined behavior.
125    pub unsafe extern "C" fn usable_size(mut ptr: *const c_void) -> usize {
126        unsafe {
127            let heap = GetProcessHeap();
128
129            if HeapValidate(heap, 0, ptr) == FALSE {
130                ptr = *(ptr as *const *const c_void).offset(-1)
131            }
132
133            let size = HeapSize(heap, 0, ptr) as usize;
134            #[cfg(feature = "allocation-tracking")]
135            crate::ALLOC.note_allocation(ptr, size);
136            size
137        }
138    }
139}