-
Notifications
You must be signed in to change notification settings - Fork 80
Decuple reference processor from ProcessEdgesWork #604
Description
TL;DR: The reference processor is tightly coupled with ProcessEdgesWork work packets, making it impossible to support runtimes that can only do object-enqueuing. We can make it general.
Problem
Currently, reference-processing work packets {Soft,Weak,Phantom}RefProcessing take ProcessEdgesWork as a parameter. For example:
pub struct SoftRefProcessing<E: ProcessEdgesWork>(PhantomData<E>);
impl<E: ProcessEdgesWork> GCWork<E::VM> for SoftRefProcessing<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
let mut w = E::new(vec![], false, mmtk);
w.set_worker(worker);
mmtk.reference_processors.scan_soft_refs(&mut w, mmtk);
w.flush();
}
}Seeing from the use pattern, it instantiates E, passes it to scan_soft_refs, and calls .flush() on it. It never calls w.do_work, which indicates ProcessEdgesWork is not a sub-task of SoftRefProcessing. Instead, SoftRefProcessing is just stealing some functionalities from ProcessEdgesWork!
Analysis
It uses the E: ProcessEdgesWork type for three purposes:
- Use
E::trace_objectto trace object. Traced soft/weak/phantom references will become softly/weakly/phantomly reachable. - Use
Eas an object queue.E::trace_objecttakes a queue parameter (currently in the form of aTransitiveClosure, but will be refactored in Remove TransitiveClosure param from Space::trace_object and Scanning::scan_object #559). - Use the object queue to create a object-scanning work packet.
w.flush()does this. It will create aScanObjectswork packet to scan objects.
From the analysis, the SoftRefProcessing work packet only has two dependencies:
- A delegate for calling
trace_objectin the appropriate space, and - The type of the object-scanning work packet to create. (More concretely, the post-scan hook which Immix needs.)
The queue is just a Vec<ObjectReference> (or whatever that wraps it) and can be created locally.
Solution
To move away from ProcessEdgesWork, we just need to parameterise {Soft,Weak,Phantom}RefProcessing with a trait that provides the above two operations, namely trace_object and post_scan_object.
I have a draft for this trait. I call it TracingDelegate.
pub trait TracingDelegate<VM: VMBinding>: 'static + Copy + Send {
fn trace_object<T: TransitiveClosure>(
&self,
trace: &mut T,
object: ObjectReference,
worker: &mut GCWorker<VM>,
) -> ObjectReference;
fn may_move_objects() -> bool;
fn post_scan_object(&self, object: ObjectReference);
}They are just the three methods provided by PlanTraceObject, except without the KIND which can be parameterised on concrete implementations.
There should be two implementations, one for SFT, and the other for PlanTraceObject, just like there are SFTProcessEdges and PlanProcessEdges.
Then SoftRefProcessing can just call trace_object from that trait. The ScanObjects trait can also be refactored to use that trait.