Skip to content

Refactor log bits #1364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
3 changes: 3 additions & 0 deletions .github/workflows/binding-tests-openjdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ jobs:
cd mmtk-openjdk
export RUST_BACKTRACE=1
./.github/scripts/${{ inputs.test-script }}
- name: Setup tmate session
Copy link
Member Author

Choose a reason for hiding this comment

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

This was used for debugging. I will revert this.

if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ portable-atomic = "1.4.3"
probe = "0.5"
regex = "1.7.0"
rustversion = "1.0"
rayon-core = "=1.12.1" # We can remove this dependency when we use MSRV 1.80+
spin = "0.9.5"
static_assertions = "1.1.0"
strum = "0.27.1"
Expand Down
4 changes: 2 additions & 2 deletions docs/userguide/src/tutorial/code/mygc_semispace/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ impl<VM: VMBinding> MyGC<VM> {
let res = MyGC {
hi: AtomicBool::new(false),
// ANCHOR: copyspace_new
copyspace0: CopySpace::new(plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()), false),
copyspace0: CopySpace::new(plan_args.get_normal_space_args("copyspace0", true, false, VMRequest::discontiguous()), false),
// ANCHOR_END: copyspace_new
copyspace1: CopySpace::new(plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()), true),
copyspace1: CopySpace::new(plan_args.get_normal_space_args("copyspace1", true, false, VMRequest::discontiguous()), true),
common: CommonPlan::new(plan_args),
};

Expand Down
2 changes: 1 addition & 1 deletion src/plan/compressor/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<VM: VMBinding> Compressor<VM> {
};

