diff --git a/vmkit/src/bdwgc_shim.rs b/vmkit/src/bdwgc_shim.rs index 76e087a..ee46759 100644 --- a/vmkit/src/bdwgc_shim.rs +++ b/vmkit/src/bdwgc_shim.rs @@ -24,6 +24,7 @@ use crate::{ MemoryManager, }, object_model::{ + finalization::FinalizerProcessing, metadata::{GCMetadata, Metadata, TraceCallback}, object::VMKitObject, }, @@ -186,7 +187,7 @@ impl VirtualMachine for BDWGC { } }); - false + FinalizerProcessing::process::(_worker, _tracer_context) } fn forward_weak_refs( @@ -510,7 +511,10 @@ static BUILDER: LazyLock> = LazyLock::new(|| { Mutex::new({ let mut builder = MMTKBuilder::new(); builder.options.read_env_var_settings(); - if !matches!(*builder.options.plan, PlanSelector::Immix | PlanSelector::MarkSweep) { + if !matches!( + *builder.options.plan, + PlanSelector::Immix | PlanSelector::MarkSweep + ) { builder.options.plan.set(PlanSelector::Immix); } builder diff --git a/vmkit/src/mm.rs b/vmkit/src/mm.rs index 40365f1..ba667bc 100644 --- a/vmkit/src/mm.rs +++ b/vmkit/src/mm.rs @@ -21,8 +21,8 @@ use mmtk::{ }, AllocationSemantics, BarrierSelector, MutatorContext, }; -use ref_glue::Finalizer; -use std::{marker::PhantomData, panic::AssertUnwindSafe}; + +use std::marker::PhantomData; #[derive(Clone, Copy)] pub struct MemoryManager(PhantomData); @@ -488,40 +488,6 @@ impl MemoryManager { .load(atomic::Ordering::SeqCst) == 0 } - - pub fn register_finalizer(object: VMKitObject, callback: Box) { - let finalizer = Finalizer { - object, - callback: Some(callback), - }; - let vm = VM::get(); - mmtk::memory_manager::add_finalizer(&vm.vmkit().mmtk, finalizer); - } - - pub fn run_finalizers() -> usize { - let vm = VM::get(); - let mut count = 0; - while let Some(mut finalizer) = mmtk::memory_manager::get_finalized_object(&vm.vmkit().mmtk) { - let _ = std::panic::catch_unwind(AssertUnwindSafe(|| finalizer.run())); - count += 1; - } - count - } - - pub fn get_finalizers_for(object: VMKitObject) -> Vec { - if object.is_null() { - return vec![]; - } - let vm = VM::get(); - mmtk::memory_manager::get_finalizers_for(&vm.vmkit().mmtk, unsafe { - object.as_object_unchecked() - }) - } - - pub fn get_finalized_object() -> Option { - let vm = VM::get(); - mmtk::memory_manager::get_finalized_object(&vm.vmkit().mmtk) - } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/vmkit/src/object_model.rs b/vmkit/src/object_model.rs index c1c6b82..493bbda 100644 --- a/vmkit/src/object_model.rs +++ b/vmkit/src/object_model.rs @@ -12,6 +12,7 @@ use object::{MoveTarget, VMKitObject}; pub mod header; pub mod metadata; pub mod object; +pub mod finalization; pub mod compression; pub struct VMKitObjectModel(PhantomData); diff --git a/vmkit/src/object_model/finalization.rs b/vmkit/src/object_model/finalization.rs new file mode 100644 index 0000000..30c0f9b --- /dev/null +++ b/vmkit/src/object_model/finalization.rs @@ -0,0 +1,127 @@ +//! Simple finalization mechanism implementation. +//! +//! Implements finalizers which are unordered and can revive objects, also +//! allows registering objects for destruction without finalization. +//! + +use std::{cell::RefCell, panic::AssertUnwindSafe}; + +use mmtk::{ + scheduler::GCWorker, + util::ObjectReference, + vm::{ObjectTracer, ObjectTracerContext}, +}; + +use crate::{mm::MemoryManager, sync::Monitor, VirtualMachine}; + +use super::object::VMKitObject; + +pub struct Finalizer { + pub object: VMKitObject, + pub finalizer: FinalizerKind, +} + +pub enum FinalizerKind { + Finalized, + /// Unordered finalizer: finalizer revives the object and + /// then executes the provided closure as a finalizer. Closure + /// can keep object alive if it's required (but that's not recommended). + Unordered(Box), + /// Drop finalizer: does not revive the object nor + /// provides access to it. This can be used to close open FDs + /// or free off heap data. + Drop(Box), +} + +impl FinalizerKind { + pub fn take(&mut self) -> Self { + std::mem::replace(self, FinalizerKind::Finalized) + } + + pub fn is_finalized(&self) -> bool { + matches!(self, FinalizerKind::Finalized) + } +} + +pub struct FinalizerProcessing; + +pub static REGISTERED_FINALIZERS: Monitor>> = + Monitor::new(RefCell::new(Vec::new())); +pub static PENDING_FINALIZERS: Monitor>> = + Monitor::new(RefCell::new(Vec::new())); + +impl FinalizerProcessing { + pub fn process( + tls: &mut GCWorker>, + tracer_context: impl ObjectTracerContext>, + ) -> bool { + let vm = VM::get(); + assert!( + vm.vmkit().mmtk.gc_in_progress(), + "Attempt to process finalizers outside of GC" + ); + + let registered = REGISTERED_FINALIZERS.lock_no_handshake(); + let pending = PENDING_FINALIZERS.lock_no_handshake(); + + let mut registered = registered.borrow_mut(); + let mut pending = pending.borrow_mut(); + let mut closure_required = false; + tracer_context.with_tracer(tls, |tracer| { + registered.retain_mut(|finalizer| { + let Ok(object) = finalizer.object.try_into() else { + return false; + }; + let object: ObjectReference = object; + + if object.is_reachable() { + let new_object = object.get_forwarded_object().unwrap_or(object); + finalizer.object = VMKitObject::from(new_object); + true + } else { + let new_object = tracer.trace_object(object); + pending.push(Finalizer { + finalizer: std::mem::replace( + &mut finalizer.finalizer, + FinalizerKind::Finalized, + ), + object: VMKitObject::from(new_object), + }); + closure_required = true; + + false + } + }); + }); + closure_required + } +} + +impl MemoryManager { + pub fn register_finalizer(object: VMKitObject, callback: Box) { + let finalizer = Finalizer { + object, + finalizer: FinalizerKind::Unordered(callback), + }; + + REGISTERED_FINALIZERS + .lock_no_handshake() + .borrow_mut() + .push(finalizer); + } + + pub fn run_finalizers() -> usize { + let vm = VM::get(); + let mut count = 0; + while let Some(mut finalizer) = mmtk::memory_manager::get_finalized_object(&vm.vmkit().mmtk) + { + let _ = std::panic::catch_unwind(AssertUnwindSafe(|| finalizer.run())); + count += 1; + } + count + } + + pub fn get_finalized_object() -> Option { + PENDING_FINALIZERS.lock_no_handshake().borrow_mut().pop() + } +}