Skip to content

Commit e058cee

Browse files
authored
Refactor log bits (#1364)
This PR refactors the log bits: the current implementation assumes log bits are used for generational plans, and they carry generation semantics. This PR removes such assumptions. With this PR, log bits are global metadata, and its semantic is defined by the plans. A plan may directly manipulate log bits, and may tell policies how to deal with log bits. A policy should never assume the semantics of log bits, and they just do whatever they are instructed to. Some policies assume the log bit may be in the side, and this PR does not try to address this issue.
1 parent 0721d12 commit e058cee

File tree

28 files changed

+380
-102
lines changed

28 files changed

+380
-102
lines changed

docs/userguide/src/tutorial/code/mygc_semispace/global.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ impl<VM: VMBinding> MyGC<VM> {
181181
let res = MyGC {
182182
hi: AtomicBool::new(false),
183183
// ANCHOR: copyspace_new
184-
copyspace0: CopySpace::new(plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()), false),
184+
copyspace0: CopySpace::new(plan_args.get_normal_space_args("copyspace0", true, false, VMRequest::discontiguous()), false),
185185
// ANCHOR_END: copyspace_new
186-
copyspace1: CopySpace::new(plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()), true),
186+
copyspace1: CopySpace::new(plan_args.get_normal_space_args("copyspace1", true, false, VMRequest::discontiguous()), true),
187187
common: CommonPlan::new(plan_args),
188188
};
189189

src/plan/compressor/global.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<VM: VMBinding> Compressor<VM> {
183183
};
184184

