]> Repositorios git - scryer-prolog.git/commitdiff
no longer generate a choice point in bb_b_put/2 (#742)
authorMark Thom <[email protected]>
Tue, 23 Feb 2021 01:27:30 +0000 (18:27 -0700)
committerMark Thom <[email protected]>
Tue, 23 Feb 2021 01:27:30 +0000 (18:27 -0700)
src/clause_types.rs
src/lib/iso_ext.pl
src/machine/heap.rs
src/machine/machine_indices.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mod.rs
src/machine/system_calls.rs

index ecfd0cbf7a1d1f8d122c2991e020b12de768a668..1804040ab4ce12b0e3933cb522bb4f28f4ab7636 100644 (file)
@@ -186,7 +186,6 @@ pub enum SystemClauseType {
     EnqueueAttributeGoal,
     EnqueueAttributedVar,
     FetchGlobalVar,
-    FetchGlobalVarWithOffset,
     FirstStream,
     FlushOutput,
     GetByte,
@@ -240,14 +239,12 @@ pub enum SystemClauseType {
     RemoveCallPolicyCheck,
     RemoveInferenceCounter,
     ResetContinuationMarker,
-    ResetGlobalVarAtKey,
-    ResetGlobalVarAtOffset,
     RestoreCutPolicy,
     SetCutPoint(RegType),
     SetInput,
     SetOutput,
+    StoreBacktrackableGlobalVar,
     StoreGlobalVar,
-    StoreGlobalVarWithOffset,
     StreamProperty,
     SetStreamPosition,
     InferenceLevel,
@@ -434,9 +431,6 @@ impl SystemClauseType {
             &SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
             &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
             &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
-            &SystemClauseType::FetchGlobalVarWithOffset => {
-                clause_name!("$fetch_global_var_with_offset")
-            }
             &SystemClauseType::FirstStream => clause_name!("$first_stream"),
             &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
             &SystemClauseType::GetByte => clause_name!("$get_byte"),
@@ -527,10 +521,10 @@ impl SystemClauseType {
             &SystemClauseType::SetSeed => clause_name!("$set_seed"),
             &SystemClauseType::StreamProperty => clause_name!("$stream_property"),
             &SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
-            &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
-            &SystemClauseType::StoreGlobalVarWithOffset => {
-                clause_name!("$store_global_var_with_offset")
+            &SystemClauseType::StoreBacktrackableGlobalVar => {
+                clause_name!("$store_back_trackable_global_var")
             }
+            &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
             &SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
             &SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
             &SystemClauseType::EraseBall => clause_name!("$erase_ball"),
@@ -539,15 +533,10 @@ impl SystemClauseType {
             &SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
             &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
             &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
-            // &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
             &SystemClauseType::NextEP => clause_name!("$nextEP"),
             &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
             &SystemClauseType::ReadTerm => clause_name!("$read_term"),
             &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
-            &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
-            &SystemClauseType::ResetGlobalVarAtOffset => {
-                clause_name!("$reset_global_var_at_offset")
-            }
             &SystemClauseType::ResetBlock => clause_name!("$reset_block"),
             &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
             &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
@@ -654,9 +643,6 @@ impl SystemClauseType {
             ("$peek_code", 2) => Some(SystemClauseType::PeekCode),
             ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
             ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
-            ("$fetch_global_var_with_offset", 3) => {
-                Some(SystemClauseType::FetchGlobalVarWithOffset)
-            }
             ("$get_byte", 2) => Some(SystemClauseType::GetByte),
             ("$get_char", 2) => Some(SystemClauseType::GetChar),
             ("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
@@ -723,8 +709,6 @@ impl SystemClauseType {
             ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
             ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
             ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
-            ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
-            ("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
             ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
             ("$set_ball", 1) => Some(SystemClauseType::SetBall),
             ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
@@ -737,8 +721,8 @@ impl SystemClauseType {
             ("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
             ("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
             ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
-            ("$store_global_var_with_offset", 2) => {
-                Some(SystemClauseType::StoreGlobalVarWithOffset)
+            ("$store_backtrackable_global_var", 2) => {
+                Some(SystemClauseType::StoreBacktrackableGlobalVar)
             }
             ("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
             ("$term_variables", 2) => Some(SystemClauseType::TermVariables),
index fe5d4baf2ea5cdcb0cef2ff00f343fce0b585ee3..61a3fa2976fe1767e697890083833df0365506b4 100644 (file)
@@ -9,7 +9,7 @@
                     partial_string_tail/2, setup_call_cleanup/3,
                     call_nth/2, variant/2]).
 
-:- use_module(library(error), [can_be/2,domain_error/3]).
+:- use_module(library(error), [can_be/2, domain_error/3, type_error/3]).
 
 
 :- meta_predicate call_cleanup(0, 0).
@@ -22,34 +22,25 @@ forall(Generate, Test) :-
 
 %% (non-)backtrackable global variables.
 
-bb_put(Key, Value) :- atom(Key), !, '$store_global_var'(Key, Value).
-bb_put(Key, _) :- throw(error(type_error(atom, Key), bb_put/2)).
+bb_put(Key, Value) :-
+    (  atom(Key) ->
+       '$store_global_var'(Key, Value)
+    ;  type_error(atom, Key, bb_put/2)
+    ).
 
 %% backtrackable global variables.
 
-bb_b_put(Key, NewValue) :-
-    (  '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
-       call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
-                    reset_global_var_at_offset(Key, OldValue, OldOffset))
-    ;  call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
-                    reset_global_var_at_key(Key))
+bb_b_put(Key, Value) :-
+    (  atom(Key) ->
+       '$store_backtrackable_global_var'(Key, Value)
+    ;  type_error(atom, Key, bb_b_put/2)
     ).
 
-store_global_var_with_offset(Key, Value) :- '$store_global_var_with_offset'(Key, Value).
-
-store_global_var(Key, Value) :- '$store_global_var'(Key, Value).
-
-reset_global_var_at_key(Key) :- '$reset_global_var_at_key'(Key).
-
-reset_global_var_at_offset(Key, Value, Offset) :- '$reset_global_var_at_offset'(Key, Value, Offset).
-
-'$bb_get_with_offset'(Key, OldValue, Offset) :-
-    atom(Key), !, '$fetch_global_var_with_offset'(Key, OldValue, Offset).
-'$bb_get_with_offset'(Key, _, _) :-
-    throw(error(type_error(atom, Key), bb_b_put/2)).
-
-bb_get(Key, Value) :- atom(Key), !, '$fetch_global_var'(Key, Value).
-bb_get(Key, _) :- throw(error(type_error(atom, Key), bb_get/2)).
+bb_get(Key, Value) :-
+    (  atom(Key) ->
+       '$fetch_global_var'(Key, Value)
+    ;  type_error(atom, Key, bb_get/2)
+    ).
 
 
 call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
index 7f9323c119ac01c03a92d10bbef6b8f1c1d7ee1d..935bad8bfb64c2b9fd07ed5f03cf6ede14b94182 100644 (file)
@@ -206,6 +206,11 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
         }
     }
 
+    #[inline]
+    pub(crate) fn is_empty(&self) -> bool {
+        self.h() == 0
+    }
+
     #[inline]
     pub(crate) fn pop(&mut self) {
         let h = self.h();
index 336ab16c1594a0334f633e180c3138638c2ed47f..04a60feba79da7634baf45af51626578a5cdd392 100644 (file)
@@ -12,7 +12,6 @@ use crate::machine::partial_string::*;
 use crate::machine::raw_block::RawBlockTraits;
 use crate::machine::streams::Stream;
 use crate::machine::term_stream::LoadStatePayload;
-use crate::machine::Ball;
 use crate::machine::CompilationTarget;
 use crate::rug::{Integer, Rational};
 use ordered_float::OrderedFloat;
@@ -297,6 +296,8 @@ pub enum TrailRef {
     Ref(Ref),
     AttrVarHeapLink(usize),
     AttrVarListLink(usize, usize),
+    BlackboardEntry(usize),
+    BlackboardOffset(usize, usize), // key atom heap location, key value heap location
 }
 
 impl From<Ref> for TrailRef {
@@ -691,13 +692,7 @@ impl SubAssign<usize> for CodePtr {
 pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
 pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
 
-pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
-pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
-
-#[derive(Debug)]
-pub(crate) struct ModuleStub {
-    pub(crate) in_situ_code_dir: InSituCodeDir,
-}
+pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
 
 pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
 pub(crate) type StreamDir = BTreeSet<Stream>;
index b7ac7499e54498087e956599382be0cb1e962775..26686fd83c5f0844c5b49c5e1e447c08e2954879 100644 (file)
@@ -657,7 +657,12 @@ impl MachineState {
 pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
 
 pub(crate) trait CallPolicy: Any + fmt::Debug {
-    fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
+    fn retry_me_else(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
         let b = machine_st.b;
         let n = machine_st
             .stack
@@ -679,7 +684,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
         let curr_tr = machine_st.tr;
 
-        machine_st.unwind_trail(old_tr, curr_tr);
+        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
         machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
 
         machine_st.trail.truncate(machine_st.tr);
@@ -708,7 +713,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         Ok(())
     }
 
-    fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
+    fn retry(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
         let b = machine_st.b;
         let n = machine_st
             .stack
@@ -730,7 +740,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
         let curr_tr = machine_st.tr;
 
-        machine_st.unwind_trail(old_tr, curr_tr);
+        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
         machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
 
         machine_st.trail.truncate(machine_st.tr);
@@ -759,7 +769,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         Ok(())
     }
 
-    fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
+    fn trust(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
         let b = machine_st.b;
         let n = machine_st
             .stack
@@ -779,7 +794,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
         let curr_tr = machine_st.tr;
 
-        machine_st.unwind_trail(old_tr, curr_tr);
+        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
         machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
 
         machine_st.trail.truncate(machine_st.tr);
@@ -811,7 +826,11 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         Ok(())
     }
 
-    fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult {
+    fn trust_me(
+        &mut self,
+        machine_st: &mut MachineState,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
         let b = machine_st.b;
         let n = machine_st
             .stack
@@ -831,7 +850,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
         let curr_tr = machine_st.tr;
 
-        machine_st.unwind_trail(old_tr, curr_tr);
+        machine_st.unwind_trail(old_tr, curr_tr, global_variables);
         machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
 
         machine_st.trail.truncate(machine_st.tr);
@@ -1225,23 +1244,42 @@ impl CallPolicy for CWILCallPolicy {
         self.increment(machine_st)
     }
 
-    fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
-        self.prev_policy.retry_me_else(machine_st, offset)?;
+    fn retry_me_else(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
+        self.prev_policy.retry_me_else(machine_st, offset, global_variables)?;
         self.increment(machine_st)
     }
 
-    fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
-        self.prev_policy.retry(machine_st, offset)?;
+    fn retry(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
+        self.prev_policy.retry(machine_st, offset, global_variables)?;
         self.increment(machine_st)
     }
 
-    fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult {
-        self.prev_policy.trust_me(machine_st)?;
+    fn trust_me(
+        &mut self,
+        machine_st: &mut MachineState,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
+        self.prev_policy.trust_me(machine_st, global_variables)?;
         self.increment(machine_st)
     }
 
-    fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
-        self.prev_policy.trust(machine_st, offset)?;
+    fn trust(
+        &mut self,
+        machine_st: &mut MachineState,
+        offset: usize,
+        global_variables: &mut GlobalVarDir,
+    ) -> CallResult {
+        self.prev_policy.trust(machine_st, offset, global_variables)?;
         self.increment(machine_st)
     }
 
index d92a4f6f51a63e27a78701072bd7bb9149c4a795..5b946b0df8d1588f3051ca0f2f98c92eaf579a65 100644 (file)
@@ -621,6 +621,14 @@ impl MachineState {
                     self.tr += 1;
                 }
             }
+            TrailRef::BlackboardOffset(key_h, value_h) => {
+                self.trail.push(TrailRef::BlackboardOffset(key_h, value_h));
+                self.tr += 1;
+            }
+            TrailRef::BlackboardEntry(key_h) => {
+                self.trail.push(TrailRef::BlackboardEntry(key_h));
+                self.tr += 1;
+            }
         }
     }
 
@@ -644,7 +652,12 @@ impl MachineState {
         }
     }
 
-    pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
+    pub(super) fn unwind_trail(
+        &mut self,
+        a1: usize,
+        a2: usize,
+        global_variables: &mut GlobalVarDir,
+    ) {
         // the sequence is reversed to respect the chronology of trail
         // additions, now that deleted attributes can be undeleted by
         // backtracking.
@@ -665,6 +678,30 @@ impl MachineState {
                 TrailRef::AttrVarListLink(h, l) => {
                     self.heap[h] = HeapCellValue::Addr(Addr::Lis(l));
                 }
+                TrailRef::BlackboardOffset(key_h, value_h) => {
+                    let key = atom_from!(
+                        self,
+                        self.store(self.deref(self.heap[key_h].as_addr(key_h)))
+                    );
+
+                    let value_addr = self.heap[value_h].as_addr(value_h);
+
+                    match global_variables.get_mut(&key) {
+                        Some((_, ref mut loc)) => *loc = Some(value_addr),
+                        None => unreachable!(),
+                    }
+                }
+                TrailRef::BlackboardEntry(key_h) => {
+                    let key = atom_from!(
+                        self,
+                        self.store(self.deref(self.heap[key_h].as_addr(key_h)))
+                    );
+
+                    match global_variables.get_mut(&key) {
+                        Some((_, ref mut loc)) => *loc = None,
+                        None => unreachable!(),
+                    }
+                }
             }
         }
     }
@@ -1266,6 +1303,7 @@ impl MachineState {
         &mut self,
         indexing_lines: &Vec<IndexingLine>,
         call_policy: &mut Box<dyn CallPolicy>,
+        global_variables: &mut GlobalVarDir,
     ) {
         let mut index = 0;
         let addr = match &indexing_lines[0] {
@@ -1372,7 +1410,12 @@ impl MachineState {
                         unreachable!()
                     }
 
-                    self.execute_indexed_choice_instr(instrs.first().unwrap(), call_policy);
+                    self.execute_indexed_choice_instr(
+                        instrs.first().unwrap(),
+                        call_policy,
+                        global_variables,
+                    );
+
                     break;
                 }
             }
@@ -2989,6 +3032,7 @@ impl MachineState {
         &mut self,
         instr: &IndexedChoiceInstruction,
         call_policy: &mut Box<dyn CallPolicy>,
+        global_variables: &mut GlobalVarDir,
     ) {
         match instr {
             &IndexedChoiceInstruction::Try(offset) => {
@@ -3018,10 +3062,10 @@ impl MachineState {
                 self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
             }
             &IndexedChoiceInstruction::Retry(l) => {
-                try_or_fail!(self, call_policy.retry(self, l));
+                try_or_fail!(self, call_policy.retry(self, l, global_variables));
             }
             &IndexedChoiceInstruction::Trust(l) => {
-                try_or_fail!(self, call_policy.trust(self, l));
+                try_or_fail!(self, call_policy.trust(self, l, global_variables));
             }
         };
     }
@@ -3030,6 +3074,7 @@ impl MachineState {
         &mut self,
         instr: &ChoiceInstruction,
         call_policy: &mut Box<dyn CallPolicy>,
+        global_variables: &mut GlobalVarDir,
     ) {
         match instr {
             &ChoiceInstruction::TryMeElse(offset) => {
@@ -3059,17 +3104,17 @@ impl MachineState {
             }
             &ChoiceInstruction::DefaultRetryMeElse(offset) => {
                 let mut call_policy = DefaultCallPolicy {};
-                try_or_fail!(self, call_policy.retry_me_else(self, offset))
+                try_or_fail!(self, call_policy.retry_me_else(self, offset, global_variables))
             }
             &ChoiceInstruction::DefaultTrustMe(_) => {
                 let mut call_policy = DefaultCallPolicy {};
-                try_or_fail!(self, call_policy.trust_me(self))
+                try_or_fail!(self, call_policy.trust_me(self, global_variables))
             }
             &ChoiceInstruction::RetryMeElse(offset) => {
-                try_or_fail!(self, call_policy.retry_me_else(self, offset))
+                try_or_fail!(self, call_policy.retry_me_else(self, offset, global_variables))
             }
             &ChoiceInstruction::TrustMe(_) => {
-                try_or_fail!(self, call_policy.trust_me(self))
+                try_or_fail!(self, call_policy.trust_me(self, global_variables))
             }
         }
     }
index 6e3bd4eb3e7c1c936488f503e4a4fc23708ac6db..d23580bad0a634cc85f331d8510bc0039e729e3e 100644 (file)
@@ -560,7 +560,11 @@ impl MachineState {
         match instr {
             &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
             &Line::Choice(ref choice_instr) => {
-                self.execute_choice_instr(choice_instr, &mut policies.call_policy)
+                self.execute_choice_instr(
+                    choice_instr,
+                    &mut policies.call_policy,
+                    &mut indices.global_variables,
+                )
             }
             &Line::Cut(ref cut_instr) => {
                 self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
@@ -579,10 +583,18 @@ impl MachineState {
                 self.p += 1;
             }
             &Line::IndexingCode(ref indexing_lines) => {
-                self.execute_indexing_instr(indexing_lines, &mut policies.call_policy)
+                self.execute_indexing_instr(
+                    indexing_lines,
+                    &mut policies.call_policy,
+                    &mut indices.global_variables,
+                )
             }
             &Line::IndexedChoice(ref choice_instr) => {
-                self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
+                self.execute_indexed_choice_instr(
+                    choice_instr,
+                    &mut policies.call_policy,
+                    &mut indices.global_variables,
+                )
             }
             &Line::Query(ref query_instr) => {
                 self.execute_query_instr(&query_instr);
index 0d94fd1c94065f2c364e6a2f356dc013b0fcc3df..72e6b3a9891bdb2f9b2e8ac51e58088a129ae3fa 100644 (file)
@@ -1850,12 +1850,10 @@ impl MachineState {
                 self.copy_term(AttrVarPolicy::StripAttributes);
             }
             &SystemClauseType::FetchGlobalVar => {
-                let key = self[temp_v!(1)];
-
-                let key = match self.store(self.deref(key)) {
+                let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) {
                     Addr::Con(h) if self.heap.atom_at(h) => {
                         if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
-                            atom.clone()
+                            (h, atom.clone())
                         } else {
                             unreachable!()
                         }
@@ -1868,52 +1866,24 @@ impl MachineState {
                 let addr = self[temp_v!(2)];
 
                 match indices.global_variables.get_mut(&key) {
-                    Some((ref mut ball, None)) => {
-                        let h = self.heap.h();
-                        let stub = ball.copy_and_align(h);
-
-                        self.heap.extend(stub.into_iter());
-                        self.unify(addr, Addr::HeapCell(h));
-                    }
-                    Some((_, Some(h))) => self.unify(addr, Addr::HeapCell(*h)),
-                    None => self.fail = true,
-                };
-            }
-            &SystemClauseType::FetchGlobalVarWithOffset => {
-                let key = self[temp_v!(1)];
-
-                let key = match self.store(self.deref(key)) {
-                    Addr::Con(h) if self.heap.atom_at(h) => {
-                        if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
-                            atom.clone()
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
-
-                let addr = self[temp_v!(2)];
-
-                match indices.global_variables.get_mut(&key) {
-                    Some((ref mut ball, ref mut offset @ None)) => {
-                        let h = self.heap.h();
-                        let stub = ball.copy_and_align(h);
-
-                        self.heap.extend(stub.into_iter());
-                        self.unify(addr, Addr::HeapCell(h));
-
-                        *offset = Some(h);
-                    }
-                    Some((_, Some(h))) => {
-                        let offset = self[temp_v!(3)];
+                    Some((ref ball, ref mut loc)) => {
+                        match loc {
+                            Some(ref value_addr) => {
+                                self.unify(addr, *value_addr);
+                            }
+                            loc @ None if !ball.stub.is_empty() => {
+                                let h = self.heap.h();
+                                let stub = ball.copy_and_align(h);
 
-                        self.unify(offset, Addr::Usize(*h));
+                                self.heap.extend(stub.into_iter());
+                                self.unify(addr, Addr::HeapCell(h));
 
-                        if !self.fail {
-                            self.unify(addr, Addr::HeapCell(*h));
+                                if !self.fail {
+                                    *loc = Some(Addr::HeapCell(h));
+                                    self.trail(TrailRef::BlackboardEntry(key_h));
+                                }
+                            }
+                            _ => self.fail = true,
                         }
                     }
                     None => self.fail = true,
@@ -3572,6 +3542,7 @@ impl MachineState {
                     }
                 }
             }
+            /*
             &SystemClauseType::ResetGlobalVarAtKey => {
                 let key = self[temp_v!(1)];
 
@@ -3626,6 +3597,7 @@ impl MachineState {
                     }
                 }
             }
+            */
             &SystemClauseType::ResetAttrVarState => {
                 self.attr_var_init.reset();
             }
@@ -4539,9 +4511,7 @@ impl MachineState {
                 self.unify(self[temp_v!(3)], property);
             }
             &SystemClauseType::StoreGlobalVar => {
-                let key = self[temp_v!(1)];
-
-                let key = match self.store(self.deref(key)) {
+                let key = match self.store(self.deref(self[temp_v!(1)])) {
                     Addr::Con(h) if self.heap.atom_at(h) => {
                         if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
                             atom.clone()
@@ -4567,13 +4537,11 @@ impl MachineState {
 
                 indices.global_variables.insert(key, (ball, None));
             }
-            &SystemClauseType::StoreGlobalVarWithOffset => {
-                let key = self[temp_v!(1)];
-
-                let key = match self.store(self.deref(key)) {
+            &SystemClauseType::StoreBacktrackableGlobalVar => {
+                let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) {
                     Addr::Con(h) if self.heap.atom_at(h) => {
                         if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
-                            atom.clone()
+                            (h, atom.clone())
                         } else {
                             unreachable!()
                         }
@@ -4583,24 +4551,27 @@ impl MachineState {
                     }
                 };
 
-                let value = self[temp_v!(2)];
-                let mut ball = Ball::new();
-                let h = self.heap.h();
-
-                ball.boundary = h;
+                let new_value = self.store(self.deref(self[temp_v!(2)]));
 
-                copy_term(
-                    CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub),
-                    value,
-                    AttrVarPolicy::DeepCopy,
-                );
-
-                let stub = ball.copy_and_align(h);
-                self.heap.extend(stub.into_iter());
-
-                indices.global_variables.insert(key, (ball, Some(h)));
-
-                self.unify(value, Addr::HeapCell(h));
+                match indices.global_variables.get_mut(&key) {
+                    Some((_, ref mut loc)) => {
+                        match loc {
+                            Some(ref mut value) => {
+                                let old_value_loc = self.heap.push(HeapCellValue::Addr(*value));
+                                self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc));
+                                *value = new_value;
+                            }
+                            loc @ None => {
+                                self.trail(TrailRef::BlackboardEntry(key_h));
+                                *loc = Some(new_value);
+                            }
+                        }
+                    }
+                    None => {
+                        self.trail(TrailRef::BlackboardEntry(key_h));
+                        indices.global_variables.insert(key, (Ball::new(), Some(new_value)));
+                    }
+                }
             }
             &SystemClauseType::Succeed => {}
             &SystemClauseType::TermAttributedVariables => {