Skip to content

Commit

Permalink
Move GcAllocator to library/alloc
Browse files Browse the repository at this point in the history
This means that programs can import `std::gc::GcAllocator` without
needing to use the `#[feature(rustc_private)]` attribute.
  • Loading branch information
jacob-hughes committed Oct 30, 2023
1 parent 44d1d62 commit f4ff60d
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 172 deletions.
81 changes: 74 additions & 7 deletions library/alloc/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use crate::boxed::Box;
use std::boxed::Box;

use core::{
alloc::{AllocError, Allocator, GlobalAlloc, Layout},
any::Any,
borrow,
cmp::Ordering,
Expand All @@ -62,19 +63,77 @@ use core::sync::atomic::{self, AtomicU64};
#[cfg(not(no_global_oom_handling))]
use core::gc::ReferenceFree;

use boehm::GcAllocator;

#[cfg(test)]
mod tests;

#[unstable(feature = "gc", issue = "none")]
static ALLOCATOR: GcAllocator = GcAllocator;

#[cfg(profile_gc)]
static FINALIZERS_REGISTERED: AtomicU64 = AtomicU64::new(0);
#[cfg(profile_gc)]
static FINALIZERS_COMPLETED: AtomicU64 = AtomicU64::new(0);

#[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 }
}

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

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

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()))
}
}

unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
}

impl GcAllocator {
pub fn force_gc() {
unsafe { boehm::GC_gcollect() }
}
}

pub fn init_gc() {
unsafe { boehm::GC_init() }
}

/// Returns true if thread was successfully registered.
pub unsafe fn register_thread(stack_base: *mut u8) -> bool {
unsafe { boehm::GC_register_my_thread(stack_base) == 0 }
}

/// Returns true if thread was successfully unregistered.
pub unsafe fn unregister_thread() -> bool {
unsafe { boehm::GC_unregister_my_thread() == 0 }
}

pub fn suppress_gc_warnings() {
unsafe { boehm::GC_set_warn_proc(&boehm::GC_ignore_warn_proc as *const _ as *mut u8) };
}

pub fn thread_registered() -> bool {
unsafe { boehm::GC_thread_is_registered() != 0 }
}

struct GcBox<T: ?Sized>(T);

/// A multi-threaded garbage collected pointer.
Expand Down Expand Up @@ -279,7 +338,7 @@ impl<T> Gc<T> {
}

unsafe {
ALLOCATOR.register_finalizer(
boehm::GC_register_finalizer_no_order(
self.ptr.as_ptr() as *mut u8,
Some(finalizer::<T>),
null_mut(),
Expand All @@ -292,7 +351,15 @@ impl<T> Gc<T> {
#[unstable(feature = "gc", issue = "none")]
pub fn unregister_finalizer(&mut self) {
let ptr = self.ptr.as_ptr() as *mut GcBox<T> as *mut u8;
ALLOCATOR.unregister_finalizer(ptr);
unsafe {
boehm::GC_register_finalizer(
ptr,
None,
::core::ptr::null_mut(),
::core::ptr::null_mut(),
::core::ptr::null_mut(),
);
}
}
}

Expand Down
70 changes: 0 additions & 70 deletions library/boehm/src/boehm.rs

This file was deleted.

134 changes: 51 additions & 83 deletions library/boehm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,102 +1,70 @@
#![no_std]
#![feature(allocator_api)]

use core::{
alloc::{AllocError, Allocator, GlobalAlloc, Layout},
ptr::NonNull,
};

mod boehm;

pub struct GcAllocator;

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

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

#[inline]
unsafe fn realloc(&self, ptr: *mut u8, _: Layout, new_size: usize) -> *mut u8 {
boehm::GC_realloc(ptr, new_size) as *mut u8
}
#[repr(C)]
#[derive(Default)]
pub struct ProfileStats {
/// Heap size in bytes (including area unmapped to OS).
pub heapsize_full: usize,
/// Total bytes contained in free and unmapped blocks.
pub free_bytes_full: usize,
/// Amount of memory unmapped to OS.
pub unmapped_bytes: usize,
/// Number of bytes allocated since the recent collection.
pub bytes_allocd_since_gc: usize,
/// Number of bytes allocated before the recent collection.
/// The value may wrap.
pub allocd_bytes_before_gc: usize,
/// Number of bytes not considered candidates for garbage collection.
pub non_gc_bytes: usize,
/// Garbage collection cycle number.
/// The value may wrap.
pub gc_no: usize,
/// Number of marker threads (excluding the initiating one).
pub markers_m1: usize,
/// Approximate number of reclaimed bytes after recent collection.
pub bytes_reclaimed_since_gc: usize,
/// Approximate number of bytes reclaimed before the recent collection.
/// The value may wrap.
pub reclaimed_bytes_before_gc: usize,
/// Number of bytes freed explicitly since the recent GC.
pub expl_freed_bytes_since_gc: usize,
}

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()))
}
}
#[link(name = "gc")]
extern "C" {
pub fn GC_malloc(nbytes: usize) -> *mut u8;

unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
}
pub fn GC_realloc(old: *mut u8, new_size: usize) -> *mut u8;

