#![feature(
negative_impls, // !Send is much cleaner than `PhantomData<Rc>`
untagged_unions, // I want to avoid ManuallyDrop in unions
const_fn_trait_bound, // So generics + const fn are unstable, huh?
generic_associated_types, // Finally!
const_trait_impl,
ptr_metadata
)]
#![allow(
clippy::missing_safety_doc, // Entirely internal code
)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use core::mem::ManuallyDrop;
use core::fmt::{self, Debug, Formatter};
use alloc::boxed::Box;
use alloc::vec::Vec;
use zerogc::prelude::*;
pub mod state;
#[macro_use]
pub mod utils;
pub mod collector;
pub mod handle;
use crate::collector::{RawCollectorImpl};
pub use crate::collector::{WeakCollectorRef, CollectorRef, CollectorId};
pub use crate::state::{CollectionManager, RawContext};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ContextState {
Active,
SafePoint {
collection_id: u64
},
#[cfg_attr(not(feature = "sync"), allow(unused))] Frozen,
}
impl ContextState {
#[cfg_attr(not(feature = "sync"), allow(unused))] fn is_frozen(&self) -> bool {
matches!(*self, ContextState::Frozen)
}
}
pub struct CollectorContext<C: RawCollectorImpl> {
raw: *mut C::RawContext,
root: bool
}
impl<C: RawCollectorImpl> CollectorContext<C> {
pub(crate) unsafe fn register_root(collector: &CollectorRef<C>) -> Self {
CollectorContext {
raw: Box::into_raw(ManuallyDrop::into_inner(
C::RawContext::register_new(collector)
)),
root: true, }
}
#[inline]
pub fn collector(&self) -> &C {
unsafe { (*self.raw).collector() }
}
#[inline(always)]
unsafe fn with_shadow_stack<R, T: Trace>(
&self, value: *mut &mut T, func: impl FnOnce() -> R
) -> R {
let old_link = (*(*self.raw).shadow_stack_ptr()).last;
let new_link = ShadowStackLink {
element: C::as_dyn_trace_pointer(value),
prev: old_link
};
(*(*self.raw).shadow_stack_ptr()).last = &new_link;
let result = func();
debug_assert_eq!(
(*(*self.raw).shadow_stack_ptr()).last,
&new_link
);
(*(*self.raw).shadow_stack_ptr()).last = new_link.prev;
result
}
#[cold]
unsafe fn trigger_basic_safepoint<T: Trace>(&self, element: &mut &mut T) {
self.with_shadow_stack(element, || {
(*self.raw).trigger_safepoint();
})
}
}
impl<C: RawCollectorImpl> Drop for CollectorContext<C> {
#[inline]
fn drop(&mut self) {
if self.root {
unsafe {
C::Manager::free_context(self.collector(), self.raw);
}
}
}
}
unsafe impl<C: RawCollectorImpl> GcContext for CollectorContext<C> {
type System = CollectorRef<C>;
type Id = CollectorId<C>;
#[inline]
unsafe fn unchecked_safepoint<T: Trace>(&self, value: &mut &mut T) {
debug_assert_eq!((*self.raw).state(), ContextState::Active);
if (*self.raw).collector().should_collect() {
self.trigger_basic_safepoint(value);
}
debug_assert_eq!((*self.raw).state(), ContextState::Active);
}
unsafe fn freeze(&mut self) {
(*self.raw).collector().manager().freeze_context(&*self.raw);
}
unsafe fn unfreeze(&mut self) {
(*self.raw).collector().manager().unfreeze_context(&*self.raw);
}
#[inline]
unsafe fn recurse_context<T, F, R>(&self, value: &mut &mut T, func: F) -> R
where T: Trace, F: for<'gc> FnOnce(&'gc mut Self, &'gc mut T) -> R {
debug_assert_eq!((*self.raw).state(), ContextState::Active);
self.with_shadow_stack(value, || {
let mut sub_context = ManuallyDrop::new(CollectorContext {
raw: self.raw,
root: false
});
let result = func(&mut *sub_context, value);
debug_assert!(!sub_context.root);
core::mem::forget(sub_context);
debug_assert_eq!((*self.raw).state(), ContextState::Active);
result
})
}
#[inline]
fn system(&self) -> &'_ Self::System {
unsafe { (&*self.raw).collector_ref() }
}
#[inline]
fn id(&self) -> Self::Id {
unsafe { (&*self.raw).collector() }.id()
}
}
impl<C: RawCollectorImpl> !Send for CollectorContext<C> {}
#[repr(C)]
#[derive(Debug)]
pub(crate) struct ShadowStackLink<T> {
pub element: T,
pub prev: *const ShadowStackLink<T>
}
impl<C: RawCollectorImpl> Debug for ShadowStack<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ShadowStack")
.field("last", &format_args!("{:p}", self.last))
.finish()
}
}
#[derive(Clone)]
pub struct ShadowStack<C: RawCollectorImpl> {
pub(crate) last: *const ShadowStackLink<C::DynTracePtr>
}
impl<C: RawCollectorImpl> ShadowStack<C> {
unsafe fn as_vec(&self) -> Vec<C::DynTracePtr> {
let mut result: Vec<_> = self.reverse_iter().collect();
result.reverse();
result
}
#[inline]
pub unsafe fn reverse_iter(&self) -> impl Iterator<Item=C::DynTracePtr> + '_ {
core::iter::successors(
self.last.as_ref(),
|link| link.prev.as_ref()
).map(|link| link.element)
}
}