diff --git a/boa_gc/src/internals/ephemeron_box.rs b/boa_gc/src/internals/ephemeron_box.rs index 3db5419513..13618524af 100644 --- a/boa_gc/src/internals/ephemeron_box.rs +++ b/boa_gc/src/internals/ephemeron_box.rs @@ -139,21 +139,33 @@ impl EphemeronBox { data.as_ref().map(|data| &data.value) } - /// Returns a reference to the ephemeron's key or None. + /// Returns the pointer to the ephemeron's key or None. /// /// # Safety /// /// The caller must ensure there are no live mutable references to the ephemeron box's data /// before calling this method. - pub(crate) unsafe fn key(&self) -> Option<&GcBox> { + pub(crate) unsafe fn key_ptr(&self) -> Option>> { // SAFETY: the garbage collector ensures the ephemeron doesn't mutate until // finalization. unsafe { let data = &*self.data.get(); - data.as_ref().map(|data| data.key.as_ref()) + data.as_ref().map(|data| data.key) } } + /// Returns a reference to the ephemeron's key or None. + /// + /// # Safety + /// + /// The caller must ensure there are no live mutable references to the ephemeron box's data + /// before calling this method. + pub(crate) unsafe fn key(&self) -> Option<&GcBox> { + // SAFETY: the garbage collector ensures the ephemeron doesn't mutate until + // finalization. + unsafe { self.key_ptr().map(|data| data.as_ref()) } + } + /// Marks this `EphemeronBox` as live. /// /// This doesn't mark the inner value of the ephemeron. [`ErasedEphemeronBox::trace`] diff --git a/boa_gc/src/pointers/ephemeron.rs b/boa_gc/src/pointers/ephemeron.rs index fd5fbab026..e687ab53ad 100644 --- a/boa_gc/src/pointers/ephemeron.rs +++ b/boa_gc/src/pointers/ephemeron.rs @@ -33,6 +33,23 @@ impl Ephemeron { unsafe { self.inner_ptr.as_ref().value().cloned() } } + /// Gets the stored key of this `Ephemeron`, or `None` if the key was already garbage collected. + #[inline] + #[must_use] + pub fn key(&self) -> Option> { + // SAFETY: this is safe because `Ephemeron` is tracked to always point to a valid pointer + // `inner_ptr`. + let key_ptr = unsafe { self.inner_ptr.as_ref().key_ptr() }?; + + // SAFETY: Returned pointer is valid, so this is safe. + unsafe { + key_ptr.as_ref().inc_ref_count(); + } + + // SAFETY: The gc pointer's reference count has been incremented, so this is safe. + Some(unsafe { Gc::from_raw(key_ptr) }) + } + /// Checks if the [`Ephemeron`] has a value. #[must_use] pub fn has_value(&self) -> bool { diff --git a/boa_gc/src/pointers/gc.rs b/boa_gc/src/pointers/gc.rs index c49ae8b0f4..7a15f063e7 100644 --- a/boa_gc/src/pointers/gc.rs +++ b/boa_gc/src/pointers/gc.rs @@ -59,7 +59,7 @@ impl Gc { // `unsafe` block. // - `set_kv`: `weak` is a newly created `EphemeronBox`, meaning it isn't possible to // collect it since `weak` is still live. - unsafe { weak.inner().inner_ptr().as_mut().set(&gc, gc.clone()) } + unsafe { weak.inner().inner_ptr().as_mut().set(&gc, ()) } gc } diff --git a/boa_gc/src/pointers/weak.rs b/boa_gc/src/pointers/weak.rs index 1acd98b3db..179d394c10 100644 --- a/boa_gc/src/pointers/weak.rs +++ b/boa_gc/src/pointers/weak.rs @@ -8,33 +8,36 @@ use std::hash::{Hash, Hasher}; #[derive(Debug, Trace, Finalize)] #[repr(transparent)] pub struct WeakGc { - inner: Ephemeron>, + inner: Ephemeron, } impl WeakGc { /// Creates a new weak pointer for a garbage collected value. + #[inline] #[must_use] pub fn new(value: &Gc) -> Self { Self { - inner: Ephemeron::new(value, value.clone()), + inner: Ephemeron::new(value, ()), } } /// Upgrade returns a `Gc` pointer for the internal value if the pointer is still live, or `None` /// if the value was already garbage collected. + #[inline] #[must_use] pub fn upgrade(&self) -> Option> { - self.inner.value() + self.inner.key() } /// Check if the [`WeakGc`] can be upgraded. + #[inline] #[must_use] pub fn is_upgradable(&self) -> bool { self.inner.has_value() } #[must_use] - pub(crate) const fn inner(&self) -> &Ephemeron> { + pub(crate) const fn inner(&self) -> &Ephemeron { &self.inner } } @@ -47,8 +50,8 @@ impl Clone for WeakGc { } } -impl From>> for WeakGc { - fn from(inner: Ephemeron>) -> Self { +impl From> for WeakGc { + fn from(inner: Ephemeron) -> Self { Self { inner } } }