]> Repositorios git - scryer-prolog.git/commitdiff
relocate most instruction routines from MachineState to Machine
authorMark Thom <[email protected]>
Sat, 18 Dec 2021 05:02:20 +0000 (22:02 -0700)
committerMark Thom <[email protected]>
Fri, 7 Jan 2022 04:46:23 +0000 (21:46 -0700)
17 files changed:
Cargo.lock
Cargo.toml
src/clause_types.rs
src/heap_print.rs
src/instructions.rs
src/lib/iso_ext.pl
src/machine/code_repo.rs
src/machine/compile.rs
src/machine/dispatch.rs [new file with mode: 0644]
src/machine/machine_indices.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mock_wam.rs
src/machine/mod.rs
src/machine/preprocessor.rs
src/machine/system_calls.rs
src/macros.rs

index e706052a0b45cbef42db5cb171acb8cd68c79dbf..7818a0a4f75ac07de5d3a5c7dc6ef2a59fc4dca0 100644 (file)
@@ -289,12 +289,6 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
-[[package]]
-name = "downcast"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
-
 [[package]]
 name = "ed25519"
 version = "1.2.0"
@@ -1398,7 +1392,6 @@ dependencies = [
  "crossterm",
  "dirs-next",
  "divrem",
- "downcast",
  "git-version",
  "hostname",
  "indexmap",
index 000c117e07a179dac0bfa7b907157c76ff45010c..d0a332fba319806d9e243a120db39e4a1e4b6e8f 100644 (file)
@@ -31,7 +31,6 @@ cpu-time = "1.0.0"
 crossterm = "0.16.0"
 dirs-next = "2.0.0"
 divrem = "0.1.0"
-downcast = "0.10.0"
 git-version = "0.3.4"
 hostname = "0.3.1"
 indexmap = "1.0.2"
@@ -66,3 +65,6 @@ slice-deque = "0.3.0"
 assert_cmd = "1.0.3"
 predicates-core = "1.0.2"
 serial_test = "0.5.1"
+
+[profile.release]
+debug = true
\ No newline at end of file
index e11e84b16aeac74f5b5c175bf9f01f5702faf8f3..8083775a4ea2770f14137a197e28a69f8eb91f89 100644 (file)
@@ -799,11 +799,13 @@ impl SystemClauseType {
             (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair),
             (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
             (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult),
+            (atom!("$first_non_octet"), 2) => Some(SystemClauseType::FirstNonOctet),
             (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML),
             (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML),
             (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv),
             (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv),
             (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv),
+            (atom!("$shell"), 2) => Some(SystemClauseType::Shell),
             (atom!("$pid"), 1) => Some(SystemClauseType::PID),
             (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64),
             (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream),
@@ -847,6 +849,7 @@ impl SystemClauseType {
             (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify),
             (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory),
             (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook),
+            (atom!("$popcount"), 2) => Some(SystemClauseType::PopCount),
             _ => None,
         }
     }
index 6f320839a3e56b44cdfd7d06c47abea35799b10b..f942178895f135bd7f213f4e73a494cf2c1def33 100644 (file)
@@ -19,7 +19,7 @@ use crate::types::*;
 
 use ordered_float::OrderedFloat;
 
-use indexmap::{IndexMap, IndexSet};
+use indexmap::IndexMap;
 
 use std::cell::Cell;
 use std::convert::TryFrom;
@@ -490,11 +490,7 @@ pub struct HCPrinter<'a, Outputter> {
     op_dir: &'a OpDir,
     state_stack: Vec<TokenOrRedirect>,
     toplevel_spec: Option<DirectedOp>,
-    // heap_locs: ReverseHeapVarDict,
-    printed_vars: IndexSet<HeapCellValue>,
     last_item_idx: usize,
-    // cyclic_terms: IndexMap<HeapCellValue, usize>,
-    // non_cyclic_terms: IndexSet<usize>,
     pub var_names: IndexMap<HeapCellValue, Rc<String>>,
     pub numbervars_offset: Integer,
     pub numbervars: bool,
@@ -530,7 +526,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
             op_dir,
             state_stack: vec![],
             toplevel_spec: None,
-            printed_vars: IndexSet::new(),
             last_item_idx: 0,
             numbervars: false,
             numbervars_offset: Integer::from(0),
index 76c9c76cf8319df105ae74e1e3b189ccdefac8af..efaf4d5a8e0fb8b3ad7524a0fb20b7eb715e03f8 100644 (file)
@@ -339,7 +339,7 @@ pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
     }
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub enum ArithmeticInstruction {
     Add(ArithmeticTerm, ArithmeticTerm, usize),
     Sub(ArithmeticTerm, ArithmeticTerm, usize),
index 2127ca8ac51978c585586fd02498c47b6564e41b..37044a405a34671594e6fd8d7e44a2026ad29b19 100644 (file)
@@ -98,7 +98,8 @@ scc_helper(_, _, _) :-
 
 :- non_counted_backtracking run_cleaners_with_handling/0.
 run_cleaners_with_handling :-
-    '$get_scc_cleaner'(C), '$get_level'(B),
+    '$get_scc_cleaner'(C),
+    '$get_level'(B),
     '$call_with_default_policy'(catch(C, _, true)),
     '$set_cp_by_default'(B),
     '$call_with_default_policy'(run_cleaners_with_handling).
index ba046228bfe1747187fbb5cb697860e251cd0cd5..f6fb6aa0b62d7f3cc2955bfd107cfcd07c660b40 100644 (file)
@@ -1,8 +1,35 @@
 use crate::clause_types::*;
 use crate::instructions::*;
-use crate::machine::MachineState;
+use crate::machine::{Machine, MachineState};
 use crate::machine::machine_indices::*;
 
+use std::fmt;
+
+pub(crate) enum OwnedOrIndexed {
+    Indexed(usize),
+    Owned(Line),
+}
+
+impl fmt::Debug for OwnedOrIndexed {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            &OwnedOrIndexed::Indexed(ref index) => write!(f, "Indexed({:?})", index),
+            &OwnedOrIndexed::Owned(ref owned) => write!(f, "Owned({:?})", owned),
+        }
+    }
+}
+
+impl OwnedOrIndexed {
+    #[inline(always)]
+    pub(crate) fn as_ref<'a>(&'a self, code: &'a Code) -> &'a Line {
+        match self {
+            &OwnedOrIndexed::Indexed(p) => &code[p],
+            &OwnedOrIndexed::Owned(ref r) => r,
+        }
+    }
+}
+
+
 // TODO: remove this, replace with just 'Code'.
 #[derive(Debug)]
 pub struct CodeRepo {
@@ -10,7 +37,7 @@ pub struct CodeRepo {
 }
 
 impl CodeRepo {
-    pub(super) fn lookup_instr<'a>(&'a self, machine_st: &MachineState, p: &CodePtr) -> Option<RefOrOwned<'a, Line>> {
+    pub(super) fn lookup_instr(&self, machine_st: &MachineState, p: &CodePtr) -> Option<OwnedOrIndexed> {
         match p {
             &CodePtr::Local(local) => {
                 return Some(self.lookup_local_instr(machine_st, local));
@@ -24,18 +51,18 @@ impl CodeRepo {
                     machine_st.last_call
                 );
 
-                Some(RefOrOwned::Owned(call_clause))
+                Some(OwnedOrIndexed::Owned(call_clause))
             }
             &CodePtr::CallN(arity, _, last_call) => {
                 let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
-                Some(RefOrOwned::Owned(call_clause))
+                Some(OwnedOrIndexed::Owned(call_clause))
             }
-            &CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
+            &CodePtr::VerifyAttrInterrupt(p) => Some(OwnedOrIndexed::Indexed(p)),
         }
     }
 
     #[inline]
-    pub(super) fn lookup_local_instr<'a>(&'a self, machine_st: &MachineState, p: LocalCodePtr) -> RefOrOwned<'a, Line> {
+    pub(super) fn lookup_local_instr(&self, machine_st: &MachineState, p: LocalCodePtr) -> OwnedOrIndexed {
         match p {
             LocalCodePtr::Halt => {
                 // exit with the interrupt exit code.
@@ -45,32 +72,36 @@ impl CodeRepo {
                 &Line::IndexingCode(ref indexing_lines) => {
                     match &indexing_lines[machine_st.oip as usize] {
                         &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
-                            RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize]))
+                            OwnedOrIndexed::Owned(
+                                Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize])
+                            )
                         }
                         &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
-                            RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize]))
+                            OwnedOrIndexed::Owned(
+                                Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize])
+                            )
                         }
                         _ => {
-                            RefOrOwned::Borrowed(&self.code[p as usize])
+                            OwnedOrIndexed::Indexed(p)
                         }
                     }
                 }
-                _ => RefOrOwned::Borrowed(&self.code[p as usize]),
+                _ => OwnedOrIndexed::Indexed(p)
             }
         }
     }
 }
 
