rsgc/
lib.rs

1//! # RSGC
2//! 
3//! RSGC is a garbage collector for Rust. It is designed to be used for languge runtimes. 
4//! 
5//! RSGC is concurrent and conservative-on-stack precise on heap garbage collector. 
6//! 
7//! For example usage see `examples` directory or implementations of basic types in `src/system` directory.
8//! 
9//! ## Features
10//! - Conservative on stack garbage collection, no need to register your pointers precisely.
11//! - Concurrent garbage collection, mutators are stoped only for small period of time.
12//! - Small latency, usually less than 20ms. 
13//! - A lot of tuning options. You can choose different region sizes, different GC heuristics, configure GC threads, etc.
14//! - Supports multiple mutators (threads) running and allocating at the same time.
15
16#![feature(
17    const_type_id,
18    const_refs_to_cell,
19    const_type_name,
20    panic_always_abort,
21    ptr_metadata,
22    core_intrinsics,
23    specialization,
24    thread_local,
25    ptr_sub_ptr,
26    portable_simd,
27    arbitrary_self_types
28)]
29#![allow(dead_code, unused_imports, incomplete_features)]
30
31use std::{cell::UnsafeCell, sync::atomic::AtomicPtr};
32
33pub mod heap;
34pub mod sync;
35pub mod system;
36pub mod utils;
37
38pub struct FormattedSize {
39    pub size: f64,
40}
41
42impl std::fmt::Display for FormattedSize {
43    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
44        let ksize = (self.size as f64) / 1024f64;
45
46        if ksize < 1f64 {
47            return write!(f, "{}B", self.size);
48        }
49
50        let msize = ksize / 1024f64;
51
52        if msize < 1f64 {
53            return write!(f, "{:.1}K", ksize);
54        }
55
56        let gsize = msize / 1024f64;
57
58        if gsize < 8f64 {
59            write!(f, "{:.1}M", msize)
60        } else {
61            write!(f, "{:.1}G", gsize)
62        }
63    }
64}
65
66impl std::fmt::Debug for FormattedSize {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{}", self)
69    }
70}
71
72pub fn formatted_size(size: usize) -> FormattedSize {
73    FormattedSize { size: size as f64 }
74}
75
76pub fn formatted_sizef(size: f64) -> FormattedSize {
77    FormattedSize { size: size as f64 }
78}
79
80static mut SINK: usize = 0;
81
82pub fn force_on_stack<T>(val: *const T) {
83    unsafe {
84        core::ptr::write_volatile(&mut SINK, val as usize);
85        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
86    }
87}
88
89#[macro_export]
90macro_rules! offsetof {
91    ($obj: ty, $($field: ident).+) => {{
92        #[allow(unused_unsafe)]
93        unsafe {
94            let addr = 0x4000 as *const $obj;
95            &(*addr).$($field).* as *const _ as usize - 0x4000
96        }
97    }
98    };
99}
100
101pub use heap::thread;
102use system::object::Allocation;
103
104/// Returns true if write barrier is required when writing to a field of type `T`.
105///
106/// Write barrier is required only if `T` contains heap pointers.
107pub const fn needs_write_barrier<T: Allocation>() -> bool {
108    !T::NO_HEAP_PTRS || (T::VARSIZE && !T::VARSIZE_NO_HEAP_PTRS)
109}
110
111pub mod prelude {
112    pub use super::heap;
113    pub use super::system;
114    pub use heap::thread::*;
115    pub use heap::region::*;
116    pub use system::{object::*, traits::*};
117}
118
119cfg_if::cfg_if! {
120    if #[cfg(not(any(feature="gc-satb", feature="gc-incremental-update", feature="gc-passive")))] {
121        compile_error!("No GC mode selected, enable one of through features: gc-satb, gc-incremental-update, gc-passive");
122    } else if #[cfg(all(feature="gc-satb", not(feature="gc-incremental-update"), not(feature = "gc-passive")))] {
123    } else if #[cfg(all(feature="gc-incremental-update", not(feature="gc-satb"), not(feature = "gc-passive")))] {
124    } else if #[cfg(all(feature="gc-passive", not(feature="gc-satb"), not(feature = "gc-incremental-update")))] {
125    } else {
126        compile_error!("Multiple GC modes selected, enable only one of through features: gc-satb, gc-incremental-update, gc-passive");
127    }
128}
129
130pub fn new_i32(thread: &mut prelude::Thread, x: i32) -> prelude::Handle<i32> {
131    let handle = thread.allocate(x);
132    handle
133}