Skip to content
Merged
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
42 changes: 7 additions & 35 deletions src/plan/generational/copying/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::plan::Plan;
use crate::plan::PlanConstraints;
use crate::policy::copyspace::CopySpace;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
use crate::util::heap::layout::heap_layout::Mmapper;
Expand All @@ -21,8 +20,6 @@ use crate::util::heap::HeapMeta;
use crate::util::heap::VMRequest;
use crate::util::metadata::side_metadata::SideMetadataSanity;
use crate::util::options::UnsafeOptionsWrapper;
#[cfg(feature = "sanity")]
use crate::util::sanity::sanity_checker::*;
use crate::util::VMWorkerThread;
use crate::vm::*;
use enum_map::EnumMap;
Expand Down Expand Up @@ -85,50 +82,25 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {

fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<VM>) {
let is_full_heap = self.request_full_heap_collection();

// TODO: We should have a schedule_generational

self.base().set_collection_kind::<Self>(self);
self.base().set_gc_status(GcStatus::GcPrepare);
if !is_full_heap {
debug!("Nursery GC");
self.common()
.schedule_common::<GenNurseryProcessEdges<VM, GenCopyCopyContext<VM>>>(
.schedule_common::<Self, GenNurseryProcessEdges<VM, GenCopyCopyContext<VM>>, GenCopyCopyContext<VM>>(
self,
&GENCOPY_CONSTRAINTS,
scheduler,
);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(StopMutators::<
GenNurseryProcessEdges<VM, GenCopyCopyContext<VM>>,
>::new());
} else {
debug!("Full heap GC");
self.common()
.schedule_common::<GenCopyMatureProcessEdges<VM>>(&GENCOPY_CONSTRAINTS, scheduler);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained]
.add(StopMutators::<GenCopyMatureProcessEdges<VM>>::new());
}

// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<Self, GenCopyCopyContext<VM>>::new(self));
if is_full_heap {
scheduler.work_buckets[WorkBucketStage::RefClosure]
.add(ProcessWeakRefs::<GenCopyMatureProcessEdges<VM>>::new());
} else {
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<
GenNurseryProcessEdges<VM, GenCopyCopyContext<VM>>,
>::new());
.schedule_common::<Self, GenCopyMatureProcessEdges<VM>, GenCopyCopyContext<VM>>(
self,
&GENCOPY_CONSTRAINTS,
scheduler,
);
}
// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<Self, GenCopyCopyContext<VM>>::new(self));
// Resume mutators
#[cfg(feature = "sanity")]
scheduler.work_buckets[WorkBucketStage::Final]
.add(ScheduleSanityGC::<Self, GenCopyCopyContext<VM>>::new(self));
scheduler.set_finalizer(Some(EndOfGC));
}

fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
Expand Down
52 changes: 6 additions & 46 deletions src/plan/generational/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::plan::Plan;
use crate::plan::PlanConstraints;
use crate::policy::immix::ImmixSpace;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::GCWorkScheduler;
use crate::scheduler::GCWorkerLocalPtr;
use crate::scheduler::*;
Expand Down Expand Up @@ -129,67 +128,28 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {
if !is_full_heap {
debug!("Nursery GC");
self.common()
.schedule_common::<GenNurseryProcessEdges<VM, GenImmixCopyContext<VM>>>(
.schedule_common::<Self, GenNurseryProcessEdges<VM, GenImmixCopyContext<VM>>, GenImmixCopyContext<VM>>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type arguments here is especially complicated, with type parameters inside type parameters.

self,
&GENIMMIX_CONSTRAINTS,
scheduler,
);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(StopMutators::<
GenNurseryProcessEdges<VM, GenImmixCopyContext<VM>>,
>::new());
} else if defrag {
debug!("Full heap GC Defrag");
self.common()
.schedule_common::<GenImmixMatureProcessEdges<VM, { TraceKind::Defrag }>>(
.schedule_common::<Self, GenImmixMatureProcessEdges<VM, { TraceKind::Defrag }>, GenImmixCopyContext<VM>>(
self,
&GENIMMIX_CONSTRAINTS,
scheduler,
);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(StopMutators::<
GenImmixMatureProcessEdges<VM, { TraceKind::Defrag }>,
>::new());
} else {
debug!("Full heap GC Fast");
self.common()
.schedule_common::<GenImmixMatureProcessEdges<VM, { TraceKind::Fast }>>(
.schedule_common::<Self, GenImmixMatureProcessEdges<VM, { TraceKind::Fast }>, GenImmixCopyContext<VM>>(
self,
&GENIMMIX_CONSTRAINTS,
scheduler,
);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(StopMutators::<
GenImmixMatureProcessEdges<VM, { TraceKind::Fast }>,
>::new());
}

// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<Self, GenImmixCopyContext<VM>>::new(self));
if is_full_heap {
if defrag {
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<
GenImmixMatureProcessEdges<VM, { TraceKind::Defrag }>,
>::new());
} else {
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<
GenImmixMatureProcessEdges<VM, { TraceKind::Fast }>,
>::new());
}
} else {
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<
GenNurseryProcessEdges<VM, GenImmixCopyContext<VM>>,
>::new());
}
// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<Self, GenImmixCopyContext<VM>>::new(self));
// Resume mutators
#[cfg(feature = "sanity")]
{
use crate::util::sanity::sanity_checker::*;
scheduler.work_buckets[WorkBucketStage::Final]
.add(ScheduleSanityGC::<Self, GenImmixCopyContext<VM>>::new(self));
}
scheduler.set_finalizer(Some(EndOfGC));
}

fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
Expand Down
41 changes: 39 additions & 2 deletions src/plan/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -919,12 +919,46 @@ impl<VM: VMBinding> CommonPlan<VM> {
self.base.release(tls, full_heap)
}

pub fn schedule_common<E: ProcessEdgesWork<VM = VM>>(
/// Schedule all the common work packets
pub fn schedule_common<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function has too many type parameters. May be simplified using traits and associated types.

P: Plan<VM = VM>,
E: ProcessEdgesWork<VM = VM>,
C: CopyContext<VM = VM> + GCWorkerLocal,
>(
&self,
plan: &'static P,
constraints: &'static PlanConstraints,
scheduler: &GCWorkScheduler<VM>,
) {
// Schedule finalization
use crate::scheduler::gc_work::*;

// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(StopMutators::<E>::new());

// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare].add(Prepare::<P, C>::new(plan));

// VM-specific weak ref processing
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<E>::new());

// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release].add(Release::<P, C>::new(plan));

// Analysis GC work
#[cfg(feature = "analysis")]
{
use crate::util::analysis::GcHookWork;
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(GcHookWork);
}

// Sanity
#[cfg(feature = "sanity")]
{
use crate::util::sanity::sanity_checker::ScheduleSanityGC;
scheduler.work_buckets[WorkBucketStage::Final].add(ScheduleSanityGC::<P, C>::new(plan));
}

// Finalization
if !self.base.options.no_finalizer {
use crate::util::finalizable_processor::{Finalization, ForwardFinalization};
// finalization
Expand All @@ -935,6 +969,9 @@ impl<VM: VMBinding> CommonPlan<VM> {
.add(ForwardFinalization::<E>::new());
}
}

// Set EndOfGC to run at the end
scheduler.set_finalizer(Some(EndOfGC));
}

