]> Repositorios git - scryer-prolog.git/commitdiff
use lookahead to skip inapplicable clauses (#1028, #1502)
authorMark <[email protected]>
Tue, 11 Jul 2023 23:59:53 +0000 (17:59 -0600)
committerMark <[email protected]>
Wed, 12 Jul 2023 20:39:02 +0000 (14:39 -0600)
build/instructions_template.rs
src/codegen.rs
src/machine/dispatch.rs
src/machine/machine_state.rs
src/machine/mod.rs
src/machine/system_calls.rs
src/targets.rs

index 2629f7b360dd89a3ab4e8d8341c9e57572edd8a9..3b2bd971ef2765ca59e35126a9d0703d18c4317e 100644 (file)
@@ -598,7 +598,7 @@ enum InstructionTemplate {
     #[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))]
     GetPartialString(Level, Atom, RegType, bool),
     #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
-    GetStructure(Atom, usize, RegType),
+    GetStructure(Level, Atom, usize, RegType),
     #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
     GetVariable(RegType, usize),
     #[strum_discriminants(strum(props(Arity = "2", Name = "get_value")))]
@@ -2105,13 +2105,14 @@ fn generate_instruction_preface() -> TokenStream {
                             [lvl_stub, rt_stub]
                         )
                     }
-                    &Instruction::GetStructure(name, arity, r) => {
+                    &Instruction::GetStructure(lvl, name, arity, r) => {
+                        let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
                         functor!(
                             atom!("get_structure"),
-                            [atom(name), fixnum(arity), str(h, 0)],
-                            [rt_stub]
+                            [str(h, 0), atom(name), fixnum(arity), str(h, 1)],
+                            [lvl_stub, rt_stub]
                         )
                     }
                     &Instruction::GetValue(r, arg) => {
index 68374c581e2c5ef08045825df5734d655b98dfc8..7d4b92d39e80a523201ee7af5da39927e8d9c1e7 100644 (file)
@@ -309,7 +309,7 @@ impl DebrayAllocator {
 fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
     match instr {
         Instruction::PutStructure(_, ref mut arity, _) |
-        Instruction::GetStructure(_, ref mut arity, _) => {
+        Instruction::GetStructure(.., ref mut arity, _) => {
             if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
                 // it is acceptable if arity == 0 is the result of
                 // this decrement. call/N will have to read the index
@@ -447,7 +447,7 @@ impl<'b> CodeGenerator<'b> {
                 }
                 TermRef::Clause(lvl, cell, name, terms) => {
                     self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
-                    target.push_back(Target::to_structure(name, terms.len(), cell.get()));
+                    target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get()));
 
                     <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(self, cell.get());
 
index e1ba0c0f3bdcbf65415fb3cfe9ad589c88abe5ad..3b30e75b208f2f3250450f8586a79e029cd95e40 100644 (file)
@@ -9,6 +9,8 @@ use crate::types::*;
 
 use crate::try_numeric_result;
 
+use fxhash::FxBuildHasher;
+
 macro_rules! step_or_fail {
     ($self:expr, $step_e:expr) => {
         if $self.machine_st.fail {
@@ -182,6 +184,128 @@ impl MachineState {
 
         Ok(())
     }
+
+    #[inline(always)]
+    pub(crate) fn select_switch_on_term_index(
+        &self,
+        addr: HeapCellValue,
+        v: IndexingCodePtr,
+        c: IndexingCodePtr,
+        l: IndexingCodePtr,
+        s: IndexingCodePtr,
+    ) -> IndexingCodePtr {
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Var |
+             HeapCellValueTag::StackVar |
+             HeapCellValueTag::AttrVar) => {
+                v
+            }
+            (HeapCellValueTag::PStrLoc |
+             HeapCellValueTag::Lis |
+             HeapCellValueTag::CStr) => {
+                l
+            }
+            (HeapCellValueTag::Fixnum |
+             HeapCellValueTag::Char |
+             HeapCellValueTag::F64) => {
+                c
+            }
+            (HeapCellValueTag::Atom, (_name, arity)) => {
+                // if arity == 0 { c } else { s }
+                debug_assert!(arity == 0);
+                c
+            }
+            (HeapCellValueTag::Str, st) => {
+                let (name, arity) = cell_as_atom_cell!(self.heap[st])
+                    .get_name_and_arity();
+
+                match (name, arity) {
+                    (atom!("."), 2) => l,
+                    (_, 0) => c,
+                    _ => s,
+                }
+            }
+            (HeapCellValueTag::Cons, ptr) => {
+                match ptr.get_tag() {
+                    ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
+                        c
+                    }
+                    _ => {
+                        IndexingCodePtr::Fail
+                    }
+                }
+            }
+            _ => {
+                unreachable!();
+            }
+        )
+    }
+
+    #[inline(always)]
+    pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal {
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Char, c) => {
+                Literal::Char(c)
+            }
+            (HeapCellValueTag::Fixnum, n) => {
+                Literal::Fixnum(n)
+            }
+            (HeapCellValueTag::F64, f) => {
+                Literal::Float(f.as_offset())
+            }
+            (HeapCellValueTag::Atom, (atom, arity)) => {
+                debug_assert_eq!(arity, 0);
+                Literal::Atom(atom)
+            }
+            (HeapCellValueTag::Str, s) => {
+                Literal::Atom(cell_as_atom_cell!(self.heap[s]).get_name())
+            }
+            (HeapCellValueTag::Cons, cons_ptr) => {
+                match_untyped_arena_ptr!(cons_ptr,
+                    (ArenaHeaderTag::Rational, r) => {
+                        Literal::Rational(r)
+                    }
+                    (ArenaHeaderTag::Integer, n) => {
+                        Literal::Integer(n)
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                )
+            }
+            _ => {
+                unreachable!()
+            }
+        )
+    }
+
+    #[inline(always)]
+    pub(crate) fn select_switch_on_structure_index(
+        &self,
+        addr: HeapCellValue,
+        hm: &IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>,
+    ) -> IndexingCodePtr {
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                match hm.get(&(name, arity)) {
+                    Some(offset) => *offset,
+                    None => IndexingCodePtr::Fail,
+                }
+            }
+            (HeapCellValueTag::Str, s) => {
+                let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                    .get_name_and_arity();
+
+                match hm.get(&(name, arity)) {
+                    Some(offset) => *offset,
+                    None => IndexingCodePtr::Fail,
+                }
+            }
+            _ => {
+                IndexingCodePtr::Fail
+            }
+        )
+    }
 }
 
 impl Machine {
@@ -349,51 +473,7 @@ impl Machine {
         loop {
             match &indexing_lines[index] {
                 &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
-                    let offset = read_heap_cell!(addr,
-                        (HeapCellValueTag::Var |
-                         HeapCellValueTag::StackVar |
-                         HeapCellValueTag::AttrVar) => {
-                            v
-                        }
-                        (HeapCellValueTag::PStrLoc |
-                         HeapCellValueTag::Lis |
-                         HeapCellValueTag::CStr) => {
-                            l
-                        }
-                        (HeapCellValueTag::Fixnum |
-                         HeapCellValueTag::Char |
-                         HeapCellValueTag::F64) => {
-                            c
-                        }
-                        (HeapCellValueTag::Atom, (_name, arity)) => {
-                            // if arity == 0 { c } else { s }
-                            debug_assert!(arity == 0);
-                            c
-                        }
-                        (HeapCellValueTag::Str, st) => {
-                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[st])
-                                .get_name_and_arity();
-
-                            match (name, arity) {
-                                (atom!("."), 2) => l,
-                                (_, 0) => c,
-                                _ => s,
-                            }
-                        }
-                        (HeapCellValueTag::Cons, ptr) => {
-                            match ptr.get_tag() {
-                                ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
-                                    c
-                                }
-                                _ => {
-                                    IndexingCodePtr::Fail
-                                }
-                            }
-                        }
-                        _ => {
-                            unreachable!();
-                        }
-                    );
+                    let offset = self.machine_st.select_switch_on_term_index(addr, v, c, l, s);
 
                     match offset {
                         IndexingCodePtr::Fail => {
@@ -423,41 +503,8 @@ impl Machine {
                         }
                     }
                 }
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
-                    let lit = read_heap_cell!(addr,
-                        (HeapCellValueTag::Char, c) => {
-                            Literal::Char(c)
-                        }
-                        (HeapCellValueTag::Fixnum, n) => {
-                            Literal::Fixnum(n)
-                        }
-                        (HeapCellValueTag::F64, f) => {
-                            Literal::Float(f.as_offset())
-                        }
-                        (HeapCellValueTag::Atom, (atom, arity)) => {
-                            debug_assert_eq!(arity, 0);
-                            Literal::Atom(atom)
-                        }
-                        (HeapCellValueTag::Str, s) => {
-                            Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name())
-                        }
-                        (HeapCellValueTag::Cons, cons_ptr) => {
-                            match_untyped_arena_ptr!(cons_ptr,
-                                (ArenaHeaderTag::Rational, r) => {
-                                    Literal::Rational(r)
-                                }
-                                (ArenaHeaderTag::Integer, n) => {
-                                    Literal::Integer(n)
-                                }
-                                _ => {
-                                    unreachable!()
-                                }
-                            )
-                        }
-                        _ => {
-                            unreachable!()
-                        }
-                    );
+                IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
+                    let lit = self.machine_st.constant_to_literal(addr);
 
                     let offset = match hm.get(&lit) {
                         Some(offset) => *offset,
@@ -492,27 +539,8 @@ impl Machine {
                         }
                     }
                 }
-                &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
-                    let offset = read_heap_cell!(addr,
-                        (HeapCellValueTag::Atom, (name, arity)) => {
-                            match hm.get(&(name, arity)) {
-                                Some(offset) => *offset,
-                                None => IndexingCodePtr::Fail,
-                            }
-                        }
-                        (HeapCellValueTag::Str, s) => {
-                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                                .get_name_and_arity();
-
-                            match hm.get(&(name, arity)) {
-                                Some(offset) => *offset,
-                                None => IndexingCodePtr::Fail,
-                            }
-                        }
-                        _ => {
-                            IndexingCodePtr::Fail
-                        }
-                    );
+                IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
+                    let offset = self.machine_st.select_switch_on_structure_index(addr, hm);
 
                     match offset {
                         IndexingCodePtr::Fail => {
@@ -997,7 +1025,7 @@ impl Machine {
                                                 fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
 
                                             self.machine_st.num_of_args += 1;
-                                            self.machine_st.try_me_else(next_i);
+                                            self.try_me_else(next_i);
                                             self.machine_st.num_of_args -= 1;
                                         }
                                         None => {
@@ -1067,7 +1095,7 @@ impl Machine {
                                                 fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
 
                                             self.machine_st.num_of_args += 1;
-                                            self.machine_st.try_me_else(next_i);
+                                            self.try_me_else(next_i);
                                             self.machine_st.num_of_args -= 1;
                                         }
                                         None => {
@@ -1118,7 +1146,7 @@ impl Machine {
                     }
                 }
                 &Instruction::TryMeElse(offset) => {
-                    self.machine_st.try_me_else(offset);
+                    self.try_me_else(offset);
                 }
                 &Instruction::DefaultRetryMeElse(offset) => {
                     self.retry_me_else(offset);
@@ -2879,7 +2907,7 @@ impl Machine {
 
                     step_or_fail!(self, self.machine_st.p += 1);
                 }
-                &Instruction::GetStructure(name, arity, reg) => {
+                &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);
 
@@ -3076,7 +3104,7 @@ impl Machine {
                         IndexingLine::IndexedChoice(ref indexed_choice) => {
                             match &indexed_choice[self.machine_st.iip as usize] {
                                 &IndexedChoiceInstruction::Try(offset) => {
-                                    self.machine_st.indexed_try(offset);
+                                    self.indexed_try(offset);
                                 }
                                 &IndexedChoiceInstruction::Retry(l) => {
                                     self.retry(l);
@@ -3122,7 +3150,7 @@ impl Machine {
                                                         fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
 
                                                     self.machine_st.num_of_args += 1;
-                                                    self.machine_st.indexed_try(offset);
+                                                    self.indexed_try(offset);
                                                     self.machine_st.num_of_args -= 1;
                                                 }
                                                 None => {
index 7b074a64965943294dd7c58ef91f59690111c2e5..5a8fc85dd8039b407701bb90dda424d2a15c2e2b 100644 (file)
@@ -858,65 +858,6 @@ impl MachineState {
             }
         );
     }
-
-    #[inline(always)]
-    pub(super) fn try_me_else(&mut self, offset: usize) {
-        let n = self.num_of_args;
-        let b = self.stack.allocate_or_frame(n);
-        let or_frame = self.stack.index_or_frame_mut(b);
-
-        or_frame.prelude.num_cells = n;
-        or_frame.prelude.e = self.e;
-        or_frame.prelude.cp = self.cp;
-        or_frame.prelude.b = self.b;
-        or_frame.prelude.bp = self.p + offset;
-        or_frame.prelude.boip = 0;
-        or_frame.prelude.biip = 0;
-        or_frame.prelude.tr = self.tr;
-        or_frame.prelude.h = self.heap.len();
-        or_frame.prelude.b0 = self.b0;
-        or_frame.prelude.attr_var_queue_len = self.attr_var_init.attr_var_queue.len();
-
-        self.b = b;
-
-        for i in 0..n {
-            or_frame[i] = self.registers[i+1];
-        }
-
-        self.hb = self.heap.len();
-        self.p += 1;
-    }
-
-    #[inline(always)]
-    pub(super) fn indexed_try(&mut self, offset: usize) {
-        let n = self.num_of_args;
-        let b = self.stack.allocate_or_frame(n);
-        let or_frame = self.stack.index_or_frame_mut(b);
-
-        or_frame.prelude.num_cells = n;
-        or_frame.prelude.e = self.e;
-        or_frame.prelude.cp = self.cp;
-        or_frame.prelude.b = self.b;
-        or_frame.prelude.bp = self.p; // + 1; in self.iip now!
-        or_frame.prelude.boip = self.oip;
-        or_frame.prelude.biip = self.iip + 1;
-        or_frame.prelude.tr = self.tr;
-        or_frame.prelude.h = self.heap.len();
-        or_frame.prelude.b0 = self.b0;
-        or_frame.prelude.attr_var_queue_len = self.attr_var_init.attr_var_queue.len();
-
-        self.b = b;
-
-        for i in 0..n {
-            or_frame[i] = self.registers[i+1];
-        }
-
-        self.hb = self.heap.len();
-        self.p = self.p + offset;
-
-        self.oip = 0;
-        self.iip = 0;
-    }
 }
 
 #[derive(Debug)]
index 78c347f2927dfa919182887de8266ba62440eae2..41cc4f394fc27e0d51ad041aa376e33613a84028 100644 (file)
@@ -547,38 +547,351 @@ impl Machine {
         self.machine_st.verify_attr_interrupt(p, arity);
     }
 
+    fn next_clause_applicable(&mut self, mut offset: usize) -> bool {
+        loop {
+            match &self.code[offset] {
+                Instruction::IndexingCode(indexing_lines) => {
+                    let mut oip = 0;
+                    let mut cell = empty_list_as_cell!();
+
+                    loop {
+                        let indexing_code_ptr = match &indexing_lines[oip] {
+                            &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, v, c, l, s)) => {
+                                cell = self.deref_register(arg);
+                                self.machine_st.select_switch_on_term_index(cell, v, c, l, s)
+                            }
+                            IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
+                                let lit = self.machine_st.constant_to_literal(cell);
+                                hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail)
+                            }
+                            IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
+                                self.machine_st.select_switch_on_structure_index(cell, hm)
+                            }
+                            _ => {
+                                offset += 1;
+                                break;
+                            }
+                        };
+
+                        match indexing_code_ptr {
+                            IndexingCodePtr::External(_) | IndexingCodePtr::DynamicExternal(_) => {
+                                offset += 1;
+                                break;
+                            }
+                            IndexingCodePtr::Internal(i) => oip += i,
+                            IndexingCodePtr::Fail => return false,
+                        }
+                    }
+                }
+                &Instruction::GetConstant(Level::Shallow, lit, RegType::Temp(t)) => {
+                    let cell = self.deref_register(t);
+
+                    if cell.is_var() {
+                        offset += 1;
+                    } else if lit.get_tag() == HeapCellValueTag::CStr {
+                        read_heap_cell!(cell,
+                            (HeapCellValueTag::CStr) => {
+                                if cell == lit {
+                                    offset += 1;
+                                } else {
+                                    return false;
+                                }
+                            }
+                            (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
+                                offset += 1;
+                            }
+                            (HeapCellValueTag::Str, s) => {
+                                let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                                    .get_name_and_arity();
+
+                                if name == atom!(".") && arity == 2 {
+                                    offset += 1;
+                                } else {
+                                    return false;
+                                }
+                            }
+                            _ => {
+                                return false;
+                            }
+                        );
+                    } else {
+                        self.machine_st.write_literal_to_var(cell, lit);
+
+                        if self.machine_st.fail {
+                            self.machine_st.fail = false;
+                            return false;
+                        } else {
+                            offset += 1;
+                        }
+                    }
+                }
+                &Instruction::GetList(Level::Shallow, RegType::Temp(t)) => {
+                    let cell = self.deref_register(t);
+
+                    read_heap_cell!(cell,
+                        (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+                            offset += 1;
+                        }
+                        (HeapCellValueTag::Str, s) => {
+                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
+
+                            if name == atom!(".") && arity == 2 {
+                                offset += 1;
+                            } else {
+                                return false;
+                            }
+                        }
+                        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                            offset += 1;
+                        }
+                        _ => {
+                            return false;
+                        }
+                    );
+                }
+                &Instruction::GetStructure(Level::Shallow, name, arity, RegType::Temp(t)) => {
+                    let cell = self.deref_register(t);
+
+                    read_heap_cell!(cell,
+                        (HeapCellValueTag::Str, s) => {
+                            if (name, arity) == cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() {
+                                offset += 1;
+                            } else {
+                                return false;
+                            }
+                        }
+                        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                            offset += 1;
+                        }
+                        _ => {
+                            return false;
+                        }
+                    );
+                }
+                &Instruction::GetPartialString(Level::Shallow, string, RegType::Temp(t), has_tail) => {
+                    let cell = self.deref_register(t);
+
+                    read_heap_cell!(cell,
+                        (HeapCellValueTag::CStr, cstr) => {
+                            if !has_tail && string != cstr {
+                                return false;
+                            }
+
+                            offset += 1;
+                        }
+                        (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
+                            offset += 1;
+                        }
+                        (HeapCellValueTag::Str, s) => {
+                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
+
+                            if name == atom!(".") && arity == 2 {
+                                offset += 1;
+                            } else {
+                                return false;
+                            }
+                        }
+                        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                            offset += 1;
+                        }
+                        _ => {
+                            return false;
+                        }
+                    );
+                }
+                Instruction::GetConstant(..) |
+                Instruction::GetList(..) |
+                Instruction::GetStructure(..) |
+                Instruction::GetPartialString(..) |
+                &Instruction::UnifyVoid(..) |
+                &Instruction::UnifyConstant(..) |
+                &Instruction::GetVariable(..) |
+                &Instruction::GetValue(..) |
+                &Instruction::UnifyVariable(..) |
+                &Instruction::UnifyValue(..) |
+                &Instruction::UnifyLocalValue(..)  => {
+                    offset += 1;
+                }
+                _ => {
+                    break;
+                }
+            }
+        }
+
+        true
+    }
+
+    fn next_applicable_clause(&mut self, mut offset: usize) -> Option<usize> {
+        while !self.next_clause_applicable(self.machine_st.p + offset + 1) {
+            match &self.code[self.machine_st.p + offset] {
+                &Instruction::DefaultRetryMeElse(o) | &Instruction::RetryMeElse(o) |
+                &Instruction::DynamicElse(.., NextOrFail::Next(o)) |
+                &Instruction::DynamicInternalElse(.., NextOrFail::Next(o)) => offset += o,
+                _ => {
+                    return None;
+                }
+            }
+        }
+
+        Some(offset)
+    }
+
+    fn next_inner_applicable_clause(&mut self) -> Option<u32> {
+        let mut inner_offset = 1u32;
+
+        loop {
+            match &self.code[self.machine_st.p] {
+                Instruction::IndexingCode(indexing_lines) => {
+                    match &indexing_lines[self.machine_st.oip as usize] {
+                        IndexingLine::IndexedChoice(indexed_choice) => {
+                            match &indexed_choice[(self.machine_st.iip + inner_offset) as usize] {
+                                &IndexedChoiceInstruction::Retry(o) => {
+                                    if self.next_clause_applicable(self.machine_st.p + o) {
+                                        return Some(inner_offset);
+                                    }
+
+                                    inner_offset += 1;
+                                }
+                                &IndexedChoiceInstruction::Trust(o) => {
+                                    return if self.next_clause_applicable(self.machine_st.p + o) {
+                                        Some(inner_offset)
+                                    } else {
+                                        None
+                                    };
+                                }
+                                _ => unreachable!(),
+                            }
+                        }
+                        IndexingLine::DynamicIndexedChoice(indexed_choice) => {
+                            let idx = (self.machine_st.iip + inner_offset) as usize;
+                            let o = indexed_choice[idx];
+
+                            if idx + 1 == indexed_choice.len() {
+                                return if self.next_clause_applicable(self.machine_st.p + o) {
+                                    Some(inner_offset)
+                                } else {
+                                    None
+                                };
+                            } else {
+                                if self.next_clause_applicable(self.machine_st.p + o) {
+                                    return Some(inner_offset);
+                                }
+
+                                inner_offset += 1;
+                            }
+                        }
+                        _ => unreachable!(),
+                    }
+                }
+                _ => unreachable!(),
+            }
+        }
+    }
+
+    #[inline(always)]
+    pub(super) fn try_me_else(&mut self, offset: usize) {
+        if let Some(offset) = self.next_applicable_clause(offset) {
+            let n = self.machine_st.num_of_args;
+            let b = self.machine_st.stack.allocate_or_frame(n);
+            let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+
+            or_frame.prelude.num_cells = n;
+            or_frame.prelude.e = self.machine_st.e;
+            or_frame.prelude.cp = self.machine_st.cp;
+            or_frame.prelude.b = self.machine_st.b;
+            or_frame.prelude.bp = self.machine_st.p + offset;
+            or_frame.prelude.boip = 0;
+            or_frame.prelude.biip = 0;
+            or_frame.prelude.tr = self.machine_st.tr;
+            or_frame.prelude.h = self.machine_st.heap.len();
+            or_frame.prelude.b0 = self.machine_st.b0;
+            or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len();
+
+            self.machine_st.b = b;
+
+            for i in 0..n {
+                or_frame[i] = self.machine_st.registers[i+1];
+            }
+
+            self.machine_st.hb = self.machine_st.heap.len();
+        }
+
+        self.machine_st.p += 1;
+    }
+
+    #[inline(always)]
+    pub(super) fn indexed_try(&mut self, offset: usize) {
+        if let Some(iip_offset) = self.next_inner_applicable_clause() {
+            let n = self.machine_st.num_of_args;
+            let b = self.machine_st.stack.allocate_or_frame(n);
+            let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+
+            or_frame.prelude.num_cells = n;
+            or_frame.prelude.e = self.machine_st.e;
+            or_frame.prelude.cp = self.machine_st.cp;
+            or_frame.prelude.b = self.machine_st.b;
+            or_frame.prelude.bp = self.machine_st.p;
+            or_frame.prelude.boip = self.machine_st.oip;
+            or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
+            or_frame.prelude.tr = self.machine_st.tr;
+            or_frame.prelude.h = self.machine_st.heap.len();
+            or_frame.prelude.b0 = self.machine_st.b0;
+            or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len();
+
+            self.machine_st.b = b;
+
+            for i in 0..n {
+                or_frame[i] = self.machine_st.registers[i+1];
+            }
+
+            self.machine_st.hb = self.machine_st.heap.len();
+
+            self.machine_st.oip = 0;
+            self.machine_st.iip = 0;
+        }
+
+        self.machine_st.p += offset;
+    }
+
     #[inline(always)]
     fn retry_me_else(&mut self, offset: usize) {
         let b = self.machine_st.b;
         let or_frame = self.machine_st.stack.index_or_frame_mut(b);
         let n = or_frame.prelude.num_cells;
 
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+
         for i in 0..n {
             self.machine_st.registers[i + 1] = or_frame[i];
         }
 
-        self.machine_st.num_of_args = n;
-        self.machine_st.e = or_frame.prelude.e;
-        self.machine_st.cp = or_frame.prelude.cp;
+        self.unwind_trail(old_tr, curr_tr);
 
-        or_frame.prelude.bp = self.machine_st.p + offset;
+        if let Some(offset) = self.next_applicable_clause(offset) {
+            let or_frame = self.machine_st.stack.index_or_frame_mut(b);
 
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = self.machine_st.tr;
-        let target_h = or_frame.prelude.h;
-        let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
+            self.machine_st.num_of_args = n;
+            self.machine_st.e = or_frame.prelude.e;
+            self.machine_st.cp = or_frame.prelude.cp;
 
-        self.machine_st.tr = or_frame.prelude.tr;
-        self.reset_attr_var_state(attr_var_queue_len);
+            or_frame.prelude.bp = self.machine_st.p + offset;
 
-        self.machine_st.hb = target_h;
+            let target_h = or_frame.prelude.h;
+            let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
 
-        self.unwind_trail(old_tr, curr_tr);
+            self.machine_st.tr = or_frame.prelude.tr;
+            self.reset_attr_var_state(attr_var_queue_len);
 
-        self.machine_st.trail.truncate(self.machine_st.tr);
-        self.machine_st.heap.truncate(target_h);
+            self.machine_st.hb = target_h;
 
-        self.machine_st.p += 1;
+            self.machine_st.trail.truncate(self.machine_st.tr);
+            self.machine_st.heap.truncate(target_h);
+
+            self.machine_st.p += 1;
+        } else {
+            self.trust_me_epilogue();
+        }
     }
 
     #[inline(always)]
