From 9c9c484ee4ef858efcdf02b8d58da63ab11f01c5 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 29 Nov 2019 00:44:23 -0700 Subject: [PATCH 01/21] add copy_term/3 (#232) --- README.md | 2 +- src/prolog/clause_types.rs | 3 + src/prolog/lib/atts.pl | 1 + src/prolog/machine/copier.rs | 72 ++++++++++++++++++------ src/prolog/machine/machine_state.rs | 2 +- src/prolog/machine/machine_state_impl.rs | 5 +- src/prolog/machine/project_attributes.pl | 7 +++ src/prolog/machine/system_calls.rs | 12 +++- 8 files changed, 81 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d6c31433..63614499 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ The following predicates are built-in to Scryer. * `clause/2` * `compare/3` * `compound/1` -* `copy_term/2` +* `copy_term/{2,3}` * `current_predicate/1` * `current_op/3` * `cyclic_term/1` diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 82bd8cde..a8246405 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -166,6 +166,7 @@ pub enum SystemClauseType { CharCode, CharsToNumber, CodesToNumber, + CopyTermWithoutAttrVars, CheckCutPoint, CopyToLiftedHeap, DeleteAttribute, @@ -264,6 +265,7 @@ impl SystemClauseType { &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), + &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), @@ -392,6 +394,7 @@ impl SystemClauseType { ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), + ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), diff --git a/src/prolog/lib/atts.pl b/src/prolog/lib/atts.pl index 3fc36974..75d01ed5 100644 --- a/src/prolog/lib/atts.pl +++ b/src/prolog/lib/atts.pl @@ -149,3 +149,4 @@ call_residue_vars(Goal, Vars) :- '$get_attr_var_queue_delim'(B), call(Goal), '$get_attr_var_queue_beyond'(B, Vars). + diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 68897044..f900ec8f 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -5,6 +5,12 @@ use std::ops::IndexMut; type Trail = Vec<(Ref, HeapCellValue)>; +#[derive(Clone, Copy)] +pub enum AttrVarPolicy { + DeepCopy, + StripAttributes +} + pub(crate) trait CopierTarget: IndexMut { fn threshold(&self) -> usize; fn push(&mut self, _: HeapCellValue); @@ -13,9 +19,10 @@ pub(crate) trait CopierTarget: IndexMut { fn stack(&mut self) -> &mut AndStack; } -pub(crate) fn copy_term(target: T, addr: Addr) { - let mut copy_term_state = CopyTermState::new(target); - copy_term_state.copy_term_impl(addr); +pub(crate) +fn copy_term(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { + let mut copy_term_state = CopyTermState::new(target, attr_var_policy); + copy_term_state.copy_term_impl(addr); } struct CopyTermState { @@ -23,15 +30,17 @@ struct CopyTermState { scan: usize, old_h: usize, target: T, + attr_var_policy: AttrVarPolicy } impl CopyTermState { - fn new(target: T) -> Self { + fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self { CopyTermState { trail: vec![], scan: 0, old_h: target.threshold(), target, + attr_var_policy } } @@ -41,6 +50,14 @@ impl CopyTermState { &mut self.target[scan] } + fn attr_var_redirect_tag(&self) -> impl Fn(usize) -> Addr { + if let AttrVarPolicy::DeepCopy = self.attr_var_policy { + Addr::AttrVar + } else { + Addr::HeapCell + } + } + fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) { match addr { Addr::HeapCell(h) => { @@ -58,8 +75,10 @@ impl CopyTermState { )); } Addr::AttrVar(h) => { - self.target[threshold] = HeapCellValue::Addr(Addr::AttrVar(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::AttrVar(threshold)); + let redirect_tag = self.attr_var_redirect_tag(); + + self.target[threshold] = HeapCellValue::Addr(redirect_tag(threshold)); + self.target[h] = HeapCellValue::Addr(redirect_tag(threshold)); self.trail .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)))); } @@ -94,10 +113,22 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(ra)); match rd.clone() { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) if h >= self.old_h => { + let redirect_tag = self.attr_var_redirect_tag(); + self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); + } + Addr::HeapCell(h) if h >= self.old_h => { self.target[threshold] = HeapCellValue::Addr(rd) } - ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { + Addr::AttrVar(h) => { + if Addr::AttrVar(h) == rd { + self.reinstantiate_var(Addr::AttrVar(h), threshold); + } else { + let redirect_tag = self.attr_var_redirect_tag(); + self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); + } + } + ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { if ra == rd { self.reinstantiate_var(ra, threshold); } else { @@ -121,20 +152,29 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(addr.clone())); match rd.clone() { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) if h >= self.old_h => { + let redirect_tag = self.attr_var_redirect_tag(); + *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(h)); + self.scan += 1; + } + Addr::HeapCell(h) if h >= self.old_h => { *self.value_at_scan() = HeapCellValue::Addr(rd); self.scan += 1; } Addr::AttrVar(h) if addr == rd => { + let redirect_tag = self.attr_var_redirect_tag(); let threshold = self.target.threshold(); - self.target - .push(HeapCellValue::Addr(Addr::AttrVar(threshold))); - let list_val = self.target[h + 1].clone(); - self.target.push(list_val); + self.target + .push(HeapCellValue::Addr(redirect_tag(threshold))); + + if let Addr::AttrVar(_) = redirect_tag(threshold) { + let list_val = self.target[h + 1].clone(); + self.target.push(list_val); + } self.reinstantiate_var(addr, threshold); - *self.value_at_scan() = HeapCellValue::Addr(Addr::AttrVar(threshold)); + *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(threshold)); } _ if addr == rd => { let scan = self.scan; @@ -185,8 +225,8 @@ impl CopyTermState { HeapCellValue::Addr(addr) => match addr { Addr::Lis(addr) => self.copy_list(addr), addr @ Addr::AttrVar(_) - | addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) => self.copy_var(addr), + | addr @ Addr::HeapCell(_) + | addr @ Addr::StackCell(..) => self.copy_var(addr), Addr::Str(addr) => self.copy_structure(addr), Addr::Con(_) | Addr::DBRef(_) => self.scan += 1, }, diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index d09b5745..3d451f7d 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -729,7 +729,7 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::CopyTerm => { - machine_st.copy_term(); + machine_st.copy_term(AttrVarPolicy::DeepCopy); return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Eq => { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index f48d77ff..9b913e83 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -2044,6 +2044,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut self.ball.stub), addr, + AttrVarPolicy::DeepCopy, ); } @@ -2941,13 +2942,13 @@ impl MachineState { } } - pub(super) fn copy_term(&mut self) { + pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { let old_h = self.heap.h; let a1 = self[temp_v!(1)].clone(); let a2 = self[temp_v!(2)].clone(); - copy_term(CopyTerm::new(self), a1); + copy_term(CopyTerm::new(self), a1, attr_var_policy); self.unify(Addr::HeapCell(old_h), a2); } diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 7349bdf5..60980406 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -83,3 +83,10 @@ gather_modules_for_attrs(Attrs, Modules, Modules) :- gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :- '$module_of'(Module, Attr), gather_modules_for_attrs(Attrs, Modules, Modules0). + +copy_term(Source, Dest, Goals) :- + term_variables(Source, Vars), + gather_modules(Vars, Modules, _), + call_attribute_goals(Modules, call_query_var_goals, Vars), + '$fetch_attribute_goals'(Goals0), + '$copy_term_without_attr_vars'([Source | Goals0], [Dest | Goals]). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index e168849b..f66ef274 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -353,7 +353,7 @@ impl MachineState { copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); - copy_term(copy_ball_term, copy_target); + copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); threshold + lh_offset + 2 } @@ -867,6 +867,9 @@ impl MachineState { _ => self.fail = true, }; } + &SystemClauseType::CopyTermWithoutAttrVars => { + self.copy_term(AttrVarPolicy::StripAttributes); + } &SystemClauseType::FetchGlobalVar => { let key = self[temp_v!(1)].clone(); @@ -1364,7 +1367,7 @@ impl MachineState { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } &SystemClauseType::FetchAttributeGoals => { - let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + let mut attr_goals = self.attr_var_init.attribute_goals.clone(); attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); self.term_dedup(&mut attr_goals); @@ -1667,6 +1670,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, + AttrVarPolicy::DeepCopy, ); let offset = self[temp_v!(3)].clone(); @@ -1905,7 +1909,7 @@ impl MachineState { ContinueResult::ContinueQuery => ';', ContinueResult::Conclude => '.' }; - + let target = self[temp_v!(1)].clone(); self.unify(Addr::Con(Constant::Char(c)), target); } @@ -1970,6 +1974,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, + AttrVarPolicy::DeepCopy, ); indices.global_variables.insert(key, (ball, None)); @@ -1990,6 +1995,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value.clone(), + AttrVarPolicy::DeepCopy, ); let stub = ball.copy_and_align(h); From 34745f6242035c61de6f80604d25c367b5389910 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 29 Nov 2019 00:59:31 -0700 Subject: [PATCH 02/21] clone attribute goals from copy_term/3, fetch attribute goals should be a move --- src/prolog/clause_types.rs | 3 +++ src/prolog/machine/project_attributes.pl | 2 +- src/prolog/machine/system_calls.rs | 33 ++++++++++++++---------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index a8246405..e4bae2ae 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -165,6 +165,7 @@ pub enum SystemClauseType { CallAttributeGoals, CharCode, CharsToNumber, + CloneAttributeGoals, CodesToNumber, CopyTermWithoutAttrVars, CheckCutPoint, @@ -264,6 +265,7 @@ impl SystemClauseType { &SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"), &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), + &SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), @@ -393,6 +395,7 @@ impl SystemClauseType { ("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), + ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 60980406..76cccca2 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -88,5 +88,5 @@ copy_term(Source, Dest, Goals) :- term_variables(Source, Vars), gather_modules(Vars, Modules, _), call_attribute_goals(Modules, call_query_var_goals, Vars), - '$fetch_attribute_goals'(Goals0), + '$clone_attribute_goals'(Goals0), '$copy_term_without_attr_vars'([Source | Goals0], [Dest | Goals]). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index f66ef274..22e9c1ea 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -527,6 +527,16 @@ impl MachineState { Ok(()) } + fn fetch_attribute_goals(&mut self, mut attr_goals: Vec) { + attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); + self.term_dedup(&mut attr_goals); + + let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter())); + let target = self[temp_v!(1)].clone(); + + self.unify(attr_goals, target); + } + fn create_instruction_functors(&mut self, code: &Code, first_idx: usize) -> Vec { let mut queue = VecDeque::new(); let mut functors = vec![]; @@ -1105,7 +1115,7 @@ impl MachineState { for i in (arity + 1 .. arity + narity + 1).rev() { self.registers[i] = self.registers[i - arity].clone(); } - + for i in 1 .. arity + 1 { self.registers[i] = self.heap[a + i].as_addr(a + i); } @@ -1118,7 +1128,7 @@ impl MachineState { ); } } - Addr::Con(Constant::Atom(name, _)) => { + Addr::Con(Constant::Atom(name, _)) => { return self.module_lookup(indices, (name, narity), module_name, true) } addr => { @@ -1366,16 +1376,13 @@ impl MachineState { &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } + &SystemClauseType::CloneAttributeGoals => { + let attr_goals = self.attr_var_init.attribute_goals.clone(); + self.fetch_attribute_goals(attr_goals); + } &SystemClauseType::FetchAttributeGoals => { - let mut attr_goals = self.attr_var_init.attribute_goals.clone(); - - attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); - self.term_dedup(&mut attr_goals); - - let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter())); - let target = self[temp_v!(1)].clone(); - - self.unify(attr_goals, target); + let attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + self.fetch_attribute_goals(attr_goals); } &SystemClauseType::GetAttributedVariableList => { let attr_var = self.store(self.deref(self[temp_v!(1)].clone())); @@ -1424,7 +1431,7 @@ impl MachineState { let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let list_addr = self[temp_v!(2)].clone(); - + self.unify(var_list_addr, list_addr); } else { self.fail = true; @@ -1909,7 +1916,7 @@ impl MachineState { ContinueResult::ContinueQuery => ';', ContinueResult::Conclude => '.' }; - + let target = self[temp_v!(1)].clone(); self.unify(Addr::Con(Constant::Char(c)), target); } From 2d719ab6b79d6fc490ce0ac6a4f7eddfddd36a7a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 29 Nov 2019 10:59:20 -0400 Subject: [PATCH 03/21] create a list of module-prefixed goals in copy_term/3 --- src/prolog/machine/project_attributes.pl | 28 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 76cccca2..3882181c 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -49,8 +49,8 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :- call_query_var_goals([], _, []). call_query_var_goals([AttrVar|AttrVars], Module, Goals) :- - ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0), - atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) + ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0) + ; atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) ), E, ( '$print_attribute_goals_exception'(Module, E), @@ -84,9 +84,25 @@ gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :- '$module_of'(Module, Attr), gather_modules_for_attrs(Attrs, Modules, Modules0). +module_prefixed_goals([], _, Gs, Gs). +module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :- + ( G = _:_ -> MG = G + ; MG = Module:G + ), + module_prefixed_goals(Gs, Module, MGs, TailGs). + +call_attribute_goals_with_module_prefix([], _, _, []). +call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars, Goals) :- + call(GoalCaller, AttrVars, Module, Goals0), + enqueue_goals(Goals0), + module_prefixed_goals(Goals0, Module, Goals, Gs), + call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs). + copy_term(Source, Dest, Goals) :- term_variables(Source, Vars), - gather_modules(Vars, Modules, _), - call_attribute_goals(Modules, call_query_var_goals, Vars), - '$clone_attribute_goals'(Goals0), - '$copy_term_without_attr_vars'([Source | Goals0], [Dest | Goals]). + gather_modules(Vars, Modules0, _), + sort(Modules0, Modules), + call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0), + sort(Goals0, Goals1), + !, + '$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]). From 3e49db1a296b84c21de70ed61175c6394ffc6196 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 29 Nov 2019 13:47:22 -0400 Subject: [PATCH 04/21] backtrack attributed variable bindings after failure (#242) --- src/prolog/machine/attributed_variables.pl | 2 +- src/prolog/machine/attributed_variables.rs | 12 +++- src/prolog/machine/copier.rs | 82 ++++++++++------------ src/prolog/machine/machine_state.rs | 48 +++++++------ src/prolog/machine/machine_state_impl.rs | 2 + src/prolog/machine/or_stack.rs | 15 ++-- src/prolog/toplevel.pl | 3 +- 7 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/prolog/machine/attributed_variables.pl b/src/prolog/machine/attributed_variables.pl index 1323d2f5..8d896083 100644 --- a/src/prolog/machine/attributed_variables.pl +++ b/src/prolog/machine/attributed_variables.pl @@ -28,7 +28,7 @@ call_verify_attributes(Attrs, _, _, []) :- call_verify_attributes([], _, _, []). call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :- gather_modules([Attr|Attrs], Modules0), - sort(Modules0, Modules), + sort(Modules0, Modules), verify_attrs(Modules, Var, Value, ListOfGoalLists). call_goals([ListOfGoalLists | ListsCubed]) :- diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 50a101b9..8631fca7 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -36,19 +36,25 @@ impl AttrVarInitializer { self.attr_var_queue.clear(); self.bindings.clear(); } + + #[inline] + pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) { + self.attr_var_queue.truncate(queue_b); + self.bindings.truncate(bindings_b); + } } impl MachineState { pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) { if self.attr_var_init.bindings.is_empty() { self.attr_var_init.instigating_p = self.p.local(); - + if self.last_call { self.attr_var_init.cp = self.cp; } else { self.attr_var_init.cp = self.p.local() + 1; } - + self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc); } @@ -61,6 +67,7 @@ impl MachineState { .bindings .iter() .map(|(ref h, _)| Addr::AttrVar(*h)); + let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let iter = self @@ -68,6 +75,7 @@ impl MachineState { .bindings .iter() .map(|(_, ref addr)| addr.clone()); + let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); (var_list_addr, value_list_addr) diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index f900ec8f..2c65da69 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -58,34 +58,6 @@ impl CopyTermState { } } - fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) { - match addr { - Addr::HeapCell(h) => { - self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.trail - .push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h)))); - } - Addr::StackCell(fr, sc) => { - self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target.stack()[fr][sc] = Addr::HeapCell(threshold); - self.trail.push(( - Ref::StackCell(fr, sc), - HeapCellValue::Addr(Addr::StackCell(fr, sc)), - )); - } - Addr::AttrVar(h) => { - let redirect_tag = self.attr_var_redirect_tag(); - - self.target[threshold] = HeapCellValue::Addr(redirect_tag(threshold)); - self.target[h] = HeapCellValue::Addr(redirect_tag(threshold)); - self.trail - .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)))); - } - _ => {} - } - } - fn copied_list(&mut self, addr: usize) -> bool { if let HeapCellValue::Addr(Addr::Lis(addr)) = self.target[addr].clone() { if addr >= self.old_h { @@ -113,22 +85,10 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(ra)); match rd.clone() { - Addr::AttrVar(h) if h >= self.old_h => { - let redirect_tag = self.attr_var_redirect_tag(); - self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); - } - Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { self.target[threshold] = HeapCellValue::Addr(rd) } - Addr::AttrVar(h) => { - if Addr::AttrVar(h) == rd { - self.reinstantiate_var(Addr::AttrVar(h), threshold); - } else { - let redirect_tag = self.attr_var_redirect_tag(); - self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); - } - } - ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { + ra @ Addr::AttrVar(..) | ra @ Addr::HeapCell(_) | ra @ Addr::StackCell(..) => { if ra == rd { self.reinstantiate_var(ra, threshold); } else { @@ -148,6 +108,38 @@ impl CopyTermState { self.scan += 1; } + fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) { + match addr { + Addr::HeapCell(h) => { + self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.trail.push(( + Ref::HeapCell(h), + HeapCellValue::Addr(Addr::HeapCell(h)), + )); + } + Addr::StackCell(fr, sc) => { + self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target.stack()[fr][sc] = Addr::HeapCell(threshold); + self.trail.push(( + Ref::StackCell(fr, sc), + HeapCellValue::Addr(Addr::StackCell(fr, sc)), + )); + } + Addr::AttrVar(h) => { + let redirect_tag = self.attr_var_redirect_tag(); + + self.target[threshold] = HeapCellValue::Addr(redirect_tag(threshold)); + self.target[h] = HeapCellValue::Addr(redirect_tag(threshold)); + self.trail.push(( + Ref::AttrVar(h), + HeapCellValue::Addr(Addr::AttrVar(h)), + )); + } + _ => unreachable!() + } + } + fn copy_var(&mut self, addr: Addr) { let rd = self.target.store(self.target.deref(addr.clone())); @@ -168,7 +160,7 @@ impl CopyTermState { self.target .push(HeapCellValue::Addr(redirect_tag(threshold))); - if let Addr::AttrVar(_) = redirect_tag(threshold) { + if let AttrVarPolicy::DeepCopy = self.attr_var_policy { let list_val = self.target[h + 1].clone(); self.target.push(list_val); } @@ -181,7 +173,9 @@ impl CopyTermState { self.reinstantiate_var(addr, scan); self.scan += 1; } - _ => *self.value_at_scan() = HeapCellValue::Addr(rd), + _ => { + *self.value_at_scan() = HeapCellValue::Addr(rd); + } } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 3d451f7d..20162ac1 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -445,11 +445,13 @@ pub(crate) trait CallPolicy: Any { machine_st.heap.truncate(machine_st.or_stack[b].h); - let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b; - machine_st - .attr_var_init - .attr_var_queue - .truncate(attr_var_init_b); + let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st.or_stack[b].attr_var_init_bindings_b; + + machine_st.attr_var_init.backtrack( + attr_var_init_queue_b, + attr_var_init_bindings_b, + ); machine_st.hb = machine_st.heap.h; machine_st.p += 1; @@ -491,11 +493,13 @@ pub(crate) trait CallPolicy: Any { machine_st.heap.truncate(machine_st.or_stack[b].h); - let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b; - machine_st - .attr_var_init - .attr_var_queue - .truncate(attr_var_init_b); + let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st.or_stack[b].attr_var_init_bindings_b; + + machine_st.attr_var_init.backtrack( + attr_var_init_queue_b, + attr_var_init_bindings_b, + ); machine_st.hb = machine_st.heap.h; machine_st.p += offset; @@ -533,11 +537,13 @@ pub(crate) trait CallPolicy: Any { machine_st.heap.truncate(machine_st.or_stack[b].h); - let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b; - machine_st - .attr_var_init - .attr_var_queue - .truncate(attr_var_init_b); + let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st.or_stack[b].attr_var_init_bindings_b; + + machine_st.attr_var_init.backtrack( + attr_var_init_queue_b, + attr_var_init_bindings_b, + ); machine_st.b = machine_st.or_stack[b].b; machine_st.or_stack.truncate(machine_st.b); @@ -580,12 +586,14 @@ pub(crate) trait CallPolicy: Any { machine_st.heap.truncate(machine_st.or_stack[b].h); - let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b; - machine_st - .attr_var_init - .attr_var_queue - .truncate(attr_var_init_b); + let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; + let attr_var_init_bindings_b = machine_st.or_stack[b].attr_var_init_bindings_b; + machine_st.attr_var_init.backtrack( + attr_var_init_queue_b, + attr_var_init_bindings_b, + ); + machine_st.b = machine_st.or_stack[b].b; machine_st.or_stack.truncate(machine_st.b); diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 9b913e83..f28eb077 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -3300,6 +3300,7 @@ impl MachineState { self.e, self.cp.clone(), self.attr_var_init.attr_var_queue.len(), + self.attr_var_init.bindings.len(), self.b, self.p.clone() + 1, self.tr, @@ -3339,6 +3340,7 @@ impl MachineState { self.e, self.cp.clone(), self.attr_var_init.attr_var_queue.len(), + self.attr_var_init.bindings.len(), self.b, self.p.clone() + offset, self.tr, diff --git a/src/prolog/machine/or_stack.rs b/src/prolog/machine/or_stack.rs index edde5722..8cf0f884 100644 --- a/src/prolog/machine/or_stack.rs +++ b/src/prolog/machine/or_stack.rs @@ -8,7 +8,8 @@ pub struct Frame { pub global_index: usize, pub e: usize, pub cp: LocalCodePtr, - pub attr_var_init_b: usize, + pub attr_var_init_queue_b: usize, + pub attr_var_init_bindings_b: usize, pub b: usize, pub bp: CodePtr, pub tr: usize, @@ -23,7 +24,8 @@ impl Frame { global_index: usize, e: usize, cp: LocalCodePtr, - attr_var_init_b: usize, + attr_var_init_queue_b: usize, + attr_var_init_bindings_b: usize, b: usize, bp: CodePtr, tr: usize, @@ -36,7 +38,8 @@ impl Frame { global_index, e, cp, - attr_var_init_b, + attr_var_init_queue_b, + attr_var_init_bindings_b, b, bp, tr, @@ -64,7 +67,8 @@ impl OrStack { global_index: usize, e: usize, cp: LocalCodePtr, - attr_var_init_b: usize, + attr_var_init_queue_b: usize, + attr_var_init_bindings_b: usize, b: usize, bp: CodePtr, tr: usize, @@ -77,7 +81,8 @@ impl OrStack { global_index, e, cp, - attr_var_init_b, + attr_var_init_queue_b, + attr_var_init_bindings_b, b, bp, tr, diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 51eb93fa..63433554 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -44,8 +44,7 @@ ), ( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ! ; write('false.'), nl - ), - '$reset_attr_var_state'. + ). '$needs_bracketing'(Value, Op) :- catch((functor(Value, F, _), From 0eb20a5d8e6e7462267f58f731bb05cbd0bf1aae Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 30 Nov 2019 14:08:02 -0700 Subject: [PATCH 05/21] pop AND frames when safe to do so, suspend resizing of AND frames until a proper GC is implemented (#244) --- src/prolog/machine/and_stack.rs | 7 ++++++- src/prolog/machine/machine_state.rs | 12 ++++-------- src/prolog/machine/machine_state_impl.rs | 20 +++++++++++++------- src/prolog/toplevel.pl | 10 ++++++---- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/prolog/machine/and_stack.rs b/src/prolog/machine/and_stack.rs index 3a16f5c0..002e6f68 100644 --- a/src/prolog/machine/and_stack.rs +++ b/src/prolog/machine/and_stack.rs @@ -55,6 +55,10 @@ impl AndStack { self.0.clear() } + /* + + // See MachineState::allocate for why this is commented out. + pub fn resize(&mut self, fr: usize, n: usize) { let len = self[fr].perms.len(); @@ -66,7 +70,8 @@ impl AndStack { } } } - + */ + #[inline] pub fn truncate(&mut self, len: usize) { self.0.truncate(len); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 20162ac1..fd506f3c 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -423,8 +423,6 @@ pub(crate) trait CallPolicy: Any { machine_st.e = machine_st.or_stack[b].e; machine_st.cp = machine_st.or_stack[b].cp.clone(); - machine_st.pop_stack_frames(); - machine_st.or_stack[b].bp = machine_st.p.clone() + offset; let old_tr = machine_st.or_stack[b].tr; @@ -471,8 +469,6 @@ pub(crate) trait CallPolicy: Any { machine_st.e = machine_st.or_stack[b].e; machine_st.cp = machine_st.or_stack[b].cp.clone(); - machine_st.pop_stack_frames(); - machine_st.or_stack[b].bp = machine_st.p.clone() + 1; let old_tr = machine_st.or_stack[b].tr; @@ -515,6 +511,8 @@ pub(crate) trait CallPolicy: Any { machine_st.registers[i] = machine_st.or_stack[b][i].clone(); } + machine_st.pop_stack_frames(); + machine_st.num_of_args = n; machine_st.e = machine_st.or_stack[b].e; machine_st.cp = machine_st.or_stack[b].cp.clone(); @@ -548,8 +546,6 @@ pub(crate) trait CallPolicy: Any { machine_st.b = machine_st.or_stack[b].b; machine_st.or_stack.truncate(machine_st.b); - machine_st.pop_stack_frames(); - machine_st.hb = machine_st.heap.h; machine_st.p += offset; @@ -564,6 +560,8 @@ pub(crate) trait CallPolicy: Any { machine_st.registers[i] = machine_st.or_stack[b][i].clone(); } + machine_st.pop_stack_frames(); + machine_st.num_of_args = n; machine_st.e = machine_st.or_stack[b].e; machine_st.cp = machine_st.or_stack[b].cp.clone(); @@ -597,8 +595,6 @@ pub(crate) trait CallPolicy: Any { machine_st.b = machine_st.or_stack[b].b; machine_st.or_stack.truncate(machine_st.b); - machine_st.pop_stack_frames(); - machine_st.hb = machine_st.heap.h; machine_st.p += 1; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index f28eb077..df22f685 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -123,7 +123,7 @@ impl MachineState { self.flags } - fn next_global_index(&self) -> usize { + pub(super) fn next_global_index(&self) -> usize { max( if self.and_stack.len() > 0 { self.and_stack[self.e].global_index @@ -3127,10 +3127,18 @@ impl MachineState { pub(super) fn allocate(&mut self, num_cells: usize) { let gi = self.next_global_index(); +// let new_e = self.e + 1; self.p += 1; - if self.e + 1 < self.and_stack.len() { +/* + /* See issue #244 for an example of a program broken (at the + top level) by the inclusion of this code. A proper GC must determine if an + existing AND frame is safe to resize; the check here is not + enough. + */ + + if new_e < self.and_stack.len() { let and_gi = self.and_stack[self.e].global_index; let or_gi = self .or_stack @@ -3139,10 +3147,8 @@ impl MachineState { .unwrap_or(0); if and_gi > or_gi { - let new_e = self.e + 1; - self.and_stack[new_e].e = self.e; - self.and_stack[new_e].cp = self.cp.clone(); + self.and_stack[new_e].cp = self.cp; self.and_stack[new_e].global_index = gi; self.and_stack.resize(new_e, num_cells); @@ -3151,7 +3157,7 @@ impl MachineState { return; } } - +*/ self.and_stack.push(gi, self.e, self.cp.clone(), num_cells); self.e = self.and_stack.len() - 1; } @@ -3353,7 +3359,7 @@ impl MachineState { self.b = self.or_stack.len(); let b = self.b - 1; - for i in 1..n + 1 { + for i in 1 .. n + 1 { self.or_stack[b][i] = self.registers[i].clone(); } diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 63433554..4700806a 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -32,7 +32,7 @@ ; !, catch(throw(error(type_error(atom, Item), repl/0)), E, - '$print_exception_with_check'(E)) + '$print_exception_with_check'(E)) ). '$instruction_match'(Term, VarList) :- '$submit_query_and_print_results'(Term, VarList), @@ -42,7 +42,9 @@ ( expand_goals(Term0, Term) -> true ; Term = Term0 ), - ( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ! + ( '$get_b_value'(B), call(Term), + '$write_eqs_and_read_input'(B, VarList), + ! ; write('false.'), nl ). @@ -79,7 +81,7 @@ ( '$needs_bracketing'(Value, (=)) -> write('('), write_term(Value, [quoted(true), variable_names(VarList)]), - write(')') + write(')') ; write_term(Value, [quoted(true), variable_names(VarList)]), ( '$trailing_period_is_ambiguous'(Value) -> write(' ') @@ -98,7 +100,7 @@ '$write_eq'(G2, VarList). '$write_eq'(G, VarList) :- '$write_last_goal'(G, VarList). - + '$graphic_token_char'(C) :- memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':', '<', '=', '>', '?', '@', '^', '~', ('\\')]). From a4cacaeab226a570493dfff37b0dfa694fa52ae0 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 30 Nov 2019 14:12:33 -0700 Subject: [PATCH 06/21] compress the definition of freeze:attribute_goals//1 --- src/prolog/lib/freeze.pl | 16 +++------------- src/prolog/machine/project_attributes.pl | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/prolog/lib/freeze.pl b/src/prolog/lib/freeze.pl index 049e024b..cca3888d 100644 --- a/src/prolog/lib/freeze.pl +++ b/src/prolog/lib/freeze.pl @@ -21,16 +21,6 @@ freeze(X, Goal) :- put_atts(Fresh, frozen(Goal)), Fresh = X. -gather_freeze_goals(Attrs, _) --> - { var(Attrs) }, - !. -gather_freeze_goals([frozen(X) | _], Var) --> - [freeze(Var, X)], - { put_atts(Var, -frozen(_)) }, - !. -gather_freeze_goals([_ | Attrs], Var) --> - gather_freeze_goals(Attrs, Var). - -attribute_goals(X) --> - { '$get_attr_list'(X, Attrs) }, - gather_freeze_goals(Attrs, X). +attribute_goals(Var) --> + { get_atts(Var, frozen(Goals)) }, + [freeze(Var, Goals)]. diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 3882181c..1c0690d5 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -63,7 +63,7 @@ call_query_var_goals([AttrVar|AttrVars], Module, Goals) :- call_attr_var_goals([], _, []). call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :- - ( catch(Module:attribute_goals(AttrVar, Goals, RGoals), + ( catch(Module:attribute_goals(AttrVar, Goals, RGoals), E, '$print_attribute_goals_exception'(Module, E) ) From 27b659c401f2b509ce1ef404087a4faabd4ca4d3 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 30 Nov 2019 14:22:59 -0700 Subject: [PATCH 07/21] add sumlist/2 to lists.pl --- src/prolog/lib/lists.pl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/prolog/lib/lists.pl b/src/prolog/lib/lists.pl index 4fc5de96..ae207403 100644 --- a/src/prolog/lib/lists.pl +++ b/src/prolog/lib/lists.pl @@ -1,7 +1,10 @@ :- module(lists, [member/2, select/3, append/3, memberchk/2, reverse/2, length/2, maplist/2, maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, - maplist/8, maplist/9]). + maplist/8, maplist/9, sumlist/2]). + + +:- use_module(library(error)). length(Xs, N) :- @@ -96,3 +99,13 @@ maplist(_, [], [], [], [], [], [], [], []). maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :- call(Cont, E1, E2, E3, E4, E5, E6, E7), maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s). + + +sumlist_([], S, S). +sumlist_([N|Ns], S, S0) :- + S1 is S0 + N, + sumlist(Ns, S, S1). + +sumlist(Ns, S) :- + must_be(list, Ns), + sumlist_(Ns, S, 0). From 77e83a390c95c11def1422043c60f55352b2c5e1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 30 Nov 2019 14:26:15 -0700 Subject: [PATCH 08/21] add sumlist/2 to lists.pl --- src/prolog/lib/lists.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/lib/lists.pl b/src/prolog/lib/lists.pl index ae207403..f3a4ef6b 100644 --- a/src/prolog/lib/lists.pl +++ b/src/prolog/lib/lists.pl @@ -104,7 +104,7 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7 sumlist_([], S, S). sumlist_([N|Ns], S, S0) :- S1 is S0 + N, - sumlist(Ns, S, S1). + sumlist_(Ns, S, S1). sumlist(Ns, S) :- must_be(list, Ns), From e48f87fcf0a17a2c01d58dcbbee851fa4870a763 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 03:04:01 -0700 Subject: [PATCH 09/21] clear ball before setting it (#246) --- src/prolog/machine/and_stack.rs | 8 +++++ src/prolog/machine/machine_state.rs | 8 ++--- src/prolog/machine/machine_state_impl.rs | 37 ++++++++++++------------ src/prolog/toplevel.pl | 3 +- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/prolog/machine/and_stack.rs b/src/prolog/machine/and_stack.rs index 002e6f68..8a01a604 100644 --- a/src/prolog/machine/and_stack.rs +++ b/src/prolog/machine/and_stack.rs @@ -42,18 +42,26 @@ impl AndStack { AndStack(mem::replace(&mut self.0, vec![])) } + #[inline] pub fn push(&mut self, global_index: usize, e: usize, cp: LocalCodePtr, n: usize) { let len = self.0.len(); self.0.push(Frame::new(global_index, len, e, cp, n)); } + #[inline] pub fn len(&self) -> usize { self.0.len() } + #[inline] pub fn clear(&mut self) { self.0.clear() } + + #[inline] + pub fn top(&self) -> Option<&Frame> { + self.0.last() + } /* diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index fd506f3c..deb79e00 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -62,7 +62,7 @@ impl Ball { }); } - stub + stub } } @@ -486,7 +486,6 @@ pub(crate) trait CallPolicy: Any { machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr; machine_st.pstr_trail.truncate(machine_st.pstr_tr); - machine_st.heap.truncate(machine_st.or_stack[b].h); let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; @@ -532,7 +531,6 @@ pub(crate) trait CallPolicy: Any { machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr; machine_st.pstr_trail.truncate(machine_st.pstr_tr); - machine_st.heap.truncate(machine_st.or_stack[b].h); let attr_var_init_queue_b = machine_st.or_stack[b].attr_var_init_queue_b; @@ -578,8 +576,8 @@ pub(crate) trait CallPolicy: Any { let curr_pstr_tr = machine_st.pstr_tr; machine_st.unwind_pstr_trail(old_pstr_tr, curr_pstr_tr); - machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr; + machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr; machine_st.pstr_trail.truncate(machine_st.pstr_tr); machine_st.heap.truncate(machine_st.or_stack[b].h); @@ -591,7 +589,7 @@ pub(crate) trait CallPolicy: Any { attr_var_init_queue_b, attr_var_init_bindings_b, ); - + machine_st.b = machine_st.or_stack[b].b; machine_st.or_stack.truncate(machine_st.b); diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index df22f685..c98a80ed 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -125,16 +125,14 @@ impl MachineState { pub(super) fn next_global_index(&self) -> usize { max( - if self.and_stack.len() > 0 { - self.and_stack[self.e].global_index - } else { - 0 - }, - if self.b > 0 { - self.or_stack[self.b - 1].global_index - } else { - 0 - }, + self.or_stack + .top() + .map(|or_fr| or_fr.global_index) + .unwrap_or(0), + self.and_stack + .top() + .map(|or_fr| or_fr.global_index) + .unwrap_or(0), ) + 1 } @@ -1074,18 +1072,18 @@ impl MachineState { (Number::Float(f), _) | (_, Number::Float(f)) => { let n = Addr::Con(Constant::Float(f)); let stub = MachineError::functor_stub(clause_name!("gcd"), 2); - + Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) } (Number::Rational(r), _) | (_, Number::Rational(r)) => { let n = Addr::Con(Constant::Rational(r)); let stub = MachineError::functor_stub(clause_name!("gcd"), 2); - + Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) } } } - + fn float_pow(&self, n1: Number, n2: Number) -> Result { let f1 = result_f(&n1, rnd_f); let f2 = result_f(&n2, rnd_f); @@ -2039,8 +2037,11 @@ impl MachineState { } pub(super) fn set_ball(&mut self) { + self.ball.reset(); + let addr = self[temp_v!(1)].clone(); self.ball.boundary = self.heap.h; + copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut self.ball.stub), addr, @@ -3127,14 +3128,14 @@ impl MachineState { pub(super) fn allocate(&mut self, num_cells: usize) { let gi = self.next_global_index(); -// let new_e = self.e + 1; +// let new_e = self.e + 1; self.p += 1; /* - /* See issue #244 for an example of a program broken (at the - top level) by the inclusion of this code. A proper GC must determine if an - existing AND frame is safe to resize; the check here is not + /* See issue #244 for an example of a program broken (at the + top level) by the inclusion of this code. A proper GC must determine if an + existing AND frame is safe to resize; the check here is not enough. */ @@ -3185,7 +3186,7 @@ impl MachineState { } } } - + fn handle_call_clause( &mut self, indices: &mut IndexStore, diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 4700806a..6b3f7711 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -42,8 +42,7 @@ ( expand_goals(Term0, Term) -> true ; Term = Term0 ), - ( '$get_b_value'(B), call(Term), - '$write_eqs_and_read_input'(B, VarList), + ( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ! ; write('false.'), nl ). From 9b71866b54d6d780fe578c2b01b7c2b15541cfa7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 14:42:59 -0700 Subject: [PATCH 10/21] properly copy attributed variables (#247)" --- src/prolog/machine/copier.rs | 89 +++++++++++------------------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 2c65da69..34c1bfe6 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -50,14 +50,6 @@ impl CopyTermState { &mut self.target[scan] } - fn attr_var_redirect_tag(&self) -> impl Fn(usize) -> Addr { - if let AttrVarPolicy::DeepCopy = self.attr_var_policy { - Addr::AttrVar - } else { - Addr::HeapCell - } - } - fn copied_list(&mut self, addr: usize) -> bool { if let HeapCellValue::Addr(Addr::Lis(addr)) = self.target[addr].clone() { if addr >= self.old_h { @@ -79,62 +71,55 @@ impl CopyTermState { *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); let hcv = self.target[addr].clone(); - self.target.push(hcv.clone()); - - let ra = hcv.as_addr(threshold); - let rd = self.target.store(self.target.deref(ra)); - - match rd.clone() { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { - self.target[threshold] = HeapCellValue::Addr(rd) - } - ra @ Addr::AttrVar(..) | ra @ Addr::HeapCell(_) | ra @ Addr::StackCell(..) => { - if ra == rd { - self.reinstantiate_var(ra, threshold); - } else { - self.target[threshold] = HeapCellValue::Addr(ra); - } - } - _ => { - self.trail - .push((Ref::HeapCell(addr), self.target[addr].clone())); - self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)) - } - }; + self.target.push(hcv); let hcv = self.target[addr + 1].clone(); self.target.push(hcv); + self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); + self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)); + self.scan += 1; } - fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) { + fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) { match addr { Addr::HeapCell(h) => { - self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); + self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.trail.push(( Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h)), )); } Addr::StackCell(fr, sc) => { - self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target.stack()[fr][sc] = Addr::HeapCell(threshold); + self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); + self.target.stack()[fr][sc] = Addr::HeapCell(frontier); self.trail.push(( Ref::StackCell(fr, sc), HeapCellValue::Addr(Addr::StackCell(fr, sc)), )); } Addr::AttrVar(h) => { - let redirect_tag = self.attr_var_redirect_tag(); + let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { + self.target.threshold() + } else { + frontier + }; - self.target[threshold] = HeapCellValue::Addr(redirect_tag(threshold)); - self.target[h] = HeapCellValue::Addr(redirect_tag(threshold)); + self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); self.trail.push(( Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)), )); + + if let AttrVarPolicy::DeepCopy = self.attr_var_policy { + self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold))); + + let list_val = self.target[h + 1].clone(); + self.target.push(list_val); + } } _ => unreachable!() } @@ -144,33 +129,12 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(addr.clone())); match rd.clone() { - Addr::AttrVar(h) if h >= self.old_h => { - let redirect_tag = self.attr_var_redirect_tag(); - *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(h)); - self.scan += 1; - } - Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { *self.value_at_scan() = HeapCellValue::Addr(rd); self.scan += 1; } - Addr::AttrVar(h) if addr == rd => { - let redirect_tag = self.attr_var_redirect_tag(); - let threshold = self.target.threshold(); - - self.target - .push(HeapCellValue::Addr(redirect_tag(threshold))); - - if let AttrVarPolicy::DeepCopy = self.attr_var_policy { - let list_val = self.target[h + 1].clone(); - self.target.push(list_val); - } - - self.reinstantiate_var(addr, threshold); - *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(threshold)); - } _ if addr == rd => { - let scan = self.scan; - self.reinstantiate_var(addr, scan); + self.reinstantiate_var(addr, self.scan); self.scan += 1; } _ => { @@ -192,8 +156,7 @@ impl CopyTermState { HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()), )); - self.target - .push(HeapCellValue::NamedStr(arity, name, fixity)); + self.target.push(HeapCellValue::NamedStr(arity, name, fixity)); for i in 0..arity { let hcv = self.target[addr + 1 + i].clone(); From 406d3520f1a276914abba9d668cd6bbaf4fced6e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 14:43:27 -0700 Subject: [PATCH 11/21] delete freeze attribute in freeze::attribute_goals//1 --- src/prolog/lib/freeze.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prolog/lib/freeze.pl b/src/prolog/lib/freeze.pl index cca3888d..2fae5976 100644 --- a/src/prolog/lib/freeze.pl +++ b/src/prolog/lib/freeze.pl @@ -22,5 +22,6 @@ freeze(X, Goal) :- Fresh = X. attribute_goals(Var) --> - { get_atts(Var, frozen(Goals)) }, + { get_atts(Var, frozen(Goals)), + put_atts(Var, -frozen(_)) }, [freeze(Var, Goals)]. From c362cc6d347d01126ee8ebf5ead1cbfad0309ebb Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 15:28:47 -0700 Subject: [PATCH 12/21] fix list copying --- src/prolog/machine/copier.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 34c1bfe6..328c504a 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -71,13 +71,31 @@ impl CopyTermState { *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); let hcv = self.target[addr].clone(); - self.target.push(hcv); + let ra = hcv.as_addr(threshold); + let rd = self.target.store(self.target.deref(ra)); + + self.target.push(hcv); + let hcv = self.target[addr + 1].clone(); self.target.push(hcv); - self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); - self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)); + match rd.clone() { + Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + self.target[threshold] = HeapCellValue::Addr(rd) + } + ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { + if ra == rd { + self.reinstantiate_var(ra, threshold); + } else { + self.target[threshold] = HeapCellValue::Addr(ra); + } + } + _ => { + self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); + self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)) + } + }; self.scan += 1; } From 52488b875a35f697ffd3ca04419e57928f044f38 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 19:30:40 -0700 Subject: [PATCH 13/21] add predicates to lists.pl --- README.md | 3 +++ src/prolog/lib/lists.pl | 33 +++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 63614499..2d060807 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ The following predicates are built-in to Scryer. * `false/0` * `findall/{3,4}` * `float/1` +* `foldl/{4,5}` * `forall/2` * `freeze/2` * `functor/3` @@ -219,6 +220,7 @@ The following predicates are built-in to Scryer. * `repeat/{0,1}` * `retract/1` * `reverse/2` +* `same_length/2` * `select/3` * `setof/3` * `setup_call_cleanup/3` @@ -226,6 +228,7 @@ The following predicates are built-in to Scryer. * `string/1` * `sub_atom/5` * `subsumes_term/2` +* `sumlist/2` * `term_expansion/2` * `term_variables/2` * `throw/1` diff --git a/src/prolog/lib/lists.pl b/src/prolog/lib/lists.pl index f3a4ef6b..153b90ff 100644 --- a/src/prolog/lib/lists.pl +++ b/src/prolog/lib/lists.pl @@ -1,7 +1,8 @@ -:- module(lists, [member/2, select/3, append/3, memberchk/2, - reverse/2, length/2, maplist/2, maplist/3, - maplist/4, maplist/5, maplist/6, maplist/7, - maplist/8, maplist/9, sumlist/2]). +:- module(lists, [member/2, select/3, append/3, foldl/4, foldl/5, + memberchk/2, reverse/2, length/2, maplist/2, + maplist/3, maplist/4, maplist/5, maplist/6, + maplist/7, maplist/8, maplist/9, same_length/2, + sumlist/2]). :- use_module(library(error)). @@ -109,3 +110,27 @@ sumlist_([N|Ns], S, S0) :- sumlist(Ns, S) :- must_be(list, Ns), sumlist_(Ns, S, 0). + + + +same_length([], []). +same_length([_|As], [_|Bs]) :- + same_length(As, Bs). + + +foldl(Goal_3, Ls, A0, A) :- + foldl_(Ls, Goal_3, A0, A). + +foldl_([], _, A, A). +foldl_([L|Ls], G_3, A0, A) :- + call(G_3, L, A0, A1), + foldl_(Ls, G_3, A1, A). + + +foldl(Goal_4, Xs, Ys, A0, A) :- + foldl_(Xs, Ys, Goal_4, A0, A). + +foldl_([], [], _, A, A). +foldl_([X|Xs], [Y|Ys], G_4, A0, A) :- + call(G_4, X, Y, A0, A1), + foldl_(Xs, Ys, G_4, A1, A). From 943e5eeb35dda39be3163885bc2e01b2b70e0c7c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 1 Dec 2019 21:46:04 -0700 Subject: [PATCH 14/21] correct misprinting of attributed variables done by printer --- src/prolog/heap_print.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 9011827a..8db9ff43 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -614,7 +614,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } match addr { - Addr::AttrVar(h) => Some(format!("_{}", h + 1)), + Addr::AttrVar(h) => Some(format!("_{}", h)), Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) => Some(format!("_{}", h)), Addr::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)), _ => None, From fc8e55c582a3be6c929356a20b035ef1cbb10c12 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 2 Dec 2019 17:06:12 -0400 Subject: [PATCH 15/21] correct copying of cyclic lists in copier.rs --- src/prolog/machine/copier.rs | 39 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 34c1bfe6..51a56dd2 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -51,13 +51,16 @@ impl CopyTermState { } fn copied_list(&mut self, addr: usize) -> bool { - if let HeapCellValue::Addr(Addr::Lis(addr)) = self.target[addr].clone() { - if addr >= self.old_h { - *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr)); - self.scan += 1; - return true; + match self.target[addr].clone() { + HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => { + if addr >= self.old_h { + *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr)); + self.scan += 1; + return true; + } } - } + _ => {} + }; false } @@ -71,13 +74,31 @@ impl CopyTermState { *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); let hcv = self.target[addr].clone(); - self.target.push(hcv); + let ra = hcv.as_addr(threshold); + let rd = self.target.store(self.target.deref(ra)); + + self.target.push(hcv); + let hcv = self.target[addr + 1].clone(); self.target.push(hcv); - self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); - self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)); + match rd.clone() { + Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + self.target[threshold] = HeapCellValue::Addr(rd) + } + ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { + if ra == rd { + self.reinstantiate_var(ra, threshold); + } else { + self.target[threshold] = HeapCellValue::Addr(ra); + } + } + _ => { + self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); + self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)) + } + }; self.scan += 1; } From 738ea59e2367b1f24233fa1897554fecbbbcf185 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 3 Dec 2019 22:01:38 -0700 Subject: [PATCH 16/21] fix copy_term/3 infinite looping on cyclic terms --- src/prolog/machine/copier.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 51a56dd2..13e21ee3 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -90,6 +90,11 @@ impl CopyTermState { ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { if ra == rd { self.reinstantiate_var(ra, threshold); + + if let AttrVarPolicy::StripAttributes = self.attr_var_policy { + self.trail.push((Ref::HeapCell(addr), self.target[addr].clone())); + self.target[addr] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + } } else { self.target[threshold] = HeapCellValue::Addr(ra); } From 43b39538ff05690b2988ea62dd2e9c9bf1bd6431 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 3 Dec 2019 22:59:51 -0700 Subject: [PATCH 17/21] correct attributed variables bugs --- src/prolog/lib/atts.pl | 37 ++++++++++++------------ src/prolog/lib/freeze.pl | 1 + src/prolog/machine/project_attributes.pl | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/prolog/lib/atts.pl b/src/prolog/lib/atts.pl index 75d01ed5..15d56313 100644 --- a/src/prolog/lib/atts.pl +++ b/src/prolog/lib/atts.pl @@ -28,19 +28,18 @@ '$get_attr_list'(V, Ls), '$absent_from_list'(Ls, Attr). -'$absent_from_list'(X, _) :- - var(X), !. -'$absent_from_list'([L|Ls], Attr) :- - ( L \= Attr -> '$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_list'(Ls, V, Attr). '$get_from_list'([L|Ls], V, Attr) :- nonvar(L), - ( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr) - ; L = Attr -> '$enqueue_attr_var'(V) - ; '$get_from_list'(Ls, V, Attr) + ( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr) + ; L = Attr, '$enqueue_attr_var'(V) ). '$put_attr'(V, Attr) :- @@ -67,15 +66,14 @@ %% assumptions: Ls0 is a list, Ls1 is its tail; %% the head of Ls0 can be ignored. '$del_attr_buried'(Ls0, Ls1, V, Attr) :- - Ls0 = [_, Att | _], - nonvar(Att), - !, - ( Att \= Attr -> '$del_attr_step'(Ls1, V, Attr) - ; '$enqueue_attr_var'(V), - '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking. - '$del_attr_step'(Ls1, V, Attr) + ( var(Ls1) -> true + ; Ls1 = [Att | Ls2] -> + ( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr) + ; '$enqueue_attr_var'(V), + '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking. + '$del_attr_step'(Ls1, V, Attr) + ) ). -'$del_attr_buried'(_, _, _, _). '$copy_attr_list'(L, []) :- var(L), !. '$copy_attr_list'([Att|Atts], [Att|CopiedAtts]) :- @@ -125,10 +123,13 @@ put_attr(Name, Arity) --> numbervars(Attr, 0, Arity), V = '$VAR'(Arity) }, [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)), + '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), + '$put_attr'(V, Attr)), (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)), - (put_atts(V, -Attr) :- !, functor(Attr, _, _), '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, Attr))]. + '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), + '$put_attr'(V, Attr)), + (put_atts(V, -Attr) :- !, functor(Attr, _, _), '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, Attr))]. get_attr(Name, Arity) --> { functor(Attr, Name, Arity), diff --git a/src/prolog/lib/freeze.pl b/src/prolog/lib/freeze.pl index 2fae5976..8ab1de9b 100644 --- a/src/prolog/lib/freeze.pl +++ b/src/prolog/lib/freeze.pl @@ -25,3 +25,4 @@ attribute_goals(Var) --> { get_atts(Var, frozen(Goals)), put_atts(Var, -frozen(_)) }, [freeze(Var, Goals)]. + diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 1c0690d5..ac851b2b 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -50,7 +50,7 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :- call_query_var_goals([], _, []). call_query_var_goals([AttrVar|AttrVars], Module, Goals) :- ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0) - ; atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) + , atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) ), E, ( '$print_attribute_goals_exception'(Module, E), From 9ae029b04dbf59d1579ecdea99afd5a77fb26274 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 3 Dec 2019 23:11:57 -0700 Subject: [PATCH 18/21] pop AND stack frames after unwinding the trail (#250) --- src/prolog/machine/machine_state.rs | 10 +++++++--- src/prolog/machine/machine_state_impl.rs | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index deb79e00..fddfb264 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -510,8 +510,8 @@ pub(crate) trait CallPolicy: Any { machine_st.registers[i] = machine_st.or_stack[b][i].clone(); } - machine_st.pop_stack_frames(); - + let old_e = machine_st.e; + machine_st.num_of_args = n; machine_st.e = machine_st.or_stack[b].e; machine_st.cp = machine_st.or_stack[b].cp.clone(); @@ -522,6 +522,8 @@ pub(crate) trait CallPolicy: Any { machine_st.unwind_trail(old_tr, curr_tr); machine_st.tr = machine_st.or_stack[b].tr; + machine_st.pop_stack_frames(old_e); + machine_st.trail.truncate(machine_st.tr); let old_pstr_tr = machine_st.or_stack[b].pstr_tr; @@ -558,7 +560,7 @@ pub(crate) trait CallPolicy: Any { machine_st.registers[i] = machine_st.or_stack[b][i].clone(); } - machine_st.pop_stack_frames(); + let old_e = machine_st.e; machine_st.num_of_args = n; machine_st.e = machine_st.or_stack[b].e; @@ -570,6 +572,8 @@ pub(crate) trait CallPolicy: Any { machine_st.unwind_trail(old_tr, curr_tr); machine_st.tr = machine_st.or_stack[b].tr; + machine_st.pop_stack_frames(old_e); + machine_st.trail.truncate(machine_st.tr); let old_pstr_tr = machine_st.or_stack[b].pstr_tr; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index c98a80ed..63ace01f 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -3172,9 +3172,9 @@ impl MachineState { self.p += 1; } - pub(super) fn pop_stack_frames(&mut self) { - if self.and_stack.len() > self.e { - let and_gi = self.and_stack[self.e].global_index; + pub(super) fn pop_stack_frames(&mut self, e: usize) { + if self.and_stack.len() > e { + let and_gi = self.and_stack[e].global_index; let or_gi = self .or_stack .top() @@ -3182,7 +3182,7 @@ impl MachineState { .unwrap_or(0); if and_gi > or_gi { - self.and_stack.truncate(self.e + 1); + self.and_stack.truncate(e + 1); } } } From 018b076835fd0044e88ccae48b29367bdb72f317 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 5 Dec 2019 00:33:46 -0700 Subject: [PATCH 19/21] binding attributed variables more eagerly after each implementation of verify_attributes/3 has been called (#248) --- src/prolog/clause_types.rs | 9 ++++--- src/prolog/lib/atts.pl | 21 ++++++++++------ src/prolog/machine/attributed_variables.pl | 3 ++- src/prolog/machine/compile.rs | 3 ++- src/prolog/machine/system_calls.rs | 29 +++++++++++++++++++--- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index e4bae2ae..37f9ada9 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -165,6 +165,7 @@ pub enum SystemClauseType { CallAttributeGoals, CharCode, CharsToNumber, + ClearAttrVarBindings, CloneAttributeGoals, CodesToNumber, CopyTermWithoutAttrVars, @@ -214,7 +215,7 @@ pub enum SystemClauseType { REPL(REPLCodePtr), ReadQueryTerm, ReadTerm, - RedoAttrVarBindings, + RedoAttrVarBinding, RemoveCallPolicyCheck, RemoveInferenceCounter, ResetGlobalVarAtKey, @@ -280,6 +281,7 @@ impl SystemClauseType { &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => { clause_name!("$use_qualified_module_from_file") } + &SystemClauseType::ClearAttrVarBindings => clause_name!("$clear_attr_var_bindings"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), @@ -340,7 +342,7 @@ impl SystemClauseType { &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"), &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), - &SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"), + &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), &SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"), @@ -395,6 +397,7 @@ impl SystemClauseType { ("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), + ("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings), ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), @@ -444,7 +447,7 @@ impl SystemClauseType { ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$op", 3) => Some(SystemClauseType::OpDeclaration), - ("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings), + ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding), ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), ("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy), diff --git a/src/prolog/lib/atts.pl b/src/prolog/lib/atts.pl index 15d56313..71115639 100644 --- a/src/prolog/lib/atts.pl +++ b/src/prolog/lib/atts.pl @@ -46,7 +46,8 @@ '$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) + ( var(Ls) -> + Ls = [Attr | _], '$enqueue_attr_var'(V) ; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr) ). @@ -56,7 +57,8 @@ Ls0 = [Att | Ls1], nonvar(Att), ( Att \= Attr -> '$del_attr_buried'(Ls0, Ls1, V, Attr) - ; '$enqueue_attr_var'(V), '$del_attr_head'(V), '$del_attr'(Ls1, V, Attr) + ; '$enqueue_attr_var'(V), + '$del_attr_head'(V), '$del_attr'(Ls1, V, Attr) ). '$del_attr_step'(Ls1, V, Attr) :- @@ -122,13 +124,18 @@ put_attr(Name, Arity) --> { functor(Attr, Name, Arity), numbervars(Attr, 0, Arity), V = '$VAR'(Arity) }, - [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), + [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)), - (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), + (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)), - (put_atts(V, -Attr) :- !, functor(Attr, _, _), '$get_attr_list'(V, Ls), + (put_atts(V, -Attr) :- !, functor(Attr, _, _), + '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, Attr))]. get_attr(Name, Arity) --> diff --git a/src/prolog/machine/attributed_variables.pl b/src/prolog/machine/attributed_variables.pl index 8d896083..01ea8b7d 100644 --- a/src/prolog/machine/attributed_variables.pl +++ b/src/prolog/machine/attributed_variables.pl @@ -1,6 +1,6 @@ driver(Vars, Values) :- iterate(Vars, Values, ListOfListsOfGoalLists), - '$redo_attr_var_bindings', % the bindings list is emptied here. + '$clear_attr_var_bindings', !, call_goals(ListOfListsOfGoalLists), '$return_from_verify_attr'. @@ -8,6 +8,7 @@ driver(Vars, Values) :- iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :- '$get_attr_list'(Var, Ls), call_verify_attributes(Ls, Var, Value, ListOfGoalLists), + '$redo_attr_var_binding'(Var, Value), iterate(VarBindings, ValueBindings, ListsCubed). iterate([], [], []). diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index 36c7bf60..f9cf5f8b 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -649,7 +649,8 @@ impl ListingCompiler { let idx = code_dir .entry((name.clone(), arity)) .or_insert(CodeIndex::default()); - set_code_index!(idx, IndexPtr::Index(p), self.get_module_name()); + + set_code_index!(idx, IndexPtr::Index(p), self.get_module_name()); self.localize_self_calls(name, arity, &mut decl_code, p); code.extend(decl_code.into_iter()); diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 22e9c1ea..11eb193e 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -1644,11 +1644,32 @@ impl MachineState { } }; } - &SystemClauseType::RedoAttrVarBindings => { - let bindings = mem::replace(&mut self.attr_var_init.bindings, vec![]); + &SystemClauseType::ClearAttrVarBindings => { + self.attr_var_init.bindings.clear(); + } + &SystemClauseType::RedoAttrVarBinding => { + let var = self.store(self.deref(self[temp_v!(1)].clone())); + let value = self.store(self.deref(self[temp_v!(2)].clone())); - for (h, addr) in bindings { - self.heap[h] = HeapCellValue::Addr(addr); + match var { + Addr::AttrVar(h) => { + if let Addr::AttrVar(h1) = value { + self.heap[h] = HeapCellValue::Addr(Addr::AttrVar(h1)); + + // append h's attributes list to h1's. + let mut l = h1 + 1; + + while let Addr::Lis(l1) = self.store(self.deref(self.heap[l].as_addr(l))) { + l = l1 + 1; + } + + self.heap[l] = HeapCellValue::Addr(Addr::HeapCell(h + 1)); + self.trail(TrailRef::Ref(Ref::HeapCell(l))); + } else { + self.heap[h] = HeapCellValue::Addr(value); + } + } + _ => unreachable!() } } &SystemClauseType::ResetGlobalVarAtKey => { From 90e1c990e5563f48cf3ddf50153328b7a83dc18d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 6 Dec 2019 10:30:16 -0400 Subject: [PATCH 20/21] print equations between variables (#228, #252) --- src/prolog/toplevel.pl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 6b3f7711..74df6a6f 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -144,13 +144,20 @@ ). '$gather_query_vars'([], []). +'$is_a_different_variable'([Var = Binding | Pairs], Value) :- + ( Value == Binding, ! + ; '$is_a_different_variable'(Pairs, Value) + ). + '$gather_goals'([], VarList, Goals) :- '$get_attr_var_queue_beyond'(0, AttrVars), '$gather_query_vars'(VarList, QueryVars), '$call_attribute_goals'(QueryVars, AttrVars), '$fetch_attribute_goals'(Goals). '$gather_goals'([Var = Value | Pairs], VarList, Goals) :- - ( nonvar(Value) -> + ( ( nonvar(Value) + ; '$is_a_different_variable'(Pairs, Value) + ) -> Goals = [Var = Value | Goals0], '$gather_goals'(Pairs, VarList, Goals0) ; '$gather_goals'(Pairs, VarList, Goals) From 5ccd334555dc2074c2f0566623f4f31eabbfc2ea Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 6 Dec 2019 15:22:28 -0400 Subject: [PATCH 21/21] resolve panic caused by lingering attribute goals (#253) --- src/prolog/clause_types.rs | 3 +++ src/prolog/machine/system_calls.rs | 3 +++ src/prolog/toplevel.pl | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 37f9ada9..006ea3d4 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -166,6 +166,7 @@ pub enum SystemClauseType { CharCode, CharsToNumber, ClearAttrVarBindings, + ClearAttributeGoals, CloneAttributeGoals, CodesToNumber, CopyTermWithoutAttrVars, @@ -266,6 +267,7 @@ impl SystemClauseType { &SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"), &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), + &SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"), &SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), @@ -398,6 +400,7 @@ impl SystemClauseType { ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings), + ("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals), ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 11eb193e..2fb652d4 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -1376,6 +1376,9 @@ impl MachineState { &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } + &SystemClauseType::ClearAttributeGoals => { + self.attr_var_init.attribute_goals.clear(); + } &SystemClauseType::CloneAttributeGoals => { let attr_goals = self.attr_var_init.attribute_goals.clone(); self.fetch_attribute_goals(attr_goals); diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 74df6a6f..cf561645 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -44,7 +44,9 @@ ), ( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ! - ; write('false.'), nl + % clear attribute goal lists, which may be populated by + % copy_term/3 prior to failure. + ; '$clear_attribute_goals', write('false.'), nl ). '$needs_bracketing'(Value, Op) :- @@ -144,7 +146,7 @@ ). '$gather_query_vars'([], []). -'$is_a_different_variable'([Var = Binding | Pairs], Value) :- +'$is_a_different_variable'([_ = Binding | Pairs], Value) :- ( Value == Binding, ! ; '$is_a_different_variable'(Pairs, Value) ).