pub fn stacks_prepared(&self) -> bool {
Expand Down
44 changes: 5 additions & 39 deletions src/plan/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,15 @@ use crate::plan::AllocationSemantics;
use crate::plan::Plan;
use crate::plan::PlanConstraints;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
#[cfg(feature = "analysis")]
use crate::util::analysis::GcHookWork;
use crate::util::heap::layout::heap_layout::Mmapper;
use crate::util::heap::layout::heap_layout::VMMap;
use crate::util::heap::layout::vm_layout_constants::{HEAP_END, HEAP_START};
use crate::util::heap::HeapMeta;
use crate::util::metadata::side_metadata::SideMetadataContext;
use crate::util::metadata::side_metadata::SideMetadataSanity;
use crate::util::options::UnsafeOptionsWrapper;
#[cfg(feature = "sanity")]
use crate::util::sanity::sanity_checker::*;
use crate::vm::VMBinding;
use crate::{mmtk::MMTK, policy::immix::ImmixSpace, util::opaque_pointer::VMWorkerThread};
use std::sync::atomic::AtomicBool;
Expand Down Expand Up @@ -92,45 +87,16 @@ impl<VM: VMBinding> Plan for Immix<VM> {
self.base().is_user_triggered_collection(),
self.base().options.full_heap_system_gc,
);
// Stop & scan mutators (mutator scanning can happen before STW)
// The blocks are not identical, clippy is wrong. Probably it does not recognize the constant type parameter.
#[allow(clippy::if_same_then_else)]
// The two StopMutators have different types parameters, thus we cannot extract the common code before add().
#[allow(clippy::branches_sharing_code)]
if in_defrag {
scheduler.work_buckets[WorkBucketStage::Unconstrained]
.add(StopMutators::<ImmixProcessEdges<VM, { TraceKind::Defrag }>>::new());
} else {
scheduler.work_buckets[WorkBucketStage::Unconstrained]
.add(StopMutators::<ImmixProcessEdges<VM, { TraceKind::Fast }>>::new());
}
// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<Self, ImmixCopyContext<VM>>::new(self));

// The blocks are not identical, clippy is wrong. Probably it does not recognize the constant type parameter.
#[allow(clippy::if_same_then_else)]
// The two StopMutators have different types parameters, thus we cannot extract the common code before add().
#[allow(clippy::branches_sharing_code)]
if in_defrag {
scheduler.work_buckets[WorkBucketStage::RefClosure].add(ProcessWeakRefs::<
ImmixProcessEdges<VM, { TraceKind::Defrag }>,
>::new());
self.common()
.schedule_common::<Self, ImmixProcessEdges<VM, { TraceKind::Defrag }>, ImmixCopyContext<VM>>(self, &IMMIX_CONSTRAINTS, scheduler);
} else {
scheduler.work_buckets[WorkBucketStage::RefClosure]
.add(ProcessWeakRefs::<ImmixProcessEdges<VM, { TraceKind::Fast }>>::new());
self.common()
.schedule_common::<Self, ImmixProcessEdges<VM, { TraceKind::Fast }>, ImmixCopyContext<VM>>(self, &IMMIX_CONSTRAINTS, scheduler);
}
// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<Self, ImmixCopyContext<VM>>::new(self));
// Analysis routine that is ran. It is generally recommended to take advantage
// of the scheduling system we have in place for more performance
#[cfg(feature = "analysis")]
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(GcHookWork);
// Resume mutators
#[cfg(feature = "sanity")]
scheduler.work_buckets[WorkBucketStage::Final]
.add(ScheduleSanityGC::<Self, ImmixCopyContext<VM>>::new(self));
scheduler.set_finalizer(Some(EndOfGC));
}

fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
Expand Down
29 changes: 5 additions & 24 deletions src/plan/marksweep/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,16 @@ use crate::plan::PlanConstraints;
use crate::policy::mallocspace::metadata::ACTIVE_CHUNK_METADATA_SPEC;
use crate::policy::mallocspace::MallocSpace;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
#[cfg(not(feature = "global_alloc_bit"))]
use crate::util::alloc_bit::ALLOC_SIDE_METADATA_SPEC;
#[cfg(feature = "analysis")]
use crate::util::analysis::GcHookWork;
use crate::util::heap::layout::heap_layout::Mmapper;
use crate::util::heap::layout::heap_layout::VMMap;
use crate::util::heap::layout::vm_layout_constants::{HEAP_END, HEAP_START};
use crate::util::heap::HeapMeta;
use crate::util::metadata::side_metadata::{SideMetadataContext, SideMetadataSanity};
use crate::util::options::UnsafeOptionsWrapper;
#[cfg(feature = "sanity")]
use crate::util::sanity::sanity_checker::*;
use crate::util::VMWorkerThread;
use crate::vm::VMBinding;
use std::sync::Arc;
Expand Down Expand Up @@ -62,26 +57,12 @@ impl<VM: VMBinding> Plan for MarkSweep<VM> {
self.base().set_collection_kind::<Self>(self);
self.base().set_gc_status(GcStatus::GcPrepare);
self.common()
.schedule_common::<MSProcessEdges<VM>>(&MS_CONSTRAINTS, scheduler);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained]
.add(StopMutators::<MSProcessEdges<VM>>::new());
// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<Self, NoCopy<VM>>::new(self));
.schedule_common::<Self, MSProcessEdges<VM>, NoCopy<VM>>(
self,
&MS_CONSTRAINTS,
scheduler,
);
scheduler.work_buckets[WorkBucketStage::Prepare].add(MSSweepChunks::<VM>::new(self));
scheduler.work_buckets[WorkBucketStage::RefClosure]
.add(ProcessWeakRefs::<MSProcessEdges<VM>>::new());
// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<Self, NoCopy<VM>>::new(self));
#[cfg(feature = "analysis")]
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(GcHookWork);
// Resume mutators
#[cfg(feature = "sanity")]
scheduler.work_buckets[WorkBucketStage::Final]
.add(ScheduleSanityGC::<Self, NoCopy<VM>>::new(self));
scheduler.set_finalizer(Some(EndOfGC));
}

fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
Expand Down
27 changes: 1 addition & 26 deletions src/plan/pageprotect/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,15 @@ use crate::plan::AllocationSemantics;
use crate::plan::Plan;
use crate::plan::PlanConstraints;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
#[cfg(feature = "analysis")]
use crate::util::analysis::GcHookWork;
use crate::util::heap::layout::heap_layout::Mmapper;
use crate::util::heap::layout::heap_layout::VMMap;
use crate::util::heap::layout::vm_layout_constants::{HEAP_END, HEAP_START};
use crate::util::heap::HeapMeta;
use crate::util::heap::VMRequest;
use crate::util::metadata::side_metadata::SideMetadataContext;
use crate::util::options::UnsafeOptionsWrapper;
#[cfg(feature = "sanity")]
use crate::util::sanity::sanity_checker::*;
use crate::{plan::global::BasePlan, vm::VMBinding};
use crate::{
plan::global::{CommonPlan, NoCopy},
Expand Down Expand Up @@ -81,27 +76,7 @@ impl<VM: VMBinding> Plan for PageProtect<VM> {
self.base().set_collection_kind::<Self>(self);
self.base().set_gc_status(GcStatus::GcPrepare);
self.common()
.schedule_common::<PPProcessEdges<VM>>(&CONSTRAINTS, scheduler);
// Stop & scan mutators (mutator scanning can happen before STW)
scheduler.work_buckets[WorkBucketStage::Unconstrained]
.add(StopMutators::<PPProcessEdges<VM>>::new());
// Prepare global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<Self, NoCopy<VM>>::new(self));
scheduler.work_buckets[WorkBucketStage::RefClosure]
.add(ProcessWeakRefs::<PPProcessEdges<VM>>::new());
// Release global/collectors/mutators
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<Self, NoCopy<VM>>::new(self));
// Scheduling all the gc hooks of analysis routines. It is generally recommended
// to take advantage of the scheduling system we have in place for more performance
#[cfg(feature = "analysis")]
scheduler.work_buckets[WorkBucketStage::Unconstrained].add(GcHookWork);
// Resume mutators
#[cfg(feature = "sanity")]
scheduler.work_buckets[WorkBucketStage::Final]
.add(ScheduleSanityGC::<Self, NoCopy<VM>>::new(self));
scheduler.set_finalizer(Some(EndOfGC));
.schedule_common::<Self, PPProcessEdges<VM>, NoCopy<VM>>(self, &CONSTRAINTS, scheduler);
}

fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
Expand Down
Loading