185185
let res = Compressor {
186-
compressor_space: CompressorSpace::new(plan_args.get_space_args(
186+
compressor_space: CompressorSpace::new(plan_args.get_normal_space_args(
187187
"compressor_space",
188188
true,
189189
false,

src/plan/generational/copying/global.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
110110
let full_heap = !self.gen.is_current_gc_nursery();
111111
self.gen.release(tls);
112112
if full_heap {
113+
if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
114+
self.fromspace().clear_side_log_bits();
115+
}
113116
self.fromspace().release();
114117
}
115118
}
@@ -209,11 +212,11 @@ impl<VM: VMBinding> GenCopy<VM> {
209212
};
210213

211214
let copyspace0 = CopySpace::new(
212-
plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()),
215+
plan_args.get_mature_space_args("copyspace0", true, false, VMRequest::discontiguous()),
213216
false,
214217
);
215218
let copyspace1 = CopySpace::new(
216-
plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()),
219+
plan_args.get_mature_space_args("copyspace1", true, false, VMRequest::discontiguous()),
217220
true,
218221
);
219222

src/plan/generational/global.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub struct CommonGenPlan<VM: VMBinding> {
4141
impl<VM: VMBinding> CommonGenPlan<VM> {
4242
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> Self {
4343
let nursery = CopySpace::new(
44-
args.get_space_args("nursery", true, false, VMRequest::discontiguous()),
44+
args.get_nursery_space_args("nursery", true, false, VMRequest::discontiguous()),
4545
true,
4646
);
4747
let full_heap_gc_count = args

src/plan/generational/immix/global.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {
129129
let full_heap = !self.gen.is_current_gc_nursery();
130130
self.gen.prepare(tls);
131131
if full_heap {
132+
if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
133+
self.immix_space.clear_side_log_bits();
134+
}
132135
self.immix_space.prepare(
133136
full_heap,
134137
Some(crate::policy::immix::defrag::StatsForDefrag::new(self)),
@@ -247,12 +250,14 @@ impl<VM: VMBinding> GenImmix<VM> {
247250
crate::plan::generational::new_generational_global_metadata_specs::<VM>(),
248251
};
249252
let immix_space = ImmixSpace::new(
250-
plan_args.get_space_args("immix_mature", true, false, VMRequest::discontiguous()),
253+
plan_args.get_mature_space_args(
254+
"immix_mature",
255+
true,
256+
false,
257+
VMRequest::discontiguous(),
258+
),
251259
ImmixSpaceArgs {
252-
// We need to unlog objects at tracing time since we currently clear all log bits during a major GC
253-
unlog_object_when_traced: true,
254260
// In GenImmix, young objects are not allocated in ImmixSpace directly.
255-
#[cfg(feature = "vo_bit")]
256261
mixed_age: false,
257262
never_move_objects: false,
258263
},

src/plan/generational/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub const FULL_NURSERY_GC: bool = false;
4545
pub const GEN_CONSTRAINTS: PlanConstraints = PlanConstraints {
4646
moves_objects: true,
4747
needs_log_bit: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier),
48+
generational: true,
4849
barrier: ACTIVE_BARRIER,
4950
// 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.
5051
may_trace_duplicate_edges: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier),

src/plan/global.rs

Lines changed: 144 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -404,18 +404,22 @@ pub struct CreateSpecificPlanArgs<'a, VM: VMBinding> {
404404

405405
impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
406406
/// Get a PlanCreateSpaceArgs that can be used to create a space
407-
pub fn get_space_args(
407+
pub fn _get_space_args(
408408
&mut self,
409409
name: &'static str,
410410
zeroed: bool,
411411
permission_exec: bool,
412+
unlog_allocated_object: bool,
413+
unlog_traced_object: bool,
412414
vmrequest: VMRequest,
413415
) -> PlanCreateSpaceArgs<'_, VM> {
414416
PlanCreateSpaceArgs {
415417
name,
416418
zeroed,
417419
permission_exec,
418420
vmrequest,
421+
unlog_allocated_object,
422+
unlog_traced_object,
419423
global_side_metadata_specs: self.global_side_metadata_specs.clone(),
420424
vm_map: self.global_args.vm_map,
421425
mmapper: self.global_args.mmapper,
@@ -427,39 +431,121 @@ impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
427431
global_state: self.global_args.state.clone(),
428432
}
429433
}
434+
435+
// The following are some convenience methods for common presets.
436+
// These are not an exhaustive list -- it is just common presets that are used by most plans.
437+
438+
/// Get a preset for a nursery space (where young objects are located).
439+
pub fn get_nursery_space_args(
440+
&mut self,
441+
name: &'static str,
442+
zeroed: bool,
443+
permission_exec: bool,
444+
vmrequest: VMRequest,
445+
) -> PlanCreateSpaceArgs<'_, VM> {
446+
// 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,
447+
// and log bits will be set in that case by the mature space.
448+
self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
449+
}
450+
451+
/// Get a preset for a mature space (where mature objects are located).
452+
pub fn get_mature_space_args(
453+
&mut self,
454+
name: &'static str,
455+
zeroed: bool,
456+
permission_exec: bool,
457+
vmrequest: VMRequest,
458+
) -> PlanCreateSpaceArgs<'_, VM> {
459+
// Objects are allocated as mature (pre-tenured), and when traced, they stay mature.
460+
// If an object gets copied into a mature space, the object is also mature,
461+
self._get_space_args(name, zeroed, permission_exec, true, true, vmrequest)
462+
}
463+
464+
// Get a preset for a mixed age space (where both young and mature objects are located).
465+
pub fn get_mixed_age_space_args(
466+
&mut self,
467+
name: &'static str,
468+
zeroed: bool,
469+
permission_exec: bool,
470+
vmrequest: VMRequest,
471+
) -> PlanCreateSpaceArgs<'_, VM> {
472+
// Objects are allocated as young, and when traced, they become mature objects.
473+
self._get_space_args(name, zeroed, permission_exec, false, true, vmrequest)
474+
}
475+
476+
/// Get a preset for spaces in a non-generational plan.
477+
pub fn get_normal_space_args(
478+
&mut self,
479+
name: &'static str,
480+
zeroed: bool,
481+
permission_exec: bool,
482+
vmrequest: VMRequest,
483+
) -> PlanCreateSpaceArgs<'_, VM> {
484+
// Non generational plan: we do not use any of the flags about log bits.
485+
self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
486+
}
487+
488+
/// Get a preset for spaces in [`crate::plan::global::CommonPlan`].
489+
/// Spaces like LOS which may include both young and mature objects should not use this method.
490+
pub fn get_common_space_args(
491+
&mut self,
492+
generational: bool,
493+
name: &'static str,
494+
) -> PlanCreateSpaceArgs<'_, VM> {
495+
self.get_base_space_args(
496+
generational,
497+
name,
498+
false, // Common spaces are not executable.
499+
)
500+
}
501+
502+
/// Get a preset for spaces in [`crate::plan::global::BasePlan`].
503+
pub fn get_base_space_args(
504+
&mut self,
505+
generational: bool,
506+
name: &'static str,
507+
permission_exec: bool,
508+
) -> PlanCreateSpaceArgs<'_, VM> {
509+
if generational {
510+
// In generational plans, common/base spaces behave like a mature space:
511+
// * the objects in these spaces are not traced in a nursery GC
512+
// * the log bits for the objects are maintained exactly the same as a mature space.
513+
// Thus we consider them as mature spaces.
514+
self.get_mature_space_args(name, true, permission_exec, VMRequest::discontiguous())
515+
} else {
516+
self.get_normal_space_args(name, true, permission_exec, VMRequest::discontiguous())
517+
}
518+
}
430519
}
431520