-impl MachineState {
-    pub(super) fn find_living_dynamic_else(&self, code: &Code, mut p: usize) -> Option<(usize, usize)> {
+impl Machine {
+    pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
         loop {
-            match &code[p] {
+            match &self.code_repo.code[p] {
                 &Line::Choice(ChoiceInstruction::DynamicElse(
                     birth,
                     death,
                     NextOrFail::Next(i),
                 )) => {
-                    if birth < self.cc && Death::Finite(self.cc) <= death {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
                         return Some((p, i));
                     } else if i > 0 {
                         p += i;
@@ -83,7 +114,7 @@ impl MachineState {
                     death,
                     NextOrFail::Fail(_),
                 )) => {
-                    if birth < self.cc && Death::Finite(self.cc) <= death {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
                         return Some((p, 0));
                     } else {
                         return None;
@@ -94,7 +125,7 @@ impl MachineState {
                     death,
                     NextOrFail::Next(i),
                 )) => {
-                    if birth < self.cc && Death::Finite(self.cc) <= death {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
                         return Some((p, i));
                     } else if i > 0 {
                         p += i;
@@ -107,7 +138,7 @@ impl MachineState {
                     death,
                     NextOrFail::Fail(_),
                 )) => {
-                    if birth < self.cc && Death::Finite(self.cc) <= death {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
                         return Some((p, 0));
                     } else {
                         return None;
@@ -123,10 +154,10 @@ impl MachineState {
         }
     }
 
-    pub(super) fn find_living_dynamic(&self, code: &Code, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
-        let p = self.p.local().abs_loc();
+    pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
+        let p = self.machine_st.p.local().abs_loc();
 
-        let indexed_choice_instrs = match &code[p] {
+        let indexed_choice_instrs = match &self.code_repo.code[p] {
             Line::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
                 IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
                     indexed_choice_instrs
@@ -138,13 +169,13 @@ impl MachineState {
 
         loop {
             match &indexed_choice_instrs.get(ii as usize) {
-                Some(&offset) => match &code[p + offset - 1] {
+                Some(&offset) => match &self.code_repo.code[p + offset - 1] {
                     &Line::Choice(ChoiceInstruction::DynamicInternalElse(
                         birth,
                         death,
                         next_or_fail,
                     )) => {
-                        if birth < self.cc && Death::Finite(self.cc) <= death {
+                        if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
                             return Some((offset, oi, ii, next_or_fail.is_next()));
                         } else {
                             ii += 1;
index 72ec57c4dbe80266e2c992d6ee1b57c0cc096e7b..8b69ced815e5cda5b58b67dd45e303f2a5e2d0ec 100644 (file)
@@ -1371,12 +1371,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         term: Term,
         settings: CodeGenSettings,
     ) -> Result<StandaloneCompileResult, SessionError> {
-        let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags);
+        let mut preprocessor = Preprocessor::new();
 
         let clause = self.try_term_to_tl(term, &mut preprocessor)?;
         let queue = preprocessor.parse_queue(self)?;
 
-        let mut cg = CodeGenerator::<DebrayAllocator>::new(&mut LS::machine_st(&mut self.payload).atom_tbl, settings);
+        let mut cg = CodeGenerator::<DebrayAllocator>::new(
+            &mut LS::machine_st(&mut self.payload).atom_tbl,
+            settings,
+        );
+
         let mut clause_code = cg.compile_predicate(&vec![clause])?;
 
         compile_appendix(
@@ -1405,7 +1409,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let mut code_ptr = code_len;
 
         let mut clauses = vec![];
-        let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags);
+        let mut preprocessor = Preprocessor::new();
 
         for term in predicates.predicates.drain(0..) {
             clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs
new file mode 100644 (file)
index 0000000..9b02d19
--- /dev/null
@@ -0,0 +1,1279 @@
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::instructions::*;
+use crate::machine::*;
+use crate::machine::arithmetic_ops::*;
+use crate::machine::code_repo::*;
+use crate::machine::machine_errors::*;
+use crate::machine::machine_state::*;
+use crate::types::*;
+
+use crate::try_numeric_result;
+
+impl Machine {
+    #[inline(always)]
+    pub(super) fn dispatch_instr(&mut self, instr: OwnedOrIndexed) {
+        match instr.as_ref(&self.code_repo.code) {
+            &Line::Arithmetic(ref arith_instr) => {
+                let stub_gen = || functor_stub(atom!("is"), 2);
+
+                match arith_instr {
+                    &ArithmeticInstruction::Add(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Max(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            max(n1, n2)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Min(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            min(n1, n2)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            int_pow(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            gcd(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            pow(n1, n2, atom!("**"))
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
+                        let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
+
+                        let r1 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a1, stub_gen));
+                        let r2 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a2, stub_gen));
+
+                        self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
+                            try_or_fail_gen!(&mut self.machine_st, rdiv(r1, r2)),
+                            self.machine_st.arena
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            int_floor_div(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            idiv(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Abs(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Sign(ref a1, t) => {
+                        let n = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = sign(n);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Neg(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::BitwiseComplement(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            bitwise_complement(n1, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Div(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            div(n1, n2)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Shr(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            shr(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Shl(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            shl(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Xor(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            xor(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::And(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            and(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Or(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            or(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Mod(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            modulus(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Rem(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
+                            &mut self.machine_st,
+                            remainder(n1, n2, &mut self.machine_st.arena)
+                        );
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Cos(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, cos(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Sin(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, sin(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Tan(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, tan(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Sqrt(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, sqrt(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Log(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, log(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Exp(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, exp(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::ACos(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, acos(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::ASin(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, asin(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::ATan(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, atan(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, atan2(n1, n2))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Float(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                            try_or_fail_gen!(&mut self.machine_st, float(n1))
+                        ));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Truncate(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Round(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] =
+                            try_or_fail_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena));
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Ceiling(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Floor(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena);
+                        self.machine_st.p += 1;
+                    }
+                    &ArithmeticInstruction::Plus(ref a1, t) => {
+                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+
+                        self.machine_st.interms[t - 1] = n1;
+                        self.machine_st.p += 1;
+                    }
+                }
+            }
+            &Line::Choice(ref choice_instr) => {
+                match choice_instr {
+                    &ChoiceInstruction::DynamicElse(..) => {
+                        if let FirstOrNext::First = self.machine_st.dynamic_mode {
+                            self.machine_st.cc = self.machine_st.global_clock;
+                        }
+
+                        let p = self.machine_st.p.local().abs_loc();
+
+                        match self.find_living_dynamic_else(p) {
+                            Some((p, next_i)) => {
+                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+
+                                match self.machine_st.dynamic_mode {
+                                    FirstOrNext::First if next_i == 0 => {
+                                        self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
+                                    }
+                                    FirstOrNext::First => {
+                                        self.machine_st.cc = self.machine_st.global_clock;
+
+                                        match self.find_living_dynamic_else(p + next_i) {
+                                            Some(_) => {
+                                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                                self.machine_st.num_of_args += 1;
+                                                self.machine_st.try_me_else(next_i);
+                                                self.machine_st.num_of_args -= 1;
+                                            }
+                                            None => {
+                                                self.machine_st.p += 1;
+                                            }
+                                        }
+                                    }
+                                    FirstOrNext::Next => {
+                                        let n = self.machine_st
+                                            .stack
+                                            .index_or_frame(self.machine_st.b)
+                                            .prelude
+                                            .univ_prelude
+                                            .num_cells;
+
+                                        self.machine_st.cc = cell_as_fixnum!(
+                                            self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+                                        ).get_num() as usize;
+
+                                        if next_i > 0 {
+                                            match self.find_living_dynamic_else(p + next_i) {
+                                                Some(_) => {
+                                                    self.retry_me_else(next_i);
+
+                                                    try_or_fail!(
+                                                        self.machine_st,
+                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                    );
+                                                }
+                                                None => {
+                                                    self.trust_me();
+
+                                                    try_or_fail!(
+                                                        self.machine_st,
+                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                    );
+                                                }
+                                            }
+                                        } else {
+                                            self.trust_me();
+
+                                            try_or_fail!(
+                                                self.machine_st,
+                                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                            );
+                                        }
+                                    }
+                                }
+                            }
+                            None => {
+                                self.machine_st.fail = true;
+                            }
+                        }
+
+                        self.machine_st.dynamic_mode = FirstOrNext::Next;
+                    }
+                    &ChoiceInstruction::DynamicInternalElse(..) => {
+                        let p = self.machine_st.p.local().abs_loc();
+
+                        match self.find_living_dynamic_else(p) {
+                            Some((p, next_i)) => {
+                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+
+                                match self.machine_st.dynamic_mode {
+                                    FirstOrNext::First if next_i == 0 => {
+                                        self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
+                                    }
+                                    FirstOrNext::First => {
+                                        match self.find_living_dynamic_else(p + next_i) {
+                                            Some(_) => {
+                                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                                self.machine_st.num_of_args += 1;
+                                                self.machine_st.try_me_else(next_i);
+                                                self.machine_st.num_of_args -= 1;
+                                            }
+                                            None => {
+                                                self.machine_st.p += 1;
+                                            }
+                                        }
+                                    }
+                                    FirstOrNext::Next => {
+                                        let n = self.machine_st
+                                            .stack
+                                            .index_or_frame(self.machine_st.b)
+                                            .prelude
+                                            .univ_prelude
+                                            .num_cells;
+
+                                        self.machine_st.cc = cell_as_fixnum!(
+                                            self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+                                        ).get_num() as usize;
+
+                                        if next_i > 0 {
+                                            match self.find_living_dynamic_else(p + next_i) {
+                                                Some(_) => {
+                                                    self.retry_me_else(next_i);
+
+                                                    try_or_fail!(
+                                                        self.machine_st,
+                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                    );
+                                                }
+                                                None => {
+                                                    self.trust_me();
+
+                                                    try_or_fail!(
+                                                        self.machine_st,
+                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                    );
+                                                }
+                                            }
+                                        } else {
+                                            self.trust_me();
+
+                                            try_or_fail!(
+                                                self.machine_st,
+                                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                            );
+                                        }
+                                    }
+                                }
+                            }
+                            None => {
+                                self.machine_st.fail = true;
+                            }
+                        }
+
+                        self.machine_st.dynamic_mode = FirstOrNext::Next;
+                    }
+                    &ChoiceInstruction::TryMeElse(offset) => {
+                        self.machine_st.try_me_else(offset);
+                    }
+                    &ChoiceInstruction::DefaultRetryMeElse(offset) => {
+                        self.retry_me_else(offset);
+                    }
+                    &ChoiceInstruction::DefaultTrustMe(_) => {
+                        self.trust_me();
+                    }
+                    &ChoiceInstruction::RetryMeElse(offset) => {
+                        self.retry_me_else(offset);
+
+                        try_or_fail!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                    &ChoiceInstruction::TrustMe(_) => {
+                        self.trust_me();
+
+                        try_or_fail!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+            }
+            &Line::Cut(ref cut_instr) => {
+                match cut_instr {
+                    &CutInstruction::NeckCut => {
+                        let b = self.machine_st.b;
+                        let b0 = self.machine_st.b0;
+
+                        if b > b0 {
+                            self.machine_st.b = b0;
+
+                            if b > self.machine_st.e {
+                                self.machine_st.stack.truncate(b);
+                            }
+                        }
+
+                        self.machine_st.p += 1;
+                    }
+                    &CutInstruction::GetLevel(r) => {
+                        let b0 = self.machine_st.b0;
+
+                        self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64));
+                        self.machine_st.p += 1;
+                    }
+                    &CutInstruction::GetLevelAndUnify(r) => {
+                        let b0 = self.machine_st[perm_v!(1)];
+                        let a = self.machine_st[r];
+
+                        unify_fn!(&mut self.machine_st, a, b0);
+                        self.machine_st.p += 1;
+                    }
+                    &CutInstruction::Cut(r) => {
+                        let value = self.machine_st[r];
+                        self.machine_st.cut_body(value);
+
+                        if !self.machine_st.fail && !(self.machine_st.run_cleaners_fn)(self) {
+                            self.machine_st.p += 1;
+                        }
+                    }
+                }
+            }
+            &Line::Control(ref ctrl_instr) => {
+                match ctrl_instr {
+                    &ControlInstruction::Allocate(num_cells) =>
+                        self.machine_st.allocate(num_cells),
+                    &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => {
+                        let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
+
+                        match INTERRUPT.compare_exchange(
+                            interrupted,
+                            false,
+                            std::sync::atomic::Ordering::Relaxed,
+                            std::sync::atomic::Ordering::Relaxed,
+                        ) {
+                            Ok(interruption) => {
+                                if interruption {
+                                    self.machine_st.throw_interrupt_exception();
+                                    return;
+                                }
+                            }
+                            Err(_) => unreachable!(),
+                        }
+
+                        self.machine_st.last_call = lco;
+
+                        match ct {
+                            &ClauseType::BuiltIn(ref ct) => {
+                                let ct = ct.clone();
+
+                                try_or_fail!(
+                                    self.machine_st,
+                                    self.call_builtin(&ct)
+                                );
+
+                                if !use_default_cp {
+                                    try_or_fail!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                            }
+                            &ClauseType::CallN => {
+                                try_or_fail!(
+                                    self.machine_st,
+                                    self.call_n(atom!("user"), arity)
+                                );
+
+                                if !use_default_cp {
+                                    try_or_fail!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                            }
+                            &ClauseType::Inlined(ref ct) => {
+                                let ct = ct.clone();
+                                self.execute_inlined(&ct);
+
+                                if lco {
+                                    self.machine_st.p = CodePtr::Local(self.machine_st.cp);
+                                }
+                            }
+                            &ClauseType::Named(name, _, ref idx) => {
+                                let idx = idx.clone();
+
+                                try_or_fail!(
+                                    self.machine_st,
+                                    self.context_call(name, arity, idx) // TODO: change to idx.get() ???
+                                );
+
+                                if !use_default_cp {
+                                    try_or_fail!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                            }
+                            &ClauseType::System(ref ct) => {
+                                let ct = ct.clone();
+
+                                try_or_fail!(
+                                    self.machine_st,
+                                    self.system_call(&ct)
+                                );
+                            }
+                        };
+
+                        self.machine_st.last_call = false;
+                    }
+                    &ControlInstruction::Deallocate =>
+                        self.machine_st.deallocate(),
+                    &ControlInstruction::JmpBy(arity, offset, _, lco) => {
+                        if !lco {
+                            self.machine_st.cp.assign_if_local(self.machine_st.p.clone() + 1);
+                        }
+
+                        self.machine_st.num_of_args = arity;
+                        self.machine_st.b0 = self.machine_st.b;
+                        self.machine_st.p += offset;
+                    }
+                    &ControlInstruction::RevJmpBy(offset) => {
+                        self.machine_st.p -= offset;
+                    }
+                    &ControlInstruction::Proceed => {
+                        self.machine_st.p = CodePtr::Local(self.machine_st.cp);
+                    }
+                }
+            }
+            &Line::Fact(ref fact_instr) => {
+                match fact_instr {
+                    &FactInstruction::GetConstant(_, c, reg) => {
+                        let value = self.machine_st.deref(self.machine_st[reg]);
+                        self.machine_st.write_literal_to_var(value, c);
+                    }
+                    &FactInstruction::GetList(_, reg) => {
+                        let deref_v = self.machine_st.deref(self.machine_st[reg]);
+                        let store_v = self.machine_st.store(deref_v);
+
+                        read_heap_cell!(store_v,
+                            (HeapCellValueTag::PStrLoc, h) => {
+                                let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h);
+
+                                self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize);
+                                self.machine_st.mode = MachineMode::Read;
+                            }
+                            (HeapCellValueTag::CStr) => {
+                                let h = self.machine_st.heap.len();
+                                self.machine_st.heap.push(store_v);
+
+                                self.machine_st.s = HeapPtr::PStrChar(h, 0);
+                                self.machine_st.mode = MachineMode::Read;
+                            }
+                            (HeapCellValueTag::Lis, l) => {
+                                self.machine_st.s = HeapPtr::HeapCell(l);
+                                self.machine_st.mode = MachineMode::Read;
+                            }
+                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                                let h = self.machine_st.heap.len();
+
+                                self.machine_st.heap.push(list_loc_as_cell!(h+1));
+                                self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+
+                                self.machine_st.mode = MachineMode::Write;
+                            }
+                            _ => {
+                                self.machine_st.fail = true;
+                            }
+                        );
+                    }
+                    &FactInstruction::GetPartialString(_, string, reg, has_tail) => {
+                        let deref_v = self.machine_st.deref(self.machine_st[reg]);
+                        let store_v = self.machine_st.store(deref_v);
+
+                        read_heap_cell!(store_v,
+                            (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+                             HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
+                             HeapCellValueTag::StackVar | HeapCellValueTag::Var |
+                             HeapCellValueTag::CStr) => {
+                                self.machine_st.match_partial_string(store_v, string, has_tail);
+                            }
+                            _ => {
+                                self.machine_st.fail = true;
+                            }
+                        );
+                    }
+                    &FactInstruction::GetStructure(ref ct, arity, reg) => {
+                        let deref_v = self.machine_st.deref(self.machine_st[reg]);
+                        let store_v = self.machine_st.store(deref_v);
+
+                        read_heap_cell!(store_v,
+                            (HeapCellValueTag::Str, a) => {
+                                let result = self.machine_st.heap[a];
+
+                                read_heap_cell!(result,
+                                    (HeapCellValueTag::Atom, (name, narity)) => {
+                                        if narity == arity && ct.name() == name {
+                                            self.machine_st.s = HeapPtr::HeapCell(a + 1);
+                                            self.machine_st.mode = MachineMode::Read;
+                                        } else {
+                                            self.machine_st.fail = true;
+                                        }
+                                    }
+                                    _ => {
+                                        unreachable!();
+                                    }
+                                );
+                            }
+                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                                let h = self.machine_st.heap.len();
+
+                                self.machine_st.heap.push(str_loc_as_cell!(h+1));
+                                self.machine_st.heap.push(atom_as_cell!(ct.name(), arity));
+
+                                self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+
+                                self.machine_st.mode = MachineMode::Write;
+                            }
+                            _ => {
+                                self.machine_st.fail = true;
+                            }
+                        );
+                    }
+                    &FactInstruction::GetVariable(norm, arg) => {
+                        self.machine_st[norm] = self.machine_st.registers[arg];
+                    }
+                    &FactInstruction::GetValue(norm, arg) => {
+                        let norm_addr = self.machine_st[norm];
+                        let reg_addr = self.machine_st.registers[arg];
+
+                        unify_fn!(&mut self.machine_st, norm_addr, reg_addr);
+                    }
+                    &FactInstruction::UnifyConstant(v) => {
+                        match self.machine_st.mode {
+                            MachineMode::Read => {
+                                let addr = self.machine_st.read_s();
+
+                                self.machine_st.write_literal_to_var(addr, v);
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                            MachineMode::Write => {
+                                self.machine_st.heap.push(v);
+                            }
+                        };
+                    }
+                    &FactInstruction::UnifyVariable(reg) => {
+                        match self.machine_st.mode {
+                            MachineMode::Read => {
+                                self.machine_st[reg] = self.machine_st.read_s();
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                            MachineMode::Write => {
+                                let h = self.machine_st.heap.len();
+
+                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                self.machine_st[reg] = heap_loc_as_cell!(h);
+                            }
+                        };
+                    }
+                    &FactInstruction::UnifyLocalValue(reg) => {
+                        match self.machine_st.mode {
+                            MachineMode::Read => {
+                                let reg_addr = self.machine_st[reg];
+                                let value = self.machine_st.read_s();
+
+                                unify_fn!(&mut self.machine_st, reg_addr, value);
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                            MachineMode::Write => {
+                                let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg]));
+                                let h = self.machine_st.heap.len();
+
+                                read_heap_cell!(value,
+                                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
+                                        let value = self.machine_st.heap[hc];
+
+                                        self.machine_st.heap.push(value);
+                                        self.machine_st.increment_s_ptr(1);
+                                    }
+                                    _ => {
+                                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                        (self.machine_st.bind_fn)(
+                                            &mut self.machine_st,
+                                            Ref::heap_cell(h),
+                                            value,
+                                        );
+                                    }
+                                );
+                            }
+                        };
+                    }
+                    &FactInstruction::UnifyValue(reg) => {
+                        match self.machine_st.mode {
+                            MachineMode::Read => {
+                                let reg_addr = self.machine_st[reg];
+                                let value = self.machine_st.read_s();
+
+                                unify_fn!(&mut self.machine_st, reg_addr, value);
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                            MachineMode::Write => {
+                                let h = self.machine_st.heap.len();
+                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+
+                                let addr = self.machine_st.store(self.machine_st[reg]);
+                                (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+                                // the former code of this match arm was:
+
+                                // let addr = self.machine_st.store(self.machine_st[reg]);
+                                // self.machine_st.heap.push(HeapCellValue::Addr(addr));
+
+                                // the old code didn't perform the occurs
+                                // check when enabled and so it was changed to
+                                // the above, which is only slightly less
+                                // efficient when the occurs_check is disabled.
+                            }
+                        };
+                    }
+                    &FactInstruction::UnifyVoid(n) => {
+                        match self.machine_st.mode {
+                            MachineMode::Read => {
+                                self.machine_st.increment_s_ptr(n);
+                            }
+                            MachineMode::Write => {
+                                let h = self.machine_st.heap.len();
+
+                                for i in h..h + n {
+                                    self.machine_st.heap.push(heap_loc_as_cell!(i));
+                                }
+                            }
+                        };
+                    }
+                }
+                self.machine_st.p += 1;
+            }
+            &Line::IndexingCode(ref indexing_lines) => {
+                #[inline(always)]
+                fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
+                    match &machine.code_repo.code[p] {
+                        Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {
+                            machine.machine_st.dynamic_mode = FirstOrNext::First;
+                            return true;
+                        }
+                        _ => {}
+                    }
+
+                    match &machine.code_repo.code[p - 1] {
+                        &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
+                            if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death {
+                                return true;
+                            } else {
+                                return false;
+                            }
+                        }
+                        _ => {}
+                    }
+
+                    true
+                }
+
+                let mut index = 0;
+                let addr = match &indexing_lines[0] {
+                    &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg]))
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                };
+
+                loop {
+                    match &indexing_lines[index] {
+                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
+                            let offset = read_heap_cell!(addr,
+                                (HeapCellValueTag::Var |
+                                 HeapCellValueTag::StackVar |
+                                 HeapCellValueTag::AttrVar) => {
+                                    v
+                                }
+                                (HeapCellValueTag::PStrLoc |
+                                 HeapCellValueTag::Lis |
+                                 HeapCellValueTag::CStr) => {
+                                    l
+                                }
+                                (HeapCellValueTag::Fixnum |
+                                 HeapCellValueTag::Char |
+                                 HeapCellValueTag::F64) => {
+                                    c
+                                }
+                                (HeapCellValueTag::Atom, (_name, arity)) => {
+                                    // if arity == 0 { c } else { s }
+                                    debug_assert!(arity == 0);
+                                    c
+                                }
+                                (HeapCellValueTag::Str) => {
+                                    s
+                                }
+                                (HeapCellValueTag::Cons, ptr) => {
+                                    match ptr.get_tag() {
+                                        ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
+                                        ArenaHeaderTag::F64 => {
+                                            c
+                                        }
+                                        _ => {
+                                            IndexingCodePtr::Fail
+                                        }
+                                    }
+                                }
+                                _ => {
+                                    unreachable!();
+                                }
+                            );
+
+                            match offset {
+                                IndexingCodePtr::Fail => {
+                                    self.machine_st.fail = true;
+                                    break;
+                                }
+                                IndexingCodePtr::DynamicExternal(o) => {
+                                    // either points directly to a
+                                    // DynamicInternalElse, or just ahead of
+                                    // one. Or neither!
+                                    let p = self.machine_st.p.local().abs_loc();
+
+                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                        self.machine_st.fail = true;
+                                    } else {
+                                        self.machine_st.p += o;
+                                    }
+
+                                    break;
+                                }
+                                IndexingCodePtr::External(o) => {
+                                    self.machine_st.p += o;
+                                    break;
+                                }
+                                IndexingCodePtr::Internal(o) => {
+                                    index += o;
+                                }
+                            }
+                        }
+                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
+                            let lit = read_heap_cell!(addr,
+                                (HeapCellValueTag::Char, c) => {
+                                    Literal::Char(c)
+                                }
+                                (HeapCellValueTag::Fixnum, n) => {
+                                    Literal::Fixnum(n)
+                                }
+                                (HeapCellValueTag::F64, f) => {
+                                    Literal::Float(f)
+                                }
+                                (HeapCellValueTag::Atom, (atom, arity)) => {
+                                    debug_assert_eq!(arity, 0);
+                                    Literal::Atom(atom)
+                                }
+                                (HeapCellValueTag::Cons, cons_ptr) => {
+                                    match_untyped_arena_ptr!(cons_ptr,
+                                        (ArenaHeaderTag::Rational, r) => {
+                                            Literal::Rational(r)
+                                        }
+                                        (ArenaHeaderTag::F64, f) => {
+                                            Literal::Float(F64Ptr(f))
+                                        }
+                                        (ArenaHeaderTag::Integer, n) => {
+                                            Literal::Integer(n)
+                                        }
+                                        _ => {
+                                            unreachable!()
+                                        }
+                                    )
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            );
+
+                            let offset = match hm.get(&lit) {
+                                Some(offset) => *offset,
+                                _ => IndexingCodePtr::Fail,
+                            };
+
+                            match offset {
+                                IndexingCodePtr::Fail => {
+                                    self.machine_st.fail = true;
+                                    break;
+                                }
+                                IndexingCodePtr::DynamicExternal(o) => {
+                                    // either points directly to a
+                                    // DynamicInternalElse, or just ahead of
+                                    // one. Or neither!
+                                    let p = self.machine_st.p.local().abs_loc();
+
+                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                        self.machine_st.fail = true;
+                                    } else {
+                                        self.machine_st.p += o;
+                                    }
+
+                                    break;
+                                }
+                                IndexingCodePtr::External(o) => {
+                                    self.machine_st.p += o;
+                                    break;
+                                }
+                                IndexingCodePtr::Internal(o) => {
+                                    index += o;
+                                }
+                            }
+                        }
+                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
+                            let offset = read_heap_cell!(addr,
+                                (HeapCellValueTag::Atom, (name, arity)) => {
+                                    match hm.get(&(name, arity)) {
+                                        Some(offset) => *offset,
+                                        None => IndexingCodePtr::Fail,
+                                    }
+                                }
+                                (HeapCellValueTag::Str, s) => {
+                                    let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                                        .get_name_and_arity();
+
+                                    match hm.get(&(name, arity)) {
+                                        Some(offset) => *offset,
+                                        None => IndexingCodePtr::Fail,
+                                    }
+                                }
+                                _ => {
+                                    IndexingCodePtr::Fail
+                                }
+                            );
+
+                            match offset {
+                                IndexingCodePtr::Fail => {
+                                    self.machine_st.fail = true;
+                                    break;
+                                }
+                                IndexingCodePtr::DynamicExternal(o) => {
+                                    let p = self.machine_st.p.local().abs_loc();
+
+                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                        self.machine_st.fail = true;
+                                    } else {
+                                        self.machine_st.p += o;
+                                    }
+
+                                    break;
+                                }
+                                IndexingCodePtr::External(o) => {
+                                    self.machine_st.p += o;
+                                    break;
+                                }
+                                IndexingCodePtr::Internal(o) => {
+                                    index += o;
+                                }
+                            }
+                        }
+                        &IndexingLine::IndexedChoice(_) => {
+                            if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() {
+                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+                                self.machine_st.oip = index as u32;
+                                self.machine_st.iip = 0;
+                            } else {
+                                unreachable!()
+                            }
+
+                            break;
+                        }
+                        &IndexingLine::DynamicIndexedChoice(_) => {
+                            self.machine_st.dynamic_mode = FirstOrNext::First;
+
+                            if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() {
+                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+                                self.machine_st.oip = index as u32;
+                                self.machine_st.iip = 0;
+                            } else {
+                                unreachable!()
+                            }
+
+                            break;
+                        }
+                    }
+                }
+            }
+            &Line::IndexedChoice(ref choice_instr) => {
+                match choice_instr {
+                    &IndexedChoiceInstruction::Try(offset) => {
+                        self.machine_st.indexed_try(offset);
+                    }
+                    &IndexedChoiceInstruction::Retry(l) => {
+                        self.retry(l);
+
+                        try_or_fail!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                    &IndexedChoiceInstruction::Trust(l) => {
+                        self.trust(l);
+
+                        try_or_fail!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+            }
+            &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(),
+            &Line::Query(ref query_instr) => {
+                match query_instr {
+                    &QueryInstruction::GetVariable(norm, arg) => {
+                        self.machine_st[norm] = self.machine_st.registers[arg];
+                    }
+                    &QueryInstruction::PutConstant(_, c, reg) => {
+                        self.machine_st[reg] = c;
+                    }
+                    &QueryInstruction::PutList(_, reg) => {
+                        self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len());
+                    }
+                    &QueryInstruction::PutPartialString(_, string, reg, has_tail) => {
+                        let pstr_addr = if has_tail {
+                            if string != atom!("") {
+                                let h = self.machine_st.heap.len();
+                                self.machine_st.heap.push(string_as_pstr_cell!(string));
+
+                                // the tail will be pushed by the next
+                                // instruction, so don't push one here.
+
+                                pstr_loc_as_cell!(h)
+                            } else {
+                                empty_list_as_cell!()
+                            }
+                        } else {
+                            string_as_cstr_cell!(string)
+                        };
+
+                        self.machine_st[reg] = pstr_addr;
+                    }
+                    &QueryInstruction::PutStructure(ref ct, arity, reg) => {
+                        let h = self.machine_st.heap.len();
+
+                        self.machine_st.heap.push(atom_as_cell!(ct.name(), arity));
+                        self.machine_st[reg] = str_loc_as_cell!(h);
+                    }
+                    &QueryInstruction::PutUnsafeValue(n, arg) => {
+                        let s = stack_loc!(AndFrame, self.machine_st.e, n);
+                        let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s)));
+
+                        if addr.is_protected(self.machine_st.e) {
+                            self.machine_st.registers[arg] = addr;
+                        } else {
+                            let h = self.machine_st.heap.len();
+
+                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+                            (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+                            self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+                        }
+                    }
+                    &QueryInstruction::PutValue(norm, arg) => {
+                        self.machine_st.registers[arg] = self.machine_st[norm];
+                    }
+                    &QueryInstruction::PutVariable(norm, arg) => {
+                        match norm {
+                            RegType::Perm(n) => {
+                                self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n);
+                                self.machine_st.registers[arg] = self.machine_st[norm];
+                            }
+                            RegType::Temp(_) => {
+                                let h = self.machine_st.heap.len();
+                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+
+                                self.machine_st[norm] = heap_loc_as_cell!(h);
+                                self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+                            }
+                        };
+                    }
+                    &QueryInstruction::SetConstant(c) => {
+                        self.machine_st.heap.push(c);
+                    }
+                    &QueryInstruction::SetLocalValue(reg) => {
+                        let addr = self.machine_st.deref(self.machine_st[reg]);
+                        let stored_v = self.machine_st.store(addr);
+
+                        if stored_v.is_stack_var() {
+                            let h = self.machine_st.heap.len();
+                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+                            (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v);
+                        } else {
+                            self.machine_st.heap.push(stored_v);
+                        }
+                    }
+                    &QueryInstruction::SetVariable(reg) => {
+                        let h = self.machine_st.heap.len();
+                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                        self.machine_st[reg] = heap_loc_as_cell!(h);
+                    }
+                    &QueryInstruction::SetValue(reg) => {
+                        let heap_val = self.machine_st.store(self.machine_st[reg]);
+                        self.machine_st.heap.push(heap_val);
+                    }
+                    &QueryInstruction::SetVoid(n) => {
+                        let h = self.machine_st.heap.len();
+
+                        for i in h..h + n {
+                            self.machine_st.heap.push(heap_loc_as_cell!(i));
+                        }
+                    }
+                }
+
+                self.machine_st.p += 1;
+            }
+        }
+    }
+}
index e7cda22dc03b091386664567932b6708ed47deab..3f8d47e8f382a5144dbe068b0e7917e73b655d1c 100644 (file)
@@ -6,8 +6,7 @@ use crate::clause_types::*;
 use crate::fixtures::*;
 use crate::forms::*;
 use crate::instructions::*;
-
-use crate::machine::code_repo::CodeRepo;
+use crate::machine::*;
 use crate::machine::heap::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::MachineStub;
@@ -19,10 +18,14 @@ use indexmap::IndexMap;
 use std::cell::Cell;
 use std::cmp::Ordering;
 use std::collections::BTreeSet;
-use std::fmt;
 use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
 use std::rc::Rc;
 
+// these statics store the locations of one-off control instructions
+// in the code vector.
+
+pub static HALT_CODE: usize = 0;
+
 use crate::types::*;
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
@@ -81,126 +84,7 @@ impl PartialOrd<Ref> for HeapCellValue {
         )
     }
 }
-/*
-impl HeapCellValue {
-    #[inline]
-    pub fn as_constant_index(self, machine_st: &MachineState) -> Option<Literal> {
-        read_heap_cell!(self,
-            (HeapCellValueTag::Char, c) => Some(Literal::Char(c)),
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    Some(Literal::Atom(name))
-                } else {
-                    None
-                }
-            }
-            (HeapCellValueTag::Fixnum, n) => {
-                Some(Literal::Fixnum(n))
-            }
-            (HeapCellValueTag::F64, f) => {
-                Some(Literal::Float(f))
-            }
-            (HeapCellValueTag::Cons, ptr) => {
-                match_untyped_arena_ptr!(ptr,
-                     (ArenaHeaderTag::Integer, n) => {
-                         Some(Literal::Integer(n))
-                     }
-                     (ArenaHeaderTag::Rational, r) => {
-                         Some(Literal::Rational(r))
-                     }
-                     _ => {
-                         None
-                     }
-                )
-            }
-        )
-    }
-}
-*/
-/*
-impl Ord for Ref {
-    fn cmp(&self, other: &Ref) -> Ordering {
-        match (self, other) {
-            (Ref::AttrVar(h1), Ref::AttrVar(h2))
-            | (Ref::HeapCell(h1), Ref::HeapCell(h2))
-            | (Ref::HeapCell(h1), Ref::AttrVar(h2))
-            | (Ref::AttrVar(h1), Ref::HeapCell(h2)) => h1.cmp(&h2),
-            (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
-                fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
-            }
-            (Ref::StackCell(..), _) => Ordering::Greater,
-            (_, Ref::StackCell(..)) => Ordering::Less,
-        }
-    }
-}
-
-impl PartialEq<Ref> for Addr {
-    fn eq(&self, r: &Ref) -> bool {
-        self.as_var() == Some(*r)
-    }
-}
-
-impl Addr {
-    #[inline]
-    pub(crate) fn is_heap_bound(&self) -> bool {
-        match self {
-            Addr::Char(_)
-            | Addr::EmptyList
-            | Addr::CutPoint(_)
-            | Addr::Usize(_)
-            | Addr::Fixnum(_)
-            | Addr::Float(_) => false,
-            _ => true,
-        }
-    }
 
-    #[inline]
-    pub(crate) fn is_ref(&self) -> bool {
-        match self {
-            Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true,
-            _ => false,
-        }
-    }
-
-    #[inline]
-    pub(crate) fn as_var(&self) -> Option<Ref> {
-        match self {
-            &Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
-            &Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
-            &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
-            _ => None,
-        }
-    }
-
-    pub(crate) fn is_protected(&self, e: usize) -> bool {
-        match self {
-            &Addr::StackCell(addr, _) if addr >= e => false,
-            _ => true,
-        }
-    }
-}
-
-impl SubAssign<usize> for Addr {
-    fn sub_assign(&mut self, rhs: usize) {
-        *self = self.clone() - rhs;
-    }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum TrailRef {
-    Ref(Ref),
-    AttrVarHeapLink(usize),
-    AttrVarListLink(usize, usize),
-    BlackboardEntry(usize),
-    BlackboardOffset(usize, usize), // key atom heap location, key value heap location
-}
-
-impl From<Ref> for TrailRef {
-    fn from(r: Ref) -> Self {
-        TrailRef::Ref(r)
-    }
-}
-*/
 #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub enum IndexPtr {
     DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
@@ -326,10 +210,10 @@ pub enum LocalCodePtr {
                                          // TopLevel(usize, usize), // chunk_num, offset
 }
 
-impl MachineState {
-    pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, p: LocalCodePtr) -> bool {
-        match code_repo.lookup_instr(self, &CodePtr::Local(p)) {
-            Some(line) => match line.as_ref() {
+impl Machine {
+    pub(crate) fn is_reset_cont_marker(&self, p: LocalCodePtr) -> bool {
+        match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) {
+            Some(line) => match line.as_ref(&self.code_repo.code) {
                 Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
                     if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
                         return true;
@@ -679,50 +563,6 @@ impl IndexStore {
     pub(super) fn new() -> Self {
         index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
     }
-
-    pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
-        let r_w_h = atom!("run_cleaners_with_handling");
-        let r_wo_h = atom!("run_cleaners_without_handling");
-        let iso_ext = atom!("iso_ext");
-
-        let r_w_h = self
-            .get_predicate_code_index(r_w_h, 0, iso_ext)
-            .and_then(|item| item.local());
-        let r_wo_h = self
-            .get_predicate_code_index(r_wo_h, 1, iso_ext)
-            .and_then(|item| item.local());
-
-        if let Some(r_w_h) = r_w_h {
-            if let Some(r_wo_h) = r_wo_h {
-                return (r_w_h, r_wo_h);
-            }
-        }
-
-        return (0, 0);
-    }
 }
 
 pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex>;
-
-pub(crate) enum RefOrOwned<'a, T: 'a> {
-    Borrowed(&'a T),
-    Owned(T),
-}
-
-impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            &RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed),
-            &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
-        }
-    }
-}
-
-impl<'a, T> RefOrOwned<'a, T> {
-    pub(crate) fn as_ref(&'a self) -> &'a T {
-        match self {
-            &RefOrOwned::Borrowed(r) => r,
-            &RefOrOwned::Owned(ref r) => r,
-        }
-    }
-}
index 68330be7a25388361641e9835308de975917a859..6bd29da2ac644d942e66e0e27a9f0b5f334e0533 100644 (file)
@@ -1,11 +1,9 @@
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::parser::ast::*;
-
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::heap_print::*;
+use crate::machine::Machine;
 use crate::machine::attributed_variables::*;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
@@ -13,20 +11,15 @@ use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
+use crate::parser::ast::*;
 use crate::types::*;
 
 use crate::parser::rug::Integer;
 
-use downcast::{
-    downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any,
-};
-
 use indexmap::IndexMap;
 
-use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
-use std::mem;
 use std::ops::{Index, IndexMut};
 use std::rc::Rc;
 
@@ -83,6 +76,9 @@ pub struct MachineState {
     pub(super) ball: Ball,
     pub(super) lifted_heap: Heap,
     pub(super) interms: Vec<Number>, // intermediate numbers.
+    // locations of cleaners, cut points, the previous block. for setup_call_cleanup.
+    pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>,
+    pub(super) cwil: CWIL,
     pub(super) last_call: bool, // TODO: REMOVE THIS.
     pub(crate) flags: MachineFlags,
     pub(crate) cc: usize,
@@ -90,6 +86,8 @@ pub struct MachineState {
     pub(crate) dynamic_mode: FirstOrNext,
     pub(crate) unify_fn: fn(&mut MachineState),
     pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
+    pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
+    pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult,
 }
 
 impl fmt::Debug for MachineState {
@@ -178,505 +176,6 @@ impl IndexMut<RegType> for MachineState {
 
 pub type CallResult = Result<(), Vec<HeapCellValue>>;
 
-pub trait CutPolicy: Any + fmt::Debug {
-    // returns true iff we fail or cut redirected the MachineState's p itself
-    fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool;
-}
-
-downcast!(dyn CutPolicy);
-
-pub trait CallPolicy: Any + fmt::Debug {
-    fn retry_me_else(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        let b = machine_st.b;
-        let or_frame = machine_st.stack.index_or_frame_mut(b);
-        let n = or_frame.prelude.univ_prelude.num_cells;
-
-        for i in 0..n {
-            machine_st.registers[i + 1] = or_frame[i];
-        }
-
-        machine_st.num_of_args = n;
-        machine_st.e = or_frame.prelude.e;
-        machine_st.cp = or_frame.prelude.cp;
-
-        or_frame.prelude.bp = machine_st.p.local() + offset;
-
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = machine_st.tr;
-        let target_h = or_frame.prelude.h;
-
-        machine_st.tr = or_frame.prelude.tr;
-
-        machine_st.attr_var_init.reset();
-        machine_st.hb = machine_st.heap.len();
-        machine_st.p += 1;
-
-        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
-
-        machine_st.trail.truncate(machine_st.tr);
-        machine_st.heap.truncate(target_h);
-
-        Ok(())
-    }
-
-    fn retry(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        let b = machine_st.b;
-        let or_frame = machine_st.stack.index_or_frame_mut(b);
-        let n = or_frame.prelude.univ_prelude.num_cells;
-
-        for i in 0..n {
-            machine_st.registers[i+1] = or_frame[i];
-        }
-
-        machine_st.num_of_args = n;
-        machine_st.e = or_frame.prelude.e;
-        machine_st.cp = or_frame.prelude.cp;
-
-        // WAS: or_frame.prelude.bp = machine_st.p.local() + 1;
-        or_frame.prelude.biip += 1;
-
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = machine_st.tr;
-        let target_h = or_frame.prelude.h;
-
-        machine_st.tr = or_frame.prelude.tr;
-        machine_st.attr_var_init.reset();
-
-        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
-
-        machine_st.trail.truncate(machine_st.tr);
-        machine_st.heap.truncate(target_h);
-
-        machine_st.hb = machine_st.heap.len();
-        machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
-
-        machine_st.oip = 0;
-        machine_st.iip = 0;
-
-        Ok(())
-    }
-
-    fn trust(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        let b = machine_st.b;
-        let or_frame = machine_st.stack.index_or_frame(b);
-        let n = or_frame.prelude.univ_prelude.num_cells;
-
-        for i in 0..n {
-            machine_st.registers[i+1] = or_frame[i];
-        }
-
-        machine_st.num_of_args = n;
-        machine_st.e = or_frame.prelude.e;
-        machine_st.cp = or_frame.prelude.cp;
-
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = machine_st.tr;
-        let target_h = or_frame.prelude.h;
-
-        machine_st.tr = or_frame.prelude.tr;
-
-        machine_st.attr_var_init.reset();
-        machine_st.b = or_frame.prelude.b;
-
-        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
-
-        machine_st.trail.truncate(machine_st.tr);
-        machine_st.stack.truncate(b);
-        machine_st.heap.truncate(target_h);
-
-        machine_st.hb = machine_st.heap.len();
-        machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
-
-        machine_st.oip = 0;
-        machine_st.iip = 0;
-
-        Ok(())
-    }
-
-    fn trust_me(
-        &mut self,
-        machine_st: &mut MachineState,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        let b = machine_st.b;
-        let or_frame = machine_st.stack.index_or_frame(b);
-        let n = or_frame.prelude.univ_prelude.num_cells;
-
-        for i in 0..n {
-            machine_st.registers[i+1] = or_frame[i];
-        }
-
-        machine_st.num_of_args = n;
-        machine_st.e = or_frame.prelude.e;
-        machine_st.cp = or_frame.prelude.cp;
-
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = machine_st.tr;
-        let target_h = or_frame.prelude.h;
-
-        machine_st.tr = or_frame.prelude.tr;
-
-        machine_st.attr_var_init.reset();
-        machine_st.b = or_frame.prelude.b;
-
-        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
-
-        machine_st.trail.truncate(machine_st.tr);
-        machine_st.stack.truncate(b);
-        machine_st.heap.truncate(target_h);
-
-        machine_st.hb = machine_st.heap.len();
-        machine_st.p += 1;
-
-        Ok(())
-    }
-
-    fn context_call(
-        &mut self,
-        machine_st: &mut MachineState,
-        name: Atom,
-        arity: usize,
-        idx: &CodeIndex,
-    ) -> CallResult {
-        if machine_st.last_call {
-            self.try_execute(machine_st, name, arity, idx)
-        } else {
-            self.try_call(machine_st, name, arity, idx)
-        }
-    }
-
-    fn try_call(
-        &mut self,
-        machine_st: &mut MachineState,
-        name: Atom,
-        arity: usize,
-        idx: &CodeIndex,
-    ) -> CallResult {
-        match idx.get() {
-            IndexPtr::DynamicUndefined => {
-                machine_st.fail = true;
-                return Ok(());
-            }
-            IndexPtr::Undefined => {
-                return Err(machine_st.throw_undefined_error(name, arity));
-            }
-            IndexPtr::DynamicIndex(compiled_tl_index) => {
-                machine_st.dynamic_mode = FirstOrNext::First;
-                machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
-            }
-            IndexPtr::Index(compiled_tl_index) => {
-                machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
-            }
-        }
-
-        Ok(())
-    }
-
-    fn try_execute(
-        &mut self,
-        machine_st: &mut MachineState,
-        name: Atom,
-        arity: usize,
-        idx: &CodeIndex,
-    ) -> CallResult {
-        match idx.get() {
-            IndexPtr::DynamicUndefined => {
-                machine_st.fail = true;
-                return Ok(());
-            }
-            IndexPtr::Undefined => {
-                return Err(machine_st.throw_undefined_error(name, arity));
-            }
-            IndexPtr::DynamicIndex(compiled_tl_index) => {
-                machine_st.dynamic_mode = FirstOrNext::First;
-                machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index));
-            }
-            IndexPtr::Index(compiled_tl_index) => {
-                machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
-            }
-        }
-
-        Ok(())
-    }
-
-    fn call_builtin(
-        &mut self,
-        machine_st: &mut MachineState,
-        ct: &BuiltInClauseType,
-        _code_dir: &CodeDir,
-        op_dir: &OpDir,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        match ct {
-            &BuiltInClauseType::AcyclicTerm => {
-                let addr = machine_st.registers[1];
-                machine_st.fail = machine_st.is_cyclic_term(addr);
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Arg => {
-                machine_st.try_arg()?;
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Compare => {
-                let stub_gen = || functor_stub(atom!("compare"), 3);
-
-                let a1 = machine_st.store(machine_st.deref(machine_st.registers[1]));
-                let a2 = machine_st.registers[2];
-                let a3 = machine_st.registers[3];
-
-                read_heap_cell!(a1,
-                    (HeapCellValueTag::Str, s) => {
-                        let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
-                            .get_name_and_arity();
-
-                        match name {
-                            atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
-                            }
-                            _ => {
-                                let err = machine_st.domain_error(DomainErrorType::Order, a1);
-                                return Err(machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                    }
-                    _ => {
-                        let err = machine_st.type_error(ValidType::Atom, a1);
-                        return Err(machine_st.error_form(err, stub_gen()));
-                    }
-                );
-
-                let atom = match compare_term_test!(machine_st, a2, a3) {
-                    Some(Ordering::Greater) => {
-                        atom!(">")
-                    }
-                    Some(Ordering::Equal) => {
-                        atom!("=")
-                    }
-                    None | Some(Ordering::Less) => {
-                        atom!("<")
-                    }
-                };
-
-                machine_st.unify_atom(atom, a1);
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::CompareTerm(qt) => {
-                machine_st.compare_term(qt);
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Read => {
-                let stream = machine_st.get_stream_or_alias(
-                    machine_st.registers[1],
-                    stream_aliases,
-                    atom!("read"),
-                    2,
-                )?;
-
-                match machine_st.read(stream, op_dir) {
-                    Ok(offset) => {
-                        let value = machine_st.registers[2];
-                        unify_fn!(machine_st, value, heap_loc_as_cell!(offset.heap_loc));
-                    }
-                    Err(ParserError::UnexpectedEOF) => {
-                        let value = machine_st.registers[2];
-                        machine_st.unify_atom(atom!("end_of_file"), value);
-                    }
-                    Err(e) => {
-                        let stub = functor_stub(atom!("read"), 2);
-                        let err = machine_st.syntax_error(e);
-
-                        return Err(machine_st.error_form(err, stub));
-                    }
-                };
-
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::CopyTerm => {
-                machine_st.copy_term(AttrVarPolicy::DeepCopy);
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Eq => {
-                let a1 = machine_st.registers[1];
-                let a2 = machine_st.registers[2];
-
-                machine_st.fail = machine_st.eq_test(a1, a2);
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Ground => {
-                machine_st.fail = machine_st.ground_test();
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Functor => {
-                machine_st.try_functor()?;
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::NotEq => {
-                let a1 = machine_st.registers[1];
-                let a2 = machine_st.registers[2];
-
-                machine_st.fail =
-                    if let Some(Ordering::Equal) = compare_term_test!(machine_st, a1, a2) {
-                        true
-                    } else {
-                        false
-                    };
-
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Sort => {
-                machine_st.check_sort_errors()?;
-
-                let stub_gen = || functor_stub(atom!("sort"), 2);
-                let mut list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?;
-
-                list.sort_unstable_by(|v1, v2| {
-                    compare_term_test!(machine_st, *v1, *v2).unwrap_or(Ordering::Less)
-                });
-
-                list.dedup_by(|v1, v2| {
-                    compare_term_test!(machine_st, *v1, *v2) == Some(Ordering::Equal)
-                });
-
-                let heap_addr = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut machine_st.heap, list.into_iter())
-                );
-
-                let r2 = machine_st.registers[2];
-                unify_fn!(machine_st, r2, heap_addr);
-
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::KeySort => {
-                machine_st.check_keysort_errors()?;
-
-                let stub_gen = || functor_stub(atom!("keysort"), 2);
-                let list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?;
-
-                let mut key_pairs = Vec::with_capacity(list.len());
-
-                for val in list {
-                    let key = machine_st.project_onto_key(val)?;
-                    key_pairs.push((key, val));
-                }
-
-                key_pairs.sort_by(|a1, a2| {
-                    compare_term_test!(machine_st, a1.0, a2.0).unwrap_or(Ordering::Less)
-                });
-
-                let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
-                let heap_addr = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut machine_st.heap, key_pairs)
-                );
-
-                let r2 = machine_st.registers[2];
-                unify_fn!(machine_st, r2, heap_addr);
-
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-            &BuiltInClauseType::Is(r, ref at) => {
-                let n1 = machine_st.store(machine_st.deref(machine_st[r]));
-                let n2 = machine_st.get_number(at)?;
-
-                match n2 {
-                    Number::Fixnum(n) => machine_st.unify_fixnum(n, n1),
-                    Number::Float(n) => {
-                        // TODO: argghh.. deal with it.
-                        let n = arena_alloc!(n, &mut machine_st.arena);
-                        machine_st.unify_f64(n, n1)
-                    }
-                    Number::Integer(n) => machine_st.unify_big_int(n, n1),
-                    Number::Rational(n) => machine_st.unify_rational(n, n1),
-                }
-
-                return_from_clause!(machine_st.last_call, machine_st)
-            }
-        }
-    }
-
-    fn call_clause_type(
-        &mut self,
-        machine_st: &mut MachineState,
-        key: PredicateKey,
-        code_dir: &CodeDir,
-        op_dir: &OpDir,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        let (name, arity) = key;
-
-        match ClauseType::from(name, arity) {
-            ClauseType::BuiltIn(built_in) => {
-                machine_st.setup_built_in_call(built_in);
-                self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?;
-            }
-            ClauseType::CallN => {
-                machine_st.handle_internal_call_n(arity);
-
-                if machine_st.fail {
-                    return Ok(());
-                }
-
-                machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
-            }
-            ClauseType::Inlined(inlined) => {
-                machine_st.execute_inlined(&inlined);
-
-                if machine_st.last_call {
-                    machine_st.p = CodePtr::Local(machine_st.cp);
-                }
-            }
-            ClauseType::Named(..) => {
-                if let Some(idx) = code_dir.get(&(name, arity)) {
-                    self.context_call(machine_st, name, arity, idx)?;
-                } else {
-                    return Err(machine_st.throw_undefined_error(name, arity));
-                }
-            }
-            ClauseType::System(_) => {
-                let (name, arity) = key;
-                let name = functor!(name);
-
-                let stub = functor_stub(atom!("call"), arity + 1);
-                let err = machine_st.type_error(ValidType::Callable, name);
-
-                return Err(machine_st.error_form(err, stub));
-            }
-        }
-
-        Ok(())
-    }
-
-    fn call_n(
-        &mut self,
-        machine_st: &mut MachineState,
-        arity: usize,
-        code_dir: &CodeDir,
-        op_dir: &OpDir,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        if let Some(key) = machine_st.setup_call_n(arity) {
-            self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?;
-        }
-
-        Ok(())
-    }
-}
-
 #[inline(always)]
 pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) {
     read_heap_cell!(heap[index],
@@ -866,6 +365,26 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
 }
 
 impl MachineState {
+    pub(crate) fn increment_call_count(&mut self) -> CallResult {
+        if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 {
+            return Ok(());
+        }
+
+        if let Some(&(ref limit, bp)) = self.cwil.limits.last() {
+            if self.cwil.count == *limit {
+                self.cwil.inference_limit_exceeded = true;
+
+                return Err(
+                    functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])
+                );
+            } else {
+                self.cwil.count += 1;
+            }
+        }
+
+        Ok(())
+    }
+
     #[allow(dead_code)]
     pub(super) fn try_char_list(&mut self, addrs: Vec<HeapCellValue>) -> Result<String, MachineError> {
         let mut chars = String::new();
@@ -958,7 +477,7 @@ impl MachineState {
             match self.read(stream, &indices.op_dir) {
                 Ok(term_write_result) => {
                     let term = self.registers[2];
-                    unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term);
+                    unify_fn!(*self, heap_loc_as_cell!(term_write_result.heap_loc), term);
                     let term = heap_loc_as_cell!(term_write_result.heap_loc);
 
                     if self.fail {
@@ -1004,7 +523,7 @@ impl MachineState {
                         iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter())
                     );
 
-                    unify_fn!(self, singletons_offset, singleton_addr);
+                    unify_fn!(*self, singletons_offset, singleton_addr);
 
                     if self.fail {
                         return Ok(());
@@ -1015,7 +534,7 @@ impl MachineState {
                         iter_to_heap_list(&mut self.heap, var_list.into_iter())
                     );
 
-                    unify_fn!(self, vars_offset, vars_addr);
+                    unify_fn!(*self, vars_offset, vars_addr);
 
                     if self.fail {
                         return Ok(());
@@ -1026,7 +545,7 @@ impl MachineState {
                         iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter())
                     );
 
-                    return Ok(unify_fn!(self, var_names_offset, var_names_addr));
+                    return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
                 }
                 Err(err) => {
                     if let ParserError::UnexpectedEOF = err {
@@ -1163,83 +682,96 @@ impl MachineState {
         (name, usize::try_from(arity.get_num()).unwrap())
     }
 
-    pub(super) fn module_lookup(
-        &mut self,
-        indices: &IndexStore,
-        call_policy: &mut Box<dyn CallPolicy>,
-        key: PredicateKey,
-        module_name: Atom,
-        _last_call: bool,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        if module_name == atom!("user") {
-            return call_policy.call_clause_type(
-                self,
-                key,
-                &indices.code_dir,
-                &indices.op_dir,
-                stream_aliases,
-            );
-        } else if let Some(module) = indices.modules.get(&module_name) {
-            return call_policy.call_clause_type(
-                self,
-                key,
-                &module.code_dir,
-                &module.op_dir,
-                stream_aliases,
-            );
+    #[inline(always)]
+    pub(super) fn cut_body(&mut self, value: HeapCellValue) {
+        let b = self.b;
+
+        read_heap_cell!(value,
+            (HeapCellValueTag::Fixnum, b0) => {
+                let b0 = b0.get_num() as usize;
+
+                if b > b0 {
+                    self.b = b0;
+                }
+            }
+            _ => {
+                self.fail = true;
+            }
+        );
+    }
+
+    #[inline(always)]
+    pub(super) fn try_me_else(&mut self, offset: usize) {
+        let n = self.num_of_args;
+        let b = self.stack.allocate_or_frame(n);
+        let or_frame = self.stack.index_or_frame_mut(b);
+
+        or_frame.prelude.univ_prelude.num_cells = n;
+        or_frame.prelude.e = self.e;
+        or_frame.prelude.cp = self.cp;
+        or_frame.prelude.b = self.b;
+        or_frame.prelude.bp = self.p.local() + offset;
+        or_frame.prelude.boip = 0;
+        or_frame.prelude.biip = 0;
+        or_frame.prelude.tr = self.tr;
+        or_frame.prelude.h = self.heap.len();
+        or_frame.prelude.b0 = self.b0;
+
+        self.b = b;
+
+        for i in 0..n {
+            self.stack[stack_loc!(OrFrame, b, i)] = self.registers[i+1];
         }
 
-        let (name, arity) = key;
+        self.hb = self.heap.len();
+        self.p += 1;
+    }
 
-        let stub = functor_stub(name, arity);
-        let err = self.module_resolution_error(module_name, name, arity);
+    #[inline(always)]
+    pub(super) fn indexed_try(&mut self, offset: usize) {
+        let n = self.num_of_args;
+        let b = self.stack.allocate_or_frame(n);
+        let or_frame = self.stack.index_or_frame_mut(b);
+
+        or_frame.prelude.univ_prelude.num_cells = n;
+        or_frame.prelude.e = self.e;
+        or_frame.prelude.cp = self.cp;
+        or_frame.prelude.b = self.b;
+        or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now!
+        or_frame.prelude.boip = self.oip;
+        or_frame.prelude.biip = self.iip + 1;
+        or_frame.prelude.tr = self.tr;
+        or_frame.prelude.h = self.heap.len();
+        or_frame.prelude.b0 = self.b0;
+
+        self.b = b;
 
-        return Err(self.error_form(err, stub));
+        for i in 0..n {
+            or_frame[i] = self.registers[i+1];
+        }
+
+        self.hb = self.heap.len();
+        self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
+
+        self.oip = 0;
+        self.iip = 0;
     }
 }
 
 #[derive(Debug)]
-pub(crate) struct CWILCallPolicy {
-    pub(crate) prev_policy: Box<dyn CallPolicy>,
+pub(crate) struct CWIL {
     count: Integer,
     limits: Vec<(Integer, usize)>,
     inference_limit_exceeded: bool,
 }
 
-impl CWILCallPolicy {
-    pub(crate) fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
-        let mut prev_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
-        mem::swap(&mut prev_policy, policy);
-
-        let new_policy = CWILCallPolicy {
-            prev_policy,
+impl CWIL {
+    pub(crate) fn new() -> Self {
+        CWIL {
             count: Integer::from(0),
             limits: vec![],
             inference_limit_exceeded: false,
-        };
-
-        *policy = Box::new(new_policy);
-    }
-
-    fn increment(&mut self, machine_st: &MachineState) -> CallResult {
-        if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 {
-            return Ok(());
         }
-
-        if let Some(&(ref limit, bp)) = self.limits.last() {
-            if self.count == *limit {
-                self.inference_limit_exceeded = true;
-
-                return Err(
-                    functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])
-                );
-            } else {
-                self.count += 1;
-            }
-        }
-
-        Ok(())
     }
 
     pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer {
@@ -1254,6 +786,7 @@ impl CWILCallPolicy {
         &self.count
     }
 
+    #[inline(always)]
     pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer {
         if let Some((_, bp)) = self.limits.last() {
             if bp == &b {
@@ -1264,207 +797,15 @@ impl CWILCallPolicy {
         &self.count
     }
 
-    pub(crate) fn is_empty(&self) -> bool {
-        self.limits.is_empty()
-    }
-
-    pub(crate) fn into_inner(&mut self) -> Box<dyn CallPolicy> {
-        let mut new_inner: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
-        mem::swap(&mut self.prev_policy, &mut new_inner);
-        new_inner
-    }
-}
-
-impl CallPolicy for CWILCallPolicy {
-    fn context_call(
-        &mut self,
-        machine_st: &mut MachineState,
-        name: Atom,
-        arity: usize,
-        idx: &CodeIndex,
-    ) -> CallResult {
-        self.prev_policy.context_call(machine_st, name, arity, idx)?;
-        self.increment(machine_st)
-    }
-
-    fn retry_me_else(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        self.prev_policy.retry_me_else(machine_st, offset, global_variables)?;
-        self.increment(machine_st)
-    }
-
-    fn retry(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        self.prev_policy.retry(machine_st, offset, global_variables)?;
-        self.increment(machine_st)
-    }
-
-    fn trust_me(
-        &mut self,
-        machine_st: &mut MachineState,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        self.prev_policy.trust_me(machine_st, global_variables)?;
-        self.increment(machine_st)
-    }
-
-    fn trust(
-        &mut self,
-        machine_st: &mut MachineState,
-        offset: usize,
-        global_variables: &mut GlobalVarDir,
-    ) -> CallResult {
-        self.prev_policy.trust(machine_st, offset, global_variables)?;
-        self.increment(machine_st)
-    }
-
-    fn call_builtin(
-        &mut self,
-        machine_st: &mut MachineState,
-        ct: &BuiltInClauseType,
-        code_dir: &CodeDir,
-        op_dir: &OpDir,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        self.prev_policy.call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?;
-        self.increment(machine_st)
-    }
-
-    fn call_n(
-        &mut self,
-        machine_st: &mut MachineState,
-        arity: usize,
-        code_dir: &CodeDir,
-        op_dir: &OpDir,
-        stream_aliases: &StreamAliasDir,
-    ) -> CallResult {
-        self.prev_policy.call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?;
-        self.increment(machine_st)
-    }
-}
-
-downcast!(dyn CallPolicy);
-
-#[derive(Debug)]
-pub(crate) struct DefaultCallPolicy {}
-
-impl CallPolicy for DefaultCallPolicy {}
-
-fn cut_body(machine_st: &mut MachineState, addr: HeapCellValue) -> bool {
-    let b = machine_st.b;
-
-    read_heap_cell!(addr,
-        (HeapCellValueTag::Fixnum, b0) => {
-            let b0 = b0.get_num() as usize;
-
-            if b > b0 {
-                machine_st.b = b0;
-            }
-        }
-        _ => {
-            machine_st.fail = true;
-            return true;
-        }
-    );
-
-    false
-}
-
-#[derive(Debug)]
-pub(crate) struct DefaultCutPolicy {}
-
-pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
-    let addr = machine_st.store(machine_st.deref(machine_st[r]));
-    cut_body(machine_st, addr);
-}
-
-impl CutPolicy for DefaultCutPolicy {
-    fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
-        let addr = machine_st[r];
-        cut_body(machine_st, addr)
-    }
-}
-
-#[derive(Debug)]
-pub(crate) struct SCCCutPolicy {
-    // locations of cleaners, cut points, the previous block
-    cont_pts: Vec<(HeapCellValue, usize, usize)>,
-    r_c_w_h: usize,
-    r_c_wo_h: usize,
-}
-
-impl SCCCutPolicy {
-    pub(crate) fn new(r_c_w_h: usize, r_c_wo_h: usize) -> Self {
-        SCCCutPolicy {
-            cont_pts: vec![],
-            r_c_w_h,
-            r_c_wo_h,
-        }
-    }
-
-    pub(crate) fn out_of_cont_pts(&self) -> bool {
-        self.cont_pts.is_empty()
-    }
-
-    pub(crate) fn push_cont_pt(&mut self, addr: HeapCellValue, b: usize, prev_b: usize) {
-        self.cont_pts.push((addr, b, prev_b));
-    }
-
-    pub(crate) fn pop_cont_pt(&mut self) -> Option<(HeapCellValue, usize, usize)> {
-        self.cont_pts.pop()
-    }
-
-    fn run_cleaners(&self, machine_st: &mut MachineState) -> bool {
-        if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
-            if machine_st.b < b_cutoff {
-                let (idx, arity) = if machine_st.block > prev_block {
-                    (dir_entry!(self.r_c_w_h), 0)
-                } else {
-                    machine_st.registers[1] = fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64));
-                    (dir_entry!(self.r_c_wo_h), 1)
-                };
-
-                if machine_st.last_call {
-                    machine_st.execute_at_index(arity, idx);
-                } else {
-                    machine_st.call_at_index(arity, idx);
-                }
-
-                return true;
-            }
-        }
-
-        false
+    #[inline(always)]
+    pub(crate) fn reset(&mut self) {
+        self.count = Integer::from(0);
+        self.limits.clear();
+        self.inference_limit_exceeded = false;
     }
-}
-
-impl CutPolicy for SCCCutPolicy {
-    fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
-        let b = machine_st.b;
 
-        read_heap_cell!(machine_st[r],
-            (HeapCellValueTag::Fixnum, b0) => {
-                let b0 = b0.get_num() as usize;
-
-                if b > b0 {
-                    machine_st.b = b0;
-                }
-            }
-            _ => {
-                machine_st.fail = true;
-                return true;
-            }
-        );
-
-        self.run_cleaners(machine_st)
+    #[inline(always)]
+    pub(crate) fn is_empty(&self) -> bool {
+        self.limits.is_empty()
     }
 }
-
index 1c6922d52b82e79183c909d1f28049213b566b81..ee04d645b07059e352e00ea0ead42c3b074e0bed 100644 (file)
@@ -4,24 +4,18 @@ use crate::types::*;
 use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
-use crate::instructions::*;
-use crate::machine::arithmetic_ops::*;
 use crate::machine::attributed_variables::*;
-use crate::machine::code_repo::CodeRepo;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
+use crate::machine::Machine;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
 use crate::machine::partial_string::*;
 use crate::machine::stack::*;
-use crate::machine::streams::*;
-use crate::machine::INTERRUPT;
 use crate::parser::ast::*;
 use crate::parser::rug::{Integer, Rational};
 
-use crate::try_numeric_result;
-
 use ordered_float::*;
 
 use indexmap::IndexSet;
@@ -29,6 +23,11 @@ use indexmap::IndexSet;
 use std::cmp::Ordering;
 use std::convert::TryFrom;
 
+// TODO: move this block to.. a place.
+impl Machine {
+
+}
+
 impl MachineState {
     pub(crate) fn new() -> Self {
         MachineState {
@@ -56,7 +55,9 @@ impl MachineState {
             block: 0,
             ball: Ball::new(),
             lifted_heap: Heap::new(),
-            interms: vec![Number::default(); 256],
+            interms: vec![Number::default();256],
+            cont_pts: Vec::with_capacity(256),
+            cwil: CWIL::new(),
             last_call: false,
             flags: MachineFlags::default(),
             cc: 0,
@@ -64,6 +65,8 @@ impl MachineState {
             dynamic_mode: FirstOrNext::First,
             unify_fn: MachineState::unify,
             bind_fn: MachineState::bind,
+            run_cleaners_fn: |_| { false },
+            increment_call_count_fn: |_| { Ok(()) },
         }
     }
 
@@ -869,7 +872,7 @@ impl MachineState {
 
         copy_term(CopyTerm::new(self), a1, attr_var_policy);
 
-        unify_fn!(self, heap_loc_as_cell!(old_h), a2);
+        unify_fn!(*self, heap_loc_as_cell!(old_h), a2);
     }
 
     pub(super) fn unwind_stack(&mut self) {
@@ -1405,7 +1408,7 @@ impl MachineState {
         }
     }
 
-    fn read_s(&mut self) -> HeapCellValue {
+    pub(crate) fn read_s(&mut self) -> HeapCellValue {
         match &self.s {
             &HeapPtr::HeapCell(h) => self.deref(self.heap[h]),
             &HeapPtr::PStrChar(h, n) => {
@@ -1837,7 +1840,7 @@ impl MachineState {
         Some(Ordering::Equal)
     }
 
-    fn increment_s_ptr(&mut self, rhs: usize) {
+    pub(crate) fn increment_s_ptr(&mut self, rhs: usize) {
         match &mut self.s {
             HeapPtr::HeapCell(ref mut h) => {
                 *h += rhs;
@@ -1861,58 +1864,6 @@ impl MachineState {
         }
     }
 
-    pub(super) fn unwind_trail(
-        &mut self,
-        a1: usize,
-        a2: usize,
-        global_variables: &mut GlobalVarDir,
-    ) {
-        // the sequence is reversed to respect the chronology of trail
-        // additions, now that deleted attributes can be undeleted by
-        // backtracking.
-        for i in (a1..a2).rev() {
-            let h = self.trail[i].get_value() as usize;
-
-            match self.trail[i].get_tag() {
-                TrailEntryTag::TrailedHeapVar => {
-                    self.heap[h] = heap_loc_as_cell!(h);
-                }
-                TrailEntryTag::TrailedStackVar => {
-                    self.stack[h] = stack_loc_as_cell!(h);
-                }
-                TrailEntryTag::TrailedAttrVar => {
-                    self.heap[h] = attr_var_as_cell!(h);
-                }
-                TrailEntryTag::TrailedAttrVarHeapLink => {
-                    self.heap[h] = heap_loc_as_cell!(h);
-                }
-                TrailEntryTag::TrailedAttrVarListLink => {
-                    let l = self.trail[i + 1].get_value();
-                    self.heap[h] = list_loc_as_cell!(l);
-                }
-                TrailEntryTag::TrailedBlackboardEntry => {
-                    let key = Atom::from(h);
-
-                    match global_variables.get_mut(&key) {
-                        Some((_, ref mut loc)) => *loc = None,
-                        None => unreachable!(),
-                    }
-                }
-                TrailEntryTag::TrailedBlackboardOffset => {
-                    let key = Atom::from(h);
-                    let value_cell = HeapCellValue::from(u64::from(self.trail[i + 1]));
-
-                    match global_variables.get_mut(&key) {
-                        Some((_, ref mut loc)) => *loc = Some(value_cell),
-                        None => unreachable!(),
-                    }
-                }
-                TrailEntryTag::TrailedAttachedValue => {
-                }
-            }
-        }
-    }
-
     pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) {
         let h = self.heap.len();
         self.heap.push(value);
@@ -2045,1035 +1996,191 @@ impl MachineState {
         )
     }
 
-    pub fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
-        let stub_gen = || functor_stub(atom!("is"), 2);
-
-        match instr {
-            &ArithmeticInstruction::Add(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(
-                    self,
-                    try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen)
-                );
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(
-                    self,
-                    try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen)
-                );
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(
-                    self,
-                    try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen)
-                );
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Max(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, max(n1, n2));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Min(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, min(n1, n2));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, int_pow(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, gcd(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, pow(n1, n2, atom!("**")));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
-                let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
-
-                let r1 = try_or_fail!(self, self.get_rational(a1, stub_gen));
-                let r2 = try_or_fail!(self, self.get_rational(a2, stub_gen));
-
-                self.interms[t - 1] = Number::Rational(arena_alloc!(
-                    try_or_fail_gen!(self, rdiv(r1, r2)),
-                    self.arena
-                ));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] =
-                    try_or_fail_gen!(self, int_floor_div(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, idiv(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Abs(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] = abs(n1, &mut self.arena);
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Sign(ref a1, t) => {
-                let n = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] = sign(n);
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Neg(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] = neg(n1, &mut self.arena);
-                self.p += 1;
-            }
-            &ArithmeticInstruction::BitwiseComplement(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] =
-                    try_or_fail_gen!(self, bitwise_complement(n1, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Div(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, div(n1, n2));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Shr(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, shr(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Shl(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, shl(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Xor(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
-
-                self.interms[t - 1] = try_or_fail_gen!(self, xor(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::And(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
+    pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
+        let arity = arity + 1;
+        let pred = self.registers[1];
 
-                self.interms[t - 1] = try_or_fail_gen!(self, and(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Or(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
+        for i in 2..arity {
+            self.registers[i - 1] = self.registers[i];
+        }
 
-                self.interms[t - 1] = try_or_fail_gen!(self, or(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Mod(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
+        if arity > 1 {
+            self.registers[arity - 1] = pred;
+            return;
+        }
 
-                self.interms[t - 1] = try_or_fail_gen!(self, modulus(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Rem(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
+        self.fail = true;
+    }
 
-                self.interms[t - 1] = try_or_fail_gen!(self, remainder(n1, n2, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Cos(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+    pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
+        let addr = self.store(self.deref(self.registers[arity]));
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, cos(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Sin(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        let (name, narity) = read_heap_cell!(addr,
+            (HeapCellValueTag::Str, s) => {
+                let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sin(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Tan(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+                if narity + arity > MAX_ARITY {
+                    let stub = functor_stub(atom!("call"), arity + 1);
+                    let err = self.representation_error(RepFlag::MaxArity);
+                    let representation_error = self.error_form(err, stub);
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, tan(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Sqrt(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+                    self.throw_exception(representation_error);
+                    return None;
+                }
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sqrt(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Log(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+                for i in (1..arity).rev() {
+                    self.registers[i + narity] = self.registers[i];
+                }
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, log(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Exp(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+                for i in 1..narity + 1 {
+                    self.registers[i] = self.heap[s + i];
+                }
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, exp(n1))));
-                self.p += 1;
+                (name, narity)
             }
-            &ArithmeticInstruction::ACos(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, acos(n1))));
-                self.p += 1;
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                if arity == 0 {
+                    (name, 0)
+                } else {
+                    self.fail = true;
+                    return None;
+                }
             }
-            &ArithmeticInstruction::ASin(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, asin(n1))));
-                self.p += 1;
+            (HeapCellValueTag::Char, c) => {
+                (self.atom_tbl.build_with(&c.to_string()), 0)
             }
-            &ArithmeticInstruction::ATan(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => {
+                let stub = functor_stub(atom!("call"), arity + 1);
+                let err = self.instantiation_error();
+                let instantiation_error = self.error_form(err, stub);
 
-                self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, atan(n1))));
-                self.p += 1;
+                self.throw_exception(instantiation_error);
+                return None;
             }
-            &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
-                let n2 = try_or_fail!(self, self.get_number(a2));
+            _ => {
+                let stub = functor_stub(atom!("call"), arity + 1);
+                let err = self.type_error(ValidType::Callable, addr);
+                let type_error = self.error_form(err, stub);
 
-                self.interms[t - 1] =
-                    Number::Float(OrderedFloat(try_or_fail_gen!(self, atan2(n1, n2))));
-                self.p += 1;
+                self.throw_exception(type_error);
+                return None;
             }
-            &ArithmeticInstruction::Float(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        );
 
-                self.interms[t - 1] =
-                    Number::Float(OrderedFloat(try_or_fail_gen!(self, float(n1))));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Truncate(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        Some((name, arity + narity - 1))
+    }
 
-                self.interms[t - 1] = truncate(n1, &mut self.arena);
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Round(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+    #[inline]
+    pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool {
+        if addr.is_constant() {
+            return false;
+        }
 
-                self.interms[t - 1] = try_or_fail_gen!(self, round(n1, &mut self.arena));
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Ceiling(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        let addr = self.store(self.deref(addr));
+        let mut iter = stackful_preorder_iter(&mut self.heap, addr);
 
-                self.interms[t - 1] = ceiling(n1, &mut self.arena);
-                self.p += 1;
-            }
-            &ArithmeticInstruction::Floor(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        while let Some(value) = iter.next() {
+            if value.is_forwarded() {
+                let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value));
 
-                self.interms[t - 1] = floor(n1, &mut self.arena);
-                self.p += 1;
+                if value.is_compound() {
+                    return true;
+                }
             }
-            &ArithmeticInstruction::Plus(ref a1, t) => {
-                let n1 = try_or_fail!(self, self.get_number(a1));
+        }
 
-                self.interms[t - 1] = n1;
-                self.p += 1;
-            }
-        };
+        false
     }
 
-    pub fn execute_fact_instr(&mut self, instr: &FactInstruction) {
-        match instr {
-            &FactInstruction::GetConstant(_, c, reg) => {
-                let value = self.deref(self[reg]);
-                self.write_literal_to_var(value, c);
-            }
-            &FactInstruction::GetList(_, reg) => {
-                let deref_v = self.deref(self[reg]);
-                let store_v = self.store(deref_v);
-
-                read_heap_cell!(store_v,
-                    (HeapCellValueTag::PStrLoc, h) => {
-                        let (h, n) = pstr_loc_and_offset(&self.heap, h);
-
-                        self.s = HeapPtr::PStrChar(h, n.get_num() as usize);
-                        self.mode = MachineMode::Read;
-                    }
-                    (HeapCellValueTag::CStr) => {
-                        let h = self.heap.len();
-                        self.heap.push(store_v);
-
-                        self.s = HeapPtr::PStrChar(h, 0);
-                        self.mode = MachineMode::Read;
-                    }
-                    (HeapCellValueTag::Lis, l) => {
-                        self.s = HeapPtr::HeapCell(l);
-                        self.mode = MachineMode::Read;
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                        let h = self.heap.len();
-
-                        self.heap.push(list_loc_as_cell!(h+1));
-                        self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+    // arg(+N, +Term, ?Arg)
+    pub fn try_arg(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("arg"), 3);
+        let n = self.store(self.deref(self.registers[1]));
 
-                        self.mode = MachineMode::Write;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
+        read_heap_cell!(n,
+            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+                // 8.5.2.3 a)
+                let err = self.instantiation_error();
+                return Err(self.error_form(err, stub_gen()));
             }
-            &FactInstruction::GetPartialString(_, string, reg, has_tail) => {
-                let deref_v = self.deref(self[reg]);
-                let store_v = self.store(deref_v);
-
-                read_heap_cell!(store_v,
-                    (HeapCellValueTag::Str | HeapCellValueTag::Lis |
-                     HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
-                     HeapCellValueTag::StackVar | HeapCellValueTag::Var |
-                     HeapCellValueTag::CStr) => {
-                        self.match_partial_string(store_v, string, has_tail);
-                    }
+            _ => {
+                let n = match Number::try_from(n) {
+                    Ok(Number::Fixnum(n)) => Number::Fixnum(n),
+                    Ok(Number::Integer(n)) => Number::Integer(n),
                     _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            &FactInstruction::GetStructure(ref ct, arity, reg) => {
-                let deref_v = self.deref(self[reg]);
-                let store_v = self.store(deref_v);
-
-                read_heap_cell!(store_v,
-                    (HeapCellValueTag::Str, a) => {
-                        let result = self.heap[a];
-
-                        read_heap_cell!(result,
-                            (HeapCellValueTag::Atom, (name, narity)) => {
-                                if narity == arity && ct.name() == name {
-                                    self.s = HeapPtr::HeapCell(a + 1);
-                                    self.mode = MachineMode::Read;
-                                } else {
-                                    self.fail = true;
-                                }
-                            }
-                            _ => {
-                                unreachable!();
-                            }
-                        );
+                        let err = self.type_error(ValidType::Integer, n);
+                        return Err(self.error_form(err, stub_gen()));
                     }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                        let h = self.heap.len();
-
-                        self.heap.push(str_loc_as_cell!(h+1));
-                        self.heap.push(atom_as_cell!(ct.name(), arity));
+                };
 
-                        self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+                if n < 0 {
+                    // 8.5.2.3 e)
+                    let err = self.domain_error(DomainErrorType::NotLessThanZero, n);
+                    return Err(self.error_form(err, stub_gen()));
+                }
 
-                        self.mode = MachineMode::Write;
-                    }
+                let n = match n {
+                    Number::Fixnum(n) => n.get_num() as usize,
+                    Number::Integer(n) => n.to_usize().unwrap(),
                     _ => {
                         self.fail = true;
+                        return Ok(());
                     }
-                );
-            }
-            &FactInstruction::GetVariable(norm, arg) => {
-                self[norm] = self.registers[arg];
-            }
-            &FactInstruction::GetValue(norm, arg) => {
-                let norm_addr = self[norm];
-                let reg_addr = self.registers[arg];
+                };
 
-                unify_fn!(self, norm_addr, reg_addr);
-            }
-            &FactInstruction::UnifyConstant(v) => {
-                match self.mode {
-                    MachineMode::Read => {
-                        let addr = self.read_s();
+                let term = self.deref(self.registers[2]);
 
-                        self.write_literal_to_var(addr, v);
-                        self.increment_s_ptr(1);
-                    }
-                    MachineMode::Write => {
-                        self.heap.push(v);
-                    }
-                };
-            }
-            &FactInstruction::UnifyVariable(reg) => {
-                match self.mode {
-                    MachineMode::Read => {
-                        self[reg] = self.read_s();
-                        self.increment_s_ptr(1);
+                read_heap_cell!(self.store(term),
+                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+                        let err = self.instantiation_error();
+                        return Err(self.error_form(err, stub_gen()));
                     }
-                    MachineMode::Write => {
-                        let h = self.heap.len();
+                    (HeapCellValueTag::Str, o) => {
+                        let arity = cell_as_atom_cell!(self.heap[o]).get_arity();
 
-                        self.heap.push(heap_loc_as_cell!(h));
-                        self[reg] = heap_loc_as_cell!(h);
+                        if 1 <= n && n <= arity {
+                            let a3 = self.registers[3];
+                            unify_fn!(*self, a3, heap_loc_as_cell!(o + n));
+                        } else {
+                            self.fail = true;
+                        }
                     }
-                };
-            }
-            &FactInstruction::UnifyLocalValue(reg) => {
-                match self.mode {
-                    MachineMode::Read => {
-                        let reg_addr = self[reg];
-                        let value = self.read_s();
-
-                        unify_fn!(self, reg_addr, value);
-                        self.increment_s_ptr(1);
+                    (HeapCellValueTag::Lis, l) => {
+                        if n == 1 || n == 2 {
+                            let a3 = self.registers[3];
+                            unify_fn!(*self, a3, heap_loc_as_cell!(l + n - 1));
+                        } else {
+                            self.fail = true;
+                        }
                     }
-                    MachineMode::Write => {
-                        let value = self.store(self.deref(self[reg]));
-                        let h = self.heap.len();
-
-                        read_heap_cell!(value,
-                            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
-                                let value = self.heap[hc];
+                    (HeapCellValueTag::PStrLoc, pstr_loc) => {
+                        if n == 1 || n == 2 {
+                            let a3 = self.registers[3];
+                            let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc);
 
-                                self.heap.push(value);
-                                self.increment_s_ptr(1);
+                            let pstr = cell_as_string!(self.heap[h]);
+                            let offset = offset.get_num() as usize;
 
-                                return;
-                            }
-                            _ => {
-                            }
-                        );
-
-                        self.heap.push(heap_loc_as_cell!(h));
-                        (self.bind_fn)(self, Ref::heap_cell(h), value);
-                    }
-                };
-            }
-            &FactInstruction::UnifyValue(reg) => {
-                match self.mode {
-                    MachineMode::Read => {
-                        let reg_addr = self[reg];
-                        let value = self.read_s();
-
-                        unify_fn!(self, reg_addr, value);
-                        self.increment_s_ptr(1);
-                    }
-                    MachineMode::Write => {
-                        let h = self.heap.len();
-                        self.heap.push(heap_loc_as_cell!(h));
-
-                        let addr = self.store(self[reg]);
-                        (self.bind_fn)(self, Ref::heap_cell(h), addr);
-
-                        // the former code of this match arm was:
-
-                        // let addr = self.store(self[reg]);
-                        // self.heap.push(HeapCellValue::Addr(addr));
-
-                        // the old code didn't perform the occurs
-                        // check when enabled and so it was changed to
-                        // the above, which is only slightly less
-                        // efficient when the occurs_check is disabled.
-                    }
-                };
-            }
-            &FactInstruction::UnifyVoid(n) => {
-                match self.mode {
-                    MachineMode::Read => {
-                        self.increment_s_ptr(n);
-                    }
-                    MachineMode::Write => {
-                        let h = self.heap.len();
-
-                        for i in h..h + n {
-                            self.heap.push(heap_loc_as_cell!(i));
-                        }
-                    }
-                };
-            }
-        };
-    }
-
-    pub(super) fn execute_indexing_instr(
-        &mut self,
-        indexing_lines: &Vec<IndexingLine>,
-        code_repo: &CodeRepo,
-    ) {
-        fn dynamic_external_of_clause_is_valid(
-            machine_st: &mut MachineState,
-            code: &Code,
-            p: usize,
-        ) -> bool {
-            match &code[p] {
-                Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {
-                    machine_st.dynamic_mode = FirstOrNext::First;
-                    return true;
-                }
-                _ => {}
-            }
-
-            match &code[p - 1] {
-                &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
-                    if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death {
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-                _ => {}
-            }
-
-            true
-        }
-
-        let mut index = 0;
-        let addr = match &indexing_lines[0] {
-            &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
-                self.store(self.deref(self[temp_v!(arg)]))
-            }
-            _ => {
-                unreachable!()
-            }
-        };
-
-        loop {
-            match &indexing_lines[index] {
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
-                    let offset = read_heap_cell!(addr,
-                        (HeapCellValueTag::Var
-                         | HeapCellValueTag::StackVar
-                         | HeapCellValueTag::AttrVar) => {
-                            v
-                        }
-                        (HeapCellValueTag::PStrLoc
-                         | HeapCellValueTag::Lis
-                         | HeapCellValueTag::CStr) => {
-                            l
-                        }
-                        (HeapCellValueTag::Fixnum
-                         | HeapCellValueTag::Char
-                         | HeapCellValueTag::F64) => {
-                            c
-                        }
-                        (HeapCellValueTag::Atom, (_name, arity)) => {
-                            // if arity == 0 { c } else { s }
-                            debug_assert!(arity == 0);
-                            c
-                        }
-                        (HeapCellValueTag::Str) => {
-                            s
-                        }
-                        (HeapCellValueTag::Cons, ptr) => {
-                            match ptr.get_tag() {
-                                ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
-                                ArenaHeaderTag::F64 => {
-                                    c
-                                }
-                                _ => {
-                                    IndexingCodePtr::Fail
-                                }
-                            }
-                        }
-                        _ => {
-                            unreachable!();
-                        }
-                    );
-
-                    match offset {
-                        IndexingCodePtr::Fail => {
-                            self.fail = true;
-                            break;
-                        }
-                        IndexingCodePtr::DynamicExternal(o) => {
-                            // either points directly to a
-                            // DynamicInternalElse, or just ahead of
-                            // one. Or neither!
-                            let p = self.p.local().abs_loc();
-
-                            if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
-                                self.fail = true;
-                            } else {
-                                self.p += o;
-                            }
-
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
-                    let lit = read_heap_cell!(addr,
-                        (HeapCellValueTag::Char, c) => {
-                            Literal::Char(c)
-                        }
-                        (HeapCellValueTag::Fixnum, n) => {
-                            Literal::Fixnum(n)
-                        }
-                        (HeapCellValueTag::F64, f) => {
-                            Literal::Float(f)
-                        }
-                        (HeapCellValueTag::Atom, (atom, arity)) => {
-                            debug_assert_eq!(arity, 0);
-                            Literal::Atom(atom)
-                        }
-                        (HeapCellValueTag::Cons, cons_ptr) => {
-                            match_untyped_arena_ptr!(cons_ptr,
-                                 (ArenaHeaderTag::Rational, r) => {
-                                     Literal::Rational(r)
-                                 }
-                                 (ArenaHeaderTag::F64, f) => {
-                                     Literal::Float(F64Ptr(f))
-                                 }
-                                 (ArenaHeaderTag::Integer, n) => {
-                                     Literal::Integer(n)
-                                 }
-                                 _ => {
-                                     unreachable!()
-                                 }
-                            )
-                        }
-                        _ => {
-                            unreachable!()
-                        }
-                    );
-
-                    let offset = match hm.get(&lit) {
-                        Some(offset) => *offset,
-                        _ => IndexingCodePtr::Fail,
-                    };
-
-                    match offset {
-                        IndexingCodePtr::Fail => {
-                            self.fail = true;
-                            break;
-                        }
-                        IndexingCodePtr::DynamicExternal(o) => {
-                            // either points directly to a
-                            // DynamicInternalElse, or just ahead of
-                            // one. Or neither!
-                            let p = self.p.local().abs_loc();
-
-                            if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
-                                self.fail = true;
-                            } else {
-                                self.p += o;
-                            }
-
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
-                    let offset = read_heap_cell!(addr,
-                        (HeapCellValueTag::Atom, (name, arity)) => {
-                            match hm.get(&(name, arity)) {
-                                Some(offset) => *offset,
-                                None => IndexingCodePtr::Fail,
-                            }
-                        }
-                        (HeapCellValueTag::Str, s) => {
-                            let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
-
-                            match hm.get(&(name, arity)) {
-                                Some(offset) => *offset,
-                                None => IndexingCodePtr::Fail,
-                            }
-                        }
-                        _ => {
-                            IndexingCodePtr::Fail
-                        }
-                    );
-
-                    match offset {
-                        IndexingCodePtr::Fail => {
-                            self.fail = true;
-                            break;
-                        }
-                        IndexingCodePtr::DynamicExternal(o) => {
-                            let p = self.p.local().abs_loc();
-
-                            if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
-                                self.fail = true;
-                            } else {
-                                self.p += o;
-                            }
-
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                &IndexingLine::IndexedChoice(_) => {
-                    if let LocalCodePtr::DirEntry(p) = self.p.local() {
-                        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-                        self.oip = index as u32;
-                        self.iip = 0;
-                    } else {
-                        unreachable!()
-                    }
-
-                    break;
-                }
-                &IndexingLine::DynamicIndexedChoice(_) => {
-                    self.dynamic_mode = FirstOrNext::First;
-
-                    if let LocalCodePtr::DirEntry(p) = self.p.local() {
-                        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-                        self.oip = index as u32;
-                        self.iip = 0;
-                    } else {
-                        unreachable!()
-                    }
-
-                    break;
-                }
-            }
-        }
-    }
-
-    pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) {
-        match instr {
-            &QueryInstruction::GetVariable(norm, arg) => {
-                self[norm] = self.registers[arg];
-            }
-            &QueryInstruction::PutConstant(_, c, reg) => {
-                self[reg] = c;
-            }
-            &QueryInstruction::PutList(_, reg) => {
-                self[reg] = list_loc_as_cell!(self.heap.len());
-            }
-            &QueryInstruction::PutPartialString(_, string, reg, has_tail) => {
-                let pstr_addr = if has_tail {
-                    if string != atom!("") {
-                        let h = self.heap.len();
-                        self.heap.push(string_as_pstr_cell!(string));
-
-                        // the tail will be pushed by the next
-                        // instruction, so don't push one here.
-
-                        pstr_loc_as_cell!(h)
-                    } else {
-                        empty_list_as_cell!()
-                    }
-                } else {
-                    string_as_cstr_cell!(string)
-                };
-
-                self[reg] = pstr_addr;
-            }
-            &QueryInstruction::PutStructure(ref ct, arity, reg) => {
-                let h = self.heap.len();
-
-                self.heap.push(atom_as_cell!(ct.name(), arity));
-                self[reg] = str_loc_as_cell!(h);
-            }
-            &QueryInstruction::PutUnsafeValue(n, arg) => {
-                let s = stack_loc!(AndFrame, self.e, n);
-                let addr = self.store(self.deref(stack_loc_as_cell!(s)));
-
-                if addr.is_protected(self.e) {
-                    self.registers[arg] = addr;
-                } else {
-                    let h = self.heap.len();
-
-                    self.heap.push(heap_loc_as_cell!(h));
-                    (self.bind_fn)(self, Ref::heap_cell(h), addr);
-
-                    self.registers[arg] = heap_loc_as_cell!(h);
-                }
-            }
-            &QueryInstruction::PutValue(norm, arg) => {
-                self.registers[arg] = self[norm];
-            }
-            &QueryInstruction::PutVariable(norm, arg) => {
-                match norm {
-                    RegType::Perm(n) => {
-                        self[norm] = stack_loc_as_cell!(AndFrame, self.e, n);
-                        self.registers[arg] = self[norm];
-                    }
-                    RegType::Temp(_) => {
-                        let h = self.heap.len();
-                        self.heap.push(heap_loc_as_cell!(h));
-
-                        self[norm] = heap_loc_as_cell!(h);
-                        self.registers[arg] = heap_loc_as_cell!(h);
-                    }
-                };
-            }
-            &QueryInstruction::SetConstant(c) => {
-                self.heap.push(c);
-            }
-            &QueryInstruction::SetLocalValue(reg) => {
-                let addr = self.deref(self[reg]);
-                let stored_v = self.store(addr);
-
-                if stored_v.is_stack_var() {
-                    let h = self.heap.len();
-                    self.heap.push(heap_loc_as_cell!(h));
-                    (self.bind_fn)(self, Ref::heap_cell(h), stored_v);
-                } else {
-                    self.heap.push(stored_v);
-                }
-            }
-            &QueryInstruction::SetVariable(reg) => {
-                let h = self.heap.len();
-                self.heap.push(heap_loc_as_cell!(h));
-                self[reg] = heap_loc_as_cell!(h);
-            }
-            &QueryInstruction::SetValue(reg) => {
-                let heap_val = self.store(self[reg]);
-                self.heap.push(heap_val);
-            }
-            &QueryInstruction::SetVoid(n) => {
-                let h = self.heap.len();
-
-                for i in h..h + n {
-                    self.heap.push(heap_loc_as_cell!(i));
-                }
-            }
-        }
-    }
-
-    pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
-        let arity = arity + 1;
-        let pred = self.registers[1];
-
-        for i in 2..arity {
-            self.registers[i - 1] = self.registers[i];
-        }
-
-        if arity > 1 {
-            self.registers[arity - 1] = pred;
-            return;
-        }
-
-        self.fail = true;
-    }
-
-    pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
-        let addr = self.store(self.deref(self.registers[arity]));
-
-        let (name, narity) = read_heap_cell!(addr,
-            (HeapCellValueTag::Str, s) => {
-                let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
-
-                if narity + arity > MAX_ARITY {
-                    let stub = functor_stub(atom!("call"), arity + 1);
-                    let err = self.representation_error(RepFlag::MaxArity);
-                    let representation_error = self.error_form(err, stub);
-
-                    self.throw_exception(representation_error);
-                    return None;
-                }
-
-                for i in (1..arity).rev() {
-                    self.registers[i + narity] = self.registers[i];
-                }
-
-                for i in 1..narity + 1 {
-                    self.registers[i] = self.heap[s + i];
-                }
-
-                (name, narity)
-            }
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    (name, 0)
-                } else {
-                    self.fail = true;
-                    return None;
-                }
-            }
-            (HeapCellValueTag::Char, c) => {
-                (self.atom_tbl.build_with(&c.to_string()), 0)
-            }
-            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => {
-                let stub = functor_stub(atom!("call"), arity + 1);
-                let err = self.instantiation_error();
-                let instantiation_error = self.error_form(err, stub);
-
-                self.throw_exception(instantiation_error);
-                return None;
-            }
-            _ => {
-                let stub = functor_stub(atom!("call"), arity + 1);
-                let err = self.type_error(ValidType::Callable, addr);
-                let type_error = self.error_form(err, stub);
-
-                self.throw_exception(type_error);
-                return None;
-            }
-        );
-
-        Some((name, arity + narity - 1))
-    }
-
-    #[inline]
-    pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool {
-        if addr.is_constant() {
-            return false;
-        }
-
-        let addr = self.store(self.deref(addr));
-        let mut iter = stackful_preorder_iter(&mut self.heap, addr);
-
-        while let Some(value) = iter.next() {
-            if value.is_forwarded() {
-                let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value));
-
-                if value.is_compound() {
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    // arg(+N, +Term, ?Arg)
-    pub fn try_arg(&mut self) -> CallResult {
-        let stub_gen = || functor_stub(atom!("arg"), 3);
-        let n = self.store(self.deref(self.registers[1]));
-
-        read_heap_cell!(n,
-            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                // 8.5.2.3 a)
-                let err = self.instantiation_error();
-                return Err(self.error_form(err, stub_gen()));
-            }
-            _ => {
-                let n = match Number::try_from(n) {
-                    Ok(Number::Fixnum(n)) => Number::Fixnum(n),
-                    Ok(Number::Integer(n)) => Number::Integer(n),
-                    _ => {
-                        let err = self.type_error(ValidType::Integer, n);
-                        return Err(self.error_form(err, stub_gen()));
-                    }
-                };
-
-                if n < 0 {
-                    // 8.5.2.3 e)
-                    let err = self.domain_error(DomainErrorType::NotLessThanZero, n);
-                    return Err(self.error_form(err, stub_gen()));
-                }
-
-                let n = match n {
-                    Number::Fixnum(n) => n.get_num() as usize,
-                    Number::Integer(n) => n.to_usize().unwrap(),
-                    _ => {
-                        self.fail = true;
-                        return Ok(());
-                    }
-                };
-
-                let term = self.deref(self.registers[2]);
-
-                read_heap_cell!(self.store(term),
-                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                        let err = self.instantiation_error();
-                        return Err(self.error_form(err, stub_gen()));
-                    }
-                    (HeapCellValueTag::Str, o) => {
-                        let arity = cell_as_atom_cell!(self.heap[o]).get_arity();
-
-                        if 1 <= n && n <= arity {
-                            let a3 = self.registers[3];
-                            unify_fn!(self, a3, heap_loc_as_cell!(o + n));
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    (HeapCellValueTag::Lis, l) => {
-                        if n == 1 || n == 2 {
-                            let a3 = self.registers[3];
-                            unify_fn!(self, a3, heap_loc_as_cell!(l + n - 1));
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    (HeapCellValueTag::PStrLoc, pstr_loc) => {
-                        if n == 1 || n == 2 {
-                            let a3 = self.registers[3];
-                            let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc);
-
-                            let pstr = cell_as_string!(self.heap[h]);
-                            let offset = offset.get_num() as usize;
-
-                            if let Some(c) = pstr.as_str_from(offset).chars().next() {
-                                if n == 1 {
-                                    self.unify_char(c, a3);
-                                } else {
-                                    let offset = (offset + c.len_utf8()) as i64;
-                                    let h_len = self.heap.len();
-                                    let pstr_atom: Atom = pstr.into();
+                            if let Some(c) = pstr.as_str_from(offset).chars().next() {
+                                if n == 1 {
+                                    self.unify_char(c, a3);
+                                } else {
+                                    let offset = (offset + c.len_utf8()) as i64;
+                                    let h_len = self.heap.len();
+                                    let pstr_atom: Atom = pstr.into();
 
                                     if pstr_atom.len() > offset as usize {
                                         self.heap.push(pstr_offset_as_cell!(h));
                                         self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
 
-                                        unify_fn!(self, pstr_loc_as_cell!(h_len), a3);
+                                        unify_fn!(*self, pstr_loc_as_cell!(h_len), a3);
                                     } else {
                                         match self.heap[h].get_tag() {
                                             HeapCellValueTag::CStr => {
                                                 self.unify_atom(atom!("[]"), self.store(self.deref(a3)));
                                             }
                                             HeapCellValueTag::PStr => {
-                                                unify_fn!(self, self.heap[h+1], a3);
+                                                unify_fn!(*self, self.heap[h+1], a3);
                                             }
                                             _ => {
                                                 unreachable!();
@@ -3103,7 +2210,7 @@ impl MachineState {
                                     self.heap.push(pstr_offset_as_cell!(h_len));
                                     self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
 
-                                    unify_fn!(self, pstr_loc_as_cell!(h_len+1), self.registers[3]);
+                                    unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]);
                                 } else {
                                     self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[3])));
                                 }
@@ -3187,182 +2294,6 @@ impl MachineState {
         )
     }
 
-    pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) {
-        match inlined {
-            &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => {
-                let n1 = try_or_fail!(self, self.get_number(at_1));
-                let n2 = try_or_fail!(self, self.get_number(at_2));
-
-                self.compare_numbers(cmp, n1, n2);
-            }
-            &InlinedClauseType::IsAtom(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity == 0 {
-                            self.p += 1;
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    (HeapCellValueTag::Char) => {
-                        self.p += 1;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsAtomic(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
-                     HeapCellValueTag::Cons) => {
-                        self.p += 1;
-                    }
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity == 0 {
-                            self.p += 1;
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsInteger(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Fixnum(_)) => {
-                        self.p += 1;
-                    }
-                    Ok(Number::Integer(_)) => {
-                        self.p += 1;
-                    }
-                    Ok(Number::Rational(n)) => {
-                        if n.denom() == &1 {
-                            self.p += 1;
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsCompound(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Str | HeapCellValueTag::Lis |
-                     HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
-                        self.p += 1;
-                    }
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity > 0 {
-                            self.p += 1;
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsFloat(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Float(_)) => {
-                        self.p += 1;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsNumber(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Fixnum(_)) => {
-                        self.p += 1;
-                    }
-                    Ok(Number::Integer(_)) => {
-                        self.p += 1;
-                    }
-                    Ok(Number::Rational(n)) => {
-                        if n.denom() == &1 {
-                            self.p += 1;
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    Ok(Number::Float(_)) => {
-                        self.p += 1;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsRational(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Cons, ptr) => {
-                        match_untyped_arena_ptr!(ptr,
-                             (ArenaHeaderTag::Rational, _r) => {
-                                 self.p += 1;
-                             }
-                             _ => {
-                                 self.fail = true;
-                             }
-                        );
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsNonVar(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                match d.get_tag() {
-                    HeapCellValueTag::AttrVar
-                    | HeapCellValueTag::Var
-                    | HeapCellValueTag::StackVar => {
-                        self.fail = true;
-                    }
-                    _ => {
-                        self.p += 1;
-                    }
-                }
-            }
-            &InlinedClauseType::IsVar(r1) => {
-                let d = self.store(self.deref(self[r1]));
-
-                match d.get_tag() {
-                    HeapCellValueTag::AttrVar
-                    | HeapCellValueTag::Var
-                    | HeapCellValueTag::StackVar => {
-                        self.p += 1;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                }
-            }
-        }
-    }
-
     #[inline(always)]
     fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
         self.try_functor_unify_components(atom_as_cell!(name), arity);
@@ -3742,545 +2673,11 @@ impl MachineState {
         self.p += 1;
     }
 
-    fn throw_interrupt_exception(&mut self) {
+    pub fn throw_interrupt_exception(&mut self) {
         let err = self.interrupt_error();
         let src = functor_stub(atom!("repl"), 0);
         let err = self.error_form(err, src);
 
         self.throw_exception(err);
     }
-
-    fn handle_call_clause(
-        &mut self,
-        indices: &mut IndexStore,
-        code_repo: &CodeRepo,
-        call_policy: &mut Box<dyn CallPolicy>,
-        cut_policy: &mut Box<dyn CutPolicy>,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
-        ct: &ClauseType,
-        arity: usize,
-        lco: bool,
-        use_default_cp: bool,
-    ) {
-        let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
-
-        match INTERRUPT.compare_exchange(
-            interrupted,
-            false,
-            std::sync::atomic::Ordering::Relaxed,
-            std::sync::atomic::Ordering::Relaxed,
-        ) {
-            Ok(interruption) => {
-                if interruption {
-                    self.throw_interrupt_exception();
-                    return;
-                }
-            }
-            Err(_) => unreachable!(),
-        }
-
-        let mut default_call_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
-
-        let call_policy = if use_default_cp {
-            &mut default_call_policy
-        } else {
-            call_policy
-        };
-
-        self.last_call = lco;
-
-        match ct {
-            &ClauseType::BuiltIn(ref ct) => try_or_fail!(
-                self,
-                call_policy.call_builtin(
-                    self,
-                    ct,
-                    &indices.code_dir,
-                    &indices.op_dir,
-                    &indices.stream_aliases,
-                )
-            ),
-            &ClauseType::CallN => try_or_fail!(
-                self,
-                call_policy.call_n(
-                    self,
-                    arity,
-                    &indices.code_dir,
-                    &indices.op_dir,
-                    &indices.stream_aliases,
-                )
-            ),
-            &ClauseType::Inlined(ref ct) => {
-                self.execute_inlined(ct);
-
-                if lco {
-                    self.p = CodePtr::Local(self.cp);
-                }
-            }
-            &ClauseType::Named(ref name, _, ref idx) => {
-                try_or_fail!(self, call_policy.context_call(self, *name, arity, idx))
-            }
-            &ClauseType::System(ref ct) => try_or_fail!(
-                self,
-                self.system_call(
-                    ct,
-                    code_repo,
-                    indices,
-                    call_policy,
-                    cut_policy,
-                    current_input_stream,
-                    current_output_stream,
-                )
-            ),
-        };
-
-        self.last_call = false;
-    }
-
-    pub fn execute_ctrl_instr(
-        &mut self,
-        indices: &mut IndexStore,
-        code_repo: &CodeRepo,
-        call_policy: &mut Box<dyn CallPolicy>,
-        cut_policy: &mut Box<dyn CutPolicy>,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
-        instr: &ControlInstruction,
-    ) {
-        match instr {
-            &ControlInstruction::Allocate(num_cells) => {
-                self.allocate(num_cells);
-            }
-            &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => self
-                .handle_call_clause(
-                    indices,
-                    code_repo,
-                    call_policy,
-                    cut_policy,
-                    current_input_stream,
-                    current_output_stream,
-                    ct,
-                    arity,
-                    lco,
-                    use_default_cp,
-                ),
-            &ControlInstruction::Deallocate => self.deallocate(),
-            &ControlInstruction::JmpBy(arity, offset, _, lco) => {
-                if !lco {
-                    self.cp.assign_if_local(self.p.clone() + 1);
-                }
-
-                self.num_of_args = arity;
-                self.b0 = self.b;
-                self.p += offset;
-            }
-            &ControlInstruction::RevJmpBy(offset) => {
-                self.p -= offset;
-            }
-            &ControlInstruction::Proceed => {
-                self.p = CodePtr::Local(self.cp);
-            }
-        };
-    }
-
-    pub(super) fn execute_dynamic_indexed_choice_instr(
-        &mut self,
-        code_repo: &CodeRepo,
-        call_policy: &mut Box<dyn CallPolicy>,
-        global_variables: &mut GlobalVarDir,
-    ) {
-        let p = self.p.local();
-
-        match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) {
-            Some((offset, oi, ii, is_next_clause)) => {
-                self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc()));
-                self.oip = oi;
-                self.iip = ii;
-
-                match self.dynamic_mode {
-                    FirstOrNext::First if !is_next_clause => {
-                        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
-                    }
-                    FirstOrNext::First => {
-                        // there's a leading DynamicElse that sets self.cc.
-                        // self.cc = self.global_clock;
-
-                        // see that there is a following dynamic_else
-                        // clause so we avoid generating a choice
-                        // point in case there isn't.
-                        match self.find_living_dynamic(&code_repo.code, oi, ii + 1) {
-                            Some(_) => {
-                                self.registers[self.num_of_args + 1] =
-                                    fixnum_as_cell!(Fixnum::build_with(self.cc as i64));
-
-                                self.num_of_args += 2;
-
-                                self.execute_indexed_choice_instr(
-                                    &IndexedChoiceInstruction::Try(offset),
-                                    call_policy,
-                                    global_variables,
-                                );
-
-                                self.num_of_args -= 2;
-                            }
-                            None => {
-                                self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
-                                self.oip = 0;
-                                self.iip = 0;
-                            }
-                        }
-                    }
-                    FirstOrNext::Next => {
-                        let b = self.b;
-                        let n = self
-                            .stack
-                            .index_or_frame(b)
-                            .prelude
-                            .univ_prelude
-                            .num_cells;
-
-                        self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, b, n-2)])
-                            .get_num() as usize;
-
-                        if is_next_clause {
-                            match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) {
-                                Some(_) => {
-                                    try_or_fail!(
-                                        self,
-                                        call_policy.retry(self, offset, global_variables)
-                                    );
-                                }
-                                None => {
-                                    try_or_fail!(
-                                        self,
-                                        call_policy.trust(self, offset, global_variables)
-                                    )
-                                }
-                            }
-                        } else {
-                            try_or_fail!(self, call_policy.trust(self, offset, global_variables))
-                        }
-                    }
-                }
-            }
-            None => {
-                self.fail = true;
-            }
-        }
-
-        self.dynamic_mode = FirstOrNext::Next;
-    }
-
-    pub(super) fn execute_indexed_choice_instr(
-        &mut self,
-        instr: &IndexedChoiceInstruction,
-        call_policy: &mut Box<dyn CallPolicy>,
-        global_variables: &mut GlobalVarDir,
-    ) {
-        match instr {
-            &IndexedChoiceInstruction::Try(offset) => {
-                let n = self.num_of_args;
-                let b = self.stack.allocate_or_frame(n);
-                let or_frame = self.stack.index_or_frame_mut(b);
-
-                or_frame.prelude.univ_prelude.num_cells = n;
-                or_frame.prelude.e = self.e;
-                or_frame.prelude.cp = self.cp;
-                or_frame.prelude.b = self.b;
-                or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now!
-                or_frame.prelude.boip = self.oip;
-                or_frame.prelude.biip = self.iip + 1;
-                or_frame.prelude.tr = self.tr;
-                or_frame.prelude.h = self.heap.len();
-                or_frame.prelude.b0 = self.b0;
-
-                self.b = b;
-
-                for i in 0..n {
-                    or_frame[i] = self.registers[i+1];
-                }
-
-                /*
-                self.iip += 1;
-
-                let oip_b = self.oip.to_ne_bytes();
-                let iip_b = self.iip.to_ne_bytes();
-
-                or_frame[n] = HeapCellValue::from_bytes(
-                    [oip_b[0], oip_b[1], oip_b[2], oip_b[3],
-                     iip_b[0], iip_b[1], iip_b[2], iip_b[3]],
-                );
-                */
-
-                self.hb = self.heap.len();
-                self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
-
-                self.oip = 0;
-                self.iip = 0;
-            }
-            &IndexedChoiceInstruction::Retry(l) => {
-                try_or_fail!(self, call_policy.retry(self, l, global_variables));
-            }
-            &IndexedChoiceInstruction::Trust(l) => {
-                try_or_fail!(self, call_policy.trust(self, l, global_variables));
-            }
-        };
-    }
-
-    pub(super) fn execute_choice_instr(
-        &mut self,
-        instr: &ChoiceInstruction,
-        code_repo: &CodeRepo,
-        call_policy: &mut Box<dyn CallPolicy>,
-        global_variables: &mut GlobalVarDir,
-    ) {
-        match instr {
-            &ChoiceInstruction::DynamicElse(..) => {
-                if let FirstOrNext::First = self.dynamic_mode {
-                    self.cc = self.global_clock;
-                }
-
-                let p = self.p.local().abs_loc();
-
-                match self.find_living_dynamic_else(&code_repo.code, p) {
-                    Some((p, next_i)) => {
-                        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-
-                        match self.dynamic_mode {
-                            FirstOrNext::First if next_i == 0 => {
-                                self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
-                            }
-                            FirstOrNext::First => {
-                                self.cc = self.global_clock;
-
-                                match self.find_living_dynamic_else(&code_repo.code, p + next_i) {
-                                    Some(_) => {
-                                        self.registers[self.num_of_args + 1] =
-                                            fixnum_as_cell!(Fixnum::build_with(self.cc as i64));
-                                        self.num_of_args += 1;
-
-                                        self.execute_choice_instr(
-                                            &ChoiceInstruction::TryMeElse(next_i),
-                                            code_repo,
-                                            call_policy,
-                                            global_variables,
-                                        );
-
-                                        self.num_of_args -= 1;
-                                    }
-                                    None => {
-                                        self.p += 1;
-                                    }
-                                }
-                            }
-                            FirstOrNext::Next => {
-                                let n = self
-                                    .stack
-                                    .index_or_frame(self.b)
-                                    .prelude
-                                    .univ_prelude
-                                    .num_cells;
-
-                                self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)])
-                                    .get_num() as usize;
-
-                                if next_i > 0 {
-                                    match self.find_living_dynamic_else(&code_repo.code, p + next_i) {
-                                        Some(_) => {
-                                            try_or_fail!(
-                                                self,
-                                                call_policy.retry_me_else(
-                                                    self,
-                                                    next_i,
-                                                    global_variables,
-                                                )
-                                            )
-                                        }
-                                        None => {
-                                            try_or_fail!(
-                                                self,
-                                                call_policy.trust_me(self, global_variables)
-                                            )
-                                        }
-                                    }
-                                } else {
-                                    try_or_fail!(self, call_policy.trust_me(self, global_variables))
-                                }
-                            }
-                        }
-                    }
-                    None => {
-                        self.fail = true;
-                    }
-                }
-
-                self.dynamic_mode = FirstOrNext::Next;
-            }
-            &ChoiceInstruction::DynamicInternalElse(..) => {
-                let p = self.p.local().abs_loc();
-
-                match self.find_living_dynamic_else(&code_repo.code, p) {
-                    Some((p, next_i)) => {
-                        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-
-                        match self.dynamic_mode {
-                            FirstOrNext::First if next_i == 0 => {
-                                self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
-                            }
-                            FirstOrNext::First => {
-                                match self.find_living_dynamic_else(&code_repo.code, p + next_i) {
-                                    Some(_) => {
-                                        self.registers[self.num_of_args + 1] =
-                                            fixnum_as_cell!(Fixnum::build_with(self.cc as i64));
-                                        self.num_of_args += 1;
-
-                                        self.execute_choice_instr(
-                                            &ChoiceInstruction::TryMeElse(next_i),
-                                            code_repo,
-                                            call_policy,
-                                            global_variables,
-                                        );
-
-                                        self.num_of_args -= 1;
-                                    }
-                                    None => {
-                                        self.p += 1;
-                                    }
-                                }
-                            }
-                            FirstOrNext::Next => {
-                                let n = self
-                                    .stack
-                                    .index_or_frame(self.b)
-                                    .prelude
-                                    .univ_prelude
-                                    .num_cells;
-
-                                self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)])
-                                    .get_num() as usize;
-
-                                if next_i > 0 {
-                                    match self.find_living_dynamic_else(&code_repo.code, p + next_i) {
-                                        Some(_) => {
-                                            try_or_fail!(
-                                                self,
-                                                call_policy.retry_me_else(
-                                                    self,
-                                                    next_i,
-                                                    global_variables,
-                                                )
-                                            )
-                                        }
-                                        None => {
-                                            try_or_fail!(
-                                                self,
-                                                call_policy.trust_me(self, global_variables)
-                                            )
-                                        }
-                                    }
-                                } else {
-                                    try_or_fail!(
-                                        self,
-                                        call_policy.trust_me(self, global_variables)
-                                    )
-                                }
-                            }
-                        }
-                    }
-                    None => {
-                        self.fail = true;
-                    }
-                }
-
-                self.dynamic_mode = FirstOrNext::Next;
-            }
-            &ChoiceInstruction::TryMeElse(offset) => {
-                let n = self.num_of_args;
-                let b = self.stack.allocate_or_frame(n);
-                let or_frame = self.stack.index_or_frame_mut(b);
-
-                or_frame.prelude.univ_prelude.num_cells = n;
-                or_frame.prelude.e = self.e;
-                or_frame.prelude.cp = self.cp;
-                or_frame.prelude.b = self.b;
-                or_frame.prelude.bp = self.p.local() + offset;
-                or_frame.prelude.boip = 0;
-                or_frame.prelude.biip = 0;
-                or_frame.prelude.tr = self.tr;
-                or_frame.prelude.h = self.heap.len();
-                or_frame.prelude.b0 = self.b0;
-
-                self.b = b;
-
-                for i in 1..n + 1 {
-                    self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i];
-                }
-
-                self.hb = self.heap.len();
-                self.p += 1;
-            }
-            &ChoiceInstruction::DefaultRetryMeElse(offset) => {
-                let mut call_policy = DefaultCallPolicy {};
-                try_or_fail!(
-                    self,
-                    call_policy.retry_me_else(self, offset, global_variables)
-                )
-            }
-            &ChoiceInstruction::DefaultTrustMe(_) => {
-                let mut call_policy = DefaultCallPolicy {};
-                try_or_fail!(self, call_policy.trust_me(self, global_variables))
-            }
-            &ChoiceInstruction::RetryMeElse(offset) => {
-                try_or_fail!(
-                    self,
-                    call_policy.retry_me_else(self, offset, global_variables)
-                )
-            }
-            &ChoiceInstruction::TrustMe(_) => {
-                try_or_fail!(self, call_policy.trust_me(self, global_variables))
-            }
-        }
-    }
-
-    pub(super) fn execute_cut_instr(
-        &mut self,
-        instr: &CutInstruction,
-        cut_policy: &mut Box<dyn CutPolicy>,
-    ) {
-        match instr {
-            &CutInstruction::NeckCut => {
-                let b = self.b;
-                let b0 = self.b0;
-
-                if b > b0 {
-                    self.b = b0;
-
-                    if b > self.e {
-                        self.stack.truncate(b);
-                    }
-                }
-
-                self.p += 1;
-            }
-            &CutInstruction::GetLevel(r) => {
-                let b0 = self.b0;
-
-                self[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64));
-                self.p += 1;
-            }
-            &CutInstruction::GetLevelAndUnify(r) => {
-                let b0 = self[perm_v!(1)];
-                let a = self[r];
-
-                unify_fn!(self, a, b0);
-                self.p += 1;
-            }
-            &CutInstruction::Cut(r) => {
-                if !cut_policy.cut(self, r) {
-                    self.p += 1;
-                }
-            }
-        }
-    }
 }
index 9524d138d530b6a26cf536c91166a51626003b4f..7f73755ae6a40c6df061ce2109388d6b7f58df2e 100644 (file)
@@ -226,8 +226,6 @@ impl Machine {
 
         let mut wam = Machine {
             machine_st,
-            inner_heap: Heap::new(),
-            policies: MachinePolicies::new(),
             indices: IndexStore::new(),
             code_repo: CodeRepo::new(),
             user_input,
index 7a73ac306dc779b8859c5022d5f6d11a3b92074d..b33df9d4a32ab06d669fe3067782a67ba1f55b22 100644 (file)
@@ -6,6 +6,7 @@ pub mod code_walker;
 pub mod loader;
 pub mod compile;
 pub mod copier;
+pub mod dispatch;
 pub mod gc;
 pub mod heap;
 pub mod load_state;
@@ -21,23 +22,29 @@ pub mod streams;
 pub mod system_calls;
 pub mod term_stream;
 
+use crate::arena::*;
 use crate::atom_table::*;
+use crate::clause_types::*;
 use crate::forms::*;
-use crate::instructions::*;
 use crate::machine::code_repo::*;
 use crate::machine::compile::*;
+use crate::machine::copier::*;
 use crate::machine::heap::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
+use crate::machine::stack::*;
 use crate::machine::streams::*;
+use crate::parser::ast::*;
+use crate::parser::rug::{Integer, Rational};
 use crate::types::*;
 
 use indexmap::IndexMap;
-
 use lazy_static::lazy_static;
+use ordered_float::OrderedFloat;
 
+use std::cmp::Ordering;
 use std::env;
 use std::path::PathBuf;
 use std::sync::atomic::AtomicBool;
@@ -49,8 +56,6 @@ lazy_static! {
 #[derive(Debug)]
 pub struct Machine {
     pub(super) machine_st: MachineState,
-    pub(super) inner_heap: Heap,
-    pub(super) policies: MachinePolicies,
     pub(super) indices: IndexStore,
     pub(super) code_repo: CodeRepo,
     pub(super) user_input: Stream,
@@ -59,29 +64,6 @@ pub struct Machine {
     pub(super) load_contexts: Vec<LoadContext>,
 }
 
-#[derive(Debug)]
-pub(crate) struct MachinePolicies {
-    call_policy: Box<dyn CallPolicy>,
-    cut_policy: Box<dyn CutPolicy>,
-}
-
-impl MachinePolicies {
-    #[inline]
-    fn new() -> Self {
-        MachinePolicies {
-            call_policy: Box::new(DefaultCallPolicy {}),
-            cut_policy: Box::new(DefaultCutPolicy {}),
-        }
-    }
-}
-
-impl Default for MachinePolicies {
-    #[inline]
-    fn default() -> Self {
-        MachinePolicies::new()
-    }
-}
-
 #[derive(Debug)]
 pub struct LoadContext {
     pub(super) path: PathBuf,
@@ -142,9 +124,7 @@ impl Machine {
         self.machine_st.throw_exception(err);
         return;
     }
-}
 
-impl Machine {
     fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
         if let Some(module) = self.indices.modules.get(&module_name) {
             if let Some(ref code_index) = module.code_dir.get(&key) {
@@ -317,8 +297,6 @@ impl Machine {
 
         let mut wam = Machine {
             machine_st,
-            inner_heap: Heap::new(),
-            policies: MachinePolicies::new(),
             indices: IndexStore::new(),
             code_repo: CodeRepo::new(),
             user_input,
@@ -413,6 +391,12 @@ impl Machine {
             .insert(atom!("user_output"), self.user_output);
 
         self.indices.streams.insert(self.user_output);
+
+        self.indices
+            .stream_aliases
+            .insert(atom!("user_error"), self.user_error);
+
+        self.indices.streams.insert(self.user_error);
     }
 
     fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
@@ -526,20 +510,14 @@ impl Machine {
 
     pub(crate) fn run_query(&mut self) {
         while !self.machine_st.p.is_halt() {
-            self.machine_st.query_stepper(
-                &mut self.indices,
-                &mut self.policies,
-                &mut self.code_repo,
-                &mut self.user_input,
-                &mut self.user_output,
-            );
+            self.query_stepper();
 
             match self.machine_st.p {
                 CodePtr::REPL(code_ptr, p) => {
                     self.handle_toplevel_command(code_ptr, p);
 
                     if self.machine_st.fail {
-                        self.machine_st.backtrack();
+                        self.backtrack();
                     }
                 }
                 _ => {
@@ -548,103 +526,34 @@ impl Machine {
             };
         }
     }
-}
-
-impl MachineState {
-    fn dispatch_instr(
-        &mut self,
-        instr: &Line,
-        indices: &mut IndexStore,
-        policies: &mut MachinePolicies,
-        code_repo: &CodeRepo,
-        user_input: &mut Stream,
-        user_output: &mut Stream,
-    ) {
-        match instr {
-            &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
-            &Line::Choice(ref choice_instr) => self.execute_choice_instr(
-                choice_instr,
-                code_repo,
-                &mut policies.call_policy,
-                &mut indices.global_variables,
-            ),
-            &Line::Cut(ref cut_instr) => {
-                self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
-            }
-            &Line::Control(ref control_instr) => self.execute_ctrl_instr(
-                indices,
-                code_repo,
-                &mut policies.call_policy,
-                &mut policies.cut_policy,
-                user_input,
-                user_output,
-                control_instr,
-            ),
-            &Line::Fact(ref fact_instr) => {
-                self.execute_fact_instr(&fact_instr);
-                self.p += 1;
-            }
-            &Line::IndexingCode(ref indexing_lines) => {
-                self.execute_indexing_instr(indexing_lines, code_repo)
-            }
-            &Line::IndexedChoice(ref choice_instr) => self.execute_indexed_choice_instr(
-                choice_instr,
-                &mut policies.call_policy,
-                &mut indices.global_variables,
-            ),
-            &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(
-                code_repo,
-                &mut policies.call_policy,
-                &mut indices.global_variables,
-            ),
-            &Line::Query(ref query_instr) => {
-                self.execute_query_instr(&query_instr);
-                self.p += 1;
-            }
-        }
-    }
 
-    fn execute_instr(
-        &mut self,
-        indices: &mut IndexStore,
-        policies: &mut MachinePolicies,
-        code_repo: &CodeRepo,
-        user_input: &mut Stream,
-        user_output: &mut Stream,
-    ) {
-        let instr = match code_repo.lookup_instr(self, &self.p) {
+    fn execute_instr(&mut self) {
+        let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) {
             Some(instr) => instr,
             None => return,
         };
 
-        self.dispatch_instr(
-            instr.as_ref(),
-            indices,
-            policies,
-            code_repo,
-            user_input,
-            user_output,
-        );
+        self.dispatch_instr(instr);
     }
 
     fn backtrack(&mut self) {
-        let b = self.b;
-        let or_frame = self.stack.index_or_frame(b);
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame(b);
 
-        self.b0 = or_frame.prelude.b0;
-        self.p = CodePtr::Local(or_frame.prelude.bp);
+        self.machine_st.b0 = or_frame.prelude.b0;
+        self.machine_st.p = CodePtr::Local(or_frame.prelude.bp);
 
-        self.oip = or_frame.prelude.boip;
-        self.iip = or_frame.prelude.biip;
+        self.machine_st.oip = or_frame.prelude.boip;
+        self.machine_st.iip = or_frame.prelude.biip;
 
-        self.pdl.clear();
-        self.fail = false;
+        self.machine_st.pdl.clear();
+        self.machine_st.fail = false;
     }
 
-    fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool {
-        match self.p {
+    fn check_machine_index(&mut self) -> bool {
+        match self.machine_st.p {
             CodePtr::Local(LocalCodePtr::DirEntry(p))
-                if p < code_repo.code.len() => {}
+                if p < self.code_repo.code.len() => {}
             CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
                 return false;
             }
@@ -655,21 +564,14 @@ impl MachineState {
     }
 
     // return true iff verify_attr_interrupt is called.
-    fn verify_attr_stepper(
-        &mut self,
-        indices: &mut IndexStore,
-        policies: &mut MachinePolicies,
-        code_repo: &mut CodeRepo,
-        user_input: &mut Stream,
-        user_output: &mut Stream,
-    ) -> bool {
+    fn verify_attr_stepper(&mut self) -> bool {
         loop {
-            let instr = match code_repo.lookup_instr(self, &self.p) {
+            let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) {
                 Some(instr) => {
-                    if instr.as_ref().is_head_instr() {
+                    if instr.as_ref(&self.code_repo.code).is_head_instr() {
                         instr
                     } else {
-                        let cp = self.p.local();
+                        let cp = self.machine_st.p.local();
                         self.run_verify_attr_interrupt(cp);
                         return true;
                     }
@@ -677,80 +579,876 @@ impl MachineState {
                 None => return false,
             };
 
-            self.dispatch_instr(
-                instr.as_ref(),
-                indices,
-                policies,
-                code_repo,
-                user_input,
-                user_output,
-            );
+            self.dispatch_instr(instr);
 
-            if self.fail {
+            if self.machine_st.fail {
                 self.backtrack();
             }
 
-            if !self.check_machine_index(code_repo) {
+            if !self.check_machine_index() {
                 return false;
             }
         }
     }
 
     fn run_verify_attr_interrupt(&mut self, cp: LocalCodePtr) {
-        let p = self.attr_var_init.verify_attrs_loc;
+        let p = self.machine_st.attr_var_init.verify_attrs_loc;
 
-        self.attr_var_init.cp = cp;
-        self.verify_attr_interrupt(p);
+        self.machine_st.attr_var_init.cp = cp;
+        self.machine_st.verify_attr_interrupt(p);
     }
 
-    fn query_stepper(
-        &mut self,
-        indices: &mut IndexStore,
-        policies: &mut MachinePolicies,
-        code_repo: &mut CodeRepo,
-        user_input: &mut Stream,
-        user_output: &mut Stream,
-    ) {
+    fn query_stepper(&mut self) {
         loop {
-            self.execute_instr(indices, policies, code_repo, user_input, user_output);
+            self.execute_instr();
 
-            if self.fail {
+            if self.machine_st.fail {
                 self.backtrack();
             }
 
-            match self.p {
+            match self.machine_st.p {
                 CodePtr::VerifyAttrInterrupt(_) => {
-                    self.p = CodePtr::Local(self.attr_var_init.cp);
+                    self.machine_st.p = CodePtr::Local(self.machine_st.attr_var_init.cp);
 
-                    let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p);
-                    let instigating_instr = code_repo
-                        .lookup_instr(self, &instigating_p)
+                    let instigating_p = CodePtr::Local(self.machine_st.attr_var_init.instigating_p);
+                    let instigating_instr = self.code_repo
+                        .lookup_instr(&self.machine_st, &instigating_p)
                         .unwrap();
 
-                    if !instigating_instr.as_ref().is_head_instr() {
-                        let cp = self.p.local();
+                    if !instigating_instr.as_ref(&self.code_repo.code).is_head_instr() {
+                        let cp = self.machine_st.p.local();
                         self.run_verify_attr_interrupt(cp);
-                    } else if !self.verify_attr_stepper(
-                        indices,
-                        policies,
-                        code_repo,
-                        user_input,
-                        user_output,
-                    ) {
-                        if self.fail {
+                    } else if !self.verify_attr_stepper() {
+                        if self.machine_st.fail {
                             break;
                         }
 
-                        let cp = self.p.local();
+                        let cp = self.machine_st.p.local();
                         self.run_verify_attr_interrupt(cp);
                     }
                 }
                 _ => {
-                    if !self.check_machine_index(code_repo) {
+                    if !self.check_machine_index() {
                         break;
                     }
                 }
             }
         }
     }
+
+    pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) {
+        match inlined {
+            &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => {
+                let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_1));
+                let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_2));
+
+                self.machine_st.compare_numbers(cmp, n1, n2);
+            }
+            &InlinedClauseType::IsAtom(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                read_heap_cell!(d,
+                    (HeapCellValueTag::Atom, (_name, arity)) => {
+                        if arity == 0 {
+                            self.machine_st.p += 1;
+                        } else {
+                            self.machine_st.fail = true;
+                        }
+                    }
+                    (HeapCellValueTag::Char) => {
+                        self.machine_st.p += 1;
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                );
+            }
+            &InlinedClauseType::IsAtomic(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                read_heap_cell!(d,
+                    (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+                     HeapCellValueTag::Cons) => {
+                        self.machine_st.p += 1;
+                    }
+                    (HeapCellValueTag::Atom, (_name, arity)) => {
+                        if arity == 0 {
+                            self.machine_st.p += 1;
+                        } else {
+                            self.machine_st.fail = true;
+                        }
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                );
+            }
+            &InlinedClauseType::IsInteger(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                match Number::try_from(d) {
+                    Ok(Number::Fixnum(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    Ok(Number::Integer(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    Ok(Number::Rational(n)) => {
+                        if n.denom() == &1 {
+                            self.machine_st.p += 1;
+                        } else {
+                            self.machine_st.fail = true;
+                        }
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                }
+            }
+            &InlinedClauseType::IsCompound(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                read_heap_cell!(d,
+                    (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+                     HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+                        self.machine_st.p += 1;
+                    }
+                    (HeapCellValueTag::Atom, (_name, arity)) => {
+                        if arity > 0 {
+                            self.machine_st.p += 1;
+                        } else {
+                            self.machine_st.fail = true;
+                        }
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                );
+            }
+            &InlinedClauseType::IsFloat(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                match Number::try_from(d) {
+                    Ok(Number::Float(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                }
+            }
+            &InlinedClauseType::IsNumber(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                match Number::try_from(d) {
+                    Ok(Number::Fixnum(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    Ok(Number::Integer(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    Ok(Number::Rational(n)) => {
+                        if n.denom() == &1 {
+                            self.machine_st.p += 1;
+                        } else {
+                            self.machine_st.fail = true;
+                        }
+                    }
+                    Ok(Number::Float(_)) => {
+                        self.machine_st.p += 1;
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                }
+            }
+            &InlinedClauseType::IsRational(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                read_heap_cell!(d,
+                    (HeapCellValueTag::Cons, ptr) => {
+                        match_untyped_arena_ptr!(ptr,
+                             (ArenaHeaderTag::Rational, _r) => {
+                                 self.machine_st.p += 1;
+                             }
+                             _ => {
+                                 self.machine_st.fail = true;
+                             }
+                        );
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                );
+            }
+            &InlinedClauseType::IsNonVar(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                match d.get_tag() {
+                    HeapCellValueTag::AttrVar
+                    | HeapCellValueTag::Var
+                    | HeapCellValueTag::StackVar => {
+                        self.machine_st.fail = true;
+                    }
+                    _ => {
+                        self.machine_st.p += 1;
+                    }
+                }
+            }
+            &InlinedClauseType::IsVar(r1) => {
+                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
+
+                match d.get_tag() {
+                    HeapCellValueTag::AttrVar |
+                    HeapCellValueTag::Var |
+                    HeapCellValueTag::StackVar => {
+                        self.machine_st.p += 1;
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                    }
+                }
+            }
+        }
+    }
+
+    #[inline(always)]
+    pub(super) fn execute_dynamic_indexed_choice_instr(&mut self) {
+        let p = self.machine_st.p.local();
+
+        match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
+            Some((offset, oi, ii, is_next_clause)) => {
+                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc()));
+                self.machine_st.oip = oi;
+                self.machine_st.iip = ii;
+
+                match self.machine_st.dynamic_mode {
+                    FirstOrNext::First if !is_next_clause => {
+                        self.machine_st.p =
+                            CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
+                    }
+                    FirstOrNext::First => {
+                        // there's a leading DynamicElse that sets self.machine_st.cc.
+                        // self.machine_st.cc = self.machine_st.global_clock;
+
+                        // see that there is a following dynamic_else
+                        // clause so we avoid generating a choice
+                        // point in case there isn't.
+                        match self.find_living_dynamic(oi, ii + 1) {
+                            Some(_) => {
+                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                self.machine_st.num_of_args += 2;
+                                self.machine_st.indexed_try(offset);
+                                self.machine_st.num_of_args -= 2;
+                            }
+                            None => {
+                                self.machine_st.p =
+                                    CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
+                                self.machine_st.oip = 0;
+                                self.machine_st.iip = 0;
+                            }
+                        }
+                    }
+                    FirstOrNext::Next => {
+                        let b = self.machine_st.b;
+                        let n = self.machine_st
+                            .stack
+                            .index_or_frame(b)
+                            .prelude
+                            .univ_prelude
+                            .num_cells;
+
+                        self.machine_st.cc = cell_as_fixnum!(
+                            self.machine_st.stack[stack_loc!(OrFrame, b, n-2)]
+                        ).get_num() as usize;
+
+                        if is_next_clause {
+                            match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
+                                Some(_) => {
+                                    self.retry(offset);
+
+                                    try_or_fail!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                                None => {
+                                    self.trust(offset);
+
+                                    try_or_fail!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                            }
+                        } else {
+                            self.trust(offset);
+
+                            try_or_fail!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+                        }
+                    }
+                }
+            }
+            None => {
+                self.machine_st.fail = true;
+            }
+        }
+
+        self.machine_st.dynamic_mode = FirstOrNext::Next;
+    }
+
+    #[inline(always)]
+    fn retry_me_else(&mut self, offset: usize) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+        let n = or_frame.prelude.univ_prelude.num_cells;
+
+        for i in 0..n {
+            self.machine_st.registers[i + 1] = or_frame[i];
+        }
+
+        self.machine_st.num_of_args = n;
+        self.machine_st.e = or_frame.prelude.e;
+        self.machine_st.cp = or_frame.prelude.cp;
+
+        or_frame.prelude.bp = self.machine_st.p.local() + offset;
+
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+        let target_h = or_frame.prelude.h;
+
+        self.machine_st.tr = or_frame.prelude.tr;
+
+        self.machine_st.attr_var_init.reset();
+        self.machine_st.hb = self.machine_st.heap.len();
+        self.machine_st.p += 1;
+
+        self.unwind_trail(old_tr, curr_tr);
+
+        self.machine_st.trail.truncate(self.machine_st.tr);
+        self.machine_st.heap.truncate(target_h);
+    }
+
+    #[inline(always)]
+    fn retry(&mut self, offset: usize) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+        let n = or_frame.prelude.univ_prelude.num_cells;
+
+        for i in 0..n {
+            self.machine_st.registers[i+1] = or_frame[i];
+        }
+
+        self.machine_st.num_of_args = n;
+        self.machine_st.e = or_frame.prelude.e;
+        self.machine_st.cp = or_frame.prelude.cp;
+
+        // WAS: or_frame.prelude.bp = self.machine_st.p.local() + 1;
+        or_frame.prelude.biip += 1;
+
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+        let target_h = or_frame.prelude.h;
+
+        self.machine_st.tr = or_frame.prelude.tr;
+        self.machine_st.attr_var_init.reset();
+
+        self.unwind_trail(old_tr, curr_tr);
+
+        self.machine_st.trail.truncate(self.machine_st.tr);
+        self.machine_st.heap.truncate(target_h);
+
+        self.machine_st.hb = self.machine_st.heap.len();
+        self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset));
+
+        self.machine_st.oip = 0;
+        self.machine_st.iip = 0;
+    }
+
+    #[inline(always)]
+    fn trust(&mut self, offset: usize) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame(b);
+        let n = or_frame.prelude.univ_prelude.num_cells;
+
+        for i in 0..n {
+            self.machine_st.registers[i+1] = or_frame[i];
+        }
+
+        self.machine_st.num_of_args = n;
+        self.machine_st.e = or_frame.prelude.e;
+        self.machine_st.cp = or_frame.prelude.cp;
+
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+        let target_h = or_frame.prelude.h;
+
+        self.machine_st.tr = or_frame.prelude.tr;
+
+        self.machine_st.attr_var_init.reset();
+        self.machine_st.b = or_frame.prelude.b;
+
+        self.unwind_trail(old_tr, curr_tr);
+
+        self.machine_st.trail.truncate(self.machine_st.tr);
+        self.machine_st.stack.truncate(b);
+        self.machine_st.heap.truncate(target_h);
+
+        self.machine_st.hb = self.machine_st.heap.len();
+        self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset));
+
+        self.machine_st.oip = 0;
+        self.machine_st.iip = 0;
+    }
+
+    #[inline(always)]
+    fn trust_me(&mut self) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame(b);
+        let n = or_frame.prelude.univ_prelude.num_cells;
+
+        for i in 0..n {
+            self.machine_st.registers[i+1] = or_frame[i];
+        }
+
+        self.machine_st.num_of_args = n;
+        self.machine_st.e = or_frame.prelude.e;
+        self.machine_st.cp = or_frame.prelude.cp;
+
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+        let target_h = or_frame.prelude.h;
+
+        self.machine_st.tr = or_frame.prelude.tr;
+
+        self.machine_st.attr_var_init.reset();
+        self.machine_st.b = or_frame.prelude.b;
+
+        self.unwind_trail(old_tr, curr_tr);
+
+        self.machine_st.trail.truncate(self.machine_st.tr);
+        self.machine_st.stack.truncate(b);
+        self.machine_st.heap.truncate(target_h);
+
+        self.machine_st.hb = self.machine_st.heap.len();
+        self.machine_st.p += 1;
+    }
+
+    #[inline(always)]
+    fn context_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
+        if self.machine_st.last_call {
+            self.try_execute(name, arity, idx)
+        } else {
+            self.try_call(name, arity, idx)
+        }
+    }
+
+    #[inline(always)]
+    fn try_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
+        match idx.get() {
+            IndexPtr::DynamicUndefined => {
+                self.machine_st.fail = true;
+                return Ok(());
+            }
+            IndexPtr::Undefined => {
+                return Err(self.machine_st.throw_undefined_error(name, arity));
+            }
+            IndexPtr::DynamicIndex(compiled_tl_index) => {
+                self.machine_st.dynamic_mode = FirstOrNext::First;
+                self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
+            }
+            IndexPtr::Index(compiled_tl_index) => {
+                self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    fn try_execute(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
+        match idx.get() {
+            IndexPtr::DynamicUndefined => {
+                self.machine_st.fail = true;
+                return Ok(());
+            }
+            IndexPtr::Undefined => {
+                return Err(self.machine_st.throw_undefined_error(name, arity));
+            }
+            IndexPtr::DynamicIndex(compiled_tl_index) => {
+                self.machine_st.dynamic_mode = FirstOrNext::First;
+                self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index));
+            }
+            IndexPtr::Index(compiled_tl_index) => {
+                self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    fn call_builtin(&mut self, ct: &BuiltInClauseType) -> CallResult {
+        match ct {
+            &BuiltInClauseType::AcyclicTerm => {
+                let addr = self.machine_st.registers[1];
+                self.machine_st.fail = self.machine_st.is_cyclic_term(addr);
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Arg => {
+                self.machine_st.try_arg()?;
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Compare => {
+                let stub_gen = || functor_stub(atom!("compare"), 3);
+
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let a2 = self.machine_st.registers[2];
+                let a3 = self.machine_st.registers[3];
+
+                read_heap_cell!(a1,
+                    (HeapCellValueTag::Str, s) => {
+                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                            .get_name_and_arity();
+
+                        match name {
+                            atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
+                            }
+                            _ => {
+                                let err = self.machine_st.domain_error(DomainErrorType::Order, a1);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
+                            }
+                        }
+                    }
+                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                    }
+                    _ => {
+                        let err = self.machine_st.type_error(ValidType::Atom, a1);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                );
+
+                let atom = match compare_term_test!(self.machine_st, a2, a3) {
+                    Some(Ordering::Greater) => {
+                        atom!(">")
+                    }
+                    Some(Ordering::Equal) => {
+                        atom!("=")
+                    }
+                    None | Some(Ordering::Less) => {
+                        atom!("<")
+                    }
+                };
+
+                self.machine_st.unify_atom(atom, a1);
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::CompareTerm(qt) => {
+                self.machine_st.compare_term(qt);
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Read => {
+                let stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
+                    atom!("read"),
+                    2,
+                )?;
+
+                match self.machine_st.read(stream, &self.indices.op_dir) {
+                    Ok(offset) => {
+                        let value = self.machine_st.registers[2];
+                        unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
+                    }
+                    Err(ParserError::UnexpectedEOF) => {
+                        let value = self.machine_st.registers[2];
+                        self.machine_st.unify_atom(atom!("end_of_file"), value);
+                    }
+                    Err(e) => {
+                        let stub = functor_stub(atom!("read"), 2);
+                        let err = self.machine_st.syntax_error(e);
+
+                        return Err(self.machine_st.error_form(err, stub));
+                    }
+                };
+
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::CopyTerm => {
+                self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Eq => {
+                let a1 = self.machine_st.registers[1];
+                let a2 = self.machine_st.registers[2];
+
+                self.machine_st.fail = self.machine_st.eq_test(a1, a2);
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Ground => {
+                self.machine_st.fail = self.machine_st.ground_test();
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Functor => {
+                self.machine_st.try_functor()?;
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::NotEq => {
+                let a1 = self.machine_st.registers[1];
+                let a2 = self.machine_st.registers[2];
+
+                self.machine_st.fail =
+                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+                        true
+                    } else {
+                        false
+                    };
+
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Sort => {
+                self.machine_st.check_sort_errors()?;
+
+                let stub_gen = || functor_stub(atom!("sort"), 2);
+                let mut list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?;
+
+                list.sort_unstable_by(|v1, v2| {
+                    compare_term_test!(self.machine_st, *v1, *v2).unwrap_or(Ordering::Less)
+                });
+
+                list.dedup_by(|v1, v2| {
+                    compare_term_test!(self.machine_st, *v1, *v2) == Some(Ordering::Equal)
+                });
+
+                let heap_addr = heap_loc_as_cell!(
+                    iter_to_heap_list(&mut self.machine_st.heap, list.into_iter())
+                );
+
+                let r2 = self.machine_st.registers[2];
+                unify_fn!(&mut self.machine_st, r2, heap_addr);
+
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::KeySort => {
+                self.machine_st.check_keysort_errors()?;
+
+                let stub_gen = || functor_stub(atom!("keysort"), 2);
+                let list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?;
+
+                let mut key_pairs = Vec::with_capacity(list.len());
+
+                for val in list {
+                    let key = self.machine_st.project_onto_key(val)?;
+                    key_pairs.push((key, val));
+                }
+
+                key_pairs.sort_by(|a1, a2| {
+                    compare_term_test!(self.machine_st, a1.0, a2.0).unwrap_or(Ordering::Less)
+                });
+
+                let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
+                let heap_addr = heap_loc_as_cell!(
+                    iter_to_heap_list(&mut self.machine_st.heap, key_pairs)
+                );
+
+                let r2 = self.machine_st.registers[2];
+                unify_fn!(&mut self.machine_st, r2, heap_addr);
+
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+            &BuiltInClauseType::Is(r, ref at) => {
+                let n1 = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+                let n2 = self.machine_st.get_number(at)?;
+
+                match n2 {
+                    Number::Fixnum(n) => self.machine_st.unify_fixnum(n, n1),
+                    Number::Float(n) => {
+                        // TODO: argghh.. deal with it.
+                        let n = arena_alloc!(n, &mut self.machine_st.arena);
+                        self.machine_st.unify_f64(n, n1)
+                    }
+                    Number::Integer(n) => self.machine_st.unify_big_int(n, n1),
+                    Number::Rational(n) => self.machine_st.unify_rational(n, n1),
+                }
+
+                return_from_clause!(self.machine_st.last_call, self.machine_st)
+            }
+        }
+    }
+
+    #[inline(always)]
+    fn call_clause_type(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
+        let (name, arity) = key;
+
+        match ClauseType::from(name, arity) {
+            ClauseType::BuiltIn(built_in) => {
+                self.machine_st.setup_built_in_call(built_in);
+                self.call_builtin(&built_in)?;
+            }
+            ClauseType::CallN => {
+                self.machine_st.handle_internal_call_n(arity);
+
+                if self.machine_st.fail {
+                    return Ok(());
+                }
+
+                self.machine_st.p = CodePtr::CallN(
+                    arity,
+                    self.machine_st.p.local(),
+                    self.machine_st.last_call,
+                );
+            }
+            ClauseType::Inlined(inlined) => {
+                self.execute_inlined(&inlined);
+
+                if self.machine_st.last_call {
+                    self.machine_st.p = CodePtr::Local(self.machine_st.cp);
+                }
+            }
+            ClauseType::Named(..) if module_name == atom!("user") => {
+                return if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
+                    self.context_call(name, arity, idx)
+                } else {
+                    Err(self.machine_st.throw_undefined_error(name, arity))
+                };
+            }
+            ClauseType::Named(..) => {
+                return if let Some(module) = self.indices.modules.get(&module_name) {
+                    if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
+                        self.context_call(name, arity, idx)
+                    } else {
+                        Err(self.machine_st.throw_undefined_error(name, arity))
+                    }
+                } else {
+                    let stub = functor_stub(name, arity);
+                    let err = self.machine_st.module_resolution_error(module_name, name, arity);
+
+                    Err(self.machine_st.error_form(err, stub))
+                };
+            }
+            ClauseType::System(_) => {
+                let (name, arity) = key;
+                let name = functor!(name);
+
+                let stub = functor_stub(atom!("call"), arity + 1);
+                let err = self.machine_st.type_error(ValidType::Callable, name);
+
+                return Err(self.machine_st.error_form(err, stub));
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    fn call_n(&mut self, module_name: Atom, arity: usize) -> CallResult {
+        if let Some(key) = self.machine_st.setup_call_n(arity) {
+            self.call_clause_type(module_name, key)?;
+        }
+
+        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+    }
+
+    #[inline(always)]
+    fn run_cleaners(&mut self) -> bool {
+        use std::sync::Once;
+
+        static CLEANER_INIT: Once = Once::new();
+
+        static mut RCWH: usize = 0;
+        static mut RCWOH: usize = 0;
+
+        let (r_c_w_h, r_c_wo_h) = unsafe {
+            CLEANER_INIT.call_once(|| {
+                let r_c_w_h_atom = atom!("run_cleaners_with_handling");
+                let r_c_wo_h_atom = atom!("run_cleaners_without_handling");
+                let iso_ext = atom!("iso_ext");
+
+                RCWH = self.indices.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
+                           .and_then(|item| item.local())
+                           .unwrap();
+                RCWOH = self.indices.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
+                            .and_then(|item| item.local())
+                            .unwrap();
+            });
+
+            (RCWH, RCWOH)
+        };
+
+        if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() {
+            if self.machine_st.b < b_cutoff {
+                let (idx, arity) = if self.machine_st.block > prev_block {
+                    (dir_entry!(r_c_w_h), 0)
+                } else {
+                    self.machine_st.registers[1] = fixnum_as_cell!(
+                        Fixnum::build_with(b_cutoff as i64)
+                    );
+
+                    (dir_entry!(r_c_wo_h), 1)
+                };
+
+                if self.machine_st.last_call {
+                    self.machine_st.execute_at_index(arity, idx);
+                } else {
+                    self.machine_st.call_at_index(arity, idx);
+                }
+
+                return true;
+            }
+        }
+
+        false
+    }
+
+    pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
+        // the sequence is reversed to respect the chronology of trail
+        // additions, now that deleted attributes can be undeleted by
+        // backtracking.
+        for i in (a1..a2).rev() {
+            let h = self.machine_st.trail[i].get_value() as usize;
+
+            match self.machine_st.trail[i].get_tag() {
+                TrailEntryTag::TrailedHeapVar => {
+                    self.machine_st.heap[h] = heap_loc_as_cell!(h);
+                }
+                TrailEntryTag::TrailedStackVar => {
+                    self.machine_st.stack[h] = stack_loc_as_cell!(h);
+                }
+                TrailEntryTag::TrailedAttrVar => {
+                    self.machine_st.heap[h] = attr_var_as_cell!(h);
+                }
+                TrailEntryTag::TrailedAttrVarHeapLink => {
+                    self.machine_st.heap[h] = heap_loc_as_cell!(h);
+                }
+                TrailEntryTag::TrailedAttrVarListLink => {
+                    let l = self.machine_st.trail[i + 1].get_value();
+                    self.machine_st.heap[h] = list_loc_as_cell!(l);
+                }
+                TrailEntryTag::TrailedBlackboardEntry => {
+                    let key = Atom::from(h);
+
+                    match self.indices.global_variables.get_mut(&key) {
+                        Some((_, ref mut loc)) => *loc = None,
+                        None => unreachable!(),
+                    }
+                }
+                TrailEntryTag::TrailedBlackboardOffset => {
+                    let key = Atom::from(h);
+                    let value_cell = HeapCellValue::from(u64::from(self.machine_st.trail[i + 1]));
+
+                    match self.indices.global_variables.get_mut(&key) {
+                        Some((_, ref mut loc)) => *loc = Some(value_cell),
+                        None => unreachable!(),
+                    }
+                }
+                TrailEntryTag::TrailedAttachedValue => {
+                }
+            }
+        }
+    }
 }
index e2c74be1702c899eefddd52693eb564e7ea0aa19..c3711db001bd6c3ef0ab5080bbeddcdab247b3c9 100644 (file)
@@ -542,14 +542,12 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
 
 #[derive(Debug)]
 pub(crate) struct Preprocessor {
-    flags: MachineFlags,
     queue: VecDeque<VecDeque<Term>>,
 }
 
 impl Preprocessor {
-    pub(super) fn new(flags: MachineFlags) -> Self {
+    pub(super) fn new() -> Self {
         Preprocessor {
-            flags,
             queue: VecDeque::new(),
         }
     }
index 15217cec46306b79b07f844704812f5e83237be6..d84c2ea988451caad3c4cec0209e0b905b93574e 100644 (file)
@@ -11,7 +11,7 @@ use crate::heap_iter::*;
 use crate::heap_print::*;
 use crate::instructions::*;
 use crate::machine;
-use crate::machine::code_repo::CodeRepo;
+use crate::machine::Machine;
 use crate::machine::code_walker::*;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
@@ -438,7 +438,7 @@ impl MachineState {
             )
         );
 
-        unify_fn!(self, list_of_vars, outcome);
+        unify_fn!(*self, list_of_vars, outcome);
     }
 
     fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) {
@@ -806,20 +806,13 @@ impl MachineState {
 
         Ok(string)
     }
+}
 
-    pub(super) fn system_call(
-        &mut self,
-        ct: &SystemClauseType,
-        code_repo: &CodeRepo,
-        indices: &mut IndexStore,
-        call_policy: &mut Box<dyn CallPolicy>,
-        cut_policy: &mut Box<dyn CutPolicy>,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
-    ) -> CallResult {
+impl Machine {
+    pub(super) fn system_call(&mut self, ct: &SystemClauseType) -> CallResult {
         match ct {
             &SystemClauseType::BindFromRegister => {
-                let reg = self.store(self.deref(self.registers[2]));
+                let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
                 let n = match Number::try_from(reg) {
                     Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
                     Ok(Number::Integer(n)) => n.to_usize(),
@@ -830,97 +823,101 @@ impl MachineState {
 
                 if let Some(n) = n {
                     if n <= MAX_ARITY {
-                        let target = self.registers[n];
-                        let addr = self.registers[1];
+                        let target = self.machine_st.registers[n];
+                        let addr = self.machine_st.registers[1];
 
-                        unify_fn!(self, addr, target);
-                        return return_from_clause!(self.last_call, self);
+                        unify_fn!(self.machine_st, addr, target);
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::CurrentHostname => {
                 match hostname::get().ok() {
                     Some(host) => match host.to_str() {
                         Some(host) => {
-                            let hostname = self.atom_tbl.build_with(host);
+                            let hostname = self.machine_st.atom_tbl.build_with(host);
+
+                            self.machine_st.unify_atom(
+                                hostname,
+                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+                            );
 
-                            self.unify_atom(hostname, self.store(self.deref(self.registers[1])));
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                         None => {}
                     },
                     None => {}
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
                 return Ok(());
             }
             &SystemClauseType::CurrentInput => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let stream = *current_input_stream;
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let stream = self.user_input;
 
                 if let Some(var) = addr.as_var() {
-                    self.bind(var, stream_as_cell!(stream));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.bind(var, stream_as_cell!(stream));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
                 read_heap_cell!(addr,
                     (HeapCellValueTag::Cons, cons_ptr) => {
                         match_untyped_arena_ptr!(cons_ptr,
                              (ArenaHeaderTag::Stream, other_stream) => {
-                                 self.fail = stream != other_stream;
+                                 self.machine_st.fail = stream != other_stream;
                              }
                              _ => {
                                  let stub = functor_stub(atom!("current_input"), 1);
-                                 let err = self.domain_error(DomainErrorType::Stream, addr);
+                                 let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                                 return Err(self.error_form(err, stub));
+                                 return Err(self.machine_st.error_form(err, stub));
                              }
                         );
                     }
                     _ => {
                         let stub = functor_stub(atom!("current_input"), 1);
-                        let err = self.domain_error(DomainErrorType::Stream, addr);
+                        let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 );
             }
             &SystemClauseType::CurrentOutput => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let stream = *current_output_stream;
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let stream = self.user_output;
 
                 if let Some(var) = addr.as_var() {
-                    self.bind(var, stream_as_cell!(stream));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.bind(var, stream_as_cell!(stream));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
                 read_heap_cell!(addr,
                     (HeapCellValueTag::Cons, cons_ptr) => {
                         match_untyped_arena_ptr!(cons_ptr,
                              (ArenaHeaderTag::Stream, other_stream) => {
-                                 self.fail = stream != other_stream;
+                                 self.machine_st.fail = stream != other_stream;
                              }
                              _ => {
                                  let stub = functor_stub(atom!("current_output"), 1);
-                                 let err = self.domain_error(DomainErrorType::Stream, addr);
+                                 let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                                 return Err(self.error_form(err, stub));
+                                 return Err(self.machine_st.error_form(err, stub));
                              }
                         );
                     }
                     _ => {
                         let stub = functor_stub(atom!("current_output"), 1);
-                        let err = self.domain_error(DomainErrorType::Stream, addr);
+                        let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 );
             }
             &SystemClauseType::DirectoryFiles => {
-                if let Some(dir) = self.value_to_str_like(self.registers[1]) {
+                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     let path = std::path::Path::new(dir.as_str());
                     let mut files = Vec::new();
 
@@ -928,7 +925,7 @@ impl MachineState {
                         for entry in entries {
                             if let Ok(entry) = entry {
                                 if let Some(name) = entry.file_name().to_str() {
-                                    let name = self.atom_tbl.build_with(name);
+                                    let name = self.machine_st.atom_tbl.build_with(name);
                                     files.push(atom_as_cstr_cell!(name));
 
                                     continue;
@@ -936,122 +933,122 @@ impl MachineState {
                             }
 
                             let stub = functor_stub(atom!("directory_files"), 2);
-                            let err = self.representation_error(RepFlag::Character);
-                            let err = self.error_form(err, stub);
+                            let err = self.machine_st.representation_error(RepFlag::Character);
+                            let err = self.machine_st.error_form(err, stub);
 
                             return Err(err);
                         }
 
                         let files_list = heap_loc_as_cell!(
-                            iter_to_heap_list(&mut self.heap, files.into_iter())
+                            iter_to_heap_list(&mut self.machine_st.heap, files.into_iter())
                         );
 
-                        unify!(self, self.registers[2], files_list);
-                        return return_from_clause!(self.last_call, self);
+                        unify!(self.machine_st, self.machine_st.registers[2], files_list);
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::FileSize => {
-                if let Some(file) = self.value_to_str_like(self.registers[1]) {
+                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     let len = Number::arena_from(
                         fs::metadata(file.as_str()).unwrap().len(),
-                        &mut self.arena,
+                        &mut self.machine_st.arena,
                     );
 
                     match len {
-                        Number::Fixnum(n) => self.unify_fixnum(n, self.registers[2]),
-                        Number::Integer(n) => self.unify_big_int(n, self.registers[2]),
+                        Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]),
+                        Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]),
                         _ => unreachable!(),
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::FileExists => {
-                if let Some(file) = self.value_to_str_like(self.registers[1]) {
+                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     let file_str = file.as_str();
 
                     if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::DirectoryExists => {
-                if let Some(dir) = self.value_to_str_like(self.registers[1]) {
+                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     let dir_str = dir.as_str();
 
                     if !std::path::Path::new(dir_str).exists()
                         || !fs::metadata(dir_str).unwrap().is_dir()
                     {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::DirectorySeparator => {
-                self.unify_char(std::path::MAIN_SEPARATOR, self.registers[1]);
+                self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]);
             }
             &SystemClauseType::MakeDirectory => {
-                if let Some(dir) = self.value_to_str_like(self.registers[1]) {
+                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match fs::create_dir(dir.as_str()) {
                         Ok(_) => {}
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::MakeDirectoryPath => {
-                if let Some(dir) = self.value_to_str_like(self.registers[1]) {
+                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
 
                     match fs::create_dir_all(dir.as_str()) {
                         Ok(_) => {}
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::DeleteFile => {
-                if let Some(file) = self.value_to_str_like(self.registers[1]) {
+                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match fs::remove_file(file.as_str()) {
                         Ok(_) => {}
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 }
             }
             &SystemClauseType::RenameFile => {
-                if let Some(file) = self.value_to_str_like(self.registers[1]) {
-                    if let Some(renamed) = self.value_to_str_like(self.registers[2]) {
+                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+                    if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
                         if fs::rename(file.as_str(), renamed.as_str()).is_ok() {
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::DeleteDirectory => {
-                if let Some(dir) = self.value_to_str_like(self.registers[1]) {
+                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match fs::remove_dir(dir.as_str()) {
                         Ok(_) => {}
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
@@ -1063,67 +1060,67 @@ impl MachineState {
                         Some(d) => d,
                         _ => {
                             let stub = functor_stub(atom!("working_directory"), 2);
-                            let err = self.representation_error(RepFlag::Character);
-                            let err = self.error_form(err, stub);
+                            let err = self.machine_st.representation_error(RepFlag::Character);
+                            let err = self.machine_st.error_form(err, stub);
 
                             return Err(err);
                         }
                     };
 
-                    let current_atom = self.atom_tbl.build_with(&current);
+                    let current_atom = self.machine_st.atom_tbl.build_with(&current);
 
-                    self.unify_complete_string(
+                    self.machine_st.unify_complete_string(
                         current_atom,
-                        self.store(self.deref(self.registers[1])),
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
                     );
 
-                    if self.fail {
+                    if self.machine_st.fail {
                         return Ok(());
                     }
 
-                    if let Some(next) = self.value_to_str_like(self.registers[2]) {
+                    if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
                         if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() {
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::PathCanonical => {
-                if let Some(path) = self.value_to_str_like(self.registers[1]) {
+                if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match fs::canonicalize(path.as_str()) {
                         Ok(canonical) => {
                             let cs = match canonical.to_str() {
                                 Some(s) => s,
                                 _ => {
                                     let stub = functor_stub(atom!("path_canonical"), 2);
-                                    let err = self.representation_error(RepFlag::Character);
-                                    let err = self.error_form(err, stub);
+                                    let err = self.machine_st.representation_error(RepFlag::Character);
+                                    let err = self.machine_st.error_form(err, stub);
 
                                     return Err(err);
                                 }
                             };
 
-                            let canonical_atom = self.atom_tbl.build_with(cs);
+                            let canonical_atom = self.machine_st.atom_tbl.build_with(cs);
 
-                            self.unify_complete_string(
+                            self.machine_st.unify_complete_string(
                                 canonical_atom,
-                                self.store(self.deref(self.registers[2])),
+                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                             );
 
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                         _ => {
                         }
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::FileTime => {
-                if let Some(file) = self.value_to_str_like(self.registers[1]) {
-                    let which = cell_as_atom!(self.store(self.deref(self.registers[2])));
+                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+                    let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
 
                     if let Ok(md) = fs::metadata(file.as_str()) {
                         if let Ok(time) = match which {
@@ -1136,58 +1133,58 @@ impl MachineState {
                         } {
                             let chars_atom = self.systemtime_to_timestamp(time);
 
-                            self.unify_complete_string(
+                            self.machine_st.unify_complete_string(
                                 chars_atom,
-                                self.registers[3],
+                                self.machine_st.registers[3],
                             );
 
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::AtomChars => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(a1,
                     (HeapCellValueTag::Char) => {
-                        let h = self.heap.len();
+                        let h = self.machine_st.heap.len();
 
-                        self.heap.push(a1);
-                        self.heap.push(empty_list_as_cell!());
+                        self.machine_st.heap.push(a1);
+                        self.machine_st.heap.push(empty_list_as_cell!());
 
-                        unify!(self, self.registers[2], list_loc_as_cell!(h));
+                        unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
                     }
                     (HeapCellValueTag::Atom, (name, arity)) => {
                         if arity == 0 {
-                            self.unify_complete_string(
+                            self.machine_st.unify_complete_string(
                                 name,
-                                self.store(self.deref(self.registers[2])),
+                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                             );
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                         }
                     }
                     (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                        let a2 = self.store(self.deref(self.registers[2]));
+                        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                        if let Some(str_like) = self.value_to_str_like(a2) {
+                        if let Some(str_like) = self.machine_st.value_to_str_like(a2) {
                             let atom = match str_like {
                                 AtomOrString::Atom(atom) => {
                                     atom
                                 }
                                 AtomOrString::String(string) => {
-                                    self.atom_tbl.build_with(&string)
+                                    self.machine_st.atom_tbl.build_with(&string)
                                 }
                             };
 
-                            self.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
-                            return return_from_clause!(self.last_call, self);
+                            self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
 
-                        self.fail = true;
+                        self.machine_st.fail = true;
                     }
                     _ => {
                         unreachable!();
@@ -1195,37 +1192,37 @@ impl MachineState {
                 );
             }
             &SystemClauseType::AtomCodes => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(a1,
                     (HeapCellValueTag::Char, c) => {
-                        let h = self.heap.len();
+                        let h = self.machine_st.heap.len();
 
-                        self.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
-                        self.heap.push(empty_list_as_cell!());
+                        self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                        self.machine_st.heap.push(empty_list_as_cell!());
 
-                        unify!(self, list_loc_as_cell!(h), self.registers[2]);
+                        unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
                     }
                     (HeapCellValueTag::Atom, (name, arity)) => {
                         if arity == 0 {
                             let iter = name.chars()
                                 .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
 
-                            let h = iter_to_heap_list(&mut self.heap, iter);
-                            unify!(self, heap_loc_as_cell!(h), self.registers[2]);
+                            let h = iter_to_heap_list(&mut self.machine_st.heap, iter);
+                            unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]);
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                         }
                     }
                     (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
                         let stub_gen = || functor_stub(atom!("atom_codes"), 2);
 
-                        match self.try_from_list(self.registers[2], stub_gen) {
+                        match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) {
                             Ok(addrs) => {
-                                let string = self.codes_to_string(addrs.into_iter(), stub_gen)?;
-                                let atom = self.atom_tbl.build_with(&string);
+                                let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+                                let atom = self.machine_st.atom_tbl.build_with(&string);
 
-                                self.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
+                                self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
                             }
                             Err(e) => {
                                 return Err(e);
@@ -1238,14 +1235,14 @@ impl MachineState {
                 );
             }
             &SystemClauseType::AtomLength => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 let len: i64 = read_heap_cell!(a1,
                     (HeapCellValueTag::Atom, (name, arity)) => {
                         if arity == 0 {
                             name.chars().count() as i64
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
@@ -1257,28 +1254,28 @@ impl MachineState {
                     }
                 );
 
-                self.unify_fixnum(
+                self.machine_st.unify_fixnum(
                     Fixnum::build_with(len),
-                    self.store(self.deref(self.registers[2])),
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                 );
             }
             &SystemClauseType::CallContinuation => {
                 let stub_gen = || functor_stub(atom!("call_continuation"), 1);
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                match self.try_from_list(a1, stub_gen) {
+                match self.machine_st.try_from_list(a1, stub_gen) {
                     Err(e) => return Err(e),
                     Ok(cont_chunks) => {
-                        let mut return_p = if self.last_call {
-                            self.cp
+                        let mut return_p = if self.machine_st.last_call {
+                            self.machine_st.cp
                         } else {
-                            self.p.local() + 1
+                            self.machine_st.p.local() + 1
                         };
 
-                        self.p = CodePtr::Local(return_p);
+                        self.machine_st.p = CodePtr::Local(return_p);
 
                         for chunk in cont_chunks.into_iter().rev() {
-                            return_p = self.call_continuation_chunk(chunk, return_p);
+                            return_p = self.machine_st.call_continuation_chunk(chunk, return_p);
                         }
                     }
                 }
@@ -1287,98 +1284,118 @@ impl MachineState {
             }
             &SystemClauseType::CharsToNumber => {
                 let stub_gen = || functor_stub(atom!("number_chars"), 2);
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                if let Some(atom_or_string) = self.value_to_str_like(a1) {
-                    self.parse_number_from_string(atom_or_string.to_string(), indices, stub_gen)?;
+                if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) {
+                    self.machine_st.parse_number_from_string(
+                        atom_or_string.to_string(),
+                        &self.indices,
+                        stub_gen,
+                    )?;
                 } else {
                     // a1 is a ground list at the call site within
                     // number_chars/2, so failure of value_to_str_like
                     // means the list contains a non-character.
-                    let err = self.type_error(ValidType::Character, a1);
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.type_error(ValidType::Character, a1);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 }
             }
             &SystemClauseType::CreatePartialString => {
-                let atom = cell_as_atom!(self.store(self.deref(self.registers[1])));
+                let atom = cell_as_atom!(
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+                );
 
                 if atom == atom!("") {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
 
-                let pstr_h = self.heap.len();
+                let pstr_h = self.machine_st.heap.len();
 
-                self.heap.push(pstr_as_cell!(atom));
-                self.heap.push(heap_loc_as_cell!(pstr_h+1));
+                self.machine_st.heap.push(pstr_as_cell!(atom));
+                self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1));
 
-                unify!(self, self.registers[2], pstr_loc_as_cell!(pstr_h));
+                unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h));
 
-                if !self.fail {
-                    self.bind(Ref::heap_cell(pstr_h+1), self.registers[3]);
+                if !self.machine_st.fail {
+                    self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]);
                 }
             }
             &SystemClauseType::IsPartialString => {
-                let value = self.store(self.deref(self.registers[1]));
+                let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let h = self.heap.len();
-                self.heap.push(value);
+                let h = self.machine_st.heap.len();
+                self.machine_st.heap.push(value);
 
-                let mut iter = HeapPStrIter::new(&self.heap, h);
+                let mut iter = HeapPStrIter::new(&self.machine_st.heap, h);
 
                 while let Some(_) = iter.next() {}
 
                 let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator();
-                self.fail = !at_end_of_pstr;
+                self.machine_st.fail = !at_end_of_pstr;
 
-                self.heap.pop();
+                self.machine_st.heap.pop();
             }
             &SystemClauseType::PartialStringTail => {
-                let pstr = self.store(self.deref(self.registers[1]));
+                let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(pstr,
                     (HeapCellValueTag::PStrLoc, h) => {
-                        let (h, _) = pstr_loc_and_offset(&self.heap, h);
+                        let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h);
 
-                        if HeapCellValueTag::CStr == self.heap[h].get_tag() {
-                            self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2])));
+                        if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() {
+                            self.machine_st.unify_atom(
+                                atom!("[]"),
+                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+                            );
                         } else {
-                            unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]);
+                            unify_fn!(
+                                self.machine_st,
+                                heap_loc_as_cell!(h+1),
+                                self.machine_st.registers[2]
+                            );
                         }
                     }
                     (HeapCellValueTag::CStr) => {
-                        self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2])));
+                        self.machine_st.unify_atom(
+                            atom!("[]"),
+                            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+                        );
                     }
                     (HeapCellValueTag::Lis, h) => {
-                        unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]);
+                        unify_fn!(
+                            self.machine_st,
+                            heap_loc_as_cell!(h+1),
+                            self.machine_st.registers[2]
+                        );
                     }
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                     }
                 );
             }
             &SystemClauseType::PeekByte => {
                 let stub_gen = || functor_stub(atom!("peek_byte"), 2);
 
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("peek_byte"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Binary,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("peek_byte"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
@@ -1386,36 +1403,36 @@ impl MachineState {
                 if stream.at_end_of_stream() {
                     stream.set_past_end_of_stream(true);
 
-                    self.unify_fixnum(
+                    self.machine_st.unify_fixnum(
                         Fixnum::build_with(-1),
-                        self.store(self.deref(self.registers[2])),
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                     );
 
-                    return return_from_clause!(self.last_call, self);
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
-                let addr = match self.store(self.deref(self.registers[2])) {
+                let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) {
                     addr if addr.is_var() => addr,
                     addr => match Number::try_from(addr) {
                         Ok(Number::Integer(n)) => {
                             if let Some(nb) = n.to_u8() {
                                 fixnum_as_cell!(Fixnum::build_with(nb as i64))
                             } else {
-                                let err = self.type_error(ValidType::InByte, addr);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::InByte, addr);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         Ok(Number::Fixnum(n)) => {
                             if let Ok(nb) = u8::try_from(n.get_num()) {
                                 fixnum_as_cell!(Fixnum::build_with(nb as i64))
                             } else {
-                                let err = self.type_error(ValidType::InByte, addr);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::InByte, addr);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         _ => {
-                            let err = self.type_error(ValidType::InByte, addr);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::InByte, addr);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     },
                 };
@@ -1423,23 +1440,23 @@ impl MachineState {
                 loop {
                     match stream.peek_byte().map_err(|e| e.kind()) {
                         Ok(b) => {
-                            self.unify_fixnum(Fixnum::build_with(b as i64), addr);
+                            self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr);
                         }
                         Err(ErrorKind::PermissionDenied) => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             break;
                         }
                         _ => {
-                            self.eof_action(
-                                self.registers[2],
+                            self.machine_st.eof_action(
+                                self.machine_st.registers[2],
                                 stream,
                                 atom!("peek_byte"),
                                 2,
                             )?;
 
                             if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.last_call, self);
-                            } else if self.fail {
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                            } else if self.machine_st.fail {
                                 return Ok(());
                             }
                         }
@@ -1449,25 +1466,25 @@ impl MachineState {
             &SystemClauseType::PeekChar => {
                 let stub_gen = || functor_stub(atom!("peek_char"), 2);
 
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("peek_char"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("peek_char"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
@@ -1476,11 +1493,11 @@ impl MachineState {
                     let end_of_file = atom!("end_of_file");
                     stream.set_past_end_of_stream(true);
 
-                    self.unify_atom(end_of_file, self.store(self.deref(self.registers[2])));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
-                let a2 = self.store(self.deref(self.registers[2]));
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let a2 = read_heap_cell!(a2,
                     (HeapCellValueTag::Char) => {
@@ -1491,44 +1508,44 @@ impl MachineState {
                             if let Some(c) = name.as_char() {
                                 char_as_cell!(c)
                             } else {
-                                let err = self.type_error(ValidType::InCharacter, a2);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         } else {
-                            let err = self.type_error(ValidType::InCharacter, a2);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
                     (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
                         a2
                     }
                     _ => {
-                        let err = self.type_error(ValidType::InCharacter, a2);
-                        return Err(self.error_form(err, stub_gen()));
+                        let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
                     }
                 );
 
                 loop {
                     match stream.peek_char().map(|result| result.map_err(|e| e.kind())) {
                         Some(Ok(d)) => {
-                            self.unify_char(d, a2);
+                            self.machine_st.unify_char(d, a2);
                             break;
                         }
                         Some(Err(ErrorKind::PermissionDenied)) => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             break;
                         }
                         _ => {
-                            self.eof_action(
-                                self.registers[2],
+                            self.machine_st.eof_action(
+                                self.machine_st.registers[2],
                                 stream,
                                 atom!("peek_char"),
                                 2,
                             )?;
 
                             if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.last_call, self);
-                            } else if self.fail {
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                            } else if self.machine_st.fail {
                                 return Ok(());
                             }
                         }
@@ -1538,25 +1555,25 @@ impl MachineState {
             &SystemClauseType::PeekCode => {
                 let stub_gen = || functor_stub(atom!("peek_code"), 2);
 
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("peek_code"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("peek_code"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
@@ -1565,11 +1582,11 @@ impl MachineState {
                     let end_of_file = atom!("end_of_file");
                     stream.set_past_end_of_stream(true);
 
-                    self.unify_atom(end_of_file, self.store(self.deref(self.registers[2])));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
-                let a2 = self.store(self.deref(self.registers[2]));
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let addr = read_heap_cell!(a2,
                     (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
@@ -1585,8 +1602,8 @@ impl MachineState {
                                 if let Some(n) = n {
                                     fixnum_as_cell!(Fixnum::build_with(n as i64))
                                 } else {
-                                    let err = self.representation_error(RepFlag::InCharacterCode);
-                                    return Err(self.error_form(err, stub_gen()));
+                                    let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                                    return Err(self.machine_st.error_form(err, stub_gen()));
                                 }
                             }
                             Ok(Number::Fixnum(n)) => {
@@ -1597,13 +1614,13 @@ impl MachineState {
                                 if let Some(n) = n {
                                     fixnum_as_cell!(Fixnum::build_with(n as i64))
                                 } else {
-                                    let err = self.representation_error(RepFlag::InCharacterCode);
-                                    return Err(self.error_form(err, stub_gen()));
+                                    let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                                    return Err(self.machine_st.error_form(err, stub_gen()));
                                 }
                             }
                             _ => {
-                                let err = self.type_error(ValidType::Integer, self.registers[2]);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                     }
@@ -1614,24 +1631,24 @@ impl MachineState {
 
                     match result.map(|result| result.map_err(|e| e.kind())) {
                         Some(Ok(c)) => {
-                            self.unify_fixnum(Fixnum::build_with(c as i64), addr);
+                            self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
                             break;
                         }
                         Some(Err(ErrorKind::PermissionDenied)) => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             break;
                         }
                         _ => {
-                            self.eof_action(
-                                self.registers[2],
+                            self.machine_st.eof_action(
+                                self.machine_st.registers[2],
                                 stream,
                                 atom!("peek_code"),
                                 2,
                             )?;
 
                             if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.last_call, self);
-                            } else if self.fail {
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                            } else if self.machine_st.fail {
                                 return Ok(());
                             }
                         }
@@ -1639,10 +1656,10 @@ impl MachineState {
                 }
             }
             &SystemClauseType::NumberToChars => {
-                let n = self.registers[1];
-                let chs = self.registers[2];
+                let n = self.machine_st.registers[1];
+                let chs = self.machine_st.registers[2];
 
-                let n = self.store(self.deref(n));
+                let n = self.machine_st.store(self.machine_st.deref(n));
 
                 let string = match Number::try_from(n) {
                     Ok(Number::Float(OrderedFloat(n))) => {
@@ -1661,12 +1678,12 @@ impl MachineState {
                     }
                 };
 
-                let chars_atom = self.atom_tbl.build_with(&string.trim());
-                self.unify_complete_string(chars_atom, self.store(self.deref(chs)));
+                let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim());
+                self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs)));
             }
             &SystemClauseType::NumberToCodes => {
-                let n = self.store(self.deref(self.registers[1]));
-                let chs = self.registers[2];
+                let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let chs = self.machine_st.registers[2];
 
                 let string = match Number::try_from(n) {
                     Ok(Number::Float(OrderedFloat(n))) => {
@@ -1689,31 +1706,31 @@ impl MachineState {
                     fixnum_as_cell!(Fixnum::build_with(c as i64))
                 });
 
-                let h = iter_to_heap_list(&mut self.heap, codes);
-                unify!(self, heap_loc_as_cell!(h), chs);
+                let h = iter_to_heap_list(&mut self.machine_st.heap, codes);
+                unify!(self.machine_st, heap_loc_as_cell!(h), chs);
             }
             &SystemClauseType::CodesToNumber => {
                 let stub_gen = || functor_stub(atom!("number_codes"), 2);
 
-                match self.try_from_list(self.registers[1], stub_gen) {
+                match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) {
                     Err(e) => {
                         return Err(e);
                     }
                     Ok(addrs) => {
-                        let string = self.codes_to_string(addrs.into_iter(), stub_gen)?;
-                        self.parse_number_from_string(string, indices, stub_gen)?;
+                        let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+                        self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?;
                     }
                 }
             }
             &SystemClauseType::LiftedHeapLength => {
-                let a1 = self.registers[1];
-                let lh_len = Fixnum::build_with(self.lifted_heap.len() as i64);
+                let a1 = self.machine_st.registers[1];
+                let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64);
 
-                self.unify_fixnum(lh_len, a1);
+                self.machine_st.unify_fixnum(lh_len, a1);
             }
             &SystemClauseType::CharCode => {
                 let stub_gen = || functor_stub(atom!("char_code"), 2);
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 let c = read_heap_cell!(a1,
                     (HeapCellValueTag::Atom, (name, _arity)) => {
@@ -1723,51 +1740,51 @@ impl MachineState {
                         c
                     }
                     _ => {
-                        let a2 = self.store(self.deref(self.registers[2]));
+                        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                         match Number::try_from(a2) {
                             Ok(Number::Integer(n)) => {
                                 let c = match n.to_u32().and_then(std::char::from_u32) {
                                     Some(c) => c,
                                     _ => {
-                                        let err = self.representation_error(RepFlag::CharacterCode);
-                                        return Err(self.error_form(err, stub_gen()));
+                                        let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+                                        return Err(self.machine_st.error_form(err, stub_gen()));
                                     }
                                 };
 
-                                self.unify_char(c, a2);
-                                return return_from_clause!(self.last_call, self);
+                                self.machine_st.unify_char(c, a2);
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
                             }
                             Ok(Number::Fixnum(n)) => {
                                 match u32::try_from(n.get_num()) {
                                     Ok(n) => {
                                         if let Some(c) = std::char::from_u32(n) {
-                                            self.unify_char(c, a1);
-                                            return return_from_clause!(self.last_call, self);
+                                            self.machine_st.unify_char(c, a1);
+                                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                                         }
                                     }
                                     _ => {}
                                 }
 
-                                let err = self.representation_error(RepFlag::CharacterCode);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                             _ => {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                                 return Ok(());
                             }
                         }
                     }
                 );
 
-                self.unify_fixnum(
+                self.machine_st.unify_fixnum(
                     Fixnum::build_with(c as i64),
-                    self.store(self.deref(self.registers[2])),
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                 );
             }
             &SystemClauseType::CharType => {
-                let a1 = self.store(self.deref(self.registers[1]));
-                let a2 = self.store(self.deref(self.registers[2]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let c = read_heap_cell!(a1,
                     (HeapCellValueTag::Char, c) => {
@@ -1782,13 +1799,13 @@ impl MachineState {
                 );
 
                 let chars = cell_as_atom!(a2);
-                self.fail = true; // This predicate fails by default.
+                self.machine_st.fail = true; // This predicate fails by default.
 
                 macro_rules! macro_check {
                     ($id:ident, $name:expr) => {
                         if $id!(c) && chars == $name {
-                            self.fail = false;
-                            return return_from_clause!(self.last_call, self);
+                            self.machine_st.fail = false;
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     };
                 }
@@ -1796,8 +1813,8 @@ impl MachineState {
                 macro_rules! method_check {
                     ($id:ident, $name:expr) => {
                         if c.$id() && chars == $name {
-                            self.fail = false;
-                            return return_from_clause!(self.last_call, self);
+                            self.machine_st.fail = false;
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     };
                 }
@@ -1845,55 +1862,55 @@ impl MachineState {
                 method_check!(is_whitespace, atom!("whitespace"));
             }
             &SystemClauseType::CheckCutPoint => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let old_b = cell_as_fixnum!(addr).get_num() as usize;
 
-                let prev_b = self.stack.index_or_frame(self.b).prelude.b;
-                let prev_b = self.stack.index_or_frame(prev_b).prelude.b;
+                let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+                let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b;
 
                 if prev_b > old_b {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::CopyTermWithoutAttrVars => {
-                self.copy_term(AttrVarPolicy::StripAttributes);
+                self.machine_st.copy_term(AttrVarPolicy::StripAttributes);
             }
             &SystemClauseType::FetchGlobalVar => {
-                let key = cell_as_atom!(self.store(self.deref(self.registers[1])));
-                let addr = self.registers[2];
+                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+                let addr = self.machine_st.registers[2];
 
-                match indices.global_variables.get_mut(&key) {
+                match self.indices.global_variables.get_mut(&key) {
                     Some((ref ball, ref mut loc)) => match loc {
                         Some(value_loc) => {
-                            unify_fn!(self, addr, *value_loc);
+                            unify_fn!(self.machine_st, addr, *value_loc);
                         }
                         None if !ball.stub.is_empty() => {
-                            let h = self.heap.len();
+                            let h = self.machine_st.heap.len();
                             let stub = ball.copy_and_align(h);
 
-                            self.heap.extend(stub.into_iter());
+                            self.machine_st.heap.extend(stub.into_iter());
 
-                            unify_fn!(self, addr, heap_loc_as_cell!(h));
+                            unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h));
 
-                            if !self.fail {
+                            if !self.machine_st.fail {
                                 *loc = Some(heap_loc_as_cell!(h));
-                                self.trail(TrailRef::BlackboardEntry(key));
+                                self.machine_st.trail(TrailRef::BlackboardEntry(key));
                             }
                         }
-                        _ => self.fail = true,
+                        _ => self.machine_st.fail = true,
                     },
-                    None => self.fail = true,
+                    None => self.machine_st.fail = true,
                 };
             }
             &SystemClauseType::PutCode => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("put_code"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
                     None,
@@ -1903,17 +1920,17 @@ impl MachineState {
 
                 let stub_gen = || functor_stub(atom!("put_code"), 2);
 
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 if addr.is_var() {
-                    let err = self.instantiation_error();
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.instantiation_error();
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 } else {
                     match Number::try_from(addr) {
                         Ok(Number::Integer(n)) => {
                             if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
                                 write!(&mut stream, "{}", c).unwrap();
-                                return return_from_clause!(self.last_call, self);
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
                             }
                         }
                         Ok(Number::Fixnum(n)) => {
@@ -1921,28 +1938,28 @@ impl MachineState {
 
                             if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) {
                                 write!(&mut stream, "{}", c).unwrap();
-                                return return_from_clause!(self.last_call, self);
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
                             }
                         }
                         _ => {
-                            let err = self.type_error(ValidType::Integer, addr);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::Integer, addr);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
 
-                    let err = self.representation_error(RepFlag::CharacterCode);
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 }
             }
             &SystemClauseType::PutChar => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("put_char"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
                     None,
@@ -1951,34 +1968,34 @@ impl MachineState {
                 )?;
 
                 let stub_gen = || functor_stub(atom!("put_char"), 2);
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 if addr.is_var() {
-                    let err = self.instantiation_error();
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.instantiation_error();
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 } else {
                     read_heap_cell!(addr,
                         (HeapCellValueTag::Atom, (name, _arity)) => {
                             let c = name.as_char().unwrap();
                             write!(&mut stream, "{}", c).unwrap();
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                         (HeapCellValueTag::Char, c) => {
                             write!(&mut stream, "{}", c).unwrap();
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                         _ => {
                         }
                     );
 
-                    let err = self.type_error(ValidType::Character, addr);
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.type_error(ValidType::Character, addr);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 }
             }
             &SystemClauseType::PutChars => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("$put_chars"),
                     2,
                 )?;
@@ -1986,12 +2003,12 @@ impl MachineState {
                 let mut bytes = Vec::new();
                 let stub_gen = || functor_stub(atom!("$put_chars"), 2);
 
-                if let Some(string) = self.value_to_str_like(self.registers[2]) {
+                if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
                     if stream.options().stream_type() == StreamType::Binary {
                         for c in string.as_str().chars() {
                             if c as u32 > 255 {
-                                let err = self.type_error(ValidType::Byte, char_as_cell!(c));
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c));
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
 
                             bytes.push(c as u8);
@@ -2002,28 +2019,28 @@ impl MachineState {
 
                     match stream.write_all(&bytes) {
                         Ok(_) => {
-                            return return_from_clause!(self.last_call, self);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                         _ => {
                             let addr = stream_as_cell!(stream);
-                            let err = self.existence_error(ExistenceError::Stream(addr));
+                            let err = self.machine_st.existence_error(ExistenceError::Stream(addr));
 
-                            return Err(self.error_form(err, stub_gen()));
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 }
             }
             &SystemClauseType::PutByte => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("put_byte"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Binary,
                     None,
@@ -2032,25 +2049,25 @@ impl MachineState {
                 )?;
 
                 let stub_gen = || functor_stub(atom!("put_byte"), 2);
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 if addr.is_var() {
-                    let err = self.instantiation_error();
-                    return Err(self.error_form(err, stub_gen()));
+                    let err = self.machine_st.instantiation_error();
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 } else {
                     match Number::try_from(addr) {
                         Ok(Number::Integer(n)) => {
                             if let Some(nb) = n.to_u8() {
                                 match stream.write(&mut [nb]) {
                                     Ok(1) => {
-                                        return return_from_clause!(self.last_call, self);
+                                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                                     }
                                     _ => {
-                                        let err = self.existence_error(
+                                        let err = self.machine_st.existence_error(
                                             ExistenceError::Stream(stream_as_cell!(stream))
                                         );
 
-                                        return Err(self.error_form(err, stub_gen()));
+                                        return Err(self.machine_st.error_form(err, stub_gen()));
                                     }
                                 }
                             }
@@ -2059,14 +2076,14 @@ impl MachineState {
                             if let Ok(nb) = u8::try_from(n.get_num()) {
                                 match stream.write(&mut [nb]) {
                                     Ok(1) => {
-                                        return return_from_clause!(self.last_call, self);
+                                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                                     }
                                     _ => {
-                                        let err = self.existence_error(
+                                        let err = self.machine_st.existence_error(
                                             ExistenceError::Stream(stream_as_cell!(stream))
                                         );
 
-                                        return Err(self.error_form(err, stub_gen()));
+                                        return Err(self.machine_st.error_form(err, stub_gen()));
                                     }
                                 }
                             }
@@ -2076,37 +2093,37 @@ impl MachineState {
                     }
                 }
 
-                let err = self.type_error(ValidType::Byte, self.registers[2]);
-                return Err(self.error_form(err, stub_gen()));
+                let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]);
+                return Err(self.machine_st.error_form(err, stub_gen()));
             }
             &SystemClauseType::GetByte => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("get_byte"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Binary,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("get_byte"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
-                    self.eof_action(self.registers[2], stream, atom!("get_byte"), 2)?;
+                    self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?;
 
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
 
                 let stub_gen = || functor_stub(atom!("get_byte"), 2);
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let addr = if addr.is_var() {
                     addr
@@ -2116,21 +2133,21 @@ impl MachineState {
                             if let Some(nb) = n.to_u8() {
                                 fixnum_as_cell!(Fixnum::build_with(nb as i64))
                             } else {
-                                let err = self.type_error(ValidType::InByte, addr);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::InByte, addr);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         Ok(Number::Fixnum(n)) => {
                             if let Ok(nb) = u8::try_from(n.get_num()) {
                                 fixnum_as_cell!(Fixnum::build_with(nb as i64))
                             } else {
-                                let err = self.type_error(ValidType::InByte, addr);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.type_error(ValidType::InByte, addr);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         _ => {
-                            let err = self.type_error(ValidType::InByte, addr);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::InByte, addr);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
                 };
@@ -2140,37 +2157,37 @@ impl MachineState {
 
                     match stream.read(&mut b) {
                         Ok(1) => {
-                            self.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
+                            self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
                             break;
                         }
                         _ => {
                             stream.set_past_end_of_stream(true);
-                            self.unify_fixnum(Fixnum::build_with(-1), self.registers[2]);
-                            return return_from_clause!(self.last_call, self);
+                            self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     }
                 }
             }
             &SystemClauseType::GetChar => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("get_char"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("get_char"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
@@ -2179,14 +2196,14 @@ impl MachineState {
                     let end_of_file = atom!("end_of_file");
                     stream.set_past_end_of_stream(true);
 
-                    self.unify_atom(end_of_file, self.store(self.deref(self.registers[2])));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
                 let stub_gen = || functor_stub(atom!("get_char"), 2);
-                let mut iter = self.open_parsing_stream(stream, atom!("get_char"), 2)?;
+                let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?;
 
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let addr = if addr.is_var() {
                     addr
@@ -2199,8 +2216,8 @@ impl MachineState {
                             addr
                         }
                         _ => {
-                            let err = self.type_error(ValidType::InCharacter, addr);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::InCharacter, addr);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     )
                 };
@@ -2210,25 +2227,25 @@ impl MachineState {
 
                     match result {
                         Some(Ok(c)) => {
-                            self.unify_char(c, addr);
+                            self.machine_st.unify_char(c, addr);
 
-                            if self.fail {
+                            if self.machine_st.fail {
                                 return Ok(());
                             }
 
                             break;
                         }
                         _ => {
-                            self.eof_action(
-                                self.registers[2],
+                            self.machine_st.eof_action(
+                                self.machine_st.registers[2],
                                 stream,
                                 atom!("get_char"),
                                 2,
                             )?;
 
                             if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.last_call, self);
-                            } else if self.fail {
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                            } else if self.machine_st.fail {
                                 return Ok(());
                             }
                         }
@@ -2236,19 +2253,19 @@ impl MachineState {
                 }
             }
             &SystemClauseType::GetNChars => {
-                let stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("get_n_chars"),
                     3,
                 )?;
 
-                let num = match Number::try_from(self.store(self.deref(self.registers[2]))) {
+                let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) {
                     Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
                     Ok(Number::Integer(n)) => match n.to_usize() {
                         Some(u) => u,
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     },
@@ -2269,7 +2286,7 @@ impl MachineState {
                         string.push(c as char);
                     }
                 } else {
-                    let mut iter = self.open_parsing_stream(stream, atom!("get_n_chars"), 2)?;
+                    let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?;
 
                     for _ in 0..num {
                         let result = iter.read_char();
@@ -2285,29 +2302,29 @@ impl MachineState {
                     }
                 };
 
-                let atom = self.atom_tbl.build_with(&string);
-                self.unify_complete_string(atom, self.store(self.deref(self.registers[3])));
+                let atom = self.machine_st.atom_tbl.build_with(&string);
+                self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
             }
             &SystemClauseType::GetCode => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("get_code"),
                     2,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
-                    Some(self.registers[2]),
+                    Some(self.machine_st.registers[2]),
                     atom!("get_code"),
                     2,
                 )?;
 
                 if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.last_call, self);
-                    } else if self.fail {
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                    } else if self.machine_st.fail {
                         return Ok(());
                     }
                 }
@@ -2317,12 +2334,12 @@ impl MachineState {
 
                     stream.set_past_end_of_stream(true);
 
-                    self.unify_atom(end_of_file, self.store(self.deref(self.registers[2])));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
                 let stub_gen = || functor_stub(atom!("get_code"), 2);
-                let addr = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let addr = if addr.is_var() {
                     addr
@@ -2336,8 +2353,8 @@ impl MachineState {
                             if let Some(n) = n {
                                 fixnum_as_cell!(Fixnum::build_with(n as i64))
                             } else {
-                                let err = self.representation_error(RepFlag::InCharacterCode);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         Ok(Number::Fixnum(n)) => {
@@ -2348,43 +2365,43 @@ impl MachineState {
                             if nf.is_some() {
                                 fixnum_as_cell!(n)
                             } else {
-                                let err = self.representation_error(RepFlag::InCharacterCode);
-                                return Err(self.error_form(err, stub_gen()));
+                                let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                                return Err(self.machine_st.error_form(err, stub_gen()));
                             }
                         }
                         _ => {
-                            let err = self.type_error(ValidType::Integer, self.registers[2]);
-                            return Err(self.error_form(err, stub_gen()));
+                            let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
                 };
 
-                let mut iter = self.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?;
+                let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?;
 
                 loop {
                     let result = iter.read_char();
 
                     match result {
                         Some(Ok(c)) => {
-                            self.unify_fixnum(Fixnum::build_with(c as i64), addr);
+                            self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
 
-                            if self.fail {
+                            if self.machine_st.fail {
                                 return Ok(());
                             }
 
                             break;
                         }
                         _ => {
-                            self.eof_action(
-                                self.registers[2],
+                            self.machine_st.eof_action(
+                                self.machine_st.registers[2],
                                 stream,
                                 atom!("get_code"),
                                 2,
                             )?;
 
                             if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.last_call, self);
-                            } else if self.fail {
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                            } else if self.machine_st.fail {
                                 return Ok(());
                             }
                         }
@@ -2395,7 +2412,7 @@ impl MachineState {
                 let mut first_stream = None;
                 let mut null_streams = BTreeSet::new();
 
-                for stream in indices.streams.iter().cloned() {
+                for stream in self.indices.streams.iter().cloned() {
                     if !stream.is_null_stream() {
                         first_stream = Some(stream);
                         break;
@@ -2404,25 +2421,30 @@ impl MachineState {
                     }
                 }
 
-                indices.streams = indices.streams.sub(&null_streams);
+                self.indices.streams = self.indices.streams.sub(&null_streams);
 
                 if let Some(first_stream) = first_stream {
                     let stream = stream_as_cell!(first_stream);
 
-                    let var = self.store(self.deref(self.registers[1])).as_var().unwrap();
-                    self.bind(var, stream);
+                    let var = self.machine_st.store(self.machine_st.deref(
+                        self.machine_st.registers[1]
+                    )).as_var().unwrap();
+
+                    self.machine_st.bind(var, stream);
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::NextStream => {
-                let prev_stream = cell_as_stream!(self.store(self.deref(self.registers[1])));
+                let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[1]
+                )));
 
                 let mut next_stream = None;
                 let mut null_streams = BTreeSet::new();
 
-                for stream in indices
+                for stream in self.indices
                     .streams
                     .range(prev_stream..)
                     .skip(1)
@@ -2436,22 +2458,25 @@ impl MachineState {
                     }
                 }
 
-                indices.streams = indices.streams.sub(&null_streams);
+                self.indices.streams = self.indices.streams.sub(&null_streams);
 
                 if let Some(next_stream) = next_stream {
-                    let var = self.store(self.deref(self.registers[2])).as_var().unwrap();
+                    let var = self.machine_st.store(self.machine_st.deref(
+                        self.machine_st.registers[2]
+                    )).as_var().unwrap();
+
                     let next_stream = stream_as_cell!(next_stream);
 
-                    self.bind(var, next_stream);
+                    self.machine_st.bind(var, next_stream);
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::FlushOutput => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("flush_output"),
                     1,
                 )?;
@@ -2460,13 +2485,13 @@ impl MachineState {
                     let stub = functor_stub(atom!("flush_output"), 1);
                     let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)];
 
-                    let err = self.permission_error(
+                    let err = self.machine_st.permission_error(
                         Permission::OutputStream,
                         atom!("stream"),
                         addr,
                     );
 
-                    return Err(self.error_form(err, stub));
+                    return Err(self.machine_st.error_form(err, stub));
                 }
 
                 stream.flush().unwrap();
@@ -2481,8 +2506,8 @@ impl MachineState {
 
                 if key == ctrl_c {
                     let stub = functor_stub(atom!("get_single_char"), 1);
-                    let err = self.interrupt_error();
-                    let err = self.error_form(err, stub);
+                    let err = self.machine_st.interrupt_error();
+                    let err = self.machine_st.error_form(err, stub);
 
                     return Err(err);
                 }
@@ -2494,14 +2519,14 @@ impl MachineState {
                     _ => unreachable!(),
                 };
 
-                self.unify_char(c, self.store(self.deref(self.registers[1])));
+                self.machine_st.unify_char(c, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
             }
             &SystemClauseType::HeadIsDynamic => {
-                let module_name = cell_as_atom!(self.store(self.deref(self.registers[1])));
+                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
 
-                let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])),
+                let (name, arity) = read_heap_cell!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                     (HeapCellValueTag::Str, s) => {
-                        cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
+                        cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity()
                     }
                     (HeapCellValueTag::Atom, (name, _arity)) => {
                         (name, 0)
@@ -2511,12 +2536,12 @@ impl MachineState {
                     }
                 );
 
-                self.fail = !indices.is_dynamic_predicate(module_name, (name, arity));
+                self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity));
             }
             &SystemClauseType::Close => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("close"),
                     2,
                 )?;
@@ -2525,69 +2550,69 @@ impl MachineState {
                     stream.flush().unwrap(); // 8.11.6.1b)
                 }
 
-                indices.streams.remove(&stream);
+                self.indices.streams.remove(&stream);
 
-                if stream == *current_input_stream {
-                    *current_input_stream = indices
+                if stream == self.user_input {
+                    self.user_input = self.indices
                         .stream_aliases
                         .get(&atom!("user_input"))
                         .cloned()
                         .unwrap();
 
-                    indices.streams.insert(*current_input_stream);
-                } else if stream == *current_output_stream {
-                    *current_output_stream = indices
+                    self.indices.streams.insert(self.user_input);
+                } else if stream == self.user_output {
+                    self.user_output = self.indices
                         .stream_aliases
                         .get(&atom!("user_output"))
                         .cloned()
                         .unwrap();
 
-                    indices.streams.insert(*current_output_stream);
+                    self.indices.streams.insert(self.user_output);
                 }
 
                 if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
                     let close_result = stream.close();
 
                     if let Some(alias) = stream.options().get_alias() {
-                        indices.stream_aliases.remove(&alias);
+                        self.indices.stream_aliases.remove(&alias);
                     }
                     if let Err(_) = close_result {
                         let stub = functor_stub(atom!("close"), 1);
                         let addr = stream_as_cell!(stream);
-                        let err  = self.existence_error(ExistenceError::Stream(addr));
+                        let err  = self.machine_st.existence_error(ExistenceError::Stream(addr));
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 }
             }
             &SystemClauseType::CopyToLiftedHeap => {
                 let lh_offset = cell_as_fixnum!(
-                    self.store(self.deref(self.registers[1]))
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
                 ).get_num() as usize;
 
-                let copy_target = self.registers[2];
+                let copy_target = self.machine_st.registers[2];
 
-                let old_threshold = self.copy_findall_solution(lh_offset, copy_target);
-                let new_threshold = self.lifted_heap.len() - lh_offset;
+                let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target);
+                let new_threshold = self.machine_st.lifted_heap.len() - lh_offset;
 
-                self.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold);
+                self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold);
 
-                for addr in self.lifted_heap[old_threshold + 1 ..].iter_mut() {
-                    *addr -= self.heap.len() + lh_offset;
+                for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() {
+                    *addr -= self.machine_st.heap.len() + lh_offset;
                 }
             },
             &SystemClauseType::DeleteAttribute => {
-                let ls0 = self.store(self.deref(self.registers[1]));
+                let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 if let HeapCellValueTag::Lis = ls0.get_tag() {
                     let l1 = ls0.get_value();
-                    let ls1 = self.store(self.deref(heap_loc_as_cell!(l1 + 1)));
+                    let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
 
                     if let HeapCellValueTag::Lis = ls1.get_tag() {
                         let l2 = ls1.get_value();
 
-                        let old_addr = self.heap[l1+1];
-                        let tail = self.store(self.deref(heap_loc_as_cell!(l2 + 1)));
+                        let old_addr = self.machine_st.heap[l1+1];
+                        let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
 
                         let tail = if tail.is_var() {
                             heap_loc_as_cell!(l1 + 1)
@@ -2607,158 +2632,139 @@ impl MachineState {
                             }
                         );
 
-                        self.heap[l1 + 1] = tail;
-                        self.trail(trail_ref);
+                        self.machine_st.heap[l1 + 1] = tail;
+                        self.machine_st.trail(trail_ref);
                     }
                 }
             }
             &SystemClauseType::DeleteHeadAttribute => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
 
                 let h = addr.get_value();
-                let addr = self.store(self.deref(self.heap[h + 1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
 
                 debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
 
                 let l = addr.get_value();
-                let tail = self.store(self.deref(heap_loc_as_cell!(l + 1)));
+                let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1)));
 
                 let tail = if tail.is_var() {
-                    self.heap[h] = heap_loc_as_cell!(h);
-                    self.trail(TrailRef::Ref(Ref::attr_var(h)));
+                    self.machine_st.heap[h] = heap_loc_as_cell!(h);
+                    self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
 
                     heap_loc_as_cell!(h + 1)
                 } else {
                     tail
                 };
 
-                self.heap[h + 1] = tail;
-                self.trail(TrailRef::AttrVarListLink(h + 1, l));
+                self.machine_st.heap[h + 1] = tail;
+                self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
             }
             &SystemClauseType::DynamicModuleResolution(narity) => {
-                let module_name = self.store(self.deref(self.registers[1 + narity]));
-                let module_name = cell_as_atom!(module_name);
+                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[1 + narity]
+                )));
 
-                let addr = self.store(self.deref(self.registers[2 + narity]));
+                let addr = self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[2 + narity]
+                ));
 
                 read_heap_cell!(addr,
                     (HeapCellValueTag::Str, a) => {
-                        let (name, arity) = cell_as_atom_cell!(self.heap[a])
+                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a])
                             .get_name_and_arity();
 
                         for i in (arity + 1..arity + narity + 1).rev() {
-                            self.registers[i] = self.registers[i - arity];
+                            self.machine_st.registers[i] = self.machine_st.registers[i - arity];
                         }
 
                         for i in 1..arity + 1 {
-                            self.registers[i] = self.heap[a + i];
+                            self.machine_st.registers[i] = self.machine_st.heap[a + i];
                         }
 
-                        return self.module_lookup(
-                            indices,
-                            call_policy,
-                            (name, arity + narity),
-                            module_name,
-                            true,
-                            &indices.stream_aliases,
-                        );
+                        return self.call_clause_type(module_name, (name, arity + narity));
                     }
                     (HeapCellValueTag::Atom, (name, _arity)) => {
-                        return self.module_lookup(
-                            indices,
-                            call_policy,
-                            (name, narity),
-                            module_name,
-                            true,
-                            &indices.stream_aliases,
-                        );
+                        return self.call_clause_type(module_name, (name, narity));
                     }
                     (HeapCellValueTag::Char, c) => {
-                        let key = (self.atom_tbl.build_with(&c.to_string()), narity);
-
-                        return self.module_lookup(
-                            indices,
-                            call_policy,
-                            key,
-                            module_name,
-                            true,
-                            &indices.stream_aliases,
-                        );
+                        let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity);
+                        return self.call_clause_type(module_name, key);
                     }
                     _ => {
                         let stub = functor_stub(atom!("(:)"), 2);
-                        let err = self.type_error(ValidType::Callable, addr);
+                        let err = self.machine_st.type_error(ValidType::Callable, addr);
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 );
             }
             &SystemClauseType::EnqueueAttributedVar => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(addr,
                     (HeapCellValueTag::AttrVar, h) => {
-                        self.attr_var_init.attr_var_queue.push(h);
+                        self.machine_st.attr_var_init.attr_var_queue.push(h);
                     }
                     _ => {
                     }
                 );
             }
             &SystemClauseType::GetNextDBRef => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 if let Some(name_var) = a1.as_var() {
-                    let mut iter = indices.code_dir.iter();
+                    let mut iter = self.indices.code_dir.iter();
 
                     while let Some(((name, arity), _)) = iter.next() {
                         if SystemClauseType::from(*name, *arity).is_some() {
                             continue;
                         }
 
-                        let arity_var = self.deref(self.registers[2])
+                        let arity_var = self.machine_st.deref(self.machine_st.registers[2])
                             .as_var().unwrap();
 
-                        self.bind(name_var, atom_as_cell!(name));
-                        self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64)));
+                        self.machine_st.bind(name_var, atom_as_cell!(name));
+                        self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64)));
 
-                        return return_from_clause!(self.last_call, self);
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                     }
 
-                    self.fail = true;
+                    self.machine_st.fail = true;
                 } else if a1.get_tag() == HeapCellValueTag::Atom {
                     let name = cell_as_atom!(a1);
-                    let arity = cell_as_fixnum!(self.store(self.deref(self.registers[2])))
+                    let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])))
                         .get_num() as usize;
 
-                    match self.get_next_db_ref(indices, &DBRef::NamedPred(name, arity)) {
+                    match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) {
                         Some(DBRef::NamedPred(name, arity)) => {
-                            let atom_var = self.deref(self.registers[3])
+                            let atom_var = self.machine_st.deref(self.machine_st.registers[3])
                                 .as_var().unwrap();
 
-                            let arity_var = self.deref(self.registers[4])
+                            let arity_var = self.machine_st.deref(self.machine_st.registers[4])
                                 .as_var().unwrap();
 
-                            self.bind(atom_var, atom_as_cell!(name));
-                            self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64)));
+                            self.machine_st.bind(atom_var, atom_as_cell!(name));
+                            self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64)));
                         }
                         Some(DBRef::Op(..)) | None => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::GetNextOpDBRef => {
-                let prec = self.store(self.deref(self.registers[1]));
+                let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 if let Some(prec_var) = prec.as_var() {
-                    let spec = self.store(self.deref(self.registers[2]));
-                    let op = self.store(self.deref(self.registers[3]));
-                    let orig_op = self.store(self.deref(self.registers[7]));
+                    let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                    let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+                    let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7]));
 
                     let spec_num = if spec.get_tag() == HeapCellValueTag::Atom {
                         (match cell_as_atom!(spec) {
@@ -2778,9 +2784,9 @@ impl MachineState {
                         let orig_op = cell_as_atom!(orig_op);
 
                         let op_descs = [
-                            indices.op_dir.get_key_value(&(orig_op, Fixity::In)),
-                            indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)),
-                            indices.op_dir.get_key_value(&(orig_op, Fixity::Post)),
+                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)),
+                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)),
+                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)),
                         ];
 
                         let number_of_keys = op_descs[0].is_some() as usize +
@@ -2789,7 +2795,7 @@ impl MachineState {
 
                         match number_of_keys {
                             0 => {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                                 return Ok(());
                             }
                             1 => {
@@ -2811,12 +2817,12 @@ impl MachineState {
 
                                         let op_prec = Fixnum::build_with(op_prec as i64);
 
-                                        self.unify_fixnum(op_prec, prec);
-                                        self.unify_atom(op_spec, spec);
+                                        self.machine_st.unify_fixnum(op_prec, prec);
+                                        self.machine_st.unify_atom(op_spec, spec);
                                     }
                                 }
 
-                                return return_from_clause!(self.last_call, self);
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
                             }
                             _ => {
                                 let mut unossified_op_dir = OssifiedOpDir::new();
@@ -2834,7 +2840,7 @@ impl MachineState {
                     } else {
                         let mut unossified_op_dir = OssifiedOpDir::new();
 
-                        unossified_op_dir.extend(indices.op_dir.iter().filter_map(
+                        unossified_op_dir.extend(self.indices.op_dir.iter().filter_map(
                             |(key, op_desc)| {
                                 let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec());
                                 let name = key.0;
@@ -2855,11 +2861,11 @@ impl MachineState {
                         unossified_op_dir
                     };
 
-                    let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.arena);
+                    let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena);
 
                     match ossified_op_dir.iter().next() {
                         Some(((op_atom, _), (op_prec, op_spec))) => {
-                            let ossified_op_dir_var = self.store(self.deref(self.registers[4]))
+                            let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]))
                                 .as_var().unwrap();
 
                             let spec_atom = match *op_spec {
@@ -2871,7 +2877,7 @@ impl MachineState {
                                 XFY => atom!("xfy"),
                                 YFX => atom!("yfx"),
                                 _ => {
-                                    self.fail = true;
+                                    self.machine_st.fail = true;
                                     return Ok(());
                                 }
                             };
@@ -2879,23 +2885,23 @@ impl MachineState {
                             let spec_var = spec.as_var().unwrap();
                             let op_var = op.as_var().unwrap();
 
-                            self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64)));
-                            self.bind(spec_var, atom_as_cell!(spec_atom));
-                            self.bind(op_var, atom_as_cell!(op_atom));
-                            self.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir));
+                            self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64)));
+                            self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+                            self.machine_st.bind(op_var, atom_as_cell!(op_atom));
+                            self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir));
                         }
                         None => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
-                    let spec = cell_as_atom!(self.store(self.deref(self.registers[2])));
-                    let op_atom = cell_as_atom!(self.store(self.deref(self.registers[3])));
-                    let ossified_op_dir_cell = self.store(self.deref(self.registers[4]));
+                    let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
+                    let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
 
                     if ossified_op_dir_cell.is_var() {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
 
@@ -2908,22 +2914,25 @@ impl MachineState {
                         atom!("xf") | atom!("yf") => Fixity::Post,
                         atom!("fx") | atom!("fy") => Fixity::Pre,
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     };
 
-                    match self.get_next_db_ref(indices, &DBRef::Op(op_atom, fixity, ossified_op_dir)) {
+                    match self.machine_st.get_next_db_ref(
+                        &self.indices,
+                        &DBRef::Op(op_atom, fixity, ossified_op_dir),
+                    ) {
                         Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => {
                             let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap();
 
-                            let prec_var = self.deref(self.registers[5])
+                            let prec_var = self.machine_st.deref(self.machine_st.registers[5])
                                 .as_var().unwrap();
 
-                            let spec_var = self.deref(self.registers[6])
+                            let spec_var = self.machine_st.deref(self.machine_st.registers[6])
                                 .as_var().unwrap();
 
-                            let op_var = self.deref(self.registers[7])
+                            let op_var = self.machine_st.deref(self.machine_st.registers[7])
                                 .as_var().unwrap();
 
                             let spec_atom = match *spec {
@@ -2935,17 +2944,17 @@ impl MachineState {
                                 XFY => atom!("xfy"),
                                 YFX => atom!("yfx"),
                                 _ => {
-                                    self.fail = true;
+                                    self.machine_st.fail = true;
                                     return Ok(());
                                 }
                             };
 
-                            self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64)));
-                            self.bind(spec_var, atom_as_cell!(spec_atom));
-                            self.bind(op_var, atom_as_cell!(op_atom));
+                            self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64)));
+                            self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+                            self.machine_st.bind(op_var, atom_as_cell!(op_atom));
                         }
                         Some(DBRef::NamedPred(..)) | None => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                         }
                     }
                 }
@@ -2956,61 +2965,65 @@ impl MachineState {
                     rand.bits(1) == 0
                 };
 
-                self.fail = result;
+                self.machine_st.fail = result;
             }
             &SystemClauseType::CpuNow => {
                 let secs = ProcessTime::now().as_duration().as_secs_f64();
-                let secs = arena_alloc!(OrderedFloat(secs), &mut self.arena);
+                let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena);
 
-                self.unify_f64(secs, self.registers[1]);
+                self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
             }
             &SystemClauseType::CurrentTime => {
                 let timestamp = self.systemtime_to_timestamp(SystemTime::now());
-                self.unify_atom(timestamp, self.registers[1]);
+                self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]);
             }
             &SystemClauseType::Open => {
-                let alias = self.registers[4];
-                let eof_action = self.registers[5];
-                let reposition = self.registers[6];
-                let stream_type = self.registers[7];
+                let alias = self.machine_st.registers[4];
+                let eof_action = self.machine_st.registers[5];
+                let reposition = self.machine_st.registers[6];
+                let stream_type = self.machine_st.registers[7];
 
-                let options  = self.to_stream_options(alias, eof_action, reposition, stream_type);
-                let src_sink = self.store(self.deref(self.registers[1]));
+                let options  = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+                let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                if let Some(str_like) = self.value_to_str_like(src_sink) {
+                if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) {
                     let file_spec = match str_like {
                         AtomOrString::Atom(atom) => {
                             atom
                         }
                         AtomOrString::String(string) => {
-                            self.atom_tbl.build_with(&string)
+                            self.machine_st.atom_tbl.build_with(&string)
                         }
                     };
 
-                    let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?;
+                    let mut stream = self.machine_st.stream_from_file_spec(
+                        file_spec,
+                        &mut self.indices,
+                        &options,
+                    )?;
 
                     *stream.options_mut() = options;
-                    indices.streams.insert(stream);
+                    self.indices.streams.insert(stream);
 
                     if let Some(alias) = stream.options().get_alias() {
-                        indices.stream_aliases.insert(alias, stream);
+                        self.indices.stream_aliases.insert(alias, stream);
                     }
 
-                    let stream_var = self.store(self.deref(self.registers[3]));
-                    self.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream));
+                    let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+                    self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream));
                 } else {
-                    let err = self.domain_error(DomainErrorType::SourceSink, src_sink);
+                    let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink);
                     let stub = functor_stub(atom!("open"), 4);
 
-                    return Err(self.error_form(err, stub));
+                    return Err(self.machine_st.error_form(err, stub));
                 }
             }
             &SystemClauseType::OpDeclaration => {
-                let priority = self.registers[1];
-                let specifier = self.registers[2];
-                let op = self.registers[3];
+                let priority = self.machine_st.registers[1];
+                let specifier = self.machine_st.registers[2];
+                let op = self.machine_st.registers[3];
 
-                let priority = self.store(self.deref(priority));
+                let priority = self.machine_st.store(self.machine_st.deref(priority));
 
                 let priority = match Number::try_from(priority) {
                     Ok(Number::Integer(n)) => n.to_u16().unwrap(),
@@ -3020,12 +3033,12 @@ impl MachineState {
                     }
                 };
 
-                let specifier = cell_as_atom_cell!(self.store(self.deref(specifier)))
+                let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier)))
                     .get_name();
 
-                let op = read_heap_cell!(self.store(self.deref(op)),
+                let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)),
                     (HeapCellValueTag::Char) => {
-                        self.atom_tbl.build_with(&op.to_string())
+                        self.machine_st.atom_tbl.build_with(&op.to_string())
                     }
                     (HeapCellValueTag::Atom, (name, _arity)) => {
                         name
@@ -3039,14 +3052,14 @@ impl MachineState {
                     .map_err(SessionError::from)
                     .and_then(|mut op_decl| {
                         if op_decl.op_desc.get_prec() == 0 {
-                            Ok(op_decl.remove(&mut indices.op_dir))
+                            Ok(op_decl.remove(&mut self.indices.op_dir))
                         } else {
                             let spec = get_op_desc(
                                 op_decl.name,
-                                &CompositeOpDir::new(&indices.op_dir, None),
+                                &CompositeOpDir::new(&self.indices.op_dir, None),
                             );
 
-                            op_decl.submit(spec, &mut indices.op_dir)
+                            op_decl.submit(spec, &mut self.indices.op_dir)
                         }
                     });
 
@@ -3054,100 +3067,102 @@ impl MachineState {
                     Ok(()) => {}
                     Err(e) => {
                         // 8.14.3.3 l)
-                        let err = self.session_error(e);
+                        let err = self.machine_st.session_error(e);
                         let stub = functor_stub(atom!("op"), 3);
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 }
             }
             &SystemClauseType::SetStreamOptions => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("open"),
                     4,
                 )?;
 
-                let alias = self.registers[2];
-                let eof_action = self.registers[3];
-                let reposition = self.registers[4];
-                let stream_type = self.registers[5];
+                let alias = self.machine_st.registers[2];
+                let eof_action = self.machine_st.registers[3];
+                let reposition = self.machine_st.registers[4];
+                let stream_type = self.machine_st.registers[5];
 
-                let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
                 *stream.options_mut() = options;
             }
             &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
-                self.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
+                self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
             }
             &SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
-                self.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
+                self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
             }
             &SystemClauseType::GetAttributedVariableList => {
-                let attr_var = self.store(self.deref(self.registers[1]));
+                let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let attr_var_list = read_heap_cell!(attr_var,
                     (HeapCellValueTag::AttrVar, h) => {
                         h + 1
                     }
                     (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
                         // create an AttrVar in the heap.
-                        let h = self.heap.len();
+                        let h = self.machine_st.heap.len();
 
-                        self.heap.push(attr_var_as_cell!(h));
-                        self.heap.push(heap_loc_as_cell!(h+1));
+                        self.machine_st.heap.push(attr_var_as_cell!(h));
+                        self.machine_st.heap.push(heap_loc_as_cell!(h+1));
 
-                        self.bind(Ref::attr_var(h), attr_var);
+                        self.machine_st.bind(Ref::attr_var(h), attr_var);
                         h + 1
                     }
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 );
 
-                let list_addr = self.store(self.deref(self.registers[2]));
-                self.bind(Ref::heap_cell(attr_var_list), list_addr);
+                let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
             }
             &SystemClauseType::GetAttrVarQueueDelimiter => {
-                let addr = self.registers[1];
-                let value = Fixnum::build_with(self.attr_var_init.attr_var_queue.len() as i64);
+                let addr = self.machine_st.registers[1];
+                let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
 
-                self.unify_fixnum(value, self.store(self.deref(addr)));
+                self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr)));
             }
             &SystemClauseType::GetAttrVarQueueBeyond => {
-                let addr = self.registers[1];
-                let addr = self.store(self.deref(addr));
+                let addr = self.machine_st.registers[1];
+                let addr = self.machine_st.store(self.machine_st.deref(addr));
 
                 let b = match Number::try_from(addr) {
                     Ok(Number::Integer(n)) => n.to_usize(),
                     Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
 
                 if let Some(b) = b {
-                    let iter = self.gather_attr_vars_created_since(b);
+                    let iter = self.machine_st.gather_attr_vars_created_since(b);
 
                     let var_list_addr = heap_loc_as_cell!(
-                        iter_to_heap_list(&mut self.heap, iter)
+                        iter_to_heap_list(&mut self.machine_st.heap, iter)
                     );
 
-                    let list_addr = self.registers[2];
-                    unify!(self, var_list_addr, list_addr);
+                    let list_addr = self.machine_st.registers[2];
+                    unify!(self.machine_st, var_list_addr, list_addr);
                 }
             }
             &SystemClauseType::GetContinuationChunk => {
-                let e = self.store(self.deref(self.registers[1]));
+                let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let e = cell_as_fixnum!(e).get_num() as usize;
 
-                let p_functor = self.store(self.deref(self.registers[2]));
-                let p = to_local_code_ptr(&self.heap, p_functor).unwrap();
+                let p_functor = self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[2]
+                ));
+                let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
 
-                let num_cells = match code_repo.lookup_instr(self, &CodePtr::Local(p)) {
+                let num_cells = match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) {
                     Some(line) => {
-                        let perm_vars = match line.as_ref() {
+                        let perm_vars = match line.as_ref(&self.code_repo.code) {
                             Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(),
                             _ => None,
                         };
@@ -3160,71 +3175,71 @@ impl MachineState {
                 let mut addrs = vec![];
 
                 for idx in 1..num_cells + 1 {
-                    addrs.push(self.stack[stack_loc!(AndFrame, e, idx)]);
+                    addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]);
                 }
 
-                let chunk = str_loc_as_cell!(self.heap.len());
+                let chunk = str_loc_as_cell!(self.machine_st.heap.len());
 
-                self.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells));
-                self.heap.push(p_functor);
-                self.heap.extend(addrs);
+                self.machine_st.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells));
+                self.machine_st.heap.push(p_functor);
+                self.machine_st.heap.extend(addrs);
 
-                unify!(self, self.registers[3], chunk);
+                unify!(self.machine_st, self.machine_st.registers[3], chunk);
             }
             &SystemClauseType::GetLiftedHeapFromOffsetDiff => {
-                let lh_offset = self.registers[1];
-                let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize;
+                let lh_offset = self.machine_st.registers[1];
+                let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize;
 
-                if lh_offset >= self.lifted_heap.len() {
-                    let solutions = self.registers[2];
-                    let diff = self.registers[3];
+                if lh_offset >= self.machine_st.lifted_heap.len() {
+                    let solutions = self.machine_st.registers[2];
+                    let diff = self.machine_st.registers[3];
 
-                    unify_fn!(self, solutions, diff);
+                    unify_fn!(self.machine_st, solutions, diff);
                 } else {
-                    let h = self.heap.len();
+                    let h = self.machine_st.heap.len();
                     let mut last_index = h;
 
-                    for value in self.lifted_heap[lh_offset ..].iter().cloned() {
-                        last_index = self.heap.len();
-                        self.heap.push(value + h);
+                    for value in self.machine_st.lifted_heap[lh_offset ..].iter().cloned() {
+                        last_index = self.machine_st.heap.len();
+                        self.machine_st.heap.push(value + h);
                     }
 
-                    if last_index < self.heap.len() {
-                        let diff = self.registers[3];
-                        unify_fn!(self, diff, self.heap[last_index]);
+                    if last_index < self.machine_st.heap.len() {
+                        let diff = self.machine_st.registers[3];
+                        unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]);
                     }
 
-                    self.lifted_heap.truncate(lh_offset);
+                    self.machine_st.lifted_heap.truncate(lh_offset);
 
-                    let solutions = self.registers[2];
-                    unify_fn!(self, heap_loc_as_cell!(h), solutions);
+                    let solutions = self.machine_st.registers[2];
+                    unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
                 }
             }
             &SystemClauseType::GetLiftedHeapFromOffset => {
-                let lh_offset = self.registers[1];
-                let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize;
+                let lh_offset = self.machine_st.registers[1];
+                let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize;
 
-                if lh_offset >= self.lifted_heap.len() {
-                    let solutions = self.registers[2];
-                    unify_fn!(self, solutions, empty_list_as_cell!());
+                if lh_offset >= self.machine_st.lifted_heap.len() {
+                    let solutions = self.machine_st.registers[2];
+                    unify_fn!(self.machine_st, solutions, empty_list_as_cell!());
                 } else {
-                    let h = self.heap.len();
+                    let h = self.machine_st.heap.len();
 
-                    for addr in self.lifted_heap[lh_offset..].iter().cloned() {
-                        self.heap.push(addr + h);
+                    for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
+                        self.machine_st.heap.push(addr + h);
                     }
 
-                    self.lifted_heap.truncate(lh_offset);
+                    self.machine_st.lifted_heap.truncate(lh_offset);
 
-                    let solutions = self.registers[2];
-                    unify_fn!(self, heap_loc_as_cell!(h), solutions);
+                    let solutions = self.machine_st.registers[2];
+                    unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
                 }
             }
             &SystemClauseType::GetDoubleQuotes => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                self.unify_atom(
-                    match self.flags.double_quotes {
+                self.machine_st.unify_atom(
+                    match self.machine_st.flags.double_quotes {
                         DoubleQuotes::Chars => atom!("chars"),
                         DoubleQuotes::Atom => atom!("atom"),
                         DoubleQuotes::Codes => atom!("codes"),
@@ -3233,32 +3248,27 @@ impl MachineState {
                 );
             }
             &SystemClauseType::GetSCCCleaner => {
-                let dest = self.registers[1];
+                let dest = self.machine_st.registers[1];
 
-                match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
-                    Some(sgc_policy) => {
-                        if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
-                            let b = self.stack.index_or_frame(self.b).prelude.b;
+                if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() {
+                    let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
 
-                            if b <= b_cutoff {
-                                self.block = prev_b;
+                    if b <= b_cutoff {
+                        self.machine_st.block = prev_b;
 
-                                if let Some(r) = dest.as_var() {
-                                    self.bind(r, addr);
-                                    return return_from_clause!(self.last_call, self);
-                                }
-                            } else {
-                                sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
-                            }
+                        if let Some(r) = dest.as_var() {
+                            self.machine_st.bind(r, addr);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
+                    } else {
+                        self.machine_st.cont_pts.push((addr, b_cutoff, prev_b));
                     }
-                    None => {}
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::Halt => {
-                let code = self.store(self.deref(self.registers[1]));
+                let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 let code = match Number::try_from(code) {
                     Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(),
@@ -3277,34 +3287,19 @@ impl MachineState {
                 std::process::exit(code);
             }
             &SystemClauseType::InstallSCCCleaner => {
-                let addr = self.registers[1];
-                let b = self.b;
-                let prev_block = self.block;
+                let addr = self.machine_st.registers[1];
+                let b = self.machine_st.b;
+                let prev_block = self.machine_st.block;
 
-                if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
-                    let (r_c_w_h, r_c_wo_h) = indices.get_cleaner_sites();
-                    *cut_policy = Box::new(SCCCutPolicy::new(r_c_w_h, r_c_wo_h));
-                }
+                self.machine_st.run_cleaners_fn = Machine::run_cleaners;
 
-                match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
-                    Some(cut_policy) => {
-                        self.install_new_block(self.registers[2]);
-                        cut_policy.push_cont_pt(addr, b, prev_block);
-                    }
-                    None => panic!(
-                        "install_cleaner: should have installed \\
-                         SCCCutPolicy."
-                    ),
-                };
+                self.machine_st.install_new_block(self.machine_st.registers[2]);
+                self.machine_st.cont_pts.push((addr, b, prev_block));
             }
             &SystemClauseType::InstallInferenceCounter => {
                 // A1 = B, A2 = L
-                let a1 = self.store(self.deref(self.registers[1]));
-                let a2 = self.store(self.deref(self.registers[2]));
-
-                if call_policy.downcast_ref::<CWILCallPolicy>().is_err() {
-                    CWILCallPolicy::new_in_place(call_policy);
-                }
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let n = match Number::try_from(a2) {
                     Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
@@ -3315,48 +3310,39 @@ impl MachineState {
                             3,
                         );
 
-                        let err = self.type_error(ValidType::Integer, a2);
-                        return Err(self.error_form(err, stub));
+                        let err = self.machine_st.type_error(ValidType::Integer, a2);
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 };
 
                 let bp = cell_as_fixnum!(a1).get_num() as usize;
+                let count = self.machine_st.cwil.add_limit(n, bp);
+                let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
 
-                match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
-                    Some(call_policy) => {
-                        let count = call_policy.add_limit(n, bp);
-                        let count = arena_alloc!(count.clone(), &mut self.arena);
+                self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
 
-                        let a3 = self.store(self.deref(self.registers[3]));
-                        self.unify_big_int(count, a3);
-                    }
-                    None => {
-                        panic!(
-                            "install_inference_counter: should have installed \\
-                             CWILCallPolicy."
-                        )
-                    }
-                }
+                let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+                self.machine_st.unify_big_int(count, a3);
             }
             &SystemClauseType::ModuleExists => {
-                let module = self.store(self.deref(self.registers[1]));
+                let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let module_name = cell_as_atom!(module);
 
-                self.fail = !indices.modules.contains_key(&module_name);
+                self.machine_st.fail = !self.indices.modules.contains_key(&module_name);
             }
             &SystemClauseType::NoSuchPredicate => {
-                let module_name = cell_as_atom!(self.store(self.deref(self.registers[1])));
-                let head = self.store(self.deref(self.registers[2]));
+                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+                let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                self.fail = read_heap_cell!(head,
+                self.machine_st.fail = read_heap_cell!(head,
                     (HeapCellValueTag::Str, s) => {
-                        let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
                             .get_name_and_arity();
 
                         if clause_type_form(name, arity).is_some() {
                             true
                         } else {
-                            let index = indices.get_predicate_code_index(
+                            let index = self.indices.get_predicate_code_index(
                                 name,
                                 arity,
                                 module_name,
@@ -3376,7 +3362,7 @@ impl MachineState {
                         if clause_type_form(name, 0).is_some() {
                             true
                         } else {
-                            let index = indices.get_predicate_code_index(
+                            let index = self.indices.get_predicate_code_index(
                                 name,
                                 0,
                                 module_name,
@@ -3391,229 +3377,217 @@ impl MachineState {
                         }
                     }
                     _ => {
-                        let err = self.type_error(ValidType::Callable, head);
+                        let err = self.machine_st.type_error(ValidType::Callable, head);
                         let stub = functor_stub(atom!("clause"), 2);
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 );
             }
             &SystemClauseType::RedoAttrVarBinding => {
-                let var = self.store(self.deref(self.registers[1]));
-                let value = self.store(self.deref(self.registers[2]));
+                let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag());
-                self.heap[var.get_value()] = value;
+                self.machine_st.heap[var.get_value()] = value;
             }
             &SystemClauseType::ResetAttrVarState => {
-                self.attr_var_init.reset();
+                self.machine_st.attr_var_init.reset();
             }
             &SystemClauseType::RemoveCallPolicyCheck => {
-                let restore_default = match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
-                    Some(call_policy) => {
-                        let a1 = self.store(self.deref(self.registers[1]));
-                        let bp = cell_as_fixnum!(a1).get_num() as usize;
+                let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[1]
+                ))).get_num() as usize;
 
-                        if call_policy.is_empty() && bp == self.b {
-                            Some(call_policy.into_inner())
-                        } else {
-                            None
-                        }
-                    }
-                    None => panic!(
-                        "remove_call_policy_check: requires \\
-                             CWILCallPolicy."
-                    ),
-                };
-
-                if let Some(new_policy) = restore_default {
-                    *call_policy = new_policy;
+                if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
+                    self.machine_st.cwil.reset();
+                    self.machine_st.increment_call_count_fn = |_| { Ok(()) };
                 }
             }
             &SystemClauseType::RemoveInferenceCounter => {
-                match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
-                    Some(call_policy) => {
-                        let a1 = self.store(self.deref(self.registers[1]));
-                        let bp = cell_as_fixnum!(a1).get_num() as usize;
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let bp = cell_as_fixnum!(a1).get_num() as usize;
 
-                        let count = call_policy.remove_limit(bp).clone();
-                        let count = arena_alloc!(count.clone(), &mut self.arena);
+                let count = self.machine_st.cwil.remove_limit(bp).clone();
+                let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
 
-                        let a2 = self.store(self.deref(self.registers[2]));
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                        self.unify_big_int(count, a2);
-                    }
-                    None => panic!(
-                        "remove_inference_counter: requires \\
-                         CWILCallPolicy."
-                    ),
-                }
+                self.machine_st.unify_big_int(count, a2);
             }
             &SystemClauseType::REPL(repl_code_ptr) => {
-                return self.repl_redirect(repl_code_ptr);
+                return self.machine_st.repl_redirect(repl_code_ptr);
             }
             &SystemClauseType::ReturnFromVerifyAttr => {
-                let e = self.e;
-                let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
+                let e = self.machine_st.e;
+                let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
 
                 for i in 1..frame_len - 1 {
-                    self.registers[i] = self.stack[stack_loc!(AndFrame, e, i)];
+                    self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
                 }
 
-                self.b0 = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len - 1)])
+                self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)])
                     .get_num() as usize;
 
-                self.num_of_args = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len)])
+                self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)])
                     .get_num() as usize;
 
-                self.deallocate();
-                self.p = CodePtr::Local(self.stack.index_and_frame(e).prelude.interrupt_cp);
+                self.machine_st.deallocate();
+                self.machine_st.p = CodePtr::Local(self.machine_st.stack.index_and_frame(e).prelude.interrupt_cp);
 
                 return Ok(());
             }
             &SystemClauseType::RestoreCutPolicy => {
-                let restore_default =
-                    if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
-                        cut_policy.out_of_cont_pts()
-                    } else {
-                        false
-                    };
-
-                if restore_default {
-                    *cut_policy = Box::new(DefaultCutPolicy {});
+                if self.machine_st.cont_pts.is_empty() {
+                    self.machine_st.run_cleaners_fn = |_| { false };
                 }
             }
             &SystemClauseType::SetCutPoint(r) => {
-                if cut_policy.cut(self, r) {
+                let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+                self.machine_st.cut_body(cp);
+
+                if (self.machine_st.run_cleaners_fn)(self) {
                     return Ok(());
                 }
             }
-            &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r),
+            &SystemClauseType::SetCutPointByDefault(r) => {
+                let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+                self.machine_st.cut_body(cp);
+            }
             &SystemClauseType::SetInput => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let stream =
-                    self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_input"), 1)?;
+                let addr = self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[1]
+                ));
+                let stream = self.machine_st.get_stream_or_alias(
+                    addr,
+                    &self.indices.stream_aliases,
+                    atom!("set_input"),
+                    1,
+                )?;
 
                 if !stream.is_input_stream() {
                     let stub = functor_stub(atom!("set_input"), 1);
-
                     let user_alias = atom_as_cell!(atom!("user"));
 
-                    let err = self.permission_error(
+                    let err = self.machine_st.permission_error(
                         Permission::InputStream,
                         atom!("stream"),
                         user_alias,
                     );
 
-                    return Err(self.error_form(err, stub));
+                    return Err(self.machine_st.error_form(err, stub));
                 }
 
-                *current_input_stream = stream;
+                self.user_input = stream;
             }
             &SystemClauseType::SetOutput => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let stream =
-                    self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_output"), 1)?;
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let stream = self.machine_st.get_stream_or_alias(
+                    addr,
+                    &self.indices.stream_aliases,
+                    atom!("set_output"),
+                    1,
+                )?;
 
                 if !stream.is_output_stream() {
                     let stub = functor_stub(atom!("set_input"), 1);
 
                     let user_alias = atom_as_cell!(atom!("user"));
-                    let err = self.permission_error(
+                    let err = self.machine_st.permission_error(
                         Permission::OutputStream,
                         atom!("stream"),
                         user_alias,
                     );
 
-                    return Err(self.error_form(err, stub));
+                    return Err(self.machine_st.error_form(err, stub));
                 }
 
-                *current_output_stream = stream;
+                self.user_output = stream;
             }
             &SystemClauseType::SetDoubleQuotes => {
-                let atom = cell_as_atom!(self.registers[1]);
+                let atom = cell_as_atom!(self.machine_st.registers[1]);
 
-                self.flags.double_quotes = match atom {
+                self.machine_st.flags.double_quotes = match atom {
                     atom!("atom") => DoubleQuotes::Atom,
                     atom!("chars") => DoubleQuotes::Chars,
                     atom!("codes") => DoubleQuotes::Codes,
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
             }
             &SystemClauseType::InferenceLevel => {
-                let a1 = self.registers[1];
-                let a2 = self.store(self.deref(self.registers[2]));
+                let a1 = self.machine_st.registers[1];
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let bp = cell_as_fixnum!(a2).get_num() as usize;
-                let prev_b = self.stack.index_or_frame(self.b).prelude.b;
+                let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
 
                 if prev_b <= bp {
-                    self.unify_atom(atom!("!"), a1)
+                    self.machine_st.unify_atom(atom!("!"), a1)
                 } else {
-                    self.unify_atom(atom!("true"), a1);
+                    self.machine_st.unify_atom(atom!("true"), a1);
                 }
             }
             &SystemClauseType::CleanUpBlock => {
-                let nb = self.store(self.deref(self.registers[1]));
+                let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let nb = cell_as_fixnum!(nb).get_num() as usize;
 
-                let b = self.b;
+                let b = self.machine_st.b;
 
-                if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb {
-                    self.b = self.stack.index_or_frame(nb).prelude.b;
+                if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb {
+                    self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b;
                 }
             }
             &SystemClauseType::EraseBall => {
-                self.ball.reset();
+                self.machine_st.ball.reset();
             }
             &SystemClauseType::Fail => {
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::GetBall => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let h = self.heap.len();
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let h = self.machine_st.heap.len();
 
-                if self.ball.stub.len() > 0 {
-                    let stub = self.ball.copy_and_align(h);
-                    self.heap.extend(stub.into_iter());
+                if self.machine_st.ball.stub.len() > 0 {
+                    let stub = self.machine_st.ball.copy_and_align(h);
+                    self.machine_st.heap.extend(stub.into_iter());
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
 
                 match addr.as_var() {
-                    Some(r) => self.bind(r, self.heap[h]),
-                    _ => self.fail = true,
+                    Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]),
+                    _ => self.machine_st.fail = true,
                 };
             }
             &SystemClauseType::GetCurrentBlock => {
-                let n = Fixnum::build_with(i64::try_from(self.block).unwrap());
-                self.unify_fixnum(n, self.registers[1]);
+                let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap());
+                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
             }
             &SystemClauseType::GetBValue => {
-                let n = Fixnum::build_with(i64::try_from(self.b).unwrap());
-                self.unify_fixnum(n, self.registers[1]);
+                let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap());
+                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
             }
             &SystemClauseType::GetCutPoint => {
-                let n = Fixnum::build_with(i64::try_from(self.b0).unwrap());
-                self.unify_fixnum(n, self.registers[1]);
+                let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap());
+                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
             }
             &SystemClauseType::GetStaggeredCutPoint => {
                 use std::sync::Once;
 
-                let b = self.store(self.deref(self.registers[1]));
+                let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0;
                 static LOC_INIT: Once = Once::new();
 
                 let semicolon_second_clause_p = unsafe {
                     LOC_INIT.call_once(|| {
-                        match indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) {
+                        match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) {
                             Some(IndexPtr::Index(p)) => {
-                                match code_repo.code[p] {
+                                match self.code_repo.code[p] {
                                     Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
                                         SEMICOLON_SECOND_BRANCH_LOC = p + o;
                                     }
@@ -3631,77 +3605,77 @@ impl MachineState {
                     LocalCodePtr::DirEntry(SEMICOLON_SECOND_BRANCH_LOC)
                 };
 
-                let staggered_b0 = if self.b > 0 {
-                    let or_frame = self.stack.index_or_frame(self.b);
+                let staggered_b0 = if self.machine_st.b > 0 {
+                    let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b);
 
                     if or_frame.prelude.bp == semicolon_second_clause_p {
                         or_frame.prelude.b0
                     } else {
-                        self.b0
+                        self.machine_st.b0
                     }
                 } else {
-                    self.b0
+                    self.machine_st.b0
                 };
 
                 let staggered_b0 = integer_as_cell!(
-                    Number::arena_from(staggered_b0, &mut self.arena)
+                    Number::arena_from(staggered_b0, &mut self.machine_st.arena)
                 );
 
-                self.bind(b.as_var().unwrap(), staggered_b0);
+                self.machine_st.bind(b.as_var().unwrap(), staggered_b0);
             }
             &SystemClauseType::InstallNewBlock => {
-                self.install_new_block(self.registers[1]);
+                self.machine_st.install_new_block(self.machine_st.registers[1]);
             }
             &SystemClauseType::NextEP => {
-                let first_arg = self.store(self.deref(self.registers[1]));
+                let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(first_arg,
                     (HeapCellValueTag::Atom, (name, arity)) => {
                         debug_assert_eq!(name, atom!("first"));
                         debug_assert_eq!(arity, 0);
 
-                        if self.e == 0 {
-                            self.fail = true;
+                        if self.machine_st.e == 0 {
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
 
-                        let and_frame = self.stack.index_and_frame(self.e);
+                        let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e);
                         let cp = (and_frame.prelude.cp - 1).unwrap();
 
                         let e = and_frame.prelude.e;
                         let e = Fixnum::build_with(i64::try_from(e).unwrap());
 
-                        let p = str_loc_as_cell!(self.heap.len());
+                        let p = str_loc_as_cell!(self.machine_st.heap.len());
 
-                        self.heap.extend(cp.as_functor());
-                        self.unify_fixnum(e, self.registers[2]);
+                        self.machine_st.heap.extend(cp.as_functor());
+                        self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
-                        if !self.fail {
-                            unify!(self, p, self.registers[3]);
+                        if !self.machine_st.fail {
+                            unify!(self.machine_st, p, self.machine_st.registers[3]);
                         }
                     }
                     (HeapCellValueTag::Fixnum, n) => {
                         let e = n.get_num() as usize;
 
                         if e == 0 {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
 
                         // get the call site so that the number of
                         // active permanent variables can be read from
                         // it later.
-                        let and_frame = self.stack.index_and_frame(e);
+                        let and_frame = self.machine_st.stack.index_and_frame(e);
                         let cp = (and_frame.prelude.cp - 1).unwrap();
 
-                        let p = str_loc_as_cell!(self.heap.len());
-                        self.heap.extend(cp.as_functor());
+                        let p = str_loc_as_cell!(self.machine_st.heap.len());
+                        self.machine_st.heap.extend(cp.as_functor());
 
                         let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
-                        self.unify_fixnum(e, self.registers[2]);
+                        self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
-                        if !self.fail {
-                            unify!(self, p, self.registers[3]);
+                        if !self.machine_st.fail {
+                            unify!(self.machine_st, p, self.machine_st.registers[3]);
                         }
                     }
                     _ => {
@@ -3710,59 +3684,59 @@ impl MachineState {
                 );
             }
             &SystemClauseType::PointsToContinuationResetMarker => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let p = match to_local_code_ptr(&self.heap, addr) {
+                let p = match to_local_code_ptr(&self.machine_st.heap, addr) {
                     Some(p) => p + 1,
                     None => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
 
-                if self.is_reset_cont_marker(&code_repo, p) {
-                    return return_from_clause!(self.last_call, self);
+                if self.is_reset_cont_marker(p) {
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
                 return Ok(());
             }
             &SystemClauseType::QuotedToken => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(addr,
                     (HeapCellValueTag::Fixnum, n) => {
                         let n = u32::try_from(n.get_num()).ok();
                         let n = n.and_then(std::char::from_u32);
 
-                        self.fail = match n {
+                        self.machine_st.fail = match n {
                             Some(c) => non_quoted_token(once(c)),
                             None => true,
                         };
                     }
                     (HeapCellValueTag::Char, c) => {
-                        self.fail = non_quoted_token(once(c));
+                        self.machine_st.fail = non_quoted_token(once(c));
                     }
                     (HeapCellValueTag::Atom, (name, arity)) => {
                         debug_assert_eq!(arity, 0);
-                        self.fail = non_quoted_token(name.as_str().chars());
+                        self.machine_st.fail = non_quoted_token(name.as_str().chars());
                     }
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                     }
                 );
             }
             &SystemClauseType::ReadQueryTerm => {
-                current_input_stream.reset();
+                self.user_input.reset();
 
                 set_prompt(true);
-                let result = self.read_term(*current_input_stream, indices);
+                let result = self.machine_st.read_term(self.user_input, &mut self.indices);
                 set_prompt(false);
 
                 match result {
                     Ok(()) => {}
                     Err(e) => {
-                        *current_input_stream = input_stream(&mut self.arena);
+                        self.user_input = input_stream(&mut self.machine_st.arena);
                         return Err(e);
                     }
                 }
@@ -3770,55 +3744,55 @@ impl MachineState {
             &SystemClauseType::ReadTerm => {
                 set_prompt(false);
 
-                let stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("read_term"),
                     3,
                 )?;
 
-                self.read_term(stream, indices)?;
+                self.machine_st.read_term(stream, &mut self.indices)?;
             }
             &SystemClauseType::ReadTermFromChars => {
-                if let Some(atom_or_string) = self.value_to_str_like(self.registers[1]) {
+                if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     let chars = atom_or_string.to_string();
-                    let stream = Stream::from_owned_string(chars, &mut self.arena);
+                    let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena);
 
-                    let term_write_result = match self.read(stream, &indices.op_dir) {
+                    let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) {
                         Ok(term_write_result) => term_write_result,
                         Err(e) => {
                             let stub = functor_stub(atom!("read_term_from_chars"), 2);
-                            let e = self.session_error(SessionError::from(e));
+                            let e = self.machine_st.session_error(SessionError::from(e));
 
-                            return Err(self.error_form(e, stub));
+                            return Err(self.machine_st.error_form(e, stub));
                         }
                     };
 
                     let result = heap_loc_as_cell!(term_write_result.heap_loc);
-                    let var = self.store(self.deref(self.registers[2])).as_var().unwrap();
+                    let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])).as_var().unwrap();
 
-                    self.bind(var, result);
+                    self.machine_st.bind(var, result);
                 } else {
                     unreachable!()
                 }
             }
             &SystemClauseType::ResetBlock => {
-                let addr = self.deref(self.registers[1]);
-                self.reset_block(addr);
+                let addr = self.machine_st.deref(self.machine_st.registers[1]);
+                self.machine_st.reset_block(addr);
             }
             &SystemClauseType::ResetContinuationMarker => {
-                let h = self.heap.len();
+                let h = self.machine_st.heap.len();
 
-                self.registers[3] = atom_as_cell!(atom!("none"));
-                self.registers[4] = heap_loc_as_cell!(h);
+                self.machine_st.registers[3] = atom_as_cell!(atom!("none"));
+                self.machine_st.registers[4] = heap_loc_as_cell!(h);
 
-                self.heap.push(heap_loc_as_cell!(h));
+                self.machine_st.heap.push(heap_loc_as_cell!(h));
             }
             &SystemClauseType::SetBall => {
-                self.set_ball();
+                self.machine_st.set_ball();
             }
             &SystemClauseType::SetSeed => {
-                let seed = self.store(self.deref(self.registers[1]));
+                let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let mut rand = RANDOM_STATE.borrow_mut();
 
                 match Number::try_from(seed) {
@@ -3826,18 +3800,18 @@ impl MachineState {
                     Ok(Number::Integer(n)) => rand.seed(&*n),
                     Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()),
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 }
             }
             &SystemClauseType::SkipMaxList => {
-                if let Err(err) = self.skip_max_list() {
+                if let Err(err) = self.machine_st.skip_max_list() {
                     return Err(err);
                 }
             }
             &SystemClauseType::Sleep => {
-                let time = self.store(self.deref(self.registers[1]));
+                let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 let time = match Number::try_from(time) {
                     Ok(Number::Float(n)) => n.into_inner(),
@@ -3854,8 +3828,8 @@ impl MachineState {
                 std::thread::sleep(duration);
             }
             &SystemClauseType::SocketClientOpen => {
-                let addr = self.store(self.deref(self.registers[1]));
-                let port = self.store(self.deref(self.registers[2]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let socket_atom = cell_as_atom!(addr);
 
@@ -3865,7 +3839,7 @@ impl MachineState {
                         name
                     }
                     _ => {
-                        self.atom_tbl.build_with(&match Number::try_from(port) {
+                        self.machine_st.atom_tbl.build_with(&match Number::try_from(port) {
                             Ok(Number::Fixnum(n)) => n.get_num().to_string(),
                             Ok(Number::Integer(n)) => n.to_string(),
                             _ => {
@@ -3881,20 +3855,20 @@ impl MachineState {
                     socket_atom
                 };
 
-                let alias = self.registers[4];
-                let eof_action = self.registers[5];
-                let reposition = self.registers[6];
-                let stream_type = self.registers[7];
+                let alias = self.machine_st.registers[4];
+                let eof_action = self.machine_st.registers[5];
+                let reposition = self.machine_st.registers[6];
+                let stream_type = self.machine_st.registers[7];
 
-                let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
 
                 if options.reposition() {
-                    return Err(self.reposition_error(atom!("socket_client_open"), 3));
+                    return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3));
                 }
 
                 if let Some(alias) = options.get_alias() {
-                    if indices.stream_aliases.contains_key(&alias) {
-                        return Err(self.occupied_alias_permission_error(
+                    if self.indices.stream_aliases.contains_key(&alias) {
+                        return Err(self.machine_st.occupied_alias_permission_error(
                             alias,
                             atom!("socket_client_open"),
                             3,
@@ -3909,36 +3883,36 @@ impl MachineState {
                         *stream.options_mut() = options;
 
                         if let Some(alias) = stream.options().get_alias() {
-                            indices.stream_aliases.insert(alias, stream);
+                            self.indices.stream_aliases.insert(alias, stream);
                         }
 
-                        indices.streams.insert(stream);
+                        self.indices.streams.insert(stream);
 
                         stream_as_cell!(stream)
                     }
                     Err(ErrorKind::PermissionDenied) => {
-                        return Err(self.open_permission_error(addr, atom!("socket_client_open"), 3));
+                        return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3));
                     }
                     Err(ErrorKind::NotFound) => {
                         let stub = functor_stub(atom!("socket_client_open"), 3);
-                        let err = self.existence_error(
+                        let err = self.machine_st.existence_error(
                             ExistenceError::SourceSink(addr),
                         );
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                     Err(_) => {
                         // for now, just fail. expand to meaningful error messages later.
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
 
-                let stream_addr = self.store(self.deref(self.registers[3]));
-                self.bind(stream_addr.as_var().unwrap(), stream);
+                let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+                self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
             }
             &SystemClauseType::SocketServerOpen => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let socket_atom = cell_as_atom_cell!(addr).get_name();
 
                 let socket_atom = if socket_atom == atom!("[]") {
@@ -3947,7 +3921,7 @@ impl MachineState {
                     socket_atom
                 };
 
-                let port = self.store(self.deref(self.registers[2]));
+                let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let port = if port.is_var() {
                     String::from("0")
@@ -3975,43 +3949,43 @@ impl MachineState {
                             let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
 
                             if let Some(port) = port {
-                                (arena_alloc!(tcp_listener, &mut self.arena), port as usize)
+                                (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize)
                             } else {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                                 return Ok(());
                             }
                         }
                         Err(ErrorKind::PermissionDenied) => {
-                            return Err(self.open_permission_error(addr, atom!("socket_server_open"), 2));
+                            return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2));
                         }
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     };
 
-                let addr = self.store(self.deref(self.registers[3]));
-                self.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+                self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener));
 
                 if had_zero_port {
-                    self.unify_fixnum(Fixnum::build_with(port as i64), self.registers[2]);
+                    self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]);
                 }
             }
             &SystemClauseType::SocketServerAccept => {
-                let alias = self.registers[4];
-                let eof_action = self.registers[5];
-                let reposition = self.registers[6];
-                let stream_type = self.registers[7];
+                let alias = self.machine_st.registers[4];
+                let eof_action = self.machine_st.registers[5];
+                let reposition = self.machine_st.registers[6];
+                let stream_type = self.machine_st.registers[7];
 
-                let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
 
                 if options.reposition() {
-                    return Err(self.reposition_error(atom!("socket_server_accept"), 4));
+                    return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4));
                 }
 
                 if let Some(alias) = options.get_alias() {
-                    if indices.stream_aliases.contains_key(&alias) {
-                        return Err(self.occupied_alias_permission_error(
+                    if self.indices.stream_aliases.contains_key(&alias) {
+                        return Err(self.machine_st.occupied_alias_permission_error(
                             alias,
                             atom!("socket_server_accept"),
                             4,
@@ -4019,7 +3993,7 @@ impl MachineState {
                     }
                 }
 
-                let culprit = self.store(self.deref(self.registers[1]));
+                let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(culprit,
                     (HeapCellValueTag::Cons, cons_ptr) => {
@@ -4027,35 +4001,39 @@ impl MachineState {
                              (ArenaHeaderTag::TcpListener, tcp_listener) => {
                                  match tcp_listener.accept().ok() {
                                      Some((tcp_stream, socket_addr)) => {
-                                         let client = self.atom_tbl.build_with(&socket_addr.to_string());
+                                         let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string());
 
                                          let mut tcp_stream = Stream::from_tcp_stream(
                                              client,
                                              tcp_stream,
-                                             &mut self.arena,
+                                             &mut self.machine_st.arena,
                                          );
 
                                          *tcp_stream.options_mut() = options;
 
                                          if let Some(alias) = &tcp_stream.options().get_alias() {
-                                             indices.stream_aliases.insert(*alias, tcp_stream);
+                                             self.indices.stream_aliases.insert(*alias, tcp_stream);
                                          }
 
-                                         indices.streams.insert(tcp_stream);
+                                         self.indices.streams.insert(tcp_stream);
 
                                          let tcp_stream = stream_as_cell!(tcp_stream);
                                          let client = atom_as_cell!(client);
 
-                                         let client_addr = self.store(self.deref(self.registers[2]));
-                                         let stream_addr = self.store(self.deref(self.registers[3]));
+                                         let client_addr = self.machine_st.store(self.machine_st.deref(
+                                             self.machine_st.registers[2],
+                                         ));
+                                         let stream_addr = self.machine_st.store(self.machine_st.deref(
+                                             self.machine_st.registers[3],
+                                         ));
 
-                                         self.bind(client_addr.as_var().unwrap(), client);
-                                         self.bind(stream_addr.as_var().unwrap(), tcp_stream);
+                                         self.machine_st.bind(client_addr.as_var().unwrap(), client);
+                                         self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream);
 
-                                         return return_from_clause!(self.last_call, self);
+                                         return return_from_clause!(self.machine_st.last_call, self.machine_st);
                                      }
                                      None => {
-                                         self.fail = true;
+                                         self.machine_st.fail = true;
                                          return Ok(());
                                      }
                                  }
@@ -4102,24 +4080,24 @@ impl MachineState {
                 }
             }
             &SystemClauseType::TLSAcceptClient => {
-                let pkcs12 = self.string_encoding_bytes(self.registers[1], atom!("octet"));
+                let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
 
-                if let Some(password) = self.value_to_str_like(self.registers[2]) {
+                if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
                     let identity =
                         match Identity::from_pkcs12(&pkcs12, password.as_str()) {
                             Ok(identity) => identity,
                             Err(_) => {
-                                return Err(self.open_permission_error(
-                                    self.registers[1],
+                                return Err(self.machine_st.open_permission_error(
+                                    self.machine_st.registers[1],
                                     atom!("tls_server_negotiate"),
                                     3,
                                 ));
                             }
                         };
 
-                    let stream0 = self.get_stream_or_alias(
-                        self.registers[3],
-                        &indices.stream_aliases,
+                    let stream0 = self.machine_st.get_stream_or_alias(
+                        self.machine_st.registers[3],
+                        &self.indices.stream_aliases,
                         atom!("tls_server_negotiate"),
                         3,
                     )?;
@@ -4130,25 +4108,25 @@ impl MachineState {
                         match acceptor.accept(stream0) {
                             Ok(tls_stream) => tls_stream,
                             Err(_) => {
-                                return Err(self.open_permission_error(
-                                    self.registers[3],
+                                return Err(self.machine_st.open_permission_error(
+                                    self.machine_st.registers[3],
                                     atom!("tls_server_negotiate"),
                                     3,
                                 ));
                             }
                         };
 
-                    let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.arena);
-                    indices.streams.insert(stream);
+                    let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena);
+                    self.indices.streams.insert(stream);
 
-                    let stream_addr = self.store(self.deref(self.registers[4]));
-                    self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
+                    let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
+                    self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
                 } else {
                     unreachable!();
                 }
             }
             &SystemClauseType::SocketServerClose => {
-                let culprit = self.store(self.deref(self.registers[1]));
+                let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 read_heap_cell!(culprit,
                     (HeapCellValueTag::Cons, cons_ptr) => {
@@ -4160,7 +4138,7 @@ impl MachineState {
                                 }
 
                                 tcp_listener.set_tag(ArenaHeaderTag::Dropped);
-                                return return_from_clause!(self.last_call, self);
+                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
                             }
                             _ => {
                             }
@@ -4170,15 +4148,15 @@ impl MachineState {
                     }
                 );
 
-                let err = self.type_error(ValidType::TcpListener, culprit);
+                let err = self.machine_st.type_error(ValidType::TcpListener, culprit);
                 let stub = functor_stub(atom!("socket_server_close"), 1);
 
-                return Err(self.error_form(err, stub));
+                return Err(self.machine_st.error_form(err, stub));
             }
             &SystemClauseType::SetStreamPosition => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("set_stream_position"),
                     2,
                 )?;
@@ -4186,16 +4164,16 @@ impl MachineState {
                 if !stream.options().reposition() {
                     let stub = functor_stub(atom!("set_stream_position"), 2);
 
-                    let err = self.permission_error(
+                    let err = self.machine_st.permission_error(
                         Permission::Reposition,
                         atom!("stream"),
                         vec![stream_as_cell!(stream)],
                     );
 
-                    return Err(self.error_form(err, stub));
+                    return Err(self.machine_st.error_form(err, stub));
                 }
 
-                let position = self.store(self.deref(self.registers[2]));
+                let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let position = match Number::try_from(position) {
                     Ok(Number::Fixnum(n)) => n.get_num() as u64,
@@ -4203,7 +4181,7 @@ impl MachineState {
                         if let Some(n) = n.to_u64() {
                             n
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
@@ -4215,21 +4193,21 @@ impl MachineState {
                 stream.set_position(position);
             }
             &SystemClauseType::StreamProperty => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("stream_property"),
                     2,
                 )?;
 
-                let atom = cell_as_atom!(self.store(self.deref(self.registers[2])));
+                let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
 
                 let property = match atom {
                     atom!("file_name") => {
                         atom_as_cell!(if let Some(file_name) = stream.file_name() {
                             file_name
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         })
                     }
@@ -4246,24 +4224,24 @@ impl MachineState {
                         atom_as_cell!(if let Some(alias) = stream.options().get_alias() {
                             alias
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         })
                     }
                     atom!("position") => {
                         if let Some((position, lines_read)) = stream.position() {
-                            let h = self.heap.len();
+                            let h = self.machine_st.heap.len();
 
                             let position_term = functor!(
                                 atom!("position_and_lines_read"),
-                                [integer(position, &mut self.arena),
-                                 integer(lines_read, &mut self.arena)]
+                                [integer(position, &mut self.machine_st.arena),
+                                 integer(lines_read, &mut self.machine_st.arena)]
                             );
 
-                            self.heap.extend(position_term.into_iter());
+                            self.machine_st.heap.extend(position_term.into_iter());
                             str_loc_as_cell!(h)
                         } else {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
@@ -4288,76 +4266,76 @@ impl MachineState {
                     }
                 };
 
-                unify!(self, property, self.registers[3]);
+                unify!(self.machine_st, property, self.machine_st.registers[3]);
             }
             &SystemClauseType::StoreGlobalVar => {
-                let key = cell_as_atom!(self.store(self.deref(self.registers[1])));
+                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
 
-                let value = self.registers[2];
+                let value = self.machine_st.registers[2];
                 let mut ball = Ball::new();
 
-                ball.boundary = self.heap.len();
+                ball.boundary = self.machine_st.heap.len();
 
                 copy_term(
-                    CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub),
+                    CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub),
                     value,
                     AttrVarPolicy::DeepCopy,
                 );
 
-                indices.global_variables.insert(key, (ball, None));
+                self.indices.global_variables.insert(key, (ball, None));
             }
             &SystemClauseType::StoreBacktrackableGlobalVar => {
-                let key = cell_as_atom!(self.store(self.deref(self.registers[1])));
-                let new_value = self.store(self.deref(self.registers[2]));
+                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+                let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                match indices.global_variables.get_mut(&key) {
+                match self.indices.global_variables.get_mut(&key) {
                     Some((_, ref mut loc)) => match loc {
                         Some(ref mut value) => {
-                            self.trail(TrailRef::BlackboardOffset(key, *value));
+                            self.machine_st.trail(TrailRef::BlackboardOffset(key, *value));
                             *value = new_value;
                         }
                         loc @ None => {
-                            self.trail(TrailRef::BlackboardEntry(key));
+                            self.machine_st.trail(TrailRef::BlackboardEntry(key));
                             *loc = Some(new_value);
                         }
                     },
                     None => {
-                        self.trail(TrailRef::BlackboardEntry(key));
-                        indices
+                        self.machine_st.trail(TrailRef::BlackboardEntry(key));
+                        self.indices
                             .global_variables
                             .insert(key, (Ball::new(), Some(new_value)));
                     }
                 }
             }
             &SystemClauseType::TermAttributedVariables => {
-                if self.registers[1].is_constant() {
-                    self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2])));
-                    return return_from_clause!(self.last_call, self);
+                if self.machine_st.registers[1].is_constant() {
+                    self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
-                let seen_vars = self.attr_vars_of_term(self.registers[1]);
+                let seen_vars = self.machine_st.attr_vars_of_term(self.machine_st.registers[1]);
                 let outcome = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.heap, seen_vars.into_iter())
+                    iter_to_heap_list(&mut self.machine_st.heap, seen_vars.into_iter())
                 );
 
-                unify_fn!(self, self.registers[2], outcome);
+                unify_fn!(self.machine_st, self.machine_st.registers[2], outcome);
             }
             &SystemClauseType::Succeed => {}
             &SystemClauseType::TermVariables => {
-                let a1 = self.registers[1];
-                let a2 = self.registers[2];
+                let a1 = self.machine_st.registers[1];
+                let a2 = self.machine_st.registers[2];
 
-                let stored_v = self.store(self.deref(a1));
+                let stored_v = self.machine_st.store(self.machine_st.deref(a1));
 
                 if stored_v.is_constant() {
-                    self.unify_atom(atom!("[]"), self.store(self.deref(a2)));
-                    return return_from_clause!(self.last_call, self);
+                    self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2)));
+                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
                 }
 
                 let mut seen_set = IndexSet::new();
 
                 {
-                    let mut iter = stackless_preorder_iter(&mut self.heap, stored_v);
+                    let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v);
 
                     while let Some(addr) = iter.next() {
                         let addr = unmark_cell_bits!(addr);
@@ -4370,7 +4348,7 @@ impl MachineState {
 
                 let outcome = heap_loc_as_cell!(
                     filtered_iter_to_heap_list(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         seen_set.into_iter().rev(),
                         |heap, value| {
                             heap_bound_store(
@@ -4381,57 +4359,63 @@ impl MachineState {
                     )
                 );
 
-                unify_fn!(self, a2, outcome);
+                unify_fn!(self.machine_st, a2, outcome);
             }
             &SystemClauseType::TermVariablesUnderMaxDepth => {
                 // Term, MaxDepth, VarList
                 let max_depth = cell_as_fixnum!(
-                    self.store(self.deref(self.registers[2]))
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
                 ).get_num() as usize;
 
-                self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]);
+                self.machine_st.term_variables_under_max_depth(
+                    self.machine_st.registers[1],
+                    max_depth,
+                    self.machine_st.registers[3],
+                );
             }
             &SystemClauseType::TruncateLiftedHeapTo => {
-                let a1 = self.store(self.deref(self.registers[1]));
+                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let lh_offset = cell_as_fixnum!(a1).get_num() as usize;
 
-                self.lifted_heap.truncate(lh_offset);
+                self.machine_st.lifted_heap.truncate(lh_offset);
             }
             &SystemClauseType::UnifyWithOccursCheck => {
-                let a1 = self.registers[1];
-                let a2 = self.registers[2];
+                let a1 = self.machine_st.registers[1];
+                let a2 = self.machine_st.registers[2];
 
-                unify_with_occurs_check!(self, a1, a2);
+                unify_with_occurs_check!(&mut self.machine_st, a1, a2);
             }
             &SystemClauseType::UnwindEnvironments => {
-                let mut e = self.e;
-                let mut cp = self.cp;
+                let mut e = self.machine_st.e;
+                let mut cp = self.machine_st.cp;
 
                 while e > 0 {
-                    if self.is_reset_cont_marker(code_repo, cp) {
-                        self.e = e;
-                        self.p = CodePtr::Local(cp + 1); // skip the reset marker.
+                    if self.is_reset_cont_marker(cp) {
+                        self.machine_st.e = e;
+                        self.machine_st.p = CodePtr::Local(cp + 1); // skip the reset marker.
 
                         return Ok(());
                     }
 
-                    let and_frame = self.stack.index_and_frame(e);
+                    let and_frame = self.machine_st.stack.index_and_frame(e);
 
                     cp = and_frame.prelude.cp;
                     e = and_frame.prelude.e;
                 }
             }
             &SystemClauseType::UnwindStack => {
-                self.unwind_stack();
+                self.machine_st.unwind_stack();
             }
             &SystemClauseType::WAMInstructions => {
-                let module_name = cell_as_atom!(self.store(self.deref(self.registers[1])));
+                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+                    self.machine_st.registers[1])
+                ));
 
-                let name = self.registers[2];
-                let arity = self.registers[3];
+                let name = self.machine_st.registers[2];
+                let arity = self.machine_st.registers[3];
 
-                let name = cell_as_atom!(self.store(self.deref(name)));
-                let arity = self.store(self.deref(arity));
+                let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name)));
+                let arity = self.machine_st.store(self.machine_st.deref(arity));
 
                 let arity = match Number::try_from(arity) {
                     Ok(Number::Fixnum(n)) => n.get_num() as usize,
@@ -4444,18 +4428,18 @@ impl MachineState {
                 let key = (name, arity);
 
                 let first_idx = match module_name {
-                    atom!("user") => indices.code_dir.get(&key),
-                    _ => match indices.modules.get(&module_name) {
+                    atom!("user") => self.indices.code_dir.get(&key),
+                    _ => match self.indices.modules.get(&module_name) {
                         Some(module) => module.code_dir.get(&key),
                         None => {
                             let stub = functor_stub(key.0, key.1);
-                            let err = self.session_error(
+                            let err = self.machine_st.session_error(
                                 SessionError::from(CompilationError::InvalidModuleResolution(
                                     module_name,
                                 )),
                             );
 
-                            return Err(self.error_form(err, stub));
+                            return Err(self.machine_st.error_form(err, stub));
                         }
                     },
                 };
@@ -4470,22 +4454,22 @@ impl MachineState {
                     }
                     _ => {
                         let stub = functor_stub(name, arity);
-                        let err = self.existence_error(
+                        let err = self.machine_st.existence_error(
                             ExistenceError::Procedure(name, arity),
                         );
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 };
 
-                let mut h = self.heap.len();
+                let mut h = self.machine_st.heap.len();
 
                 let mut functors = vec![];
                 let mut functor_list = vec![];
 
-                walk_code(&code_repo.code, first_idx, |instr| {
+                walk_code(&self.code_repo.code, first_idx, |instr| {
                     let old_len = functors.len();
-                    instr.enqueue_functors(h, &mut self.arena, &mut functors);
+                    instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors);
                     let new_len = functors.len();
 
                     for index in old_len..new_len {
@@ -4506,26 +4490,26 @@ impl MachineState {
                 });
 
                 for functor in functors {
-                    self.heap.extend(functor.into_iter());
+                    self.machine_st.heap.extend(functor.into_iter());
                 }
 
                 let listing = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.heap, functor_list.into_iter())
+                    iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter())
                 );
 
-                let listing_var = self.registers[4];
+                let listing_var = self.machine_st.registers[4];
 
-                unify!(self, listing, listing_var);
+                unify!(self.machine_st, listing, listing_var);
             }
             &SystemClauseType::WriteTerm => {
-                let mut stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let mut stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("write_term"),
                     3,
                 )?;
 
-                self.check_stream_properties(
+                self.machine_st.check_stream_properties(
                     stream,
                     StreamType::Text,
                     None, // input
@@ -4542,7 +4526,7 @@ impl MachineState {
                 };
 
                 if let Some(err_atom) = opt_err {
-                    return Err(self.stream_permission_error(
+                    return Err(self.machine_st.stream_permission_error(
                         Permission::OutputStream,
                         err_atom,
                         stream,
@@ -4551,7 +4535,7 @@ impl MachineState {
                     ));
                 }
 
-                let printer = match self.write_term(&indices.op_dir)? {
+                let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
                     Some(printer) => printer,
                     None => {
                         // this next line is executed by
@@ -4559,7 +4543,7 @@ impl MachineState {
                         // commented here because rustc can't prove
                         // that it's no longer borrowed.
 
-                        // self.fail = true;
+                        // self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
@@ -4570,37 +4554,37 @@ impl MachineState {
                     Ok(_) => {}
                     Err(_) => {
                         let stub = functor_stub(atom!("open"), 4);
-                        let err = self.existence_error(
-                            ExistenceError::Stream(self.registers[1]),
+                        let err = self.machine_st.existence_error(
+                            ExistenceError::Stream(self.machine_st.registers[1]),
                         );
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 }
 
                 stream.flush().unwrap();
             }
             &SystemClauseType::WriteTermToChars => {
-                let printer = match self.write_term(&indices.op_dir)? {
+                let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
                     None => {
                         // this next line is executed by
                         // MachineState::write_term in this case. it's
                         // commented here because rustc can't prove
                         // that it's no longer borrowed.
 
-                        // self.fail = true;
+                        // self.machine_st.fail = true;
                         return Ok(());
                     }
                     Some(printer) => printer,
                 };
 
                 let result = printer.print().result();
-                let chars = put_complete_string(&mut self.heap, &result, &mut self.atom_tbl);
+                let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl);
 
-                let result_addr = self.store(self.deref(self.registers[1]));
+                let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
                 if let Some(var) = result_addr.as_var() {
-                    self.bind(var, chars);
+                    self.machine_st.bind(var, chars);
                 } else {
                     unreachable!()
                 }
@@ -4609,12 +4593,12 @@ impl MachineState {
                 use git_version::git_version;
 
                 let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
-                let buffer_atom = self.atom_tbl.build_with(buffer);
+                let buffer_atom = self.machine_st.atom_tbl.build_with(buffer);
 
-                self.unify_complete_string(buffer_atom, self.store(self.deref(self.registers[1])));
+                self.machine_st.unify_complete_string(buffer_atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
             }
             &SystemClauseType::CryptoRandomByte => {
-                let arg = self.registers[1];
+                let arg = self.machine_st.registers[1];
                 let mut bytes: [u8; 1] = [0];
 
                 match rng().fill(&mut bytes) {
@@ -4623,19 +4607,19 @@ impl MachineState {
                         // the error payload here is of type 'Unspecified',
                         // which contains no information whatsoever. So, for now,
                         // just fail.
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 }
 
                 let byte = Fixnum::build_with(bytes[0] as i64);
-                self.unify_fixnum(byte, arg);
+                self.machine_st.unify_fixnum(byte, arg);
             }
             &SystemClauseType::CryptoDataHash => {
-                let encoding = cell_as_atom!(self.registers[2]);
-                let bytes = self.string_encoding_bytes(self.registers[1], encoding);
+                let encoding = cell_as_atom!(self.machine_st.registers[2]);
+                let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
 
-                let algorithm = cell_as_atom!(self.registers[4]);
+                let algorithm = cell_as_atom!(self.machine_st.registers[4]);
 
                 let ints_list = match algorithm {
                     atom!("sha3_224") => {
@@ -4644,7 +4628,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4658,7 +4642,7 @@ impl MachineState {
                         context.input(&bytes);
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4673,7 +4657,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4688,7 +4672,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4703,7 +4687,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4718,7 +4702,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4733,7 +4717,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 context
                                     .result()
                                     .as_ref()
@@ -4758,7 +4742,7 @@ impl MachineState {
 
                         heap_loc_as_cell!(
                             iter_to_heap_list(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 ints.as_ref()
                                     .iter()
                                     .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
@@ -4767,28 +4751,28 @@ impl MachineState {
                     }
                 };
 
-                unify!(self, self.registers[3], ints_list);
+                unify!(self.machine_st, self.machine_st.registers[3], ints_list);
             }
             &SystemClauseType::CryptoDataHKDF => {
-                let encoding = cell_as_atom!(self.registers[2]);
-                let data = self.string_encoding_bytes(self.registers[1], encoding);
+                let encoding = cell_as_atom!(self.machine_st.registers[2]);
+                let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
 
                 let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
-                let salt = self.integers_to_bytevec(self.registers[3], stub1_gen);
+                let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
 
                 let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
-                let info = self.integers_to_bytevec(self.registers[4], stub2_gen);
+                let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
-                let algorithm = cell_as_atom!(self.registers[5]);
+                let algorithm = cell_as_atom!(self.machine_st.registers[5]);
 
-                let length = self.store(self.deref(self.registers[6]));
+                let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6]));
 
                 let length = match Number::try_from(length) {
                     Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
                     Ok(Number::Integer(n)) => match n.to_usize() {
                         Some(u) => u,
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     },
@@ -4803,7 +4787,7 @@ impl MachineState {
                         atom!("sha384") => hkdf::HKDF_SHA384,
                         atom!("sha512") => hkdf::HKDF_SHA512,
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     };
@@ -4818,14 +4802,14 @@ impl MachineState {
                             r.fill(&mut bytes).unwrap();
                         }
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
 
                     heap_loc_as_cell!(
                         iter_to_heap_list(
-                            &mut self.heap,
+                            &mut self.machine_st.heap,
                             bytes
                                 .iter()
                                 .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
@@ -4833,22 +4817,22 @@ impl MachineState {
                     )
                 };
 
-                unify!(self, self.registers[7], ints_list);
+                unify!(self.machine_st, self.machine_st.registers[7], ints_list);
             }
             &SystemClauseType::CryptoPasswordHash => {
                 let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3);
-                let data = self.integers_to_bytevec(self.registers[1], stub1_gen);
+                let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
                 let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3);
-                let salt = self.integers_to_bytevec(self.registers[2], stub2_gen);
+                let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
 
-                let iterations = self.store(self.deref(self.registers[3]));
+                let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
 
                 let iterations = match Number::try_from(iterations) {
                     Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(),
                     Ok(Number::Integer(n)) => match n.to_u64() {
                         Some(i) => i,
                         None => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     },
@@ -4870,7 +4854,7 @@ impl MachineState {
 
                     heap_loc_as_cell!(
                         iter_to_heap_list(
-                            &mut self.heap,
+                            &mut self.machine_st.heap,
                             bytes
                                 .iter()
                                 .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
@@ -4878,19 +4862,19 @@ impl MachineState {
                     )
                 };
 
-                unify!(self, self.registers[4], ints_list);
+                unify!(self.machine_st, self.machine_st.registers[4], ints_list);
             }
             &SystemClauseType::CryptoDataEncrypt => {
-                let encoding = cell_as_atom!(self.registers[3]);
+                let encoding = cell_as_atom!(self.machine_st.registers[3]);
 
-                let data = self.string_encoding_bytes(self.registers[1], encoding);
-                let aad = self.string_encoding_bytes(self.registers[2], encoding);
+                let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
+                let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
 
                 let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
-                let key = self.integers_to_bytevec(self.registers[4], stub2_gen);
+                let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
                 let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
-                let iv = self.integers_to_bytevec(self.registers[5], stub3_gen);
+                let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen);
 
                 let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
                 let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
@@ -4905,14 +4889,14 @@ impl MachineState {
                 ) {
                     Ok(d) => d,
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
 
                 let tag_list = heap_loc_as_cell!(
                     iter_to_heap_list(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         tag.as_ref()
                             .iter()
                             .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
@@ -4921,22 +4905,22 @@ impl MachineState {
 
                 let complete_string = {
                     let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
-                    put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl)
+                    put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
                 };
 
-                unify!(self, self.registers[6], tag_list);
-                unify!(self, self.registers[7], complete_string);
+                unify!(self.machine_st, self.machine_st.registers[6], tag_list);
+                unify!(self.machine_st, self.machine_st.registers[7], complete_string);
             }
             &SystemClauseType::CryptoDataDecrypt => {
-                let data = self.string_encoding_bytes(self.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.registers[5]);
+                let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+                let encoding = cell_as_atom!(self.machine_st.registers[5]);
 
-                let aad = self.string_encoding_bytes(self.registers[2], encoding);
+                let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
                 let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
 
-                let key = self.integers_to_bytevec(self.registers[3], stub1_gen);
+                let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
                 let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
-                let iv = self.integers_to_bytevec(self.registers[4], stub2_gen);
+                let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
                 let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
                 let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
@@ -4949,7 +4933,7 @@ impl MachineState {
                         match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
                             Ok(d) => d,
                             _ => {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                                 return Ok(());
                             }
                         };
@@ -4959,7 +4943,7 @@ impl MachineState {
                         atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) {
                             Ok(str) => str,
                             _ => {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                                 return Ok(());
                             }
                         },
@@ -4968,13 +4952,13 @@ impl MachineState {
                         }
                     };
 
-                    put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl)
+                    put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
                 };
 
-                unify!(self, self.registers[6], complete_string);
+                unify!(self.machine_st, self.machine_st.registers[6], complete_string);
             }
             &SystemClauseType::CryptoCurveScalarMult => {
-                let curve = cell_as_atom!(self.registers[1]);
+                let curve = cell_as_atom!(self.machine_st.registers[1]);
 
                 let curve_id = match curve {
                     atom!("secp112r1") => Nid::SECP112R1,
@@ -4984,7 +4968,7 @@ impl MachineState {
                     }
                 };
 
-                let scalar = self.store(self.deref(self.registers[2]));
+                let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
                 let scalar = match Number::try_from(scalar) {
                     Ok(Number::Fixnum(n)) => Integer::from(n.get_num()),
@@ -4995,7 +4979,7 @@ impl MachineState {
                 };
 
                 let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5);
-                let qbytes = self.integers_to_bytevec(self.registers[3], stub_gen);
+                let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
 
                 let mut bnctx = BigNumContext::new().unwrap();
                 let group = EcGroup::from_curve_name(curve_id).unwrap();
@@ -5013,40 +4997,40 @@ impl MachineState {
                     .ok();
 
                 let sx = put_complete_string(
-                    &mut self.heap,
+                    &mut self.machine_st.heap,
                     &rx.to_dec_str().unwrap(),
-                    &mut self.atom_tbl,
+                    &mut self.machine_st.atom_tbl,
                 );
 
                 let sy = put_complete_string(
-                    &mut self.heap,
+                    &mut self.machine_st.heap,
                     &ry.to_dec_str().unwrap(),
-                    &mut self.atom_tbl,
+                    &mut self.machine_st.atom_tbl,
                 );
 
-                unify!(self, self.registers[4], sx);
-                unify!(self, self.registers[5], sy);
+                unify!(self.machine_st, self.machine_st.registers[4], sx);
+                unify!(self.machine_st, self.machine_st.registers[5], sy);
             }
             &SystemClauseType::Ed25519NewKeyPair => {
                 let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
                 let complete_string = {
                     let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
                     put_complete_string(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         &buffer,
-                        &mut self.atom_tbl,
+                        &mut self.machine_st.atom_tbl,
                     )
                 };
 
-                unify!(self, self.registers[1], complete_string)
+                unify!(self.machine_st, self.machine_st.registers[1], complete_string)
             }
             &SystemClauseType::Ed25519KeyPairPublicKey => {
-                let bytes = self.string_encoding_bytes(self.registers[1], atom!("octet"));
+                let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
 
                 let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
                     Ok(kp) => kp,
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
@@ -5057,23 +5041,23 @@ impl MachineState {
                     );
 
                     put_complete_string(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         &buffer,
-                        &mut self.atom_tbl,
+                        &mut self.machine_st.atom_tbl,
                     )
                 };
 
-                unify!(self, self.registers[2], complete_string);
+                unify!(self.machine_st, self.machine_st.registers[2], complete_string);
             }
             &SystemClauseType::Ed25519Sign => {
-                let key = self.string_encoding_bytes(self.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.registers[3]);
-                let data = self.string_encoding_bytes(self.registers[2], encoding);
+                let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+                let encoding = cell_as_atom!(self.machine_st.registers[3]);
+                let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
 
                 let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
                     Ok(kp) => kp,
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
@@ -5082,134 +5066,133 @@ impl MachineState {
 
                 let sig_list = heap_loc_as_cell!(
                     iter_to_heap_list(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         sig.as_ref()
                             .iter()
                             .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
                     )
                 );
 
-                unify!(self, self.registers[4], sig_list);
+                unify!(self.machine_st, self.machine_st.registers[4], sig_list);
             }
             &SystemClauseType::Ed25519Verify => {
-                let key = self.string_encoding_bytes(self.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.registers[3]);
-                let data = self.string_encoding_bytes(self.registers[2], encoding);
+                let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+                let encoding = cell_as_atom!(self.machine_st.registers[3]);
+                let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
                 let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
-                let signature = self.integers_to_bytevec(self.registers[4], stub_gen);
+                let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
 
                 let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
 
                 match peer_public_key.verify(&data, &signature) {
                     Ok(_) => {}
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 }
             }
             &SystemClauseType::Curve25519ScalarMult => {
                 let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
-                let scalar_bytes = self.integers_to_bytevec(self.registers[1], stub1_gen);
+                let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
                 let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
 
                 let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
-                let point_bytes = self.integers_to_bytevec(self.registers[2], stub2_gen);
+                let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
                 let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
 
                 let result = scalarmult(&scalar, &point).unwrap();
 
                 let string = String::from_iter(result[..].iter().map(|b| *b as char));
-                let cstr = put_complete_string(&mut self.heap, &string, &mut self.atom_tbl);
+                let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl);
 
-                unify!(self, self.registers[3], cstr);
+                unify!(self.machine_st, self.machine_st.registers[3], cstr);
             }
             &SystemClauseType::FirstNonOctet => {
-                let addr = self.store(self.deref(self.registers[1]));
+                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                if let Some(string) = self.value_to_str_like(addr) {
+                if let Some(string) = self.machine_st.value_to_str_like(addr) {
                     for c in string.as_str().chars() {
                         if c as u32 > 255 {
-                            let non_octet = self.atom_tbl.build_with(&c.to_string());
-                            self.unify_atom(non_octet, self.registers[2]);
-                            return return_from_clause!(self.last_call, self);
+                            let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string());
+                            self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]);
+                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
                         }
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
                 return Ok(());
             }
             &SystemClauseType::LoadHTML => {
-                if let Some(string) = self.value_to_str_like(self.registers[1]) {
-                    let doc = select::document::Document::from_read(string.as_str().as_bytes())
-                        .unwrap();
+                if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+                    let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap();
+                    let result = self.html_node_to_term(doc.nth(0).unwrap());
 
-                    let result = self.html_node_to_term(indices, doc.nth(0).unwrap());
-                    unify!(self, self.registers[2], result);
+                    unify!(self.machine_st, self.machine_st.registers[2], result);
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::LoadXML => {
-                if let Some(string) = self.value_to_str_like(self.registers[1]) {
+                if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match roxmltree::Document::parse(string.as_str()) {
                         Ok(doc) => {
-                            let result = self.xml_node_to_term(indices, doc.root_element());
-                            unify!(self, self.registers[2], result);
+                            let result = self.xml_node_to_term(doc.root_element());
+                            unify!(self.machine_st, self.machine_st.registers[2], result);
                         }
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::GetEnv => {
-                if let Some(key) = self.value_to_str_like(self.registers[1]) {
+                if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
                     match env::var(key.as_str()) {
                         Ok(value) => {
                             let cstr = put_complete_string(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 &value,
-                                &mut self.atom_tbl,
+                                &mut self.machine_st.atom_tbl,
                             );
 
-                            unify!(self, self.registers[2], cstr);
+                            unify!(self.machine_st, self.machine_st.registers[2], cstr);
                         }
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
-                    self.fail = true;
+                    self.machine_st.fail = true;
                     return Ok(());
                 }
             }
             &SystemClauseType::SetEnv => {
-                let key = self.value_to_str_like(self.registers[1]).unwrap();
-                let value = self.value_to_str_like(self.registers[2]).unwrap();
+                let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
+                let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
 
                 env::set_var(key.as_str(), value.as_str());
             }
             &SystemClauseType::UnsetEnv => {
-                let key = self.value_to_str_like(self.registers[1]).unwrap();
+                let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
                 env::remove_var(key.as_str());
             }
             &SystemClauseType::PID => {
                 let pid = process::id();
 
-                match fixnum!(Number, pid as i64, &mut self.arena) {
+                match fixnum!(Number, pid as i64, &mut self.machine_st.arena) {
                     Number::Fixnum(pid) => {
-                        self.unify_fixnum(pid, self.registers[1]);
+                        self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]);
                     }
                     Number::Integer(pid) => {
-                        self.unify_big_int(pid, self.registers[1]);
+                        self.machine_st.unify_big_int(pid, self.machine_st.registers[1]);
                     }
                     _ => {
                         unreachable!();
@@ -5241,7 +5224,7 @@ impl MachineState {
                     }
                 }
 
-                let command = self.value_to_str_like(self.store(self.deref(self.registers[1]))).unwrap();
+                let command = self.machine_st.value_to_str_like(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))).unwrap();
 
                 match env::var("SHELL") {
                     Ok(value) => {
@@ -5249,7 +5232,7 @@ impl MachineState {
                             .arg("-c")
                             .arg(command.as_str())
                             .status();
-                        command_result(self, command);
+                        command_result(&mut self.machine_st, command);
                     }
                     _ => {
                         match env::var("COMSPEC") {
@@ -5258,18 +5241,18 @@ impl MachineState {
                                     .arg("/C")
                                     .arg(command.as_str())
                                     .status();
-                                command_result(self, command);
+                                command_result(&mut self.machine_st, command);
                             }
                             _ => {
-                                self.fail = true;
+                                self.machine_st.fail = true;
                             }
                         }
                     }
                 };
             }
             &SystemClauseType::CharsBase64 => {
-                let padding = cell_as_atom!(self.registers[3]);
-                let charset = cell_as_atom!(self.registers[4]);
+                let padding = cell_as_atom!(self.machine_st.registers[3]);
+                let charset = cell_as_atom!(self.machine_st.registers[4]);
 
                 let config = if padding == atom!("true") {
                     if charset == atom!("standard") {
@@ -5285,38 +5268,38 @@ impl MachineState {
                     }
                 };
 
-                if self.store(self.deref(self.registers[1])).is_var() {
-                    let b64 = self.value_to_str_like(self.registers[2]).unwrap();
+                if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() {
+                    let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
                     let bytes = base64::decode_config(b64.as_str(), config);
 
                     match bytes {
                         Ok(bs) => {
                             let string = String::from_iter(bs.iter().map(|b| *b as char));
                             let cstr = put_complete_string(
-                                &mut self.heap,
+                                &mut self.machine_st.heap,
                                 &string,
-                                &mut self.atom_tbl,
+                                &mut self.machine_st.atom_tbl,
                             );
 
-                            unify!(self, self.registers[1], cstr);
+                            unify!(self.machine_st, self.machine_st.registers[1], cstr);
                         }
                         _ => {
-                            self.fail = true;
+                            self.machine_st.fail = true;
                             return Ok(());
                         }
                     }
                 } else {
                     let mut bytes = vec![];
-                    for c in self.value_to_str_like(self.registers[1]).unwrap().as_str().chars() {
+                    for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() {
                         if c as u32 > 255 {
                             let stub = functor_stub(atom!("chars_base64"), 3);
 
-                            let err = self.type_error(
+                            let err = self.machine_st.type_error(
                                 ValidType::Byte,
                                 char_as_cell!(c),
                             );
 
-                            return Err(self.error_form(err, stub));
+                            return Err(self.machine_st.error_form(err, stub));
                         }
 
                         bytes.push(c as u8);
@@ -5324,23 +5307,23 @@ impl MachineState {
 
                     let b64 = base64::encode_config(bytes, config);
                     let cstr = put_complete_string(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         &b64,
-                        &mut self.atom_tbl,
+                        &mut self.machine_st.atom_tbl,
                     );
 
-                    unify!(self, self.registers[2], cstr);
+                    unify!(self.machine_st, self.machine_st.registers[2], cstr);
                 }
             }
             &SystemClauseType::LoadLibraryAsStream => {
-                let library_name = cell_as_atom!(self.store(self.deref(self.registers[1])));
+                let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
 
                 use crate::machine::LIBRARIES;
 
                 match LIBRARIES.borrow().get(library_name.as_str()) {
                     Some(library) => {
-                        let lib_stream = Stream::from_static_string(library, &mut self.arena);
-                        unify!(self, stream_as_cell!(lib_stream), self.registers[2]);
+                        let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena);
+                        unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]);
 
                         let mut path_buf = machine::current_dir();
 
@@ -5348,65 +5331,65 @@ impl MachineState {
                         path_buf.push(library_name.as_str());
 
                         let library_path_str = path_buf.to_str().unwrap();
-                        let library_path = self.atom_tbl.build_with(library_path_str);
+                        let library_path = self.machine_st.atom_tbl.build_with(library_path_str);
 
-                        self.unify_atom(library_path, self.registers[3]);
+                        self.machine_st.unify_atom(library_path, self.machine_st.registers[3]);
                     }
                     None => {
                         let stub = functor_stub(atom!("load"), 1);
-                        let err = self.existence_error(
+                        let err = self.machine_st.existence_error(
                             ExistenceError::ModuleSource(ModuleSource::Library(library_name))
                         );
 
-                        return Err(self.error_form(err, stub));
+                        return Err(self.machine_st.error_form(err, stub));
                     }
                 }
             }
             &SystemClauseType::DevourWhitespace => {
-                let stream = self.get_stream_or_alias(
-                    self.registers[1],
-                    &indices.stream_aliases,
+                let stream = self.machine_st.get_stream_or_alias(
+                    self.machine_st.registers[1],
+                    &self.indices.stream_aliases,
                     atom!("$devour_whitespace"),
                     1,
                 )?;
 
-                match self.devour_whitespace(stream) {
+                match self.machine_st.devour_whitespace(stream) {
                     Ok(false) => { // not at EOF.
                     }
                     _ => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 }
             }
             &SystemClauseType::IsSTOEnabled => {
-                if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
-                    self.unify_atom(atom!("true"), self.registers[1]);
-                } else if self.unify_fn as usize
+                if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
+                    self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]);
+                } else if self.machine_st.unify_fn as usize
                     == MachineState::unify_with_occurs_check_with_error as usize
                 {
-                    self.unify_atom(atom!("error"), self.registers[1]);
+                    self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]);
                 } else {
-                    self.unify_atom(atom!("false"), self.registers[1]);
+                    self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]);
                 }
             }
             &SystemClauseType::SetSTOAsUnify => {
-                self.unify_fn = MachineState::unify_with_occurs_check;
-                self.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+                self.machine_st.unify_fn = MachineState::unify_with_occurs_check;
+                self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper;
             }
             &SystemClauseType::SetNSTOAsUnify => {
-                self.unify_fn = MachineState::unify;
-                self.bind_fn = MachineState::bind;
+                self.machine_st.unify_fn = MachineState::unify;
+                self.machine_st.bind_fn = MachineState::bind;
             }
             &SystemClauseType::SetSTOWithErrorAsUnify => {
-                self.unify_fn = MachineState::unify_with_occurs_check_with_error;
-                self.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+                self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error;
+                self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
             }
             &SystemClauseType::HomeDirectory => {
                 let path = match dirs_next::home_dir() {
                     Some(path) => path,
                     None => {
-                        self.fail = true;
+                        self.machine_st.fail = true;
                         return Ok(());
                     }
                 };
@@ -5414,40 +5397,40 @@ impl MachineState {
                 if path.is_dir() {
                     if let Some(path) = path.to_str() {
                         let path_string = put_complete_string(
-                            &mut self.heap,
+                            &mut self.machine_st.heap,
                             path,
-                            &mut self.atom_tbl,
+                            &mut self.machine_st.atom_tbl,
                         );
 
-                        unify!(self, self.registers[1], path_string);
-                        return return_from_clause!(self.last_call, self);
+                        unify!(self.machine_st, self.machine_st.registers[1], path_string);
+                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
                     }
                 }
 
-                self.fail = true;
+                self.machine_st.fail = true;
             }
             &SystemClauseType::DebugHook => {
-                self.fail = false;
+                self.machine_st.fail = false;
             }
             &SystemClauseType::PopCount => {
-                let number = self.store(self.deref(self.registers[1]));
+                let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
                 let pop_count = integer_as_cell!(match Number::try_from(number) {
                     Ok(Number::Fixnum(n)) => {
                         Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64))
                     }
                     Ok(Number::Integer(n)) => {
-                        Number::arena_from(n.count_ones().unwrap(), &mut self.arena)
+                        Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena)
                     }
                     _ => {
                         unreachable!()
                     }
                 });
 
-                unify!(self, self.registers[2], pop_count);
+                unify!(self.machine_st, self.machine_st.registers[2], pop_count);
             }
         };
 
-        return_from_clause!(self.last_call, self)
+        return_from_clause!(self.machine_st.last_call, self.machine_st)
     }
 
     pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom {
@@ -5466,11 +5449,11 @@ impl MachineState {
         fstr.push_str("finis].");
         let s = datetime.format(&fstr).to_string();
 
-        self.atom_tbl.build_with(&s)
+        self.machine_st.atom_tbl.build_with(&s)
     }
 
     pub(super) fn string_encoding_bytes(&mut self, data_arg: HeapCellValue, encoding: Atom) -> Vec<u8> {
-        let data = self.value_to_str_like(data_arg).unwrap();
+        let data = self.machine_st.value_to_str_like(data_arg).unwrap();
 
         match encoding {
             atom!("utf8") => data.as_str().bytes().collect(),
@@ -5481,114 +5464,106 @@ impl MachineState {
         }
     }
 
-    pub(super) fn xml_node_to_term(
-        &mut self,
-        indices: &mut IndexStore,
-        node: roxmltree::Node,
-    ) -> HeapCellValue {
+    pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue {
         if node.is_text() {
             put_complete_string(
-                &mut self.heap,
+                &mut self.machine_st.heap,
                 node.text().unwrap(),
-                &mut self.atom_tbl,
+                &mut self.machine_st.atom_tbl,
             )
         } else {
             let mut avec = Vec::new();
 
             for attr in node.attributes() {
-                let name = self.atom_tbl.build_with(attr.name());
+                let name = self.machine_st.atom_tbl.build_with(attr.name());
                 let value = put_complete_string(
-                    &mut self.heap,
+                    &mut self.machine_st.heap,
                     &attr.value(),
-                    &mut self.atom_tbl,
+                    &mut self.machine_st.atom_tbl,
                 );
 
-                avec.push(heap_loc_as_cell!(self.heap.len()));
+                avec.push(heap_loc_as_cell!(self.machine_st.heap.len()));
 
-                self.heap.push(atom_as_cell!(atom!("="), 2));
-                self.heap.push(atom_as_cell!(name));
-                self.heap.push(value);
+                self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+                self.machine_st.heap.push(atom_as_cell!(name));
+                self.machine_st.heap.push(value);
             }
 
             let attrs = heap_loc_as_cell!(
-                iter_to_heap_list(&mut self.heap, avec.into_iter())
+                iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter())
             );
 
             let mut cvec = Vec::new();
 
             for child in node.children() {
-                cvec.push(self.xml_node_to_term(indices, child));
+                cvec.push(self.xml_node_to_term(child));
             }
 
             let children = heap_loc_as_cell!(
-                iter_to_heap_list(&mut self.heap, cvec.into_iter())
+                iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter())
             );
 
-            let tag = self.atom_tbl.build_with(node.tag_name().name());
+            let tag = self.machine_st.atom_tbl.build_with(node.tag_name().name());
 
-            let result = heap_loc_as_cell!(self.heap.len());
+            let result = heap_loc_as_cell!(self.machine_st.heap.len());
 
-            self.heap.push(atom_as_cell!(atom!("element"), 3));
-            self.heap.push(atom_as_cell!(tag));
-            self.heap.push(attrs);
-            self.heap.push(children);
+            self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3));
+            self.machine_st.heap.push(atom_as_cell!(tag));
+            self.machine_st.heap.push(attrs);
+            self.machine_st.heap.push(children);
 
             result
         }
     }
 
-    pub(super) fn html_node_to_term(
-        &mut self,
-        indices: &mut IndexStore,
-        node: select::node::Node,
-    ) -> HeapCellValue {
+    pub(super) fn html_node_to_term(&mut self, node: select::node::Node) -> HeapCellValue {
         match node.name() {
             None => {
                 put_complete_string(
-                    &mut self.heap,
+                    &mut self.machine_st.heap,
                     &node.text(),
-                    &mut self.atom_tbl,
+                    &mut self.machine_st.atom_tbl,
                 )
             }
             Some(name) => {
                 let mut avec = Vec::new();
 
                 for attr in node.attrs() {
-                    let name = self.atom_tbl.build_with(attr.0);
+                    let name = self.machine_st.atom_tbl.build_with(attr.0);
                     let value = put_complete_string(
-                        &mut self.heap,
+                        &mut self.machine_st.heap,
                         &attr.1,
-                        &mut self.atom_tbl,
+                        &mut self.machine_st.atom_tbl,
                     );
 
-                    avec.push(heap_loc_as_cell!(self.heap.len()));
+                    avec.push(heap_loc_as_cell!(self.machine_st.heap.len()));
 
-                    self.heap.push(atom_as_cell!(atom!("="), 2));
-                    self.heap.push(atom_as_cell!(name));
-                    self.heap.push(value);
+                    self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+                    self.machine_st.heap.push(atom_as_cell!(name));
+                    self.machine_st.heap.push(value);
                 }
 
                 let attrs = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.heap, avec.into_iter())
+                    iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter())
                 );
 
                 let mut cvec = Vec::new();
 
                 for child in node.children() {
-                    cvec.push(self.html_node_to_term(indices, child));
+                    cvec.push(self.html_node_to_term(child));
                 }
 
                 let children = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.heap, cvec.into_iter())
+                    iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter())
                 );
 
-                let tag = self.atom_tbl.build_with(name);
-                let result = heap_loc_as_cell!(self.heap.len());
+                let tag = self.machine_st.atom_tbl.build_with(name);
+                let result = heap_loc_as_cell!(self.machine_st.heap.len());
 
-                self.heap.push(atom_as_cell!(atom!("element"), 3));
-                self.heap.push(atom_as_cell!(tag));
-                self.heap.push(attrs);
-                self.heap.push(children);
+                self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3));
+                self.machine_st.heap.push(atom_as_cell!(tag));
+                self.machine_st.heap.push(attrs);
+                self.machine_st.heap.push(children);
 
                 result
             }
index b248080dca9b9c976186a53c80979017b98ff940..90fed1109d055f3c053288285d0c4e1ab351c21a 100644 (file)
@@ -778,7 +778,7 @@ macro_rules! unify {
 macro_rules! unify_fn {
     ($machine_st:expr, $($value:expr),*) => {{
         $($machine_st.pdl.push($value);)*
-        ($machine_st.unify_fn)($machine_st)
+        ($machine_st.unify_fn)(&mut $machine_st)
     }};
 }