@@ -587,34 +900,42 @@ impl Machine {
         let or_frame = self.machine_st.stack.index_or_frame_mut(b);
         let n = or_frame.prelude.num_cells;
 
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+
         for i in 0..n {
             self.machine_st.registers[i+1] = or_frame[i];
         }
 
-        self.machine_st.num_of_args = n;
-        self.machine_st.e = or_frame.prelude.e;
-        self.machine_st.cp = or_frame.prelude.cp;
+        self.unwind_trail(old_tr, curr_tr);
 
-        or_frame.prelude.biip += 1;
+        if let Some(iip_offset) = self.next_inner_applicable_clause() {
+            let or_frame = self.machine_st.stack.index_or_frame_mut(b);
 
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = self.machine_st.tr;
-        let target_h = or_frame.prelude.h;
-        let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
+            self.machine_st.num_of_args = n;
+            self.machine_st.e = or_frame.prelude.e;
+            self.machine_st.cp = or_frame.prelude.cp;
 
-        self.machine_st.tr = or_frame.prelude.tr;
-        self.reset_attr_var_state(attr_var_queue_len);
+            or_frame.prelude.biip += iip_offset;
 
-        self.machine_st.hb = target_h;
-        self.machine_st.p = self.machine_st.p + offset;
+            let target_h = or_frame.prelude.h;
+            let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
 
-        self.unwind_trail(old_tr, curr_tr);
+            self.machine_st.tr = or_frame.prelude.tr;
+            self.machine_st.trail.truncate(self.machine_st.tr);
 
-        self.machine_st.trail.truncate(self.machine_st.tr);
-        self.machine_st.heap.truncate(target_h);
+            self.reset_attr_var_state(attr_var_queue_len);
 
-        self.machine_st.oip = 0;
-        self.machine_st.iip = 0;
+            self.machine_st.hb = target_h;
+            self.machine_st.p += offset;
+
+            self.machine_st.heap.truncate(target_h);
+
+            self.machine_st.oip = 0;
+            self.machine_st.iip = 0;
+        } else {
+            self.trust_epilogue(offset);
+        }
     }
 
     #[inline(always)]
