diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 13ae0cb..4b93671 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,13 +38,3 @@ jobs: run: rustup update stable && rustup default stable && rustup target add wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown --release - - alloc_api: - name: Allocator API - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly && rustup default nightly - - run: cargo test --features 'allocator-api global' - diff --git a/Cargo.toml b/Cargo.toml index a8724e2..a86999f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dlmalloc" -version = "0.1.4" +version = "0.2.0" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" @@ -40,6 +40,4 @@ global = [] # Enable very expensive debug checks in this crate debug = [] -# Enable experimental support for the standard library's unstable allocator API. -allocator-api = [] rustc-dep-of-std = ['core', 'compiler_builtins/rustc-dep-of-std'] diff --git a/src/dlmalloc.rs b/src/dlmalloc.rs index 06e3e89..d16f523 100644 --- a/src/dlmalloc.rs +++ b/src/dlmalloc.rs @@ -7,9 +7,9 @@ use core::cmp; use core::mem; use core::ptr; -use sys; +use Allocator; -pub struct Dlmalloc { +pub struct Dlmalloc { smallmap: u32, treemap: u32, smallbins: [*mut Chunk; (NSMALLBINS + 1) * 2], @@ -24,31 +24,9 @@ pub struct Dlmalloc { trim_check: usize, least_addr: *mut u8, release_checks: usize, + system_allocator: A, } - -unsafe impl Send for Dlmalloc {} - -pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc { - smallmap: 0, - treemap: 0, - smallbins: [0 as *mut _; (NSMALLBINS + 1) * 2], - treebins: [0 as *mut _; NTREEBINS], - dvsize: 0, - topsize: 0, - dv: 0 as *mut _, - top: 0 as *mut _, - footprint: 0, - max_footprint: 0, - seg: Segment { - base: 0 as *mut _, - size: 0, - next: 0 as *mut _, - flags: 0, - }, - trim_check: 0, - least_addr: 0 as *mut _, - release_checks: 0, -}; +unsafe impl Send for Dlmalloc {} // TODO: document this const NSMALLBINS: usize = 32; @@ -108,7 +86,34 @@ fn leftshift_for_tree_index(x: u32) -> u32 { } } -impl Dlmalloc { +impl Dlmalloc { + pub const fn new(system_allocator: A) -> Dlmalloc { + Dlmalloc { + smallmap: 0, + treemap: 0, + smallbins: [0 as *mut _; (NSMALLBINS + 1) * 2], + treebins: [0 as *mut _; NTREEBINS], + dvsize: 0, + topsize: 0, + dv: 0 as *mut _, + top: 0 as *mut _, + footprint: 0, + max_footprint: 0, + seg: Segment { + base: 0 as *mut _, + size: 0, + next: 0 as *mut _, + flags: 0, + }, + trim_check: 0, + least_addr: 0 as *mut _, + release_checks: 0, + system_allocator, + } + } +} + +impl Dlmalloc { // TODO: can we get rid of this? pub fn malloc_alignment(&self) -> usize { mem::size_of::() * 2 @@ -225,7 +230,7 @@ impl Dlmalloc { } pub unsafe fn calloc_must_clear(&self, ptr: *mut u8) -> bool { - !sys::allocates_zeros() || !Chunk::mmapped(Chunk::from_mem(ptr)) + !self.system_allocator.allocates_zeros() || !Chunk::mmapped(Chunk::from_mem(ptr)) } pub unsafe fn malloc(&mut self, size: usize) -> *mut u8 { @@ -344,6 +349,7 @@ impl Dlmalloc { self.sys_alloc(nb) } + /// allocates system resources unsafe fn sys_alloc(&mut self, size: usize) -> *mut u8 { self.check_malloc_state(); // keep in sync with max_request @@ -352,7 +358,7 @@ impl Dlmalloc { DEFAULT_GRANULARITY, ); - let (tbase, tsize, flags) = sys::alloc(asize); + let (tbase, tsize, flags) = self.system_allocator.alloc(asize); if tbase.is_null() { return tbase; } @@ -533,7 +539,7 @@ impl Dlmalloc { let oldmmsize = oldsize + offset + self.mmap_foot_pad(); let newmmsize = self.mmap_align(nb + 6 * mem::size_of::() + self.malloc_alignment() - 1); - let ptr = sys::remap( + let ptr = self.system_allocator.remap( (oldp as *mut u8).offset(-(offset as isize)), oldmmsize, newmmsize, @@ -555,7 +561,7 @@ impl Dlmalloc { } fn mmap_align(&self, a: usize) -> usize { - align_up(a, sys::page_size()) + align_up(a, self.system_allocator.page_size()) } // Only call this with power-of-two alignment and alignment > @@ -631,7 +637,10 @@ impl Dlmalloc { let prevsize = (*p).prev_foot; if Chunk::mmapped(p) { psize += prevsize + self.mmap_foot_pad(); - if sys::free((p as *mut u8).offset(-(prevsize as isize)), psize) { + if self + .system_allocator + .free((p as *mut u8).offset(-(prevsize as isize)), psize) + { self.footprint -= psize; } return; @@ -1161,7 +1170,10 @@ impl Dlmalloc { if Chunk::mmapped(p) { psize += prevsize + self.mmap_foot_pad(); - if sys::free((p as *mut u8).offset(-(prevsize as isize)), psize) { + if self + .system_allocator + .free((p as *mut u8).offset(-(prevsize as isize)), psize) + { self.footprint -= psize; } return; @@ -1242,10 +1254,13 @@ impl Dlmalloc { debug_assert!(!sp.is_null()); if !Segment::is_extern(sp) { - if Segment::can_release_part(sp) { + if Segment::can_release_part(&self.system_allocator, sp) { if (*sp).size >= extra && !self.has_segment_link(sp) { let newsize = (*sp).size - extra; - if sys::free_part((*sp).base, (*sp).size, newsize) { + if self + .system_allocator + .free_part((*sp).base, (*sp).size, newsize) + { released = extra; } } @@ -1295,7 +1310,7 @@ impl Dlmalloc { let next = (*sp).next; nsegs += 1; - if Segment::can_release_part(sp) && !Segment::is_extern(sp) { + if Segment::can_release_part(&self.system_allocator, sp) && !Segment::is_extern(sp) { let p = self.align_as_chunk(base); let psize = Chunk::size(p); // We can unmap if the first chunk holds the entire segment and @@ -1311,7 +1326,7 @@ impl Dlmalloc { } else { self.unlink_large_chunk(tp); } - if sys::free(base, size) { + if self.system_allocator.free(base, size) { released += size; self.footprint -= size; // unlink our obsolete record @@ -1405,7 +1420,7 @@ impl Dlmalloc { ); debug_assert!(p as *mut u8 >= self.least_addr); debug_assert!(!self.is_small(sz)); - debug_assert_eq!(align_up(len, sys::page_size()), len); + debug_assert_eq!(align_up(len, self.system_allocator.page_size()), len); debug_assert_eq!((*Chunk::plus_offset(p, sz)).head, Chunk::fencepost_head()); debug_assert_eq!( (*Chunk::plus_offset(p, sz + mem::size_of::())).head, @@ -1746,8 +1761,8 @@ impl Segment { (*seg).flags & EXTERN != 0 } - unsafe fn can_release_part(seg: *mut Segment) -> bool { - sys::can_release_part((*seg).flags >> 1) + unsafe fn can_release_part(system_allocator: &A, seg: *mut Segment) -> bool { + system_allocator.can_release_part((*seg).flags >> 1) } unsafe fn sys_flags(seg: *mut Segment) -> u32 { @@ -1766,10 +1781,11 @@ impl Segment { #[cfg(test)] mod tests { use super::*; + use System; // Prime the allocator with some allocations such that there will be free // chunks in the treemap - unsafe fn setup_treemap(a: &mut Dlmalloc) { + unsafe fn setup_treemap(a: &mut Dlmalloc) { let large_request_size = NSMALLBINS * (1 << SMALLBIN_SHIFT); assert!(!a.is_small(large_request_size)); let large_request1 = a.malloc(large_request_size); @@ -1784,7 +1800,7 @@ mod tests { // Test allocating, with a non-empty treemap, a specific size that used to // trigger an integer overflow bug fn treemap_alloc_overflow_minimal() { - let mut a = DLMALLOC_INIT; + let mut a = Dlmalloc::new(System::new()); unsafe { setup_treemap(&mut a); let min_idx31_size = (0xc000 << TREEBIN_SHIFT) - a.chunk_overhead() + 1; @@ -1795,7 +1811,7 @@ mod tests { #[test] // Test allocating the maximum request size with a non-empty treemap fn treemap_alloc_max() { - let mut a = DLMALLOC_INIT; + let mut a = Dlmalloc::new(System::new()); unsafe { setup_treemap(&mut a); let max_request_size = a.max_request() - 1; diff --git a/src/dummy.rs b/src/dummy.rs new file mode 100644 index 0000000..d6ca226 --- /dev/null +++ b/src/dummy.rs @@ -0,0 +1,42 @@ +use core::ptr; +use Allocator; + +pub struct System { + _priv: (), +} + +impl System { + const fn new() -> System { + System { _priv: () } + } +} + +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + (ptr::null_mut(), 0, 0) + } + + fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { + false + } + + fn free(&self, ptr: *mut u8, size: usize) -> bool { + false + } + + fn can_release_part(&self, flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 1 + } +} diff --git a/src/global.rs b/src/global.rs index bb9ce04..fbac315 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,9 +1,5 @@ -#[cfg(feature = "allocator-api")] -use core::alloc::{Alloc, AllocErr}; use core::alloc::{GlobalAlloc, Layout}; use core::ops::{Deref, DerefMut}; -#[cfg(feature = "allocator-api")] -use core::ptr::NonNull; use Dlmalloc; @@ -35,35 +31,7 @@ unsafe impl GlobalAlloc for GlobalDlmalloc { } } -#[cfg(feature = "allocator-api")] -unsafe impl Alloc for GlobalDlmalloc { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - get().alloc(layout) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - get().dealloc(ptr, layout) - } - - #[inline] - unsafe fn realloc( - &mut self, - ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - Alloc::realloc(&mut *get(), ptr, layout, new_size) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - get().alloc_zeroed(layout) - } -} - -static mut DLMALLOC: Dlmalloc = Dlmalloc(::dlmalloc::DLMALLOC_INIT); +static mut DLMALLOC: Dlmalloc = Dlmalloc::new(); struct Instance; diff --git a/src/lib.rs b/src/lib.rs index 38826ef..22a43c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,33 +11,66 @@ //! Support for other platforms is largely untested and unused, but is used when //! testing this crate. -#![cfg_attr(feature = "allocator-api", feature(allocator_api))] -#![cfg_attr(target_env = "sgx", feature(llvm_asm))] -#![cfg_attr(not(feature = "allocator-api"), allow(dead_code))] +#![allow(dead_code)] #![no_std] #![deny(missing_docs)] -#[cfg(feature = "allocator-api")] -use core::alloc::{Alloc, AllocErr, Layout}; use core::cmp; use core::ptr; +use sys::System; -#[cfg(all(feature = "global", not(test)))] +#[cfg(feature = "global")] pub use self::global::GlobalDlmalloc; mod dlmalloc; -#[cfg(all(feature = "global", not(test)))] +#[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(dlmalloc::Dlmalloc); - -/// Constant initializer for `Dlmalloc` structure. -pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc(dlmalloc::DLMALLOC_INIT); +pub struct Dlmalloc(dlmalloc::Dlmalloc); #[cfg(target_arch = "wasm32")] #[path = "wasm.rs"] @@ -51,16 +84,25 @@ mod sys; #[path = "linux.rs"] mod sys; -#[cfg(target_env = "sgx")] -#[path = "sgx.rs"] +#[cfg(not(any(target_os = "linux", target_os = "macos", target_arch = "wasm32")))] +#[path = "dummy.rs"] mod sys; -impl Dlmalloc { - /// Creates a new instance of an allocator, same as `DLMALLOC_INIT`. - pub fn new() -> Dlmalloc { - DLMALLOC_INIT +impl Dlmalloc { + /// Creates a new instance of an allocator + pub const fn new() -> Dlmalloc { + Dlmalloc(dlmalloc::Dlmalloc::new(System::new())) } +} +impl Dlmalloc { + /// Creates a new instance of an allocator + pub const fn new_with_allocator(sys_allocator: A) -> Dlmalloc { + Dlmalloc(dlmalloc::Dlmalloc::new(sys_allocator)) + } +} + +impl Dlmalloc { /// Allocates `size` bytes with `align` align. /// /// Returns a null pointer if allocation fails. Returns a valid pointer @@ -129,34 +171,3 @@ impl Dlmalloc { } } } - -#[cfg(feature = "allocator-api")] -unsafe impl Alloc for Dlmalloc { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - let ptr = ::malloc(self, layout.size(), layout.align()); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: ptr::NonNull, layout: Layout) { - ::free(self, ptr.as_ptr(), layout.size(), layout.align()) - } - - #[inline] - unsafe fn realloc( - &mut self, - ptr: ptr::NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let ptr = ::realloc(self, ptr.as_ptr(), layout.size(), layout.align(), new_size); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - let ptr = ::calloc(self, layout.size(), layout.align()); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } -} diff --git a/src/linux.rs b/src/linux.rs index cbc4ef1..42e6549 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1,51 +1,77 @@ extern crate libc; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let addr = libc::mmap( - 0 as *mut _, - size, - libc::PROT_WRITE | libc::PROT_READ, - libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, - -1, - 0, - ); - if addr == libc::MAP_FAILED { - (ptr::null_mut(), 0, 0) - } else { - (addr as *mut u8, size, 0) - } +/// System setting for Linux +pub struct System { + _priv: (), } -pub unsafe fn remap(ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 { - let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 }; - let ptr = libc::mremap(ptr as *mut _, oldsize, newsize, flags); - if ptr == libc::MAP_FAILED { - ptr::null_mut() - } else { - ptr as *mut u8 +impl System { + pub const fn new() -> System { + System { _priv: () } } } -pub unsafe fn free_part(ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { - let rc = libc::mremap(ptr as *mut _, oldsize, newsize, 0); - if rc != libc::MAP_FAILED { - return true; +#[cfg(feature = "global")] +static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let addr = unsafe { + libc::mmap( + 0 as *mut _, + size, + libc::PROT_WRITE | libc::PROT_READ, + libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, + -1, + 0, + ) + }; + if addr == libc::MAP_FAILED { + (ptr::null_mut(), 0, 0) + } else { + (addr as *mut u8, size, 0) + } } - libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 -} -pub unsafe fn free(ptr: *mut u8, size: usize) -> bool { - libc::munmap(ptr as *mut _, size) == 0 -} + fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 { + let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 }; + let ptr = unsafe { libc::mremap(ptr as *mut _, oldsize, newsize, flags) }; + if ptr == libc::MAP_FAILED { + ptr::null_mut() + } else { + ptr as *mut u8 + } + } -pub fn can_release_part(_flags: u32) -> bool { - true -} + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { + unsafe { + let rc = libc::mremap(ptr as *mut _, oldsize, newsize, 0); + if rc != libc::MAP_FAILED { + return true; + } + libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 + } + } -#[cfg(feature = "global")] -static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + fn free(&self, ptr: *mut u8, size: usize) -> bool { + unsafe { libc::munmap(ptr as *mut _, size) == 0 } + } + + fn can_release_part(&self, _flags: u32) -> bool { + true + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 4096 + } +} #[cfg(feature = "global")] pub fn acquire_global_lock() { @@ -56,11 +82,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) } } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 4096 -} diff --git a/src/macos.rs b/src/macos.rs index 5a94813..d131271 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -1,41 +1,65 @@ extern crate libc; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let addr = libc::mmap( - 0 as *mut _, - size, - libc::PROT_WRITE | libc::PROT_READ, - libc::MAP_ANON | libc::MAP_PRIVATE, - -1, - 0, - ); - if addr == libc::MAP_FAILED { - (ptr::null_mut(), 0, 0) - } else { - (addr as *mut u8, size, 0) - } +/// System setting for MacOS +pub struct System { + _priv: (), } -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - ptr::null_mut() +impl System { + pub const fn new() -> System { + System { _priv: () } + } } -pub unsafe fn free_part(ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { - libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 -} +#[cfg(feature = "global")] +static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; -pub unsafe fn free(ptr: *mut u8, size: usize) -> bool { - libc::munmap(ptr as *mut _, size) == 0 -} +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let addr = unsafe { + libc::mmap( + 0 as *mut _, + size, + libc::PROT_WRITE | libc::PROT_READ, + libc::MAP_ANON | libc::MAP_PRIVATE, + -1, + 0, + ) + }; + if addr == libc::MAP_FAILED { + (ptr::null_mut(), 0, 0) + } else { + (addr as *mut u8, size, 0) + } + } -pub fn can_release_part(_flags: u32) -> bool { - true -} + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } -#[cfg(feature = "global")] -static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { + unsafe { libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 } + } + + fn free(&self, ptr: *mut u8, size: usize) -> bool { + unsafe { libc::munmap(ptr as *mut _, size) == 0 } + } + + fn can_release_part(&self, _flags: u32) -> bool { + true + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 4096 + } +} #[cfg(feature = "global")] pub fn acquire_global_lock() { @@ -46,11 +70,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) } } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 4096 -} diff --git a/src/sgx.rs b/src/sgx.rs deleted file mode 100644 index 722bf03..0000000 --- a/src/sgx.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::ptr; -use core::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; - -// Do not remove inline: will result in relocation failure -#[inline(always)] -unsafe fn rel_ptr_mut(offset: u64) -> *mut T { - (image_base() + offset) as *mut T -} - -// Do not remove inline: will result in relocation failure -// For the same reason we use inline ASM here instead of an extern static to -// locate the base -#[inline(always)] -fn image_base() -> u64 { - let base; - unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; - base -} - -pub unsafe fn alloc(_size: usize) -> (*mut u8, usize, u32) { - extern "C" { - static HEAP_BASE: u64; - static HEAP_SIZE: usize; - } - static INIT: AtomicBool = ATOMIC_BOOL_INIT; - // No ordering requirement since this function is protected by the global lock. - if !INIT.swap(true, Ordering::Relaxed) { - (rel_ptr_mut(HEAP_BASE), HEAP_SIZE, 0) - } else { - (ptr::null_mut(), 0, 0) - } -} - -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - ptr::null_mut() -} - -pub unsafe fn free_part(_ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { - false -} - -pub unsafe fn free(_ptr: *mut u8, _size: usize) -> bool { - false -} - -pub fn can_release_part(_flags: u32) -> bool { - false -} - -#[cfg(feature = "global")] -pub fn acquire_global_lock() { - compile_error!("The `global` feature is not implemented for the SGX platform") -} - -#[cfg(feature = "global")] -pub fn release_global_lock() { - compile_error!("The `global` feature is not implemented for the SGX platform") -} - -pub fn allocates_zeros() -> bool { - false -} - -pub fn page_size() -> usize { - 0x1000 -} diff --git a/src/wasm.rs b/src/wasm.rs index f63e8fa..381fb02 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1,30 +1,56 @@ use core::arch::wasm32; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let pages = size / page_size(); - let prev = wasm32::memory_grow(0, pages); - if prev == usize::max_value() { - return (ptr::null_mut(), 0, 0); - } - ((prev * page_size()) as *mut u8, pages * page_size(), 0) +/// System setting for Wasm +pub struct System { + _priv: (), } -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - // TODO: I think this can be implemented near the end? - ptr::null_mut() +impl System { + pub const fn new() -> System { + System { _priv: () } + } } -pub unsafe fn free_part(_ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { - false -} +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let pages = size / self.page_size(); + let prev = wasm32::memory_grow(0, pages); + if prev == usize::max_value() { + return (ptr::null_mut(), 0, 0); + } + ( + (prev * self.page_size()) as *mut u8, + pages * self.page_size(), + 0, + ) + } -pub unsafe fn free(_ptr: *mut u8, _size: usize) -> bool { - false -} + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + // TODO: I think this can be implemented near the end? + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + false + } -pub fn can_release_part(_flags: u32) -> bool { - false + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 64 * 1024 + } } #[cfg(feature = "global")] @@ -36,11 +62,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { // single threaded, no need! } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 64 * 1024 -} diff --git a/tests/global.rs b/tests/global.rs index c803ccc..1e9bc66 100644 --- a/tests/global.rs +++ b/tests/global.rs @@ -1,12 +1,10 @@ -#![cfg(all(feature = "allocator-api", feature = "global"))] -#![feature(global_allocator)] - extern crate dlmalloc; use std::collections::HashMap; use std::thread; #[global_allocator] +#[cfg(feature = "global")] static A: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc; #[test]