Skip to content

Commit 093da76

Browse files
authored
Add Immix GC (#382)
1 parent 1b481f7 commit 093da76

File tree

24 files changed

+2419
-12
lines changed

24 files changed

+2419
-12
lines changed

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#![feature(trait_alias)]
1515
#![feature(const_panic)]
1616
#![feature(const_fn_union)]
17+
#![feature(step_trait)]
18+
#![feature(step_trait_ext)]
19+
#![feature(const_generics)]
1720
// TODO: We should fix missing docs for public items and turn this on (Issue #309).
1821
// #![deny(missing_docs)]
1922

src/mmtk.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ impl<VM: VMBinding> MMTK<VM> {
5353
pub fn new() -> Self {
5454
let scheduler = MMTkScheduler::new();
5555
let options = Arc::new(UnsafeOptionsWrapper::new(Options::default()));
56-
let plan = crate::plan::create_plan(options.plan, &VM_MAP, &MMAPPER, options.clone());
56+
let plan = crate::plan::create_plan(
57+
options.plan,
58+
&VM_MAP,
59+
&MMAPPER,
60+
options.clone(),
61+
scheduler.clone(),
62+
);
5763
MMTK {
5864
plan,
5965
reference_processors: ReferenceProcessors::new(),

src/plan/global.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub fn create_mutator<VM: VMBinding>(
126126
PlanSelector::MarkSweep => {
127127
crate::plan::marksweep::mutator::create_ms_mutator(tls, &*mmtk.plan)
128128
}
129+
PlanSelector::Immix => crate::plan::immix::mutator::create_immix_mutator(tls, &*mmtk.plan),
129130
PlanSelector::PageProtect => {
130131
crate::plan::pageprotect::mutator::create_pp_mutator(tls, &*mmtk.plan)
131132
}
@@ -137,6 +138,7 @@ pub fn create_plan<VM: VMBinding>(
137138
vm_map: &'static VMMap,
138139
mmapper: &'static Mmapper,
139140
options: Arc<UnsafeOptionsWrapper>,
141+
scheduler: Arc<MMTkScheduler<VM>>,
140142
) -> Box<dyn Plan<VM = VM>> {
141143
match plan {
142144
PlanSelector::NoGC => Box::new(crate::plan::nogc::NoGC::new(vm_map, mmapper, options)),
@@ -149,6 +151,9 @@ pub fn create_plan<VM: VMBinding>(
149151
PlanSelector::MarkSweep => Box::new(crate::plan::marksweep::MarkSweep::new(
150152
vm_map, mmapper, options,
151153
)),
154+
PlanSelector::Immix => Box::new(crate::plan::immix::Immix::new(
155+
vm_map, mmapper, options, scheduler,
156+
)),
152157
PlanSelector::PageProtect => Box::new(crate::plan::pageprotect::PageProtect::new(
153158
vm_map, mmapper, options,
154159
)),
@@ -649,7 +654,7 @@ impl<VM: VMBinding> BasePlan<VM> {
649654
*self.gc_status.lock().unwrap() == GcStatus::GcProper
650655
}
651656

652-
fn is_user_triggered_collection(&self) -> bool {
657+
pub fn is_user_triggered_collection(&self) -> bool {
653658
self.user_triggered_collection.load(Ordering::Relaxed)
654659
}
655660

src/plan/immix/gc_work.rs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
use super::global::Immix;
2+
use crate::plan::PlanConstraints;
3+
use crate::policy::immix::ScanObjectsAndMarkLines;
4+
use crate::policy::space::Space;
5+
use crate::scheduler::gc_work::*;
6+
use crate::scheduler::{WorkBucketStage, WorkerLocal};
7+
use crate::util::alloc::{Allocator, ImmixAllocator};
8+
use crate::util::object_forwarding;
9+
use crate::util::{Address, ObjectReference};
10+
use crate::vm::VMBinding;
11+
use crate::MMTK;
12+
use crate::{
13+
plan::CopyContext,
14+
util::opaque_pointer::{VMThread, VMWorkerThread},
15+
};
16+
use std::{
17+
mem,
18+
ops::{Deref, DerefMut},
19+
};
20+
21+
/// Immix copy allocator
22+
pub struct ImmixCopyContext<VM: VMBinding> {
23+
immix: ImmixAllocator<VM>,
24+
}
25+
26+
impl<VM: VMBinding> CopyContext for ImmixCopyContext<VM> {
27+
type VM = VM;
28+
29+
fn constraints(&self) -> &'static PlanConstraints {
30+
&super::global::IMMIX_CONSTRAINTS
31+
}
32+
fn init(&mut self, tls: VMWorkerThread) {
33+
self.immix.tls = tls.0;
34+
}
35+
fn prepare(&mut self) {
36+
self.immix.reset()
37+
}
38+
fn release(&mut self) {
39+
self.immix.reset()
40+
}
41+
#[inline(always)]
42+
fn alloc_copy(
43+
&mut self,
44+
_original: ObjectReference,
45+
bytes: usize,
46+
align: usize,
47+
offset: isize,
48+
_semantics: crate::AllocationSemantics,
49+
) -> Address {
50+
self.immix.alloc(bytes, align, offset)
51+
}
52+
#[inline(always)]
53+
fn post_copy(
54+
&mut self,
55+
obj: ObjectReference,
56+
_tib: Address,
57+
_bytes: usize,
58+
_semantics: crate::AllocationSemantics,
59+
) {
60+
object_forwarding::clear_forwarding_bits::<VM>(obj);
61+
}
62+
}
63+
64+
impl<VM: VMBinding> ImmixCopyContext<VM> {
65+
pub fn new(mmtk: &'static MMTK<VM>) -> Self {
66+
Self {
67+
immix: ImmixAllocator::new(
68+
VMThread::UNINITIALIZED,
69+
Some(&mmtk.plan.downcast_ref::<Immix<VM>>().unwrap().immix_space),
70+
&*mmtk.plan,
71+
true,
72+
),
73+
}
74+
}
75+
}
76+
77+
impl<VM: VMBinding> WorkerLocal for ImmixCopyContext<VM> {
78+
fn init(&mut self, tls: VMWorkerThread) {
79+
CopyContext::init(self, tls);
80+
}
81+
}
82+
83+
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
84+
pub(super) enum TraceKind {
85+
Fast,
86+
Defrag,
87+
}
88+
89+
pub(super) struct ImmixProcessEdges<VM: VMBinding, const KIND: TraceKind> {
90+
// Use a static ref to the specific plan to avoid overhead from dynamic dispatch or
91+
// downcast for each traced object.
92+
plan: &'static Immix<VM>,
93+
base: ProcessEdgesBase<Self>,
94+
mmtk: &'static MMTK<VM>,
95+
}
96+
97+
impl<VM: VMBinding, const KIND: TraceKind> ImmixProcessEdges<VM, KIND> {
98+
fn immix(&self) -> &'static Immix<VM> {
99+
self.plan
100+
}
101+
102+
#[inline(always)]
103+
fn fast_trace_object(&mut self, object: ObjectReference) -> ObjectReference {
104+
if object.is_null() {
105+
return object;
106+
}
107+
if self.immix().immix_space.in_space(object) {
108+
self.immix().immix_space.fast_trace_object(self, object)
109+
} else {
110+
self.immix()
111+
.common
112+
.trace_object::<Self, ImmixCopyContext<VM>>(self, object)
113+
}
114+
}
115+
116+
/// Trace objects without evacuation.
117+
#[inline(always)]
118+
fn fast_process_edge(&mut self, slot: Address) {
119+
let object = unsafe { slot.load::<ObjectReference>() };
120+
self.fast_trace_object(object);
121+
}
122+
}
123+
124+
impl<VM: VMBinding, const KIND: TraceKind> ProcessEdgesWork for ImmixProcessEdges<VM, KIND> {
125+
type VM = VM;
126+
const OVERWRITE_REFERENCE: bool = crate::policy::immix::DEFRAG;
127+
128+
fn new(edges: Vec<Address>, _roots: bool, mmtk: &'static MMTK<VM>) -> Self {
129+
let base = ProcessEdgesBase::new(edges, mmtk);
130+
let plan = base.plan().downcast_ref::<Immix<VM>>().unwrap();
131+
Self { plan, base, mmtk }
132+
}
133+
134+
#[cold]
135+
fn flush(&mut self) {
136+
let mut new_nodes = vec![];
137+
mem::swap(&mut new_nodes, &mut self.nodes);
138+
let scan_objects_work =
139+
ScanObjectsAndMarkLines::<Self>::new(new_nodes, false, &self.immix().immix_space);
140+
if Self::SCAN_OBJECTS_IMMEDIATELY {
141+
self.worker().do_work(scan_objects_work);
142+
} else {
143+
self.mmtk.scheduler.work_buckets[WorkBucketStage::Closure].add(scan_objects_work);
144+
}
145+
}
146+
147+
/// Trace and evacuate objects.
148+
#[inline(always)]
149+
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
150+
if object.is_null() {
151+
return object;
152+
}
153+
if self.immix().immix_space.in_space(object) {
154+
self.immix().immix_space.trace_object(
155+
self,
156+
object,
157+
super::global::ALLOC_IMMIX,
158+
unsafe { self.worker().local::<ImmixCopyContext<VM>>() },
159+
)
160+
} else {
161+
self.immix()
162+
.common
163+
.trace_object::<Self, ImmixCopyContext<VM>>(self, object)
164+
}
165+
}
166+
167+
#[inline]
168+
fn process_edges(&mut self) {
169+
if KIND == TraceKind::Fast {
170+
for i in 0..self.edges.len() {
171+
// Use fast_process_edge since we don't need to forward any objects.
172+
self.fast_process_edge(self.edges[i])
173+
}
174+
} else {
175+
for i in 0..self.edges.len() {
176+
self.process_edge(self.edges[i])
177+
}
178+
}
179+
}
180+
}
181+
182+
impl<VM: VMBinding, const KIND: TraceKind> Deref for ImmixProcessEdges<VM, KIND> {
183+
type Target = ProcessEdgesBase<Self>;
184+
#[inline]
185+
fn deref(&self) -> &Self::Target {
186+
&self.base
187+
}
188+
}
189+
190+
impl<VM: VMBinding, const KIND: TraceKind> DerefMut for ImmixProcessEdges<VM, KIND> {
191+
#[inline]
192+
fn deref_mut(&mut self) -> &mut Self::Target {
193+
&mut self.base
194+
}
195+
}

0 commit comments

Comments
 (0)