use crate::{ finalizer_safe, internals::GcBox, trace::{Finalize, Trace}, Allocator, }; use std::{ cell::Cell, cmp::Ordering, fmt::{self, Debug, Display}, hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, ptr::{self, addr_of_mut, NonNull}, rc::Rc, }; // Technically, this function is safe, since we're just modifying the address of a pointer without // dereferencing it. pub(crate) fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { // SAFETY: this should be safe as ptr must be a valid nonnull unsafe { ptr::write(addr_of_mut!(ptr).cast::<*mut u8>(), data.cast::()); } ptr } /// A garbage-collected pointer type over an immutable value. pub struct Gc { pub(crate) inner_ptr: Cell>>, pub(crate) marker: PhantomData>, } impl Gc { /// Constructs a new `Gc` with the given value. pub fn new(value: T) -> Self { // Create GcBox and allocate it to heap. // // Note: Allocator can cause Collector to run let inner_ptr = Allocator::allocate(GcBox::new(value)); // SAFETY: inner_ptr was just allocated, so it must be a valid value that implements [`Trace`] unsafe { (*inner_ptr.as_ptr()).value().unroot() } let gc = Self { inner_ptr: Cell::new(inner_ptr), marker: PhantomData, }; gc.set_root(); gc } /// Consumes the `Gc`, returning a wrapped raw pointer. /// /// To avoid a memory leak, the pointer must be converted back to a `Gc` using [`Gc::from_raw`]. #[allow(clippy::use_self)] pub fn into_raw(this: Gc) -> NonNull> { let ptr = this.inner_ptr.get(); std::mem::forget(this); ptr } } impl Gc { /// Returns `true` if the two `Gc`s point to the same allocation. pub fn ptr_eq(this: &Self, other: &Self) -> bool { GcBox::ptr_eq(this.inner(), other.inner()) } /// Constructs a `Gc` from a raw pointer. /// /// The raw pointer must have been returned by a previous call to [`Gc::into_raw`][Gc::into_raw] /// where `U` must have the same size and alignment as `T`. /// /// # Safety /// /// This function is unsafe because improper use may lead to memory corruption, double-free, /// or misbehaviour of the garbage collector. #[must_use] pub const unsafe fn from_raw(ptr: NonNull>) -> Self { Self { inner_ptr: Cell::new(ptr), marker: PhantomData, } } /// Return a rooted `Gc` from a `GcBox` pointer pub(crate) unsafe fn from_ptr(ptr: NonNull>) -> Self { // SAFETY: the caller must ensure that the pointer is valid. unsafe { ptr.as_ref().root_inner(); let gc = Self { inner_ptr: Cell::new(ptr), marker: PhantomData, }; gc.set_root(); gc } } } /// Returns the given pointer with its root bit cleared. pub(crate) unsafe fn clear_root_bit( ptr: NonNull>, ) -> NonNull> { let ptr = ptr.as_ptr(); let data = ptr.cast::(); let addr = data as isize; let ptr = set_data_ptr(ptr, data.wrapping_offset((addr & !1) - addr)); // SAFETY: ptr must be a non null value unsafe { NonNull::new_unchecked(ptr) } } impl Gc { fn rooted(&self) -> bool { self.inner_ptr.get().as_ptr().cast::() as usize & 1 != 0 } pub(crate) fn set_root(&self) { let ptr = self.inner_ptr.get().as_ptr(); let data = ptr.cast::(); let addr = data as isize; let ptr = set_data_ptr(ptr, data.wrapping_offset((addr | 1) - addr)); // SAFETY: ptr must be a non null value. unsafe { self.inner_ptr.set(NonNull::new_unchecked(ptr)); } } fn clear_root(&self) { // SAFETY: inner_ptr must be a valid non-null pointer to a live GcBox. unsafe { self.inner_ptr.set(clear_root_bit(self.inner_ptr.get())); } } pub(crate) fn inner_ptr(&self) -> NonNull> { assert!(finalizer_safe()); // SAFETY: inner_ptr must be a live GcBox. Calling this on a dropped GcBox // can result in Undefined Behavior. unsafe { clear_root_bit(self.inner_ptr.get()) } } fn inner(&self) -> &GcBox { // SAFETY: Please see Gc::inner_ptr() unsafe { self.inner_ptr().as_ref() } } } impl Finalize for Gc {} // SAFETY: `Gc` maintains it's own rootedness and implements all methods of // Trace. It is not possible to root an already rooted `Gc` and vice versa. unsafe impl Trace for Gc { unsafe fn trace(&self) { // SAFETY: Inner must be live and allocated GcBox. unsafe { self.inner().trace_inner(); } } unsafe fn weak_trace(&self) { self.inner().weak_trace_inner(); } unsafe fn root(&self) { assert!(!self.rooted(), "Can't double-root a Gc"); // Try to get inner before modifying our state. Inner may be // inaccessible due to this method being invoked during the sweeping // phase, and we don't want to modify our state before panicking. self.inner().root_inner(); self.set_root(); } unsafe fn unroot(&self) { assert!(self.rooted(), "Can't double-unroot a Gc"); // Try to get inner before modifying our state. Inner may be // inaccessible due to this method being invoked during the sweeping // phase, and we don't want to modify our state before panicking. self.inner().unroot_inner(); self.clear_root(); } fn run_finalizer(&self) { Finalize::finalize(self); } } impl Clone for Gc { fn clone(&self) -> Self { // SAFETY: `&self` is a valid Gc pointer. unsafe { Self::from_ptr(self.inner_ptr()) } } } impl Deref for Gc { type Target = T; fn deref(&self) -> &T { self.inner().value() } } impl Drop for Gc { fn drop(&mut self) { // If this pointer was a root, we should unroot it. if self.rooted() { self.inner().unroot_inner(); } } } impl Default for Gc { fn default() -> Self { Self::new(Default::default()) } } #[allow(clippy::inline_always)] impl PartialEq for Gc { #[inline(always)] fn eq(&self, other: &Self) -> bool { **self == **other } } impl Eq for Gc {} #[allow(clippy::inline_always)] impl PartialOrd for Gc { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { (**self).partial_cmp(&**other) } #[inline(always)] fn lt(&self, other: &Self) -> bool { **self < **other } #[inline(always)] fn le(&self, other: &Self) -> bool { **self <= **other } #[inline(always)] fn gt(&self, other: &Self) -> bool { **self > **other } #[inline(always)] fn ge(&self, other: &Self) -> bool { **self >= **other } } impl Ord for Gc { fn cmp(&self, other: &Self) -> Ordering { (**self).cmp(&**other) } } impl Hash for Gc { fn hash(&self, state: &mut H) { (**self).hash(state); } } impl Display for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&**self, f) } } impl Debug for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&**self, f) } } impl fmt::Pointer for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&self.inner(), f) } } impl std::borrow::Borrow for Gc { fn borrow(&self) -> &T { self } } impl AsRef for Gc { fn as_ref(&self) -> &T { self } }