Skip to content

Commit

Permalink
misc: general cleanup and renaming
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Mar 23, 2020
1 parent 081b73d commit 446f422
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 208 deletions.
113 changes: 27 additions & 86 deletions crates/mun_gc/src/handle.rs
Original file line number Diff line number Diff line change
@@ -1,118 +1,59 @@
use crate::{GCRuntime, Type};
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::sync::{Arc, Weak};

/// A `GCHandle` is what you interact with outside of the allocator. It is a pointer to a piece of
/// A `GCPtr` is what you interact with outside of the allocator. It is a pointer to a piece of
/// memory that points to the actual data stored in memory.
///
/// This creates an indirection that must be followed to get to the actual data of the object. Note
/// that the indirection pointer must therefor be pinned in memory whereas the pointer stored
/// at the indirection may change.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct GCHandle(RawGCHandle);
pub struct GCPtr(RawGCPtr);

/// A `GCHandle` is thread safe.
unsafe impl Send for GCHandle {}
unsafe impl Sync for GCHandle {}
/// A `GCPtr` is thread safe.
unsafe impl Send for GCPtr {}
unsafe impl Sync for GCPtr {}

/// A `RawGCHandle` is an unsafe version of a `GCHandle`. It represents the raw internal pointer
/// A `RawGCPtr` is an unsafe version of a `GCPtr`. It represents the raw internal pointer
/// semantics used by the runtime.
pub type RawGCHandle = *const *mut std::ffi::c_void;
pub type RawGCPtr = *const *mut std::ffi::c_void;

