use crate::plan::barriers::{Barrier, WriteTarget};
use crate::plan::global::Plan;
use crate::plan::AllocationSemantics as AllocationType;
use crate::policy::space::Space;
use crate::util::alloc::allocators::{AllocatorSelector, Allocators};
use crate::util::OpaquePointer;
use crate::util::{Address, ObjectReference};
use crate::vm::VMBinding;
use enum_map::EnumMap;
type SpaceMapping<VM> = Vec<(AllocatorSelector, &'static dyn Space<VM>)>;
#[repr(C)]
pub struct MutatorConfig<VM: VMBinding> {
pub allocator_mapping: &'static EnumMap<AllocationType, AllocatorSelector>,
#[allow(clippy::box_vec)]
pub space_mapping: Box<SpaceMapping<VM>>,
pub prepare_func: &'static dyn Fn(&mut Mutator<VM>, OpaquePointer),
pub release_func: &'static dyn Fn(&mut Mutator<VM>, OpaquePointer),
}
unsafe impl<VM: VMBinding> Send for MutatorConfig<VM> {}
unsafe impl<VM: VMBinding> Sync for MutatorConfig<VM> {}
#[repr(C)]
pub struct Mutator<VM: VMBinding> {
pub allocators: Allocators<VM>,
pub barrier: Box<dyn Barrier>,
pub mutator_tls: OpaquePointer,
pub plan: &'static dyn Plan<VM = VM>,
pub config: MutatorConfig<VM>,
}
impl<VM: VMBinding> MutatorContext<VM> for Mutator<VM> {
fn prepare(&mut self, tls: OpaquePointer) {
(*self.config.prepare_func)(self, tls)
}
fn release(&mut self, tls: OpaquePointer) {
(*self.config.release_func)(self, tls)
}
fn alloc(
&mut self,
size: usize,
align: usize,
offset: isize,
allocator: AllocationType,
) -> Address {
unsafe {
self.allocators
.get_allocator_mut(self.config.allocator_mapping[allocator])
}
.alloc(size, align, offset)
}
fn post_alloc(&mut self, refer: ObjectReference, _bytes: usize, allocator: AllocationType) {
unsafe {
self.allocators
.get_allocator_mut(self.config.allocator_mapping[allocator])
}
.get_space()
.unwrap()
.initialize_header(refer, true)
}
fn get_tls(&self) -> OpaquePointer {
self.mutator_tls
}
fn barrier(&mut self) -> &mut dyn Barrier {
&mut *self.barrier
}
}
pub trait MutatorContext<VM: VMBinding>: Send + Sync + 'static {
fn prepare(&mut self, tls: OpaquePointer);
fn release(&mut self, tls: OpaquePointer);
fn alloc(
&mut self,
size: usize,
align: usize,
offset: isize,
allocator: AllocationType,
) -> Address;
fn post_alloc(&mut self, refer: ObjectReference, bytes: usize, allocator: AllocationType);
fn flush_remembered_sets(&mut self) {
self.barrier().flush();
}
fn flush(&mut self) {
self.flush_remembered_sets();
}
fn get_tls(&self) -> OpaquePointer;
fn barrier(&mut self) -> &mut dyn Barrier;
fn record_modified_node(&mut self, obj: ObjectReference) {
self.barrier().post_write_barrier(WriteTarget::Object(obj));
}
}