1 //! A Rust port of the `dlmalloc` allocator.
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
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.
16 #![deny(missing_docs)]
17 #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))]
23 #[cfg(feature = "global")]
24 pub use self::global
::{enable_alloc_after_fork, GlobalDlmalloc}
;
27 #[cfg(feature = "global")]
30 /// In order for this crate to efficiently manage memory, it needs a way to communicate with the
31 /// underlying platform. This `Allocator` trait provides an interface for this communication.
32 pub unsafe trait Allocator
: Send
{
33 /// Allocates system memory region of at least `size` bytes
34 /// Returns a triple of `(base, size, flags)` where `base` is a pointer to the beginning of the
35 /// allocated memory region. `size` is the actual size of the region while `flags` specifies
36 /// properties of the allocated region. If `EXTERN_BIT` (bit 0) set in flags, then we did not
37 /// allocate this segment and so should not try to deallocate or merge with others.
38 /// This function can return a `std::ptr::null_mut()` when allocation fails (other values of
39 /// the triple will be ignored).
40 fn alloc(&self, size
: usize) -> (*mut u8, usize, u32);
42 /// Remaps system memory region at `ptr` with size `oldsize` to a potential new location with
43 /// size `newsize`. `can_move` indicates if the location is allowed to move to a completely new
44 /// location, or that it is only allowed to change in size. Returns a pointer to the new
45 /// location in memory.
46 /// This function can return a `std::ptr::null_mut()` to signal an error.
47 fn remap(&self, ptr
: *mut u8, oldsize
: usize, newsize
: usize, can_move
: bool
) -> *mut u8;
49 /// Frees a part of a memory chunk. The original memory chunk starts at `ptr` with size `oldsize`
50 /// and is turned into a memory region starting at the same address but with `newsize` bytes.
51 /// Returns `true` iff the access memory region could be freed.
52 fn free_part(&self, ptr
: *mut u8, oldsize
: usize, newsize
: usize) -> bool
;
54 /// Frees an entire memory region. Returns `true` iff the operation succeeded. When `false` is
55 /// returned, the `dlmalloc` may re-use the location on future allocation requests
56 fn free(&self, ptr
: *mut u8, size
: usize) -> bool
;
58 /// Indicates if the system can release a part of memory. For the `flags` argument, see
59 /// `Allocator::alloc`
60 fn can_release_part(&self, flags
: u32) -> bool
;
62 /// Indicates whether newly allocated regions contain zeros.
63 fn allocates_zeros(&self) -> bool
;
65 /// Returns the page size. Must be a power of two
66 fn page_size(&self) -> usize;
69 /// An allocator instance
71 /// Instances of this type are used to allocate blocks of memory. For best
72 /// results only use one of these. Currently doesn't implement `Drop` to release
73 /// lingering memory back to the OS. That may happen eventually though!
74 pub struct Dlmalloc
<A
= System
>(dlmalloc
::Dlmalloc
<A
>);
76 #[cfg(target_family = "wasm")]
80 #[cfg(any(target_os = "linux", target_os = "macos"))]
84 #[cfg(not(any(target_os = "linux", target_os = "macos", target_family = "wasm")))]
88 impl Dlmalloc
<System
> {
89 /// Creates a new instance of an allocator
90 pub const fn new() -> Dlmalloc
<System
> {
91 Dlmalloc(dlmalloc
::Dlmalloc
::new(System
::new()))
96 /// Creates a new instance of an allocator
97 pub const fn new_with_allocator(sys_allocator
: A
) -> Dlmalloc
<A
> {
98 Dlmalloc(dlmalloc
::Dlmalloc
::new(sys_allocator
))
102 impl<A
: Allocator
> Dlmalloc
<A
> {
103 /// Allocates `size` bytes with `align` align.
105 /// Returns a null pointer if allocation fails. Returns a valid pointer
108 /// Safety and contracts are largely governed by the `GlobalAlloc::alloc`
109 /// method contracts.
111 pub unsafe fn malloc(&mut self, size
: usize, align
: usize) -> *mut u8 {
112 if align
<= self.0.malloc_alignment() {
115 self.0.memalign(align
, size
)
119 /// Same as `malloc`, except if the allocation succeeds it's guaranteed to
120 /// point to `size` bytes of zeros.
122 pub unsafe fn calloc(&mut self, size
: usize, align
: usize) -> *mut u8 {
123 let ptr
= self.malloc(size
, align
);
124 if !ptr
.is_null() && self.0.calloc_must_clear(ptr
) {
125 ptr
::write_bytes(ptr
, 0, size
);
130 /// Deallocates a `ptr` with `size` and `align` as the previous request used
133 /// Safety and contracts are largely governed by the `GlobalAlloc::dealloc`
134 /// method contracts.
136 pub unsafe fn free(&mut self, ptr
: *mut u8, size
: usize, align
: usize) {
141 /// Reallocates `ptr`, a previous allocation with `old_size` and
142 /// `old_align`, to have `new_size` and the same alignment as before.
144 /// Returns a null pointer if the memory couldn't be reallocated, but `ptr`
145 /// is still valid. Returns a valid pointer and frees `ptr` if the request
148 /// Safety and contracts are largely governed by the `GlobalAlloc::realloc`
149 /// method contracts.
151 pub unsafe fn realloc(
158 if old_align
<= self.0.malloc_alignment() {
159 self.0.realloc(ptr
, new_size
)
161 let res
= self.malloc(new_size
, old_align
);
163 let size
= cmp
::min(old_size
, new_size
);
164 ptr
::copy_nonoverlapping(ptr
, res
, size
);
165 self.free(ptr
, old_size
, old_align
);