feat: finalizers implemented by VMKit

This commit is contained in:
playX18 2025-02-14 14:22:29 +07:00
parent cdab71fda1
commit 8a7828299a
4 changed files with 136 additions and 38 deletions

View file

@ -24,6 +24,7 @@ use crate::{
MemoryManager, MemoryManager,
}, },
object_model::{ object_model::{
finalization::FinalizerProcessing,
metadata::{GCMetadata, Metadata, TraceCallback}, metadata::{GCMetadata, Metadata, TraceCallback},
object::VMKitObject, object::VMKitObject,
}, },
@ -186,7 +187,7 @@ impl VirtualMachine for BDWGC {
} }
}); });
false FinalizerProcessing::process::<BDWGC>(_worker, _tracer_context)
} }
fn forward_weak_refs( fn forward_weak_refs(
@ -510,7 +511,10 @@ static BUILDER: LazyLock<Mutex<MMTKBuilder>> = LazyLock::new(|| {
Mutex::new({ Mutex::new({
let mut builder = MMTKBuilder::new(); let mut builder = MMTKBuilder::new();
builder.options.read_env_var_settings(); 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.options.plan.set(PlanSelector::Immix);
} }
builder builder

View file

@ -21,8 +21,8 @@ use mmtk::{
}, },
AllocationSemantics, BarrierSelector, MutatorContext, AllocationSemantics, BarrierSelector, MutatorContext,
}; };
use ref_glue::Finalizer;
use std::{marker::PhantomData, panic::AssertUnwindSafe}; use std::marker::PhantomData;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct MemoryManager<VM: VirtualMachine>(PhantomData<VM>); pub struct MemoryManager<VM: VirtualMachine>(PhantomData<VM>);
@ -488,40 +488,6 @@ impl<VM: VirtualMachine> MemoryManager<VM> {
.load(atomic::Ordering::SeqCst) .load(atomic::Ordering::SeqCst)
== 0 == 0
} }
pub fn register_finalizer(object: VMKitObject, callback: Box<dyn FnOnce(VMKitObject) + Send>) {
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<Finalizer> {
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<Finalizer> {
let vm = VM::get();
mmtk::memory_manager::get_finalized_object(&vm.vmkit().mmtk)
}
} }
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

View file

@ -12,6 +12,7 @@ use object::{MoveTarget, VMKitObject};
pub mod header; pub mod header;
pub mod metadata; pub mod metadata;
pub mod object; pub mod object;
pub mod finalization;
pub mod compression; pub mod compression;
pub struct VMKitObjectModel<VM: VirtualMachine>(PhantomData<VM>); pub struct VMKitObjectModel<VM: VirtualMachine>(PhantomData<VM>);

View file

@ -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<dyn FnOnce(VMKitObject) + Send>),
/// 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<dyn FnOnce() + Send>),
}
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<RefCell<Vec<Finalizer>>> =
Monitor::new(RefCell::new(Vec::new()));
pub static PENDING_FINALIZERS: Monitor<RefCell<Vec<Finalizer>>> =
Monitor::new(RefCell::new(Vec::new()));
impl FinalizerProcessing {
pub fn process<VM: VirtualMachine>(
tls: &mut GCWorker<MemoryManager<VM>>,
tracer_context: impl ObjectTracerContext<MemoryManager<VM>>,
) -> 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<VM: VirtualMachine> MemoryManager<VM> {
pub fn register_finalizer(object: VMKitObject, callback: Box<dyn FnOnce(VMKitObject) + Send>) {
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<Finalizer> {
PENDING_FINALIZERS.lock_no_handshake().borrow_mut().pop()
}
}