pub trait HasGCHandlePtr {
pub trait HasIndirectionPtr {
/// Returns a pointer to the referenced memory.
///
/// # Safety
///
/// This method is unsafe because casting to a generic type T may be unsafe. We don't know the
/// type of the stored data.
unsafe fn get_ptr<T: Sized>(&self) -> NonNull<T>;
}

impl HasGCHandlePtr for GCHandle {
unsafe fn get_ptr<T: Sized>(&self) -> NonNull<T> {
NonNull::new(*self.0)
.expect("indirection pointer is null")
.cast::<T>()
}
}

impl Into<RawGCHandle> for GCHandle {
fn into(self) -> RawGCHandle {
self.0
}
}

impl Into<GCHandle> for RawGCHandle {
fn into(self) -> GCHandle {
GCHandle(self)
}
}

/// A `GCHandle` that automatically roots and unroots its internal `GCHandle`.
pub struct GCRootHandle<T: Type, G: GCRuntime<T>> {
handle: GCHandle,
runtime: Weak<G>,
ty: PhantomData<T>,
}

impl<T: Type, G: GCRuntime<T>> Clone for GCRootHandle<T, G> {
fn clone(&self) -> Self {
if let Some(runtime) = self.runtime.upgrade() {
unsafe { runtime.root(self.handle) }
}
Self {
handle: self.handle,
runtime: self.runtime.clone(),
ty: Default::default(),
}
}
}
/// This is an unsafe method because derefencing could result in an access violation.
unsafe fn deref<T: Sized>(&self) -> *const T;

impl<T: Type, G: GCRuntime<T>> GCRootHandle<T, G> {
/// Constructs a new GCRootHandle from a runtime and a handle
/// Returns a mutable pointer to the referenced memory.
///
/// # Safety
///
/// This method is unsafe because the passed GCHandle could point to random memory.
pub unsafe fn new(runtime: &Arc<G>, handle: GCHandle) -> Self {
runtime.root(handle);
Self {
handle,
runtime: Arc::downgrade(runtime),
ty: Default::default(),
}
}

/// Returns the handle of this instance
pub fn handle(&self) -> GCHandle {
self.handle
/// This is an unsafe method because derefencing could result in an access violation.
unsafe fn deref_mut<T: Sized>(&self) -> *mut T {
self.deref::<T>() as *mut _
}
}

/// Unroots the handle consuming self and returning the unrooted handle
pub fn unroot(self) -> GCHandle {
self.handle
impl HasIndirectionPtr for GCPtr {
unsafe fn deref<T: Sized>(&self) -> *const T {
(*self.0).cast()
}
}

impl<T: Type, G: GCRuntime<T>> Into<GCHandle> for GCRootHandle<T, G> {
fn into(self) -> GCHandle {
self.handle
impl Into<RawGCPtr> for GCPtr {
fn into(self) -> RawGCPtr {
self.0
}
}

impl<T: Type, G: GCRuntime<T>> Drop for GCRootHandle<T, G> {
fn drop(&mut self) {
if let Some(runtime) = self.runtime.upgrade() {
unsafe { runtime.unroot(self.handle) }
}
impl Into<GCPtr> for RawGCPtr {
fn into(self) -> GCPtr {
GCPtr(self)
}
}

impl<T: Type, G: GCRuntime<T>> HasGCHandlePtr for GCRootHandle<T, G> {
unsafe fn get_ptr<R: Sized>(&self) -> NonNull<R> {
self.handle.get_ptr()
impl GCPtr {
pub(crate) fn as_ptr(self) -> RawGCPtr {
self.0
}
}
45 changes: 30 additions & 15 deletions crates/mun_gc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
mod handle;
mod mark_sweep;
mod root_handle;

pub use handle::{GCHandle, GCRootHandle, HasGCHandlePtr, RawGCHandle};
pub use handle::{GCPtr, HasIndirectionPtr, RawGCPtr};
pub use mark_sweep::MarkSweep;
pub use root_handle::GCRootHandle;

/// Contains stats about the current state of a GC implementation
#[derive(Debug, Clone, Default)]
pub struct Stats {
pub allocated_memory: usize,
}

/// A trait used by the GC to identify an object.
pub trait Type: Send + Sync {
type Trace: Iterator<Item = GCHandle>;
type Trace: Iterator<Item = GCPtr>;

/// Returns the size in bytes of an object of this type.
fn size(&self) -> usize;
Expand All @@ -15,29 +23,29 @@ pub trait Type: Send + Sync {
fn alignment(&self) -> usize;

/// Returns an iterator to iterate over all GC objects that are referenced by the given object.
fn trace(&self, obj: GCHandle) -> Self::Trace;
fn trace(&self, obj: GCPtr) -> Self::Trace;
}

/// An object that can be used to allocate and collect memory.
pub trait GCRuntime<T: Type>: Send + Sync {
/// Allocates an object of the given type returning a GCHandle
fn alloc_object(&self, ty: T) -> GCHandle;
/// Allocates an object of the given type returning a GCPtr
fn alloc(&self, ty: T) -> GCPtr;

/// Returns the type of the specified `obj`.
///
/// # Safety
///
/// This method is unsafe because the passed GCHandle could point to random memory.
unsafe fn object_type(&self, obj: GCHandle) -> T;
/// This method is unsafe because the passed GCPtr could point to random memory.
unsafe fn ptr_type(&self, obj: GCPtr) -> T;

/// Tell the runtime that the specified object should be considered a root which keeps all other
/// objects it references alive. Objects marked as root, must also be unrooted before they can
/// be collected. Internally this increments a root refcount.
///
/// # Safety
///
/// This method is unsafe because the passed GCHandle could point to random memory.
unsafe fn root(&self, obj: GCHandle);
/// This method is unsafe because the passed GCPtr could point to random memory.
unsafe fn root(&self, obj: GCPtr);

/// Tell the runtime that the specified object should unrooted which keeps all other
/// objects it references alive. Objects marked as root, must also be unrooted before they can
Expand All @@ -46,29 +54,36 @@ pub trait GCRuntime<T: Type>: Send + Sync {
///
/// # Safety
///
/// This method is unsafe because the passed GCHandle could point to random memory.
unsafe fn unroot(&self, obj: GCHandle);
/// This method is unsafe because the passed GCPtr could point to random memory.
unsafe fn unroot(&self, obj: GCPtr);

/// Returns stats about the current state of the runtime.
fn stats(&self) -> Stats;
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Event {
/// The GC performed an allocation
Allocation(GCHandle),
Allocation(GCPtr),

/// A GC cycle started
Start,

/// A deallocation took place
Deallocation(GCHandle),
Deallocation(GCPtr),

/// A GC cycle ended
End,
}

pub trait GCObserver: Send + Sync {
/// A `Observer` is trait that can receive `Event`s from a GC implementation. A `GCRuntime` can
/// be typed by a `GCObserver` which enables optional tracing of events.
pub trait Observer: Send + Sync {
fn event(&self, _event: Event) {}
}

/// A default implementation of a `Observer` which ensures that the compiler does not generate
/// code for event handling.
#[derive(Clone, Default)]
pub struct NoopObserver;
impl GCObserver for NoopObserver {}
impl Observer for NoopObserver {}
Loading

0 comments on commit 446f422

Please sign in to comment.