let res = Compressor {
compressor_space: CompressorSpace::new(plan_args.get_space_args(
compressor_space: CompressorSpace::new(plan_args.get_normal_space_args(
"compressor_space",
true,
false,
Expand Down
7 changes: 5 additions & 2 deletions src/plan/generational/copying/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
let full_heap = !self.gen.is_current_gc_nursery();
self.gen.release(tls);
if full_heap {
if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
self.fromspace().clear_side_log_bits();
}
self.fromspace().release();
}
}
Expand Down Expand Up @@ -209,11 +212,11 @@ impl<VM: VMBinding> GenCopy<VM> {
};

let copyspace0 = CopySpace::new(
plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()),
plan_args.get_mature_space_args("copyspace0", true, false, VMRequest::discontiguous()),
false,
);
let copyspace1 = CopySpace::new(
plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()),
plan_args.get_mature_space_args("copyspace1", true, false, VMRequest::discontiguous()),
true,
);

Expand Down
5 changes: 4 additions & 1 deletion src/plan/generational/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub struct CommonGenPlan<VM: VMBinding> {
impl<VM: VMBinding> CommonGenPlan<VM> {
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> Self {
let nursery = CopySpace::new(
args.get_space_args("nursery", true, false, VMRequest::discontiguous()),
args.get_nursery_space_args("nursery", true, false, VMRequest::discontiguous()),
true,
);
let full_heap_gc_count = args
Expand Down Expand Up @@ -74,6 +74,9 @@ impl<VM: VMBinding> CommonGenPlan<VM> {
/// Release Gen. This should be called by a single thread in GC release work.
pub fn release(&mut self, tls: VMWorkerThread) {
let full_heap = !self.is_current_gc_nursery();
if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
self.nursery.clear_side_log_bits();
}
self.common.release(tls, full_heap);
self.nursery.release();
}
Expand Down
13 changes: 9 additions & 4 deletions src/plan/generational/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {
let full_heap = !self.gen.is_current_gc_nursery();
self.gen.prepare(tls);
if full_heap {
if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
self.immix_space.clear_side_log_bits();
}
self.immix_space.prepare(
full_heap,
Some(crate::policy::immix::defrag::StatsForDefrag::new(self)),
Expand Down Expand Up @@ -247,12 +250,14 @@ impl<VM: VMBinding> GenImmix<VM> {
crate::plan::generational::new_generational_global_metadata_specs::<VM>(),
};
let immix_space = ImmixSpace::new(
plan_args.get_space_args("immix_mature", true, false, VMRequest::discontiguous()),
plan_args.get_mature_space_args(
"immix_mature",
true,
false,
VMRequest::discontiguous(),
),
ImmixSpaceArgs {
// We need to unlog objects at tracing time since we currently clear all log bits during a major GC
unlog_object_when_traced: true,
// In GenImmix, young objects are not allocated in ImmixSpace directly.
#[cfg(feature = "vo_bit")]
mixed_age: false,
never_move_objects: false,
},
Expand Down
1 change: 1 addition & 0 deletions src/plan/generational/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub const FULL_NURSERY_GC: bool = false;
pub const GEN_CONSTRAINTS: PlanConstraints = PlanConstraints {
moves_objects: true,
needs_log_bit: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier),
generational: true,
barrier: ACTIVE_BARRIER,
// 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.
may_trace_duplicate_edges: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier),
Expand Down
167 changes: 144 additions & 23 deletions src/plan/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,18 +404,22 @@ pub struct CreateSpecificPlanArgs<'a, VM: VMBinding> {

impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
/// Get a PlanCreateSpaceArgs that can be used to create a space
pub fn get_space_args(
pub fn _get_space_args(
&mut self,
name: &'static str,
zeroed: bool,
permission_exec: bool,
unlog_allocated_object: bool,
unlog_traced_object: bool,
vmrequest: VMRequest,
) -> PlanCreateSpaceArgs<VM> {
PlanCreateSpaceArgs {
name,
zeroed,
permission_exec,
vmrequest,
unlog_allocated_object,
unlog_traced_object,
global_side_metadata_specs: self.global_side_metadata_specs.clone(),
vm_map: self.global_args.vm_map,
mmapper: self.global_args.mmapper,
Expand All @@ -427,39 +431,121 @@ impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
global_state: self.global_args.state.clone(),
}
}

// The following are some convenience methods for common presets.
// These are not an exhaustive list -- it is just common presets that are used by most plans.

/// Get a preset for a nursery space (where young objects are located).
pub fn get_nursery_space_args(
&mut self,
name: &'static str,
zeroed: bool,
permission_exec: bool,
vmrequest: VMRequest,
) -> PlanCreateSpaceArgs<VM> {
// Objects are allocatd as young, and when traced, they stay young. If they are copied out of the nursery space, they will be moved to a mature space,
// and log bits will be set in that case by the mature space.
self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
}

/// Get a preset for a mature space (where mature objects are located).
pub fn get_mature_space_args(
&mut self,
name: &'static str,
zeroed: bool,
permission_exec: bool,
vmrequest: VMRequest,
) -> PlanCreateSpaceArgs<VM> {
// Objects are allocated as mature (pre-tenured), and when traced, they stay mature.
// If an object gets copied into a mature space, the object is also mature,
self._get_space_args(name, zeroed, permission_exec, true, true, vmrequest)
}

// Get a preset for a mixed age space (where both young and mature objects are located).
pub fn get_mixed_age_space_args(
&mut self,
name: &'static str,
zeroed: bool,
permission_exec: bool,
vmrequest: VMRequest,
) -> PlanCreateSpaceArgs<VM> {
// Objects are allocated as young, and when traced, they become mature objects.
self._get_space_args(name, zeroed, permission_exec, false, true, vmrequest)
}

/// Get a preset for spaces in a non-generational plan.
pub fn get_normal_space_args(
&mut self,
name: &'static str,
zeroed: bool,
permission_exec: bool,
vmrequest: VMRequest,
) -> PlanCreateSpaceArgs<VM> {
// Non generational plan: we do not use any of the flags about log bits.
self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
}

/// Get a preset for spaces in [`crate::plan::global::CommonPlan`].
/// Spaces like LOS which may include both young and mature objects should not use this method.
pub fn get_common_space_args(
&mut self,
generational: bool,
name: &'static str,
) -> PlanCreateSpaceArgs<VM> {
self.get_base_space_args(
generational,
name,
false, // Common spaces are not executable.
)
}

/// Get a preset for spaces in [`crate::plan::global::BasePlan`].
pub fn get_base_space_args(
&mut self,
generational: bool,
name: &'static str,
permission_exec: bool,
) -> PlanCreateSpaceArgs<VM> {
if generational {
// In generational plans, common/base spaces behave like a mature space:
// * the objects in these spaces are not traced in a nursery GC
// * the log bits for the objects are maintained exactly the same as a mature space.
// Thus we consider them as mature spaces.
self.get_mature_space_args(name, true, permission_exec, VMRequest::discontiguous())
} else {
self.get_normal_space_args(name, true, permission_exec, VMRequest::discontiguous())
}
}
}

impl<VM: VMBinding> BasePlan<VM> {
#[allow(unused_mut)] // 'args' only needs to be mutable for certain features
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> BasePlan<VM> {
let _generational = args.constraints.generational;
BasePlan {
#[cfg(feature = "code_space")]
code_space: ImmortalSpace::new(args.get_space_args(
code_space: ImmortalSpace::new(args.get_base_space_args(
_generational,
"code_space",
true,
true,
VMRequest::discontiguous(),
)),
#[cfg(feature = "code_space")]
code_lo_space: ImmortalSpace::new(args.get_space_args(
code_lo_space: ImmortalSpace::new(args.get_base_space_args(
_generational,
"code_lo_space",
true,
true,
VMRequest::discontiguous(),
)),
#[cfg(feature = "ro_space")]
ro_space: ImmortalSpace::new(args.get_space_args(
ro_space: ImmortalSpace::new(args.get_base_space_args(
_generational,
"ro_space",
true,
false,
VMRequest::discontiguous(),
)),
#[cfg(feature = "vm_space")]
vm_space: VMSpace::new(args.get_space_args(
vm_space: VMSpace::new(args.get_base_space_args(
_generational,
"vm_space",
false,
false, // it doesn't matter -- we are not mmapping for VM space.
VMRequest::discontiguous(),
)),

global_state: args.global_args.state.clone(),
Expand Down Expand Up @@ -517,6 +603,28 @@ impl<VM: VMBinding> BasePlan<VM> {
self.vm_space.release();
}

pub fn clear_side_log_bits(&self) {
#[cfg(feature = "code_space")]
self.code_space.clear_side_log_bits();
#[cfg(feature = "code_space")]
self.code_lo_space.clear_side_log_bits();
#[cfg(feature = "ro_space")]
self.ro_space.clear_side_log_bits();
#[cfg(feature = "vm_space")]
self.vm_space.clear_side_log_bits();
}

pub fn set_side_log_bits(&self) {
#[cfg(feature = "code_space")]
self.code_space.set_side_log_bits();
#[cfg(feature = "code_space")]
self.code_lo_space.set_side_log_bits();
#[cfg(feature = "ro_space")]
self.ro_space.set_side_log_bits();
#[cfg(feature = "vm_space")]
self.vm_space.set_side_log_bits();
}

pub fn end_of_gc(&mut self, _tls: VMWorkerThread) {
// Do nothing here. None of the spaces needs end_of_gc.
}
Expand Down Expand Up @@ -584,16 +692,19 @@ pub struct CommonPlan<VM: VMBinding> {

impl<VM: VMBinding> CommonPlan<VM> {
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> CommonPlan<VM> {
let needs_log_bit = args.constraints.needs_log_bit;
let generational = args.constraints.generational;
CommonPlan {
immortal: ImmortalSpace::new(args.get_space_args(
"immortal",
true,
false,
VMRequest::discontiguous(),
)),
immortal: ImmortalSpace::new(args.get_common_space_args(generational, "immortal")),
los: LargeObjectSpace::new(
args.get_space_args("los", true, false, VMRequest::discontiguous()),
// LOS is a bit special, as it is a mixed age space. It has a logical nursery.
if generational {
args.get_mixed_age_space_args("los", true, false, VMRequest::discontiguous())
} else {
args.get_normal_space_args("los", true, false, VMRequest::discontiguous())
},
false,
needs_log_bit,
),
nonmoving: Self::new_nonmoving_space(&mut args),
base: BasePlan::new(args),
Expand Down Expand Up @@ -621,6 +732,18 @@ impl<VM: VMBinding> CommonPlan<VM> {
self.base.release(tls, full_heap)
}

pub fn clear_side_log_bits(&self) {
self.immortal.clear_side_log_bits();
self.los.clear_side_log_bits();
self.base.clear_side_log_bits();
}

pub fn set_side_log_bits(&self) {
self.immortal.set_side_log_bits();
self.los.set_side_log_bits();
self.base.set_side_log_bits();
}

pub fn end_of_gc(&mut self, tls: VMWorkerThread) {
self.end_of_gc_nonmoving_space();
self.base.end_of_gc(tls);
Expand All @@ -639,7 +762,7 @@ impl<VM: VMBinding> CommonPlan<VM> {
}

fn new_nonmoving_space(args: &mut CreateSpecificPlanArgs<VM>) -> NonMovingSpace<VM> {
let space_args = args.get_space_args("nonmoving", true, false, VMRequest::discontiguous());
let space_args = args.get_common_space_args(args.constraints.generational, "nonmoving");
cfg_if::cfg_if! {
if #[cfg(any(feature = "immortal_as_nonmoving", feature = "marksweep_as_nonmoving"))] {
NonMovingSpace::new(space_args)
Expand All @@ -648,8 +771,6 @@ impl<VM: VMBinding> CommonPlan<VM> {
NonMovingSpace::new(
space_args,
crate::policy::immix::ImmixSpaceArgs {
unlog_object_when_traced: false,
#[cfg(feature = "vo_bit")]
mixed_age: false,
never_move_objects: true,
},
Expand Down
18 changes: 15 additions & 3 deletions src/plan/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@ impl<VM: VMBinding> Immix<VM> {
Self::new_with_args(
plan_args,
ImmixSpaceArgs {
unlog_object_when_traced: false,
#[cfg(feature = "vo_bit")]
mixed_age: false,
never_move_objects: false,
},
Expand All @@ -152,7 +150,21 @@ impl<VM: VMBinding> Immix<VM> {
) -> Self {
let immix = Immix {
immix_space: ImmixSpace::new(
plan_args.get_space_args("immix", true, false, VMRequest::discontiguous()),
if space_args.mixed_age {
plan_args.get_mixed_age_space_args(
"immix",
true,
false,
VMRequest::discontiguous(),
)
} else {
plan_args.get_normal_space_args(
"immix",
true,
false,
VMRequest::discontiguous(),
)
},
space_args,
),
common: CommonPlan::new(plan_args),
Expand Down
Loading
Loading