Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
230fcdf
Get ReferenceProcessor work
qinsoon Mar 15, 2022
63e1fda
No need to set referent when a reference is added
qinsoon Mar 15, 2022
3589cfe
Fix Immix post copy
qinsoon Mar 15, 2022
9373a71
Add post_copy for ImmixCopyContext: mark object and line
qinsoon Mar 16, 2022
ea23295
Cargo fmt
qinsoon Mar 16, 2022
40bcb3e
Merge branch 'immix-post-copy' into reference-processor
qinsoon Mar 16, 2022
e0484d0
Add reference processing work for MarkCompact. Add SecondRoots bucket.
qinsoon Mar 20, 2022
32dad45
Fix mark compact
qinsoon Mar 21, 2022
f47e85b
Enqueue references in Release stage
qinsoon Mar 21, 2022
c4374d1
Add reference processing work for MarkCompact. Add SecondRoots bucket.
qinsoon Mar 20, 2022
d60b2c1
Fix mark compact
qinsoon Mar 21, 2022
ea0f19e
cargo fmt
qinsoon Mar 21, 2022
89b07f4
Properly deactivate buckets
qinsoon Mar 21, 2022
8863a9c
Merge branch 'mark-compact-object-ref' into reference-processor
qinsoon Mar 21, 2022
722546b
Bulk enqueue references
qinsoon Mar 21, 2022
a55db73
* needs_forward_after_liveness for RefForwarding
qinsoon Mar 22, 2022
4ba3ed2
Merge branch 'master' into reference-processor
qinsoon Mar 22, 2022
40e2152
Massive code clean up for reference processor. Do proper nursery
qinsoon Mar 24, 2022
dde48d1
Fix build/style
qinsoon Mar 24, 2022
88bbc64
Add some assertions in enqueue.
qinsoon Mar 25, 2022
612ee33
No longer accept new candidates when we start scanning
qinsoon Mar 25, 2022
4024354
No longer accept weak ref candidates after forwarding.
qinsoon Mar 28, 2022
3d29846
Use HasSet for the reference table.
qinsoon Mar 29, 2022
4fd8469
Provide get_options
qinsoon Apr 5, 2022
a90ab0f
Merge branch 'master' into reference-processor
qinsoon Apr 5, 2022
03fb2d3
Add tls to enqueue_reference()
qinsoon Apr 6, 2022
1767b52
Set the default for no_reference_types to true. Adding weak candidates
qinsoon Apr 6, 2022
5ef5afc
Rename ProcessWeakRefs to VMProcessWeakRefs
qinsoon Apr 7, 2022
065377b
Separate retain from scan. process_reference returns Option.
qinsoon Apr 8, 2022
4715b64
Merge branch 'master' into reference-processor
qinsoon Apr 27, 2022
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
6 changes: 3 additions & 3 deletions examples/mmtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ extern void* mmtk_starting_heap_address();
extern void* mmtk_last_heap_address();

// Add a reference to the list of weak references
extern void mmtk_add_weak_candidate(void* ref, void* referent);
extern void mmtk_add_weak_candidate(void* ref);

// Add a reference to the list of soft references
extern void mmtk_add_soft_candidate(void* ref, void* referent);
extern void mmtk_add_soft_candidate(void* ref);

// Add a reference to the list of phantom references
extern void mmtk_add_phantom_candidate(void* ref, void* referent);
extern void mmtk_add_phantom_candidate(void* ref);

// Generic hook to allow benchmarks to be harnessed
extern void mmtk_harness_begin(void* tls);
Expand Down
39 changes: 12 additions & 27 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,49 +416,34 @@ pub fn modify_check<VM: VMBinding>(mmtk: &MMTK<VM>, object: ObjectReference) {
mmtk.plan.modify_check(object);
}

/// Add a reference to the list of weak references.
/// Add a reference to the list of weak references. A binding may
/// call this either when a weak reference is created, or when a weak reference is traced during GC.
///
/// Arguments:
/// * `mmtk`: A reference to an MMTk instance.
/// * `reff`: The weak reference to add.
/// * `referent`: The object that the reference points to.
pub fn add_weak_candidate<VM: VMBinding>(
mmtk: &MMTK<VM>,
reff: ObjectReference,
referent: ObjectReference,
) {
mmtk.reference_processors
.add_weak_candidate::<VM>(reff, referent);
pub fn add_weak_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
mmtk.reference_processors.add_weak_candidate::<VM>(reff);
}

