]> Repositorios git - scryer-prolog.git/commitdiff
simplify and optimize attributed variables (#1590, #1634, #1730)
authorMark Thom <[email protected]>
Fri, 10 Feb 2023 07:09:22 +0000 (00:09 -0700)
committerMark Thom <[email protected]>
Sat, 11 Feb 2023 04:56:42 +0000 (21:56 -0700)
build/instructions_template.rs
src/lib/atts.pl
src/machine/attributed_variables.rs
src/machine/dispatch.rs
src/machine/mod.rs
src/machine/system_calls.rs

index 23c96068289bacbaf994696a9213837a5bf25626..982953088f22c22d615d2fa8964b4405cce4c95f 100644 (file)
@@ -272,16 +272,10 @@ enum SystemClauseType {
     PathCanonical,
     #[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
     FileTime,
-    #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))]
-    DeleteAttribute,
-    #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))]
-    DeleteHeadAttribute,
     #[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
     DynamicModuleResolution(usize),
     #[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
     PrepareCallClause(usize),
-    #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
-    EnqueueAttributedVar,
     #[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
     FetchGlobalVar,
     #[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
@@ -566,8 +560,12 @@ enum SystemClauseType {
     GetClauseP,
     #[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
     InvokeClauseAtP,
-    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_from_attr_list")))]
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$get_from_attr_list")))]
     GetFromAttributedVarList,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$put_to_attr_list")))]
+    PutToAttributedVarList,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$del_from_attr_list")))]
+    DeleteFromAttributedVarList,
     REPL(REPLCodePtr),
 }
 
@@ -1620,8 +1618,6 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallDeleteDirectory(_) |
                     &Instruction::CallPathCanonical(_) |
                     &Instruction::CallFileTime(_) |
-                    &Instruction::CallDeleteAttribute(_) |
-                    &Instruction::CallDeleteHeadAttribute(_) |
                     &Instruction::CallDynamicModuleResolution(..) |
                     &Instruction::CallPrepareCallClause(..) |
                     &Instruction::CallCompileInlineOrExpandedGoal(..) |
@@ -1629,7 +1625,8 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallGetClauseP(_) |
                     &Instruction::CallInvokeClauseAtP(_) |
                     &Instruction::CallGetFromAttributedVarList(_) |
-                    &Instruction::CallEnqueueAttributedVar(_) |
+                    &Instruction::CallPutToAttributedVarList(_) |
+                    &Instruction::CallDeleteFromAttributedVarList(_) |
                     &Instruction::CallFetchGlobalVar(_) |
                     &Instruction::CallFirstStream(_) |
                     &Instruction::CallFlushOutput(_) |
@@ -1836,8 +1833,6 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteDeleteDirectory(_) |
                     &Instruction::ExecutePathCanonical(_) |
                     &Instruction::ExecuteFileTime(_) |
-                    &Instruction::ExecuteDeleteAttribute(_) |
-                    &Instruction::ExecuteDeleteHeadAttribute(_) |
                     &Instruction::ExecuteDynamicModuleResolution(..) |
                     &Instruction::ExecutePrepareCallClause(..) |
                     &Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
@@ -1845,7 +1840,8 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteGetClauseP(_) |
                     &Instruction::ExecuteInvokeClauseAtP(_) |
                     &Instruction::ExecuteGetFromAttributedVarList(_) |
-                    &Instruction::ExecuteEnqueueAttributedVar(_) |
+                    &Instruction::ExecutePutToAttributedVarList(_) |
+                    &Instruction::ExecuteDeleteFromAttributedVarList(_) |
                     &Instruction::ExecuteFetchGlobalVar(_) |
                     &Instruction::ExecuteFirstStream(_) |
                     &Instruction::ExecuteFlushOutput(_) |
index 752be478a886e11c32b9aa7e0532b4344766df47..d6ee47a3d41f3c9453d56efb607d06cb9d23d1e1 100644 (file)
     '$default_attr_list'(PGs, Module, AttrVar).
 '$default_attr_list'([], _, _) --> [].
 
-'$absent_attr'(V, Attr) :-
-    '$get_attr_list'(V, Ls),
-    '$absent_from_list'(Ls, Attr).
-
-'$absent_from_list'(X, Attr) :-
-    (  var(X) ->
-       true
-    ;  X = [L|Ls],
-       L \= Attr ->
-       '$absent_from_list'(Ls, Attr)
-    ).
-
-'$get_attr'(V, Attr) :-
-    '$get_attr_list'(V, Ls),
-    nonvar(Ls),
-    '$get_from_attr_list'(Ls, Attr).
-
-/*
-'$get_from_list'([L|Ls], V, Attr) :-
-    nonvar(L),
-    (  L \= Attr ->
-       nonvar(Ls),
-       '$get_from_list'(Ls, V, Attr)
-    ;  L = Attr
-    ).
-*/
-
-'$put_attr'(V, Attr) :-
-    '$get_attr_list'(V, Ls),
-    '$add_to_list'(Ls, V, Attr).
-
-'$add_to_list'(Ls, V, Attr) :-
-    (  var(Ls) ->
-       Ls = [Attr | _],
-       '$enqueue_attr_var'(V)
-    ;  Ls = [_ | Ls0],
-       '$add_to_list'(Ls0, V, Attr)
-    ).
-
-'$del_attr'(Ls0, _, _) :-
-    var(Ls0),
-    !.
-'$del_attr'(Ls0, V, Attr) :-
-    Ls0 = [Att | Ls1],
-    nonvar(Att),
-    (  Att \= Attr ->
-       '$del_attr_buried'(Ls0, Ls1, V, Attr)
-    ;  '$del_attr_head'(V),
-       '$del_attr'(Ls1, V, Attr)
-    ).
-
-'$del_attr_step'(Ls1, V, Attr) :-
-    (  nonvar(Ls1) ->
-       Ls1 = [_ | Ls2],
-       '$del_attr_buried'(Ls1, Ls2, V, Attr)
+'$absent_attr'(V, Module, Attr) :-
+    (  '$get_from_attr_list'(V, Module, Attr) ->
+       false
     ;  true
     ).
 
-%% assumptions: Ls0 is a list, Ls1 is its tail;
-%%              the head of Ls0 can be ignored.
-'$del_attr_buried'(Ls0, Ls1, V, Attr) :-
-    (  var(Ls1) -> true
-    ;  Ls1 = [Att | Ls2] ->
-       (  Att \= Attr ->
-          '$del_attr_buried'(Ls1, Ls2, V, Attr)
-       ;  '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
-             '$del_attr_step'(Ls1, V, Attr)
-       )
-    ).
-
 '$copy_attr_list'(L, _Module, []) :- var(L), !.
 '$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
     (  Module0 == Module ->
@@ -144,38 +80,28 @@ put_attr(Name, Arity, Module) -->
     { functor(Attr, Name, Arity) },
     [(put_atts(V, +Attr) :-
           !,
-          functor(Attr, Head, Arity),
-             functor(AttrForm, Head, Arity),
-             '$get_attr_list'(V, Ls),
-             atts:'$del_attr'(Ls, V, Module:AttrForm),
-             atts:'$put_attr'(V, Module:Attr)),
-     (put_atts(V,  Attr) :-
+          '$put_to_attr_list'(V, Module, Attr)),
+     (put_atts(V, Attr) :-
           !,
-          functor(Attr, Head, Arity),
-             functor(AttrForm, Head, Arity),
-             '$get_attr_list'(V, Ls),
-             atts:'$del_attr'(Ls, V, Module:AttrForm),
-             atts:'$put_attr'(V, Module:Attr)),
+          '$put_to_attr_list'(V, Module, Attr)),
      (put_atts(V, -Attr) :-
           !,
-          functor(Attr, _, _),
-             '$get_attr_list'(V, Ls),
-             atts:'$del_attr'(Ls, V, Module:Attr))].
+          '$del_from_attr_list'(V, Module, Attr))].
 
 get_attr(Name, Arity, Module) -->
     { functor(Attr, Name, Arity) },
     [(get_atts(V, +Attr) :-
           !,
           functor(Attr, _, _),
-          atts:'$get_attr'(V, Module:Attr)),
+          atts:'$get_from_attr_list'(V, Module, Attr)),
      (get_atts(V,  Attr) :-
           !,
           functor(Attr, _, _),
-          atts:'$get_attr'(V, Module:Attr)),
+          atts:'$get_from_attr_list'(V, Module, Attr)),
      (get_atts(V, -Attr) :-
           !,
           functor(Attr, _, _),
-          atts:'$absent_attr'(V, Module:Attr))].
+          atts:'$absent_attr'(V, ModuleAttr))].
 
 user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
     nonvar(Term),
