]> Repositorios git - scryer-prolog.git/commitdiff
revise InstallVerifyAttrs to remove need for predicate scanning (#3175)
authorMark Thom <[email protected]>
Wed, 26 Nov 2025 07:17:22 +0000 (23:17 -0800)
committerMark Thom <[email protected]>
Wed, 26 Nov 2025 07:17:51 +0000 (23:17 -0800)
build/instructions_template.rs
src/machine/attributed_variables.rs
src/machine/dispatch.rs
src/machine/mod.rs
src/machine/system_calls.rs

index 674892d3c115997be020eaa9e0dc77b3b186fa77..29f3d715a98f61dde182d4332a2e0fcc91e95ee4 100644 (file)
@@ -834,12 +834,9 @@ enum InstructionTemplate {
     // break from loop instruction.
     #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))]
     BreakFromDispatchLoop,
-    // swap the verify attr interrupt instruction with the next control instruction.
-    #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
-    InstallVerifyAttr,
-    // call verify_attrs.
-    #[strum_discriminants(strum(props(Arity = "1", Name = "verify_attr_interrupt")))]
-    VerifyAttrInterrupt(usize),
+    // run verify_attr, eventually.
+    #[strum_discriminants(strum(props(Arity = "0", Name = "run_verify_attr")))]
+    RunVerifyAttr,
     // procedures
     CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
                                                       // arity,
@@ -1168,33 +1165,6 @@ fn generate_instruction_preface() -> TokenStream {
         pub type CodeDeque = VecDeque<Instruction>;
 
         impl Instruction {
-            #[inline]
-            pub fn registers(&self) -> Vec<RegType> {
-                match *self {
-                    Instruction::GetConstant(_, _, r) => vec![r],
-                    Instruction::GetList(_, r) => vec![r],
-                    Instruction::GetPartialString(_, _, r) => vec![r],
-                    Instruction::GetStructure(_, _, _, r) => vec![r],
-                    Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
-                    Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
-                    Instruction::UnifyLocalValue(r) => vec![r],
-                    Instruction::UnifyVariable(r) => vec![r],
-                    Instruction::PutConstant(_, _, r) => vec![r],
-                    Instruction::PutList(_, r) => vec![r],
-                    Instruction::PutPartialString(_, _, r) => vec![r],
-                    Instruction::PutStructure(_, _, r) => vec![r],
-                    Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
-                    Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
-                    Instruction::SetLocalValue(r) => vec![r],
-                    Instruction::SetVariable(r) => vec![r],
-                    Instruction::SetValue(r) => vec![r],
-                    Instruction::GetLevel(r) => vec![r],
-                    Instruction::GetPrevLevel(r) => vec![r],
-                    Instruction::GetCutPoint(r) => vec![r],
-                    _ => vec![],
-                }
-            }
-
             #[inline]
             pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
                 match self {
@@ -1211,38 +1181,6 @@ fn generate_instruction_preface() -> TokenStream {
                 }
             }
 
-            #[inline]
-            pub fn is_head_instr(&self) -> bool {
-                matches!(self,
-                    Instruction::Deallocate |
-                    Instruction::GetConstant(..) |
-                    Instruction::GetList(..) |
-                    Instruction::GetPartialString(..) |
-                    Instruction::GetStructure(..) |
-                    Instruction::GetValue(..) |
-                    Instruction::UnifyConstant(..) |
-                    Instruction::UnifyLocalValue(..) |
-                    Instruction::UnifyVariable(..) |
-                    Instruction::UnifyValue(..) |
-                    Instruction::UnifyVoid(..) |
-                    Instruction::GetVariable(..) |
-                    Instruction::PutConstant(..) |
-                    Instruction::PutList(..) |
-                    Instruction::PutPartialString(..) |
-                    Instruction::PutStructure(..) |
-                    Instruction::PutUnsafeValue(..) |
-                    Instruction::PutValue(..) |
-                    Instruction::PutVariable(..) |
-                    Instruction::SetConstant(..) |
-                    Instruction::SetLocalValue(..) |
-                    Instruction::SetVariable(..) |
-                    Instruction::SetValue(..) |
-                    Instruction::SetVoid(..) |
-                    Instruction::GetLevel(..) |
-                    Instruction::GetPrevLevel(..) |
-                    Instruction::GetCutPoint(..))
-            }
-
             pub fn enqueue_functors(
                 &self,
                 arena: &mut Arena,
@@ -1278,11 +1216,8 @@ fn generate_instruction_preface() -> TokenStream {
 
             fn to_functor(&self, arena: &mut Arena) -> MachineStub {
                 match self {
-                    &Instruction::InstallVerifyAttr => {
-                        functor!(atom!("install_verify_attr"))
-                    }
-                    &Instruction::VerifyAttrInterrupt(arity) => {
-                        functor!(atom!("verify_attr_interrupt"), [fixnum(arity)])
+                    &Instruction::RunVerifyAttr => {
+                        functor!(atom!("run_verify_attr"))
                     }
                     &Instruction::DynamicElse(birth, death, next_or_fail) => {
                         match (death, next_or_fail) {
index 4aaf45ee815537de271aef670dcbc8a348f2140d..2cfdf6005f6f7f9310e9069847e8a549ad2178a9 100644 (file)
@@ -41,13 +41,13 @@ impl MachineState {
     pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) {
         if self.attr_var_init.bindings.is_empty() {
             // save self.p and self.cp and ensure that the next
-            // instruction is InstallVerifyAttrInterrupt.
+            // instruction is RunVerifyAttrInterrupt.
 
             self.attr_var_init.p = self.p;
             self.attr_var_init.cp = self.cp;
 
-            self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1;
-            self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
+            self.p = VERIFY_ATTR_INTERRUPT_LOC - 1;
+            self.cp = VERIFY_ATTR_INTERRUPT_LOC;
         }
 
         debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
index fb1c5d12fc82248c62831a9f0a1912bdc32b8350..a7a46d0e0559c1182d93dfb7318434abd36fdcbe 100644 (file)
@@ -12,8 +12,8 @@ use fxhash::FxBuildHasher;
 
 macro_rules! step_or_fail {
     ($self:expr, $step_e:expr) => {
-        if $self.machine_st.fail {
-            $self.machine_st.backtrack();
+        if $self.fail {
+            $self.backtrack();
         } else {
             $step_e;
         }
@@ -21,7 +21,7 @@ macro_rules! step_or_fail {
 }
 
 macro_rules! try_or_throw {
-    ($s:expr, $e:expr) => {{
+    ($s:expr, $e:expr, $control:expr) => {{
         match $e {
             Ok(val) => val,
             Err(msg) => {
@@ -30,17 +30,17 @@ macro_rules! try_or_throw {
                 }
 
                 $s.backtrack();
-                continue;
+                $control;
             }
         }
     }};
 }
 
 macro_rules! backtrack_on_resource_error {
-    ($machine_st:expr, $val:expr) => {
+    ($machine_st:expr, $val:expr, $control_expr:expr) => {
         step_or_resource_error!($machine_st, $val, {
             $machine_st.backtrack();
-            continue;
+            $control_expr;
         })
     };
 }
@@ -62,17 +62,17 @@ macro_rules! try_or_throw_gen {
                 let e = msg_fn($s);
                 $s.throw_exception(e);
                 $s.backtrack();
-                continue;
+                return;
             }
         }
     }};
 }
 
 macro_rules! push_cell {
-    ($machine_st:expr, $cell:expr) => {{
+    ($machine_st:expr, $cell:expr, $control_expr:expr) => {{
         step_or_resource_error!($machine_st, $machine_st.heap.push_cell($cell), {
             $machine_st.backtrack();
-            continue;
+            $control_expr;
         })
     }};
 }
@@ -194,7 +194,6 @@ impl MachineState {
         );
 
         let target_addr = self.registers[2];
-
         unify_fn!(*self, target_addr, heap_addr);
         Ok(())
     }
@@ -296,818 +295,1523 @@ impl MachineState {
             }
         )
     }
-}
 
-impl Machine {
-    pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
-        loop {
-            match self.code[p] {
-                Instruction::DynamicElse(birth, death, NextOrFail::Next(i)) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, i));
-                    } else if i > 0 {
-                        p += i;
-                    } else {
-                        return None;
-                    }
-                }
-                Instruction::DynamicElse(birth, death, NextOrFail::Fail(_)) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, 0));
-                    } else {
-                        return None;
-                    }
-                }
-                Instruction::DynamicInternalElse(birth, death, NextOrFail::Next(i)) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, i));
-                    } else if i > 0 {
-                        p += i;
-                    } else {
-                        return None;
-                    }
-                }
-                Instruction::DynamicInternalElse(birth, death, NextOrFail::Fail(_)) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, 0));
-                    } else {
-                        return None;
-                    }
-                }
-                Instruction::RevJmpBy(i) => {
-                    p -= i;
-                }
-                _ => {
-                    unreachable!();
+    fn check_for_interrupt(&mut self) {
+        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();
+                    self.backtrack();
+
+                    // We have extracted controll over the Tokio runtime to the calling context for enabling library use case
+                    // (see https://github.com/mthom/scryer-prolog/pull/1880)
+                    // So we only have access to a runtime handle in here and can't shut it down.
+                    // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880
+                    // was not merged, I'm only deactivating it for now.
+
+                    //#[cfg(not(target_arch = "wasm32"))]
+                    //let runtime = tokio::runtime::Runtime::new().unwrap();
+                    //#[cfg(target_arch = "wasm32")]
+                    //let runtime = tokio::runtime::Builder::new_current_thread()
+                    //    .enable_all()
+                    //    .build()
+                    //    .unwrap();
+
+                    //let old_runtime = tokio::runtime::Handle::current();
+                    //old_runtime.shutdown_background();
                 }
             }
+            Err(_) => unreachable!(),
         }
     }
 
-    pub(super) fn find_living_dynamic(
-        &self,
-        oi: u32,
-        mut ii: u32,
-    ) -> Option<(usize, u32, u32, bool)> {
-        let p = self.machine_st.p;
+    #[inline(always)]
+    fn add_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let stub_gen = || functor_stub(atom!("is"), 2);
 
-        let indexed_choice_instrs = match &self.code[p] {
-            Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
-                IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
-                    indexed_choice_instrs
-                }
-                _ => unreachable!(),
-            },
-            _ => unreachable!(),
-        };
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-        loop {
-            match &indexed_choice_instrs.get(ii as usize) {
-                Some(&offset) => match &self.code[p + offset - 1] {
-                    &Instruction::DynamicInternalElse(birth, death, next_or_fail) => {
-                        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;
-                        }
-                    }
-                    _ => unreachable!(),
-                },
-                None => return None,
-            }
-        }
+        let value = try_or_throw_gen!(
+            self,
+            try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen)
+        );
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
     }
 
     #[inline(always)]
-    fn execute_switch_on_term(&mut self) {
-        #[inline(always)]
-        fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
-            if let Instruction::DynamicInternalElse(..) = machine.code[p] {
-                machine.machine_st.dynamic_mode = FirstOrNext::First;
-                return true;
-            }
+    fn sub_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let stub_gen = || functor_stub(atom!("is"), 2);
 
-            if let Instruction::DynamicInternalElse(birth, death, _) = machine.code[p - 1] {
-                return birth < machine.machine_st.cc
-                    && Death::Finite(machine.machine_st.cc) <= death;
-            }
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-            true
-        }
+        let value = try_or_throw_gen!(
+            self,
+            try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen)
+        );
 
-        let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap();
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-        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!()
-            }
-        };
+    #[inline(always)]
+    fn mul_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let stub_gen = || functor_stub(atom!("is"), 2);
 
-        loop {
-            match &indexing_lines[index] {
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
-                    let offset = self
-                        .machine_st
-                        .select_switch_on_term_index(addr, v, c, l, s);
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                    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;
+        let value = try_or_throw_gen!(
+            self,
+            try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen)
+        );
 
-                            if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                self.machine_st.fail = true;
-                            } else {
-                                self.machine_st.p += o;
-                            }
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.machine_st.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
-                    // let lit = self.machine_st.constant_to_literal(addr);
+    #[inline(always)]
+    fn max_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                    let offset = match hm.get(&addr) {
-                        Some(offset) => *offset,
-                        _ => IndexingCodePtr::Fail,
-                    };
+        let value = try_or_throw_gen!(self, max(n1, n2));
 
-                    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;
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                            if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                self.machine_st.fail = true;
-                            } else {
-                                self.machine_st.p += o;
-                            }
+    #[inline(always)]
+    fn min_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.machine_st.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
-                    let offset = self.machine_st.select_switch_on_structure_index(addr, hm);
+        let value = try_or_throw_gen!(self, min(n1, n2));
 
