mirror of https://github.com/boa-dev/boa.git
Browse Source
* Find roots when running GC Attempt to address the issue #2773. The existing implementation had an expensive overhead of managing root counts, especially for mutable borrow of GcRefCell. Instead of managing the root counts, this change counts the number of Gc/WeakGc handles located in Gc heap objects and total number of them. Then, we can find whether there is a root by comparing those numbers. * Fix clippy errors * Keep reference counts in Box * Addressing comment * Fix clippy errors * Fix typo * non_root_count includes mark bit * give a spacepull/3176/head
Choongwoo Han
1 year ago
committed by
GitHub
16 changed files with 238 additions and 440 deletions
@ -1,87 +0,0 @@
|
||||
use std::ptr::{self, addr_of_mut, NonNull}; |
||||
|
||||
/// A [`NonNull`] pointer with a `rooted` tag.
|
||||
///
|
||||
/// This pointer can be created only from pointers that are 2-byte aligned. In other words,
|
||||
/// the pointer must point to an address that is a multiple of 2.
|
||||
pub(crate) struct Rootable<T: ?Sized> { |
||||
ptr: NonNull<T>, |
||||
} |
||||
|
||||
impl<T: ?Sized> Copy for Rootable<T> {} |
||||
|
||||
impl<T: ?Sized> Clone for Rootable<T> { |
||||
fn clone(&self) -> Self { |
||||
Self { ptr: self.ptr } |
||||
} |
||||
} |
||||
|
||||
impl<T: ?Sized> std::fmt::Debug for Rootable<T> { |
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||
f.debug_struct("Rootable") |
||||
.field("ptr", &self.as_ptr()) |
||||
.field("is_rooted", &self.is_rooted()) |
||||
.finish() |
||||
} |
||||
} |
||||
|
||||
impl<T: ?Sized> Rootable<T> { |
||||
/// Creates a new `Rootable` without checking if the [`NonNull`] is properly aligned.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptr` must be 2-byte aligned.
|
||||
pub(crate) const unsafe fn new_unchecked(ptr: NonNull<T>) -> Self { |
||||
Self { ptr } |
||||
} |
||||
|
||||
/// Returns `true` if the pointer is rooted.
|
||||
pub(crate) fn is_rooted(self) -> bool { |
||||
self.ptr.as_ptr().cast::<u8>() as usize & 1 != 0 |
||||
} |
||||
|
||||
/// Returns a pointer with the same address as `self` but rooted.
|
||||
pub(crate) fn rooted(self) -> Self { |
||||
let ptr = self.ptr.as_ptr(); |
||||
let data = ptr.cast::<u8>(); |
||||
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::new_unchecked(NonNull::new_unchecked(ptr)) } |
||||
} |
||||
|
||||
/// Returns a pointer with the same address as `self` but unrooted.
|
||||
pub(crate) fn unrooted(self) -> Self { |
||||
let ptr = self.ptr.as_ptr(); |
||||
let data = ptr.cast::<u8>(); |
||||
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::new_unchecked(NonNull::new_unchecked(ptr)) } |
||||
} |
||||
|
||||
/// Acquires the underlying `NonNull` pointer.
|
||||
pub(crate) fn as_ptr(self) -> NonNull<T> { |
||||
self.unrooted().ptr |
||||
} |
||||
|
||||
/// Returns a shared reference to the pointee.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`NonNull::as_ref`].
|
||||
pub(crate) unsafe fn as_ref(&self) -> &T { |
||||
// SAFETY: it is the caller's job to ensure the safety of this operation.
|
||||
unsafe { self.as_ptr().as_ref() } |
||||
} |
||||
} |
||||
|
||||
// Technically, this function is safe, since we're just modifying the address of a pointer without
|
||||
// dereferencing it.
|
||||
fn set_data_ptr<T: ?Sized, U>(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::<u8>()); |
||||
} |
||||
ptr |
||||
} |
Loading…
Reference in new issue