use crate::scheduler::gc_work::*;
use crate::scheduler::WorkBucketStage;
use crate::util::side_metadata::*;
use crate::util::*;
use crate::MMTK;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BarrierSelector {
NoBarrier,
ObjectBarrier,
}
pub enum WriteTarget {
Object(ObjectReference),
Slot(Address),
}
pub trait Barrier: 'static + Send + Sync {
fn flush(&mut self);
fn post_write_barrier(&mut self, target: WriteTarget);
}
pub struct NoBarrier;
impl Barrier for NoBarrier {
fn flush(&mut self) {}
fn post_write_barrier(&mut self, _target: WriteTarget) {}
}
pub struct ObjectRememberingBarrier<E: ProcessEdgesWork> {
mmtk: &'static MMTK<E::VM>,
modbuf: Vec<ObjectReference>,
meta: SideMetadataSpec,
}
impl<E: ProcessEdgesWork> ObjectRememberingBarrier<E> {
#[allow(unused)]
pub fn new(mmtk: &'static MMTK<E::VM>, meta: SideMetadataSpec) -> Self {
Self {
mmtk,
modbuf: vec![],
meta,
}
}
#[inline(always)]
fn enqueue_node(&mut self, obj: ObjectReference) {
if compare_exchange_atomic(self.meta, obj.to_address(), 0b1, 0b0) {
self.modbuf.push(obj);
if self.modbuf.len() >= E::CAPACITY {
self.flush();
}
}
}
}
impl<E: ProcessEdgesWork> Barrier for ObjectRememberingBarrier<E> {
#[cold]
fn flush(&mut self) {
let mut modbuf = vec![];
std::mem::swap(&mut modbuf, &mut self.modbuf);
debug_assert!(
!self.mmtk.scheduler.work_buckets[WorkBucketStage::Final].is_activated(),
"{:?}",
self as *const _
);
if !modbuf.is_empty() {
self.mmtk.scheduler.work_buckets[WorkBucketStage::Closure]
.add(ProcessModBuf::<E>::new(modbuf, self.meta));
}
}
#[inline(always)]
fn post_write_barrier(&mut self, target: WriteTarget) {
match target {
WriteTarget::Object(obj) => {
self.enqueue_node(obj);
}
_ => unreachable!(),
}
}
}