Skip to content

Commit 0babba2

Browse files
authored
Split the TransitiveClosure trait (#566)
* Split the TransitiveClosure trait Moved the `process_edge` function of the `TransitiveClosure` trait into a dedicated trait `EdgeVisitor` for visiting edges of an object (or stack roots). As a result, 1. VM bindings only require the `EdgeVisitor` trait for object scanning. VM bindings no longer use the `TransitiveClosure` in any way. 2. Now `TransitiveClosure` only serves one purpose in `mmtk-core`, i.e. as a super-trait of ProcessEdgesWork for the `process_node` method. It is only called by `trace_object` of different spaces. With this change, it will be easy to refactor `trace_object` and remove `TransitiveClosure` completely. * Fix scan_object{,s} API Now both scan_object and scan_objects take EdgeVisitor as parameter. We now implement scan_objects in mmtk-core. We no longer expect the VM bindings to create ProcessEdgesWork in scan_objects.
1 parent be96a27 commit 0babba2

File tree

7 files changed

+59
-58
lines changed

7 files changed

+59
-58
lines changed

src/plan/transitive_closure.rs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,18 @@ use std::mem;
55
use crate::scheduler::gc_work::ProcessEdgesWork;
66
use crate::scheduler::{GCWorker, WorkBucketStage};
77
use crate::util::{Address, ObjectReference};
8-
use crate::MMTK;
8+
use crate::vm::EdgeVisitor;
99

1010
/// This trait is the fundamental mechanism for performing a
1111
/// transitive closure over an object graph.
1212
pub trait TransitiveClosure {
1313
// The signature of this function changes during the port
1414
// because the argument `ObjectReference source` is never used in the original version
1515
// See issue #5
16-
fn process_edge(&mut self, slot: Address);
1716
fn process_node(&mut self, object: ObjectReference);
1817
}
1918

2019
impl<T: ProcessEdgesWork> TransitiveClosure for T {
21-
fn process_edge(&mut self, _slot: Address) {
22-
unreachable!();
23-
}
2420
#[inline]
2521
fn process_node(&mut self, object: ObjectReference) {
2622
ProcessEdgesWork::process_node(self, object);
@@ -29,28 +25,31 @@ impl<T: ProcessEdgesWork> TransitiveClosure for T {
2925

3026
/// A transitive closure visitor to collect all the edges of an object.
3127
pub struct ObjectsClosure<'a, E: ProcessEdgesWork> {
32-
mmtk: &'static MMTK<E::VM>,
3328
buffer: Vec<Address>,
3429
worker: &'a mut GCWorker<E::VM>,
3530
}
3631

3732
impl<'a, E: ProcessEdgesWork> ObjectsClosure<'a, E> {
38-
pub fn new(
39-
mmtk: &'static MMTK<E::VM>,
40-
buffer: Vec<Address>,
41-
worker: &'a mut GCWorker<E::VM>,
42-
) -> Self {
33+
pub fn new(worker: &'a mut GCWorker<E::VM>) -> Self {
4334
Self {
44-
mmtk,
45-
buffer,
35+
buffer: vec![],
4636
worker,
4737
}
4838
}
39+
40+
fn flush(&mut self) {
41+
let mut new_edges = Vec::new();
42+
mem::swap(&mut new_edges, &mut self.buffer);
43+
self.worker.add_work(
44+
WorkBucketStage::Closure,
45+
E::new(new_edges, false, self.worker.mmtk),
46+
);
47+
}
4948
}
5049

51-
impl<'a, E: ProcessEdgesWork> TransitiveClosure for ObjectsClosure<'a, E> {
50+
impl<'a, E: ProcessEdgesWork> EdgeVisitor for ObjectsClosure<'a, E> {
5251
#[inline(always)]
53-
fn process_edge(&mut self, slot: Address) {
52+
fn visit_edge(&mut self, slot: Address) {
5453
if self.buffer.is_empty() {
5554
self.buffer.reserve(E::CAPACITY);
5655
}
@@ -60,23 +59,15 @@ impl<'a, E: ProcessEdgesWork> TransitiveClosure for ObjectsClosure<'a, E> {
6059
mem::swap(&mut new_edges, &mut self.buffer);
6160
self.worker.add_work(
6261
WorkBucketStage::Closure,
63-
E::new(new_edges, false, self.mmtk),
62+
E::new(new_edges, false, self.worker.mmtk),
6463
);
6564
}
6665
}
67-
fn process_node(&mut self, _object: ObjectReference) {
68-
unreachable!()
69-
}
7066
}
7167

7268
impl<'a, E: ProcessEdgesWork> Drop for ObjectsClosure<'a, E> {
7369
#[inline(always)]
7470
fn drop(&mut self) {
75-
let mut new_edges = Vec::new();
76-
mem::swap(&mut new_edges, &mut self.buffer);
77-
self.worker.add_work(
78-
WorkBucketStage::Closure,
79-
E::new(new_edges, false, self.mmtk),
80-
);
71+
self.flush();
8172
}
8273
}

src/policy/immix/immixspace.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -592,15 +592,12 @@ impl<Edges: ProcessEdgesWork> ScanObjectsAndMarkLines<Edges> {
592592
}
593593

594594
impl<E: ProcessEdgesWork> GCWork<E::VM> for ScanObjectsAndMarkLines<E> {
595-
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
595+
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, _mmtk: &'static MMTK<E::VM>) {
596596
trace!("ScanObjectsAndMarkLines");
597-
let mut closure = ObjectsClosure::<E>::new(mmtk, vec![], worker);
597+
let tls = worker.tls;
598+
let mut closure = ObjectsClosure::<E>::new(worker);
598599
for object in &self.buffer {
599-
<E::VM as VMBinding>::VMScanning::scan_object(
600-
&mut closure,
601-
*object,
602-
VMWorkerThread(VMThread::UNINITIALIZED),
603-
);
600+
<E::VM as VMBinding>::VMScanning::scan_object(tls, *object, &mut closure);
604601
if super::MARK_LINE_AT_SCAN_TIME
605602
&& !super::BLOCK_ONLY
606603
&& self.immix_space.in_space(*object)

src/scheduler/gc_work.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::work_bucket::WorkBucketStage;
22
use super::*;
33
use crate::plan::GcStatus;
4+
use crate::plan::ObjectsClosure;
45
use crate::util::metadata::*;
56
use crate::util::*;
67
use crate::vm::*;
@@ -551,7 +552,11 @@ impl<Edges: ProcessEdgesWork> ScanObjects<Edges> {
551552
impl<E: ProcessEdgesWork> GCWork<E::VM> for ScanObjects<E> {
552553
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, _mmtk: &'static MMTK<E::VM>) {
553554
trace!("ScanObjects");
554-
<E::VM as VMBinding>::VMScanning::scan_objects::<E>(&self.buffer, worker);
555+
{
556+
let tls = worker.tls;
557+
let mut closure = ObjectsClosure::<E>::new(worker);
558+
<E::VM as VMBinding>::VMScanning::scan_objects(tls, &self.buffer, &mut closure);
559+
}
555560
trace!("ScanObjects End");
556561
}
557562
}

src/scheduler/worker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub struct GCWorker<VM: VMBinding> {
4848
/// The sending end of the channel to send message to the controller thread.
4949
pub sender: Sender<CoordinatorMessage<VM>>,
5050
/// The reference to the MMTk instance.
51-
mmtk: &'static MMTK<VM>,
51+
pub mmtk: &'static MMTK<VM>,
5252
/// True if this struct is the embedded GCWorker of the controller thread.
5353
/// False if this struct belongs to a standalone GCWorker thread.
5454
is_coordinator: bool,

src/vm/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub use self::collection::GCThreadContext;
2828
pub use self::object_model::specs::*;
2929
pub use self::object_model::ObjectModel;
3030
pub use self::reference_glue::ReferenceGlue;
31+
pub use self::scanning::EdgeVisitor;
3132
pub use self::scanning::Scanning;
3233

3334
/// The `VMBinding` trait associates with each trait, and provides VM-specific constants.

src/vm/scanning.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
use crate::plan::{Mutator, TransitiveClosure};
2-
use crate::scheduler::GCWorker;
1+
use crate::plan::Mutator;
32
use crate::scheduler::ProcessEdgesWork;
4-
use crate::util::ObjectReference;
53
use crate::util::VMWorkerThread;
4+
use crate::util::{Address, ObjectReference};
65
use crate::vm::VMBinding;
76

7+
// Callback trait of scanning functions that report edges.
8+
pub trait EdgeVisitor {
9+
/// Call this function for each edge.
10+
fn visit_edge(&mut self, edge: Address);
11+
// TODO: Add visit_soft_edge, visit_weak_edge, ... here.
12+
}
13+
814
/// VM-specific methods for scanning roots/objects.
915
pub trait Scanning<VM: VMBinding> {
1016
/// Scan stack roots after all mutators are paused.
@@ -15,18 +21,17 @@ pub trait Scanning<VM: VMBinding> {
1521
/// `SCAN_MUTATORS_IN_SAFEPOINT` should also be enabled
1622
const SINGLE_THREAD_MUTATOR_SCANNING: bool = true;
1723

18-
/// Delegated scanning of a object, processing each pointer field
19-
/// encountered. This method probably will be removed in the future,
20-
/// in favor of bulk scanning `scan_objects`.
24+
/// Delegated scanning of a object, visiting each pointer field
25+
/// encountered.
2126
///
2227
/// Arguments:
23-
/// * `trace`: The `TransitiveClosure` to use for scanning.
28+
/// * `tls`: The VM-specific thread-local storage for the current worker.
2429
/// * `object`: The object to be scanned.
25-
/// * `tls`: The GC worker thread that is doing this tracing.
26-
fn scan_object<T: TransitiveClosure>(
27-
trace: &mut T,
28-
object: ObjectReference,
30+
/// * `edge_visitor`: Called back for each edge.
31+
fn scan_object<EV: EdgeVisitor>(
2932
tls: VMWorkerThread,
33+
object: ObjectReference,
34+
edge_visitor: &mut EV,
3035
);
3136

3237
/// MMTk calls this method at the first time during a collection that thread's stacks
@@ -41,11 +46,18 @@ pub trait Scanning<VM: VMBinding> {
4146
/// Bulk scanning of objects, processing each pointer field for each object.
4247
///
4348
/// Arguments:
49+
/// * `tls`: The VM-specific thread-local storage for the current worker.
4450
/// * `objects`: The slice of object references to be scanned.
45-
fn scan_objects<W: ProcessEdgesWork<VM = VM>>(
51+
/// * `edge_visitor`: Called back for each edge in each object in `objects`.
52+
fn scan_objects<EV: EdgeVisitor>(
53+
tls: VMWorkerThread,
4654
objects: &[ObjectReference],
47-
worker: &mut GCWorker<VM>,
48-
);
55+
edge_visitor: &mut EV,
56+
) {
57+
for object in objects.iter() {
58+
Self::scan_object(tls, *object, edge_visitor);
59+
}
60+
}
4961

5062
/// Scan all the mutators for roots.
5163
fn scan_thread_roots<W: ProcessEdgesWork<VM = VM>>();

vmbindings/dummyvm/src/scanning.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@ use crate::DummyVM;
22
use mmtk::scheduler::*;
33
use mmtk::util::opaque_pointer::*;
44
use mmtk::util::ObjectReference;
5+
use mmtk::vm::EdgeVisitor;
56
use mmtk::vm::Scanning;
6-
use mmtk::{Mutator, TransitiveClosure};
7+
use mmtk::Mutator;
78

89
pub struct VMScanning {}
910

1011
impl Scanning<DummyVM> for VMScanning {
11-
fn scan_objects<W: ProcessEdgesWork<VM = DummyVM>>(
12-
_objects: &[ObjectReference],
13-
_worker: &mut GCWorker<DummyVM>,
14-
) {
15-
unimplemented!()
16-
}
1712
fn scan_thread_roots<W: ProcessEdgesWork<VM = DummyVM>>() {
1813
unimplemented!()
1914
}
@@ -26,10 +21,10 @@ impl Scanning<DummyVM> for VMScanning {
2621
fn scan_vm_specific_roots<W: ProcessEdgesWork<VM = DummyVM>>() {
2722
unimplemented!()
2823
}
29-
fn scan_object<T: TransitiveClosure>(
30-
_trace: &mut T,
31-
_object: ObjectReference,
24+
fn scan_object<EV: EdgeVisitor>(
3225
_tls: VMWorkerThread,
26+
_object: ObjectReference,
27+
_edge_visitor: &mut EV,
3328
) {
3429
unimplemented!()
3530
}

0 commit comments

Comments
 (0)