impl GcAllocator {
pub fn force_gc() {
unsafe { boehm::GC_gcollect() }
}
pub fn GC_free(dead: *mut u8);

pub fn GC_register_finalizer(
ptr: *mut u8,
finalizer: Option<unsafe extern "C" fn(*mut u8, *mut u8)>,
client_data: *mut u8,
old_finalizer: *mut extern "C" fn(*mut u8, *mut u8),
old_client_data: *mut *mut u8,
);

pub unsafe fn register_finalizer(
&self,
obj: *mut u8,
pub fn GC_register_finalizer_no_order(
ptr: *mut u8,
finalizer: Option<unsafe extern "C" fn(*mut u8, *mut u8)>,
client_data: *mut u8,
old_finalizer: *mut extern "C" fn(*mut u8, *mut u8),
old_client_data: *mut *mut u8,
) {
boehm::GC_register_finalizer_no_order(
obj,
finalizer,
client_data,
old_finalizer,
old_client_data,
)
}
);

pub fn unregister_finalizer(&self, gcbox: *mut u8) {
unsafe {
boehm::GC_register_finalizer(
gcbox,
None,
::core::ptr::null_mut(),
::core::ptr::null_mut(),
::core::ptr::null_mut(),
);
}
}
pub fn GC_gcollect();

pub fn init() {
unsafe { boehm::GC_init() }
}
pub fn GC_thread_is_registered() -> u32;

/// Returns true if thread was successfully registered.
pub unsafe fn register_thread(stack_base: *mut u8) -> bool {
boehm::GC_register_my_thread(stack_base) == 0
}
pub fn GC_register_my_thread(stack_base: *mut u8) -> i32;

/// Returns true if thread was successfully unregistered.
pub unsafe fn unregister_thread() -> bool {
boehm::GC_unregister_my_thread() == 0
}
pub fn GC_unregister_my_thread() -> i32;

pub fn thread_registered() -> bool {
unsafe { boehm::GC_thread_is_registered() != 0 }
}
pub fn GC_init();

pub fn allow_register_threads() {
unsafe { boehm::GC_allow_register_threads() }
}
pub fn GC_set_warn_proc(level: *mut u8);

pub fn suppress_warnings() {
unsafe { boehm::GC_set_warn_proc(&boehm::GC_ignore_warn_proc as *const _ as *mut u8) };
}
pub fn GC_ignore_warn_proc(proc: *mut u8, word: usize);
}
2 changes: 1 addition & 1 deletion library/std/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use core::{mem, ptr};
pub use alloc_crate::alloc::*;

#[unstable(feature = "gc", issue = "none")]
pub use alloc_crate::boehm::GcAllocator;
pub use alloc_crate::gc::GcAllocator;

/// The default memory allocator provided by the operating system.
///
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ pub use core::u8;
#[allow(deprecated, deprecated_in_future)]
pub use core::usize;

#[unstable(feature = "gc", issue = "none")]
pub use alloc_crate::gc::GcAllocator;

pub mod f32;
pub mod f64;

Expand Down
6 changes: 2 additions & 4 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,18 @@ macro_rules! rtunwrap {
#[cfg_attr(test, allow(dead_code))]
unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
unsafe {
use crate::alloc::GcAllocator;

// Internally, this registers a SIGSEGV handler to compute the start and
// end bounds of the data segment. This means it *MUST* be called before
// rustc registers its own SIGSEGV stack overflow handler.
//
// Rust's stack overflow handler will unregister and return if there is
// no stack overflow, allowing the fault to "fall-through" to Boehm's
// handler next time. The is not true in the reverse case.
GcAllocator::init();
crate::gc::init();

// Boehm GC prints OOM warnings which are useful for debugging, but
// annoying when building the compiler in release mode.
GcAllocator::suppress_warnings();
crate::gc::suppress_warnings();

sys::init(argc, argv, sigpipe);

Expand Down
Loading

0 comments on commit f4ff60d

Please sign in to comment.