Skip to content

Commit 61d20e2

Browse files
udesouqinsoonwks
authored
This PR enables transitively pinning (TP) objects from particular roots for Immix/StickyImmix (#897)
- A new bucket `ImmovableClosure` has been created to trace and transitively pin roots, i.e., roots in which no object in its transitive closure is allowed to move. - `RootsWorkFactory` has two new functions `create_process_tp_edge_roots_work` and `create_process_tp_node_roots_work` to create work to process these roots. - `GCWorkContext` expects an `TPProcessEdges` type, which performs the transitively pinning trace (and is unimplemented for unsupported plans). - `create_process_node_roots_work` creates work to process roots in the `NodeRootsTrace` bucket, which is executed after `TPClosure`, but any work derived from it is put into the regular `Closure` bucket, meaning that the binding shouldn't need to pin root nodes. - For sticky immix, currently we only support non-moving nursery collections (`sticky_immix_non_moving_nursery`), but the solution here is to use the `TPClosure` on the modified buffer constructed from the write barrier (since during nursery collection we do not know if these objects should be transitively pinned or not). --------- Co-authored-by: Yi Lin <qinsoon@gmail.com> Co-authored-by: Kunshan Wang <wks1986@gmail.com>
1 parent 62f1dc9 commit 61d20e2

File tree

29 files changed

+415
-158
lines changed

29 files changed

+415
-158
lines changed

.github/scripts/replace-mmtk-dep.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@
1919

2020
mmtk_node = toml_data["dependencies"]["mmtk"]
2121

22-
print("Deleting dependencies.mmtk.git")
23-
if "git" in mmtk_node:
24-
del mmtk_node["git"]
25-
22+
# These keys may specify the locations of the dependency. Remove them.
23+
for key in ["git", "branch", "version", "registry"]:
24+
if key in mmtk_node:
25+
print("Deleting dependencies.mmtk.{}".format(key))
26+
del mmtk_node[key]
27+
else:
28+
print("Key dependencies.mmtk.{} does not exist. Ignored.".format(key))
29+
30+
# Use mmtk-core from the specified local directory.
2631
mmtk_repo_path = os.path.realpath(args.mmtk_core_path)
2732
print("Setting dependencies.mmtk.path to {}".format(mmtk_repo_path))
2833
mmtk_node["path"] = mmtk_repo_path

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ object_pinning = []
105105
# Disable any object copying in Immix. This makes Immix a non-moving policy.
106106
immix_non_moving = []
107107

108+
# Disable any object copying in nursery GC for Sticky Immix while allowing other kinds of copying.
109+
# `immix_non_moving` disables all kinds of copying in Immix, so this feature is not needed
110+
# if `immix_non_moving` is in use.
111+
sticky_immix_non_moving_nursery = []
112+
113+
108114
# Reduce block size for ImmixSpace. This mitigates fragmentation when defrag is disabled.
109115
immix_smaller_block = []
110116
# Zero the unmarked lines after a GC cycle in immix. This helps debug untraced objects.

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// ANCHOR: imports
22
use super::global::MyGC;
3-
use crate::scheduler::gc_work::*;
3+
use crate::scheduler::{gc_work::*, WorkBucketStage};
44
use crate::vm::VMBinding;
55
use std::ops::{Deref, DerefMut};
66
// ANCHOR_END: imports
@@ -11,24 +11,26 @@ impl<VM: VMBinding> crate::scheduler::GCWorkContext for MyGCWorkContext<VM> {
1111
type VM = VM;
1212
type PlanType = MyGC<VM>;
1313
type ProcessEdgesWorkType = SFTProcessEdges<Self::VM>;
14+
type TPProcessEdges = UnsupportedProcessEdges<Self::VM>;
1415
}
1516
// ANCHOR_END: workcontext_sft
1617

1718
// ANCHOR: workcontext_plan
18-
use crate::scheduler::gc_work::PlanProcessEdges;
1919
use crate::policy::gc_work::DEFAULT_TRACE;
20+
use crate::scheduler::gc_work::PlanProcessEdges;
2021
pub struct MyGCWorkContext2<VM: VMBinding>(std::marker::PhantomData<VM>);
2122
impl<VM: VMBinding> crate::scheduler::GCWorkContext for MyGCWorkContext2<VM> {
2223
type VM = VM;
2324
type PlanType = MyGC<VM>;
2425
type ProcessEdgesWorkType = PlanProcessEdges<Self::VM, MyGC<VM>, DEFAULT_TRACE>;
26+
type TPProcessEdges = UnsupportedProcessEdges<Self::VM>;
2527
}
2628
// ANCHOR_END: workcontext_plan
2729

28-
use crate::util::ObjectReference;
30+
use crate::policy::space::Space;
2931
use crate::util::copy::CopySemantics;
32+
use crate::util::ObjectReference;
3033
use crate::MMTK;
31-
use crate::policy::space::Space;
3234

3335
// ANCHOR: mygc_process_edges
3436
pub struct MyGCProcessEdges<VM: VMBinding> {
@@ -38,12 +40,17 @@ pub struct MyGCProcessEdges<VM: VMBinding> {
3840
// ANCHOR_END: mygc_process_edges
3941

4042
// ANCHOR: mygc_process_edges_impl
41-
impl<VM:VMBinding> ProcessEdgesWork for MyGCProcessEdges<VM> {
43+
impl<VM: VMBinding> ProcessEdgesWork for MyGCProcessEdges<VM> {
4244
type VM = VM;
4345
type ScanObjectsWorkType = ScanObjects<Self>;
4446

45-
fn new(edges: Vec<EdgeOf<Self>>, roots: bool, mmtk: &'static MMTK<VM>) -> Self {
46-
let base = ProcessEdgesBase::new(edges, roots, mmtk);
47+
fn new(
48+
edges: Vec<EdgeOf<Self>>,
49+
roots: bool,
50+
mmtk: &'static MMTK<VM>,
51+
bucket: WorkBucketStage,
52+
) -> Self {
53+
let base = ProcessEdgesBase::new(edges, roots, mmtk, bucket);
4754
let plan = base.plan().downcast_ref::<MyGC<VM>>().unwrap();
4855
Self { base, plan }
4956
}
@@ -74,7 +81,7 @@ impl<VM:VMBinding> ProcessEdgesWork for MyGCProcessEdges<VM> {
7481
}
7582

7683
fn create_scan_work(&self, nodes: Vec<ObjectReference>, roots: bool) -> ScanObjects<Self> {
77-
ScanObjects::<Self>::new(nodes, false, roots)
84+
ScanObjects::<Self>::new(nodes, false, roots, self.bucket)
7885
}
7986
}
8087
// ANCHOR_END: mygc_process_edges_impl
@@ -100,5 +107,6 @@ impl<VM: VMBinding> crate::scheduler::GCWorkContext for MyGCWorkContext3<VM> {
100107
type VM = VM;
101108
type PlanType = MyGC<VM>;
102109
type ProcessEdgesWorkType = MyGCProcessEdges<Self::VM>;
110+
type TPProcessEdges = UnsupportedProcessEdges<Self::VM>;
103111
}
104112
// ANCHOR: workcontext_mygc

src/plan/generational/copying/gc_work.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ use crate::plan::generational::gc_work::GenNurseryProcessEdges;
33
use crate::vm::*;
44

55
use crate::policy::gc_work::DEFAULT_TRACE;
6-
use crate::scheduler::gc_work::PlanProcessEdges;
6+
use crate::scheduler::gc_work::{PlanProcessEdges, UnsupportedProcessEdges};
77

88
pub struct GenCopyNurseryGCWorkContext<VM: VMBinding>(std::marker::PhantomData<VM>);
99
impl<VM: VMBinding> crate::scheduler::GCWorkContext for GenCopyNurseryGCWorkContext<VM> {
1010
type VM = VM;
1111
type PlanType = GenCopy<VM>;
1212
type ProcessEdgesWorkType = GenNurseryProcessEdges<Self::VM, Self::PlanType>;
13+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
1314
}
1415

1516
pub struct GenCopyGCWorkContext<VM: VMBinding>(std::marker::PhantomData<VM>);
1617
impl<VM: VMBinding> crate::scheduler::GCWorkContext for GenCopyGCWorkContext<VM> {
1718
type VM = VM;
1819
type PlanType = GenCopy<VM>;
1920
type ProcessEdgesWorkType = PlanProcessEdges<Self::VM, GenCopy<VM>, DEFAULT_TRACE>;
21+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
2022
}

src/plan/generational/gc_work.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use atomic::Ordering;
22

33
use crate::plan::PlanTraceObject;
4-
use crate::scheduler::{gc_work::*, GCWork, GCWorker};
4+
use crate::scheduler::{gc_work::*, GCWork, GCWorker, WorkBucketStage};
55
use crate::util::ObjectReference;
66
use crate::vm::edge_shape::{Edge, MemorySlice};
77
use crate::vm::*;
@@ -25,8 +25,13 @@ impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>> ProcessEdg
2525
type VM = VM;
2626
type ScanObjectsWorkType = PlanScanObjects<Self, P>;
2727

28-
fn new(edges: Vec<EdgeOf<Self>>, roots: bool, mmtk: &'static MMTK<VM>) -> Self {
29-
let base = ProcessEdgesBase::new(edges, roots, mmtk);
28+
fn new(
29+
edges: Vec<EdgeOf<Self>>,
30+
roots: bool,
31+
mmtk: &'static MMTK<VM>,
32+
bucket: WorkBucketStage,
33+
) -> Self {
34+
let base = ProcessEdgesBase::new(edges, roots, mmtk, bucket);
3035
let plan = base.plan().downcast_ref().unwrap();
3136
Self { plan, base }
3237
}
@@ -51,7 +56,7 @@ impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>> ProcessEdg
5156
nodes: Vec<ObjectReference>,
5257
roots: bool,
5358
) -> Self::ScanObjectsWorkType {
54-
PlanScanObjects::new(self.plan, nodes, false, roots)
59+
PlanScanObjects::new(self.plan, nodes, false, roots, self.bucket)
5560
}
5661
}
5762

@@ -111,7 +116,7 @@ impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessModBuf<E> {
111116
// Scan objects in the modbuf and forward pointers
112117
let modbuf = std::mem::take(&mut self.modbuf);
113118
GCWork::do_work(
114-
&mut ScanObjects::<E>::new(modbuf, false, false),
119+
&mut ScanObjects::<E>::new(modbuf, false, false, WorkBucketStage::Closure),
115120
worker,
116121
mmtk,
117122
)
@@ -154,7 +159,11 @@ impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessRegionModBuf<E> {
154159
}
155160
}
156161
// Forward entries
157-
GCWork::do_work(&mut E::new(edges, false, mmtk), worker, mmtk)
162+
GCWork::do_work(
163+
&mut E::new(edges, false, mmtk, WorkBucketStage::Closure),
164+
worker,
165+
mmtk,
166+
)
158167
}
159168
}
160169
}

src/plan/generational/immix/gc_work.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use super::global::GenImmix;
22
use crate::plan::generational::gc_work::GenNurseryProcessEdges;
33
use crate::policy::gc_work::TraceKind;
44
use crate::scheduler::gc_work::PlanProcessEdges;
5+
use crate::scheduler::gc_work::UnsupportedProcessEdges;
56
use crate::vm::VMBinding;
67

78
pub struct GenImmixNurseryGCWorkContext<VM: VMBinding>(std::marker::PhantomData<VM>);
89
impl<VM: VMBinding> crate::scheduler::GCWorkContext for GenImmixNurseryGCWorkContext<VM> {
910
type VM = VM;
1011
type PlanType = GenImmix<VM>;
1112
type ProcessEdgesWorkType = GenNurseryProcessEdges<VM, Self::PlanType>;
13+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
1214
}
1315

1416
pub(super) struct GenImmixMatureGCWorkContext<VM: VMBinding, const KIND: TraceKind>(
@@ -20,4 +22,5 @@ impl<VM: VMBinding, const KIND: TraceKind> crate::scheduler::GCWorkContext
2022
type VM = VM;
2123
type PlanType = GenImmix<VM>;
2224
type ProcessEdgesWorkType = PlanProcessEdges<VM, GenImmix<VM>, KIND>;
25+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
2326
}

src/plan/immix/gc_work.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::global::Immix;
22
use crate::policy::gc_work::TraceKind;
3+
use crate::policy::gc_work::TRACE_KIND_TRANSITIVE_PIN;
34
use crate::scheduler::gc_work::PlanProcessEdges;
45
use crate::vm::VMBinding;
56

@@ -12,4 +13,5 @@ impl<VM: VMBinding, const KIND: TraceKind> crate::scheduler::GCWorkContext
1213
type VM = VM;
1314
type PlanType = Immix<VM>;
1415
type ProcessEdgesWorkType = PlanProcessEdges<VM, Immix<VM>, KIND>;
16+
type TPProcessEdges = PlanProcessEdges<VM, Immix<VM>, TRACE_KIND_TRANSITIVE_PIN>;
1517
}