/// Add a reference to the list of soft references.
/// Add a reference to the list of soft references. A binding may
/// call this either when a weak reference is created, or when a weak reference is traced during GC.
///
/// Arguments:
/// * `mmtk`: A reference to an MMTk instance.
/// * `reff`: The soft reference to add.
/// * `referent`: The object that the reference points to.
pub fn add_soft_candidate<VM: VMBinding>(
mmtk: &MMTK<VM>,
reff: ObjectReference,
referent: ObjectReference,
) {
mmtk.reference_processors
.add_soft_candidate::<VM>(reff, referent);
pub fn add_soft_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
mmtk.reference_processors.add_soft_candidate::<VM>(reff);
}

/// Add a reference to the list of phantom references.
/// Add a reference to the list of phantom references. A binding may
/// call this either when a weak reference is created, or when a weak reference is traced during GC.
///
/// Arguments:
/// * `mmtk`: A reference to an MMTk instance.
/// * `reff`: The phantom reference to add.
/// * `referent`: The object that the reference points to.
pub fn add_phantom_candidate<VM: VMBinding>(
mmtk: &MMTK<VM>,
reff: ObjectReference,
referent: ObjectReference,
) {
mmtk.reference_processors
.add_phantom_candidate::<VM>(reff, referent);
pub fn add_phantom_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
mmtk.reference_processors.add_phantom_candidate::<VM>(reff);
}

/// Generic hook to allow benchmarks to be harnessed. We do a full heap
Expand Down
5 changes: 5 additions & 0 deletions src/mmtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ impl<VM: VMBinding> MMTK<VM> {
pub fn get_plan(&self) -> &dyn Plan<VM = VM> {
self.plan.as_ref()
}

#[inline(always)]
pub fn get_options(&self) -> &Options {
&self.options
}
}

