diff --git a/library/alloc/src/gc.rs b/library/alloc/src/gc.rs index 24ed545e34e56..5fe0d35bf1241 100644 --- a/library/alloc/src/gc.rs +++ b/library/alloc/src/gc.rs @@ -45,6 +45,7 @@ use crate::boxed::Box; use std::boxed::Box; use core::{ + alloc::{AllocError, Allocator, GlobalAlloc, Layout}, any::Any, borrow, cmp::Ordering, @@ -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, 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, _: 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); /// A multi-threaded garbage collected pointer. @@ -279,7 +338,7 @@ impl Gc { } unsafe { - ALLOCATOR.register_finalizer( + boehm::GC_register_finalizer_no_order( self.ptr.as_ptr() as *mut u8, Some(finalizer::), null_mut(), @@ -292,7 +351,15 @@ impl Gc { #[unstable(feature = "gc", issue = "none")] pub fn unregister_finalizer(&mut self) { let ptr = self.ptr.as_ptr() as *mut GcBox 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(), + ); + } } } diff --git a/library/boehm/src/boehm.rs b/library/boehm/src/boehm.rs deleted file mode 100644 index 7633a0909a318..0000000000000 --- a/library/boehm/src/boehm.rs +++ /dev/null @@ -1,70 +0,0 @@ -#[repr(C)] -#[derive(Default)] -pub struct ProfileStats { - /// Heap size in bytes (including area unmapped to OS). - pub(crate) heapsize_full: usize, - /// Total bytes contained in free and unmapped blocks. - pub(crate) free_bytes_full: usize, - /// Amount of memory unmapped to OS. - pub(crate) unmapped_bytes: usize, - /// Number of bytes allocated since the recent collection. - pub(crate) bytes_allocd_since_gc: usize, - /// Number of bytes allocated before the recent collection. - /// The value may wrap. - pub(crate) allocd_bytes_before_gc: usize, - /// Number of bytes not considered candidates for garbage collection. - pub(crate) non_gc_bytes: usize, - /// Garbage collection cycle number. - /// The value may wrap. - pub(crate) gc_no: usize, - /// Number of marker threads (excluding the initiating one). - pub(crate) markers_m1: usize, - /// Approximate number of reclaimed bytes after recent collection. - pub(crate) bytes_reclaimed_since_gc: usize, - /// Approximate number of bytes reclaimed before the recent collection. - /// The value may wrap. - pub(crate) reclaimed_bytes_before_gc: usize, - /// Number of bytes freed explicitly since the recent GC. - pub(crate) expl_freed_bytes_since_gc: usize, -} - -#[link(name = "gc")] -extern "C" { - pub(crate) fn GC_malloc(nbytes: usize) -> *mut u8; - - pub(crate) fn GC_realloc(old: *mut u8, new_size: usize) -> *mut u8; - - pub(crate) fn GC_free(dead: *mut u8); - - pub(crate) fn GC_register_finalizer( - ptr: *mut u8, - finalizer: Option, - client_data: *mut u8, - old_finalizer: *mut extern "C" fn(*mut u8, *mut u8), - old_client_data: *mut *mut u8, - ); - - pub(crate) fn GC_register_finalizer_no_order( - ptr: *mut u8, - finalizer: Option, - client_data: *mut u8, - old_finalizer: *mut extern "C" fn(*mut u8, *mut u8), - old_client_data: *mut *mut u8, - ); - - pub(crate) fn GC_gcollect(); - - pub(crate) fn GC_thread_is_registered() -> u32; - - pub(crate) fn GC_register_my_thread(stack_base: *mut u8) -> i32; - - pub(crate) fn GC_unregister_my_thread() -> i32; - - pub(crate) fn GC_allow_register_threads(); - - pub(crate) fn GC_init(); - - pub(crate) fn GC_set_warn_proc(level: *mut u8); - - pub(crate) fn GC_ignore_warn_proc(proc: *mut u8, word: usize); -} diff --git a/library/boehm/src/lib.rs b/library/boehm/src/lib.rs index 45c40a9041fd0..c63a02864b4ec 100644 --- a/library/boehm/src/lib.rs +++ b/library/boehm/src/lib.rs @@ -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, 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, _: 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, + 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, 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); } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 75ed4c43bde5a..3201c7e1e68be 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -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. /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3225be806da3a..e00c49da03bd5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -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; diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 9e012e339a579..5bb6b1afeab8e 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -94,8 +94,6 @@ 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. @@ -103,11 +101,11 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // 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); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index d84e70723e68f..ae6ecb1453071 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -158,7 +158,6 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; -use crate::alloc::GcAllocator; use crate::any::Any; use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; @@ -523,7 +522,7 @@ impl Builder { let stack_start = unsafe { imp::guard::get_stack_start().unwrap() }; if stack_start != crate::ptr::null_mut() { unsafe { - GcAllocator::register_thread(&stack_start as *const _ as *mut u8); + crate::gc::register_thread(&stack_start as *const _ as *mut u8); } } @@ -541,7 +540,7 @@ impl Builder { // SAFETY: The thread has no more work to do, so can be unregisterd. unsafe { - GcAllocator::unregister_thread(); + crate::gc::unregister_thread(); } // SAFETY: `their_packet` as been built just above and moved by the diff --git a/tests/ui/runtime/gc/multithreaded.rs b/tests/ui/runtime/gc/multithreaded.rs index faa93525272ad..f776bbb88c845 100644 --- a/tests/ui/runtime/gc/multithreaded.rs +++ b/tests/ui/runtime/gc/multithreaded.rs @@ -1,6 +1,5 @@ // run-pass #![feature(gc)] -#![feature(rustc_private)] use std::alloc::GcAllocator; use std::gc::Gc; diff --git a/tests/ui/runtime/gc/run_finalizers.rs b/tests/ui/runtime/gc/run_finalizers.rs index 8a1cd080e486e..52d526e5f933a 100644 --- a/tests/ui/runtime/gc/run_finalizers.rs +++ b/tests/ui/runtime/gc/run_finalizers.rs @@ -1,7 +1,6 @@ // run-pass // ignore-tidy-linelength #![feature(gc)] -#![feature(rustc_private)] use std::gc::{Gc, GcAllocator}; use std::sync::atomic::{self, AtomicUsize}; diff --git a/tests/ui/runtime/gc/unchecked_finalizer.rs b/tests/ui/runtime/gc/unchecked_finalizer.rs index e0807b23931f0..afbbb87d770d4 100644 --- a/tests/ui/runtime/gc/unchecked_finalizer.rs +++ b/tests/ui/runtime/gc/unchecked_finalizer.rs @@ -1,7 +1,6 @@ // run-pass // ignore-tidy-linelength #![feature(gc)] -#![feature(rustc_private)] #![feature(negative_impls)] use std::gc::{Gc, GcAllocator, FinalizeUnchecked}; diff --git a/tests/ui/runtime/gc/zero_vecs.rs b/tests/ui/runtime/gc/zero_vecs.rs index ba3d6ddeeae64..b7d196da402b0 100644 --- a/tests/ui/runtime/gc/zero_vecs.rs +++ b/tests/ui/runtime/gc/zero_vecs.rs @@ -1,7 +1,6 @@ // run-pass // ignore-tidy-linelength #![feature(gc)] -#![feature(rustc_private)] #![feature(negative_impls)] #![feature(allocator_api)] #![allow(unused_assignments)]