]>
Commit | Line | Data |
---|---|---|
0731742a XL |
1 | //! A Rust port of the `dlmalloc` allocator. |
2 | //! | |
3 | //! The `dlmalloc` allocator is described at | |
4 | //! http://g.oswego.edu/dl/html/malloc.html and this Rust crate is a straight | |
5 | //! port of the C code for the allocator into Rust. The implementation is | |
6 | //! wrapped up in a `Dlmalloc` type and has support for Linux, OSX, and Wasm | |
7 | //! currently. | |
8 | //! | |
9 | //! The primary purpose of this crate is that it serves as the default memory | |
10 | //! allocator for the `wasm32-unknown-unknown` target in the standard library. | |
11 | //! Support for other platforms is largely untested and unused, but is used when | |
12 | //! testing this crate. | |
13 | ||
14 | #![cfg_attr(feature = "allocator-api", feature(allocator_api))] | |
0731742a XL |
15 | #![cfg_attr(target_env = "sgx", feature(asm))] |
16 | #![cfg_attr(not(feature = "allocator-api"), allow(dead_code))] | |
17 | #![no_std] | |
18 | #![deny(missing_docs)] | |
19 | ||
20 | #[cfg(feature = "allocator-api")] | |
21 | use core::alloc::{Alloc, Layout, AllocErr}; | |
22 | use core::cmp; | |
23 | use core::ptr; | |
24 | ||
25 | #[cfg(feature = "global")] | |
26 | pub use self::global::GlobalDlmalloc; | |
27 | ||
28 | #[cfg(feature = "global")] | |
29 | mod global; | |
30 | mod dlmalloc; | |
31 | ||
32 | /// An allocator instance | |
33 | /// | |
34 | /// Instances of this type are used to allocate blocks of memory. For best | |
35 | /// results only use one of these. Currently doesn't implement `Drop` to release | |
36 | /// lingering memory back to the OS. That may happen eventually though! | |
37 | pub struct Dlmalloc(dlmalloc::Dlmalloc); | |
38 | ||
39 | /// Constant initializer for `Dlmalloc` structure. | |
40 | pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc(dlmalloc::DLMALLOC_INIT); | |
41 | ||
42 | #[cfg(target_arch = "wasm32")] | |
43 | #[path = "wasm.rs"] | |
44 | mod sys; | |
45 | ||
46 | #[cfg(target_os = "macos")] | |
47 | #[path = "macos.rs"] | |
48 | mod sys; | |
49 | ||
50 | #[cfg(target_os = "linux")] | |
51 | #[path = "linux.rs"] | |
52 | mod sys; | |
53 | ||
54 | #[cfg(target_env = "sgx")] | |
55 | #[path = "sgx.rs"] | |
56 | mod sys; | |
57 | ||
58 | impl Dlmalloc { | |
59 | /// Creates a new instance of an allocator, same as `DLMALLOC_INIT`. | |
60 | pub fn new() -> Dlmalloc { | |
61 | DLMALLOC_INIT | |
62 | } | |
63 | ||
64 | /// Allocates `size` bytes with `align` align. | |
65 | /// | |
66 | /// Returns a null pointer if allocation fails. Returns a valid pointer | |
67 | /// otherwise. | |
68 | /// | |
69 | /// Safety and contracts are largely governed by the `GlobalAlloc::alloc` | |
70 | /// method contracts. | |
71 | #[inline] | |
72 | pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 { | |
73 | if align <= self.0.malloc_alignment() { | |
74 | self.0.malloc(size) | |
75 | } else { | |
76 | self.0.memalign(align, size) | |
77 | } | |
78 | } | |
79 | ||
80 | /// Same as `malloc`, except if the allocation succeeds it's guaranteed to | |
81 | /// point to `size` bytes of zeros. | |
82 | #[inline] | |
83 | pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 { | |
84 | let ptr = self.malloc(size, align); | |
85 | if !ptr.is_null() && self.0.calloc_must_clear(ptr) { | |
86 | ptr::write_bytes(ptr, 0, size); | |
87 | } | |
88 | ptr | |
89 | } | |
90 | ||
91 | /// Deallocates a `ptr` with `size` and `align` as the previous request used | |
92 | /// to allocate it. | |
93 | /// | |
94 | /// Safety and contracts are largely governed by the `GlobalAlloc::dealloc` | |
95 | /// method contracts. | |
96 | #[inline] | |
97 | pub unsafe fn free(&mut self, ptr: *mut u8, size: usize, align: usize) { | |
98 | drop((size, align)); | |
99 | self.0.free(ptr) | |
100 | } | |
101 | ||
102 | /// Reallocates `ptr`, a previous allocation with `old_size` and | |
103 | /// `old_align`, to have `new_size` and the same alignment as before. | |
104 | /// | |
105 | /// Returns a null pointer if the memory couldn't be reallocated, but `ptr` | |
106 | /// is still valid. Returns a valid pointer and frees `ptr` if the request | |
107 | /// is satisfied. | |
108 | /// | |
109 | /// Safety and contracts are largely governed by the `GlobalAlloc::realloc` | |
110 | /// method contracts. | |
111 | #[inline] | |
112 | pub unsafe fn realloc(&mut self, | |
113 | ptr: *mut u8, | |
114 | old_size: usize, | |
115 | old_align: usize, | |
116 | new_size: usize) -> *mut u8 { | |
117 | if old_align <= self.0.malloc_alignment() { | |
118 | self.0.realloc(ptr, new_size) | |
119 | } else { | |
120 | let res = self.malloc(new_size, old_align); | |
121 | if !res.is_null() { | |
122 | let size = cmp::min(old_size, new_size); | |
123 | ptr::copy_nonoverlapping(ptr, res, size); | |
124 | self.free(ptr, old_size, old_align); | |
125 | } | |
126 | res | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | #[cfg(feature = "allocator-api")] | |
132 | unsafe impl Alloc for Dlmalloc { | |
133 | #[inline] | |
134 | unsafe fn alloc( | |
135 | &mut self, | |
136 | layout: Layout | |
137 | ) -> Result<ptr::NonNull<u8>, AllocErr> { | |
138 | let ptr = <Dlmalloc>::malloc(self, layout.size(), layout.align()); | |
139 | ptr::NonNull::new(ptr).ok_or(AllocErr) | |
140 | } | |
141 | ||
142 | #[inline] | |
143 | unsafe fn dealloc(&mut self, ptr: ptr::NonNull<u8>, layout: Layout) { | |
144 | <Dlmalloc>::free(self, ptr.as_ptr(), layout.size(), layout.align()) | |
145 | } | |
146 | ||
147 | #[inline] | |
148 | unsafe fn realloc( | |
149 | &mut self, | |
150 | ptr: ptr::NonNull<u8>, | |
151 | layout: Layout, | |
152 | new_size: usize | |
153 | ) -> Result<ptr::NonNull<u8>, AllocErr> { | |
154 | let ptr = <Dlmalloc>::realloc( | |
155 | self, | |
156 | ptr.as_ptr(), | |
157 | layout.size(), | |
158 | layout.align(), | |
159 | new_size, | |
160 | ); | |
161 | ptr::NonNull::new(ptr).ok_or(AllocErr) | |
162 | } | |
163 | ||
164 | #[inline] | |
165 | unsafe fn alloc_zeroed( | |
166 | &mut self, | |
167 | layout: Layout | |
168 | ) -> Result<ptr::NonNull<u8>, AllocErr> { | |
169 | let ptr = <Dlmalloc>::calloc(self, layout.size(), layout.align()); | |
170 | ptr::NonNull::new(ptr).ok_or(AllocErr) | |
171 | } | |
172 | } |