use atomic::Ordering;
use crate::plan::PlanTraceObject;
use crate::plan::VectorObjectQueue;
use crate::policy::gc_work::TraceKind;
use crate::scheduler::{gc_work::*, GCWork, GCWorker, WorkBucketStage};
use crate::util::ObjectReference;
use crate::vm::slot::{MemorySlice, Slot};
use crate::vm::*;
use crate::MMTK;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use super::global::GenerationalPlanExt;
pub struct GenNurseryProcessEdges<
VM: VMBinding,
P: GenerationalPlanExt<VM> + PlanTraceObject<VM>,
const KIND: TraceKind,
> {
plan: &'static P,
base: ProcessEdgesBase<VM>,
}
impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>, const KIND: TraceKind>
ProcessEdgesWork for GenNurseryProcessEdges<VM, P, KIND>
{
type VM = VM;
type ScanObjectsWorkType = PlanScanObjects<Self, P>;
fn new(
slots: Vec<SlotOf<Self>>,
roots: bool,
mmtk: &'static MMTK<VM>,
bucket: WorkBucketStage,
) -> Self {
let base = ProcessEdgesBase::new(slots, roots, mmtk, bucket);
let plan = base.plan().downcast_ref().unwrap();
Self { plan, base }
}
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
let worker = self.worker();
self.plan.trace_object_nursery::<VectorObjectQueue, KIND>(
&mut self.base.nodes,
object,
worker,
)
}
fn process_slot(&mut self, slot: SlotOf<Self>) {
let Some(object) = slot.load() else {
return;
};
let new_object = self.trace_object(object);
debug_assert!(!self.plan.is_object_in_nursery(new_object));
if new_object != object {
slot.store(new_object);
}
}
fn create_scan_work(&self, nodes: Vec<ObjectReference>) -> Self::ScanObjectsWorkType {
PlanScanObjects::new(self.plan, nodes, false, self.bucket)
}
}
impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>, const KIND: TraceKind> Deref
for GenNurseryProcessEdges<VM, P, KIND>
{
type Target = ProcessEdgesBase<VM>;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl<VM: VMBinding, P: GenerationalPlanExt<VM> + PlanTraceObject<VM>, const KIND: TraceKind>
DerefMut for GenNurseryProcessEdges<VM, P, KIND>
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
pub struct ProcessModBuf<E: ProcessEdgesWork> {
modbuf: Vec<ObjectReference>,
phantom: PhantomData<E>,
}
impl<E: ProcessEdgesWork> ProcessModBuf<E> {
pub fn new(modbuf: Vec<ObjectReference>) -> Self {
debug_assert!(!modbuf.is_empty());
Self {
modbuf,
phantom: PhantomData,
}
}
}
impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessModBuf<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
for obj in &self.modbuf {
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<E::VM, u8>(
*obj,
1,
None,
Ordering::SeqCst,
);
}
if mmtk
.get_plan()
.generational()
.unwrap()
.is_current_gc_nursery()
{
let modbuf = std::mem::take(&mut self.modbuf);
GCWork::do_work(
&mut ScanObjects::<E>::new(modbuf, false, WorkBucketStage::Closure),
worker,
mmtk,
)
}
}
}
pub struct ProcessRegionModBuf<E: ProcessEdgesWork> {
modbuf: Vec<<E::VM as VMBinding>::VMMemorySlice>,
phantom: PhantomData<E>,
}
impl<E: ProcessEdgesWork> ProcessRegionModBuf<E> {
pub fn new(modbuf: Vec<<E::VM as VMBinding>::VMMemorySlice>) -> Self {
Self {
modbuf,
phantom: PhantomData,
}
}
}
impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessRegionModBuf<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
if mmtk
.get_plan()
.generational()
.unwrap()
.is_current_gc_nursery()
{
let mut slots = vec![];
for slice in &self.modbuf {
for slot in slice.iter_slots() {
slots.push(slot);
}
}
GCWork::do_work(
&mut E::new(slots, false, mmtk, WorkBucketStage::Closure),
worker,
mmtk,
)
}
}
}