use crate::vm::edge_shape::{Edge, MemorySlice};
use crate::vm::ObjectModel;
use crate::{
util::{metadata::MetadataSpec, *},
vm::VMBinding,
};
use atomic::Ordering;
use downcast_rs::Downcast;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BarrierSelector {
NoBarrier,
ObjectBarrier,
}
impl BarrierSelector {
pub const fn equals(&self, other: BarrierSelector) -> bool {
*self as u8 == other as u8
}
}
pub trait Barrier<VM: VMBinding>: 'static + Send + Downcast {
fn flush(&mut self) {}
fn object_reference_write(
&mut self,
src: ObjectReference,
slot: VM::VMEdge,
target: ObjectReference,
) {
self.object_reference_write_pre(src, slot, target);
slot.store(target);
self.object_reference_write_post(src, slot, target);
}
fn object_reference_write_pre(
&mut self,
_src: ObjectReference,
_slot: VM::VMEdge,
_target: ObjectReference,
) {
}
fn object_reference_write_post(
&mut self,
_src: ObjectReference,
_slot: VM::VMEdge,
_target: ObjectReference,
) {
}
fn object_reference_write_slow(
&mut self,
_src: ObjectReference,
_slot: VM::VMEdge,
_target: ObjectReference,
) {
}
fn memory_region_copy(&mut self, src: VM::VMMemorySlice, dst: VM::VMMemorySlice) {
self.memory_region_copy_pre(src.clone(), dst.clone());
VM::VMMemorySlice::copy(&src, &dst);
self.memory_region_copy_post(src, dst);
}
fn memory_region_copy_pre(&mut self, _src: VM::VMMemorySlice, _dst: VM::VMMemorySlice) {}
fn memory_region_copy_post(&mut self, _src: VM::VMMemorySlice, _dst: VM::VMMemorySlice) {}
}
impl_downcast!(Barrier<VM> where VM: VMBinding);
pub struct NoBarrier;
impl<VM: VMBinding> Barrier<VM> for NoBarrier {}
pub trait BarrierSemantics: 'static + Send {
type VM: VMBinding;
const UNLOG_BIT_SPEC: MetadataSpec =
*<Self::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC.as_spec();
fn flush(&mut self);
fn object_reference_write_slow(
&mut self,
src: ObjectReference,
slot: <Self::VM as VMBinding>::VMEdge,
target: ObjectReference,
);
fn memory_region_copy_slow(
&mut self,
src: <Self::VM as VMBinding>::VMMemorySlice,
dst: <Self::VM as VMBinding>::VMMemorySlice,
);
}
pub struct ObjectBarrier<S: BarrierSemantics> {
semantics: S,
}
impl<S: BarrierSemantics> ObjectBarrier<S> {
pub fn new(semantics: S) -> Self {
Self { semantics }
}
#[inline(always)]
fn object_is_unlogged(&self, object: ObjectReference) -> bool {
unsafe { S::UNLOG_BIT_SPEC.load::<S::VM, u8>(object, None) != 0 }
}
#[inline(always)]
fn log_object(&self, object: ObjectReference) -> bool {
loop {
let old_value =
S::UNLOG_BIT_SPEC.load_atomic::<S::VM, u8>(object, None, Ordering::SeqCst);
if old_value == 0 {
return false;
}
if S::UNLOG_BIT_SPEC
.compare_exchange_metadata::<S::VM, u8>(
object,
1,
0,
None,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
return true;
}
}
}
}
impl<S: BarrierSemantics> Barrier<S::VM> for ObjectBarrier<S> {
fn flush(&mut self) {
self.semantics.flush();
}
#[inline(always)]
fn object_reference_write_post(
&mut self,
src: ObjectReference,
slot: <S::VM as VMBinding>::VMEdge,
target: ObjectReference,
) {
if self.object_is_unlogged(src) {
self.object_reference_write_slow(src, slot, target);
}
}
#[inline(always)]
fn object_reference_write_slow(
&mut self,
src: ObjectReference,
slot: <S::VM as VMBinding>::VMEdge,
target: ObjectReference,
) {
if self.log_object(src) {
self.semantics
.object_reference_write_slow(src, slot, target);
}
}
#[inline(always)]
fn memory_region_copy_post(
&mut self,
src: <S::VM as VMBinding>::VMMemorySlice,
dst: <S::VM as VMBinding>::VMMemorySlice,
) {
self.semantics.memory_region_copy_slow(src, dst);
}
}