Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 4 additions & 3 deletions src/plan/generational/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {

fn last_collection_was_exhaustive(&self) -> bool {
self.last_gc_was_full_heap.load(Ordering::Relaxed)
&& ImmixSpace::<VM>::is_last_gc_exhaustive(
self.last_gc_was_defrag.load(Ordering::Relaxed),
)
&& self
.immix_space
.is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
}

fn collection_required(&self, space_full: bool, space: Option<SpaceStats<Self::VM>>) -> bool
Expand Down Expand Up @@ -254,6 +254,7 @@ impl<VM: VMBinding> GenImmix<VM> {
// In GenImmix, young objects are not allocated in ImmixSpace directly.
#[cfg(feature = "vo_bit")]
mixed_age: false,
never_move_objects: cfg!(feature = "immix_non_moving"),
},
);

Expand Down
6 changes: 4 additions & 2 deletions src/plan/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub struct Immix<VM: VMBinding> {

/// The plan constraints for the immix plan.
pub const IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints {
moves_objects: crate::policy::immix::DEFRAG,
moves_objects: true,
Comment thread
qinsoon marked this conversation as resolved.
Outdated
// Max immix object size is half of a block.
max_non_los_default_alloc_bytes: crate::policy::immix::MAX_IMMIX_OBJECT_SIZE,
needs_prepare_mutator: false,
Expand All @@ -51,7 +51,8 @@ impl<VM: VMBinding> Plan for Immix<VM> {
}

fn last_collection_was_exhaustive(&self) -> bool {
ImmixSpace::<VM>::is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
self.immix_space
.is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
}

fn constraints(&self) -> &'static PlanConstraints {
Expand Down Expand Up @@ -139,6 +140,7 @@ impl<VM: VMBinding> Immix<VM> {
unlog_object_when_traced: false,
#[cfg(feature = "vo_bit")]
mixed_age: false,
never_move_objects: cfg!(feature = "immix_non_moving"),
Comment thread
qinsoon marked this conversation as resolved.
Outdated
},
)
}
Expand Down
8 changes: 4 additions & 4 deletions src/plan/sticky/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::plan::PlanConstraints;
use crate::policy::gc_work::TraceKind;
use crate::policy::gc_work::TRACE_KIND_TRANSITIVE_PIN;
use crate::policy::immix::ImmixSpace;
use crate::policy::immix::PREFER_COPY_ON_NURSERY_GC;
use crate::policy::immix::TRACE_KIND_FAST;
use crate::policy::sft::SFT;
use crate::policy::space::Space;
Expand Down Expand Up @@ -41,7 +40,7 @@ pub struct StickyImmix<VM: VMBinding> {

/// The plan constraints for the sticky immix plan.
pub const STICKY_IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints {
moves_objects: crate::policy::immix::DEFRAG || crate::policy::immix::PREFER_COPY_ON_NURSERY_GC,
moves_objects: true,
Comment thread
wks marked this conversation as resolved.
Outdated
needs_log_bit: true,
barrier: crate::plan::BarrierSelector::ObjectBarrier,
// We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743.
Expand Down Expand Up @@ -164,7 +163,7 @@ impl<VM: VMBinding> Plan for StickyImmix<VM> {

fn current_gc_may_move_object(&self) -> bool {
if self.is_current_gc_nursery() {
PREFER_COPY_ON_NURSERY_GC
self.get_immix_space().prefer_copy_on_nursery_gc()
} else {
self.get_immix_space().in_defrag()
}
Expand Down Expand Up @@ -263,7 +262,7 @@ impl<VM: VMBinding> crate::plan::generational::global::GenerationalPlanExt<VM> f
self.immix
.immix_space
.trace_object_without_moving(queue, object)
} else if crate::policy::immix::PREFER_COPY_ON_NURSERY_GC {
} else if self.immix.immix_space.prefer_copy_on_nursery_gc() {
let ret = self.immix.immix_space.trace_object_with_opportunistic_copy(
queue,
object,
Expand Down Expand Up @@ -330,6 +329,7 @@ impl<VM: VMBinding> StickyImmix<VM> {
// In StickyImmix, both young and old objects are allocated in the ImmixSpace.
#[cfg(feature = "vo_bit")]
mixed_age: true,
never_move_objects: cfg!(feature = "immix_non_moving"),
},
);
Self {
Expand Down
9 changes: 4 additions & 5 deletions src/policy/immix/defrag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,18 @@ impl Defrag {
}

/// Determine whether the current GC should do defragmentation.
#[allow(clippy::too_many_arguments)]
pub fn decide_whether_to_defrag(
&self,
defrag_enabled: bool,
emergency_collection: bool,
collect_whole_heap: bool,
collection_attempts: usize,
user_triggered: bool,
exhausted_reusable_space: bool,
full_heap_system_gc: bool,
) {
let in_defrag = super::DEFRAG
let in_defrag = defrag_enabled
&& (emergency_collection
|| (collection_attempts > 1)
|| !exhausted_reusable_space
Expand Down Expand Up @@ -116,9 +118,8 @@ impl Defrag {
}

/// Prepare work. Should be called in ImmixSpace::prepare.
#[allow(clippy::assertions_on_constants)]
pub fn prepare<VM: VMBinding>(&self, space: &ImmixSpace<VM>, plan_stats: StatsForDefrag) {
debug_assert!(super::DEFRAG);
debug_assert!(space.is_defrag_enabled());
self.defrag_space_exhausted.store(false, Ordering::Release);

// Calculate available free space for defragmentation.
Expand Down Expand Up @@ -207,9 +208,7 @@ impl Defrag {
}

/// Reset the in-defrag state.
#[allow(clippy::assertions_on_constants)]
pub fn reset_in_defrag(&self) {
debug_assert!(super::DEFRAG);
self.in_defrag_collection.store(false, Ordering::Release);
}
}
57 changes: 42 additions & 15 deletions src/policy/immix/immixspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub struct ImmixSpaceArgs {
// Currently only used when "vo_bit" is enabled. Using #[cfg(...)] to eliminate dead code warning.
#[cfg(feature = "vo_bit")]
pub mixed_age: bool,
/// Disable copying for this Immix space.
pub never_move_objects: bool,
}

unsafe impl<VM: VMBinding> Sync for ImmixSpace<VM> {}
Expand All @@ -84,7 +86,7 @@ impl<VM: VMBinding> SFT for ImmixSpace<VM> {

fn get_forwarded_object(&self, object: ObjectReference) -> Option<ObjectReference> {
// If we never move objects, look no further.
if super::NEVER_MOVE_OBJECTS {
if !self.is_movable() {
return None;
}

Expand All @@ -102,7 +104,7 @@ impl<VM: VMBinding> SFT for ImmixSpace<VM> {
}

// If we never move objects, look no further.
if super::NEVER_MOVE_OBJECTS {
if !self.is_movable() {
return false;
}

Expand All @@ -122,7 +124,7 @@ impl<VM: VMBinding> SFT for ImmixSpace<VM> {
VM::VMObjectModel::LOCAL_PINNING_BIT_SPEC.is_object_pinned::<VM>(object)
}
fn is_movable(&self) -> bool {
!super::NEVER_MOVE_OBJECTS
!self.space_args.never_move_objects
}

#[cfg(feature = "sanity")]
Expand Down Expand Up @@ -278,12 +280,13 @@ impl<VM: VMBinding> ImmixSpace<VM> {
args: crate::policy::space::PlanCreateSpaceArgs<VM>,
space_args: ImmixSpaceArgs,
) -> Self {
#[cfg(feature = "immix_non_moving")]
info!(
"Creating non-moving ImmixSpace: {}. Block size: 2^{}",
args.name,
Block::LOG_BYTES
);
if space_args.never_move_objects {
Comment thread
qinsoon marked this conversation as resolved.
Outdated
info!(
"Creating non-moving ImmixSpace: {}. Block size: 2^{}",
args.name,
Block::LOG_BYTES
);
Comment thread
qinsoon marked this conversation as resolved.
Outdated
}

if space_args.unlog_object_when_traced {
assert!(
Expand All @@ -292,7 +295,18 @@ impl<VM: VMBinding> ImmixSpace<VM> {
);
}

super::validate_features();
// validate features
if super::BLOCK_ONLY {
assert!(
space_args.never_move_objects,
"Block-only immix must not move objects"
);
}
assert!(
Block::LINES / 2 <= u8::MAX as usize - 2,
"Number of lines in a block should not exceed BlockState::MARK_MARKED"
);

#[cfg(feature = "vo_bit")]
vo_bit::helper::validate_config::<VM>();
let vm_map = args.vm_map;
Expand Down Expand Up @@ -356,6 +370,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
full_heap_system_gc: bool,
) -> bool {
self.defrag.decide_whether_to_defrag(
self.is_defrag_enabled(),
emergency_collection,
collect_whole_heap,
collection_attempts,
Expand Down Expand Up @@ -390,7 +405,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
}

// Prepare defrag info
if super::DEFRAG {
if self.is_defrag_enabled() {
self.defrag.prepare(self, plan_stats);
}

Expand Down Expand Up @@ -483,7 +498,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
/// Return whether this GC was a defrag GC, as a plan may want to know this.
pub fn end_of_gc(&mut self) -> bool {
let did_defrag = self.defrag.in_defrag();
if super::DEFRAG {
if self.is_defrag_enabled() {
self.defrag.reset_in_defrag();
}
did_defrag
Expand Down Expand Up @@ -806,8 +821,8 @@ impl<VM: VMBinding> ImmixSpace<VM> {
Some((start, end))
}

pub fn is_last_gc_exhaustive(did_defrag_for_last_gc: bool) -> bool {
if super::DEFRAG {
pub fn is_last_gc_exhaustive(&self, did_defrag_for_last_gc: bool) -> bool {
if self.is_defrag_enabled() {
did_defrag_for_last_gc
} else {
// If defrag is disabled, every GC is exhaustive.
Expand All @@ -833,6 +848,18 @@ impl<VM: VMBinding> ImmixSpace<VM> {
self.mark_lines(object);
}
}

pub(crate) fn prefer_copy_on_nursery_gc(&self) -> bool {
self.is_nursery_copy_enabled()
}

pub(crate) fn is_nursery_copy_enabled(&self) -> bool {
!self.space_args.never_move_objects && !cfg!(feature = "sticky_immix_non_moving_nursery")
}

pub(crate) fn is_defrag_enabled(&self) -> bool {
!self.space_args.never_move_objects
}
}

/// A work packet to prepare each block for a major GC.
Expand Down Expand Up @@ -867,7 +894,7 @@ impl<VM: VMBinding> GCWork<VM> for PrepareBlockState<VM> {
continue;
}
// Check if this block needs to be defragmented.
let is_defrag_source = if !super::DEFRAG {
let is_defrag_source = if !self.space.is_defrag_enabled() {
// Do not set any block as defrag source if defrag is disabled.
false
} else if super::DEFRAG_EVERY_BLOCK {
Expand Down
25 changes: 0 additions & 25 deletions src/policy/immix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ pub const MAX_IMMIX_OBJECT_SIZE: usize = Block::BYTES >> 1;
/// Mark/sweep memory for block-level only
pub const BLOCK_ONLY: bool = false;

/// Do we allow Immix to do defragmentation?
pub const DEFRAG: bool = !cfg!(feature = "immix_non_moving"); // defrag if we are allowed to move.

// STRESS COPYING: Set the feature 'immix_stress_copying' so that Immix will copy as many objects as possible.
// Useful for debugging copying GC if you cannot use SemiSpace.
//
Expand Down Expand Up @@ -46,28 +43,6 @@ pub const DEFRAG_HEADROOM_PERCENT: usize = if cfg!(feature = "immix_stress_copyi
2
};

/// If Immix is used as a nursery space, do we prefer copy?
pub const PREFER_COPY_ON_NURSERY_GC: bool =
!cfg!(feature = "immix_non_moving") && !cfg!(feature = "sticky_immix_non_moving_nursery"); // copy nursery objects if we are allowed to move.

/// In some cases/settings, Immix may never move objects.
/// Currently we only have two cases where we move objects: 1. defrag, 2. nursery copy.
/// If we do neither, we will not move objects.
/// If we have other reasons to move objects, we need to add them here.
pub const NEVER_MOVE_OBJECTS: bool = !DEFRAG && !PREFER_COPY_ON_NURSERY_GC;

/// Mark lines when scanning objects.
/// Otherwise, do it at mark time.
pub const MARK_LINE_AT_SCAN_TIME: bool = true;

macro_rules! validate {
($x: expr) => { assert!($x, stringify!($x)) };
($x: expr => $y: expr) => { if $x { assert!($y, stringify!($x implies $y)) } };
}

fn validate_features() {
// Block-only immix cannot do defragmentation
validate!(DEFRAG => !BLOCK_ONLY);
// Number of lines in a block should not exceed BlockState::MARK_MARKED
assert!(Block::LINES / 2 <= u8::MAX as usize - 2);
}