Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 6 additions & 40 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions oscars/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ oscars_derive = { path = "../oscars_derive", version = "0.1.0" }
rustc-hash = "2.1.1"
thin-vec = { version = "0.2", optional = true }
# Optional Trace/Finalize impls for external types.
boa_string = { git = "https://github.com/boa-dev/boa.git", branch = "main", optional = true }
icu_locale_core = { version = "2.2.0", default-features = false, optional = true }
either = { version = "1.16.0", optional = true }
arrayvec = { version = "0.7.6", optional = true }
Expand Down Expand Up @@ -44,7 +43,6 @@ mark_sweep_branded = ["mark_sweep"]
null_collector = ["mark_sweep"]
null_collector_branded = ["mark_sweep"]
thin-vec = ["dep:thin-vec", "mark_sweep"]
boa_string = ["dep:boa_string", "mark_sweep"]
icu = ["dep:icu_locale_core", "mark_sweep"]
either = ["dep:either", "mark_sweep"]
arrayvec = ["dep:arrayvec", "mark_sweep"]
5 changes: 1 addition & 4 deletions oscars/src/alloc/mempool3/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,7 @@ impl<'pool, T: ?Sized> PoolPointer<'pool, T> {
self.0
}

pub fn to_erased(self) -> ErasedPoolPointer<'pool>
where
T: Sized,
{
pub fn to_erased(self) -> ErasedPoolPointer<'pool> {
ErasedPoolPointer(self.0.cast::<u8>(), PhantomData)
}

Expand Down
3 changes: 0 additions & 3 deletions oscars/src/collectors/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,6 @@ impl Finalize for icu_locale_core::LanguageIdentifier {}
#[cfg(feature = "icu")]
impl Finalize for icu_locale_core::Locale {}

#[cfg(feature = "boa_string")]
impl Finalize for boa_string::JsString {}

#[cfg(feature = "either")]
impl<L: Finalize, R: Finalize> Finalize for either::Either<L, R> {}

Expand Down
1 change: 1 addition & 0 deletions oscars/src/collectors/mark_sweep/internals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod gc_header;
mod vtable;

pub(crate) use ephemeron::Ephemeron;
#[allow(unused_imports)]
pub(crate) use gc_header::{GcHeader, HeaderColor};
pub(crate) use vtable::{DropFn, FinalizeFn, TraceFn, VTable, vtable_of};

Expand Down
14 changes: 2 additions & 12 deletions oscars/src/collectors/mark_sweep/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ unsafe impl<T: Trace> Trace for OnceCell<T> {
mod icu_trace {
use icu_locale_core::{LanguageIdentifier, Locale};

use crate::mark_sweep::{Finalize, Trace};
use crate::mark_sweep::Trace;

// SAFETY: `LanguageIdentifier` doesn't have any traceable data.
unsafe impl Trace for LanguageIdentifier {
Expand All @@ -459,19 +459,9 @@ mod icu_trace {
}
}

#[cfg(feature = "boa_string")]
mod boa_string_trace {
use crate::mark_sweep::{Finalize, Trace};

// SAFETY: `boa_string::JsString` doesn't have any traceable data.
unsafe impl Trace for boa_string::JsString {
empty_trace!();
}
}

#[cfg(feature = "either")]
mod either_trace {
use crate::mark_sweep::{Finalize, Trace};
use crate::mark_sweep::Trace;

unsafe impl<L: Trace, R: Trace> Trace for either::Either<L, R> {
custom_trace!(this, mark, {
Expand Down
126 changes: 118 additions & 8 deletions oscars/src/collectors/mark_sweep_branded/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ use core::cell::{Ref, RefCell, RefMut};
use core::ops::{Deref, DerefMut};

/// A GC-aware wrapper around [`RefCell<T>`].
pub struct GcRefCell<T: Trace> {
///
/// Unlike a plain `RefCell`, this can hold unsized `T` through a `Box<T>`
/// indirection when needed. The `T: Trace` bound ensures the GC can visit
/// the contained value.
pub struct GcRefCell<T: Trace + ?Sized> {
inner: RefCell<T>,
}

Expand All @@ -16,7 +20,31 @@ impl<T: Trace> GcRefCell<T> {
inner: RefCell::new(value),
}
}
}

impl<T: Trace + Clone> Clone for GcRefCell<T> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}

impl<T: Trace + core::fmt::Debug + ?Sized> core::fmt::Debug for GcRefCell<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.inner, f)
}
}

impl<T: Trace + Default> Default for GcRefCell<T> {
#[inline]
fn default() -> Self {
Self::new(T::default())
}
}

impl<T: Trace + ?Sized> GcRefCell<T> {
/// Acquires a shared borrow of the inner value.
///
/// # Panics
Expand All @@ -34,37 +62,119 @@ impl<T: Trace> GcRefCell<T> {
pub fn borrow_mut(&self) -> GcRefMut<'_, T> {
GcRefMut(self.inner.borrow_mut())
}

pub fn try_borrow(&self) -> Result<GcRef<'_, T>, core::cell::BorrowError> {
self.inner.try_borrow().map(GcRef)
}

pub fn try_borrow_mut(&self) -> Result<GcRefMut<'_, T>, core::cell::BorrowMutError> {
self.inner.try_borrow_mut().map(GcRefMut)
}
}