-                    match offset {
-                        IndexingCodePtr::Fail => {
-                            self.machine_st.fail = true;
-                            break;
-                        }
-                        IndexingCodePtr::DynamicExternal(o) => {
-                            let p = self.machine_st.p;
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                            if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                self.machine_st.fail = true;
-                            } else {
-                                self.machine_st.p += o;
-                            }
+    #[inline(always)]
+    fn int_pow_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                            break;
-                        }
-                        IndexingCodePtr::External(o) => {
-                            self.machine_st.p += o;
-                            break;
-                        }
-                        IndexingCodePtr::Internal(o) => {
-                            index += o;
-                        }
-                    }
-                }
-                &IndexingLine::IndexedChoice(_) => {
-                    self.machine_st.oip = index as u32;
-                    self.machine_st.iip = 0;
+        let value = try_or_throw_gen!(self, int_pow(n1, n2, &mut self.arena));
 
-                    break;
-                }
-                &IndexingLine::DynamicIndexedChoice(_) => {
-                    self.machine_st.dynamic_mode = FirstOrNext::First;
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                    self.machine_st.oip = index as u32;
-                    self.machine_st.iip = 0;
+    #[inline(always)]
+    fn gcd_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                    break;
-                }
-            }
-        }
+        let value = try_or_throw_gen!(self, gcd(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
     }
 
     #[inline(always)]
-    pub(super) fn dispatch_loop(&mut self) -> std::process::ExitCode {
-        'outer: loop {
-            for _ in 0..INSTRUCTIONS_PER_INTERRUPT_POLL {
-                match &self.code[self.machine_st.p] {
-                    &Instruction::BreakFromDispatchLoop => {
-                        break 'outer;
-                    }
-                    &Instruction::InstallVerifyAttr => {
-                        self.machine_st.p = self.machine_st.attr_var_init.p;
+    fn pow_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                        if self.code[self.machine_st.p].is_execute() {
-                            self.machine_st.p = self.machine_st.attr_var_init.cp;
-                        } else {
-                            self.machine_st.p += 1;
-                            self.machine_st.cp = self.machine_st.attr_var_init.cp;
-                        }
+        let value = try_or_throw_gen!(self, pow(n1, n2, atom!("**")));
 
-                        let p = self.machine_st.p;
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                        // Find the boundaries of the current predicate
-                        self.indices.code_dir.sort_by(|_, a, _, b| {
-                            let a = self.machine_st.arena.code_index_tbl.get_entry((*a).into());
-                            let b = self.machine_st.arena.code_index_tbl.get_entry((*b).into());
+    #[inline(always)]
+    fn rdiv_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
 
-                            a.cmp(&b)
-                        });
+        let r1 = try_or_throw!(self, self.get_rational(a1, stub_gen), return);
+        let r2 = try_or_throw!(self, self.get_rational(a2, stub_gen), return);
 
-                        let predicate_idx = self
-                            .indices
-                            .code_dir
-                            .binary_search_by_key(&p, |_, x| -> usize {
-                                self.machine_st
-                                    .arena
-                                    .code_index_tbl
-                                    .get_entry((*x).into())
-                                    .p() as usize
-                            })
-                            .unwrap_or_else(|x| x - 1);
-
-                        let current_pred_start = self
-                            .indices
-                            .code_dir
-                            .get_index(predicate_idx)
-                            .map(|idx| {
-                                self.machine_st
-                                    .arena
-                                    .code_index_tbl
-                                    .get_entry((*idx.1).into())
-                                    .p() as usize
-                            })
-                            .unwrap();
+        let value = Number::Rational(arena_alloc!(
+            try_or_throw_gen!(self, rdiv(r1, r2)),
+            &mut self.arena
+        ));
 
-                        debug_assert!(current_pred_start <= p);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                        let current_pred_end = self
-                            .indices
-                            .code_dir
-                            .get_index(predicate_idx + 1)
-                            .map(|idx| {
-                                self.machine_st
-                                    .arena
-                                    .code_index_tbl
-                                    .get_entry((*idx.1).into())
-                                    .p() as usize
-                            })
-                            .unwrap_or(self.code.len());
-
-                        debug_assert!(current_pred_end >= p);
-                        debug_assert!(current_pred_end <= self.code.len());
-
-                        // Find point to insert the interrupt
-                        let p_interrupt = p + self.code[p..current_pred_end]
-                            .iter()
-                            .position(|x| !x.is_head_instr())
-                            .unwrap();
+    #[inline(always)]
+    fn int_floor_div_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                        // Scan registers of all instructions to find out how many to save
-                        let arity = self.code[current_pred_start..current_pred_end]
-                            .iter()
-                            .flat_map(Instruction::registers)
-                            .flat_map(|r| match r {
-                                RegType::Temp(t) => Some(t),
-                                _ => None,
-                            })
-                            .max()
-                            .unwrap_or(0);
-
-                        let instr = std::mem::replace(
-                            &mut self.code[p_interrupt],
-                            Instruction::VerifyAttrInterrupt(arity),
-                        );
+        let value = try_or_throw_gen!(self, int_floor_div(n1, n2, &mut self.arena));
 
-                        self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
-                        self.machine_st.attr_var_init.cp = p_interrupt;
-                    }
-                    &Instruction::VerifyAttrInterrupt(arity) => {
-                        self.run_verify_attr_interrupt(arity);
-                    }
-                    &Instruction::Add(ref a1, ref a2, t) => {
-                        let stub_gen = || functor_stub(atom!("is"), 2);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+    #[inline(always)]
+    fn idiv_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
+        let value = try_or_throw_gen!(self, idiv(n1, n2, &mut self.arena));
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::Sub(ref a1, ref a2, t) => {
-                        let stub_gen = || functor_stub(atom!("is"), 2);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
 
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+    #[inline(always)]
+    fn abs_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = abs(n1, &mut self.arena);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn sign_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n = try_or_throw!(self, self.get_number(a1), return);
+        let value = n.sign();
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn neg_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let value = neg(n1, &mut self.arena);
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn bitwise_complement_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let value = try_or_throw_gen!(self, bitwise_complement(n1, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn div_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+        let value = try_or_throw_gen!(self, div(n1, n2));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn shr_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, shr(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn shl_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, shl(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn xor_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, xor(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn and_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, and(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn or_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, or(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn mod_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, modulus(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn rem_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = try_or_throw_gen!(self, remainder(n1, n2, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn cos_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, cos(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn sin_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, sin(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn tan_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, tan(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn sqrt_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, sqrt(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn log_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, log(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn exp_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, exp(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn acos_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, acos(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn asin_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, asin(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn atan_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, atan(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn atan2_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        let n2 = try_or_throw!(self, self.get_number(a2), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, atan2(n1, n2))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn float_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, float(n1))));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn truncate_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = truncate(n1, &mut self.arena);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn round_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = try_or_throw_gen!(self, round(n1, &mut self.arena));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn ceiling_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = ceiling(n1, &mut self.arena);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn floor_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = floor(n1, &mut self.arena);
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn float_fractional_part_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
+            self,
+            float_fractional_part(n1)
+        )));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn float_integer_part_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+
+        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
+            self,
+            float_integer_part(n1)
+        )));
+
+        self.registers[t] = HeapCellValue::from((value, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn plus_instr(&mut self, a1: &ArithmeticTerm, t: usize) {
+        let n1 = try_or_throw!(self, self.get_number(a1), return);
+        self.registers[t] = HeapCellValue::from((n1, &mut self.arena));
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_level_instr(&mut self, r: RegType) {
+        let b0 = self.b0;
+        self[r] = fixnum_as_cell!(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint()
+        );
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_prev_level_instr(&mut self, r: RegType) {
+        let prev_b = self.stack.index_or_frame(self.b).prelude.b;
+
+        self[r] = fixnum_as_cell!(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint()
+        );
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_cut_point_instr(&mut self, r: RegType) {
+        self[r] = fixnum_as_cell!(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(self.b as i64) }.as_cutpoint()
+        );
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_constant_instr(&mut self, c: HeapCellValue, r: RegType) {
+        unify!(self, self[r], c);
+        step_or_fail!(self, self.p += 1);
+    }
+
+    #[inline(always)]
+    fn get_list_instr(&mut self, r: RegType) {
+        let deref_v = self.deref(self[r]);
+        let store_v = self.store(deref_v);
+
+        read_heap_cell!(store_v,
+            (HeapCellValueTag::PStrLoc, h) => {
+                self.s = HeapPtr::PStr(h);
+                self.s_offset = 0;
+                self.mode = MachineMode::Read;
+            }
+            (HeapCellValueTag::Str, s) => {
+                let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                    .get_name_and_arity();
+
+                if name == atom!(".") && arity == 2 {
+                    self.s = HeapPtr::HeapCell(s+1);
+                    self.s_offset = 0;
+                    self.mode = MachineMode::Read;
+                } else {
+                    self.backtrack();
+            return;
+                }
+            }
+            (HeapCellValueTag::Lis, l) => {
+                self.s = HeapPtr::HeapCell(l);
+                self.s_offset = 0;
+                self.mode = MachineMode::Read;
+            }
+            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                let h = self.heap.cell_len();
+                push_cell!(self, list_loc_as_cell!(h+1), return);
+                self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+                self.mode = MachineMode::Write;
+            }
+            _ => {
+                self.backtrack();
+                return;
+            }
+        );
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_partial_string_instr(&mut self, string: &String, r: RegType) {
+        self.heap[0] = self[r];
+
+        let mut h = 0;
+        let mut string_cursor = string.as_str();
+
+        if self.heap[0].is_stack_var() {
+            let cell = self.store(self.deref(self.heap[0]));
+
+            if let Some(r) = cell.as_var() {
+                let target_cell = backtrack_on_resource_error!(
+                    self,
+                    self.heap.allocate_pstr(string_cursor),
+                    return
+                );
+
+                self.bind(r, target_cell);
+                self.mode = MachineMode::Write;
+
+                debug_assert!(!self.fail);
+                self.p += 1;
+
+                return;
+            }
+
+            self.heap[0] = cell;
+        }
+
+        while let Some(c) = string_cursor.chars().next() {
+            read_heap_cell!(self.heap[h],
+            (HeapCellValueTag::PStrLoc, pstr_loc) => {
+                        let heap_slice = &self.heap.as_slice()[pstr_loc ..];
+
+                        match compare_pstr_slices(heap_slice, string_cursor.as_bytes()) {
+                            PStrSegmentCmpResult::Continue(v1, v2) => {
+                                // for v2, the value of a TailIndex mustn't ever be read
+                                // since string does not lie in the heap.
+                                match (v1, v2) {
+                                    (PStrContinuable::TailIndex(tail_idx), PStrContinuable::TailIndex(_)) => {
+                                        self.s = HeapPtr::HeapCell(tail_idx + cell_index!(pstr_loc));
+                                        self.s_offset = 0;
+                                        self.mode = MachineMode::Read;
+
+                                        break;
+                                    }
+                                    (PStrContinuable::TailIndex(tail_idx), PStrContinuable::PStrOffset(pos)) => {
+                                        h = tail_idx + cell_index!(pstr_loc);
+                                        string_cursor = &string_cursor[pos ..];
+                                    }
+                                    (PStrContinuable::PStrOffset(pos), PStrContinuable::TailIndex(_)) => {
+                                        self.s = HeapPtr::PStr(pstr_loc);
+                                        self.s_offset = pos;
+                                        self.mode = MachineMode::Read;
+
+                                        break;
+                                    }
+                                    _ => unreachable!(),
+                                }
+                            }
+                            _ => {
+                                self.fail = true;
+                                break;
+                            }
+                        }
+                    }
+                    (HeapCellValueTag::Lis, l) => {
+                        let cell = self.store(self.deref(self.heap[l]));
+
+                        if let Some(d) = cell.as_char() {
+                            if c != d {
+                                self.fail = true;
+                                break;
+                            }
+                        } else if let Some(r) = cell.as_var() {
+                            self.bind(r, char_as_cell!(c));
+                        } else {
+                            self.fail = true;
+                        }
+
+                        if self.fail {
+                            break;
+                        } else {
+                            h = l+1;
+                            string_cursor = &string_cursor[c.len_utf8() ..];
+
+                            if string_cursor.is_empty() {
+                                self.s = HeapPtr::HeapCell(h);
+                                self.s_offset = 0;
+                                self.mode = MachineMode::Read;
+                            }
+                        }
+                    }
+                    (HeapCellValueTag::Str, s) => {
+                        let cell = self.store(self.deref(self.heap[s+1]));
+
+                        if let Some(d) = cell.as_char() {
+                            if c != d {
+                                self.fail = true;
+                                break;
+                            }
+                        } else if let Some(r) = cell.as_var() {
+                            self.bind(r, char_as_cell!(c));
+                        } else {
+                            self.fail = true;
+                        }
+
+                        if self.fail {
+                            break;
+                        }
+
+                        h = s+2;
+                        string_cursor = &string_cursor[c.len_utf8() ..];
+
+                        if string_cursor.is_empty() {
+                            self.s = HeapPtr::HeapCell(h);
+                            self.s_offset = 0;
+                            self.mode = MachineMode::Read;
+                        }
+                    }
+                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, v) => {
+                        if h == v {
+                            let target_cell = backtrack_on_resource_error!(
+                                self,
+                                self.heap.allocate_pstr(string_cursor),
+                    return
+                            );
+
+                            self.bind(
+                                self.heap[h].as_var().unwrap(),
+                                target_cell,
+                            );
+
+                            self.mode = MachineMode::Write;
+                            break;
+                        } else {
+                            h = v;
+                        }
+                    }
+                    _ => {
+                        self.fail = true;
+                        break;
+                    }
+                );
+        }
+
+        step_or_fail!(self, self.p += 1);
+    }
+
+    #[inline(always)]
+    fn get_structure_instr(&mut self, name: Atom, arity: usize, r: RegType) {
+        let deref_v = self.deref(self[r]);
+        let store_v = self.store(deref_v);
+
+        read_heap_cell!(store_v,
+            (HeapCellValueTag::Str, a) => {
+                read_heap_cell!(self.heap[a],
+            (HeapCellValueTag::Atom, (result_name, result_arity)) => {
+            if arity == result_arity && name == result_name {
+                self.s = HeapPtr::HeapCell(a + 1);
+                self.s_offset = 0;
+                self.mode = MachineMode::Read;
+            } else {
+                self.backtrack();
+                return;
+            }
+            }
+                _ => {
+            unreachable!();
+            }
+                );
+            }
+            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                let h = self.heap.cell_len();
+
+                push_cell!(self, str_loc_as_cell!(h+1), return);
+                push_cell!(self, atom_as_cell!(name, arity), return);
+
+                self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+                self.mode = MachineMode::Write;
+            }
+            _ => {
+                self.backtrack();
+        return;
+            }
+        );
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_variable_instr(&mut self, norm: RegType, arg: usize) {
+        self[norm] = self.registers[arg];
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn get_value_instr(&mut self, norm: RegType, arg: usize) {
+        let norm_addr = self[norm];
+        let reg_addr = self.registers[arg];
+
+        unify_fn!(&mut *self, norm_addr, reg_addr);
+
+        if self.fail {
+            self.backtrack();
+            return;
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn unify_constant_instr(&mut self, v: HeapCellValue) {
+        match self.mode {
+            MachineMode::Read => {
+                let (addr, s_offset_incr) = self.read_s();
+                unify!(self, addr, v);
+
+                if self.fail {
+                    self.backtrack();
+                    return;
+                } else {
+                    self.s_offset += s_offset_incr;
+                }
+            }
+            MachineMode::Write => {
+                push_cell!(self, v, return);
+            }
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn unify_local_value_instr(&mut self, r: RegType) {
+        match self.mode {
+            MachineMode::Read => {
+                let reg_addr = self[r];
+                let (value, s_offset_incr) = self.read_s();
+
+                unify_fn!(&mut *self, reg_addr, value);
+
+                if self.fail {
+                    self.backtrack();
+                    return;
+                } else {
+                    self.s_offset += s_offset_incr;
+                }
+            }
+            MachineMode::Write => {
+                let value = self.store(self.deref(self[r]));
+                let h = self.heap.cell_len();
+
+                read_heap_cell!(value,
+                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
+                        let value = self.heap[hc];
+                        push_cell!(self, value, return);
+                        self.s_offset += 1;
+                    }
+                    _ => {
+                        push_cell!(self, heap_loc_as_cell!(h), return);
+                        (self.bind_fn)(self, Ref::heap_cell(h), value);
+                    }
+                );
+            }
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn unify_variable_instr(&mut self, r: RegType) {
+        match self.mode {
+            MachineMode::Read => {
+                let (value, s_offset_incr) = self.read_s();
+                self[r] = value;
+                self.s_offset += s_offset_incr;
+            }
+            MachineMode::Write => {
+                let h = self.heap.cell_len();
+                push_cell!(self, heap_loc_as_cell!(h), return);
+                self[r] = heap_loc_as_cell!(h);
+            }
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn unify_value_instr(&mut self, r: RegType) {
+        match self.mode {
+            MachineMode::Read => {
+                let reg_addr = self[r];
+                let (value, s_offset_incr) = self.read_s();
+
+                unify_fn!(&mut *self, reg_addr, value);
+
+                if self.fail {
+                    self.backtrack();
+                    return;
+                } else {
+                    self.s_offset += s_offset_incr;
+                }
+            }
+            MachineMode::Write => {
+                let h = self.heap.cell_len();
+                push_cell!(self, heap_loc_as_cell!(h), return);
+
+                let addr = self.store(self[r]);
+                (self.bind_fn)(self, Ref::heap_cell(h), addr);
+
+                // the former code of this match arm was:
+
+                // let addr = self.store(self[reg]);
+                // push_cell!(self, 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.
+            }
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn unify_void_instr(&mut self, n: usize) {
+        match self.mode {
+            MachineMode::Read => match &self.s {
+                HeapPtr::HeapCell(_) => self.s_offset += n,
+                &HeapPtr::PStr(pstr_loc) => {
+                    debug_assert!(n <= 2);
+                    let mut char_iter = self.heap.char_iter(pstr_loc);
+
+                    // this only matters in the case that n == 1, but the case
+                    // analysis isn't worth doing since the effect is benign if n ==
+                    // 2
+                    self.s_offset += char_iter.next().unwrap().len_utf8();
+                }
+            },
+            MachineMode::Write => {
+                let h = self.heap.cell_len();
+
+                for i in h..h + n {
+                    push_cell!(self, heap_loc_as_cell!(i), return);
+                }
+            }
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_constant_instr(&mut self, cell: HeapCellValue, r: RegType) {
+        self[r] = cell;
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_list_instr(&mut self, r: RegType) {
+        self[r] = list_loc_as_cell!(self.heap.cell_len());
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_partial_string_instr(&mut self, string: &str, r: RegType) {
+        self[r] = backtrack_on_resource_error!(self, self.heap.allocate_pstr(string), return);
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_structure_instr(&mut self, name: Atom, arity: usize, r: RegType) {
+        let h = self.heap.cell_len();
+
+        push_cell!(self, atom_as_cell!(name, arity), return);
+        self[r] = str_loc_as_cell!(h);
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_unsafe_value_instr(&mut self, perm_slot: usize, arg: usize) {
+        let s = stack_loc!(AndFrame, self.e, perm_slot);
+        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.cell_len();
+            push_cell!(self, heap_loc_as_cell!(h), return);
+
+            (self.bind_fn)(self, Ref::heap_cell(h), addr);
+            self.registers[arg] = heap_loc_as_cell!(h);
+        }
+
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_value_instr(&mut self, norm: RegType, arg: usize) {
+        self.registers[arg] = self[norm];
+        self.p += 1;
+    }
+
+    #[inline(always)]
+    fn put_variable_instr(&mut self, norm: RegType, arg: usize) {
+        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.cell_len();
+                push_cell!(self, heap_loc_as_cell!(h), return);
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
+                self[norm] = heap_loc_as_cell!(h);
+                self.registers[arg] = heap_loc_as_cell!(h);
+            }
+        }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::Mul(ref a1, ref a2, t) => {
-                        let stub_gen = || functor_stub(atom!("is"), 2);
+        self.p += 1;
+    }
 
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+    #[inline(always)]
+    fn set_constant_instr(&mut self, c: HeapCellValue) {
+        push_cell!(self, c, return);
+        self.p += 1;
+    }
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
+    #[inline(always)]
+    fn set_local_value_instr(&mut self, r: RegType) {
+        let addr = self.deref(self[r]);
+        let stored_v = self.store(addr);
+
+        if stored_v.is_stack_var() {
+            let h = self.heap.cell_len();
+            push_cell!(self, heap_loc_as_cell!(h), return);
+            (self.bind_fn)(self, Ref::heap_cell(h), stored_v);
+        } else {
+            push_cell!(self, stored_v, return);
+        }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::Max(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+        self.p += 1;
+    }
 
-                        let value = try_or_throw_gen!(&mut self.machine_st, max(n1, n2));
+    #[inline(always)]
+    fn set_variable_instr(&mut self, r: RegType) {
+        let h = self.heap.cell_len();
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::Min(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+        push_cell!(self, heap_loc_as_cell!(h), return);
+        self[r] = heap_loc_as_cell!(h);
 
-                        let value = try_or_throw_gen!(&mut self.machine_st, min(n1, n2));
+        self.p += 1;
+    }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::IntPow(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            int_pow(n1, n2, &mut self.machine_st.arena)
-                        );
+    #[inline(always)]
+    fn set_value_instr(&mut self, r: RegType) {
+        let heap_val = self.store(self[r]);
+        push_cell!(self, heap_val, return);
+        self.p += 1;
+    }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+    #[inline(always)]
+    fn set_void_instr(&mut self, n: usize) {
+        let h = self.heap.cell_len();
+
+        for i in h..h + n {
+            push_cell!(self, heap_loc_as_cell!(i), return);
+        }
+
+        self.p += 1;
+    }
+}
+
+impl Machine {
+    pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
+        loop {
+            match self.code[p] {
+                Instruction::DynamicElse(birth, death, NextOrFail::Next(i)) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, i));
+                    } else if i > 0 {
+                        p += i;
+                    } else {
+                        return None;
+                    }
+                }
+                Instruction::DynamicElse(birth, death, NextOrFail::Fail(_)) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, 0));
+                    } else {
+                        return None;
+                    }
+                }
+                Instruction::DynamicInternalElse(birth, death, NextOrFail::Next(i)) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, i));
+                    } else if i > 0 {
+                        p += i;
+                    } else {
+                        return None;
                     }
-                    &Instruction::Gcd(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+                }
+                Instruction::DynamicInternalElse(birth, death, NextOrFail::Fail(_)) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, 0));
+                    } else {
+                        return None;
+                    }
+                }
+                Instruction::RevJmpBy(i) => {
+                    p -= i;
+                }
+                _ => {
+                    unreachable!();
+                }
+            }
+        }
+    }
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            gcd(n1, n2, &mut self.machine_st.arena)
-                        );
+    pub(super) fn find_living_dynamic(
+        &self,
+        oi: u32,
+        mut ii: u32,
+    ) -> Option<(usize, u32, u32, bool)> {
+        let p = self.machine_st.p;
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+        let indexed_choice_instrs = match &self.code[p] {
+            Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
+                IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
+                    indexed_choice_instrs
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
+        };
+
+        loop {
+            match &indexed_choice_instrs.get(ii as usize) {
+                Some(&offset) => match &self.code[p + offset - 1] {
+                    &Instruction::DynamicInternalElse(birth, death, next_or_fail) => {
+                        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;
+                        }
                     }
-                    &Instruction::Pow(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+                    _ => unreachable!(),
+                },
+                None => return None,
+            }
+        }
+    }
 
-                        let value =
-                            try_or_throw_gen!(&mut self.machine_st, pow(n1, n2, atom!("**")));
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
+    #[inline(always)]
+    fn execute_switch_on_term(&mut self) {
+        #[inline(always)]
+        fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
+            if let Instruction::DynamicInternalElse(..) = machine.code[p] {
+                machine.machine_st.dynamic_mode = FirstOrNext::First;
+                return true;
+            }
 
-                        self.machine_st.p += 1;
+            if let Instruction::DynamicInternalElse(birth, death, _) = machine.code[p - 1] {
+                return birth < machine.machine_st.cc
+                    && Death::Finite(machine.machine_st.cc) <= death;
+            }
+
+            true
+        }
+
+        let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap();
+
+        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 = self
+                        .machine_st
+                        .select_switch_on_term_index(addr, v, c, l, s);
+
+                    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;
+
+                            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;
+                        }
                     }
-                    &Instruction::RDiv(ref a1, ref a2, t) => {
-                        let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
+                }
+                IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
+                    // let lit = self.machine_st.constant_to_literal(addr);
 
-                        let r1 = try_or_throw!(
-                            self.machine_st,
-                            self.machine_st.get_rational(a1, stub_gen)
-                        );
-                        let r2 = try_or_throw!(
-                            self.machine_st,
-                            self.machine_st.get_rational(a2, stub_gen)
-                        );
+                    let offset = match hm.get(&addr) {
+                        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;
 
-                        let value = Number::Rational(arena_alloc!(
-                            try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
-                            &mut self.machine_st.arena
-                        ));
+                            if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                self.machine_st.fail = true;
+                            } else {
+                                self.machine_st.p += o;
+                            }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            self.machine_st.p += o;
+                            break;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            index += o;
+                        }
                     }
-                    &Instruction::IntFloorDiv(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+                }
+                IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
+                    let offset = self.machine_st.select_switch_on_structure_index(addr, hm);
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            int_floor_div(n1, n2, &mut self.machine_st.arena)
-                        );
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.machine_st.fail = true;
+                            break;
+                        }
+                        IndexingCodePtr::DynamicExternal(o) => {
+                            let p = self.machine_st.p;
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                            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;
+                        }
                     }
-                    &Instruction::IDiv(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+                }
+                &IndexingLine::IndexedChoice(_) => {
+                    self.machine_st.oip = index as u32;
+                    self.machine_st.iip = 0;
 
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            idiv(n1, n2, &mut self.machine_st.arena)
-                        );
+                    break;
+                }
+                &IndexingLine::DynamicIndexedChoice(_) => {
+                    self.machine_st.dynamic_mode = FirstOrNext::First;
+
+                    self.machine_st.oip = index as u32;
+                    self.machine_st.iip = 0;
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::Abs(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    break;
+                }
+            }
+        }
+    }
 
-                        let value = abs(n1, &mut self.machine_st.arena);
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+    fn verify_attr_dispatch_loop(&mut self) -> Option<std::process::ExitCode> {
+        'outer: loop {
+            for _ in 0..INSTRUCTIONS_PER_INTERRUPT_POLL {
+                match &self.code[self.machine_st.p] {
+                    &Instruction::BreakFromDispatchLoop => {
+                        break 'outer;
                     }
-                    &Instruction::Sign(ref a1, t) => {
-                        let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let value = n.sign();
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Add(ref a1, ref a2, t) => self.machine_st.add_instr(a1, a2, t),
+                    &Instruction::Sub(ref a1, ref a2, t) => self.machine_st.sub_instr(a1, a2, t),
+                    &Instruction::Mul(ref a1, ref a2, t) => self.machine_st.mul_instr(a1, a2, t),
+                    &Instruction::Max(ref a1, ref a2, t) => self.machine_st.max_instr(a1, a2, t),
+                    &Instruction::Min(ref a1, ref a2, t) => self.machine_st.min_instr(a1, a2, t),
+                    &Instruction::IntPow(ref a1, ref a2, t) => {
+                        self.machine_st.int_pow_instr(a1, a2, t)
                     }
-                    &Instruction::Neg(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = neg(n1, &mut self.machine_st.arena);
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Gcd(ref a1, ref a2, t) => self.machine_st.gcd_instr(a1, a2, t),
+                    &Instruction::Pow(ref a1, ref a2, t) => self.machine_st.pow_instr(a1, a2, t),
+                    &Instruction::RDiv(ref a1, ref a2, t) => self.machine_st.rdiv_instr(a1, a2, t),
+                    &Instruction::IntFloorDiv(ref a1, ref a2, t) => {
+                        self.machine_st.int_floor_div_instr(a1, a2, t)
                     }
+                    &Instruction::IDiv(ref a1, ref a2, t) => self.machine_st.idiv_instr(a1, a2, t),
+                    &Instruction::Abs(ref a1, t) => self.machine_st.abs_instr(a1, t),
+                    &Instruction::Sign(ref a1, t) => self.machine_st.sign_instr(a1, t),
+                    &Instruction::Neg(ref a1, t) => self.machine_st.neg_instr(a1, t),
                     &Instruction::BitwiseComplement(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            bitwise_complement(n1, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                        self.machine_st.bitwise_complement_instr(a1, t)
+                    }
+                    &Instruction::Div(ref a1, ref a2, t) => self.machine_st.div_instr(a1, a2, t),
+                    &Instruction::Shr(ref a1, ref a2, t) => self.machine_st.shr_instr(a1, a2, t),
+                    &Instruction::Shl(ref a1, ref a2, t) => self.machine_st.shl_instr(a1, a2, t),
+                    &Instruction::Xor(ref a1, ref a2, t) => self.machine_st.xor_instr(a1, a2, t),
+                    &Instruction::And(ref a1, ref a2, t) => self.machine_st.and_instr(a1, a2, t),
+                    &Instruction::Or(ref a1, ref a2, t) => self.machine_st.or_instr(a1, a2, t),
+                    &Instruction::Mod(ref a1, ref a2, t) => self.machine_st.mod_instr(a1, a2, t),
+                    &Instruction::Rem(ref a1, ref a2, t) => self.machine_st.rem_instr(a1, a2, t),
+                    &Instruction::Cos(ref a1, t) => self.machine_st.cos_instr(a1, t),
+                    &Instruction::Sin(ref a1, t) => self.machine_st.sin_instr(a1, t),
+                    &Instruction::Tan(ref a1, t) => self.machine_st.tan_instr(a1, t),
+                    &Instruction::Sqrt(ref a1, t) => self.machine_st.sqrt_instr(a1, t),
+                    &Instruction::Log(ref a1, t) => self.machine_st.log_instr(a1, t),
+                    &Instruction::Exp(ref a1, t) => self.machine_st.exp_instr(a1, t),
+                    &Instruction::ACos(ref a1, t) => self.machine_st.acos_instr(a1, t),
+                    &Instruction::ASin(ref a1, t) => self.machine_st.asin_instr(a1, t),
+                    &Instruction::ATan(ref a1, t) => self.machine_st.atan_instr(a1, t),
+                    &Instruction::ATan2(ref a1, ref a2, t) => {
+                        self.machine_st.atan2_instr(a1, a2, t)
                     }
-                    &Instruction::Div(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(&mut self.machine_st, div(n1, n2));
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Float(ref a1, t) => self.machine_st.float_instr(a1, t),
+                    &Instruction::Truncate(ref a1, t) => self.machine_st.truncate_instr(a1, t),
+                    &Instruction::Round(ref a1, t) => self.machine_st.round_instr(a1, t),
+                    &Instruction::Ceiling(ref a1, t) => self.machine_st.ceiling_instr(a1, t),
+                    &Instruction::Floor(ref a1, t) => self.machine_st.floor_instr(a1, t),
+                    &Instruction::FloatFractionalPart(ref a1, t) => {
+                        self.machine_st.float_fractional_part_instr(a1, t)
                     }
-                    &Instruction::Shr(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            shr(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::FloatIntegerPart(ref a1, t) => {
+                        self.machine_st.float_integer_part_instr(a1, t)
                     }
-                    &Instruction::Shl(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            shl(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Plus(ref a1, t) => self.machine_st.plus_instr(a1, t),
+                    &Instruction::GetLevel(r) => self.machine_st.get_level_instr(r),
+                    &Instruction::GetPrevLevel(r) => self.machine_st.get_prev_level_instr(r),
+                    &Instruction::GetCutPoint(r) => self.machine_st.get_cut_point_instr(r),
+                    &Instruction::Deallocate => self.machine_st.deallocate(),
+                    &Instruction::JmpByCall(offset) => {
+                        self.machine_st.p += offset;
                     }
-                    &Instruction::Xor(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            xor(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::RevJmpBy(offset) => {
+                        self.machine_st.p -= offset;
                     }
-                    &Instruction::And(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            and(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetConstant(_, c, reg) => {
+                        self.machine_st.get_constant_instr(c, reg)
                     }
-                    &Instruction::Or(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            or(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetList(_, reg) => self.machine_st.get_list_instr(reg),
+                    &Instruction::GetPartialString(_, ref string, reg) => {
+                        self.machine_st.get_partial_string_instr(string, reg)
                     }
-                    &Instruction::Mod(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            modulus(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetStructure(_lvl, name, arity, reg) => {
+                        self.machine_st.get_structure_instr(name, arity, reg)
                     }
-                    &Instruction::Rem(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            remainder(n1, n2, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetVariable(norm, arg) => {
+                        self.machine_st.get_variable_instr(norm, arg)
                     }
-                    &Instruction::Cos(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            cos(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetValue(norm, arg) => self.machine_st.get_value_instr(norm, arg),
+                    &Instruction::UnifyConstant(v) => self.machine_st.unify_constant_instr(v),
+                    &Instruction::UnifyLocalValue(reg) => {
+                        self.machine_st.unify_local_value_instr(reg)
                     }
-                    &Instruction::Sin(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            sin(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::UnifyVariable(reg) => self.machine_st.unify_variable_instr(reg),
+                    &Instruction::UnifyValue(reg) => self.machine_st.unify_value_instr(reg),
+                    &Instruction::UnifyVoid(n) => self.machine_st.unify_void_instr(n),
+                    &Instruction::PutConstant(_, cell, reg) => {
+                        self.machine_st.put_constant_instr(cell, reg)
                     }
-                    &Instruction::Tan(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            tan(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::PutList(_, reg) => self.machine_st.put_list_instr(reg),
+                    &Instruction::PutPartialString(_, ref string, reg) => {
+                        self.machine_st.put_partial_string_instr(string, reg)
                     }
-                    &Instruction::Sqrt(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            sqrt(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::PutStructure(name, arity, reg) => {
+                        self.machine_st.put_structure_instr(name, arity, reg)
                     }
-                    &Instruction::Log(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            log(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::PutUnsafeValue(perm_slot, arg) => {
+                        self.machine_st.put_unsafe_value_instr(perm_slot, arg)
                     }
-                    &Instruction::Exp(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            exp(n1)
-                        )));
+                    &Instruction::PutValue(norm, arg) => self.machine_st.put_value_instr(norm, arg),
+                    &Instruction::PutVariable(norm, arg) => {
+                        self.machine_st.put_variable_instr(norm, arg)
+                    }
+                    &Instruction::SetConstant(c) => self.machine_st.set_constant_instr(c),
+                    &Instruction::SetLocalValue(reg) => self.machine_st.set_local_value_instr(reg),
+                    &Instruction::SetVariable(reg) => self.machine_st.set_variable_instr(reg),
+                    &Instruction::SetValue(reg) => self.machine_st.set_value_instr(reg),
+                    &Instruction::SetVoid(n) => self.machine_st.set_void_instr(n),
+                    _ => return None,
+                }
+            }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::ACos(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+            self.machine_st.check_for_interrupt();
+        }
 
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            acos(n1)
-                        )));
+        Some(std::process::ExitCode::SUCCESS)
+    }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+    pub(super) fn dispatch_loop(&mut self) -> std::process::ExitCode {
+        'outer: loop {
+            for _ in 0..INSTRUCTIONS_PER_INTERRUPT_POLL {
+                match &self.code[self.machine_st.p] {
+                    &Instruction::BreakFromDispatchLoop => {
+                        break 'outer;
                     }
-                    &Instruction::ASin(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    &Instruction::RunVerifyAttr => {
+                        self.machine_st.p = self.machine_st.attr_var_init.p;
 
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            asin(n1)
-                        )));
+                        if self.code[self.machine_st.p].is_execute() {
+                            self.machine_st.p = self.machine_st.attr_var_init.cp;
+                        } else {
+                            self.machine_st.p += 1;
+                            self.machine_st.cp = self.machine_st.attr_var_init.cp;
+                        }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::ATan(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                        if let Some(exit_code) = self.verify_attr_dispatch_loop() {
+                            return exit_code;
+                        }
 
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            atan(n1)
-                        )));
+                        if self.machine_st.fail {
+                            continue;
+                        }
 
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                        self.machine_st.attr_var_init.cp = self.machine_st.p;
+                        let (_, arity) = self.code[self.machine_st.p].to_name_and_arity();
+                        self.run_verify_attr_interrupt(arity);
+                    }
+                    &Instruction::Add(ref a1, ref a2, t) => self.machine_st.add_instr(a1, a2, t),
+                    &Instruction::Sub(ref a1, ref a2, t) => self.machine_st.sub_instr(a1, a2, t),
+                    &Instruction::Mul(ref a1, ref a2, t) => self.machine_st.mul_instr(a1, a2, t),
+                    &Instruction::Max(ref a1, ref a2, t) => self.machine_st.max_instr(a1, a2, t),
+                    &Instruction::Min(ref a1, ref a2, t) => self.machine_st.min_instr(a1, a2, t),
+                    &Instruction::IntPow(ref a1, ref a2, t) => {
+                        self.machine_st.int_pow_instr(a1, a2, t)
+                    }
+                    &Instruction::Gcd(ref a1, ref a2, t) => self.machine_st.gcd_instr(a1, a2, t),
+                    &Instruction::Pow(ref a1, ref a2, t) => self.machine_st.pow_instr(a1, a2, t),
+                    &Instruction::RDiv(ref a1, ref a2, t) => self.machine_st.rdiv_instr(a1, a2, t),
+                    &Instruction::IntFloorDiv(ref a1, ref a2, t) => {
+                        self.machine_st.int_floor_div_instr(a1, a2, t)
                     }
+                    &Instruction::IDiv(ref a1, ref a2, t) => self.machine_st.idiv_instr(a1, a2, t),
+                    &Instruction::Abs(ref a1, t) => self.machine_st.abs_instr(a1, t),
+                    &Instruction::Sign(ref a1, t) => self.machine_st.sign_instr(a1, t),
+                    &Instruction::Neg(ref a1, t) => self.machine_st.neg_instr(a1, t),
+                    &Instruction::BitwiseComplement(ref a1, t) => {
+                        self.machine_st.bitwise_complement_instr(a1, t)
+                    }
+                    &Instruction::Div(ref a1, ref a2, t) => self.machine_st.div_instr(a1, a2, t),
+                    &Instruction::Shr(ref a1, ref a2, t) => self.machine_st.shr_instr(a1, a2, t),
+                    &Instruction::Shl(ref a1, ref a2, t) => self.machine_st.shl_instr(a1, a2, t),
+                    &Instruction::Xor(ref a1, ref a2, t) => self.machine_st.xor_instr(a1, a2, t),
+                    &Instruction::And(ref a1, ref a2, t) => self.machine_st.and_instr(a1, a2, t),
+                    &Instruction::Or(ref a1, ref a2, t) => self.machine_st.or_instr(a1, a2, t),
+                    &Instruction::Mod(ref a1, ref a2, t) => self.machine_st.mod_instr(a1, a2, t),
+                    &Instruction::Rem(ref a1, ref a2, t) => self.machine_st.rem_instr(a1, a2, t),
+                    &Instruction::Cos(ref a1, t) => self.machine_st.cos_instr(a1, t),
+                    &Instruction::Sin(ref a1, t) => self.machine_st.sin_instr(a1, t),
+                    &Instruction::Tan(ref a1, t) => self.machine_st.tan_instr(a1, t),
+                    &Instruction::Sqrt(ref a1, t) => self.machine_st.sqrt_instr(a1, t),
+                    &Instruction::Log(ref a1, t) => self.machine_st.log_instr(a1, t),
+                    &Instruction::Exp(ref a1, t) => self.machine_st.exp_instr(a1, t),
+                    &Instruction::ACos(ref a1, t) => self.machine_st.acos_instr(a1, t),
+                    &Instruction::ASin(ref a1, t) => self.machine_st.asin_instr(a1, t),
+                    &Instruction::ATan(ref a1, t) => self.machine_st.atan_instr(a1, t),
                     &Instruction::ATan2(ref a1, ref a2, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            atan2(n1, n2)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                        self.machine_st.atan2_instr(a1, a2, t)
                     }
-                    &Instruction::Float(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            float(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Float(ref a1, t) => self.machine_st.float_instr(a1, t),
+                    &Instruction::Truncate(ref a1, t) => self.machine_st.truncate_instr(a1, t),
+                    &Instruction::Round(ref a1, t) => self.machine_st.round_instr(a1, t),
+                    &Instruction::Ceiling(ref a1, t) => self.machine_st.ceiling_instr(a1, t),
+                    &Instruction::Floor(ref a1, t) => self.machine_st.floor_instr(a1, t),
+                    &Instruction::FloatFractionalPart(ref a1, t) => {
+                        self.machine_st.float_fractional_part_instr(a1, t)
                     }
-                    &Instruction::Truncate(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = truncate(n1, &mut self.machine_st.arena);
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::FloatIntegerPart(ref a1, t) => {
+                        self.machine_st.float_integer_part_instr(a1, t)
                     }
-                    &Instruction::Round(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = try_or_throw_gen!(
-                            &mut self.machine_st,
-                            round(n1, &mut self.machine_st.arena)
-                        );
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::Plus(ref a1, t) => self.machine_st.plus_instr(a1, t),
+                    &Instruction::GetLevel(r) => self.machine_st.get_level_instr(r),
+                    &Instruction::GetPrevLevel(r) => self.machine_st.get_prev_level_instr(r),
+                    &Instruction::GetCutPoint(r) => self.machine_st.get_cut_point_instr(r),
+                    &Instruction::Deallocate => self.machine_st.deallocate(),
+                    &Instruction::GetConstant(_, c, reg) => {
+                        self.machine_st.get_constant_instr(c, reg)
                     }
-                    &Instruction::Ceiling(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = ceiling(n1, &mut self.machine_st.arena);
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetList(_, reg) => self.machine_st.get_list_instr(reg),
+                    &Instruction::GetPartialString(_, ref string, reg) => {
+                        self.machine_st.get_partial_string_instr(string, reg)
                     }
-                    &Instruction::Floor(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = floor(n1, &mut self.machine_st.arena);
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetStructure(_lvl, name, arity, reg) => {
+                        self.machine_st.get_structure_instr(name, arity, reg)
                     }
-                    &Instruction::FloatFractionalPart(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            float_fractional_part(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetVariable(norm, arg) => {
+                        self.machine_st.get_variable_instr(norm, arg)
                     }
-                    &Instruction::FloatIntegerPart(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        let value = Number::Float(OrderedFloat(try_or_throw_gen!(
-                            &mut self.machine_st,
-                            float_integer_part(n1)
-                        )));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((value, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::GetValue(norm, arg) => self.machine_st.get_value_instr(norm, arg),
+                    &Instruction::UnifyConstant(v) => self.machine_st.unify_constant_instr(v),
+                    &Instruction::UnifyLocalValue(reg) => {
+                        self.machine_st.unify_local_value_instr(reg)
                     }
-                    &Instruction::Plus(ref a1, t) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
-
-                        self.machine_st.registers[t] =
-                            HeapCellValue::from((n1, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
+                    &Instruction::UnifyVariable(reg) => self.machine_st.unify_variable_instr(reg),
+                    &Instruction::UnifyValue(reg) => self.machine_st.unify_value_instr(reg),
+                    &Instruction::UnifyVoid(n) => self.machine_st.unify_void_instr(n),
+                    &Instruction::PutConstant(_, cell, reg) => {
+                        self.machine_st.put_constant_instr(cell, reg)
+                    }
+                    &Instruction::PutList(_, reg) => self.machine_st.put_list_instr(reg),
+                    &Instruction::PutPartialString(_, ref string, reg) => {
+                        self.machine_st.put_partial_string_instr(string, reg)
+                    }
+                    &Instruction::PutStructure(name, arity, reg) => {
+                        self.machine_st.put_structure_instr(name, arity, reg)
+                    }
+                    &Instruction::PutUnsafeValue(perm_slot, arg) => {
+                        self.machine_st.put_unsafe_value_instr(perm_slot, arg)
                     }
+                    &Instruction::PutValue(norm, arg) => self.machine_st.put_value_instr(norm, arg),
+                    &Instruction::PutVariable(norm, arg) => {
+                        self.machine_st.put_variable_instr(norm, arg)
+                    }
+                    &Instruction::SetConstant(c) => self.machine_st.set_constant_instr(c),
+                    &Instruction::SetLocalValue(reg) => self.machine_st.set_local_value_instr(reg),
+                    &Instruction::SetVariable(reg) => self.machine_st.set_variable_instr(reg),
+                    &Instruction::SetValue(reg) => self.machine_st.set_value_instr(reg),
+                    &Instruction::SetVoid(n) => self.machine_st.set_void_instr(n),
                     &Instruction::DynamicElse(..) => {
                         if let FirstOrNext::First = self.machine_st.dynamic_mode {
                             self.machine_st.cc = self.machine_st.global_clock;
@@ -1292,37 +1996,6 @@ impl Machine {
                         self.machine_st.neck_cut();
                         self.machine_st.p += 1;
                     }
-                    &Instruction::GetLevel(r) => {
-                        let b0 = self.machine_st.b0;
-
-                        self.machine_st[r] = fixnum_as_cell!(
-                            /* FIXME this is not safe */
-                            unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint()
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::GetPrevLevel(r) => {
-                        let prev_b = self
-                            .machine_st
-                            .stack
-                            .index_or_frame(self.machine_st.b)
-                            .prelude
-                            .b;
-
-                        self.machine_st[r] = fixnum_as_cell!(
-                            /* FIXME this is not safe */
-                            unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint()
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::GetCutPoint(r) => {
-                        self.machine_st[r] =
-                            fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
-                                Fixnum::build_with_unchecked(self.machine_st.b as i64)
-                            }
-                            .as_cutpoint());
-                        self.machine_st.p += 1;
-                    }
                     &Instruction::Cut(r) => {
                         let value = self.machine_st[r];
                         self.machine_st.cut_body(value);
@@ -1385,20 +2058,20 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::DefaultCallArg => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_arg());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteArg => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_arg());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::DefaultCallCompare => {
-                        try_or_throw!(self.machine_st, self.machine_st.compare());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.compare(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteCompare => {
-                        try_or_throw!(self.machine_st, self.machine_st.compare());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.compare(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::DefaultCallTermGreaterThan => {
                         let a1 = self.machine_st.registers[1];
@@ -1496,7 +2169,7 @@ impl Machine {
                     }
                     &Instruction::DefaultCallCopyTerm => {
                         self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteCopyTerm => {
                         self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
@@ -1542,12 +2215,11 @@ impl Machine {
                         }
                     }
                     &Instruction::DefaultCallFunctor => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_functor());
-
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteFunctor => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_functor());
+                        try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1576,24 +2248,26 @@ impl Machine {
                         }
                     }
                     &Instruction::DefaultCallSort => {
-                        try_or_throw!(self.machine_st, self.machine_st.sort());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.sort(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteSort => {
-                        try_or_throw!(self.machine_st, self.machine_st.sort());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.sort(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::DefaultCallKeySort => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Distinct)
+                            self.machine_st.keysort(VarComparison::Distinct),
+                            continue
                         );
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteKeySort => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Distinct)
+                            self.machine_st.keysort(VarComparison::Distinct),
+                            continue
                         );
 
                         if self.machine_st.fail {
@@ -1603,20 +2277,20 @@ impl Machine {
                         }
                     }
                     &Instruction::DefaultCallIs(r, at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.is(r, at));
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::DefaultExecuteIs(r, at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.is(r, at));
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     Instruction::DefaultCallGetNumber(at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.get_number(at));
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     Instruction::DefaultExecuteGetNumber(at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.get_number(at));
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallAcyclicTerm => {
                         let addr = self.deref_register(1);
@@ -1649,7 +2323,7 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallArg => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_arg());
+                        try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1659,7 +2333,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteArg => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_arg());
+                        try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1669,7 +2343,7 @@ impl Machine {
                         }
                     }
                     &Instruction::CallCompare => {
-                        try_or_throw!(self.machine_st, self.machine_st.compare());
+                        try_or_throw!(self.machine_st, self.machine_st.compare(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1679,7 +2353,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteCompare => {
-                        try_or_throw!(self.machine_st, self.machine_st.compare());
+                        try_or_throw!(self.machine_st, self.machine_st.compare(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1849,7 +2523,7 @@ impl Machine {
                         }
                     }
                     &Instruction::CallFunctor => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_functor());
+                        try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1859,7 +2533,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteFunctor => {
-                        try_or_throw!(self.machine_st, self.machine_st.try_functor());
+                        try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1891,7 +2565,7 @@ impl Machine {
                         }
                     }
                     &Instruction::CallSort => {
-                        try_or_throw!(self.machine_st, self.machine_st.sort());
+                        try_or_throw!(self.machine_st, self.machine_st.sort(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1901,7 +2575,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteSort => {
-                        try_or_throw!(self.machine_st, self.machine_st.sort());
+                        try_or_throw!(self.machine_st, self.machine_st.sort(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1913,7 +2587,8 @@ impl Machine {
                     &Instruction::CallKeySort => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Distinct)
+                            self.machine_st.keysort(VarComparison::Distinct),
+                            continue
                         );
 
                         if self.machine_st.fail {
@@ -1926,7 +2601,8 @@ impl Machine {
                     &Instruction::ExecuteKeySort => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Distinct)
+                            self.machine_st.keysort(VarComparison::Distinct),
+                            continue
                         );
 
                         if self.machine_st.fail {
@@ -1939,7 +2615,8 @@ impl Machine {
                     &Instruction::CallKeySortWithConstantVarOrdering => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Indistinct)
+                            self.machine_st.keysort(VarComparison::Indistinct),
+                            continue
                         );
 
                         if self.machine_st.fail {
@@ -1952,7 +2629,8 @@ impl Machine {
                     &Instruction::ExecuteKeySortWithConstantVarOrdering => {
                         try_or_throw!(
                             self.machine_st,
-                            self.machine_st.keysort(VarComparison::Indistinct)
+                            self.machine_st.keysort(VarComparison::Indistinct),
+                            continue
                         );
 
                         if self.machine_st.fail {
@@ -1963,7 +2641,7 @@ impl Machine {
                         }
                     }
                     &Instruction::CallIs(r, at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+                        try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1973,7 +2651,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteIs(r, at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+                        try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1983,7 +2661,7 @@ impl Machine {
                         }
                     }
                     Instruction::CallGetNumber(at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.get_number(at));
+                        try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -1993,7 +2671,7 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteGetNumber(at) => {
-                        try_or_throw!(self.machine_st, self.machine_st.get_number(at));
+                        try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -2011,7 +2689,7 @@ impl Machine {
 
                         self.machine_st.registers[arity] = pred;
 
-                        try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity));
+                        try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -2028,7 +2706,11 @@ impl Machine {
 
                         self.machine_st.registers[arity] = pred;
 
-                        try_or_throw!(self.machine_st, self.execute_n(atom!("user"), arity));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.execute_n(atom!("user"), arity),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -2045,7 +2727,7 @@ impl Machine {
 
                         self.machine_st.registers[arity] = pred;
 
-                        try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity));
+                        try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -2060,15 +2742,27 @@ impl Machine {
 
                         self.machine_st.registers[arity] = pred;
 
-                        try_or_throw!(self.machine_st, self.execute_n(atom!("user"), arity));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.execute_n(atom!("user"), arity),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
                         }
                     }
                     Instruction::CallNumberLessThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less | Ordering::Equal => {
@@ -2081,8 +2775,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberLessThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less | Ordering::Equal => {
@@ -2095,8 +2797,16 @@ impl Machine {
                         }
                     }
                     Instruction::CallNumberEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2109,8 +2819,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2123,8 +2841,16 @@ impl Machine {
                         }
                     }
                     Instruction::CallNumberNotEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2137,8 +2863,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberNotEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2151,8 +2885,16 @@ impl Machine {
                         }
                     }
                     Instruction::CallNumberGreaterThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater | Ordering::Equal => {
@@ -2165,8 +2907,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater | Ordering::Equal => {
@@ -2179,8 +2929,16 @@ impl Machine {
                         }
                     }
                     Instruction::CallNumberGreaterThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater => {
@@ -2193,8 +2951,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberGreaterThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater => {
@@ -2207,8 +2973,16 @@ impl Machine {
                         }
                     }
                     Instruction::CallNumberLessThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less => {
@@ -2221,8 +2995,16 @@ impl Machine {
                         }
                     }
                     Instruction::ExecuteNumberLessThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less => {
@@ -2235,8 +3017,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberLessThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less | Ordering::Equal => {
@@ -2248,8 +3038,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberLessThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less | Ordering::Equal => {
@@ -2261,8 +3059,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberNotEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2274,8 +3080,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberNotEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2287,8 +3101,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2300,8 +3122,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Equal => {
@@ -2313,8 +3143,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberGreaterThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater | Ordering::Equal => {
@@ -2326,8 +3164,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater | Ordering::Equal => {
@@ -2339,8 +3185,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberGreaterThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater => {
@@ -2352,8 +3206,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberGreaterThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Greater => {
@@ -2365,8 +3227,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultCallNumberLessThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less => {
@@ -2378,8 +3248,16 @@ impl Machine {
                         }
                     }
                     Instruction::DefaultExecuteNumberLessThan(ref at_1, ref at_2) => {
-                        let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
-                        let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+                        let n1 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_1),
+                            continue
+                        );
+                        let n2 = try_or_throw!(
+                            self.machine_st,
+                            self.machine_st.get_number(at_2),
+                            continue
+                        );
 
                         match n1.cmp(&n2) {
                             Ordering::Less => {
@@ -2704,533 +3582,145 @@ impl Machine {
                             Ok(Number::Float(_)) => {
                                 self.machine_st.p += 1;
                             }
-                            _ => {
-                                self.machine_st.backtrack();
-                            }
-                        }
-                    }
-                    &Instruction::ExecuteIsFloat(r) => {
-                        let d = self
-                            .machine_st
-                            .store(self.machine_st.deref(self.machine_st[r]));
-
-                        match Number::try_from((d, &self.machine_st.arena.f64_tbl)) {
-                            Ok(Number::Float(_)) => {
-                                self.machine_st.p = self.machine_st.cp;
-                            }
-                            _ => {
-                                self.machine_st.backtrack();
-                            }
-                        }
-                    }
-                    &Instruction::CallIsNonVar(r) => {
-                        let d = self
-                            .machine_st
-                            .store(self.machine_st.deref(self.machine_st[r]));
-
-                        match d.get_tag() {
-                            HeapCellValueTag::AttrVar
-                            | HeapCellValueTag::Var
-                            | HeapCellValueTag::StackVar => {
-                                self.machine_st.backtrack();
-                            }
-                            _ => {
-                                self.machine_st.p += 1;
-                            }
-                        }
-                    }
-                    &Instruction::ExecuteIsNonVar(r) => {
-                        let d = self
-                            .machine_st
-                            .store(self.machine_st.deref(self.machine_st[r]));
-
-                        match d.get_tag() {
-                            HeapCellValueTag::AttrVar
-                            | HeapCellValueTag::Var
-                            | HeapCellValueTag::StackVar => {
-                                self.machine_st.backtrack();
-                            }
-                            _ => {
-                                self.machine_st.p = self.machine_st.cp;
-                            }
-                        }
-                    }
-                    &Instruction::CallIsVar(r) => {
-                        let d = self
-                            .machine_st
-                            .store(self.machine_st.deref(self.machine_st[r]));
-
-                        match d.get_tag() {
-                            HeapCellValueTag::AttrVar
-                            | HeapCellValueTag::Var
-                            | HeapCellValueTag::StackVar => {
-                                self.machine_st.p += 1;
-                            }
-                            _ => {
-                                self.machine_st.backtrack();
-                            }
-                        }
-                    }
-                    &Instruction::ExecuteIsVar(r) => {
-                        let d = self
-                            .machine_st
-                            .store(self.machine_st.deref(self.machine_st[r]));
-
-                        match d.get_tag() {
-                            HeapCellValueTag::AttrVar
-                            | HeapCellValueTag::Var
-                            | HeapCellValueTag::StackVar => {
-                                self.machine_st.p = self.machine_st.cp;
-                            }
-                            _ => {
-                                self.machine_st.backtrack();
-                            }
-                        }
-                    }
-                    &Instruction::CallNamed(arity, name, idx) => {
-                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
-
-                        try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
-
-                        if self.machine_st.fail {
-                            self.machine_st.backtrack();
-                        } else {
-                            increment_call_count!(self.machine_st);
-                        }
-                    }
-                    &Instruction::ExecuteNamed(arity, name, idx) => {
-                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
-
-                        try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
-
-                        if self.machine_st.fail {
-                            self.machine_st.backtrack();
-                        } else {
-                            increment_call_count!(self.machine_st);
-                        }
-                    }
-                    &Instruction::DefaultCallNamed(arity, name, idx) => {
-                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
-
-                        try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
-
-                        if self.machine_st.fail {
-                            self.machine_st.backtrack();
-                        }
-                    }
-                    &Instruction::DefaultExecuteNamed(arity, name, idx) => {
-                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
-
-                        try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
-
-                        if self.machine_st.fail {
-                            self.machine_st.backtrack();
-                        }
-                    }
-                    &Instruction::Deallocate => self.machine_st.deallocate(),
-                    &Instruction::JmpByCall(offset) => {
-                        self.machine_st.p += offset;
-                    }
-                    &Instruction::RevJmpBy(offset) => {
-                        self.machine_st.p -= offset;
-                    }
-                    &Instruction::Proceed => {
-                        self.machine_st.p = self.machine_st.cp;
-                    }
-                    &Instruction::GetConstant(_, c, reg) => {
-                        unify!(self.machine_st, self.machine_st[reg], c);
-                        step_or_fail!(self, self.machine_st.p += 1);
-                    }
-                    &Instruction::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) => {
-                                self.machine_st.s = HeapPtr::PStr(h);
-                                self.machine_st.s_offset = 0;
-                                self.machine_st.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::Str, s) => {
-                                let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                                    .get_name_and_arity();
-
-                                if name == atom!(".") && arity == 2 {
-                                    self.machine_st.s = HeapPtr::HeapCell(s+1);
-                                    self.machine_st.s_offset = 0;
-                                    self.machine_st.mode = MachineMode::Read;
-                                } else {
-                                    self.machine_st.backtrack();
-                                    continue;
-                                }
-                            }
-                            (HeapCellValueTag::Lis, l) => {
-                                self.machine_st.s = HeapPtr::HeapCell(l);
-                                self.machine_st.s_offset = 0;
-                                self.machine_st.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.cell_len();
-
-                                push_cell!(self.machine_st, 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.backtrack();
-                                continue;
-                            }
-                        );
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::GetPartialString(_, ref string, reg) => {
-                        self.machine_st.heap[0] = self.machine_st[reg];
-
-                        let mut h = 0;
-                        let mut string_cursor = string.as_str();
-
-                        if self.machine_st.heap[0].is_stack_var() {
-                            let cell = self
-                                .machine_st
-                                .store(self.machine_st.deref(self.machine_st.heap[0]));
-
-                            if let Some(r) = cell.as_var() {
-                                let target_cell = backtrack_on_resource_error!(
-                                    self.machine_st,
-                                    self.machine_st.heap.allocate_pstr(string_cursor)
-                                );
-
-                                self.machine_st.bind(r, target_cell);
-                                self.machine_st.mode = MachineMode::Write;
-
-                                debug_assert!(!self.machine_st.fail);
-                                self.machine_st.p += 1;
-
-                                continue;
-                            }
-
-                            self.machine_st.heap[0] = cell;
-                        }
-
-                        while let Some(c) = string_cursor.chars().next() {
-                            read_heap_cell!(self.machine_st.heap[h],
-                                (HeapCellValueTag::PStrLoc, pstr_loc) => {
-                                    let heap_slice = &self.machine_st.heap.as_slice()[pstr_loc ..];
-
-                                    match compare_pstr_slices(heap_slice, string_cursor.as_bytes()) {
-                                        PStrSegmentCmpResult::Continue(v1, v2) => {
-                                            // for v2, the value of a TailIndex mustn't ever be read
-                                            // since string does not lie in the heap.
-                                            match (v1, v2) {
-                                                (PStrContinuable::TailIndex(tail_idx), PStrContinuable::TailIndex(_)) => {
-                                                    self.machine_st.s = HeapPtr::HeapCell(tail_idx + cell_index!(pstr_loc));
-                                                    self.machine_st.s_offset = 0;
-                                                    self.machine_st.mode = MachineMode::Read;
-
-                                                    break;
-                                                }
-                                                (PStrContinuable::TailIndex(tail_idx), PStrContinuable::PStrOffset(pos)) => {
-                                                    h = tail_idx + cell_index!(pstr_loc);
-                                                    string_cursor = &string_cursor[pos ..];
-                                                }
-                                                (PStrContinuable::PStrOffset(pos), PStrContinuable::TailIndex(_)) => {
-                                                    self.machine_st.s = HeapPtr::PStr(pstr_loc);
-                                                    self.machine_st.s_offset = pos;
-                                                    self.machine_st.mode = MachineMode::Read;
-
-                                                    break;
-                                                }
-                                                _ => unreachable!(),
-                                            }
-                                        }
-                                        _ => {
-                                            self.machine_st.fail = true;
-                                            break;
-                                        }
-                                    }
-                                }
-                                (HeapCellValueTag::Lis, l) => {
-                                    let cell = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l]));
-
-                                    if let Some(d) = cell.as_char() {
-                                        if c != d {
-                                            self.machine_st.fail = true;
-                                            break;
-                                        }
-                                    } else if let Some(r) = cell.as_var() {
-                                        self.machine_st.bind(r, char_as_cell!(c));
-                                    } else {
-                                        self.machine_st.fail = true;
-                                    }
-
-                                    if self.machine_st.fail {
-                                        break;
-                                    } else {
-                                        h = l+1;
-                                        string_cursor = &string_cursor[c.len_utf8() ..];
-
-                                        if string_cursor.is_empty() {
-                                            self.machine_st.s = HeapPtr::HeapCell(h);
-                                            self.machine_st.s_offset = 0;
-                                            self.machine_st.mode = MachineMode::Read;
-                                        }
-                                    }
-                                }
-                                (HeapCellValueTag::Str, s) => {
-                                    let cell = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[s+1]));
-
-                                    if let Some(d) = cell.as_char() {
-                                        if c != d {
-                                            self.machine_st.fail = true;
-                                            break;
-                                        }
-                                    } else if let Some(r) = cell.as_var() {
-                                        self.machine_st.bind(r, char_as_cell!(c));
-                                    } else {
-                                        self.machine_st.fail = true;
-                                    }
-
-                                    if self.machine_st.fail {
-                                        break;
-                                    }
-
-                                    h = s+2;
-                                    string_cursor = &string_cursor[c.len_utf8() ..];
-
-                                    if string_cursor.is_empty() {
-                                        self.machine_st.s = HeapPtr::HeapCell(h);
-                                        self.machine_st.s_offset = 0;
-                                        self.machine_st.mode = MachineMode::Read;
-                                    }
-                                }
-                                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, v) => {
-                                    if h == v {
-                                        let target_cell = backtrack_on_resource_error!(
-                                            self.machine_st,
-                                            self.machine_st.heap.allocate_pstr(string_cursor)
-                                        );
-
-                                        self.machine_st.bind(
-                                            self.machine_st.heap[h].as_var().unwrap(),
-                                            target_cell,
-                                        );
-
-                                        self.machine_st.mode = MachineMode::Write;
-                                        break;
-                                    } else {
-                                        h = v;
-                                    }
-                                }
-                                _ => {
-                                    self.machine_st.fail = true;
-                                    break;
-                                }
-                            );
-                        }
-
-                        step_or_fail!(self, self.machine_st.p += 1);
-                    }
-                    &Instruction::GetStructure(_lvl, name, 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) => {
-                                read_heap_cell!(self.machine_st.heap[a],
-                                    (HeapCellValueTag::Atom, (result_name, result_arity)) => {
-                                        if arity == result_arity && name == result_name {
-                                            self.machine_st.s = HeapPtr::HeapCell(a + 1);
-                                            self.machine_st.s_offset = 0;
-                                            self.machine_st.mode = MachineMode::Read;
-                                        } else {
-                                            self.machine_st.backtrack();
-                                            continue;
-                                        }
-                                    }
-                                    _ => {
-                                        unreachable!();
-                                    }
-                                );
-                            }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.cell_len();
-
-                                push_cell!(self.machine_st, str_loc_as_cell!(h+1));
-                                push_cell!(self.machine_st, atom_as_cell!(name, arity));
+                            _ => {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                    }
+                    &Instruction::ExecuteIsFloat(r) => {
+                        let d = self
+                            .machine_st
+                            .store(self.machine_st.deref(self.machine_st[r]));
 
-                                self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
-                                self.machine_st.mode = MachineMode::Write;
+                        match Number::try_from((d, &self.machine_st.arena.f64_tbl)) {
+                            Ok(Number::Float(_)) => {
+                                self.machine_st.p = self.machine_st.cp;
                             }
                             _ => {
                                 self.machine_st.backtrack();
-                                continue;
                             }
-                        );
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::GetVariable(norm, arg) => {
-                        self.machine_st[norm] = self.machine_st.registers[arg];
-                        self.machine_st.p += 1;
+                        }
                     }
-                    &Instruction::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);
+                    &Instruction::CallIsNonVar(r) => {
+                        let d = self
+                            .machine_st
+                            .store(self.machine_st.deref(self.machine_st[r]));
 
-                        if self.machine_st.fail {
-                            self.machine_st.backtrack();
-                            continue;
+                        match d.get_tag() {
+                            HeapCellValueTag::AttrVar
+                            | HeapCellValueTag::Var
+                            | HeapCellValueTag::StackVar => {
+                                self.machine_st.backtrack();
+                            }
+                            _ => {
+                                self.machine_st.p += 1;
+                            }
                         }
-
-                        self.machine_st.p += 1;
                     }
-                    &Instruction::UnifyConstant(v) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let (addr, s_offset_incr) = self.machine_st.read_s();
-                                unify!(&mut self.machine_st, addr, v);
+                    &Instruction::ExecuteIsNonVar(r) => {
+                        let d = self
+                            .machine_st
+                            .store(self.machine_st.deref(self.machine_st[r]));
 
-                                if self.machine_st.fail {
-                                    self.machine_st.backtrack();
-                                    continue;
-                                } else {
-                                    self.machine_st.s_offset += s_offset_incr;
-                                }
+                        match d.get_tag() {
+                            HeapCellValueTag::AttrVar
+                            | HeapCellValueTag::Var
+                            | HeapCellValueTag::StackVar => {
+                                self.machine_st.backtrack();
                             }
-                            MachineMode::Write => {
-                                push_cell!(self.machine_st, v);
+                            _ => {
+                                self.machine_st.p = self.machine_st.cp;
                             }
                         }
-
-                        self.machine_st.p += 1;
                     }
-                    &Instruction::UnifyLocalValue(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let reg_addr = self.machine_st[reg];
-                                let (value, s_offset_incr) = self.machine_st.read_s();
-
-                                unify_fn!(&mut self.machine_st, reg_addr, value);
+                    &Instruction::CallIsVar(r) => {
+                        let d = self
+                            .machine_st
+                            .store(self.machine_st.deref(self.machine_st[r]));
 
-                                if self.machine_st.fail {
-                                    self.machine_st.backtrack();
-                                    continue;
-                                } else {
-                                    self.machine_st.s_offset += s_offset_incr;
-                                }
+                        match d.get_tag() {
+                            HeapCellValueTag::AttrVar
+                            | HeapCellValueTag::Var
+                            | HeapCellValueTag::StackVar => {
+                                self.machine_st.p += 1;
                             }
-                            MachineMode::Write => {
-                                let value = self
-                                    .machine_st
-                                    .store(self.machine_st.deref(self.machine_st[reg]));
-                                let h = self.machine_st.heap.cell_len();
-
-                                read_heap_cell!(value,
-                                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
-                                        let value = self.machine_st.heap[hc];
-
-                                        push_cell!(self.machine_st, value);
-                                        self.machine_st.s_offset += 1;
-                                    }
-                                    _ => {
-                                        push_cell!(self.machine_st, heap_loc_as_cell!(h));
-                                        (self.machine_st.bind_fn)(
-                                            &mut self.machine_st,
-                                            Ref::heap_cell(h),
-                                            value,
-                                        );
-                                    }
-                                );
+                            _ => {
+                                self.machine_st.backtrack();
                             }
                         }
-
-                        self.machine_st.p += 1;
                     }
-                    &Instruction::UnifyVariable(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let (value, s_offset_incr) = self.machine_st.read_s();
-                                self.machine_st[reg] = value;
-                                self.machine_st.s_offset += s_offset_incr;
+                    &Instruction::ExecuteIsVar(r) => {
+                        let d = self
+                            .machine_st
+                            .store(self.machine_st.deref(self.machine_st[r]));
+
+                        match d.get_tag() {
+                            HeapCellValueTag::AttrVar
+                            | HeapCellValueTag::Var
+                            | HeapCellValueTag::StackVar => {
+                                self.machine_st.p = self.machine_st.cp;
                             }
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.cell_len();
-                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
-                                self.machine_st[reg] = heap_loc_as_cell!(h);
+                            _ => {
+                                self.machine_st.backtrack();
                             }
                         }
-
-                        self.machine_st.p += 1;
                     }
-                    &Instruction::UnifyValue(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let reg_addr = self.machine_st[reg];
-                                let (value, s_offset_incr) = self.machine_st.read_s();
+                    &Instruction::CallNamed(arity, name, idx) => {
+                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
 
-                                unify_fn!(&mut self.machine_st, reg_addr, value);
+                        try_or_throw!(self.machine_st, self.try_call(name, arity, idx), continue);
 
-                                if self.machine_st.fail {
-                                    self.machine_st.backtrack();
-                                    continue;
-                                } else {
-                                    self.machine_st.s_offset += s_offset_incr;
-                                }
-                            }
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.cell_len();
-                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
+                        if self.machine_st.fail {
+                            self.machine_st.backtrack();
+                        } else {
+                            increment_call_count!(self.machine_st);
+                        }
+                    }
+                    &Instruction::ExecuteNamed(arity, name, idx) => {
+                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
 
-                                let addr = self.machine_st.store(self.machine_st[reg]);
-                                (self.machine_st.bind_fn)(
-                                    &mut self.machine_st,
-                                    Ref::heap_cell(h),
-                                    addr,
-                                );
+                        try_or_throw!(
+                            self.machine_st,
+                            self.try_execute(name, arity, idx),
+                            continue
+                        );
 
-                                // the former code of this match arm was:
+                        if self.machine_st.fail {
+                            self.machine_st.backtrack();
+                        } else {
+                            increment_call_count!(self.machine_st);
+                        }
+                    }
+                    &Instruction::DefaultCallNamed(arity, name, idx) => {
+                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
 
-                                // let addr = self.machine_st.store(self.machine_st[reg]);
-                                // push_cell!(self.machine_st, HeapCellValue::Addr(addr));
+                        try_or_throw!(self.machine_st, self.try_call(name, arity, idx), continue);
 
-                                // 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.
-                            }
+                        if self.machine_st.fail {
+                            self.machine_st.backtrack();
                         }
-
-                        self.machine_st.p += 1;
                     }
-                    &Instruction::UnifyVoid(n) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => match &self.machine_st.s {
-                                HeapPtr::HeapCell(_) => self.machine_st.s_offset += n,
-                                &HeapPtr::PStr(pstr_loc) => {
-                                    debug_assert!(n <= 2);
-                                    let mut char_iter = self.machine_st.heap.char_iter(pstr_loc);
-
-                                    // this only matters in the case that n == 1, but the case
-                                    // analysis isn't worth doing since the effect is benign if n ==
-                                    // 2
-                                    self.machine_st.s_offset +=
-                                        char_iter.next().unwrap().len_utf8();
-                                }
-                            },
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.cell_len();
+                    &Instruction::DefaultExecuteNamed(arity, name, idx) => {
+                        let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
 
-                                for i in h..h + n {
-                                    push_cell!(self.machine_st, heap_loc_as_cell!(i));
-                                }
-                            }
-                        }
+                        try_or_throw!(
+                            self.machine_st,
+                            self.try_execute(name, arity, idx),
+                            continue
+                        );
 
-                        self.machine_st.p += 1;
+                        if self.machine_st.fail {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                    &Instruction::JmpByCall(offset) => {
+                        self.machine_st.p += offset;
+                    }
+                    &Instruction::RevJmpBy(offset) => {
+                        self.machine_st.p -= offset;
+                    }
+                    &Instruction::Proceed => {
+                        self.machine_st.p = self.machine_st.cp;
                     }
                     Instruction::IndexingCode(ref indexing_lines) => {
                         match &indexing_lines[self.machine_st.oip as usize] {
@@ -3362,123 +3852,10 @@ impl Machine {
                             }
                         }
                     }
-                    &Instruction::PutConstant(_, cell, reg) => {
-                        self.machine_st[reg] = cell;
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::PutList(_, reg) => {
-                        self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.cell_len());
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::PutPartialString(_, ref string, reg) => {
-                        self.machine_st[reg] = backtrack_on_resource_error!(
-                            self.machine_st,
-                            self.machine_st.heap.allocate_pstr(string)
-                        );
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::PutStructure(name, arity, reg) => {
-                        let h = self.machine_st.heap.cell_len();
-
-                        push_cell!(self.machine_st, atom_as_cell!(name, arity));
-                        self.machine_st[reg] = str_loc_as_cell!(h);
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::PutUnsafeValue(perm_slot, arg) => {
-                        let s = stack_loc!(AndFrame, self.machine_st.e, perm_slot);
-                        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.cell_len();
-
-                            push_cell!(self.machine_st, 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);
-                        }
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::PutValue(norm, arg) => {
-                        self.machine_st.registers[arg] = self.machine_st[norm];
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::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.cell_len();
-                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
-
-                                self.machine_st[norm] = heap_loc_as_cell!(h);
-                                self.machine_st.registers[arg] = heap_loc_as_cell!(h);
-                            }
-                        };
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::SetConstant(c) => {
-                        push_cell!(self.machine_st, c);
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::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.cell_len();
-                            push_cell!(self.machine_st, heap_loc_as_cell!(h));
-                            (self.machine_st.bind_fn)(
-                                &mut self.machine_st,
-                                Ref::heap_cell(h),
-                                stored_v,
-                            );
-                        } else {
-                            push_cell!(self.machine_st, stored_v);
-                        }
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::SetVariable(reg) => {
-                        let h = self.machine_st.heap.cell_len();
-
-                        push_cell!(self.machine_st, heap_loc_as_cell!(h));
-                        self.machine_st[reg] = heap_loc_as_cell!(h);
-
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::SetValue(reg) => {
-                        let heap_val = self.machine_st.store(self.machine_st[reg]);
-                        push_cell!(self.machine_st, heap_val);
-                        self.machine_st.p += 1;
-                    }
-                    &Instruction::SetVoid(n) => {
-                        let h = self.machine_st.heap.cell_len();
-
-                        for i in h..h + n {
-                            push_cell!(self.machine_st, heap_loc_as_cell!(i));
-                        }
-
-                        self.machine_st.p += 1;
-                    }
                     //
                     &Instruction::CallAtomChars => {
                         self.atom_chars();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteAtomChars => {
                         self.atom_chars();
@@ -3490,7 +3867,7 @@ impl Machine {
                         }
                     }
                     &Instruction::CallAtomCodes => {
-                        try_or_throw!(self.machine_st, self.atom_codes());
+                        try_or_throw!(self.machine_st, self.atom_codes(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -3499,7 +3876,7 @@ impl Machine {
                         }
                     }
                     &Instruction::ExecuteAtomCodes => {
-                        try_or_throw!(self.machine_st, self.atom_codes());
+                        try_or_throw!(self.machine_st, self.atom_codes(), continue);
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -3509,241 +3886,246 @@ impl Machine {
                     }
                     &Instruction::CallAtomLength => {
                         self.atom_length();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteAtomLength => {
                         self.atom_length();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallBindFromRegister => {
                         self.bind_from_register();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteBindFromRegister => {
                         self.bind_from_register();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallContinuation => {
-                        try_or_throw!(self.machine_st, self.call_continuation(false));
+                        try_or_throw!(self.machine_st, self.call_continuation(false), continue);
                     }
                     &Instruction::ExecuteContinuation => {
-                        try_or_throw!(self.machine_st, self.call_continuation(true));
+                        try_or_throw!(self.machine_st, self.call_continuation(true), continue);
                     }
                     &Instruction::CallCharCode => {
-                        try_or_throw!(self.machine_st, self.char_code());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.char_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCharCode => {
-                        try_or_throw!(self.machine_st, self.char_code());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.char_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCharType => {
                         self.char_type();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCharType => {
                         self.char_type();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCharsToNumber => {
-                        try_or_throw!(self.machine_st, self.chars_to_number());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.chars_to_number(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCharsToNumber => {
-                        try_or_throw!(self.machine_st, self.chars_to_number());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.chars_to_number(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCodesToNumber => {
-                        try_or_throw!(self.machine_st, self.codes_to_number());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.codes_to_number(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCodesToNumber => {
-                        try_or_throw!(self.machine_st, self.codes_to_number());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.codes_to_number(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCopyTermWithoutAttrVars => {
                         self.copy_term_without_attr_vars();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCopyTermWithoutAttrVars => {
                         self.copy_term_without_attr_vars();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCheckCutPoint => {
                         self.check_cut_point();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCheckCutPoint => {
                         self.check_cut_point();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallClose => {
-                        try_or_throw!(self.machine_st, self.close());
+                        try_or_throw!(self.machine_st, self.close(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteClose => {
-                        try_or_throw!(self.machine_st, self.close());
+                        try_or_throw!(self.machine_st, self.close(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallCopyToLiftedHeap => {
                         self.copy_to_lifted_heap();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCopyToLiftedHeap => {
                         self.copy_to_lifted_heap();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCreatePartialString => {
                         self.create_partial_string();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCreatePartialString => {
                         self.create_partial_string();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCurrentHostname => {
                         self.current_hostname();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCurrentHostname => {
                         self.current_hostname();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCurrentInput => {
-                        try_or_throw!(self.machine_st, self.current_input());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.current_input(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCurrentInput => {
-                        try_or_throw!(self.machine_st, self.current_input());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.current_input(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCurrentOutput => {
-                        try_or_throw!(self.machine_st, self.current_output());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.current_output(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCurrentOutput => {
-                        try_or_throw!(self.machine_st, self.current_output());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.current_output(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDirectoryFiles => {
-                        try_or_throw!(self.machine_st, self.directory_files());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.directory_files(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDirectoryFiles => {
-                        try_or_throw!(self.machine_st, self.directory_files());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.directory_files(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFileSize => {
                         self.file_size();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFileSize => {
                         self.file_size();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFileExists => {
                         self.file_exists();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFileExists => {
                         self.file_exists();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDirectoryExists => {
                         self.directory_exists();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDirectoryExists => {
                         self.directory_exists();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDirectorySeparator => {
                         self.directory_separator();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDirectorySeparator => {
                         self.directory_separator();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallMakeDirectory => {
                         self.make_directory();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteMakeDirectory => {
                         self.make_directory();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallMakeDirectoryPath => {
                         self.make_directory_path();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteMakeDirectoryPath => {
                         self.make_directory_path();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDeleteFile => {
                         self.delete_file();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDeleteFile => {
                         self.delete_file();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallRenameFile => {
                         self.rename_file();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteRenameFile => {
                         self.rename_file();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFileCopy => {
                         self.file_copy();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFileCopy => {
                         self.file_copy();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallWorkingDirectory => {
-                        try_or_throw!(self.machine_st, self.working_directory());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.working_directory(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteWorkingDirectory => {
-                        try_or_throw!(self.machine_st, self.working_directory());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.working_directory(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDeleteDirectory => {
                         self.delete_directory();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDeleteDirectory => {
                         self.delete_directory();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPathCanonical => {
-                        try_or_throw!(self.machine_st, self.path_canonical());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.path_canonical(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePathCanonical => {
-                        try_or_throw!(self.machine_st, self.path_canonical());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.path_canonical(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFileTime => {
                         self.file_time();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFileTime => {
                         self.file_time();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDynamicModuleResolution(arity) => {
                         let (module_name, key) = try_or_throw!(
                             self.machine_st,
-                            self.dynamic_module_resolution(arity - 2)
+                            self.dynamic_module_resolution(arity - 2),
+                            continue
                         );
 
-                        try_or_throw!(self.machine_st, self.call_clause(module_name, key));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.call_clause(module_name, key),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -3752,10 +4134,15 @@ impl Machine {
                     &Instruction::ExecuteDynamicModuleResolution(arity) => {
                         let (module_name, key) = try_or_throw!(
                             self.machine_st,
-                            self.dynamic_module_resolution(arity - 2)
+                            self.dynamic_module_resolution(arity - 2),
+                            continue
                         );
 
-                        try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.execute_clause(module_name, key),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -3763,384 +4150,384 @@ impl Machine {
                     }
                     &Instruction::CallFetchGlobalVar => {
                         self.fetch_global_var();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFetchGlobalVar => {
                         self.fetch_global_var();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFirstStream => {
                         self.first_stream();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFirstStream => {
                         self.first_stream();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFlushOutput => {
-                        try_or_throw!(self.machine_st, self.flush_output());
+                        try_or_throw!(self.machine_st, self.flush_output(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteFlushOutput => {
-                        try_or_throw!(self.machine_st, self.flush_output());
+                        try_or_throw!(self.machine_st, self.flush_output(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallGetByte => {
-                        try_or_throw!(self.machine_st, self.get_byte());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.get_byte(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetByte => {
-                        try_or_throw!(self.machine_st, self.get_byte());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.get_byte(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetChar => {
-                        try_or_throw!(self.machine_st, self.get_char());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.get_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetChar => {
-                        try_or_throw!(self.machine_st, self.get_char());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.get_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetNChars => {
-                        try_or_throw!(self.machine_st, self.get_n_chars());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.get_n_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetNChars => {
-                        try_or_throw!(self.machine_st, self.get_n_chars());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.get_n_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetCode => {
-                        try_or_throw!(self.machine_st, self.get_code());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.get_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetCode => {
-                        try_or_throw!(self.machine_st, self.get_code());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.get_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetSingleChar => {
-                        try_or_throw!(self.machine_st, self.get_single_char());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.get_single_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetSingleChar => {
-                        try_or_throw!(self.machine_st, self.get_single_char());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.get_single_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff => {
                         self.truncate_if_no_lifted_heap_growth_diff();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff => {
                         self.truncate_if_no_lifted_heap_growth_diff();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTruncateIfNoLiftedHeapGrowth => {
                         self.truncate_if_no_lifted_heap_growth();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth => {
                         self.truncate_if_no_lifted_heap_growth();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetAttributedVariableList => {
                         self.get_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetAttributedVariableList => {
                         self.get_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetAttrVarQueueDelimiter => {
                         self.get_attr_var_queue_delimiter();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetAttrVarQueueDelimiter => {
                         self.get_attr_var_queue_delimiter();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetAttrVarQueueBeyond => {
                         self.get_attr_var_queue_beyond();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetAttrVarQueueBeyond => {
                         self.get_attr_var_queue_beyond();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetBValue => {
                         self.get_b_value();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetBValue => {
                         self.get_b_value();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetContinuationChunk => {
                         self.get_continuation_chunk();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetContinuationChunk => {
                         self.get_continuation_chunk();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLookupDBRef => {
                         self.lookup_db_ref();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLookupDBRef => {
                         self.lookup_db_ref();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetNextOpDBRef => {
                         self.get_next_op_db_ref();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetNextOpDBRef => {
                         self.get_next_op_db_ref();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallIsPartialString => {
                         self.is_partial_string();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteIsPartialString => {
                         self.is_partial_string();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHalt | &Instruction::ExecuteHalt => {
                         return self.halt();
                     }
                     &Instruction::CallGetLiftedHeapFromOffset => {
                         self.get_lifted_heap_from_offset();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetLiftedHeapFromOffset => {
                         self.get_lifted_heap_from_offset();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetLiftedHeapFromOffsetDiff => {
                         self.get_lifted_heap_from_offset_diff();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetLiftedHeapFromOffsetDiff => {
                         self.get_lifted_heap_from_offset_diff();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetSCCCleaner => {
                         self.get_scc_cleaner();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetSCCCleaner => {
                         self.get_scc_cleaner();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHeadIsDynamic => {
                         self.head_is_dynamic();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHeadIsDynamic => {
                         self.head_is_dynamic();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInstallSCCCleaner => {
                         self.install_scc_cleaner();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInstallSCCCleaner => {
                         self.install_scc_cleaner();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInstallInferenceCounter => {
-                        try_or_throw!(self.machine_st, self.install_inference_counter());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.install_inference_counter(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInstallInferenceCounter => {
-                        try_or_throw!(self.machine_st, self.install_inference_counter());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.install_inference_counter(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInferenceCount => {
                         let global_count = self.machine_st.cwil.global_count.clone();
                         self.inference_count(self.machine_st.registers[1], global_count);
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInferenceCount => {
                         let global_count = self.machine_st.cwil.global_count.clone();
                         self.inference_count(self.machine_st.registers[1], global_count);
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLiftedHeapLength => {
                         self.lifted_heap_length();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLiftedHeapLength => {
                         self.lifted_heap_length();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadLibraryAsStream => {
-                        try_or_throw!(self.machine_st, self.load_library_as_stream());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.load_library_as_stream(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadLibraryAsStream => {
-                        try_or_throw!(self.machine_st, self.load_library_as_stream());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.load_library_as_stream(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallModuleExists => {
                         self.module_exists();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteModuleExists => {
                         self.module_exists();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallNextEP => {
                         self.next_ep();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteNextEP => {
                         self.next_ep();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallNoSuchPredicate => {
-                        try_or_throw!(self.machine_st, self.no_such_predicate());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.no_such_predicate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteNoSuchPredicate => {
-                        try_or_throw!(self.machine_st, self.no_such_predicate());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.no_such_predicate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallNumberToChars => {
                         self.number_to_chars();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteNumberToChars => {
                         self.number_to_chars();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallNumberToCodes => {
                         self.number_to_codes();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteNumberToCodes => {
                         self.number_to_codes();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallOpDeclaration => {
-                        try_or_throw!(self.machine_st, self.op_declaration());
+                        try_or_throw!(self.machine_st, self.op_declaration(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteOpDeclaration => {
-                        try_or_throw!(self.machine_st, self.op_declaration());
+                        try_or_throw!(self.machine_st, self.op_declaration(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallOpen => {
-                        try_or_throw!(self.machine_st, self.open());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteOpen => {
-                        try_or_throw!(self.machine_st, self.open());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetStreamOptions => {
-                        try_or_throw!(self.machine_st, self.set_stream_options());
+                        try_or_throw!(self.machine_st, self.set_stream_options(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteSetStreamOptions => {
-                        try_or_throw!(self.machine_st, self.set_stream_options());
+                        try_or_throw!(self.machine_st, self.set_stream_options(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallNextStream => {
                         self.next_stream();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteNextStream => {
                         self.next_stream();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPartialStringTail => {
                         self.partial_string_tail();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePartialStringTail => {
                         self.partial_string_tail();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPeekByte => {
-                        try_or_throw!(self.machine_st, self.peek_byte());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.peek_byte(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePeekByte => {
-                        try_or_throw!(self.machine_st, self.peek_byte());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.peek_byte(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPeekChar => {
-                        try_or_throw!(self.machine_st, self.peek_char());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.peek_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePeekChar => {
-                        try_or_throw!(self.machine_st, self.peek_char());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.peek_char(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPeekCode => {
-                        try_or_throw!(self.machine_st, self.peek_code());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.peek_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePeekCode => {
-                        try_or_throw!(self.machine_st, self.peek_code());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.peek_code(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPointsToContinuationResetMarker => {
                         self.points_to_continuation_reset_marker();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePointsToContinuationResetMarker => {
                         self.points_to_continuation_reset_marker();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPutByte => {
-                        try_or_throw!(self.machine_st, self.put_byte());
+                        try_or_throw!(self.machine_st, self.put_byte(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecutePutByte => {
-                        try_or_throw!(self.machine_st, self.put_byte());
+                        try_or_throw!(self.machine_st, self.put_byte(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallPutChar => {
-                        try_or_throw!(self.machine_st, self.put_char());
+                        try_or_throw!(self.machine_st, self.put_char(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecutePutChar => {
-                        try_or_throw!(self.machine_st, self.put_char());
+                        try_or_throw!(self.machine_st, self.put_char(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallPutChars => {
-                        try_or_throw!(self.machine_st, self.put_chars());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.put_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePutChars => {
-                        try_or_throw!(self.machine_st, self.put_chars());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.put_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPutCode => {
-                        try_or_throw!(self.machine_st, self.put_code());
+                        try_or_throw!(self.machine_st, self.put_code(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecutePutCode => {
-                        try_or_throw!(self.machine_st, self.put_code());
+                        try_or_throw!(self.machine_st, self.put_code(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallReadQueryTerm => {
-                        try_or_throw!(self.machine_st, self.read_query_term());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.read_query_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteReadQueryTerm => {
-                        try_or_throw!(self.machine_st, self.read_query_term());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.read_query_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallReadTerm => {
-                        try_or_throw!(self.machine_st, self.read_term());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.read_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteReadTerm => {
-                        try_or_throw!(self.machine_st, self.read_term());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.read_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallRedoAttrVarBinding => {
                         self.redo_attr_var_binding();
@@ -4160,11 +4547,11 @@ impl Machine {
                     }
                     &Instruction::CallRemoveInferenceCounter => {
                         self.remove_inference_counter();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteRemoveInferenceCounter => {
                         self.remove_inference_counter();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallResetContinuationMarker => {
                         self.reset_continuation_marker();
@@ -4184,14 +4571,14 @@ impl Machine {
                     }
                     &Instruction::CallSetCutPoint(r) => {
                         if !self.set_cut_point(r) {
-                            step_or_fail!(self, self.machine_st.p += 1);
+                            step_or_fail!(self.machine_st, self.machine_st.p += 1);
                         }
                     }
                     &Instruction::ExecuteSetCutPoint(r) => {
                         let cp = self.machine_st.cp;
 
                         if !self.set_cut_point(r) {
-                            step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                            step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                         } else {
                             // run_cleaners in set_cut_point calls call_by_index.
                             // replace the effect of call_by_index with that
@@ -4201,19 +4588,19 @@ impl Machine {
                         }
                     }
                     &Instruction::CallSetInput => {
-                        try_or_throw!(self.machine_st, self.set_input());
+                        try_or_throw!(self.machine_st, self.set_input(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteSetInput => {
-                        try_or_throw!(self.machine_st, self.set_input());
+                        try_or_throw!(self.machine_st, self.set_input(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallSetOutput => {
-                        try_or_throw!(self.machine_st, self.set_output());
+                        try_or_throw!(self.machine_st, self.set_output(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteSetOutput => {
-                        try_or_throw!(self.machine_st, self.set_output());
+                        try_or_throw!(self.machine_st, self.set_output(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallStoreBacktrackableGlobalVar => {
@@ -4233,28 +4620,28 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallStreamProperty => {
-                        try_or_throw!(self.machine_st, self.stream_property());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.stream_property(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteStreamProperty => {
-                        try_or_throw!(self.machine_st, self.stream_property());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.stream_property(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetStreamPosition => {
-                        try_or_throw!(self.machine_st, self.set_stream_position());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.set_stream_position(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetStreamPosition => {
-                        try_or_throw!(self.machine_st, self.set_stream_position());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.set_stream_position(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInferenceLevel => {
                         self.inference_level();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInferenceLevel => {
                         self.inference_level();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCleanUpBlock => {
                         self.clean_up_block();
@@ -4269,245 +4656,245 @@ impl Machine {
                     }
                     &Instruction::CallGetBall => {
                         self.get_ball();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetBall => {
                         self.get_ball();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetCurrentBlock => {
                         self.get_current_block();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetCurrentBlock => {
                         self.get_current_block();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetCurrentSCCBlock => {
                         self.get_current_scc_block();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetCurrentSCCBlock => {
                         self.get_current_scc_block();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetCutPoint => {
                         self.get_cut_point();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetCutPoint => {
                         self.get_cut_point();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetDoubleQuotes => {
                         self.get_double_quotes();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetDoubleQuotes => {
                         self.get_double_quotes();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetUnknown => {
                         self.get_unknown();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetUnknown => {
                         self.get_unknown();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInstallNewBlock => {
                         self.machine_st
                             .install_new_block(self.machine_st.registers[1]);
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInstallNewBlock => {
                         self.machine_st
                             .install_new_block(self.machine_st.registers[1]);
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallRandomInteger => {
                         self.random_integer();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteRandomInteger => {
                         self.random_integer();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallMaybe => {
                         self.maybe();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteMaybe => {
                         self.maybe();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCpuNow => {
                         self.cpu_now();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCpuNow => {
                         self.cpu_now();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDeterministicLengthRundown => {
-                        try_or_throw!(self.machine_st, self.det_length_rundown());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.det_length_rundown(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDeterministicLengthRundown => {
-                        try_or_throw!(self.machine_st, self.det_length_rundown());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.det_length_rundown(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHttpOpen => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_open());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.http_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHttpOpen => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_open());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.http_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHttpListen => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_listen());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.http_listen(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHttpListen => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_listen());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.http_listen(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHttpAccept => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_accept());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.http_accept(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHttpAccept => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_accept());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.http_accept(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallHttpAnswer => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_answer());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.http_answer(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHttpAnswer => {
                         #[cfg(feature = "http")]
-                        try_or_throw!(self.machine_st, self.http_answer());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.http_answer(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadForeignLib => {
-                        try_or_throw!(self.machine_st, self.load_foreign_lib());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.load_foreign_lib(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadForeignLib => {
-                        try_or_throw!(self.machine_st, self.load_foreign_lib());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.load_foreign_lib(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallForeignCall => {
-                        try_or_throw!(self.machine_st, self.foreign_call());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.foreign_call(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteForeignCall => {
-                        try_or_throw!(self.machine_st, self.foreign_call());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.foreign_call(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDefineForeignStruct => {
-                        try_or_throw!(self.machine_st, self.define_foreign_struct());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.define_foreign_struct(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDefineForeignStruct => {
-                        try_or_throw!(self.machine_st, self.define_foreign_struct());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.define_foreign_struct(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFfiAllocate => {
-                        try_or_throw!(self.machine_st, self.ffi_allocate());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.ffi_allocate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFfiAllocate => {
-                        try_or_throw!(self.machine_st, self.ffi_allocate());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.ffi_allocate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFfiReadPtr => {
-                        try_or_throw!(self.machine_st, self.ffi_read_ptr());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.ffi_read_ptr(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFfiReadPtr => {
-                        try_or_throw!(self.machine_st, self.ffi_read_ptr());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.ffi_read_ptr(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFfiDeallocate => {
-                        try_or_throw!(self.machine_st, self.ffi_deallocate());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.ffi_deallocate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFfiDeallocate => {
-                        try_or_throw!(self.machine_st, self.ffi_deallocate());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.ffi_deallocate(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallJsEval => {
-                        try_or_throw!(self.machine_st, self.js_eval());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.js_eval(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteJsEval => {
-                        try_or_throw!(self.machine_st, self.js_eval());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.js_eval(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallArgv => {
-                        try_or_throw!(self.machine_st, self.argv());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.argv(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteArgv => {
-                        try_or_throw!(self.machine_st, self.argv());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.argv(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCurrentTime => {
                         self.current_time();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCurrentTime => {
                         self.current_time();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallQuotedToken => {
                         self.quoted_token();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteQuotedToken => {
                         self.quoted_token();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallReadFromChars => {
-                        try_or_throw!(self.machine_st, self.read_from_chars());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.read_from_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteReadFromChars => {
-                        try_or_throw!(self.machine_st, self.read_from_chars());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.read_from_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallReadTermFromChars => {
-                        try_or_throw!(self.machine_st, self.read_term_from_chars());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.read_term_from_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteReadTermFromChars => {
-                        try_or_throw!(self.machine_st, self.read_term_from_chars());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.read_term_from_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallResetBlock => {
                         self.reset_block();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteResetBlock => {
                         self.reset_block();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallResetSCCBlock => {
                         self.reset_scc_block();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteResetSCCBlock => {
                         self.reset_scc_block();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallReturnFromVerifyAttr
                     | &Instruction::ExecuteReturnFromVerifyAttr => {
@@ -4515,19 +4902,19 @@ impl Machine {
                     }
                     &Instruction::CallSetBall => {
                         self.set_ball();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetBall => {
                         self.set_ball();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPushBallStack => {
                         self.push_ball_stack();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePushBallStack => {
                         self.push_ball_stack();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPopBallStack => {
                         self.pop_ball_stack();
@@ -4547,43 +4934,43 @@ impl Machine {
                     }
                     &Instruction::CallSetCutPointByDefault(r) => {
                         self.set_cut_point_by_default(r);
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetCutPointByDefault(r) => {
                         self.set_cut_point_by_default(r);
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetDoubleQuotes => {
                         self.set_double_quotes();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetDoubleQuotes => {
                         self.set_double_quotes();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetUnknown => {
                         self.set_unknown();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetUnknown => {
                         self.set_unknown();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetSeed => {
                         self.set_seed();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetSeed => {
                         self.set_seed();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSkipMaxList => {
-                        try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.machine_st.skip_max_list(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSkipMaxList => {
-                        try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.machine_st.skip_max_list(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSleep => {
                         self.sleep();
@@ -4594,56 +4981,56 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallSocketClientOpen => {
-                        try_or_throw!(self.machine_st, self.socket_client_open());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.socket_client_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSocketClientOpen => {
-                        try_or_throw!(self.machine_st, self.socket_client_open());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.socket_client_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSocketServerOpen => {
-                        try_or_throw!(self.machine_st, self.socket_server_open());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.socket_server_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSocketServerOpen => {
-                        try_or_throw!(self.machine_st, self.socket_server_open());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.socket_server_open(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSocketServerAccept => {
-                        try_or_throw!(self.machine_st, self.socket_server_accept());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.socket_server_accept(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSocketServerAccept => {
-                        try_or_throw!(self.machine_st, self.socket_server_accept());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.socket_server_accept(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSocketServerClose => {
-                        try_or_throw!(self.machine_st, self.socket_server_close());
+                        try_or_throw!(self.machine_st, self.socket_server_close(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteSocketServerClose => {
-                        try_or_throw!(self.machine_st, self.socket_server_close());
+                        try_or_throw!(self.machine_st, self.socket_server_close(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallTLSAcceptClient => {
                         #[cfg(feature = "tls")]
-                        try_or_throw!(self.machine_st, self.tls_accept_client());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.tls_accept_client(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTLSAcceptClient => {
                         #[cfg(feature = "tls")]
-                        try_or_throw!(self.machine_st, self.tls_accept_client());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.tls_accept_client(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTLSClientConnect => {
                         #[cfg(feature = "tls")]
-                        try_or_throw!(self.machine_st, self.tls_client_connect());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.tls_client_connect(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTLSClientConnect => {
                         #[cfg(feature = "tls")]
-                        try_or_throw!(self.machine_st, self.tls_client_connect());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.tls_client_connect(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSucceed => {
                         self.machine_st.p += 1;
@@ -4653,27 +5040,27 @@ impl Machine {
                     }
                     &Instruction::CallTermAttributedVariables => {
                         self.term_attributed_variables();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTermAttributedVariables => {
                         self.term_attributed_variables();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTermVariables => {
                         self.term_variables();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTermVariables => {
                         self.term_variables();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTermVariablesUnderMaxDepth => {
                         self.term_variables_under_max_depth();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteTermVariablesUnderMaxDepth => {
                         self.term_variables_under_max_depth();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallTruncateLiftedHeapTo => {
                         self.truncate_lifted_heap_to();
@@ -4685,11 +5072,11 @@ impl Machine {
                     }
                     &Instruction::CallUnifyWithOccursCheck => {
                         self.unify_with_occurs_check();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteUnifyWithOccursCheck => {
                         self.unify_with_occurs_check();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallUnwindEnvironments => {
                         if !self.unwind_environments() {
@@ -4706,12 +5093,12 @@ impl Machine {
                         self.machine_st.backtrack();
                     }
                     &Instruction::CallWAMInstructions => {
-                        try_or_throw!(self.machine_st, self.wam_instructions());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.wam_instructions(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteWAMInstructions => {
-                        try_or_throw!(self.machine_st, self.wam_instructions());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.wam_instructions(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInlinedInstructions => {
                         self.inlined_instructions();
@@ -4722,256 +5109,256 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallWriteTerm => {
-                        try_or_throw!(self.machine_st, self.write_term());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.write_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteWriteTerm => {
-                        try_or_throw!(self.machine_st, self.write_term());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.write_term(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallWriteTermToChars => {
-                        try_or_throw!(self.machine_st, self.write_term_to_chars());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.write_term_to_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteWriteTermToChars => {
-                        try_or_throw!(self.machine_st, self.write_term_to_chars());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.write_term_to_chars(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallScryerPrologVersion => {
                         self.scryer_prolog_version();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteScryerPrologVersion => {
                         self.scryer_prolog_version();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoRandomByte => {
                         self.crypto_random_byte();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoRandomByte => {
                         self.crypto_random_byte();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoDataHash => {
                         self.crypto_data_hash();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoDataHash => {
                         self.crypto_data_hash();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoHMAC => {
                         self.crypto_hmac();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoHMAC => {
                         self.crypto_hmac();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoDataHKDF => {
                         self.crypto_data_hkdf();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoDataHKDF => {
                         self.crypto_data_hkdf();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoPasswordHash => {
                         self.crypto_password_hash();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoPasswordHash => {
                         self.crypto_password_hash();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     #[cfg(feature = "crypto-full")]
                     &Instruction::CallCryptoDataEncrypt => {
                         self.crypto_data_encrypt();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     #[cfg(feature = "crypto-full")]
                     &Instruction::ExecuteCryptoDataEncrypt => {
                         self.crypto_data_encrypt();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     #[cfg(feature = "crypto-full")]
                     &Instruction::CallCryptoDataDecrypt => {
                         self.crypto_data_decrypt();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     #[cfg(feature = "crypto-full")]
                     &Instruction::ExecuteCryptoDataDecrypt => {
                         self.crypto_data_decrypt();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallBeta => {
                         self.beta();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteBeta => {
                         self.beta();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallBetaI => {
                         self.betai();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteBetaI => {
                         self.betai();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInvBetaI => {
                         self.invbetai();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInvBetaI => {
                         self.invbetai();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGamma => {
                         self.gamma();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGamma => {
                         self.gamma();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLnGamma => {
                         self.ln_gamma();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLnGamma => {
                         self.ln_gamma();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGammP => {
                         self.gammp();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGammP => {
                         self.gammp();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInvGammP => {
                         self.invgammp();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInvGammP => {
                         self.invgammp();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGammQ => {
                         self.gammq();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGammQ => {
                         self.gammq();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallErf => {
                         self.erf();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteErf => {
                         self.erf();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallErfc => {
                         self.erfc();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteErfc => {
                         self.erfc();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInvErf => {
                         self.inverf();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInvErf => {
                         self.inverf();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInvErfc => {
                         self.inverfc();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInvErfc => {
                         self.inverfc();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCryptoCurveScalarMult => {
                         self.crypto_curve_scalar_mult();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCryptoCurveScalarMult => {
                         self.crypto_curve_scalar_mult();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallEd25519SignRaw => {
                         self.ed25519_sign_raw();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteEd25519SignRaw => {
                         self.ed25519_sign_raw();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallEd25519VerifyRaw => {
                         self.ed25519_verify_raw();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteEd25519VerifyRaw => {
                         self.ed25519_verify_raw();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallEd25519SeedToPublicKey => {
                         self.ed25519_seed_to_public_key();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteEd25519SeedToPublicKey => {
                         self.ed25519_seed_to_public_key();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCurve25519ScalarMult => {
                         self.curve25519_scalar_mult();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCurve25519ScalarMult => {
                         self.curve25519_scalar_mult();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFirstNonOctet => {
                         self.first_non_octet();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteFirstNonOctet => {
                         self.first_non_octet();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadHTML => {
-                        backtrack_on_resource_error!(self.machine_st, self.load_html());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        backtrack_on_resource_error!(self.machine_st, self.load_html(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadHTML => {
-                        backtrack_on_resource_error!(self.machine_st, self.load_html());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        backtrack_on_resource_error!(self.machine_st, self.load_html(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadXML => {
-                        backtrack_on_resource_error!(self.machine_st, self.load_xml());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        backtrack_on_resource_error!(self.machine_st, self.load_xml(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadXML => {
-                        backtrack_on_resource_error!(self.machine_st, self.load_xml());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        backtrack_on_resource_error!(self.machine_st, self.load_xml(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetEnv => {
                         self.get_env();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetEnv => {
                         self.get_env();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetEnv => {
                         self.set_env();
@@ -4991,83 +5378,83 @@ impl Machine {
                     }
                     &Instruction::CallShell => {
                         self.shell();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteShell => {
                         self.shell();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallProcessCreate => {
-                        try_or_throw!(self.machine_st, self.process_create());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.process_create(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteProcessCreate => {
-                        try_or_throw!(self.machine_st, self.process_create());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.process_create(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallProcessId => {
-                        try_or_throw!(self.machine_st, self.process_id());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.process_id(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteProcessId => {
-                        try_or_throw!(self.machine_st, self.process_id());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.process_id(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallProcessWait => {
-                        try_or_throw!(self.machine_st, self.process_wait());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.process_wait(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteProcessWait => {
-                        try_or_throw!(self.machine_st, self.process_wait());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.process_wait(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallProcessKill => {
-                        try_or_throw!(self.machine_st, self.process_kill());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.process_kill(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteProcessKill => {
-                        try_or_throw!(self.machine_st, self.process_kill());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.process_kill(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallProcessRelease => {
-                        try_or_throw!(self.machine_st, self.process_release());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.process_release(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteProcessRelease => {
-                        try_or_throw!(self.machine_st, self.process_release());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.process_release(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPid => {
                         self.pid();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePid => {
                         self.pid();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCharsBase64 => {
-                        try_or_throw!(self.machine_st, self.chars_base64());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.chars_base64(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCharsBase64 => {
-                        try_or_throw!(self.machine_st, self.chars_base64());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.chars_base64(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDevourWhitespace => {
-                        try_or_throw!(self.machine_st, self.devour_whitespace());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.devour_whitespace(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDevourWhitespace => {
-                        try_or_throw!(self.machine_st, self.devour_whitespace());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.devour_whitespace(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallIsSTOEnabled => {
                         self.is_sto_enabled();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteIsSTOEnabled => {
                         self.is_sto_enabled();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallSetSTOAsUnify => {
                         self.set_sto_as_unify();
@@ -5095,11 +5482,11 @@ impl Machine {
                     }
                     &Instruction::CallHomeDirectory => {
                         self.home_directory();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteHomeDirectory => {
                         self.home_directory();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDebugHook => {
                         self.debug_hook();
@@ -5111,139 +5498,155 @@ impl Machine {
                     }
                     &Instruction::CallPopCount => {
                         self.pop_count();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePopCount => {
                         self.pop_count();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallAddDiscontiguousPredicate => {
-                        try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_discontiguous_predicate(),
+                            continue
+                        );
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddDiscontiguousPredicate => {
-                        try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_discontiguous_predicate(),
+                            continue
+                        );
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddDynamicPredicate => {
-                        try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+                        try_or_throw!(self.machine_st, self.add_dynamic_predicate(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddDynamicPredicate => {
-                        try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+                        try_or_throw!(self.machine_st, self.add_dynamic_predicate(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddMultifilePredicate => {
-                        try_or_throw!(self.machine_st, self.add_multifile_predicate());
+                        try_or_throw!(self.machine_st, self.add_multifile_predicate(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddMultifilePredicate => {
-                        try_or_throw!(self.machine_st, self.add_multifile_predicate());
+                        try_or_throw!(self.machine_st, self.add_multifile_predicate(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddGoalExpansionClause => {
-                        try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+                        try_or_throw!(self.machine_st, self.add_goal_expansion_clause(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddGoalExpansionClause => {
-                        try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+                        try_or_throw!(self.machine_st, self.add_goal_expansion_clause(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddTermExpansionClause => {
-                        try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+                        try_or_throw!(self.machine_st, self.add_term_expansion_clause(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddTermExpansionClause => {
-                        try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+                        try_or_throw!(self.machine_st, self.add_term_expansion_clause(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddInSituFilenameModule => {
-                        try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_in_situ_filename_module(),
+                            continue
+                        );
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddInSituFilenameModule => {
-                        try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_in_situ_filename_module(),
+                            continue
+                        );
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallClauseToEvacuable => {
-                        try_or_throw!(self.machine_st, self.clause_to_evacuable());
+                        try_or_throw!(self.machine_st, self.clause_to_evacuable(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteClauseToEvacuable => {
-                        try_or_throw!(self.machine_st, self.clause_to_evacuable());
+                        try_or_throw!(self.machine_st, self.clause_to_evacuable(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallScopedClauseToEvacuable => {
-                        try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+                        try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteScopedClauseToEvacuable => {
-                        try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+                        try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallConcludeLoad => {
-                        try_or_throw!(self.machine_st, self.conclude_load());
+                        try_or_throw!(self.machine_st, self.conclude_load(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteConcludeLoad => {
-                        try_or_throw!(self.machine_st, self.conclude_load());
+                        try_or_throw!(self.machine_st, self.conclude_load(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallDeclareModule => {
-                        try_or_throw!(self.machine_st, self.declare_module());
+                        try_or_throw!(self.machine_st, self.declare_module(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteDeclareModule => {
-                        try_or_throw!(self.machine_st, self.declare_module());
+                        try_or_throw!(self.machine_st, self.declare_module(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallLoadCompiledLibrary => {
-                        try_or_throw!(self.machine_st, self.load_compiled_library());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.load_compiled_library(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadCompiledLibrary => {
-                        try_or_throw!(self.machine_st, self.load_compiled_library());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.load_compiled_library(), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadContextSource => {
                         self.load_context_source();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadContextSource => {
                         self.load_context_source();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadContextFile => {
                         self.load_context_file();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadContextFile => {
                         self.load_context_file();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadContextDirectory => {
                         self.load_context_directory();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadContextDirectory => {
                         self.load_context_directory();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadContextModule => {
                         self.load_context_module(self.deref_register(1));
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadContextModule => {
                         self.load_context_module(self.deref_register(1));
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadContextStream => {
                         self.load_context_stream();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadContextStream => {
                         self.load_context_stream();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPopLoadContext => {
                         self.pop_load_context();
@@ -5262,27 +5665,27 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallPushLoadContext => {
-                        try_or_throw!(self.machine_st, self.push_load_context());
+                        try_or_throw!(self.machine_st, self.push_load_context(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecutePushLoadContext => {
-                        try_or_throw!(self.machine_st, self.push_load_context());
+                        try_or_throw!(self.machine_st, self.push_load_context(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallPushLoadStatePayload => {
                         self.push_load_state_payload();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePushLoadStatePayload => {
                         self.push_load_state_payload();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallUseModule => {
-                        try_or_throw!(self.machine_st, self.use_module());
+                        try_or_throw!(self.machine_st, self.use_module(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteUseModule => {
-                        try_or_throw!(self.machine_st, self.use_module());
+                        try_or_throw!(self.machine_st, self.use_module(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallBuiltInProperty => {
@@ -5292,7 +5695,7 @@ impl Machine {
                         );
 
                         self.machine_st.fail = !self.indices.builtin_property(key);
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteBuiltInProperty => {
                         let key = self.machine_st.read_predicate_key(
@@ -5301,161 +5704,193 @@ impl Machine {
                         );
 
                         self.machine_st.fail = !self.indices.builtin_property(key);
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallMetaPredicateProperty => {
                         self.meta_predicate_property();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteMetaPredicateProperty => {
                         self.meta_predicate_property();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallMultifileProperty => {
                         self.multifile_property();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteMultifileProperty => {
                         self.multifile_property();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDiscontiguousProperty => {
                         self.discontiguous_property();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDiscontiguousProperty => {
                         self.discontiguous_property();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDynamicProperty => {
                         self.dynamic_property();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDynamicProperty => {
                         self.dynamic_property();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallAbolishClause => {
-                        try_or_throw!(self.machine_st, self.abolish_clause());
+                        try_or_throw!(self.machine_st, self.abolish_clause(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAbolishClause => {
-                        try_or_throw!(self.machine_st, self.abolish_clause());
+                        try_or_throw!(self.machine_st, self.abolish_clause(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAsserta => {
                         try_or_throw!(
                             self.machine_st,
-                            self.compile_assert(AppendOrPrepend::Prepend)
+                            self.compile_assert(AppendOrPrepend::Prepend),
+                            continue
                         );
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAsserta => {
                         try_or_throw!(
                             self.machine_st,
-                            self.compile_assert(AppendOrPrepend::Prepend)
+                            self.compile_assert(AppendOrPrepend::Prepend),
+                            continue
                         );
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAssertz => {
                         try_or_throw!(
                             self.machine_st,
-                            self.compile_assert(AppendOrPrepend::Append)
+                            self.compile_assert(AppendOrPrepend::Append),
+                            continue
                         );
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAssertz => {
                         try_or_throw!(
                             self.machine_st,
-                            self.compile_assert(AppendOrPrepend::Append)
+                            self.compile_assert(AppendOrPrepend::Append),
+                            continue
                         );
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallRetract => {
-                        try_or_throw!(self.machine_st, self.retract_clause());
+                        try_or_throw!(self.machine_st, self.retract_clause(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteRetract => {
-                        try_or_throw!(self.machine_st, self.retract_clause());
+                        try_or_throw!(self.machine_st, self.retract_clause(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallIsConsistentWithTermQueue => {
-                        try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(
+                            self.machine_st,
+                            self.is_consistent_with_term_queue(),
+                            continue
+                        );
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteIsConsistentWithTermQueue => {
-                        try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(
+                            self.machine_st,
+                            self.is_consistent_with_term_queue(),
+                            continue
+                        );
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::CallFlushTermQueue => {
-                        try_or_throw!(self.machine_st, self.flush_term_queue());
+                        try_or_throw!(self.machine_st, self.flush_term_queue(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteFlushTermQueue => {
-                        try_or_throw!(self.machine_st, self.flush_term_queue());
+                        try_or_throw!(self.machine_st, self.flush_term_queue(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallRemoveModuleExports => {
-                        try_or_throw!(self.machine_st, self.remove_module_exports());
+                        try_or_throw!(self.machine_st, self.remove_module_exports(), continue);
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteRemoveModuleExports => {
-                        try_or_throw!(self.machine_st, self.remove_module_exports());
+                        try_or_throw!(self.machine_st, self.remove_module_exports(), continue);
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallAddNonCountedBacktracking => {
-                        try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_non_counted_backtracking(),
+                            continue
+                        );
                         self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAddNonCountedBacktracking => {
-                        try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+                        try_or_throw!(
+                            self.machine_st,
+                            self.add_non_counted_backtracking(),
+                            continue
+                        );
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallPredicateDefined => {
                         self.machine_st.fail = !self.predicate_defined();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePredicateDefined => {
                         self.machine_st.fail = !self.predicate_defined();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallStripModule => {
                         self.strip_module();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteStripModule => {
                         self.strip_module();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPrepareCallClause(arity) => {
-                        try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(self.machine_st, self.prepare_call_clause(arity), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePrepareCallClause(arity) => {
-                        try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(self.machine_st, self.prepare_call_clause(arity), continue);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCompileInlineOrExpandedGoal => {
-                        try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        try_or_throw!(
+                            self.machine_st,
+                            self.compile_inline_or_expanded_goal(),
+                            continue
+                        );
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCompileInlineOrExpandedGoal => {
-                        try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        try_or_throw!(
+                            self.machine_st,
+                            self.compile_inline_or_expanded_goal(),
+                            continue
+                        );
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallIsExpandedOrInlined => {
                         self.machine_st.fail = !self.is_expanded_or_inlined();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteIsExpandedOrInlined => {
                         self.machine_st.fail = !self.is_expanded_or_inlined();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallFastCallN(arity) => {
                         let call_at_index =
                             |wam: &mut Machine, name, arity, ptr| wam.try_call(name, arity, ptr);
 
-                        try_or_throw!(self.machine_st, self.fast_call(arity, call_at_index));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.fast_call(arity, call_at_index),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -5465,7 +5900,11 @@ impl Machine {
                         let call_at_index =
                             |wam: &mut Machine, name, arity, ptr| wam.try_execute(name, arity, ptr);
 
-                        try_or_throw!(self.machine_st, self.fast_call(arity, call_at_index));
+                        try_or_throw!(
+                            self.machine_st,
+                            self.fast_call(arity, call_at_index),
+                            continue
+                        );
 
                         if self.machine_st.fail {
                             self.machine_st.backtrack();
@@ -5484,14 +5923,15 @@ impl Machine {
 
                         let str_cell = backtrack_on_resource_error!(
                             &mut self.machine_st,
-                            writer(&mut self.machine_st.heap)
+                            writer(&mut self.machine_st.heap),
+                            continue
                         );
 
                         let r = r.as_var().unwrap();
 
                         self.machine_st.bind(r, str_cell);
 
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetClauseP => {
                         let module_name = cell_as_atom!(self.deref_register(3));
@@ -5506,14 +5946,13 @@ impl Machine {
 
                         let str_cell = backtrack_on_resource_error!(
                             &mut self.machine_st,
-                            writer(&mut self.machine_st.heap)
+                            writer(&mut self.machine_st.heap),
+                            continue
                         );
 
                         let r = r.as_var().unwrap();
-
                         self.machine_st.bind(r, str_cell);
-
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInvokeClauseAtP => {
                         let key_cell = self.machine_st.registers[1];
@@ -5609,27 +6048,27 @@ impl Machine {
                     }
                     &Instruction::CallGetFromAttributedVarList => {
                         self.get_from_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetFromAttributedVarList => {
                         self.get_from_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPutToAttributedVarList => {
                         self.put_to_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecutePutToAttributedVarList => {
                         self.put_to_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDeleteFromAttributedVarList => {
                         self.delete_from_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteDeleteFromAttributedVarList => {
                         self.delete_from_attributed_variable_list();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallDeleteAllAttributesFromVar => {
                         self.delete_all_attributes_from_var();
@@ -5641,7 +6080,7 @@ impl Machine {
                     }
                     &Instruction::CallUnattributedVar => {
                         self.machine_st.unattributed_var();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteUnattributedVar => {
                         self.machine_st.unattributed_var();
@@ -5649,56 +6088,24 @@ impl Machine {
                     }
                     &Instruction::CallGetDBRefs => {
                         self.get_db_refs();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteGetDBRefs => {
                         self.get_db_refs();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallInferenceLimitExceeded => {
                         self.inference_limit_exceeded();
-                        step_or_fail!(self, self.machine_st.p += 1);
+                        step_or_fail!(self.machine_st, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteInferenceLimitExceeded => {
                         self.inference_limit_exceeded();
-                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                        step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.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();
-                        self.machine_st.backtrack();
-
-                        // We have extracted controll over the Tokio runtime to the calling context for enabling library use case
-                        // (see https://github.com/mthom/scryer-prolog/pull/1880)
-                        // So we only have access to a runtime handle in here and can't shut it down.
-                        // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880
-                        // was not merged, I'm only deactivating it for now.
-
-                        //#[cfg(not(target_arch = "wasm32"))]
-                        //let runtime = tokio::runtime::Runtime::new().unwrap();
-                        //#[cfg(target_arch = "wasm32")]
-                        //let runtime = tokio::runtime::Builder::new_current_thread()
-                        //    .enable_all()
-                        //    .build()
-                        //    .unwrap();
-
-                        //let old_runtime = tokio::runtime::Handle::current();
-                        //old_runtime.shutdown_background();
-                    }
-                }
-                Err(_) => unreachable!(),
-            }
+            self.machine_st.check_for_interrupt();
         }
 
         std::process::ExitCode::SUCCESS
index db6dae7e82eb2a852bb610b5a7c9b88c780ab2ba..da41f166985a4842a4289974e4a7dc5f1475801e 100644 (file)
@@ -141,9 +141,8 @@ mod libraries {
 }
 
 pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0;
-pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1;
-pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2;
-pub static LIB_QUERY_SUCCESS: usize = 3;
+pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 1;
+pub static LIB_QUERY_SUCCESS: usize = 2;
 
 pub struct MachinePreludeView<'a> {
     pub indices: &'a mut IndexStore,
@@ -414,12 +413,11 @@ impl Machine {
     }
 
     pub(crate) fn add_impls_to_indices(&mut self) {
-        let impls_offset = self.code.len() + 4;
+        let impls_offset = self.code.len() + 3;
 
         self.code.extend(vec![
             Instruction::BreakFromDispatchLoop,
-            Instruction::InstallVerifyAttr,
-            Instruction::VerifyAttrInterrupt(0),
+            Instruction::RunVerifyAttr,
             Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS
             Instruction::ExecuteTermGreaterThan,
             Instruction::ExecuteTermLessThan,
index 5fc4088b1441d5d41098909430ab27d7d84b0428..4294b68ca7bcddedd6fa98eec65d27261fe72423 100644 (file)
@@ -24,7 +24,7 @@ use crate::machine::machine_state::*;
 use crate::machine::partial_string::*;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
-use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
+use crate::machine::{get_structure_index, Machine};
 use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::dashu::Integer;
@@ -6255,6 +6255,7 @@ impl Machine {
         self.machine_st.heap[var.get_value() as usize] = value;
     }
 
+    /*
     #[inline(always)]
     pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) {
         match &self.code[VERIFY_ATTR_INTERRUPT_LOC] {
@@ -6269,10 +6270,11 @@ impl Machine {
             }
         }
     }
+    */
 
     #[inline(always)]
     pub(crate) fn reset_attr_var_state(&mut self, queue_len: usize) {
-        self.restore_instr_at_verify_attr_interrupt();
+        // self.restore_instr_at_verify_attr_interrupt();
         self.machine_st.attr_var_init.reset(queue_len);
     }
 
@@ -6303,7 +6305,7 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn return_from_verify_attr(&mut self) {
-        self.restore_instr_at_verify_attr_interrupt();
+        // self.restore_instr_at_verify_attr_interrupt();
 
         let e = self.machine_st.e;
         let frame_len = self.machine_st.stack.index_and_frame(e).prelude.num_cells;