use std::{collections::HashMap, time::Instant};
use beamr::{
atom::Atom,
interpreter::{ExecutionResult, run},
loader::Instruction,
loader::decode::compact::Operand,
module::Module,
process::{ExitReason, Process},
term::{Term, boxed::Cons},
};
fn module(code: Vec<Instruction>) -> Module {
let label_index = code
.iter()
.enumerate()
.filter_map(|(i, instr)| {
if let Instruction::Label { label } = instr {
Some((*label, i))
} else {
None
}
})
.collect();
Module {
name: Atom::OK,
generation: 0,
exports: HashMap::new(),
label_index,
code,
literals: Vec::new(),
resolved_imports: Vec::new(),
lambdas: Vec::new(),
string_table: Vec::new(),
line_info: Vec::new(),
}
}
#[test]
fn interpreter_survives_10_000_allocations_under_gc_pressure() {
let mut code = vec![Instruction::Move {
source: Operand::Atom(None),
destination: Operand::X(0),
}];
for value in 0..10_000 {
code.push(Instruction::TestHeap {
heap_need: Operand::Unsigned(2),
live: Operand::Unsigned(1),
});
code.push(Instruction::PutList {
head: Operand::Integer(value),
tail: Operand::X(0),
destination: Operand::X(0),
});
}
code.push(Instruction::Return);
let module = module(code);
let mut process = Process::new(1, 2_048);
process.reset_reductions(100_000);
process.heap_mut().set_max_capacity(32_768);
let start = Instant::now();
let result = run(&mut process, &module);
assert_eq!(result, Ok(ExecutionResult::Exited(ExitReason::Normal)));
assert!(start.elapsed().as_secs_f64() < 5.0);
assert_eq!(list_len(process.x_reg(0)), 10_000);
assert!(process.heap().old_used() > 0);
}
fn list_len(mut term: Term) -> usize {
let mut len = 0;
while term.is_list() {
let cons = Cons::new(term).expect("valid cons cell");
len += 1;
term = cons.tail();
}
assert!(term.is_nil());
len
}