432521
impl<VM: VMBinding> BasePlan<VM> {
433522
#[allow(unused_mut)] // 'args' only needs to be mutable for certain features
434523
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> BasePlan<VM> {
524+
let _generational = args.constraints.generational;
435525
BasePlan {
436526
#[cfg(feature = "code_space")]
437-
code_space: ImmortalSpace::new(args.get_space_args(
527+
code_space: ImmortalSpace::new(args.get_base_space_args(
528+
_generational,
438529
"code_space",
439530
true,
440-
true,
441-
VMRequest::discontiguous(),
442531
)),
443532
#[cfg(feature = "code_space")]
444-
code_lo_space: ImmortalSpace::new(args.get_space_args(
533+
code_lo_space: ImmortalSpace::new(args.get_base_space_args(
534+
_generational,
445535
"code_lo_space",
446536
true,
447-
true,
448-
VMRequest::discontiguous(),
449537
)),
450538
#[cfg(feature = "ro_space")]
451-
ro_space: ImmortalSpace::new(args.get_space_args(
539+
ro_space: ImmortalSpace::new(args.get_base_space_args(
540+
_generational,
452541
"ro_space",
453-
true,
454542
false,
455-
VMRequest::discontiguous(),
456543
)),
457544
#[cfg(feature = "vm_space")]
458-
vm_space: VMSpace::new(args.get_space_args(
545+
vm_space: VMSpace::new(args.get_base_space_args(
546+
_generational,
459547
"vm_space",
460-
false,
461548
false, // it doesn't matter -- we are not mmapping for VM space.
462-
VMRequest::discontiguous(),
463549
)),
464550

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

606+
pub fn clear_side_log_bits(&self) {
607+
#[cfg(feature = "code_space")]
608+
self.code_space.clear_side_log_bits();
609+
#[cfg(feature = "code_space")]
610+
self.code_lo_space.clear_side_log_bits();
611+
#[cfg(feature = "ro_space")]
612+
self.ro_space.clear_side_log_bits();
613+
#[cfg(feature = "vm_space")]
614+
self.vm_space.clear_side_log_bits();
615+
}
616+
617+
pub fn set_side_log_bits(&self) {
618+
#[cfg(feature = "code_space")]
619+
self.code_space.set_side_log_bits();
620+
#[cfg(feature = "code_space")]
621+
self.code_lo_space.set_side_log_bits();
622+
#[cfg(feature = "ro_space")]
623+
self.ro_space.set_side_log_bits();
624+
#[cfg(feature = "vm_space")]
625+
self.vm_space.set_side_log_bits();
626+
}
627+
520628
pub fn end_of_gc(&mut self, _tls: VMWorkerThread) {
521629
// Do nothing here. None of the spaces needs end_of_gc.
522630
}
@@ -584,16 +692,19 @@ pub struct CommonPlan<VM: VMBinding> {
584692

585693
impl<VM: VMBinding> CommonPlan<VM> {
586694
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> CommonPlan<VM> {
695+
let needs_log_bit = args.constraints.needs_log_bit;
696+
let generational = args.constraints.generational;
587697
CommonPlan {
588-
immortal: ImmortalSpace::new(args.get_space_args(
589-
"immortal",
590-
true,
591-
false,
592-
VMRequest::discontiguous(),
593-
)),
698+
immortal: ImmortalSpace::new(args.get_common_space_args(generational, "immortal")),
594699
los: LargeObjectSpace::new(
595-
args.get_space_args("los", true, false, VMRequest::discontiguous()),
700+
// LOS is a bit special, as it is a mixed age space. It has a logical nursery.
701+
if generational {
702+
args.get_mixed_age_space_args("los", true, false, VMRequest::discontiguous())
703+
} else {
704+
args.get_normal_space_args("los", true, false, VMRequest::discontiguous())
705+
},
596706
false,
707+
needs_log_bit,
597708
),
598709
nonmoving: Self::new_nonmoving_space(&mut args),
599710
base: BasePlan::new(args),
@@ -621,6 +732,18 @@ impl<VM: VMBinding> CommonPlan<VM> {
621732
self.base.release(tls, full_heap)
622733
}
623734

735+
pub fn clear_side_log_bits(&self) {
736+
self.immortal.clear_side_log_bits();
737+
self.los.clear_side_log_bits();
738+
self.base.clear_side_log_bits();
739+
}
740+
741+
pub fn set_side_log_bits(&self) {
742+
self.immortal.set_side_log_bits();
743+
self.los.set_side_log_bits();
744+
self.base.set_side_log_bits();
745+
}
746+
624747
pub fn end_of_gc(&mut self, tls: VMWorkerThread) {
625748
self.end_of_gc_nonmoving_space();
626749
self.base.end_of_gc(tls);
@@ -639,7 +762,7 @@ impl<VM: VMBinding> CommonPlan<VM> {
639762
}
640763

641764
fn new_nonmoving_space(args: &mut CreateSpecificPlanArgs<VM>) -> NonMovingSpace<VM> {
642-
let space_args = args.get_space_args("nonmoving", true, false, VMRequest::discontiguous());
765+
let space_args = args.get_common_space_args(args.constraints.generational, "nonmoving");
643766
cfg_if::cfg_if! {
644767
if #[cfg(any(feature = "immortal_as_nonmoving", feature = "marksweep_as_nonmoving"))] {
645768
NonMovingSpace::new(space_args)
@@ -648,8 +771,6 @@ impl<VM: VMBinding> CommonPlan<VM> {
648771
NonMovingSpace::new(
649772
space_args,
650773
crate::policy::immix::ImmixSpaceArgs {
651-
unlog_object_when_traced: false,
652-
#[cfg(feature = "vo_bit")]
653774
mixed_age: false,
654775
never_move_objects: true,
655776
},

src/plan/immix/global.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,6 @@ impl<VM: VMBinding> Immix<VM> {
138138
Self::new_with_args(
139139
plan_args,
140140
ImmixSpaceArgs {
141-
unlog_object_when_traced: false,
142-
#[cfg(feature = "vo_bit")]
143141
mixed_age: false,
144142
never_move_objects: false,
145143
},
@@ -152,7 +150,21 @@ impl<VM: VMBinding> Immix<VM> {
152150
) -> Self {
153151
let immix = Immix {
154152
immix_space: ImmixSpace::new(
155-
plan_args.get_space_args("immix", true, false, VMRequest::discontiguous()),
153+
if space_args.mixed_age {
154+
plan_args.get_mixed_age_space_args(
155+
"immix",
156+
true,
157+
false,
158+
VMRequest::discontiguous(),
159+
)
160+
} else {
161+
plan_args.get_normal_space_args(
162+
"immix",
163+
true,
164+
false,
165+
VMRequest::discontiguous(),
166+
)
167+
},
156168
space_args,
157169
),
158170
common: CommonPlan::new(plan_args),

src/plan/markcompact/global.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl<VM: VMBinding> MarkCompact<VM> {
198198
global_side_metadata_specs,
199199
};
200200

201-
let mc_space = MarkCompactSpace::new(plan_args.get_space_args(
201+
let mc_space = MarkCompactSpace::new(plan_args.get_normal_space_args(
202202
"mc",
203203
true,
204204
false,

src/plan/marksweep/global.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl<VM: VMBinding> MarkSweep<VM> {
112112
};
113113

114114
let res = MarkSweep {
115-
ms: MarkSweepSpace::new(plan_args.get_space_args(
115+
ms: MarkSweepSpace::new(plan_args.get_normal_space_args(
116116
"ms",
117117
true,
118118
false,

0 commit comments

Comments
 (0)