1#![no_std]
2
3extern crate libc;
4extern crate libmimalloc_sys as ffi;
5
6use core::ffi::c_void;
7use core::alloc::{GlobalAlloc, Layout};
8
9use libmimalloc_sys::*;
10
11
12#[cfg(all(any(
14 target_arch = "x86",
15 target_arch = "arm",
16 target_arch = "mips",
17 target_arch = "powerpc",
18 target_arch = "powerpc64",
19 target_arch = "asmjs",
20 target_arch = "wasm32"
21)))]
22const MIN_ALIGN: usize = 8;
23
24#[cfg(all(any(
25 target_arch = "x86_64",
26 target_arch = "aarch64",
27 target_arch = "mips64",
28 target_arch = "s390x",
29 target_arch = "sparc64"
30)))]
31const MIN_ALIGN: usize = 16;
32
33pub struct MiMalloc;
43
44#[cfg(target_os = "linux")]
45const ONE_G: usize = 1073741824; #[cfg(target_os = "linux")]
48#[inline]
49fn hugepage_align(layout: Layout) -> usize {
50 let mut len_bytes = layout.size();
51 let rem = len_bytes % ONE_G;
53 if rem != 0 {
54 len_bytes += ONE_G - rem;
55 }
56 debug_assert_eq!(len_bytes % ONE_G, 0);
57
58 len_bytes
59}
60
61#[cfg(target_os = "linux")]
62#[inline]
63unsafe fn hugepage_alloc_zeroed(layout: Layout) -> *mut u8 {
64 let len_bytes = hugepage_align(layout);
67
68 const FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_HUGETLB;
70 const PROTECT_FLAGS: libc::c_int = libc::PROT_READ | libc::PROT_WRITE; let addr = core::ptr::null_mut();
73 let ptr: *mut libc::c_void = libc::mmap(addr, len_bytes, PROTECT_FLAGS, FLAGS, -1, 0);
74 if ptr == libc::MAP_FAILED {
75 return core::ptr::null_mut();
79 } else {
80 return ptr as *mut u8;
81 }
82}
83
84#[cfg(target_os = "linux")]
85#[inline]
86unsafe fn hugepage_dealloc(ptr: *mut u8, layout: Layout) -> libc::c_int {
87 let len_bytes = hugepage_align(layout);
88 libc::munmap(ptr as *mut libc::c_void, len_bytes)
90}
91
92unsafe impl GlobalAlloc for MiMalloc {
93 #[inline]
94 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
95 #[cfg(target_os = "linux")]
96 {
97 if layout.size() >= ONE_G {
98 let ptr = hugepage_alloc_zeroed(layout);
99 if !ptr.is_null() {
100 return ptr;
101 }
102 }
103 }
104
105 if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
106 mi_malloc(layout.size()) as *mut u8
107 } else {
108 #[cfg(target_os = "macos")]
109 if layout.align() > (1 << 31) {
110 return core::ptr::null_mut();
111 }
112
113 mi_malloc_aligned(layout.size(), layout.align()) as *mut u8
114 }
115 }
116
117 #[inline]
118 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
119 #[cfg(target_os = "linux")]
120 {
121 if layout.size() >= ONE_G {
122 let ptr = hugepage_alloc_zeroed(layout);
123 if !ptr.is_null() {
124 return ptr;
125 }
126 }
127 }
128
129 if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
130 mi_zalloc(layout.size()) as *mut u8
131 } else {
132 #[cfg(target_os = "macos")]
133 if layout.align() > (1 << 31) {
134 return core::ptr::null_mut();
135 }
136
137 mi_zalloc_aligned(layout.size(), layout.align()) as *mut u8
138 }
139 }
140
141 #[inline]
142 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
143 #[cfg(target_os = "linux")]
144 {
145 if layout.size() >= ONE_G {
146 let ret = hugepage_dealloc(ptr, layout);
147 if ret == 0 {
148 return ();
149 }
150 }
151 }
152
153 mi_free(ptr as *mut c_void);
154 }
155
156 #[inline]
157 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
158 if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
159 mi_realloc(ptr as *mut c_void, new_size) as *mut u8
160 } else {
161 mi_realloc_aligned(ptr as *mut c_void, new_size, layout.align()) as *mut u8
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn it_frees_allocated_memory() {
172 unsafe {
173 let layout = Layout::from_size_align(8, 8).unwrap();
174 let alloc = MiMalloc;
175
176 let ptr = alloc.alloc(layout);
177 alloc.dealloc(ptr, layout);
178 }
179 }
180
181 #[test]
182 fn it_frees_allocated_big_memory() {
183 unsafe {
184 let layout = Layout::from_size_align(1 << 20, 32).unwrap();
185 let alloc = MiMalloc;
186
187 let ptr = alloc.alloc(layout);
188 alloc.dealloc(ptr, layout);
189 }
190 }
191
192 #[test]
193 fn it_frees_zero_allocated_memory() {
194 unsafe {
195 let layout = Layout::from_size_align(8, 8).unwrap();
196 let alloc = MiMalloc;
197
198 let ptr = alloc.alloc_zeroed(layout);
199 alloc.dealloc(ptr, layout);
200 }
201 }
202
203 #[test]
204 fn it_frees_zero_allocated_big_memory() {
205 unsafe {
206 let layout = Layout::from_size_align(1 << 20, 32).unwrap();
207 let alloc = MiMalloc;
208
209 let ptr = alloc.alloc_zeroed(layout);
210 alloc.dealloc(ptr, layout);
211 }
212 }
213
214 #[test]
215 fn it_frees_reallocated_memory() {
216 unsafe {
217 let layout = Layout::from_size_align(8, 8).unwrap();
218 let alloc = MiMalloc;
219
220 let ptr = alloc.alloc(layout);
221 let ptr = alloc.realloc(ptr, layout, 16);
222 alloc.dealloc(ptr, layout);
223 }
224 }
225
226 #[test]
227 fn it_frees_reallocated_big_memory() {
228 unsafe {
229 let layout = Layout::from_size_align(1 << 20, 32).unwrap();
230 let alloc = MiMalloc;
231
232 let ptr = alloc.alloc(layout);
233 let ptr = alloc.realloc(ptr, layout, 2 << 20);
234 alloc.dealloc(ptr, layout);
235 }
236 }
237}