comet/
lib.rs

1use std::mem::size_of;
2
3use gc_info_table::GCInfo;
4use header::HeapObjectHeader;
5use large_space::PreciseAllocation;
6
7macro_rules! as_atomic {
8    ($value: expr;$t: ident) => {
9        unsafe { core::mem::transmute::<_, &'_ core::sync::atomic::$t>($value as *const _) }
10    };
11}
12
13macro_rules! logln_if {
14    ($cond: expr, $($t:tt)*) => {
15        if $cond {
16            println!($($t)*);
17        }
18    };
19}
20/// rounds the given value `val` up to the nearest multiple
21/// of `align`
22pub fn align(value: u32, align: u32) -> u32 {
23    if align == 0 {
24        return value;
25    }
26
27    ((value + align - 1) / align) * align
28}
29macro_rules! log_if {
30    ($cond: expr, $($t:tt)*) => {
31        if $cond {
32            print!($($t)*);
33        }
34    };
35}
36pub mod allocation_config;
37pub mod allocator;
38pub mod block;
39pub mod block_allocator;
40pub mod gc_info_table;
41pub mod gcref;
42pub mod global_allocator;
43pub mod globals;
44pub mod header;
45pub mod heap;
46pub mod internal;
47pub mod large_space;
48pub mod marking;
49pub mod mmap;
50pub mod task_scheduler;
51pub mod visitor;
52
53pub struct GCPlatform;
54
55impl GCPlatform {
56    /// Initializes global state for GC.
57    pub fn initialize() {
58        #[cfg(target_family = "wasm")]
59        {
60            panic!("Invoke GCPlatform::initialize_wasm on WASM!");
61        }
62        unsafe {
63            gc_info_table::GCInfoTable::init(None);
64        }
65    }
66
67    pub unsafe fn initialize_wasm(
68        _gc_info_table_mem: &'static mut [u8; size_of::<GCInfo>() * (1 << 14)],
69    ) {
70    }
71}
72
73/// Configuration for heap constructor.
74#[repr(C)]
75pub struct Config {
76    /// How fast heap threshold should grow
77    pub heap_growth_factor: f64,
78    /// Heap size. It is heap size only for Immix block space. LargeObjectSpace will allocate until System OOMs
79    pub heap_size: usize,
80    /// Maximum heap size before first GC
81    pub max_heap_size: usize,
82    /// Maximum eden heap size before first GC (does not matter atm)
83    pub max_eden_size: usize,
84    /// Enables verbose printing
85    pub verbose: bool,
86    /// Enable generational GC (does not work atm)
87    pub generational: bool,
88}
89
90impl Default for Config {
91    fn default() -> Self {
92        Self {
93            generational: false,
94            verbose: false,
95            max_eden_size: 64 * 1024,
96            max_heap_size: 256 * 1024,
97            heap_growth_factor: 1.5,
98            heap_size: 1 * 1024 * 1024 * 1024,
99        }
100    }
101}
102
103/// Returns GC allocation size of object.
104pub fn gc_size(ptr: *const HeapObjectHeader) -> usize {
105    unsafe {
106        let size = (*ptr).get_size();
107        if size == 0 {
108            (*PreciseAllocation::from_cell(ptr as _)).cell_size()
109        } else {
110            size
111        }
112    }
113}
114
115pub mod c_api {
116
117    use std::ptr::{null_mut, NonNull};
118
119    use crate::{
120        gc_info_table::{GCInfo, GC_TABLE},
121        gcref::{UntypedGcRef, WeakGcRef},
122        header::HeapObjectHeader,
123        heap::Heap,
124        internal::gc_info::GCInfoIndex,
125        visitor::Visitor,
126        Config, GCPlatform,
127    };
128
129    #[no_mangle]
130    pub extern "C" fn comet_gc_size(ptr: *const HeapObjectHeader) -> usize {
131        super::gc_size(ptr)
132    }
133    #[no_mangle]
134    pub extern "C" fn comet_default_config() -> Config {
135        Config::default()
136    }
137    #[no_mangle]
138    pub extern "C" fn comet_init() {
139        GCPlatform::initialize();
140    }
141    #[no_mangle]
142    pub extern "C" fn comet_heap_create(config: Config) -> *mut Heap {
143        Box::into_raw(Heap::new(config))
144    }
145    /// Free comet heap
146    #[no_mangle]
147    pub extern "C" fn comet_heap_free(heap: *mut Heap) {
148        unsafe {
149            Box::from_raw(heap);
150        }
151    }
152
153    /// Add GC constraint to the Comet Heap. Each constraint is executed when marking starts
154    /// to obtain list of root objects.
155    #[no_mangle]
156    pub extern "C" fn comet_heap_add_constraint(
157        heap: *mut Heap,
158        data: *mut u8,
159        callback: extern "C" fn(*mut u8, *mut Visitor),
160    ) {
161        unsafe {
162            (*heap).add_constraint(move |vis: &mut Visitor| {
163                let data = data;
164                callback(data, vis as *mut _);
165            });
166        }
167    }
168
169    /// Add core constraints to the heap. This one will setup stack scanning routines.
170    #[no_mangle]
171    pub extern "C" fn comet_heap_add_core_constraints(heap: *mut Heap) {
172        unsafe {
173            (*heap).add_core_constraints();
174        }
175    }
176
177    #[no_mangle]
178    pub extern "C" fn comet_heap_collect(heap: *mut Heap) {
179        unsafe {
180            (*heap).collect_garbage();
181        }
182    }
183
184    #[no_mangle]
185    pub extern "C" fn comet_heap_collect_if_necessary_or_defer(heap: *mut Heap) {
186        unsafe {
187            (*heap).collect_if_necessary_or_defer();
188        }
189    }
190
191    #[no_mangle]
192    pub extern "C" fn comet_heap_allocate_weak(
193        heap: *mut Heap,
194        object: *mut HeapObjectHeader,
195    ) -> WeakGcRef {
196        unsafe {
197            (*heap).allocate_weak(UntypedGcRef {
198                header: NonNull::new_unchecked(object),
199            })
200        }
201    }
202
203    /// Allocates memory and returns pointer. NULL is returned if no memory is available.
204    #[no_mangle]
205    pub extern "C" fn comet_heap_allocate(
206        heap: *mut Heap,
207        size: usize,
208        index: GCInfoIndex,
209    ) -> *mut HeapObjectHeader {
210        unsafe {
211            match (*heap).allocate_raw(size, index) {
212                Some(mem) => mem.header.as_ptr(),
213                None => null_mut(),
214            }
215        }
216    }
217
218    /// Allocates memory and returns pointer. When no memory is left process is aborted.
219    #[no_mangle]
220    pub extern "C" fn comet_heap_allocate_or_fail(
221        heap: *mut Heap,
222        size: usize,
223        index: GCInfoIndex,
224    ) -> *mut HeapObjectHeader {
225        unsafe { (*heap).allocate_raw_or_fail(size, index).header.as_ptr() }
226    }
227
228    /// Upgrade weak ref. If it is still alive then pointer is returned otherwise NULL is returned.
229    #[no_mangle]
230    pub extern "C" fn comet_weak_upgrade(weak: WeakGcRef) -> *mut HeapObjectHeader {
231        match weak.upgrade() {
232            Some(ptr) => ptr.header.as_ptr(),
233            None => null_mut(),
234        }
235    }
236
237    #[no_mangle]
238    pub extern "C" fn comet_trace(vis: *mut Visitor, ptr: *mut HeapObjectHeader) {
239        if ptr.is_null() {
240            return;
241        }
242        unsafe {
243            (*vis).trace_untyped(UntypedGcRef {
244                header: NonNull::new_unchecked(ptr),
245            })
246        }
247    }
248
249    #[no_mangle]
250    pub extern "C" fn comet_trace_conservatively(
251        vis: *mut Visitor,
252        from: *const u8,
253        to: *const u8,
254    ) {
255        unsafe { (*vis).trace_conservatively(from, to) }
256    }
257
258    #[no_mangle]
259    pub extern "C" fn comet_add_gc_info(info: GCInfo) -> GCInfoIndex {
260        unsafe { GC_TABLE.add_gc_info(info) }
261    }
262
263    #[no_mangle]
264    pub extern "C" fn comet_get_gc_info(index: GCInfoIndex) -> *mut GCInfo {
265        unsafe { GC_TABLE.get_gc_info_mut(index) as *mut _ }
266    }
267}