diff --git a/crates/mun_memory/src/gc.rs b/crates/mun_memory/src/gc.rs index 526447361..90639d9ba 100644 --- a/crates/mun_memory/src/gc.rs +++ b/crates/mun_memory/src/gc.rs @@ -2,7 +2,7 @@ mod mark_sweep; mod ptr; mod root_ptr; -use crate::TypeLayout; +use crate::TypeMemory; use std::marker::PhantomData; pub use mark_sweep::MarkSweep; @@ -24,7 +24,7 @@ pub trait TypeTrace: Send + Sync { } /// An object that can be used to allocate and collect memory. -pub trait GcRuntime: Send + Sync { +pub trait GcRuntime: Send + Sync { /// Allocates an object of the given type returning a GcPtr fn alloc(&self, ty: T) -> GcPtr; diff --git a/crates/mun_memory/src/gc/mark_sweep.rs b/crates/mun_memory/src/gc/mark_sweep.rs index 28f47f00e..7e0d99f48 100644 --- a/crates/mun_memory/src/gc/mark_sweep.rs +++ b/crates/mun_memory/src/gc/mark_sweep.rs @@ -2,7 +2,7 @@ use crate::{ cast, gc::{Event, GcPtr, GcRuntime, Observer, RawGcPtr, Stats, TypeTrace}, mapping::{self, FieldMapping, MemoryMapper}, - TypeDesc, TypeLayout, + TypeDesc, TypeMemory, }; use mapping::{Conversion, Mapping}; use parking_lot::RwLock; @@ -18,7 +18,7 @@ use std::{ #[derive(Debug)] pub struct MarkSweep where - T: TypeLayout + TypeTrace + Clone, + T: TypeMemory + TypeTrace + Clone, O: Observer, { objects: RwLock>>>>, @@ -28,7 +28,7 @@ where impl Default for MarkSweep where - T: TypeLayout + TypeTrace + Clone, + T: TypeMemory + TypeTrace + Clone, O: Observer + Default, { fn default() -> Self { @@ -42,7 +42,7 @@ where impl MarkSweep where - T: TypeLayout + TypeTrace + Clone, + T: TypeMemory + TypeTrace + Clone, O: Observer, { /// Creates a `MarkSweep` memory collector with the specified `Observer`. @@ -70,7 +70,7 @@ where } } -fn alloc_obj(ty: T) -> Pin>> { +fn alloc_obj(ty: T) -> Pin>> { let ptr = unsafe { std::alloc::alloc(ty.layout()) }; Box::pin(ObjectInfo { ptr, @@ -82,7 +82,7 @@ fn alloc_obj(ty: T) -> Pin> impl GcRuntime for MarkSweep where - T: TypeLayout + TypeTrace + Clone, + T: TypeMemory + TypeTrace + Clone, O: Observer, { fn alloc(&self, ty: T) -> GcPtr { @@ -135,7 +135,7 @@ where impl MarkSweep where - T: TypeLayout + TypeTrace + Clone, + T: TypeMemory + TypeTrace + Clone, O: Observer, { /// Collects all memory that is no longer referenced by rooted objects. Returns `true` if memory @@ -207,7 +207,7 @@ where impl MemoryMapper for MarkSweep where - T: TypeDesc + TypeLayout + TypeTrace + Clone + Eq + Hash, + T: TypeDesc + TypeMemory + TypeTrace + Clone + Eq + Hash, O: Observer, { fn map_memory(&self, mapping: Mapping) -> Vec { @@ -292,7 +292,7 @@ where src: NonNull, dest: NonNull, ) where - T: TypeDesc + TypeLayout + TypeTrace + Clone + Eq + Hash, + T: TypeDesc + TypeMemory + TypeTrace + Clone + Eq + Hash, O: Observer, { for FieldMapping { @@ -315,10 +315,8 @@ where src as *mut u8 }; - if let Some(old_memory_kind) = old_ty.memory_kind() { - let new_memory_kind = new_ty.memory_kind().expect( - "We are dealing with a struct and we do not directly compare fundamental types and struct type, so its counterpart must also be a struct.", - ); + if old_ty.group().is_struct() { + debug_assert!(new_ty.group().is_struct()); // When the name is the same, we are dealing with the same struct, // but different internals @@ -327,8 +325,8 @@ where // If the same struct changed, there must also be a conversion let conversion = conversions.get(old_ty); - if old_memory_kind == abi::StructMemoryKind::Value { - if new_memory_kind == abi::StructMemoryKind::Value { + if old_ty.is_stack_allocated() { + if new_ty.is_stack_allocated() { // struct(value) -> struct(value) if is_same_struct { // Map in-memory struct to in-memory struct @@ -378,7 +376,7 @@ where new_allocations.push(object); } - } else if new_memory_kind == abi::StructMemoryKind::GC { + } else if !new_ty.is_stack_allocated() { // struct(gc) -> struct(gc) let field_src = field_src.cast::(); let field_dest = field_dest.cast::(); @@ -472,7 +470,7 @@ where }; } mapping::Action::Insert => { - if let Some(abi::StructMemoryKind::GC) = new_ty.memory_kind() { + if !new_ty.is_stack_allocated() { let object = alloc_obj(new_ty.clone()); // We want to return a pointer to the `ObjectInfo`, to be used as @@ -516,7 +514,7 @@ enum Color { /// meta information. #[derive(Debug)] #[repr(C)] -struct ObjectInfo { +struct ObjectInfo { pub ptr: *mut u8, pub roots: u32, pub color: Color, @@ -524,28 +522,28 @@ struct ObjectInfo { } /// An `ObjectInfo` is thread-safe. -unsafe impl Send for ObjectInfo {} -unsafe impl Sync for ObjectInfo {} +unsafe impl Send for ObjectInfo {} +unsafe impl Sync for ObjectInfo {} -impl Into<*const ObjectInfo> for GcPtr { +impl Into<*const ObjectInfo> for GcPtr { fn into(self) -> *const ObjectInfo { self.as_ptr() as *const ObjectInfo } } -impl Into<*mut ObjectInfo> for GcPtr { +impl Into<*mut ObjectInfo> for GcPtr { fn into(self) -> *mut ObjectInfo { self.as_ptr() as *mut ObjectInfo } } -impl Into for *const ObjectInfo { +impl Into for *const ObjectInfo { fn into(self) -> GcPtr { (self as RawGcPtr).into() } } -impl Into for *mut ObjectInfo { +impl Into for *mut ObjectInfo { fn into(self) -> GcPtr { (self as RawGcPtr).into() } diff --git a/crates/mun_memory/src/gc/root_ptr.rs b/crates/mun_memory/src/gc/root_ptr.rs index af6f16d15..4b47f306f 100644 --- a/crates/mun_memory/src/gc/root_ptr.rs +++ b/crates/mun_memory/src/gc/root_ptr.rs @@ -1,18 +1,18 @@ use crate::{ gc::{GcPtr, GcRuntime, HasIndirectionPtr, TypeTrace}, - TypeLayout, + TypeMemory, }; use std::marker::PhantomData; use std::sync::{Arc, Weak}; /// A `GcPtr` that automatically roots and unroots its internal `GcPtr`. -pub struct GcRootPtr> { +pub struct GcRootPtr> { handle: GcPtr, runtime: Weak, ty: PhantomData, } -impl> Clone for GcRootPtr { +impl> Clone for GcRootPtr { fn clone(&self) -> Self { if let Some(runtime) = self.runtime.upgrade() { runtime.root(self.handle) @@ -25,7 +25,7 @@ impl> Clone for GcRootPtr { } } -impl> GcRootPtr { +impl> GcRootPtr { /// Constructs a new GCRootHandle from a runtime and a handle pub fn new(runtime: &Arc, handle: GcPtr) -> Self { runtime.root(handle); @@ -47,13 +47,13 @@ impl> GcRootPtr { } } -impl> Into for GcRootPtr { +impl> Into for GcRootPtr { fn into(self) -> GcPtr { self.handle } } -impl> Drop for GcRootPtr { +impl> Drop for GcRootPtr { fn drop(&mut self) { if let Some(runtime) = self.runtime.upgrade() { runtime.unroot(self.handle) @@ -61,7 +61,7 @@ impl> Drop for GcRootPtr { } } -impl> HasIndirectionPtr for GcRootPtr { +impl> HasIndirectionPtr for GcRootPtr { unsafe fn deref(&self) -> *const R { self.handle.deref() } diff --git a/crates/mun_memory/src/lib.rs b/crates/mun_memory/src/lib.rs index 8f32b34ad..0f4b3dcf8 100644 --- a/crates/mun_memory/src/lib.rs +++ b/crates/mun_memory/src/lib.rs @@ -20,12 +20,12 @@ pub trait TypeDesc: Send + Sync { fn group(&self) -> abi::TypeGroup; } -/// A trait used to obtain a type's memory layout. -pub trait TypeLayout: Send + Sync { +/// A trait used to obtain a type's memory description. +pub trait TypeMemory: Send + Sync { /// Returns the memory layout of this type. fn layout(&self) -> Layout; - /// Returns the memory kind of this type, if it is a struct. - fn memory_kind(&self) -> Option; + /// Returns whether the memory is stack-allocated. + fn is_stack_allocated(&self) -> bool; } /// A trait used to obtain a type's fields. diff --git a/crates/mun_memory/src/mapping.rs b/crates/mun_memory/src/mapping.rs index d4d06de55..ef96645dd 100644 --- a/crates/mun_memory/src/mapping.rs +++ b/crates/mun_memory/src/mapping.rs @@ -1,27 +1,27 @@ use crate::{ diff::{diff, Diff, FieldDiff, FieldEditKind}, gc::GcPtr, - TypeDesc, TypeFields, TypeLayout, + TypeDesc, TypeFields, TypeMemory, }; use std::{ collections::{HashMap, HashSet}, hash::Hash, }; -pub struct Mapping { +pub struct Mapping { pub deletions: HashSet, pub conversions: HashMap>, pub identical: Vec<(T, T)>, } -pub struct Conversion { +pub struct Conversion { pub field_mapping: Vec>, pub new_ty: T, } /// Description of the mapping of a single field. When stored together with the new index, this /// provides all information necessary for a mapping function. -pub struct FieldMapping { +pub struct FieldMapping { pub new_ty: T, pub new_offset: usize, pub action: Action, @@ -29,7 +29,7 @@ pub struct FieldMapping { /// The `Action` to take when mapping memory from A to B. #[derive(Eq, PartialEq)] -pub enum Action { +pub enum Action { Cast { old_offset: usize, old_ty: T }, Copy { old_offset: usize }, Insert, @@ -37,7 +37,7 @@ pub enum Action { impl Mapping where - T: TypeDesc + TypeFields + TypeLayout + Copy + Eq + Hash, + T: TypeDesc + TypeFields + TypeMemory + Copy + Eq + Hash, { /// pub fn new(old: &[T], new: &[T]) -> Self { @@ -83,7 +83,7 @@ where let mut new_candidates: HashSet = new .iter() // Filter non-struct types - .filter(|ty| ty.memory_kind().is_some()) + .filter(|ty| ty.group().is_struct()) // Filter inserted structs .filter(|ty| !insertions.contains(*ty)) .cloned() @@ -92,7 +92,7 @@ where let mut old_candidates: HashSet = old .iter() // Filter non-struct types - .filter(|ty| ty.memory_kind().is_some()) + .filter(|ty| ty.group().is_struct()) // Filter deleted structs .filter(|ty| !deletions.contains(*ty)) // Filter edited types @@ -139,7 +139,7 @@ where /// # Safety /// /// Expects the `diff` to be based on `old_ty` and `new_ty`. If not, it causes undefined behavior. -pub unsafe fn field_mapping + TypeLayout>( +pub unsafe fn field_mapping + TypeMemory>( old_ty: T, new_ty: T, diff: &[FieldDiff], @@ -265,7 +265,7 @@ pub unsafe fn field_mapping + TypeLayout>( } /// A trait used to map allocated memory using type differences. -pub trait MemoryMapper { +pub trait MemoryMapper { /// Maps its allocated memory using the provided `mapping`. /// /// A `Vec` is returned containing all objects of types that were deleted. The diff --git a/crates/mun_memory/tests/diff/util.rs b/crates/mun_memory/tests/diff/util.rs index 06743107c..5cc2f080e 100644 --- a/crates/mun_memory/tests/diff/util.rs +++ b/crates/mun_memory/tests/diff/util.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use mun_memory::{ diff::{myers, Diff, FieldDiff, FieldEditKind}, - TypeDesc, TypeFields, TypeLayout, + TypeDesc, TypeFields, TypeMemory, }; use std::alloc::Layout; @@ -106,14 +106,14 @@ impl TypeDesc for &TypeInfo { } } -impl TypeLayout for &TypeInfo { +impl TypeMemory for &TypeInfo { fn layout(&self) -> Layout { self.layout } - fn memory_kind(&self) -> Option { + fn is_stack_allocated(&self) -> bool { // NOTE: This contrived test does not support structs - None + true } } diff --git a/crates/mun_memory/tests/gc/util.rs b/crates/mun_memory/tests/gc/util.rs index 065ae7d82..769518ca3 100644 --- a/crates/mun_memory/tests/gc/util.rs +++ b/crates/mun_memory/tests/gc/util.rs @@ -72,15 +72,15 @@ macro_rules! impl_struct_ty { impl_primitive_types!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, bool); -impl mun_memory::TypeLayout for &'static TypeInfo { +impl mun_memory::TypeMemory for &'static TypeInfo { fn layout(&self) -> Layout { Layout::from_size_align(self.size as usize, self.alignment as usize) .expect("invalid layout specified by TypeInfo") } - fn memory_kind(&self) -> Option { + fn is_stack_allocated(&self) -> bool { // NOTE: This contrived test does not support structs - None + true } } diff --git a/crates/mun_runtime/src/garbage_collector.rs b/crates/mun_runtime/src/garbage_collector.rs index 42f8af634..53986a45d 100644 --- a/crates/mun_runtime/src/garbage_collector.rs +++ b/crates/mun_runtime/src/garbage_collector.rs @@ -113,15 +113,20 @@ impl Iterator for Trace { } } -impl memory::TypeLayout for UnsafeTypeInfo { +impl memory::TypeMemory for UnsafeTypeInfo { fn layout(&self) -> Layout { let ty = unsafe { self.0.as_ref() }; Layout::from_size_align(ty.size_in_bytes(), ty.alignment()) .unwrap_or_else(|_| panic!("invalid layout from Mun Type: {:?}", ty)) } - fn memory_kind(&self) -> Option { - unsafe { self.0.as_ref().as_struct().map(|s| s.memory_kind.clone()) } + fn is_stack_allocated(&self) -> bool { + unsafe { + self.0 + .as_ref() + .as_struct() + .map_or(true, |s| s.memory_kind == abi::StructMemoryKind::Value) + } } }