Skip to content

Remove ProcessEdgesBase::worker #597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 9 additions & 5 deletions src/plan/generational/gc_work.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::plan::generational::global::Gen;
use crate::policy::space::Space;
use crate::scheduler::gc_work::*;
use crate::scheduler::{gc_work::*, GCWorker};
use crate::util::{Address, ObjectReference};
use crate::vm::*;
use crate::MMTK;
Expand All @@ -23,16 +23,20 @@ impl<VM: VMBinding> ProcessEdgesWork for GenNurseryProcessEdges<VM> {
Self { gen, base }
}
#[inline]
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
fn trace_object(
&mut self,
worker: &mut GCWorker<Self::VM>,
object: ObjectReference,
) -> ObjectReference {
if object.is_null() {
return object;
}
self.gen.trace_object_nursery(self, object, self.worker())
self.gen.trace_object_nursery(self, object, worker)
}
#[inline]
fn process_edge(&mut self, slot: Address) {
fn process_edge(&mut self, worker: &mut GCWorker<Self::VM>, slot: Address) {
let object = unsafe { slot.load::<ObjectReference>() };
let new_object = self.trace_object(object);
let new_object = self.trace_object(worker, object);
debug_assert!(!self.gen.nursery.in_space(new_object));
unsafe { slot.store(new_object) };
}
Expand Down
63 changes: 33 additions & 30 deletions src/scheduler/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,6 @@ pub struct ProcessEdgesBase<VM: VMBinding> {
pub edges: Vec<Address>,
pub nodes: Vec<ObjectReference>,
mmtk: &'static MMTK<VM>,
// Use raw pointer for fast pointer dereferencing, instead of using `Option<&'static mut GCWorker<E::VM>>`.
// Because a copying gc will dereference this pointer at least once for every object copy.
worker: *mut GCWorker<VM>,
pub roots: bool,
}

Expand All @@ -349,17 +346,9 @@ impl<VM: VMBinding> ProcessEdgesBase<VM> {
edges,
nodes: vec![],
mmtk,
worker: std::ptr::null_mut(),
roots,
}
}
pub fn set_worker(&mut self, worker: &mut GCWorker<VM>) {
self.worker = worker;
}
#[inline]
pub fn worker(&self) -> &'static mut GCWorker<VM> {
unsafe { &mut *self.worker }
}
#[inline]
pub fn mmtk(&self) -> &'static MMTK<VM> {
self.mmtk
Expand Down Expand Up @@ -398,7 +387,11 @@ pub trait ProcessEdgesWork:
const OVERWRITE_REFERENCE: bool = true;
const SCAN_OBJECTS_IMMEDIATELY: bool = true;
fn new(edges: Vec<Address>, roots: bool, mmtk: &'static MMTK<Self::VM>) -> Self;
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference;
fn trace_object(
&mut self,
worker: &mut GCWorker<Self::VM>,
object: ObjectReference,
) -> ObjectReference;

#[cfg(feature = "sanity")]
fn cache_roots_for_sanity_gc(&mut self) {
Expand All @@ -424,14 +417,18 @@ pub trait ProcessEdgesWork:
/// Start the a scan work packet. If SCAN_OBJECTS_IMMEDIATELY, the work packet will be executed immediately, in this method.
/// Otherwise, the work packet will be added the Closure work bucket and will be dispatched later by the scheduler.
#[inline]
fn start_or_dispatch_scan_work(&mut self, work_packet: Box<dyn GCWork<Self::VM>>) {
fn start_or_dispatch_scan_work(
&mut self,
worker: &mut GCWorker<Self::VM>,
work_packet: Box<dyn GCWork<Self::VM>>,
) {
if Self::SCAN_OBJECTS_IMMEDIATELY {
// We execute this `scan_objects_work` immediately.
// This is expected to be a useful optimization because,
// say for _pmd_ with 200M heap, we're likely to have 50000~60000 `ScanObjects` work packets
// being dispatched (similar amount to `ProcessEdgesWork`).
// Executing these work packets now can remarkably reduce the global synchronization time.
self.worker().do_boxed_work(work_packet);
worker.do_boxed_work(work_packet);
} else {
self.mmtk.scheduler.work_buckets[WorkBucketStage::Closure].add_boxed(work_packet);
}
Expand All @@ -449,27 +446,27 @@ pub trait ProcessEdgesWork:
/// Flush the nodes in ProcessEdgesBase, and create a ScanObjects work packet for it. If the node set is empty,
/// this method will simply return with no work packet created.
#[cold]
fn flush(&mut self) {
fn flush(&mut self, worker: &mut GCWorker<Self::VM>) {
if self.nodes.is_empty() {
return;
}
let nodes = self.pop_nodes();
self.start_or_dispatch_scan_work(self.create_scan_work(nodes));
self.start_or_dispatch_scan_work(worker, self.create_scan_work(nodes));
}

#[inline]
fn process_edge(&mut self, slot: Address) {
fn process_edge(&mut self, worker: &mut GCWorker<Self::VM>, slot: Address) {
let object = unsafe { slot.load::<ObjectReference>() };
let new_object = self.trace_object(object);
let new_object = self.trace_object(worker, object);
if Self::OVERWRITE_REFERENCE {
unsafe { slot.store(new_object) };
}
}

#[inline]
fn process_edges(&mut self) {
fn process_edges(&mut self, worker: &mut GCWorker<Self::VM>) {
for i in 0..self.edges.len() {
self.process_edge(self.edges[i])
self.process_edge(worker, self.edges[i])
}
}
}
Expand All @@ -478,10 +475,9 @@ impl<E: ProcessEdgesWork> GCWork<E::VM> for E {
#[inline]
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, _mmtk: &'static MMTK<E::VM>) {
trace!("ProcessEdgesWork");
self.set_worker(worker);
self.process_edges();
self.process_edges(worker);
if !self.nodes.is_empty() {
self.flush();
self.flush(worker);
}
#[cfg(feature = "sanity")]
if self.roots {
Expand Down Expand Up @@ -510,7 +506,11 @@ impl<VM: VMBinding> ProcessEdgesWork for SFTProcessEdges<VM> {
}

#[inline]
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
fn trace_object(
&mut self,
worker: &mut GCWorker<Self::VM>,
object: ObjectReference,
) -> ObjectReference {
use crate::policy::space::*;

if object.is_null() {
Expand All @@ -522,7 +522,7 @@ impl<VM: VMBinding> ProcessEdgesWork for SFTProcessEdges<VM> {
crate::mmtk::SFT_MAP.assert_valid_entries_for_object::<VM>(object);

// Erase <VM> type parameter
let worker = GCWorkerMutRef::new(self.worker());
let worker = GCWorkerMutRef::new(worker);
let trace = SFTProcessEdgesMutRef::new(self);

// Invoke trace object on sft
Expand Down Expand Up @@ -648,18 +648,21 @@ impl<VM: VMBinding, P: PlanTraceObject<VM> + Plan<VM = VM>, const KIND: TraceKin
}

#[inline(always)]
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
fn trace_object(
&mut self,
worker: &mut GCWorker<Self::VM>,
object: ObjectReference,
) -> ObjectReference {
if object.is_null() {
return object;
}
self.plan
.trace_object::<Self, KIND>(self, object, self.worker())
self.plan.trace_object::<Self, KIND>(self, object, worker)
}

#[inline]
fn process_edge(&mut self, slot: Address) {
fn process_edge(&mut self, worker: &mut GCWorker<Self::VM>, slot: Address) {
let object = unsafe { slot.load::<ObjectReference>() };
let new_object = self.trace_object(object);
let new_object = self.trace_object(worker, object);
if P::may_move_objects::<KIND>() {
unsafe { slot.store(new_object) };
}
Expand Down
4 changes: 2 additions & 2 deletions src/scheduler/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ impl<VM: VMBinding> GCWorker<VM> {
&mut self.copy
}

pub fn do_work(&'static mut self, mut work: impl GCWork<VM>) {
pub fn do_work(&mut self, mut work: impl GCWork<VM>) {
work.do_work(self, self.mmtk);
}

pub fn do_boxed_work(&'static mut self, mut work: Box<dyn GCWork<VM>>) {
pub fn do_boxed_work(&mut self, mut work: Box<dyn GCWork<VM>>) {
work.do_work(self, self.mmtk);
}

Expand Down
65 changes: 42 additions & 23 deletions src/util/finalizable_processor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::scheduler::gc_work::ProcessEdgesWork;
use crate::scheduler::{GCWork, GCWorker};
use crate::util::{ObjectReference, VMWorkerThread};
use crate::util::ObjectReference;
use crate::vm::{Collection, VMBinding};
use crate::MMTK;
use std::marker::PhantomData;
Expand Down Expand Up @@ -34,20 +34,27 @@ impl FinalizableProcessor {
}

fn get_forwarded_finalizable<E: ProcessEdgesWork>(
worker: &mut GCWorker<E::VM>,
e: &mut E,
object: ObjectReference,
) -> ObjectReference {
e.trace_object(object)
e.trace_object(worker, object)
}

fn return_for_finalize<E: ProcessEdgesWork>(
worker: &mut GCWorker<E::VM>,
e: &mut E,
object: ObjectReference,
) -> ObjectReference {
e.trace_object(object)
e.trace_object(worker, object)
}

pub fn scan<E: ProcessEdgesWork>(&mut self, tls: VMWorkerThread, e: &mut E, nursery: bool) {
pub fn scan<E: ProcessEdgesWork>(
&mut self,
worker: &mut GCWorker<E::VM>,
e: &mut E,
nursery: bool,
) {
let start = if nursery { self.nursery_index } else { 0 };

// We should go through ready_for_finalize objects and keep them alive.
Expand All @@ -63,39 +70,49 @@ impl FinalizableProcessor {
{
trace!("Pop {:?} for finalization", reff);
if reff.is_live() {
let res = FinalizableProcessor::get_forwarded_finalizable(e, reff);
let res = FinalizableProcessor::get_forwarded_finalizable(worker, e, reff);
trace!("{:?} is live, push {:?} back to candidates", reff, res);
self.candidates.push(res);
continue;
}

let retained = FinalizableProcessor::return_for_finalize(e, reff);
let retained = FinalizableProcessor::return_for_finalize(worker, e, reff);
self.ready_for_finalize.push(retained);
trace!(
"{:?} is not live, push {:?} to ready_for_finalize",
reff,
retained
);
}
e.flush();
e.flush(worker);

self.nursery_index = self.candidates.len();

<<E as ProcessEdgesWork>::VM as VMBinding>::VMCollection::schedule_finalization(tls);
<<E as ProcessEdgesWork>::VM as VMBinding>::VMCollection::schedule_finalization(worker.tls);
}

pub fn forward_candidate<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
self.candidates
.iter_mut()
.for_each(|reff| *reff = FinalizableProcessor::get_forwarded_finalizable(e, *reff));
e.flush();
pub fn forward_candidate<E: ProcessEdgesWork>(
&mut self,
worker: &mut GCWorker<E::VM>,
e: &mut E,
_nursery: bool,
) {
self.candidates.iter_mut().for_each(|reff| {
*reff = FinalizableProcessor::get_forwarded_finalizable(worker, e, *reff)
});
e.flush(worker);
}

pub fn forward_finalizable<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
self.ready_for_finalize
.iter_mut()
.for_each(|reff| *reff = FinalizableProcessor::get_forwarded_finalizable(e, *reff));
e.flush();
pub fn forward_finalizable<E: ProcessEdgesWork>(
&mut self,
worker: &mut GCWorker<E::VM>,
e: &mut E,
_nursery: bool,
) {
self.ready_for_finalize.iter_mut().for_each(|reff| {
*reff = FinalizableProcessor::get_forwarded_finalizable(worker, e, *reff)
});
e.flush(worker);
}

pub fn get_ready_object(&mut self) -> Option<ObjectReference> {
Expand All @@ -116,8 +133,7 @@ impl<E: ProcessEdgesWork> GCWork<E::VM> for Finalization<E> {
);

let mut w = E::new(vec![], false, mmtk);
w.set_worker(worker);
finalizable_processor.scan(worker.tls, &mut w, mmtk.plan.is_current_gc_nursery());
finalizable_processor.scan(worker, &mut w, mmtk.plan.is_current_gc_nursery());
debug!(
"Finished finalization, {} objects in candidates, {} objects ready to finalize",
finalizable_processor.candidates.len(),
Expand All @@ -139,10 +155,13 @@ impl<E: ProcessEdgesWork> GCWork<E::VM> for ForwardFinalization<E> {
trace!("Forward finalization");
let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
let mut w = E::new(vec![], false, mmtk);
w.set_worker(worker);
finalizable_processor.forward_candidate(&mut w, mmtk.plan.is_current_gc_nursery());
finalizable_processor.forward_candidate(worker, &mut w, mmtk.plan.is_current_gc_nursery());

finalizable_processor.forward_finalizable(&mut w, mmtk.plan.is_current_gc_nursery());
finalizable_processor.forward_finalizable(
worker,
&mut w,
mmtk.plan.is_current_gc_nursery(),
);
trace!("Finished forwarding finlizable");
}
}
Expand Down
Loading