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,
|
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
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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>);
|
||||||
|
|
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