From ea9c1887c719f3e90d5d22ec6f737f2cd2c16793 Mon Sep 17 00:00:00 2001 From: playX18 Date: Thu, 13 Feb 2025 22:32:44 +0700 Subject: [PATCH] finalization --- vmkit/Cargo.toml | 2 +- vmkit/examples/binarytrees.rs | 2 + vmkit/src/bdwgc_shim.rs | 106 ++++++++++++++++++++------- vmkit/src/lib.rs | 39 +++++++++- vmkit/src/mm.rs | 37 +++++++++- vmkit/src/mm/conservative_roots.rs | 1 + vmkit/src/mm/ref_glue.rs | 62 +++++++++++----- vmkit/src/mm/traits.rs | 9 +++ vmkit/src/object_model/object.rs | 113 ++++++++++++++++++++++++++++- vmkit/src/threading.rs | 1 + 10 files changed, 321 insertions(+), 51 deletions(-) diff --git a/vmkit/Cargo.toml b/vmkit/Cargo.toml index 4437103..e68cbc7 100644 --- a/vmkit/Cargo.toml +++ b/vmkit/Cargo.toml @@ -26,7 +26,7 @@ sysinfo = "0.33.1" default = ["uncooperative"] -uncooperative = ["cooperative", "mmtk/immix_non_moving"] +uncooperative = ["cooperative", "mmtk/immix_non_moving", "mmtk/immix_zero_on_release"] # VMKit is built for use in cooperative runtime. Such runtime # would be able to use write barriers and safepoints. Such environment diff --git a/vmkit/examples/binarytrees.rs b/vmkit/examples/binarytrees.rs index 8045384..2572b7a 100644 --- a/vmkit/examples/binarytrees.rs +++ b/vmkit/examples/binarytrees.rs @@ -1,4 +1,5 @@ use mmtk::util::Address; +use mmtk::vm::slot::UnimplementedMemorySlice; use mmtk::{util::options::PlanSelector, vm::slot::SimpleSlot, AllocationSemantics, MMTKBuilder}; use std::cell::RefCell; use std::mem::offset_of; @@ -65,6 +66,7 @@ impl VirtualMachine for BenchVM { type Metadata = &'static GCMetadata; type Slot = SimpleSlot; type ThreadContext = ThreadBenchContext; + type MemorySlice = UnimplementedMemorySlice; fn get() -> &'static Self { VM.get().unwrap() } diff --git a/vmkit/src/bdwgc_shim.rs b/vmkit/src/bdwgc_shim.rs index 712f670..8697479 100644 --- a/vmkit/src/bdwgc_shim.rs +++ b/vmkit/src/bdwgc_shim.rs @@ -34,7 +34,10 @@ use crate::{ use easy_bitfield::*; use mmtk::{ util::Address, - vm::{slot::SimpleSlot, ObjectTracer}, + vm::{ + slot::{SimpleSlot, UnimplementedMemorySlice}, + ObjectTracer, + }, AllocationSemantics, MMTKBuilder, }; use parking_lot::{Mutex, Once}; @@ -150,6 +153,7 @@ impl VirtualMachine for BDWGC { type BlockAdapterList = (GCBlockAdapter, ()); type Metadata = BDWGCMetadata; type Slot = SimpleSlot; + type MemorySlice = UnimplementedMemorySlice; fn get() -> &'static Self { BDWGC_VM.get().expect("GC is not initialized") @@ -501,7 +505,16 @@ static INIT: Once = Once::new(); #[no_mangle] pub static mut GC_VERBOSE: i32 = 0; -static BUILDER: LazyLock> = LazyLock::new(|| Mutex::new(MMTKBuilder::new())); +static BUILDER: LazyLock> = LazyLock::new(|| { + Mutex::new({ + let mut builder = MMTKBuilder::new(); + builder + .options + .plan + .set(mmtk::util::options::PlanSelector::Immix); + builder + }) +}); #[no_mangle] pub extern "C-unwind" fn GC_get_parallel() -> libc::c_int { @@ -1135,61 +1148,97 @@ pub extern "C-unwind" fn GC_general_register_disappearing_link( #[no_mangle] pub extern "C-unwind" fn GC_register_finalizer( obj: *mut libc::c_void, - finalizer: extern "C" fn(*mut libc::c_void), + finalizer: extern "C-unwind" fn(*mut libc::c_void, *mut libc::c_void), cd: *mut libc::c_void, ofn: *mut extern "C" fn(*mut libc::c_void), ocd: *mut *mut libc::c_void, ) { - let _ = obj; // TBD - let _ = finalizer; // TBD - let _ = cd; // TBD - let _ = ofn; // TBD - let _ = ocd; // TBD + let object = GC_base(obj); + if object.is_null() { + return; + } + let _ = ofn; + let _ = ocd; + let cd = Address::from_mut_ptr(cd); + let object = VMKitObject::from_address(Address::from_mut_ptr(object)); + MemoryManager::::register_finalizer( + object, + Box::new(move |object| { + finalizer(object.as_address().to_mut_ptr(), cd.to_mut_ptr()); + }), + ); } #[no_mangle] pub extern "C-unwind" fn GC_register_finalizer_ignore_self( obj: *mut libc::c_void, - finalizer: extern "C" fn(*mut libc::c_void), + finalizer: extern "C" fn(*mut libc::c_void, *mut libc::c_void), cd: *mut libc::c_void, ofn: *mut extern "C" fn(*mut libc::c_void), ocd: *mut *mut libc::c_void, ) { - let _ = obj; // TBD - let _ = finalizer; // TBD - let _ = cd; // TBD - let _ = ofn; // TBD - let _ = ocd; // TBD + let object = GC_base(obj); + if object.is_null() { + return; + } + let _ = ofn; + let _ = ocd; + let cd = Address::from_mut_ptr(cd); + let object = VMKitObject::from_address(Address::from_mut_ptr(object)); + MemoryManager::::register_finalizer( + object, + Box::new(move |object| { + finalizer(object.as_address().to_mut_ptr(), cd.to_mut_ptr()); + }), + ); } #[no_mangle] pub extern "C-unwind" fn GC_register_finalizer_no_order( obj: *mut libc::c_void, - finalizer: extern "C" fn(*mut libc::c_void), + finalizer: extern "C" fn(*mut libc::c_void, *mut libc::c_void), cd: *mut libc::c_void, ofn: *mut extern "C" fn(*mut libc::c_void), ocd: *mut *mut libc::c_void, ) { - let _ = obj; // TBD - let _ = finalizer; // TBD - let _ = cd; // TBD - let _ = ofn; // TBD - let _ = ocd; // TBD + let object = GC_base(obj); + if object.is_null() { + return; + } + let _ = ofn; + let _ = ocd; + let cd = Address::from_mut_ptr(cd); + let object = VMKitObject::from_address(Address::from_mut_ptr(object)); + MemoryManager::::register_finalizer( + object, + Box::new(move |object| { + finalizer(object.as_address().to_mut_ptr(), cd.to_mut_ptr()); + }), + ); } #[no_mangle] pub extern "C-unwind" fn GC_register_finalizer_unreachable( obj: *mut libc::c_void, - finalizer: extern "C" fn(*mut libc::c_void), + finalizer: extern "C" fn(*mut libc::c_void, *mut libc::c_void), cd: *mut libc::c_void, ofn: *mut extern "C" fn(*mut libc::c_void), ocd: *mut *mut libc::c_void, ) { - let _ = obj; // TBD - let _ = finalizer; // TBD - let _ = cd; // TBD - let _ = ofn; // TBD - let _ = ocd; // TBD + let object = GC_base(obj); + if object.is_null() { + return; + } + let _ = ofn; + let _ = ocd; + let cd = Address::from_mut_ptr(cd); + let object = VMKitObject::from_address(Address::from_mut_ptr(object)); + MemoryManager::::register_finalizer( + object, + Box::new(move |object| { + finalizer(object.as_address().to_mut_ptr(), cd.to_mut_ptr()); + }), + ); } #[no_mangle] @@ -1441,3 +1490,8 @@ pub unsafe extern "C-unwind" fn GC_malloc_explicitly_typed_ignore_off_page( let _ = descr; GC_malloc_ignore_off_page(size) } + +#[no_mangle] +pub extern "C-unwind" fn GC_invoke_finalizers() -> usize { + MemoryManager::::run_finalizers() +} diff --git a/vmkit/src/lib.rs b/vmkit/src/lib.rs index f98d5c7..febe1f9 100644 --- a/vmkit/src/lib.rs +++ b/vmkit/src/lib.rs @@ -4,8 +4,9 @@ use std::{ }; use mm::{aslr::aslr_vm_layout, traits::SlotExtra, MemoryManager}; -use mmtk::{MMTKBuilder, MMTK}; -use threading::{initialize_threading, ThreadManager}; +use mmtk::{vm::slot::MemorySlice, MMTKBuilder, MMTK}; +use object_model::object::VMKitObject; +use threading::{initialize_threading, Thread, ThreadManager}; pub mod machine_context; pub mod mm; @@ -24,7 +25,7 @@ pub trait VirtualMachine: Sized + 'static + Send + Sync { type BlockAdapterList: threading::BlockAdapterList; type Metadata: object_model::metadata::Metadata; type Slot: SlotExtra; - + type MemorySlice: MemorySlice; const ALIGNMENT_VALUE: u32 = 0xdead_beef; const MAX_ALIGNMENT: usize = 32; const MIN_ALIGNMENT: usize = 8; @@ -113,6 +114,38 @@ pub trait VirtualMachine: Sized + 'static + Send + Sync { eprintln!("Out of memory: {:?}", err_kind); std::process::exit(1); } + + /// Weak and soft references always clear the referent before enqueueing. + fn clear_referent(new_reference: VMKitObject) { + let _ = new_reference; + unimplemented!() + } + + /// Get the referent from a weak reference object. + fn get_referent(object: VMKitObject) -> VMKitObject { + let _ = object; + unimplemented!() + } + + /// Set the referent in a weak reference object. + fn set_referent(reff: VMKitObject, referent: VMKitObject) { + let _ = reff; + let _ = referent; + unimplemented!() + } + + /// For weak reference types, if the referent is cleared during GC, the reference + /// will be added to a queue, and MMTk will call this method to inform + /// the VM about the changes for those references. This method is used + /// to implement Java's ReferenceQueue. + /// Note that this method is called for each type of weak references during GC, and + /// the references slice will be cleared after this call is returned. That means + /// MMTk will no longer keep these references alive once this method is returned. + fn enqueue_references(references: impl Iterator, tls: &Thread) { + let _ = references; + let _ = tls; + unimplemented!() + } } pub struct VMKit { diff --git a/vmkit/src/mm.rs b/vmkit/src/mm.rs index c5887b6..40365f1 100644 --- a/vmkit/src/mm.rs +++ b/vmkit/src/mm.rs @@ -21,7 +21,8 @@ use mmtk::{ }, AllocationSemantics, BarrierSelector, MutatorContext, }; -use std::marker::PhantomData; +use ref_glue::Finalizer; +use std::{marker::PhantomData, panic::AssertUnwindSafe}; #[derive(Clone, Copy)] pub struct MemoryManager(PhantomData); @@ -487,6 +488,40 @@ 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/mm/conservative_roots.rs b/vmkit/src/mm/conservative_roots.rs index 1bc810e..ea44d84 100644 --- a/vmkit/src/mm/conservative_roots.rs +++ b/vmkit/src/mm/conservative_roots.rs @@ -37,6 +37,7 @@ impl ConservativeRoots { return; }; + println!("found {}", start); self.roots.insert(start); } diff --git a/vmkit/src/mm/ref_glue.rs b/vmkit/src/mm/ref_glue.rs index b1f7bb6..553c738 100644 --- a/vmkit/src/mm/ref_glue.rs +++ b/vmkit/src/mm/ref_glue.rs @@ -4,46 +4,72 @@ use std::marker::PhantomData; use mmtk::vm::{Finalizable, ReferenceGlue}; -use crate::{object_model::object::VMKitObject, VirtualMachine}; +use crate::{object_model::object::VMKitObject, threading::Thread, VirtualMachine}; use super::MemoryManager; - pub struct VMKitReferenceGlue(PhantomData); - - impl ReferenceGlue> for VMKitReferenceGlue { - type FinalizableType = VMKitObject; - + type FinalizableType = Finalizer; + fn clear_referent(new_reference: mmtk::util::ObjectReference) { - + VM::clear_referent(new_reference.into()); } - fn enqueue_references(references: &[mmtk::util::ObjectReference], tls: mmtk::util::VMWorkerThread) { - + fn enqueue_references( + references: &[mmtk::util::ObjectReference], + tls: mmtk::util::VMWorkerThread, + ) { + VM::enqueue_references( + references.iter().copied().map(VMKitObject::from), + Thread::::from_vm_worker_thread(tls), + ); } fn get_referent(object: mmtk::util::ObjectReference) -> Option { - todo!() + VM::get_referent(object.into()).try_into().ok() } - + fn set_referent(reff: mmtk::util::ObjectReference, referent: mmtk::util::ObjectReference) { - todo!() + VM::set_referent(reff.into(), referent.into()); } - } -impl Finalizable for VMKitObject { +impl Finalizable for Finalizer { fn get_reference(&self) -> mmtk::util::ObjectReference { - todo!() + unsafe { self.object.as_object_unchecked() } } fn keep_alive(&mut self, trace: &mut E) { - + unsafe { + let mmtk_obj = self.object.as_object_unchecked(); + let new = trace.trace_object(mmtk_obj); + self.object = VMKitObject::from(new); + } } fn set_reference(&mut self, object: mmtk::util::ObjectReference) { - + self.object = VMKitObject::from(object); } -} \ No newline at end of file +} + +pub struct Finalizer { + pub object: VMKitObject, + pub callback: Option>, +} + +impl Finalizer { + pub fn run(&mut self) { + match self.callback.take() { + Some(callback) => callback(self.object), + None => {} + } + } +} + +impl std::fmt::Debug for Finalizer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#", self.object.as_address(),) + } +} diff --git a/vmkit/src/mm/traits.rs b/vmkit/src/mm/traits.rs index 215be5f..0220edb 100644 --- a/vmkit/src/mm/traits.rs +++ b/vmkit/src/mm/traits.rs @@ -100,6 +100,7 @@ pub trait SlotExtra: Slot { /// as internally we use `VMKitObject` to represent all objects. fn from_vmkit_object(object: &VMKitObject) -> Self; fn from_address(address: Address) -> Self; + fn as_address(&self) -> Address; /// Construct a slot from an `InternalPointer`. VMs are not required to implement /// this as InternalPointer can also be traced. @@ -135,6 +136,10 @@ impl SlotExtra for SimpleSlot { let _ = pointer; unimplemented!("SimpleSlot does not support internal pointers") } + + fn as_address(&self) -> Address { + SimpleSlot::as_address(self) + } } impl SlotExtra for Address { @@ -150,6 +155,10 @@ impl SlotExtra for Address { let _ = pointer; unimplemented!("Address does not support internal pointers") } + + fn as_address(&self) -> Address { + *self + } } /// Trait to check if type can be enqueued as a slot of an object. diff --git a/vmkit/src/object_model/object.rs b/vmkit/src/object_model/object.rs index 172a1a7..fdbc6ed 100644 --- a/vmkit/src/object_model/object.rs +++ b/vmkit/src/object_model/object.rs @@ -1,11 +1,15 @@ -use std::fmt; use crate::mm::traits::SlotExtra; use crate::threading::Thread; use crate::{mm::MemoryManager, VirtualMachine}; use atomic::Atomic; +use core::ops::Range; +use std::hash::Hash; use mmtk::util::{ constants::LOG_BYTES_IN_ADDRESS, conversions::raw_align_up, Address, ObjectReference, }; +use mmtk::vm::slot::{MemorySlice, SimpleSlot, Slot}; +use std::fmt; +use std::marker::PhantomData; use super::{ compression::CompressedOps, @@ -152,7 +156,7 @@ impl VMKitObject { align_of::(), ) + overhead }; - + res } @@ -606,3 +610,108 @@ impl VMKitNarrow { self.to_object().object_start::() } } + +pub struct SimpleMemorySlice { + range: Range, +} + +impl SimpleMemorySlice { + pub fn from(value: Range) -> Self { + Self { range: value } + } +} + +impl fmt::Debug for SimpleMemorySlice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SimpleMemorySlice({:?})", self.range) + } +} + +impl Hash for SimpleMemorySlice { + fn hash(&self, state: &mut H) { + self.range.start.as_address().hash(state); + self.range.end.as_address().hash(state); + } +} + +impl PartialEq for SimpleMemorySlice { + fn eq(&self, other: &Self) -> bool { + self.range == other.range + } +} + +impl Eq for SimpleMemorySlice {} + +impl Clone for SimpleMemorySlice { + fn clone(&self) -> Self { + Self { range: self.range.clone() } + } +} + + + +pub struct SimpleMemorySliceRangeIterator { + cursor: Address, + end: Address, + marker: PhantomData, +} + +impl Iterator for SimpleMemorySliceRangeIterator { + type Item = SL; + + fn next(&mut self) -> Option { + if self.cursor < self.end { + let res = self.cursor; + self.cursor = self.cursor + size_of::(); + Some(SL::from_address(res)) + } else { + None + } + } +} + +impl From> for SimpleMemorySliceRangeIterator { + fn from(value: SimpleMemorySlice) -> Self { + let start = value.range.start.as_address(); + let end = value.range.end.as_address(); + Self { + cursor: start, + end, + marker: PhantomData, + } + } +} + +impl MemorySlice for SimpleMemorySlice { + type SlotType = SL; + type SlotIterator = SimpleMemorySliceRangeIterator; + + fn iter_slots(&self) -> Self::SlotIterator { + SimpleMemorySliceRangeIterator { + cursor: self.range.start.as_address(), + end: self.range.end.as_address(), + marker: PhantomData, + } + } + + fn object(&self) -> Option { + None + } + + fn start(&self) -> Address { + self.range.start.as_address() + } + + fn bytes(&self) -> usize { + self.range.end.as_address() - self.range.start.as_address() + } + + fn copy(src: &Self, tgt: &Self) { + unsafe { + let bytes = tgt.bytes(); + let src = src.start().to_ptr::(); + let dst = tgt.start().to_mut_ptr::(); + std::ptr::copy(src, dst, bytes); + } + } +} diff --git a/vmkit/src/threading.rs b/vmkit/src/threading.rs index 7ed82bb..1008bdd 100644 --- a/vmkit/src/threading.rs +++ b/vmkit/src/threading.rs @@ -1864,6 +1864,7 @@ extern "C-unwind" fn signal_handler_suspend_resume( return; } + thread .stack_pointer .store(approximate_stack_pointer.as_usize(), Ordering::Release);