/// A shared borrow guard returned by [`GcRefCell::borrow`].
pub struct GcRef<'a, T: Trace>(Ref<'a, T>);
pub struct GcRef<'a, T: Trace + ?Sized>(Ref<'a, T>);

impl<T: Trace> Deref for GcRef<'_, T> {
impl<T: Trace + ?Sized> Deref for GcRef<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}

impl<T: Trace + core::fmt::Debug + ?Sized> core::fmt::Debug for GcRef<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&**self, f)
}
}

impl<T: Trace + core::fmt::Display + ?Sized> core::fmt::Display for GcRef<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&**self, f)
}
}

impl<'a, T: Trace + ?Sized> GcRef<'a, T> {
/// Projects a `GcRef<T>` to a `GcRef<U>` via a closure, mirroring
/// [`Ref::map`].
pub fn map<U, F>(orig: Self, f: F) -> GcRef<'a, U>
where
U: Trace + ?Sized,
F: FnOnce(&T) -> &U,
{
GcRef(Ref::map(orig.0, f))
}

pub fn try_map<U: Trace + ?Sized, F>(orig: GcRef<'a, T>, f: F) -> Option<GcRef<'a, U>>
where
F: FnOnce(&T) -> Option<&U>,
{
Ref::filter_map(orig.0, f).ok().map(GcRef)
}

/// Casts a `GcRef<T>` to a `GcRef<U>` without type checking.
///
/// # Safety
///
/// `T` and `U` must be pointer-compatible. The underlying value must be
/// a valid `U`.
pub unsafe fn cast<U: Trace>(orig: GcRef<'a, T>) -> GcRef<'a, U> {
GcRef(Ref::map(orig.0, |t| unsafe {
&*((t as *const T).cast::<U>())
}))
}
}

/// A mutable borrow guard returned by [`GcRefCell::borrow_mut`].
pub struct GcRefMut<'a, T: Trace>(RefMut<'a, T>);
pub struct GcRefMut<'a, T: Trace + ?Sized>(RefMut<'a, T>);

impl<T: Trace> Deref for GcRefMut<'_, T> {
impl<T: Trace + ?Sized> Deref for GcRefMut<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}

impl<T: Trace> DerefMut for GcRefMut<'_, T> {
impl<T: Trace + ?Sized> DerefMut for GcRefMut<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}

impl<T: Trace> Finalize for GcRefCell<T> {}
impl<'a, T: Trace + ?Sized> GcRefMut<'a, T> {
/// Projects a `GcRefMut<T>` to a `GcRefMut<U>` via a closure, mirroring
/// [`RefMut::map`].
pub fn map<U, F>(orig: Self, f: F) -> GcRefMut<'a, U>
where
U: Trace + ?Sized,
F: FnOnce(&mut T) -> &mut U,
{
GcRefMut(RefMut::map(orig.0, f))
}

pub fn try_map<U: Trace + ?Sized, F>(orig: GcRefMut<'a, T>, f: F) -> Option<GcRefMut<'a, U>>
where
F: FnOnce(&mut T) -> Option<&mut U>,
{
RefMut::filter_map(orig.0, f).ok().map(GcRefMut)
}

/// Casts a `GcRefMut<T>` to a `GcRefMut<U>` without type checking.
///
/// # Safety
///
/// `T` and `U` must be pointer compatible, the underlying value must be
/// a valid `U`
pub unsafe fn cast<U: Trace>(orig: GcRefMut<'a, T>) -> GcRefMut<'a, U> {
GcRefMut(RefMut::map(orig.0, |t| unsafe {
&mut *((t as *mut T).cast::<U>())
}))
}
}

impl<T: Trace + ?Sized> Finalize for GcRefCell<T> {}

unsafe impl<T: Trace> Trace for GcRefCell<T> {
unsafe impl<T: Trace + ?Sized> Trace for GcRefCell<T> {
unsafe fn trace(&self, tracer: &mut Tracer) {
let val = unsafe { &*self.inner.as_ptr() };
unsafe {
Expand Down
Loading