impl<VM: VMBinding> Default for MMTK<VM> {
Expand Down
32 changes: 26 additions & 6 deletions src/plan/markcompact/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ impl<VM: VMBinding> Plan for MarkCompact<VM> {
scheduler.work_buckets[WorkBucketStage::Prepare]
.add(Prepare::<MarkCompactGCWorkContext<VM>>::new(self));

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

scheduler.work_buckets[WorkBucketStage::CalculateForwarding]
.add(CalculateForwardingAddress::<VM>::new(&self.mc_space));
// do another trace to update references
Expand All @@ -111,17 +107,41 @@ impl<VM: VMBinding> Plan for MarkCompact<VM> {
scheduler.work_buckets[WorkBucketStage::Release]
.add(Release::<MarkCompactGCWorkContext<VM>>::new(self));

// Reference processing
if !*self.base().options.no_reference_types {
use crate::util::reference_processor::{
PhantomRefProcessing, SoftRefProcessing, WeakRefProcessing,
};
scheduler.work_buckets[WorkBucketStage::SoftRefClosure]
.add(SoftRefProcessing::<MarkingProcessEdges<VM>>::new());
scheduler.work_buckets[WorkBucketStage::WeakRefClosure]
.add(WeakRefProcessing::<MarkingProcessEdges<VM>>::new());
scheduler.work_buckets[WorkBucketStage::PhantomRefClosure]
.add(PhantomRefProcessing::<MarkingProcessEdges<VM>>::new());

// VM-specific weak ref processing
scheduler.work_buckets[WorkBucketStage::WeakRefClosure]
.add(VMProcessWeakRefs::<MarkingProcessEdges<VM>>::new());

use crate::util::reference_processor::RefForwarding;
scheduler.work_buckets[WorkBucketStage::RefForwarding]
.add(RefForwarding::<ForwardingProcessEdges<VM>>::new());

use crate::util::reference_processor::RefEnqueue;
scheduler.work_buckets[WorkBucketStage::Release].add(RefEnqueue::<VM>::new());
}

// Finalization
if !*self.base().options.no_finalizer {
use crate::util::finalizable_processor::{Finalization, ForwardFinalization};
// finalization
// treat finalizable objects as roots and perform a closure (marking)
// must be done before calculating forwarding pointers
scheduler.work_buckets[WorkBucketStage::RefClosure]
scheduler.work_buckets[WorkBucketStage::FinalRefClosure]
.add(Finalization::<MarkingProcessEdges<VM>>::new());
// update finalizable object references
// must be done before compacting
scheduler.work_buckets[WorkBucketStage::RefForwarding]
scheduler.work_buckets[WorkBucketStage::FinalizableForwarding]
.add(ForwardFinalization::<ForwardingProcessEdges<VM>>::new());
}

Expand Down
2 changes: 2 additions & 0 deletions src/plan/plan_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct PlanConstraints {
pub needs_linear_scan: bool,
pub needs_concurrent_workers: bool,
pub generate_gc_trace: bool,
/// Some policies do object forwarding after the first liveness transitive closure, such as mark compact.
/// For plans that use those policies, they should set this as true.
pub needs_forward_after_liveness: bool,
}

Expand Down
15 changes: 10 additions & 5 deletions src/scheduler/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ impl<C: GCWorkContext + 'static> GCWork<C::VM> for Release<C> {
for w in &mmtk.scheduler.workers_shared {
w.local_work_bucket.add(ReleaseCollector);
}
// TODO: Process weak references properly
mmtk.reference_processors.clear();
}
}

Expand Down Expand Up @@ -250,15 +248,15 @@ impl<VM: VMBinding> CoordinatorWork<VM> for EndOfGC {}
/// processing of those weakrefs may be more complex. For such case, we delegate to the
/// VM binding to process weak references.
#[derive(Default)]
pub struct ProcessWeakRefs<E: ProcessEdgesWork>(PhantomData<E>);
pub struct VMProcessWeakRefs<E: ProcessEdgesWork>(PhantomData<E>);

impl<E: ProcessEdgesWork> ProcessWeakRefs<E> {
impl<E: ProcessEdgesWork> VMProcessWeakRefs<E> {
pub fn new() -> Self {
Self(PhantomData)
}
}

impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessWeakRefs<E> {
impl<E: ProcessEdgesWork> GCWork<E::VM> for VMProcessWeakRefs<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, _mmtk: &'static MMTK<E::VM>) {
trace!("ProcessWeakRefs");
<E::VM as VMBinding>::VMCollection::process_weak_refs::<E>(worker);
Expand Down Expand Up @@ -384,6 +382,13 @@ impl<VM: VMBinding> ProcessEdgesBase<VM> {
}

/// Scan & update a list of object slots
//
// Note: be very careful when using this trait. process_node() will push objects
// to the buffer, and it is expected that at the end of the operation, flush()
// is called to create new scan work from the buffered objects. If flush()
// is not called, we may miss the objects in the GC and have dangling pointers.
// FIXME: We possibly want to enforce Drop on this trait, and require calling
// flush() in Drop.
pub trait ProcessEdgesWork:
Send + 'static + Sized + DerefMut + Deref<Target = ProcessEdgesBase<Self::VM>>
{
Expand Down
48 changes: 39 additions & 9 deletions src/scheduler/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ impl<VM: VMBinding> GCWorkScheduler<VM> {
WorkBucketStage::Unconstrained => WorkBucket::new(true, worker_monitor.clone()),
WorkBucketStage::Prepare => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::Closure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::RefClosure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::SoftRefClosure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::WeakRefClosure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::FinalRefClosure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::PhantomRefClosure => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::CalculateForwarding => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::SecondRoots => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::RefForwarding => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::FinalizableForwarding => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::Compact => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::Release => WorkBucket::new(false, worker_monitor.clone()),
WorkBucketStage::Final => WorkBucket::new(false, worker_monitor.clone()),
Expand All @@ -78,7 +82,7 @@ impl<VM: VMBinding> GCWorkScheduler<VM> {
let should_open = scheduler.are_buckets_drained(&cur_stages)
&& scheduler.all_workers_parked();
// Additional check before the `RefClosure` bucket opens.
if should_open && s == WorkBucketStage::RefClosure {
if should_open && s == crate::scheduler::work_bucket::LAST_CLOSURE_BUCKET {
if let Some(closure_end) = scheduler.closure_end.lock().unwrap().as_ref() {
if closure_end() {
// Don't open `RefClosure` if `closure_end` added more works to `Closure`.
Expand All @@ -92,10 +96,14 @@ impl<VM: VMBinding> GCWorkScheduler<VM> {
};

open_next(Closure);
open_next(RefClosure);
open_next(SoftRefClosure);
open_next(WeakRefClosure);
open_next(FinalRefClosure);
open_next(PhantomRefClosure);
open_next(CalculateForwarding);
open_next(SecondRoots);
open_next(RefForwarding);
open_next(FinalizableForwarding);
open_next(Compact);
open_next(Release);
open_next(Final);
Expand Down Expand Up @@ -183,10 +191,6 @@ impl<VM: VMBinding> GCWorkScheduler<VM> {
// Prepare global/collectors/mutators
self.work_buckets[WorkBucketStage::Prepare].add(Prepare::<C>::new(plan));

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

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

Expand All @@ -205,15 +209,41 @@ impl<VM: VMBinding> GCWorkScheduler<VM> {
.add(ScheduleSanityGC::<C::PlanType>::new(plan));
}

// Reference processing
if !*plan.base().options.no_reference_types {
use crate::util::reference_processor::{
PhantomRefProcessing, SoftRefProcessing, WeakRefProcessing,
};
self.work_buckets[WorkBucketStage::SoftRefClosure]
.add(SoftRefProcessing::<C::ProcessEdgesWorkType>::new());
self.work_buckets[WorkBucketStage::WeakRefClosure]
.add(WeakRefProcessing::<C::ProcessEdgesWorkType>::new());
self.work_buckets[WorkBucketStage::PhantomRefClosure]
.add(PhantomRefProcessing::<C::ProcessEdgesWorkType>::new());

// VM-specific weak ref processing
self.work_buckets[WorkBucketStage::WeakRefClosure]
.add(VMProcessWeakRefs::<C::ProcessEdgesWorkType>::new());

use crate::util::reference_processor::RefForwarding;
if plan.constraints().needs_forward_after_liveness {
self.work_buckets[WorkBucketStage::RefForwarding]
.add(RefForwarding::<C::ProcessEdgesWorkType>::new());
}

use crate::util::reference_processor::RefEnqueue;
self.work_buckets[WorkBucketStage::Release].add(RefEnqueue::<VM>::new());
}

// Finalization
if !*plan.base().options.no_finalizer {
use crate::util::finalizable_processor::{Finalization, ForwardFinalization};
// finalization
self.work_buckets[WorkBucketStage::RefClosure]
self.work_buckets[WorkBucketStage::FinalRefClosure]
.add(Finalization::<C::ProcessEdgesWorkType>::new());
// forward refs
if plan.constraints().needs_forward_after_liveness {
self.work_buckets[WorkBucketStage::RefForwarding]
self.work_buckets[WorkBucketStage::FinalizableForwarding]
.add(ForwardFinalization::<C::ProcessEdgesWorkType>::new());
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/scheduler/work_bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,17 @@ pub enum WorkBucketStage {
Unconstrained,
Prepare,
Closure,
// TODO: We only support final reference at the moment. If we have references of multiple strengths,
// we may need more than one buckets for each reference strength.
RefClosure,
SoftRefClosure,
WeakRefClosure,
FinalRefClosure,
PhantomRefClosure,
CalculateForwarding,
SecondRoots,
RefForwarding,
FinalizableForwarding,
Compact,
Release,
Final,
}

pub const LAST_CLOSURE_BUCKET: WorkBucketStage = WorkBucketStage::PhantomRefClosure;
2 changes: 2 additions & 0 deletions src/util/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ mod tests {
pub struct ObjectReference(usize);

impl ObjectReference {
pub const NULL: ObjectReference = ObjectReference(0);

/// converts the ObjectReference to an Address
#[inline(always)]
pub fn to_address(self) -> Address {
Expand Down
6 changes: 5 additions & 1 deletion src/util/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,11 @@ options! {
// Should finalization be disabled?
no_finalizer: bool [env_var: true, command_line: true] [always_valid] = false,
// Should reference type processing be disabled?
no_reference_types: bool [env_var: true, command_line: true] [always_valid] = false,
// If reference type processing is disabled, no weak reference processing work is scheduled,
// and we expect a binding to treat weak references as strong references.
// We disable weak reference processing by default, as we are still working on it. This will be changed to `false`
// once weak reference processing is implemented properly.
no_reference_types: bool [env_var: true, command_line: true] [always_valid] = true,
// The zeroing approach to use for new object allocations. Affects each plan differently. (not supported)
nursery_zeroing: NurseryZeroingOptions[env_var: true, command_line: true] [always_valid] = NurseryZeroingOptions::Temporal,
// How frequent (every X bytes) should we do a stress GC?
Expand Down
Loading