remove pstr_vec

This commit is contained in:
Mark Thom
2024-12-06 21:47:36 -08:00
committed by Mark Thom
parent 3c85ef2724
commit ae4d12a123
40 changed files with 2262 additions and 1891 deletions

View File

@@ -1,13 +1,71 @@
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use crate::atom_table::*;
use crate::machine::get_structure_index;
use crate::machine::heap::*;
use crate::machine::stack::*;
use crate::types::*;
use scryer_modular_bitfield::specifiers::*;
use scryer_modular_bitfield::*;
use std::collections::BTreeMap;
use std::mem;
use std::ops::{IndexMut, Range};
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
#[bits = 6]
enum TrailRefTag {
HeapCell = 0b001011,
StackCell = 0b001101,
AttrVar = 0b010001,
PStrLoc = 0b001111,
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct TrailRef {
val: B56,
#[allow(unused)]
m: bool,
#[allow(unused)]
f: bool,
tag: TrailRefTag,
}
impl TrailRef {
#[inline(always)]
fn heap_cell(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::HeapCell)
.with_val(h as u64)
}
#[inline(always)]
fn stack_cell(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::StackCell)
.with_val(h as u64)
}
#[inline(always)]
fn attr_var(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::AttrVar)
.with_val(h as u64)
}
#[inline(always)]
fn pstr_loc(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::PStrLoc)
.with_val(h as u64)
}
}
type Trail = Vec<(TrailRef, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub enum AttrVarPolicy {
@@ -18,15 +76,12 @@ pub enum AttrVarPolicy {
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn store(&self, value: HeapCellValue) -> HeapCellValue;
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
// fn push_cell(&mut self, value: HeapCellValue) -> Result<(), usize>;
fn push_attr_var_queue(&mut self, attr_var_loc: usize);
fn stack(&mut self) -> &mut Stack;
fn threshold(&self) -> usize;
// returns the tail location of the pstr on success
fn as_slice_from<'a>(&'a self, from: usize) -> Box<dyn Iterator<Item = u8> + 'a>;
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize>;
fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize;
fn pstr_at(&self, loc: usize) -> bool;
fn next_non_pstr_cell_index(&self, loc: usize) -> usize;
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize>;
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize>;
}
@@ -35,14 +90,25 @@ pub(crate) fn copy_term<T: CopierTarget>(
target: T,
addr: HeapCellValue,
attr_var_policy: AttrVarPolicy,
) -> Result<(), usize> {
) -> Result<usize, usize> {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
let old_threshold = copy_term_state.target.threshold();
copy_term_state.copy_term_impl(addr)?;
copy_term_state.copy_attr_var_lists()?;
copy_term_state.unwind_trail();
Ok(())
let new_threshold = copy_term_state.target.threshold();
copy_term_state.copy_pstrs()?;
Ok(new_threshold - old_threshold)
}
#[derive(Debug)]
pub struct PStrData {
pre_old_h_tail_loc: usize,
post_old_h_tail_loc: usize,
post_old_h_pstr_loc_locs: IndexSet<usize, FxBuildHasher>,
}
#[derive(Debug)]
@@ -53,6 +119,9 @@ struct CopyTermState<T: CopierTarget> {
target: T,
attr_var_policy: AttrVarPolicy,
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
// keys of pstr_loc_locs are byte indices rounded down to the
// nearest cell boundary
pstr_loc_locs: BTreeMap<usize, PStrData>,
}
impl<T: CopierTarget> CopyTermState<T> {
@@ -64,6 +133,7 @@ impl<T: CopierTarget> CopyTermState<T> {
target,
attr_var_policy,
attr_var_list_locs: vec![],
pstr_loc_locs: BTreeMap::new(),
}
}
@@ -74,7 +144,7 @@ impl<T: CopierTarget> CopyTermState<T> {
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
self.trail.push((Ref::heap_cell(addr), trail_item));
self.trail.push((TrailRef::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) -> Result<(), usize> {
@@ -93,7 +163,7 @@ impl<T: CopierTarget> CopyTermState<T> {
}
let threshold = self.target.threshold();
self.target.copy_slice_to_end(addr .. addr + 2)?;
self.target.copy_slice_to_end(addr..addr + 2)?;
*self.value_at_scan() = list_loc_as_cell!(threshold);
@@ -122,54 +192,90 @@ impl<T: CopierTarget> CopyTermState<T> {
Ok(())
}
/*
* write a null byte to the first word of a partial string to
* flag that it has been copied followed by the copied
* string's index in the next 7 bytes. write the bytes in big
* endian order so that the null byte is at index 0.
*/
fn write_pstr_index(&mut self, head_cell_idx: usize, threshold: usize) {
let bytes = u64::to_be_bytes(threshold as u64);
debug_assert_eq!(bytes[0], 0);
self.target[head_cell_idx] = HeapCellValue::from_bytes(bytes);
}
fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> {
let head_cell_idx = self.target.pstr_head_cell_index(pstr_loc);
let head_byte_idx = heap_index!(head_cell_idx);
let pstr_offset = pstr_loc - head_byte_idx;
// if a partial string has been copied previously, we
// track it by writing a null byte to its first word, which is trailed,
// and then the new pstr_loc in the word's remaining 7 bytes. see write_pstr_index
// comment.
if self.target[head_cell_idx].into_bytes()[0] == 0u8 {
let head_bytes = self.target[head_cell_idx].into_bytes();
let new_pstr_loc = u64::from_be_bytes(head_bytes) as usize;
*self.value_at_scan() = pstr_loc_as_cell!(heap_index!(new_pstr_loc) + pstr_offset);
self.scan += 1;
return Ok(());
match self.pstr_loc_locs.range_mut(..=pstr_loc).next_back() {
Some((
_prev_pstr_loc,
&mut PStrData {
pre_old_h_tail_loc,
ref mut post_old_h_pstr_loc_locs,
..
},
)) if pre_old_h_tail_loc >= cell_index!(pstr_loc) => {
post_old_h_pstr_loc_locs.insert(self.scan);
self.scan += 1;
return Ok(());
}
_ => {}
}
let threshold = self.target.threshold();
let tail_loc = self.target.copy_pstr_to_threshold(head_byte_idx)?;
let offset = self
.target
.as_slice_from(pstr_loc)
.take_while(|b| *b != 0u8)
.count();
*self.value_at_scan() = pstr_loc_as_cell!(heap_index!(threshold) + pstr_offset);
let left_pstr_boundary = cell_index!(pstr_loc + offset);
let flag = u64::from_be_bytes(self.target[left_pstr_boundary].into_bytes());
let pstr_loc_idx = cell_index!(pstr_loc);
self.trail.push((Ref::heap_cell(head_cell_idx), self.target[head_cell_idx]));
self.write_pstr_index(head_cell_idx, threshold);
if flag == 1 {
if left_pstr_boundary != pstr_loc_idx {
let mut pstr_data = self
.pstr_loc_locs
.remove(&heap_index!(left_pstr_boundary))
.unwrap();
let tail_cell = self.target[tail_loc];
let mut writer = self.target.reserve(1)?;
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
self.pstr_loc_locs
.insert(heap_index!(cell_index!(pstr_loc)), pstr_data);
writer.write_with(|section| {
section.push_cell(tail_cell);
});
let old_cell = self.target[pstr_loc_idx];
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
self.trail
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
} else {
let pstr_data = self
.pstr_loc_locs
.get_mut(&heap_index!(left_pstr_boundary))
.unwrap();
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
}
} else {
let old_cell = self.target[pstr_loc_idx];
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
self.trail
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
let old_tail_idx = if (pstr_loc + offset + 1) % Heap::heap_cell_alignment() == 0 {
cell_index!(pstr_loc + offset) + 2
} else {
cell_index!(pstr_loc + offset) + 1
};
let tail_cell = self.target[old_tail_idx];
let new_tail_idx = self.target.threshold();
let mut writer = self.target.reserve(1)?;
writer.write_with(|section| {
section.push_cell(tail_cell);
});
let mut post_old_h_pstr_loc_locs = IndexSet::with_hasher(FxBuildHasher::default());
post_old_h_pstr_loc_locs.insert(self.scan);
let pstr_data = PStrData {
pre_old_h_tail_loc: old_tail_idx,
post_old_h_tail_loc: new_tail_idx,
post_old_h_pstr_loc_locs,
};
self.pstr_loc_locs
.insert(heap_index!(pstr_loc_idx), pstr_data);
}
self.scan += 1;
Ok(())
}
@@ -210,6 +316,7 @@ impl<T: CopierTarget> CopyTermState<T> {
});
debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str);
self.copy_term_impl(str_cell)?;
list_addr = self.target[heap_loc + 1];
@@ -227,13 +334,13 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target[h] = heap_loc_as_cell!(frontier);
self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h)));
self.trail.push((TrailRef::heap_cell(h), heap_loc_as_cell!(h)));
}
(HeapCellValueTag::StackVar, s) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target.stack()[s] = heap_loc_as_cell!(frontier);
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
self.trail.push((TrailRef::stack_cell(s), stack_loc_as_cell!(s)));
}
(HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
@@ -245,10 +352,10 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = heap_loc_as_cell!(threshold);
self.target[h] = heap_loc_as_cell!(threshold);
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
self.trail.push((TrailRef::attr_var(h), attr_var_as_cell!(h)));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
let mut writer = self.target.reserve(2).unwrap();
let mut writer = self.target.reserve(2)?;
writer.write_with(|section| {
section.push_cell(attr_var_as_cell!(threshold));
@@ -256,7 +363,7 @@ impl<T: CopierTarget> CopyTermState<T> {
});
let old_list_link = self.target[h + 1];
self.trail.push((Ref::heap_cell(h + 1), old_list_link));
self.trail.push((TrailRef::heap_cell(h + 1), old_list_link));
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
if old_list_link.get_tag() == HeapCellValueTag::Lis {
@@ -317,7 +424,21 @@ impl<T: CopierTarget> CopyTermState<T> {
(HeapCellValueTag::Atom, (_name, arity)) => {
let threshold = self.target.threshold();
*self.value_at_scan() = str_loc_as_cell!(threshold);
let index_cell = self.target[addr.saturating_sub(1)];
*self.value_at_scan() = if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
let mut writer = self.target.reserve(1).unwrap();
writer.write_with(|section| {
section.push_cell(index_cell);
});
str_loc_as_cell!(threshold + 1)
} else {
str_loc_as_cell!(threshold)
};
self.target.copy_slice_to_end(addr .. addr + 1 + arity)?;
@@ -326,28 +447,7 @@ impl<T: CopierTarget> CopyTermState<T> {
str_loc_as_cell!(threshold),
);
self.trail.push((Ref::heap_cell(addr), trail_item));
/*
self.target.push(atom_as_cell!(name, arity));
for i in 0..arity {
let hcv = self.target[addr + 1 + i];
self.target.push(hcv);
}
*/
if !self.target.pstr_at(addr + 1 + arity) {
let index_cell = self.target[addr + 1 + arity];
if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
let mut writer = self.target.reserve(1).unwrap();
writer.write_with(|section| {
section.push_cell(index_cell);
});
}
}
self.trail.push((TrailRef::heap_cell(addr), trail_item));
}
(HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h);
@@ -370,11 +470,6 @@ impl<T: CopierTarget> CopyTermState<T> {
});
while self.scan < self.target.threshold() {
if self.target.pstr_at(self.scan) {
self.scan = self.target.next_non_pstr_cell_index(self.scan);
continue;
}
let addr = *self.value_at_scan();
read_heap_cell!(addr,
@@ -405,17 +500,40 @@ impl<T: CopierTarget> CopyTermState<T> {
Ok(())
}
fn unwind_trail(mut self) {
for (r, value) in self.trail {
let index = r.get_value() as usize;
fn copy_pstrs(&mut self) -> Result<(), usize> {
while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() {
let threshold = heap_index!(self.target.threshold());
match r.get_tag() {
RefTag::AttrVar | RefTag::HeapCell => {
for pstr_loc_loc in pstr_data.post_old_h_pstr_loc_locs {
let pstr_loc = self.target[pstr_loc_loc].get_value() as usize;
self.target[pstr_loc_loc] =
pstr_loc_as_cell!(threshold + pstr_loc - least_pstr_loc);
}
self.target.copy_pstr_to_threshold(least_pstr_loc)?;
let mut writer = self.target.reserve(1)?;
writer.write_with(|section| {
section.push_cell(heap_loc_as_cell!(pstr_data.post_old_h_tail_loc));
});
}
Ok(())
}
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(..) {
let index = r.val() as usize;
match r.tag() {
TrailRefTag::AttrVar | TrailRefTag::HeapCell => {
self.target[index] = value;
self.target[index].set_mark_bit(false);
self.target[index].set_forwarding_bit(false);
}
RefTag::StackCell => self.target.stack()[index] = value,
TrailRefTag::StackCell => self.target.stack()[index] = value,
TrailRefTag::PStrLoc => self.target[index] = value,
}
}
}
@@ -438,9 +556,10 @@ mod tests {
let a_atom = atom!("a");
let b_atom = atom!("b");
let mut functor_writer = Heap::functor_writer(
functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]),
);
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[atom_as_cell(a_atom), atom_as_cell(b_atom)]
));
functor_writer(&mut wam.machine_st.heap).unwrap();
@@ -480,29 +599,233 @@ mod tests {
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "abc ".len()),
"abc "
);
assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc ");
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
wam.machine_st.heap.slice_to_str(heap_index!(2), "def".len()),
wam.machine_st
.heap
.slice_to_str(heap_index!(2), "def".len()),
"def"
);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(5)));
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(9)));
assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(
wam.machine_st.heap.slice_to_str(heap_index!(5), "abc ".len()),
wam.machine_st
.heap
.slice_to_str(heap_index!(7), "abc ".len()),
"abc "
);
assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
assert_eq!(
wam.machine_st.heap.slice_to_str(heap_index!(7), "def".len()),
wam.machine_st
.heap
.slice_to_str(heap_index!(9), "def".len()),
"def"
);
assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(heap_index!(5)));
assert_eq!(wam.machine_st.heap[10], heap_loc_as_cell!(6));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("abc ");
section.push_cell(pstr_loc_as_cell!(heap_index!(2) + 9));
section.push_pstr("defdefdefdef");
section.push_cell(pstr_loc_as_cell!(0));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc ");
assert_eq!(
wam.machine_st.heap[1],
pstr_loc_as_cell!(heap_index!(2) + 9)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(2), "defdefdefdef".len()),
"defdefdefdef"
);
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.machine_st.heap[6],
pstr_loc_as_cell!(heap_index!(10) + 1)
);
assert_eq!(wam.machine_st.heap[7], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(8), "abc ".len()),
"abc "
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(6));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(10), "fdef".len()),
"fdef"
);
assert_eq!(wam.machine_st.heap[11], heap_loc_as_cell!(7));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0)));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(heap_index!(0)));
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(6)));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 9));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 9)
);
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 9)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 7));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 7)
);
assert_eq!(
wam.machine_st.heap[4],
pstr_loc_as_cell!(heap_index!(6) + 11)
);
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 7)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 12));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 12)
);
assert_eq!(
wam.machine_st.heap[4],
pstr_loc_as_cell!(heap_index!(6) + 3)
);
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 4)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "8912345".len()),
"8912345"
);
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
@@ -528,7 +851,6 @@ mod tests {
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom));
assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6));
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4));
assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom));