Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ pub fn handle_user_collection_request<VM: VMBinding>(
///
/// Arguments:
/// * `object`: The object reference to query.
pub fn is_live_object(object: ObjectReference) -> bool {
object.is_live()
pub fn is_live_object<VM: VMBinding>(mmtk: &MMTK<VM>, object: ObjectReference) -> bool {
mmtk.get_plan().is_live_object(object)
}

/// Check if `addr` is the raw address of an object reference to an MMTk object.
Expand Down
14 changes: 6 additions & 8 deletions src/mmtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use crate::util::sanity::sanity_checker::SanityChecker;
#[cfg(feature = "extreme_assertions")]
use crate::util::slot_logger::SlotLogger;
use crate::util::statistics::stats::Stats;
use crate::vm::ReferenceGlue;
use crate::vm::VMBinding;
use std::cell::UnsafeCell;
use std::collections::HashMap;
Expand Down Expand Up @@ -113,9 +112,8 @@ pub struct MMTK<VM: VMBinding> {
pub(crate) options: Arc<Options>,
pub(crate) state: Arc<GlobalState>,
pub(crate) plan: UnsafeCell<Box<dyn Plan<VM = VM>>>,
pub(crate) reference_processors: ReferenceProcessors,
pub(crate) finalizable_processor:
Mutex<FinalizableProcessor<<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType>>,
pub(crate) reference_processors: ReferenceProcessors<VM>,
pub(crate) finalizable_processor: Mutex<FinalizableProcessor<VM>>,
pub(crate) scheduler: Arc<GCWorkScheduler<VM>>,
#[cfg(feature = "sanity")]
pub(crate) sanity_checker: Mutex<SanityChecker<VM::VMSlot>>,
Expand Down Expand Up @@ -207,14 +205,14 @@ impl<VM: VMBinding> MMTK<VM> {
},
);

let static_plan: &'static dyn Plan<VM = VM> = unsafe { &*(&*plan as *const _) };

MMTK {
options,
state,
plan: UnsafeCell::new(plan),
reference_processors: ReferenceProcessors::new(),
finalizable_processor: Mutex::new(FinalizableProcessor::<
<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType,
>::new()),
reference_processors: ReferenceProcessors::new(static_plan),
finalizable_processor: Mutex::new(FinalizableProcessor::new(static_plan)),
scheduler,
#[cfg(feature = "sanity")]
sanity_checker: Mutex::new(SanityChecker::new()),
Expand Down
4 changes: 4 additions & 0 deletions src/plan/generational/copying/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
fn generational(&self) -> Option<&dyn GenerationalPlan<VM = Self::VM>> {
Some(self)
}

fn is_live_object(&self, object: ObjectReference) -> bool {
self.gen.is_live_object(object)
}
}

impl<VM: VMBinding> GenerationalPlan for GenCopy<VM> {
Expand Down
16 changes: 16 additions & 0 deletions src/plan/generational/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,22 @@ impl<VM: VMBinding> CommonGenPlan<VM> {
pub fn get_used_pages(&self) -> usize {
self.nursery.reserved_pages() + self.common.get_used_pages()
}

pub fn is_live_object(&self, object: ObjectReference) -> bool {
use crate::policy::sft::SFT;
if self.is_current_gc_nursery() {
if self.nursery.in_space(object) {
self.nursery.is_live(object)
} else if self.common.get_los().in_space(object) {
self.common.get_los().is_live(object)
} else {
true
}
} else {
let sft = unsafe { crate::mmtk::SFT_MAP.get_unchecked(object.to_raw_address()) };
sft.is_live(object)
}
}
}

/// This trait includes methods that are specific to generational plans. This trait needs
Expand Down
4 changes: 4 additions & 0 deletions src/plan/generational/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {
fn generational(&self) -> Option<&dyn GenerationalPlan<VM = VM>> {
Some(self)
}

fn is_live_object(&self, object: ObjectReference) -> bool {
self.gen.is_live_object(object)
}
}

impl<VM: VMBinding> GenerationalPlan for GenImmix<VM> {
Expand Down
5 changes: 5 additions & 0 deletions src/plan/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,11 @@ pub trait Plan: 'static + HasSpaces + Sync + Downcast {
space.verify_side_metadata_sanity(&mut side_metadata_sanity_checker);
})
}

fn is_live_object(&self, object: ObjectReference) -> bool {
let sft = unsafe { crate::mmtk::SFT_MAP.get_unchecked(object.to_raw_address()) };
sft.is_live(object)
}
}

impl_downcast!(Plan assoc VM);
Expand Down
17 changes: 17 additions & 0 deletions src/plan/sticky/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::util::heap::gc_trigger::SpaceStats;
use crate::util::metadata::log_bit::UnlogBitsOperation;
use crate::util::metadata::side_metadata::SideMetadataContext;
use crate::util::statistics::counter::EventCounter;
use crate::util::ObjectReference;
use crate::vm::ObjectModel;
use crate::vm::VMBinding;
use crate::Plan;
Expand Down Expand Up @@ -224,6 +225,22 @@ impl<VM: VMBinding> Plan for StickyImmix<VM> {
}
true
}

fn is_live_object(&self, object: ObjectReference) -> bool {
use crate::policy::sft::SFT;
if self.is_current_gc_nursery() {
if self.immix.immix_space.in_space(object) {
self.immix.immix_space.is_live(object)
} else if self.immix.common().get_los().in_space(object) {
self.immix.common().get_los().is_live(object)
} else {
true
}
} else {
let sft = unsafe { crate::mmtk::SFT_MAP.get_unchecked(object.to_raw_address()) };
sft.is_live(object)
}
}
}

impl<VM: VMBinding> GenerationalPlan for StickyImmix<VM> {
Expand Down
2 changes: 1 addition & 1 deletion src/policy/immix/immixspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
);

queue.enqueue(new_object);
debug_assert!(new_object.is_live());
debug_assert!(new_object.is_reachable());
new_object
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/policy/space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ impl<VM: VMBinding> CommonSpace<VM> {
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_unlogged::<VM>(object, Ordering::Relaxed),
);
}
println!("is live = {}", object.is_live());
println!("is reachable = {}", object.is_reachable());
}
}

Expand Down
5 changes: 0 additions & 5 deletions src/util/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,6 @@ impl ObjectReference {
unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_reachable(self)
}

/// Is the object live, determined by the policy?
pub fn is_live(self) -> bool {
unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_live(self)
}

