use std::collections::HashSet;
use std::mem::swap;
use std::sync::Mutex;
use crate::util::ObjectReference;
use super::object_enum::ObjectEnumerator;
pub struct TreadMill {
sync: Mutex<TreadMillSync>,
}
#[derive(Default)]
struct TreadMillSync {
from_space: HashSet<ObjectReference>,
to_space: HashSet<ObjectReference>,
collect_nursery: HashSet<ObjectReference>,
alloc_nursery: HashSet<ObjectReference>,
}
impl std::fmt::Debug for TreadMill {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let sync = self.sync.lock().unwrap();
f.debug_struct("TreadMill")
.field("from_space", &sync.from_space)
.field("to_space", &sync.to_space)
.field("collect_nursery", &sync.collect_nursery)
.field("alloc_nursery", &sync.alloc_nursery)
.finish()
}
}
impl TreadMill {
pub fn new() -> Self {
TreadMill {
sync: Mutex::new(Default::default()),
}
}
pub fn add_to_treadmill(&self, object: ObjectReference, nursery: bool) {
let mut sync = self.sync.lock().unwrap();
if nursery {
trace!("Adding {} to alloc_nursery", object);
sync.alloc_nursery.insert(object);
} else {
trace!("Adding {} to to_space", object);
sync.to_space.insert(object);
}
}
pub fn collect_nursery(&self) -> impl IntoIterator<Item = ObjectReference> {
let mut sync = self.sync.lock().unwrap();
std::mem::take(&mut sync.collect_nursery)
}
pub fn collect_mature(&self) -> impl IntoIterator<Item = ObjectReference> {
let mut sync = self.sync.lock().unwrap();
std::mem::take(&mut sync.from_space)
}
pub fn copy(&self, object: ObjectReference, is_in_nursery: bool) {
let mut sync = self.sync.lock().unwrap();
if is_in_nursery {
debug_assert!(
sync.collect_nursery.contains(&object),
"copy source object ({}) must be in collect_nursery",
object
);
sync.collect_nursery.remove(&object);
} else {
debug_assert!(
sync.from_space.contains(&object),
"copy source object ({}) must be in from_space",
object
);
sync.from_space.remove(&object);
}
sync.to_space.insert(object);
}
pub fn is_to_space_empty(&self) -> bool {
let sync = self.sync.lock().unwrap();
sync.to_space.is_empty()
}
pub fn is_from_space_empty(&self) -> bool {
let sync = self.sync.lock().unwrap();
sync.from_space.is_empty()
}
pub fn is_alloc_nursery_empty(&self) -> bool {
let sync = self.sync.lock().unwrap();
sync.alloc_nursery.is_empty()
}
pub fn is_collect_nursery_empty(&self) -> bool {
let sync = self.sync.lock().unwrap();
sync.collect_nursery.is_empty()
}
pub fn flip(&mut self, full_heap: bool) {
let sync = self.sync.get_mut().unwrap();
swap(&mut sync.alloc_nursery, &mut sync.collect_nursery);
trace!("Flipped alloc_nursery and collect_nursery");
if full_heap {
swap(&mut sync.from_space, &mut sync.to_space);
trace!("Flipped from_space and to_space");
}
}
pub(crate) fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator, all: bool) {
let sync = self.sync.lock().unwrap();
let mut enumerated = 0usize;
let mut visit_objects = |set: &HashSet<ObjectReference>| {
for object in set.iter() {
enumerator.visit_object(*object);
enumerated += 1;
}
};
visit_objects(&sync.alloc_nursery);
visit_objects(&sync.to_space);
if all {
visit_objects(&sync.collect_nursery);
visit_objects(&sync.from_space);
}
debug!("Enumerated {enumerated} objects in LOS. all: {all}. from_space: {fs}, to_space: {ts}, collect_nursery: {cn}, alloc_nursery: {an}",
fs=sync.from_space.len(),
ts=sync.to_space.len(),
cn=sync.collect_nursery.len(),
an=sync.alloc_nursery.len(),
);
}
}
impl Default for TreadMill {
fn default() -> Self {
Self::new()
}
}