Skip to content

Commit

Permalink
Merge pull request #101 from jacob-hughes/memaligned_malloc
Browse files Browse the repository at this point in the history
Use GC_memalign for larger allocations
  • Loading branch information
ltratt authored Nov 21, 2023
2 parents ad11770 + 339fdb6 commit ef706e8
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 11 deletions.
62 changes: 51 additions & 11 deletions library/alloc/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use std::boxed::Box;
use core::{
alloc::{AllocError, Allocator, GlobalAlloc, Layout},
any::Any,
borrow,
borrow, cmp,
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
marker::{FinalizerSafe, PhantomData, Unsize},
mem::MaybeUninit,
ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver},
ptr,
ptr::{drop_in_place, null_mut, NonNull},
};

Expand All @@ -27,35 +28,74 @@ use core::sync::atomic::{self, AtomicU64};
#[cfg(not(no_global_oom_handling))]
use core::gc::ReferenceFree;

// Fast-path for low alignment values
pub const MIN_ALIGN: usize = 8;

#[derive(Debug)]
pub struct GcAllocator;

unsafe impl GlobalAlloc for GcAllocator {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
unsafe { boehm::GC_malloc(layout.size()) as *mut u8 }
unsafe { gc_malloc(layout) }
}

#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
unsafe {
boehm::GC_free(ptr);
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { gc_free(ptr, layout) }
}

#[inline]
unsafe fn realloc(&self, ptr: *mut u8, _: Layout, new_size: usize) -> *mut u8 {
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { gc_realloc(ptr, layout, new_size) }
}
}

#[inline]
unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
unsafe { boehm::GC_malloc(layout.size()) as *mut u8 }
} else {
unsafe { boehm::GC_memalign(layout.align(), layout.size()) as *mut u8 }
}
}

#[inline]
unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
if old_layout.align() <= MIN_ALIGN && old_layout.align() <= new_size {
unsafe { boehm::GC_realloc(ptr, new_size) as *mut u8 }
} else {
unsafe {
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());

let new_ptr = gc_malloc(new_layout);
if !new_ptr.is_null() {
let size = cmp::min(old_layout.size(), new_size);
ptr::copy_nonoverlapping(ptr, new_ptr, size);
gc_free(ptr, old_layout);
}
new_ptr
}
}
}

#[inline]
unsafe fn gc_free(ptr: *mut u8, _: Layout) {
unsafe {
boehm::GC_free(ptr);
}
}

unsafe impl Allocator for GcAllocator {
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
let ptr = boehm::GC_malloc(layout.size()) as *mut u8;
let ptr = NonNull::new_unchecked(ptr);
Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
size => unsafe {
let ptr = gc_malloc(layout);
let ptr = NonNull::new(ptr).ok_or(AllocError)?;
Ok(NonNull::slice_from_raw_parts(ptr, size))
},
}
}

Expand Down
12 changes: 12 additions & 0 deletions library/alloc/tests/gc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::gc::GcAllocator;

#[repr(align(1024))]
struct S(u8);

#[test]
fn large_alignment() {
let x = Box::new_in(S(123), GcAllocator);
let ptr = Box::into_raw(x);
assert!(!ptr.is_null());
assert!(ptr.is_aligned());
}
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ mod c_str;
mod const_fns;
mod cow_str;
mod fmt;
mod gc;
mod heap;
mod linked_list;
mod rc;
Expand Down
2 changes: 2 additions & 0 deletions library/boehm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub struct ProfileStats {
extern "C" {
pub fn GC_malloc(nbytes: usize) -> *mut u8;

pub fn GC_memalign(align: usize, nbytes: usize) -> *mut u8;

pub fn GC_realloc(old: *mut u8, new_size: usize) -> *mut u8;

pub fn GC_free(dead: *mut u8);
Expand Down

0 comments on commit ef706e8

Please sign in to comment.