/// Can the object be moved?
pub fn is_movable(self) -> bool {
unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_movable()
Expand Down
52 changes: 30 additions & 22 deletions src/util/finalizable_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,51 @@ use crate::util::reference_processor::RescanReferences;
use crate::util::ObjectReference;
use crate::util::VMWorkerThread;
use crate::vm::Finalizable;
use crate::vm::{Collection, VMBinding};
use crate::vm::{Collection, ReferenceGlue, VMBinding};
use crate::MMTK;
use std::marker::PhantomData;

type F<VM> = <<VM as VMBinding>::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType;

/// A special processor for Finalizable objects.
// TODO: we should consider if we want to merge FinalizableProcessor with ReferenceProcessor,
// and treat final reference as a special reference type in ReferenceProcessor.
#[derive(Default)]
pub struct FinalizableProcessor<F: Finalizable> {
pub struct FinalizableProcessor<VM: VMBinding> {
plan: &'static dyn crate::plan::Plan<VM = VM>,
/// Candidate objects that has finalizers with them
candidates: Vec<F>,
candidates: Vec<F<VM>>,
/// Index into candidates to record where we are up to in the last scan of the candidates.
/// Index after nursery_index are new objects inserted after the last GC.
nursery_index: usize,
/// Objects that can be finalized. They are actually dead, but we keep them alive
/// until the binding pops them from the queue.
ready_for_finalize: Vec<F>,
ready_for_finalize: Vec<F<VM>>,
}

impl<F: Finalizable> FinalizableProcessor<F> {
pub fn new() -> Self {
impl<VM: VMBinding> FinalizableProcessor<VM> {
pub fn new(plan: &'static dyn crate::plan::Plan<VM = VM>) -> Self {
Self {
plan,
candidates: vec![],
nursery_index: 0,
ready_for_finalize: vec![],
}
}

pub fn add(&mut self, object: F) {
pub fn add(&mut self, object: F<VM>) {
self.candidates.push(object);
}

fn forward_finalizable_reference<E: ProcessEdgesWork>(e: &mut E, finalizable: &mut F) {
fn forward_finalizable_reference<E: ProcessEdgesWork>(e: &mut E, finalizable: &mut F<VM>) {
finalizable.keep_alive::<E>(e);
}

pub fn scan<E: ProcessEdgesWork>(&mut self, tls: VMWorkerThread, e: &mut E, nursery: bool) {
pub fn scan<E: ProcessEdgesWork<VM = VM>>(
&mut self,
tls: VMWorkerThread,
e: &mut E,
nursery: bool,
) {
let start = if nursery { self.nursery_index } else { 0 };

// We should go through ready_for_finalize objects and keep them alive.
Expand All @@ -51,11 +59,11 @@ impl<F: Finalizable> FinalizableProcessor<F> {
self.candidates.append(&mut self.ready_for_finalize);
debug_assert!(self.ready_for_finalize.is_empty());

for mut f in self.candidates.drain(start..).collect::<Vec<F>>() {
for mut f in self.candidates.drain(start..).collect::<Vec<F<VM>>>() {
let reff = f.get_reference();
trace!("Pop {:?} for finalization", reff);
if reff.is_live() {
FinalizableProcessor::<F>::forward_finalizable_reference(e, &mut f);
if self.plan.is_live_object(reff) {
FinalizableProcessor::<VM>::forward_finalizable_reference(e, &mut f);
trace!("{:?} is live, push {:?} back to candidates", reff, f);
self.candidates.push(f);
continue;
Expand All @@ -79,25 +87,25 @@ impl<F: Finalizable> FinalizableProcessor<F> {
<<E as ProcessEdgesWork>::VM as VMBinding>::VMCollection::schedule_finalization(tls);
}

pub fn forward_candidate<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
pub fn forward_candidate<E: ProcessEdgesWork<VM = VM>>(&mut self, e: &mut E, _nursery: bool) {
self.candidates
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
.for_each(|f| FinalizableProcessor::<VM>::forward_finalizable_reference(e, f));
e.flush();
}

pub fn forward_finalizable<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
pub fn forward_finalizable<E: ProcessEdgesWork<VM = VM>>(&mut self, e: &mut E, _nursery: bool) {
self.ready_for_finalize
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
.for_each(|f| FinalizableProcessor::<VM>::forward_finalizable_reference(e, f));
e.flush();
}

pub fn get_ready_object(&mut self) -> Option<F> {
pub fn get_ready_object(&mut self) -> Option<F<VM>> {
self.ready_for_finalize.pop()
}

pub fn get_all_finalizers(&mut self) -> Vec<F> {
pub fn get_all_finalizers(&mut self) -> Vec<F<VM>> {
let mut ret = std::mem::take(&mut self.candidates);
let ready_objects = std::mem::take(&mut self.ready_for_finalize);
ret.extend(ready_objects);
Expand All @@ -108,12 +116,12 @@ impl<F: Finalizable> FinalizableProcessor<F> {
ret
}

pub fn get_finalizers_for(&mut self, object: ObjectReference) -> Vec<F> {
pub fn get_finalizers_for(&mut self, object: ObjectReference) -> Vec<F<VM>> {
// Drain filter for finalizers that equal to 'object':
// * for elements that equal to 'object', they will be removed from the original vec, and returned.
// * for elements that do not equal to 'object', they will be left in the original vec.
// TODO: We should replace this with `vec.drain_filter()` when it is stablized.
let drain_filter = |vec: &mut Vec<F>| -> Vec<F> {
let drain_filter = |vec: &mut Vec<F<VM>>| -> Vec<F<VM>> {
let mut i = 0;
let mut ret = vec![];
while i < vec.len() {
Expand All @@ -126,7 +134,7 @@ impl<F: Finalizable> FinalizableProcessor<F> {
}
ret
};
let mut ret: Vec<F> = drain_filter(&mut self.candidates);
let mut ret: Vec<F<VM>> = drain_filter(&mut self.candidates);
ret.extend(drain_filter(&mut self.ready_for_finalize));

// We removed objects from candidates. Reset nursery_index
Expand Down
Loading
Loading