index 2bab7451b6334447c54e209765afed4fb168a795..57ea1c225380454b5ae3873a77b16c8ad1c5ea57 100644 (file)
@@ -52,6 +52,7 @@ impl MachineState {
             self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
         }
 
+        debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
         self.attr_var_init.bindings.push((h, addr));
     }
 
@@ -63,10 +64,9 @@ impl MachineState {
             .map(|(ref h, _)| attr_var_as_cell!(*h));
 
         let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
-
         let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
-
         let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
+
         (var_list_addr, value_list_addr)
     }
 
index 5ea18ba46cfe993851293908a976f65f0da3e5c3..1cb1a8fa9a6d9d015636177a47c92158222c6f9b 100644 (file)
@@ -3570,22 +3570,6 @@ impl Machine {
                     self.file_time();
                     step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                 }
-                &Instruction::CallDeleteAttribute(_) => {
-                    self.delete_attribute();
-                    self.machine_st.p += 1;
-                }
-                &Instruction::ExecuteDeleteAttribute(_) => {
-                    self.delete_attribute();
-                    self.machine_st.p = self.machine_st.cp;
-                }
-                &Instruction::CallDeleteHeadAttribute(_) => {
-                    self.delete_head_attribute();
-                    self.machine_st.p += 1;
-                }
-                &Instruction::ExecuteDeleteHeadAttribute(_) => {
-                    self.delete_head_attribute();
-                    self.machine_st.p = self.machine_st.cp;
-                }
                 &Instruction::CallDynamicModuleResolution(arity, _) => {
                     let (module_name, key) = try_or_throw!(
                         self.machine_st,
@@ -3616,14 +3600,6 @@ impl Machine {
                         self.machine_st.backtrack();
                     }
                 }
-                &Instruction::CallEnqueueAttributedVar(_) => {
-                    self.enqueue_attributed_var();
-                    self.machine_st.p += 1;
-                }
-                &Instruction::ExecuteEnqueueAttributedVar(_) => {
-                    self.enqueue_attributed_var();
-                    self.machine_st.p = self.machine_st.cp;
-                }
                 &Instruction::CallFetchGlobalVar(_) => {
                     self.fetch_global_var();
                     step_or_fail!(self, self.machine_st.p += 1);
@@ -5215,6 +5191,22 @@ impl Machine {
                     self.get_from_attributed_variable_list();
                     step_or_fail!(self, 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);
+                }
+                &Instruction::ExecutePutToAttributedVarList(_) => {
+                    self.put_to_attributed_variable_list();
+                    step_or_fail!(self, 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);
+                }
+                &Instruction::ExecuteDeleteFromAttributedVarList(_) => {
+                    self.delete_from_attributed_variable_list();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
             }
         }
 
index 09883b99bbd60ac872a0da9ce9827002b1b7518b..2a498b02b23c62e5a459e197be5e4cde7b642413 100644 (file)
@@ -870,7 +870,18 @@ impl Machine {
                     let l = self.machine_st.trail[i + 1].get_value() as usize;
 
                     if l < self.machine_st.hb {
-                        self.machine_st.heap[h] = list_loc_as_cell!(l);
+                        if h == l {
+                            self.machine_st.heap[h] = heap_loc_as_cell!(h);
+                        } else {
+                            read_heap_cell!(self.machine_st.heap[l],
+                                (HeapCellValueTag::Var) => {
+                                    self.machine_st.heap[h] = list_loc_as_cell!(l);
+                                }
+                                _ => {
+                                    self.machine_st.heap[h] = heap_loc_as_cell!(l);
+                                }
+                            );
+                        }
                     } else {
                         self.machine_st.heap[h] = heap_loc_as_cell!(h);
                     }
index a41d4aefa6f6f1fce5c59c8426ce2d3472935fc2..0854a9f87b0d31f34702d8db03edcc46b35f66c9 100644 (file)
@@ -456,7 +456,41 @@ impl BrentAlgState {
     }
 }
 
+#[derive(Debug)]
+enum MatchSite {
+    NoMatchVarTail(usize), // no match, we refer to the location of the uninstantiated tail instead.
+    Match(usize), // a match
+}
+
+#[derive(Debug)]
+struct AttrListMatch {
+    match_site: MatchSite,
+    prev_tail: Option<usize>,
+}
+
 impl MachineState {
+    pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option<usize> {
+        read_heap_cell!(attr_var,
+            (HeapCellValueTag::AttrVar, h) => {
+                Some(h + 1)
+            }
+            (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                // create an AttrVar in the heap.
+                let h = self.heap.len();
+
+                self.heap.push(attr_var_as_cell!(h));
+                self.heap.push(heap_loc_as_cell!(h+1));
+
+                self.bind(Ref::attr_var(h), attr_var);
+
+                Some(h + 1)
+            }
+            _ => {
+                None
+            }
+        )
+    }
+
     pub(crate) fn name_and_arity_from_heap(&self, cell: HeapCellValue) -> Option<PredicateKey> {
         read_heap_cell!(self.store(self.deref(cell)),
             (HeapCellValueTag::Str, s) => {
@@ -4306,17 +4340,10 @@ impl Machine {
         let attr_var = self.deref_register(1);
         let attr_var_list = read_heap_cell!(attr_var,
             (HeapCellValueTag::AttrVar, h) => {
-                h + 1
+                h+1
             }
-            (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                // create an AttrVar in the heap.
-                let h = self.machine_st.heap.len();
-
-                self.machine_st.heap.push(attr_var_as_cell!(h));
-                self.machine_st.heap.push(heap_loc_as_cell!(h+1));
-
-                self.machine_st.bind(Ref::attr_var(h), attr_var);
-                h + 1
+            (HeapCellValueTag::Var, h) => {
+                h
             }
             _ => {
                 self.machine_st.fail = true;
@@ -4330,67 +4357,40 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn get_from_attributed_variable_list(&mut self) {
-        let mut attrs_list = self.deref_register(1);
-        let attr = self.deref_register(2);
-
-        let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
-            Some(key) => key,
-            None => {
+        let attr_var = self.deref_register(1);
+        let attr = self.deref_register(3);
+        let attr_var_list = read_heap_cell!(attr_var,
+            (HeapCellValueTag::AttrVar, h) => {
+                self.machine_st.heap[h+1]
+            }
+            _ => {
                 self.machine_st.fail = true;
                 return;
             }
-        };
-
-        while let HeapCellValueTag::Lis = attrs_list.get_tag() {
-            let mut list_head = self.machine_st.heap[attrs_list.get_value()];
-
-            loop {
-                read_heap_cell!(list_head,
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                        if list_head != self.machine_st.heap[h] {
-                            list_head = self.machine_st.heap[h];
-                        } else {
-                            self.machine_st.fail = true;
-                            return;
-                        }
-                    }
-                    (HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
-                        let (t_name, t_arity) = self.machine_st
-                            .name_and_arity_from_heap(list_head)
-                            .unwrap();
-
-                        if name == t_name && arity == t_arity {
-                            let old_tr = self.machine_st.tr;
-
-                            unify!(self.machine_st, list_head, attr);
+        );
 
-                            if self.machine_st.fail {
-                                let curr_tr = self.machine_st.trail.len();
+        let module = self.deref_register(2);
 
-                                self.unwind_trail(old_tr, curr_tr);
-                                self.machine_st.tr = old_tr;
+        match self.match_attribute(attr_var_list, module, attr) {
+            Some(AttrListMatch { match_site: MatchSite::Match(match_site), .. }) => {
+                let list_head = self.machine_st.heap[match_site];
 
-                                self.machine_st.pdl.clear();
-                                self.machine_st.fail = false;
-                            } else {
-                                return;
-                            }
-                        }
+                if list_head.get_value() == match_site {
+                    // at the end of the list, no match found in this case.
+                    self.machine_st.fail = true;
+                } else {
+                    let (_, qualified_goal) = self.machine_st.strip_module(
+                        list_head,
+                        empty_list_as_cell!(),
+                    );
 
-                        break;
-                    }
-                    _ => {
-                        break;
-                    }
-                );
+                    unify!(self.machine_st, qualified_goal, attr);
+                }
+            }
+            _ => {
+                self.machine_st.fail = true;
             }
-
-            attrs_list = self.machine_st.store(
-                self.machine_st.deref(self.machine_st.heap[attrs_list.get_value()+1])
-            );
         }
-
-        self.machine_st.fail = true;
     }
 
     #[inline(always)]
@@ -4427,81 +4427,202 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(crate) fn enqueue_attributed_var(&mut self) {
-        let addr = self.deref_register(1);
-
-        read_heap_cell!(addr,
+    pub(crate) fn delete_from_attributed_variable_list(&mut self) {
+        let attr_var = self.deref_register(1);
+        let attr = self.deref_register(3);
+        let attr_var_list = read_heap_cell!(attr_var,
             (HeapCellValueTag::AttrVar, h) => {
-                self.machine_st.attr_var_init.attr_var_queue.push(h);
+                h + 1
             }
             _ => {
+                return;
             }
         );
+
+        let module = self.deref_register(2);
+
+        match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
+            Some(AttrListMatch { prev_tail, match_site: MatchSite::Match(match_site) }) => {
+                let prev_tail = if let Some(prev_tail) = prev_tail {
+                    // not at the head.
+                    prev_tail
+                } else {
+                    if self.machine_st.heap[match_site + 1].is_var() {
+                        let h = attr_var.get_value();
+
+                        self.machine_st.heap[h] = heap_loc_as_cell!(h);
+                        self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
+                    }
+
+                    // at the head.
+                    attr_var_list
+                };
+
+                if self.machine_st.heap[match_site + 1].get_tag() == HeapCellValueTag::Lis {
+                    let prev_tail_value = self.machine_st.heap[match_site + 1].get_value();
+                    self.machine_st.heap[prev_tail].set_value(prev_tail_value);
+                } else {
+                    self.machine_st.heap[prev_tail] = heap_loc_as_cell!(prev_tail);
+                }
+
+                self.machine_st.trail(TrailRef::AttrVarListLink(prev_tail, match_site));
+            }
+            _ => {
+            }
+        }
     }
 
     #[inline(always)]
-    pub(crate) fn delete_attribute(&mut self) {
-        let ls0 = self.deref_register(1);
+    pub(crate) fn put_to_attributed_variable_list(&mut self) {
+        let attr_var = self.deref_register(1);
+        let attr = self.deref_register(3);
+        let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) {
+            Some(h) => h,
+            None => {
+                self.machine_st.fail = true;
+                return;
+            }
+        };
 
-        if let HeapCellValueTag::Lis = ls0.get_tag() {
-            let l1 = ls0.get_value();
-            let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
+        let module = self.deref_register(2);
+
+        /*
+         * How to handle attribute trailing using just AttrVarListLink (which
+         * should be re-named to something more general) in unwind_trail:
+         *
+         * Given AttrVarListLink(h, l):
+         *
+         * 1. Check cell at offset l.
+         * 2. If h == l, set heap[h] = heap_loc_as_cell!(h).
+         * 3. If cell is a Var, set heap[h] = list_loc_as_cell!(l).
+         * 4. Otherwise, cell points to an element of the list which is therefore
+         *    an atom or str. Set heap[h] accordingly.
+         *
+         * For this to work, all elements of attributed variable lists must be
+         * heap cell locs pointing to later elements in the heap, either atoms (0-arity)
+         * or str cells (> 0-arity).
+         */
 
-            if let HeapCellValueTag::Lis = ls1.get_tag() {
-                let l2 = ls1.get_value();
+        let h = self.machine_st.heap.len();
 
-                let old_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l1+1]));
-                let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
+        self.machine_st.heap.push(str_loc_as_cell!(h+1));
+        self.machine_st.heap.extend(functor!(atom!(":"), [cell(module), cell(attr)]));
 
-                let tail = if tail.is_var() {
-                    heap_loc_as_cell!(l1 + 1)
-                } else {
-                    tail
-                };
+        match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
+            Some(AttrListMatch { match_site, .. }) => {
+                let (match_site, l) = match match_site {
+                    MatchSite::NoMatchVarTail(match_site) => {
+                        let l = self.machine_st.heap[match_site].get_value();
 
-                let trail_ref = read_heap_cell!(old_addr,
-                    (HeapCellValueTag::Var, h) => {
-                        TrailRef::AttrVarHeapLink(h)
-                    }
-                    (HeapCellValueTag::Lis, l) => {
-                        TrailRef::AttrVarListLink(l1 + 1, l)
+                        // at the end of the (non-empty) list here.
+                        self.machine_st.heap[match_site] = list_loc_as_cell!(h+4);
+                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                        self.machine_st.heap.push(heap_loc_as_cell!(h+5));
+
+                        (match_site, l)
                     }
-                    _ => {
-                        unreachable!()
+                    MatchSite::Match(match_site) => {
+                        let l = self.machine_st.heap[match_site].get_value();
+                        self.machine_st.heap[match_site].set_value(h);
+
+                        (match_site, l)
                     }
-                );
+                };
+
+                self.machine_st.trail(TrailRef::AttrVarListLink(match_site, l));
+            }
+            None => {
+                // the list is empty.
+                self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h+4);
+                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                self.machine_st.heap.push(heap_loc_as_cell!(h+5));
 
-                self.machine_st.heap[l1 + 1] = tail;
-                self.machine_st.trail(trail_ref);
+                self.machine_st.attr_var_init.attr_var_queue.push(attr_var_list - 1);
+                self.machine_st.trail(TrailRef::AttrVarListLink(attr_var_list, attr_var_list));
             }
         }
     }
 
-    #[inline(always)]
-     pub(crate) fn delete_head_attribute(&mut self) {
-        let addr = self.deref_register(1);
+    fn match_attribute(
+        &self,
+        mut attrs_list: HeapCellValue,
+        module: HeapCellValue,
+        attr: HeapCellValue,
+    ) -> Option<AttrListMatch> {
+        let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
+            Some(key) => key,
+            None => {
+                return None;
+            }
+        };
 
-        debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
+        let mut prev_tail = None;
 
-        let h = addr.get_value();
-        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
+        while let HeapCellValueTag::Lis = attrs_list.get_tag() {
+            let mut list_head = self.machine_st.heap[attrs_list.get_value()];
 
-        debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
+            loop {
+                read_heap_cell!(list_head,
+                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+                        debug_assert!(list_head != self.machine_st.heap[h]);
+                        list_head = self.machine_st.heap[h];
+                    }
+                    (HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
+                        let (module_loc, qualified_goal) = self.machine_st.strip_module(
+                            list_head,
+                            empty_list_as_cell!(),
+                        );
 
-        let l = addr.get_value();
-        let tail = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l + 1]));
+                        let (t_name, t_arity) = self.machine_st
+                            .name_and_arity_from_heap(qualified_goal)
+                            .unwrap();
 
-        let tail = if tail.is_var() {
-            self.machine_st.heap[h] = heap_loc_as_cell!(h);
-            self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
+                        if module == module_loc && name == t_name && arity == t_arity {
+                            return Some(AttrListMatch {
+                                match_site: MatchSite::Match(attrs_list.get_value()),
+                                prev_tail,
+                            });
+                        }
 
-            heap_loc_as_cell!(h + 1)
-        } else {
-            tail
-        };
+                        break;
+                    }
+                    _ => {
+                        break;
+                    }
+                );
+            }
+
+            let tail_loc = attrs_list.get_value() + 1;
+            prev_tail = Some(tail_loc);
+
+            // do the work of self.store(self.deref(...)) but inline it
+            // for speed and simplify it.
+            let mut list_tail = self.machine_st.heap[tail_loc];
+
+            loop {
+                read_heap_cell!(list_tail,
+                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+                        if list_tail != self.machine_st.heap[h] {
+                            list_tail = self.machine_st.heap[h];
+                        } else {
+                            return Some(AttrListMatch {
+                                match_site: MatchSite::NoMatchVarTail(h),
+                                prev_tail,
+                            });
+                        }
+                    }
+                    (HeapCellValueTag::Lis) => {
+                        attrs_list = list_tail;
+                        break;
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                );
+            }
+        }
 
-        self.machine_st.heap[h + 1] = tail;
-        self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
+        None
     }
 
     #[inline(always)]