use crate::process::{ArenaRange, PredicateFn};
use crate::sched::ProcessId;
use super::EdgeKind;
use super::StateCellId;
use super::instance::StateEngine;
pub struct FrameArena {
words: Vec<u64>,
edge_terms: Vec<(EdgeKind, StateCellId, Option<PredicateFn>)>,
fork_children: Vec<ProcessId>,
}
impl Default for FrameArena {
fn default() -> Self {
Self::new()
}
}
impl FrameArena {
pub fn new() -> Self {
FrameArena {
words: Vec::new(),
edge_terms: Vec::new(),
fork_children: Vec::new(),
}
}
pub fn alloc_frame_words(&mut self, n: u32) -> ArenaRange {
let base = self.words.len() as u32;
self.words.resize(self.words.len() + n as usize, 0);
ArenaRange { base, count: n }
}
pub fn alloc_edge_terms(
&mut self,
terms: &[(EdgeKind, StateCellId, Option<PredicateFn>)],
) -> ArenaRange {
let base = self.edge_terms.len() as u32;
self.edge_terms.extend_from_slice(terms);
ArenaRange {
base,
count: terms.len() as u32,
}
}
pub fn alloc_fork_children(&mut self, n: u32) -> ArenaRange {
let base = self.fork_children.len() as u32;
self.fork_children
.resize(self.fork_children.len() + n as usize, 0);
ArenaRange { base, count: n }
}
}
impl StateEngine {
pub fn new_activation_record(
&mut self,
pc: u32,
frame_word_count: u32,
) -> crate::process::ActivationRecord {
let frame = self.frame.alloc_frame_words(frame_word_count);
crate::process::ActivationRecord {
pc,
frame,
pending_wait: crate::process::WaitSpecStorage::None,
fork_state: None,
}
}
}
#[cfg(test)]
mod tests {
use super::super::instance::StateEngine;
use super::super::instance::TemplateRegistry;
use super::*;
use crate::process::ArenaRange;
#[test]
fn activation_records_are_allocated_by_state_not_constructed_ad_hoc() {
let mut engine = StateEngine::new(TemplateRegistry::new());
let ar1 = engine.new_activation_record(0, 4);
let ar2 = engine.new_activation_record(0, 4);
assert_eq!(ar2.frame.base, ar1.frame.base + 4);
assert_eq!(ar1.frame.count, 4);
assert_eq!(ar2.frame.count, 4);
}
#[test]
fn activation_record_is_still_pod_after_going_through_state_allocation() {
let mut engine = StateEngine::new(TemplateRegistry::new());
let ar = engine.new_activation_record(0, 4);
let copy = ar;
engine.frame.words[ar.frame.base as usize] = 0xDEAD_BEEF;
assert_eq!(copy.frame.base, ar.frame.base);
assert_eq!(copy.frame.count, ar.frame.count);
assert_eq!(engine.frame.words[copy.frame.base as usize], 0xDEAD_BEEF);
assert_eq!(engine.frame.words[ar.frame.base as usize], 0xDEAD_BEEF);
}
#[test]
fn edge_list_and_fork_children_get_independent_arena_ranges() {
use crate::state::{EdgeKind, StateCellId};
let mut fa = FrameArena::new();
let edge_range = fa.alloc_edge_terms(&[
(EdgeKind::Posedge, StateCellId(0), None),
(EdgeKind::Negedge, StateCellId(1), None),
(EdgeKind::BothEdges, StateCellId(2), None),
]);
let fork_range = fa.alloc_fork_children(2);
assert_eq!(edge_range, ArenaRange { base: 0, count: 3 });
assert_eq!(fork_range, ArenaRange { base: 0, count: 2 });
fa.fork_children[fork_range.base as usize] = 42;
fa.fork_children[fork_range.base as usize + 1] = 43;
assert_eq!(fa.edge_terms.len(), 3);
assert_eq!(fa.edge_terms[0].1, StateCellId(0));
assert_eq!(fa.fork_children[0], 42);
assert_eq!(fa.fork_children[1], 43);
}
#[test]
fn resume_pc_lives_on_the_activation_record_state_owns_no_separate_pc_table() {
let mut engine = StateEngine::new(TemplateRegistry::new());
let mut ar1 = engine.new_activation_record(10, 0);
let ar2 = engine.new_activation_record(20, 0);
assert_eq!(ar1.pc, 10);
assert_eq!(ar2.pc, 20);
ar1.pc = 99;
assert_eq!(ar1.pc, 99);
assert_eq!(
ar2.pc, 20,
"mutating one record's pc must never affect another's"
);
}
}