|
|
|
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<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
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A garbage-collected pointer type over an immutable value.
|
|
|
|
pub struct Gc<T: Trace + ?Sized + 'static> {
|
|
|
|
pub(crate) inner_ptr: Cell<NonNull<GcBox<T>>>,
|
|
|
|
pub(crate) marker: PhantomData<Rc<T>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace> Gc<T> {
|
|
|
|
/// Constructs a new `Gc<T>` 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
|
|
|
|
}
|
Redesign native functions and closures API (#2499)
This PR is a complete redesign of our current native functions and closures API.
I was a bit dissatisfied with our previous design (even though I created it 😆), because it had a lot of superfluous traits, a forced usage of `Gc<GcCell<T>>` and an overly restrictive `NativeObject` bound. This redesign, on the other hand, simplifies a lot our public API, with a simple `NativeCallable` struct that has several constructors for each type of required native function.
This new design doesn't require wrapping every capture type with `Gc<GcCell<T>>`, relaxes the trait requirement to `Trace + 'static` for captures, can be reused in both `JsObject` functions and (soonish) host defined functions, and is (in my opinion) a bit cleaner than the previous iteration. It also offers an `unsafe` API as an escape hatch for users that want to pass non-Copy closures which don't capture traceable types.
Would ask for bikeshedding about the names though, because I don't know if `NativeCallable` is the most precise name for this. Same about the constructor names; I added the `from` prefix to all of them because it's the "standard" practice, but seeing the API doesn't have any other method aside from `call`, it may be better to just remove the prefix altogether.
Let me know what you think :)
2 years ago
|
|
|
|
|
|
|
/// 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<T>) -> NonNull<GcBox<T>> {
|
|
|
|
let ptr = this.inner_ptr.get();
|
|
|
|
std::mem::forget(this);
|
|
|
|
ptr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> Gc<T> {
|
|
|
|
/// 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())
|
|
|
|
}
|
|
|
|
|
Redesign native functions and closures API (#2499)
This PR is a complete redesign of our current native functions and closures API.
I was a bit dissatisfied with our previous design (even though I created it 😆), because it had a lot of superfluous traits, a forced usage of `Gc<GcCell<T>>` and an overly restrictive `NativeObject` bound. This redesign, on the other hand, simplifies a lot our public API, with a simple `NativeCallable` struct that has several constructors for each type of required native function.
This new design doesn't require wrapping every capture type with `Gc<GcCell<T>>`, relaxes the trait requirement to `Trace + 'static` for captures, can be reused in both `JsObject` functions and (soonish) host defined functions, and is (in my opinion) a bit cleaner than the previous iteration. It also offers an `unsafe` API as an escape hatch for users that want to pass non-Copy closures which don't capture traceable types.
Would ask for bikeshedding about the names though, because I don't know if `NativeCallable` is the most precise name for this. Same about the constructor names; I added the `from` prefix to all of them because it's the "standard" practice, but seeing the API doesn't have any other method aside from `call`, it may be better to just remove the prefix altogether.
Let me know what you think :)
2 years ago
|
|
|
/// Constructs a `Gc<T>` from a raw pointer.
|
|
|
|
///
|
|
|
|
/// The raw pointer must have been returned by a previous call to [`Gc<U>::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<GcBox<T>>) -> 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<GcBox<T>>) -> 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<T: ?Sized + Trace>(
|
|
|
|
ptr: NonNull<GcBox<T>>,
|
|
|
|
) -> NonNull<GcBox<T>> {
|
|
|
|
let ptr = 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 { NonNull::new_unchecked(ptr) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> Gc<T> {
|
|
|
|
fn rooted(&self) -> bool {
|
|
|
|
self.inner_ptr.get().as_ptr().cast::<u8>() as usize & 1 != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn set_root(&self) {
|
|
|
|
let ptr = self.inner_ptr.get().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.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<GcBox<T>> {
|
|
|
|
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<T> {
|
|
|
|
// SAFETY: Please see Gc::inner_ptr()
|
|
|
|
unsafe { self.inner_ptr().as_ref() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> Finalize for Gc<T> {}
|
|
|
|
|
|
|
|
// 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<T: Trace + ?Sized> Trace for Gc<T> {
|
|
|
|
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<T>");
|
|
|
|
// 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<T>");
|
|
|
|
// 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<T: Trace + ?Sized> Clone for Gc<T> {
|
|
|
|
fn clone(&self) -> Self {
|
Redesign native functions and closures API (#2499)
This PR is a complete redesign of our current native functions and closures API.
I was a bit dissatisfied with our previous design (even though I created it 😆), because it had a lot of superfluous traits, a forced usage of `Gc<GcCell<T>>` and an overly restrictive `NativeObject` bound. This redesign, on the other hand, simplifies a lot our public API, with a simple `NativeCallable` struct that has several constructors for each type of required native function.
This new design doesn't require wrapping every capture type with `Gc<GcCell<T>>`, relaxes the trait requirement to `Trace + 'static` for captures, can be reused in both `JsObject` functions and (soonish) host defined functions, and is (in my opinion) a bit cleaner than the previous iteration. It also offers an `unsafe` API as an escape hatch for users that want to pass non-Copy closures which don't capture traceable types.
Would ask for bikeshedding about the names though, because I don't know if `NativeCallable` is the most precise name for this. Same about the constructor names; I added the `from` prefix to all of them because it's the "standard" practice, but seeing the API doesn't have any other method aside from `call`, it may be better to just remove the prefix altogether.
Let me know what you think :)
2 years ago
|
|
|
// SAFETY: `&self` is a valid Gc pointer.
|
|
|
|
unsafe { Self::from_ptr(self.inner_ptr()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> Deref for Gc<T> {
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
fn deref(&self) -> &T {
|
|
|
|
self.inner().value()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> Drop for Gc<T> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// If this pointer was a root, we should unroot it.
|
|
|
|
if self.rooted() {
|
|
|
|
self.inner().unroot_inner();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + Default> Default for Gc<T> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new(Default::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::inline_always)]
|
|
|
|
impl<T: Trace + ?Sized + PartialEq> PartialEq for Gc<T> {
|
|
|
|
#[inline(always)]
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
**self == **other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized + Eq> Eq for Gc<T> {}
|
|
|
|
|
|
|
|
#[allow(clippy::inline_always)]
|
|
|
|
impl<T: Trace + ?Sized + PartialOrd> PartialOrd for Gc<T> {
|
|
|
|
#[inline(always)]
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
(**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<T: Trace + ?Sized + Ord> Ord for Gc<T> {
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
(**self).cmp(&**other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized + Hash> Hash for Gc<T> {
|
|
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
|
(**self).hash(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized + Display> Display for Gc<T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
Display::fmt(&**self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized + Debug> Debug for Gc<T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
Debug::fmt(&**self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> fmt::Pointer for Gc<T> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt::Pointer::fmt(&self.inner(), f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> std::borrow::Borrow<T> for Gc<T> {
|
|
|
|
fn borrow(&self) -> &T {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Trace + ?Sized> AsRef<T> for Gc<T> {
|
|
|
|
fn as_ref(&self) -> &T {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|