src/plan/immix/global.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ impl<VM: VMBinding> Immix<VM> {
157157
/// to schedule a full heap collection. A plan must call set_collection_kind and set_gc_status before this method.
158158
pub(crate) fn schedule_immix_full_heap_collection<
159159
PlanType: Plan<VM = VM>,
160-
FastContext: 'static + GCWorkContext<VM = VM, PlanType = PlanType>,
161-
DefragContext: 'static + GCWorkContext<VM = VM, PlanType = PlanType>,
160+
FastContext: GCWorkContext<VM = VM, PlanType = PlanType>,
161+
DefragContext: GCWorkContext<VM = VM, PlanType = PlanType>,
162162
>(
163163
plan: &'static DefragContext::PlanType,
164164
immix_space: &ImmixSpace<VM>,

src/plan/markcompact/gc_work.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ impl<VM: VMBinding> GCWork<VM> for UpdateReferences<VM> {
5757
.get_and_clear_worker_live_bytes();
5858

5959
for mutator in VM::VMActivePlan::mutators() {
60-
mmtk.scheduler.work_buckets[WorkBucketStage::SecondRoots]
61-
.add(ScanMutatorRoots::<ForwardingProcessEdges<VM>>(mutator));
60+
mmtk.scheduler.work_buckets[WorkBucketStage::SecondRoots].add(ScanMutatorRoots::<
61+
MarkCompactForwardingGCWorkContext<VM>,
62+
>(mutator));
6263
}
6364

6465
mmtk.scheduler.work_buckets[WorkBucketStage::SecondRoots]
65-
.add(ScanVMSpecificRoots::<ForwardingProcessEdges<VM>>::new());
66+
.add(ScanVMSpecificRoots::<MarkCompactForwardingGCWorkContext<VM>>::new());
6667
}
6768
}
6869

@@ -102,4 +103,13 @@ impl<VM: VMBinding> crate::scheduler::GCWorkContext for MarkCompactGCWorkContext
102103
type VM = VM;
103104
type PlanType = MarkCompact<VM>;
104105
type ProcessEdgesWorkType = MarkingProcessEdges<VM>;
106+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
107+
}
108+
109+
pub struct MarkCompactForwardingGCWorkContext<VM: VMBinding>(std::marker::PhantomData<VM>);
110+
impl<VM: VMBinding> crate::scheduler::GCWorkContext for MarkCompactForwardingGCWorkContext<VM> {
111+
type VM = VM;
112+
type PlanType = MarkCompact<VM>;
113+
type ProcessEdgesWorkType = ForwardingProcessEdges<VM>;
114+
type TPProcessEdges = UnsupportedProcessEdges<VM>;
105115
}

src/plan/markcompact/global.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<VM: VMBinding> Plan for MarkCompact<VM> {
9292

9393
// Stop & scan mutators (mutator scanning can happen before STW)
9494
scheduler.work_buckets[WorkBucketStage::Unconstrained]
95-
.add(StopMutators::<MarkingProcessEdges<VM>>::new());
95+
.add(StopMutators::<MarkCompactGCWorkContext<VM>>::new());
9696

9797
// Prepare global/collectors/mutators
9898
scheduler.work_buckets[WorkBucketStage::Prepare]

0 commit comments

Comments
 (0)