use super::gc_work::ImmixGCWorkContext;
use super::mutator::ALLOCATOR_MAPPING;
use crate::plan::global::BasePlan;
use crate::plan::global::CommonPlan;
use crate::plan::global::GcStatus;
use crate::plan::AllocationSemantics;
use crate::plan::Plan;
use crate::plan::PlanConstraints;
use crate::policy::immix::{TRACE_KIND_DEFRAG, TRACE_KIND_FAST};
use crate::policy::space::Space;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
use crate::util::copy::*;
use crate::util::heap::layout::heap_layout::Mmapper;
use crate::util::heap::layout::heap_layout::VMMap;
use crate::util::heap::HeapMeta;
use crate::util::metadata::side_metadata::SideMetadataContext;
use crate::util::metadata::side_metadata::SideMetadataSanity;
use crate::util::options::Options;
use crate::vm::VMBinding;
use crate::{policy::immix::ImmixSpace, util::opaque_pointer::VMWorkerThread};
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use atomic::Ordering;
use enum_map::EnumMap;
use mmtk_macros::PlanTraceObject;
#[derive(PlanTraceObject)]
pub struct Immix<VM: VMBinding> {
#[post_scan]
#[trace(CopySemantics::DefaultCopy)]
pub immix_space: ImmixSpace<VM>,
#[fallback_trace]
pub common: CommonPlan<VM>,
last_gc_was_defrag: AtomicBool,
}
pub const IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints {
moves_objects: crate::policy::immix::DEFRAG,
gc_header_bits: 2,
gc_header_words: 0,
num_specialized_scans: 1,
max_non_los_default_alloc_bytes: crate::policy::immix::MAX_IMMIX_OBJECT_SIZE,
..PlanConstraints::default()
};
impl<VM: VMBinding> Plan for Immix<VM> {
type VM = VM;
fn collection_required(&self, space_full: bool, _space: Option<&dyn Space<Self::VM>>) -> bool {
self.base().collection_required(self, space_full)
}
fn last_collection_was_exhaustive(&self) -> bool {
ImmixSpace::<VM>::is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
}
fn constraints(&self) -> &'static PlanConstraints {
&IMMIX_CONSTRAINTS
}
fn create_copy_config(&'static self) -> CopyConfig<Self::VM> {
use enum_map::enum_map;
CopyConfig {
copy_mapping: enum_map! {
CopySemantics::DefaultCopy => CopySelector::Immix(0),
_ => CopySelector::Unused,
},
space_mapping: vec![(CopySelector::Immix(0), &self.immix_space)],
constraints: &IMMIX_CONSTRAINTS,
}
}
fn get_spaces(&self) -> Vec<&dyn Space<Self::VM>> {
let mut ret = self.common.get_spaces();
ret.push(&self.immix_space);
ret
}
fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<VM>) {
self.base().set_collection_kind::<Self>(self);
self.base().set_gc_status(GcStatus::GcPrepare);
let in_defrag = self.immix_space.decide_whether_to_defrag(
self.is_emergency_collection(),
true,
self.base().cur_collection_attempts.load(Ordering::SeqCst),
self.base().is_user_triggered_collection(),
*self.base().options.full_heap_system_gc,
);
#[allow(clippy::if_same_then_else)]
if in_defrag {
scheduler.schedule_common_work::<ImmixGCWorkContext<VM, TRACE_KIND_DEFRAG>>(self);
} else {
scheduler.schedule_common_work::<ImmixGCWorkContext<VM, TRACE_KIND_FAST>>(self);
}
}
fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
&*ALLOCATOR_MAPPING
}
fn prepare(&mut self, tls: VMWorkerThread) {
self.common.prepare(tls, true);
self.immix_space.prepare(true);
}
fn release(&mut self, tls: VMWorkerThread) {
self.common.release(tls, true);
self.last_gc_was_defrag
.store(self.immix_space.release(true), Ordering::Relaxed);
}
fn get_collection_reserved_pages(&self) -> usize {
self.immix_space.defrag_headroom_pages()
}
fn get_used_pages(&self) -> usize {
self.immix_space.reserved_pages() + self.common.get_used_pages()
}
fn base(&self) -> &BasePlan<VM> {
&self.common.base
}
fn common(&self) -> &CommonPlan<VM> {
&self.common
}
}
impl<VM: VMBinding> Immix<VM> {
pub fn new(
vm_map: &'static VMMap,
mmapper: &'static Mmapper,
options: Arc<Options>,
scheduler: Arc<GCWorkScheduler<VM>>,
) -> Self {
let mut heap = HeapMeta::new(&options);
let global_metadata_specs = SideMetadataContext::new_global_specs(&[]);
let immix = Immix {
immix_space: ImmixSpace::new(
"immix",
vm_map,
mmapper,
&mut heap,
scheduler,
global_metadata_specs.clone(),
),
common: CommonPlan::new(
vm_map,
mmapper,
options,
heap,
&IMMIX_CONSTRAINTS,
global_metadata_specs,
),
last_gc_was_defrag: AtomicBool::new(false),
};
{
let mut side_metadata_sanity_checker = SideMetadataSanity::new();
immix
.common
.verify_side_metadata_sanity(&mut side_metadata_sanity_checker);
immix
.immix_space
.verify_side_metadata_sanity(&mut side_metadata_sanity_checker);
}
immix
}
}