feat: finalizers implemented by VMKit
This commit is contained in:
parent
cdab71fda1
commit
8a7828299a
4 changed files with 136 additions and 38 deletions
|
@ -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::<BDWGC>(_worker, _tracer_context)
|
||||
}
|
||||
|
||||
fn forward_weak_refs(
|
||||
|
@ -510,7 +511,10 @@ static BUILDER: LazyLock<Mutex<MMTKBuilder>> = 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
|
||||
|
|
|
@ -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<VM: VirtualMachine>(PhantomData<VM>);
|
||||
|
@ -488,40 +488,6 @@ impl<VM: VirtualMachine> MemoryManager<VM> {
|
|||
.load(atomic::Ordering::SeqCst)
|
||||
== 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)]
|
||||
|
|
|
@ -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<VM: VirtualMachine>(PhantomData<VM>);
|
||||
|
|
127
vmkit/src/object_model/finalization.rs
Normal file
127
vmkit/src/object_model/finalization.rs
Normal 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()
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue