diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/dlmalloc/src/lib.rs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/dlmalloc/src/lib.rs b/vendor/dlmalloc/src/lib.rs new file mode 100644 index 000000000..238386fbc --- /dev/null +++ b/vendor/dlmalloc/src/lib.rs @@ -0,0 +1,170 @@ +//! A Rust port of the `dlmalloc` allocator. +//! +//! The `dlmalloc` allocator is described at +//! http://g.oswego.edu/dl/html/malloc.html and this Rust crate is a straight +//! port of the C code for the allocator into Rust. The implementation is +//! wrapped up in a `Dlmalloc` type and has support for Linux, OSX, and Wasm +//! currently. +//! +//! The primary purpose of this crate is that it serves as the default memory +//! allocator for the `wasm32-unknown-unknown` target in the standard library. +//! Support for other platforms is largely untested and unused, but is used when +//! testing this crate. + +#![allow(dead_code)] +#![no_std] +#![deny(missing_docs)] +#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] + +use core::cmp; +use core::ptr; +use sys::System; + +#[cfg(feature = "global")] +pub use self::global::{enable_alloc_after_fork, GlobalDlmalloc}; + +mod dlmalloc; +#[cfg(feature = "global")] +mod global; + +/// In order for this crate to efficiently manage memory, it needs a way to communicate with the +/// underlying platform. This `Allocator` trait provides an interface for this communication. +pub unsafe trait Allocator: Send { + /// Allocates system memory region of at least `size` bytes + /// Returns a triple of `(base, size, flags)` where `base` is a pointer to the beginning of the + /// allocated memory region. `size` is the actual size of the region while `flags` specifies + /// properties of the allocated region. If `EXTERN_BIT` (bit 0) set in flags, then we did not + /// allocate this segment and so should not try to deallocate or merge with others. + /// This function can return a `std::ptr::null_mut()` when allocation fails (other values of + /// the triple will be ignored). + fn alloc(&self, size: usize) -> (*mut u8, usize, u32); + + /// Remaps system memory region at `ptr` with size `oldsize` to a potential new location with + /// size `newsize`. `can_move` indicates if the location is allowed to move to a completely new + /// location, or that it is only allowed to change in size. Returns a pointer to the new + /// location in memory. + /// This function can return a `std::ptr::null_mut()` to signal an error. + fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8; + + /// Frees a part of a memory chunk. The original memory chunk starts at `ptr` with size `oldsize` + /// and is turned into a memory region starting at the same address but with `newsize` bytes. + /// Returns `true` iff the access memory region could be freed. + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool; + + /// Frees an entire memory region. Returns `true` iff the operation succeeded. When `false` is + /// returned, the `dlmalloc` may re-use the location on future allocation requests + fn free(&self, ptr: *mut u8, size: usize) -> bool; + + /// Indicates if the system can release a part of memory. For the `flags` argument, see + /// `Allocator::alloc` + fn can_release_part(&self, flags: u32) -> bool; + + /// Indicates whether newly allocated regions contain zeros. + fn allocates_zeros(&self) -> bool; + + /// Returns the page size. Must be a power of two + fn page_size(&self) -> usize; +} + +/// An allocator instance +/// +/// Instances of this type are used to allocate blocks of memory. For best +/// results only use one of these. Currently doesn't implement `Drop` to release +/// lingering memory back to the OS. That may happen eventually though! +pub struct Dlmalloc<A = System>(dlmalloc::Dlmalloc<A>); + +#[cfg(target_family = "wasm")] +#[path = "wasm.rs"] +mod sys; + +#[cfg(any(target_os = "linux", target_os = "macos"))] +#[path = "unix.rs"] +mod sys; + +#[cfg(not(any(target_os = "linux", target_os = "macos", target_family = "wasm")))] +#[path = "dummy.rs"] +mod sys; + +impl Dlmalloc<System> { + /// Creates a new instance of an allocator + pub const fn new() -> Dlmalloc<System> { + Dlmalloc(dlmalloc::Dlmalloc::new(System::new())) + } +} + +impl<A> Dlmalloc<A> { + /// Creates a new instance of an allocator + pub const fn new_with_allocator(sys_allocator: A) -> Dlmalloc<A> { + Dlmalloc(dlmalloc::Dlmalloc::new(sys_allocator)) + } +} + +impl<A: Allocator> Dlmalloc<A> { + /// Allocates `size` bytes with `align` align. + /// + /// Returns a null pointer if allocation fails. Returns a valid pointer + /// otherwise. + /// + /// Safety and contracts are largely governed by the `GlobalAlloc::alloc` + /// method contracts. + #[inline] + pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 { + if align <= self.0.malloc_alignment() { + self.0.malloc(size) + } else { + self.0.memalign(align, size) + } + } + + /// Same as `malloc`, except if the allocation succeeds it's guaranteed to + /// point to `size` bytes of zeros. + #[inline] + pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 { + let ptr = self.malloc(size, align); + if !ptr.is_null() && self.0.calloc_must_clear(ptr) { + ptr::write_bytes(ptr, 0, size); + } + ptr + } + + /// Deallocates a `ptr` with `size` and `align` as the previous request used + /// to allocate it. + /// + /// Safety and contracts are largely governed by the `GlobalAlloc::dealloc` + /// method contracts. + #[inline] + pub unsafe fn free(&mut self, ptr: *mut u8, size: usize, align: usize) { + drop((size, align)); + self.0.free(ptr) + } + + /// Reallocates `ptr`, a previous allocation with `old_size` and + /// `old_align`, to have `new_size` and the same alignment as before. + /// + /// Returns a null pointer if the memory couldn't be reallocated, but `ptr` + /// is still valid. Returns a valid pointer and frees `ptr` if the request + /// is satisfied. + /// + /// Safety and contracts are largely governed by the `GlobalAlloc::realloc` + /// method contracts. + #[inline] + pub unsafe fn realloc( + &mut self, + ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + ) -> *mut u8 { + if old_align <= self.0.malloc_alignment() { + self.0.realloc(ptr, new_size) + } else { + let res = self.malloc(new_size, old_align); + if !res.is_null() { + let size = cmp::min(old_size, new_size); + ptr::copy_nonoverlapping(ptr, res, size); + self.free(ptr, old_size, old_align); + } + res + } + } +} |