use std::marker::PhantomData;
use crate::scheduler::gc_work::{ProcessEdgesWork, SlotOf};
use crate::scheduler::{GCWorker, WorkBucketStage, EDGES_WORK_BUFFER_SIZE};
use crate::util::{ObjectReference, VMThread, VMWorkerThread};
use crate::vm::{Scanning, SlotVisitor, VMBinding};
pub trait ObjectQueue {
fn enqueue(&mut self, object: ObjectReference);
}
pub type VectorObjectQueue = VectorQueue<ObjectReference>;
pub struct VectorQueue<T> {
buffer: Vec<T>,
}
impl<T> VectorQueue<T> {
const CAPACITY: usize = EDGES_WORK_BUFFER_SIZE;
pub fn new() -> Self {
Self { buffer: Vec::new() }
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn take(&mut self) -> Vec<T> {
std::mem::take(&mut self.buffer)
}
pub fn into_vec(self) -> Vec<T> {
self.buffer
}
pub fn is_full(&self) -> bool {
self.buffer.len() >= Self::CAPACITY
}
pub fn push(&mut self, v: T) {
if self.buffer.is_empty() {
self.buffer.reserve(Self::CAPACITY);
}
self.buffer.push(v);
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn clear(&mut self) {
self.buffer.clear()
}
}
impl<T> Default for VectorQueue<T> {
fn default() -> Self {
Self::new()
}
}
impl ObjectQueue for VectorQueue<ObjectReference> {
fn enqueue(&mut self, v: ObjectReference) {
self.push(v);
}
}
pub struct ObjectsClosure<'a, E: ProcessEdgesWork> {
buffer: VectorQueue<SlotOf<E>>,
pub(crate) worker: &'a mut GCWorker<E::VM>,
bucket: WorkBucketStage,
}
impl<'a, E: ProcessEdgesWork> ObjectsClosure<'a, E> {
pub fn new(worker: &'a mut GCWorker<E::VM>, bucket: WorkBucketStage) -> Self {
Self {
buffer: VectorQueue::new(),
worker,
bucket,
}
}
fn flush(&mut self) {
let buf = self.buffer.take();
if !buf.is_empty() {
self.worker.add_work(
self.bucket,
E::new(buf, false, self.worker.mmtk, self.bucket),
);
}
}
}
impl<E: ProcessEdgesWork> SlotVisitor<SlotOf<E>> for ObjectsClosure<'_, E> {
fn visit_slot(&mut self, slot: SlotOf<E>) {
#[cfg(debug_assertions)]
{
use crate::vm::slot::Slot;
trace!(
"(ObjectsClosure) Visit slot {:?} (pointing to {:?})",
slot,
slot.load()
);
}
self.buffer.push(slot);
if self.buffer.is_full() {
self.flush();
}
}
}
impl<E: ProcessEdgesWork> Drop for ObjectsClosure<'_, E> {
fn drop(&mut self) {
self.flush();
}
}
pub(crate) struct SlotIterator<VM: VMBinding> {
_p: PhantomData<VM>,
}
impl<VM: VMBinding> SlotIterator<VM> {
pub fn iterate_fields<F: FnMut(VM::VMSlot)>(object: ObjectReference, _tls: VMThread, mut f: F) {
let fake_tls = VMWorkerThread(VMThread::UNINITIALIZED);
if !<VM::VMScanning as Scanning<VM>>::support_slot_enqueuing(fake_tls, object) {
panic!("SlotIterator::iterate_fields cannot be used on objects that don't support slot-enqueuing");
}
<VM::VMScanning as Scanning<VM>>::scan_object(fake_tls, object, &mut f);
}
}