@@ -623,19 +944,32 @@ impl Machine {
         let or_frame = self.machine_st.stack.index_or_frame(b);
         let n = or_frame.prelude.num_cells;
 
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+
         for i in 0..n {
             self.machine_st.registers[i+1] = or_frame[i];
         }
 
+        self.unwind_trail(old_tr, curr_tr);
+        self.trust_epilogue(offset);
+    }
+
+    #[inline(always)]
+    fn trust_epilogue(&mut self, offset: usize) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame(b);
+        let n = or_frame.prelude.num_cells;
+
         self.machine_st.num_of_args = n;
         self.machine_st.e = or_frame.prelude.e;
         self.machine_st.cp = or_frame.prelude.cp;
 
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = self.machine_st.tr;
         let target_h = or_frame.prelude.h;
 
         self.machine_st.tr = or_frame.prelude.tr;
+        self.machine_st.trail.truncate(self.machine_st.tr);
+
         self.machine_st.b = or_frame.prelude.b;
 
         self.reset_attr_var_state(or_frame.prelude.attr_var_queue_len);
@@ -643,9 +977,6 @@ impl Machine {
         self.machine_st.hb = target_h;
         self.machine_st.p = self.machine_st.p + offset;
 
-        self.unwind_trail(old_tr, curr_tr);
-
-        self.machine_st.trail.truncate(self.machine_st.tr);
         self.machine_st.stack.truncate(b);
         self.machine_st.heap.truncate(target_h);
 
@@ -663,12 +994,24 @@ impl Machine {
             self.machine_st.registers[i+1] = or_frame[i];
         }
 
+        let old_tr = or_frame.prelude.tr;
+        let curr_tr = self.machine_st.tr;
+
+        self.unwind_trail(old_tr, curr_tr);
+
+        self.trust_me_epilogue();
+    }
+
+    #[inline(always)]
+    fn trust_me_epilogue(&mut self) {
+        let b = self.machine_st.b;
+        let or_frame = self.machine_st.stack.index_or_frame(b);
+        let n = or_frame.prelude.num_cells;
+
         self.machine_st.num_of_args = n;
         self.machine_st.e = or_frame.prelude.e;
         self.machine_st.cp = or_frame.prelude.cp;
 
-        let old_tr = or_frame.prelude.tr;
-        let curr_tr = self.machine_st.tr;
         let target_h = or_frame.prelude.h;
 
         self.machine_st.tr = or_frame.prelude.tr;
@@ -679,8 +1022,6 @@ impl Machine {
         self.machine_st.hb = target_h;
         self.machine_st.p += 1;
 
-        self.unwind_trail(old_tr, curr_tr);
-
         self.machine_st.trail.truncate(self.machine_st.tr);
         self.machine_st.stack.truncate(b);
         self.machine_st.heap.truncate(target_h);
index 111569ec09cddedb858820fddd73111575f55a74..532fb1e35bf0a626b18cf12cff7210f8ea5ca94d 100644 (file)
@@ -1277,7 +1277,7 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(crate) fn deref_register(&mut self, i: usize) -> HeapCellValue {
+    pub(crate) fn deref_register(&self, i: usize) -> HeapCellValue {
            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[i]))
     }
 
index 56a4c12754f339f08a11a5159838f0502c4a6179..1596aae2c0c14719f8a66d280dfe0bb7569b708b 100644 (file)
@@ -16,7 +16,7 @@ pub(crate) trait CompilationTarget<'a> {
 
     fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
     fn to_list(lvl: Level, r: RegType) -> Instruction;
-    fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction;
+    fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
 
     fn to_void(num_subterms: usize) -> Instruction;
     fn is_void_instr(instr: &Instruction) -> bool;
@@ -51,8 +51,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
     }
 
-    fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction {
-        Instruction::GetStructure(name, arity, reg)
+    fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction {
+        Instruction::GetStructure(lvl, name, arity, reg)
     }
 
     fn to_list(lvl: Level, reg: RegType) -> Instruction {
@@ -125,7 +125,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
         post_order_iter(term)
     }
 
-    fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction {
+    fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
         Instruction::PutStructure(name, arity, r)
     }