use crate::{process::Process, term::Term};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct RootSet {
live_x: usize,
roots: Vec<Term>,
}
impl RootSet {
pub(crate) fn snapshot(process: &mut Process, live_x: usize) -> Self {
Self {
live_x,
roots: process.roots_with_live_x(live_x),
}
}
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut Term> {
self.roots.iter_mut()
}
pub(crate) fn replace_process_roots(self, process: &mut Process) {
process.replace_roots_with_live_x(self.live_x, &self.roots);
}
#[cfg(test)]
pub(crate) fn as_slice(&self) -> &[Term] {
&self.roots
}
}
pub(crate) fn root_set(process: &mut Process, live_x: usize) -> RootSet {
RootSet::snapshot(process, live_x)
}
#[cfg(test)]
mod tests {
use crate::{
atom::Atom,
gc::tests::{Snapshot, alloc_tuple, module_pin, snapshot},
process::{Exception, Process},
term::Term,
};
use super::root_set;
#[test]
fn root_set_includes_only_live_x_prefix() {
let mut process = Process::new(1, 32);
process.set_x_reg(0, Term::small_int(1));
process.set_x_reg(1, Term::small_int(2));
process.set_x_reg(2, Term::small_int(3));
let roots = root_set(&mut process, 2);
assert_eq!(roots.as_slice(), &[Term::small_int(1), Term::small_int(2)]);
}
#[test]
fn root_set_includes_y_registers_mailbox_and_exception_payload() {
let mut process = Process::new(1, 64);
let y0 = alloc_tuple(&mut process, &[Term::small_int(10)]);
let y1 = alloc_tuple(&mut process, &[Term::small_int(11)]);
let message = alloc_tuple(&mut process, &[Term::small_int(12)]);
let reason = alloc_tuple(&mut process, &[Term::small_int(13)]);
let stacktrace = alloc_tuple(&mut process, &[Term::small_int(14)]);
process
.stack_mut()
.push_frame(Atom::OK, 0, module_pin(Atom::OK), 2)
.expect("frame fits");
process.stack_mut().set_y_reg(0, y0).expect("Y0 exists");
process.stack_mut().set_y_reg(1, y1).expect("Y1 exists");
process.mailbox_mut().push_owned_for_test(message);
process.set_current_exception(Some(Exception {
class: Term::atom(Atom::ERROR),
reason,
stacktrace,
}));
let roots = root_set(&mut process, 0);
let snapshots: Vec<_> = roots.as_slice().iter().copied().map(snapshot).collect();
assert_eq!(
snapshots,
vec![
Snapshot::Tuple(vec![Snapshot::Int(10)]),
Snapshot::Tuple(vec![Snapshot::Int(11)]),
Snapshot::Tuple(vec![Snapshot::Int(12)]),
Snapshot::Tuple(vec![Snapshot::Int(13)]),
Snapshot::Tuple(vec![Snapshot::Int(14)]),
]
);
}
}