Browse Source

Reduce `WeakGc<T>` memory usage (#3492)

* Reduce `WeakGc<T>` memory usage

Makes inner storage of `WeakGc<T>` store `()` in place of `Ephemeron` value,
insteadthe of a clone of the `Gc<T>` which is already stored in the key.

Reducing the size by the width of one pointer.

* Apply review
pull/3498/head
Haled Odat 1 year ago committed by GitHub
parent
commit
13ba869d2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      boa_gc/src/internals/ephemeron_box.rs
  2. 17
      boa_gc/src/pointers/ephemeron.rs
  3. 2
      boa_gc/src/pointers/gc.rs
  4. 15
      boa_gc/src/pointers/weak.rs

18
boa_gc/src/internals/ephemeron_box.rs

@ -139,21 +139,33 @@ impl<K: Trace, V: Trace> EphemeronBox<K, V> {
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<K>> {
pub(crate) unsafe fn key_ptr(&self) -> Option<NonNull<GcBox<K>>> {
// 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<K>> {
// 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`]

17
boa_gc/src/pointers/ephemeron.rs

@ -33,6 +33,23 @@ impl<K: Trace, V: Trace + Clone> Ephemeron<K, V> {
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<Gc<K>> {
// 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 {

2
boa_gc/src/pointers/gc.rs

@ -59,7 +59,7 @@ impl<T: Trace> Gc<T> {
// `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
}

15
boa_gc/src/pointers/weak.rs

@ -8,33 +8,36 @@ use std::hash::{Hash, Hasher};
#[derive(Debug, Trace, Finalize)]
#[repr(transparent)]
pub struct WeakGc<T: Trace + 'static> {
inner: Ephemeron<T, Gc<T>>,
inner: Ephemeron<T, ()>,
}
impl<T: Trace> WeakGc<T> {
/// Creates a new weak pointer for a garbage collected value.
#[inline]
#[must_use]
pub fn new(value: &Gc<T>) -> 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<Gc<T>> {
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<T, Gc<T>> {
pub(crate) const fn inner(&self) -> &Ephemeron<T, ()> {
&self.inner
}
}
@ -47,8 +50,8 @@ impl<T: Trace> Clone for WeakGc<T> {
}
}
impl<T: Trace> From<Ephemeron<T, Gc<T>>> for WeakGc<T> {
fn from(inner: Ephemeron<T, Gc<T>>) -> Self {
impl<T: Trace> From<Ephemeron<T, ()>> for WeakGc<T> {
fn from(inner: Ephemeron<T, ()>) -> Self {
Self { inner }
}
}

Loading…
Cancel
Save