add call_with_inference_limit/3
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -99,7 +99,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.7.8"
|
version = "0.7.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"downcast 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"downcast 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.7.8"
|
version = "0.7.9"
|
||||||
authors = ["Mark Thom"]
|
authors = ["Mark Thom"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -700,7 +700,9 @@ pub struct Rule {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum SystemClauseType {
|
pub enum SystemClauseType {
|
||||||
|
CallWithDefaultPolicy,
|
||||||
CheckCutPoint,
|
CheckCutPoint,
|
||||||
|
GetBValue,
|
||||||
GetSCCCleaner,
|
GetSCCCleaner,
|
||||||
InstallSCCCleaner,
|
InstallSCCCleaner,
|
||||||
InstallInferenceCounter,
|
InstallInferenceCounter,
|
||||||
@@ -731,7 +733,9 @@ impl SystemClauseType {
|
|||||||
|
|
||||||
pub fn name(&self) -> ClauseName {
|
pub fn name(&self) -> ClauseName {
|
||||||
match self {
|
match self {
|
||||||
|
&SystemClauseType::CallWithDefaultPolicy => clause_name!("$call_with_default_policy"),
|
||||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||||
|
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
|
||||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||||
&SystemClauseType::InstallInferenceCounter =>
|
&SystemClauseType::InstallInferenceCounter =>
|
||||||
@@ -761,7 +765,9 @@ impl SystemClauseType {
|
|||||||
|
|
||||||
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
||||||
match (name, arity) {
|
match (name, arity) {
|
||||||
|
("$call_with_default_policy", 1) => Some(SystemClauseType::CallWithDefaultPolicy),
|
||||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||||
|
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
|
||||||
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
||||||
("$install_scc_cleaner", 2) =>
|
("$install_scc_cleaner", 2) =>
|
||||||
Some(SystemClauseType::InstallSCCCleaner),
|
Some(SystemClauseType::InstallSCCCleaner),
|
||||||
@@ -769,7 +775,7 @@ impl SystemClauseType {
|
|||||||
Some(SystemClauseType::InstallInferenceCounter),
|
Some(SystemClauseType::InstallInferenceCounter),
|
||||||
("$remove_call_policy_check", 1) =>
|
("$remove_call_policy_check", 1) =>
|
||||||
Some(SystemClauseType::RemoveCallPolicyCheck),
|
Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||||
("$remove_inference_counter", 1) =>
|
("$remove_inference_counter", 2) =>
|
||||||
Some(SystemClauseType::RemoveInferenceCounter),
|
Some(SystemClauseType::RemoveInferenceCounter),
|
||||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||||
@@ -1613,9 +1619,6 @@ impl CodePtr {
|
|||||||
pub enum LocalCodePtr {
|
pub enum LocalCodePtr {
|
||||||
DirEntry(usize, ClauseName), // offset, resident module name.
|
DirEntry(usize, ClauseName), // offset, resident module name.
|
||||||
TopLevel(usize, usize), // chunk_num, offset.
|
TopLevel(usize, usize), // chunk_num, offset.
|
||||||
// DynamicModuleCall(ClauseName, ClauseName, usize)
|
|
||||||
// module name, predicate name and arity.
|
|
||||||
// used for internal, dynamic module calls.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalCodePtr {
|
impl LocalCodePtr {
|
||||||
|
|||||||
@@ -343,6 +343,8 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChunkedTerm::BodyTerm(&QueryTerm::GetLevelAndUnify(..)) => {
|
ChunkedTerm::BodyTerm(&QueryTerm::GetLevelAndUnify(..)) => {
|
||||||
|
self.deep_cut_encountered = true;
|
||||||
|
|
||||||
result.push(term);
|
result.push(term);
|
||||||
arity = 1;
|
arity = 1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
(>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2,
|
(>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2,
|
||||||
(-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2, (=..)/2, (==)/2,
|
(-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2, (=..)/2, (==)/2,
|
||||||
(\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2,
|
(\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2,
|
||||||
(:)/2, catch/3, setup_call_cleanup/3, throw/1, true/0, false/0]).
|
(:)/2, call_with_inference_limit/3, catch/3,
|
||||||
|
setup_call_cleanup/3, throw/1, true/0, false/0]).
|
||||||
|
|
||||||
% arithmetic operators.
|
% arithmetic operators.
|
||||||
:- op(700, xfx, is).
|
:- op(700, xfx, is).
|
||||||
@@ -149,13 +150,13 @@ univ_worker(Term, List, _) :-
|
|||||||
|
|
||||||
% setup_call_cleanup.
|
% setup_call_cleanup.
|
||||||
|
|
||||||
setup_call_cleanup(S, G, C) :- '$get_cp'(B),
|
setup_call_cleanup(S, G, C) :- '$get_b_value'(B),
|
||||||
S, '$set_cp_by_default'(B), '$get_current_block'(Bb),
|
S, '$set_cp_by_default'(B), '$get_current_block'(Bb),
|
||||||
( var(C) -> throw(error(instantiation_error, setup_call_cleanup/3))
|
( var(C) -> throw(error(instantiation_error, setup_call_cleanup/3))
|
||||||
; scc_helper(C, G, Bb) ).
|
; scc_helper(C, G, Bb) ).
|
||||||
|
|
||||||
scc_helper(C, G, Bb) :-
|
scc_helper(C, G, Bb) :-
|
||||||
'$get_level'(Cp), '$install_scc_cleaner'(C, NBb), call(G),
|
'$get_cp'(Cp), '$install_scc_cleaner'(C, NBb), call(G),
|
||||||
( '$check_cp'(Cp) -> '$reset_block'(Bb), run_cleaners_without_handling(Cp)
|
( '$check_cp'(Cp) -> '$reset_block'(Bb), run_cleaners_without_handling(Cp)
|
||||||
; true
|
; true
|
||||||
; '$reset_block'(NBb), '$fail').
|
; '$reset_block'(NBb), '$fail').
|
||||||
@@ -163,7 +164,7 @@ scc_helper(_, _, Bb) :-
|
|||||||
'$reset_block'(Bb), '$get_ball'(Ball),
|
'$reset_block'(Bb), '$get_ball'(Ball),
|
||||||
run_cleaners_with_handling, throw(Ball).
|
run_cleaners_with_handling, throw(Ball).
|
||||||
scc_helper(_, _, _) :-
|
scc_helper(_, _, _) :-
|
||||||
run_cleaners_without_handling(Cp), false.
|
'$get_cp'(Cp), run_cleaners_without_handling(Cp), '$fail'.
|
||||||
|
|
||||||
run_cleaners_with_handling :-
|
run_cleaners_with_handling :-
|
||||||
'$get_scc_cleaner'(C), '$get_level'(B), catch(C, _, true), '$set_cp_by_default'(B),
|
'$get_scc_cleaner'(C), '$get_level'(B), catch(C, _, true), '$set_cp_by_default'(B),
|
||||||
@@ -177,6 +178,40 @@ run_cleaners_without_handling(Cp) :-
|
|||||||
run_cleaners_without_handling(Cp) :-
|
run_cleaners_without_handling(Cp) :-
|
||||||
'$set_cp_by_default'(Cp), '$restore_cut_policy'.
|
'$set_cp_by_default'(Cp), '$restore_cut_policy'.
|
||||||
|
|
||||||
|
% call_with_inference_limit
|
||||||
|
|
||||||
|
call_with_inference_limit(G, L, R) :-
|
||||||
|
'$get_current_block'(Bb),
|
||||||
|
'$get_b_value'(B),
|
||||||
|
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
|
||||||
|
'$remove_call_policy_check'(B).
|
||||||
|
|
||||||
|
call_with_inference_limit(G, L, R, Bb, B) :-
|
||||||
|
'$install_new_block'(NBb),
|
||||||
|
'$install_inference_counter'(B, L, Count0),
|
||||||
|
call(G),
|
||||||
|
'$inference_level'(R, B),
|
||||||
|
'$remove_inference_counter'(B, Count1),
|
||||||
|
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
|
||||||
|
'$call_with_default_policy'(end_block(B, Bb, NBb, Diff)).
|
||||||
|
call_with_inference_limit(_, _, R, Bb, B) :-
|
||||||
|
'$reset_block'(Bb),
|
||||||
|
'$remove_inference_counter'(B, _),
|
||||||
|
( '$get_ball'(Ball), '$get_level'(Cp), '$set_cp_by_default'(Cp)
|
||||||
|
; '$remove_call_policy_check'(B), '$fail' ),
|
||||||
|
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||||
|
|
||||||
|
end_block(_, Bb, NBb, L) :-
|
||||||
|
'$clean_up_block'(NBb),
|
||||||
|
'$reset_block'(Bb).
|
||||||
|
end_block(B, Bb, NBb, L) :-
|
||||||
|
'$install_inference_counter'(B, L, _),
|
||||||
|
'$reset_block'(NBb),
|
||||||
|
'$fail'.
|
||||||
|
|
||||||
|
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :- !.
|
||||||
|
handle_ile(B, _, _) :- '$remove_call_policy_check'(B), '$unwind_stack'. % throw(E).
|
||||||
|
|
||||||
% exceptions.
|
% exceptions.
|
||||||
|
|
||||||
catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb).
|
catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb).
|
||||||
@@ -187,7 +222,7 @@ catch(G,C,R,Bb) :- '$reset_block'(Bb), '$get_ball'(Ball), handle_ball(Ball, C, R
|
|||||||
end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb).
|
end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb).
|
||||||
end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'.
|
end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'.
|
||||||
|
|
||||||
handle_ball(Ball, C, R) :- Ball = C, '$get_level'(B), '$set_cp_by_default'(B), '$erase_ball', call(R).
|
handle_ball(C, C, R) :- !, '$erase_ball', call(R).
|
||||||
handle_ball(_, _, _) :- '$unwind_stack'.
|
handle_ball(_, _, _) :- '$unwind_stack'.
|
||||||
|
|
||||||
throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
|
throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use prolog::tabled_rc::*;
|
|||||||
|
|
||||||
use downcast::Any;
|
use downcast::Any;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
@@ -31,6 +32,7 @@ impl Ball {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) struct CodeDirs<'a> {
|
pub(crate) struct CodeDirs<'a> {
|
||||||
pub code_dir: &'a CodeDir,
|
pub code_dir: &'a CodeDir,
|
||||||
pub op_dir: &'a OpDir,
|
pub op_dir: &'a OpDir,
|
||||||
@@ -80,6 +82,33 @@ impl<'a> CodeDirs<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CodeDirsAdapter<'a> {
|
||||||
|
fn get_code_index(&self, PredicateKey, ClauseName) -> Option<CodeIndex>;
|
||||||
|
fn get_op(&self, OpDirKey) -> Option<(Specifier, usize, ClauseName)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CodeDirsAdapter<'a> for CodeDirs<'a> {
|
||||||
|
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex> {
|
||||||
|
self.get(key.0, key.1, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> {
|
||||||
|
self.op_dir.get(&key).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CodeDirsAdapter<'a> for &'a Module {
|
||||||
|
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
|
||||||
|
self.code_dir.get(&key)
|
||||||
|
.cloned()
|
||||||
|
.map(|ModuleCodeIndex(ptr, module)| CodeIndex(Rc::new(RefCell::new((ptr, module)))))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> {
|
||||||
|
self.op_dir.get(&key).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct DuplicateTerm<'a> {
|
pub(super) struct DuplicateTerm<'a> {
|
||||||
state: &'a mut MachineState
|
state: &'a mut MachineState
|
||||||
}
|
}
|
||||||
@@ -391,9 +420,9 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
fn context_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
||||||
idx: CodeIndex, code_dirs: CodeDirs)
|
idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
if machine_st.last_call {
|
if machine_st.last_call {
|
||||||
self.try_execute(machine_st, name, arity, idx, code_dirs)
|
self.try_execute(machine_st, name, arity, idx, code_dirs)
|
||||||
@@ -402,9 +431,9 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
fn try_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
||||||
idx: CodeIndex, code_dirs: CodeDirs)
|
idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
match idx.0.borrow().0 {
|
match idx.0.borrow().0 {
|
||||||
IndexPtr::Module => {
|
IndexPtr::Module => {
|
||||||
@@ -412,7 +441,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
let module_name = idx.0.borrow().1.clone();
|
let module_name = idx.0.borrow().1.clone();
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h;
|
||||||
|
|
||||||
if let Some(ref idx) = code_dirs.get(name.clone(), arity, module_name.clone()) {
|
if let Some(ref idx) = code_dirs.get_code_index((name.clone(), arity), module_name.clone())
|
||||||
|
{
|
||||||
if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 {
|
if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 {
|
||||||
call_at_index(machine_st, module_name, arity, compiled_tl_index);
|
call_at_index(machine_st, module_name, arity, compiled_tl_index);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -439,7 +469,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||||
arity: usize, idx: CodeIndex, code_dirs: CodeDirs)
|
arity: usize, idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
match idx.0.borrow().0 {
|
match idx.0.borrow().0 {
|
||||||
@@ -448,7 +478,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
let module_name = idx.0.borrow().1.clone();
|
let module_name = idx.0.borrow().1.clone();
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h;
|
||||||
|
|
||||||
if let Some(ref idx) = code_dirs.get(name.clone(), arity, module_name.clone()) {
|
if let Some(ref idx) = code_dirs.get_code_index((name.clone(), arity), module_name.clone())
|
||||||
|
{
|
||||||
if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 {
|
if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 {
|
||||||
execute_at_index(machine_st, module_name, arity, compiled_tl_index);
|
execute_at_index(machine_st, module_name, arity, compiled_tl_index);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -610,7 +641,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize,
|
||||||
|
code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||||
@@ -631,7 +663,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
ClauseType::Inlined(inlined) =>
|
ClauseType::Inlined(inlined) =>
|
||||||
machine_st.execute_inlined(&inlined),
|
machine_st.execute_inlined(&inlined),
|
||||||
ClauseType::Op(..) | ClauseType::Named(..) =>
|
ClauseType::Op(..) | ClauseType::Named(..) =>
|
||||||
if let Some(idx) = code_dirs.get(name.clone(), arity, user) {
|
if let Some(idx) = code_dirs.get_code_index((name.clone(), arity), user) {
|
||||||
self.context_call(machine_st, name, arity, idx, code_dirs)?;
|
self.context_call(machine_st, name, arity, idx, code_dirs)?;
|
||||||
} else {
|
} else {
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h;
|
||||||
@@ -654,37 +686,37 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
impl CallPolicy for CWILCallPolicy {
|
||||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
fn context_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||||
arity: usize, idx: CodeIndex, code_dirs: CodeDirs)
|
arity: usize, idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.context_call(machine_st, name, arity, idx, code_dirs)?;
|
self.prev_policy.context_call(machine_st, name, arity, idx, code_dirs)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) -> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.retry_me_else(machine_st, offset)?;
|
self.prev_policy.retry_me_else(machine_st, offset)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.retry(machine_st, offset)?;
|
self.prev_policy.retry(machine_st, offset)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
|
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.trust_me(machine_st)?;
|
self.prev_policy.trust_me(machine_st)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.trust(machine_st, offset)?;
|
self.prev_policy.trust(machine_st, offset)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
|
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
|
||||||
@@ -692,14 +724,15 @@ impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
|||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.call_builtin(machine_st, ct, code_dirs)?;
|
self.prev_policy.call_builtin(machine_st, ct, code_dirs)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize,
|
||||||
|
code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
self.prev_policy.call_n(machine_st, arity, code_dirs)?;
|
self.prev_policy.call_n(machine_st, arity, code_dirs)?;
|
||||||
self.increment()
|
self.increment(machine_st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,27 +742,34 @@ pub(crate) struct DefaultCallPolicy {}
|
|||||||
|
|
||||||
impl CallPolicy for DefaultCallPolicy {}
|
impl CallPolicy for DefaultCallPolicy {}
|
||||||
|
|
||||||
pub(crate) struct CallWithInferenceLimitCallPolicy {
|
pub(crate) struct CWILCallPolicy {
|
||||||
pub(crate) prev_policy: Box<CallPolicy>,
|
pub(crate) prev_policy: Box<CallPolicy>,
|
||||||
count: BigUint,
|
pub(crate) count: BigUint,
|
||||||
limits: Vec<(BigUint, usize)>
|
limits: Vec<(BigUint, usize)>,
|
||||||
|
inference_limit_exceeded: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallWithInferenceLimitCallPolicy {
|
impl CWILCallPolicy {
|
||||||
pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>)
|
pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>)
|
||||||
{
|
{
|
||||||
let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
|
let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
|
||||||
swap(&mut prev_policy, policy);
|
swap(&mut prev_policy, policy);
|
||||||
|
|
||||||
let new_policy = CallWithInferenceLimitCallPolicy { prev_policy,
|
let new_policy = CWILCallPolicy { prev_policy,
|
||||||
count: BigUint::zero(),
|
count: BigUint::zero(),
|
||||||
limits: vec![] };
|
limits: vec![],
|
||||||
|
inference_limit_exceeded: false };
|
||||||
*policy = Box::new(new_policy);
|
*policy = Box::new(new_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment(&mut self) -> CallResult {
|
fn increment(&mut self, machine_st: &MachineState) -> CallResult {
|
||||||
|
if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(&(ref limit, bp)) = self.limits.last() {
|
if let Some(&(ref limit, bp)) = self.limits.last() {
|
||||||
if self.count == *limit {
|
if self.count == *limit {
|
||||||
|
self.inference_limit_exceeded = true;
|
||||||
return Err(functor!("inference_limit_exceeded", 1,
|
return Err(functor!("inference_limit_exceeded", 1,
|
||||||
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]));
|
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]));
|
||||||
} else {
|
} else {
|
||||||
@@ -782,24 +822,34 @@ pub(crate) trait CutPolicy: Any {
|
|||||||
|
|
||||||
downcast!(CutPolicy);
|
downcast!(CutPolicy);
|
||||||
|
|
||||||
|
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
|
||||||
|
let b = machine_st.b;
|
||||||
|
|
||||||
|
if let Addr::Con(Constant::Usize(b0)) = addr {
|
||||||
|
if b > b0 {
|
||||||
|
machine_st.b = b0;
|
||||||
|
machine_st.tidy_trail();
|
||||||
|
machine_st.or_stack.truncate(machine_st.b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
machine_st.fail = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct DefaultCutPolicy {}
|
pub(crate) struct DefaultCutPolicy {}
|
||||||
|
|
||||||
|
pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
|
||||||
|
let addr = machine_st.store(machine_st.deref(machine_st[r].clone()));
|
||||||
|
cut_body(machine_st, addr);
|
||||||
|
}
|
||||||
|
|
||||||
impl CutPolicy for DefaultCutPolicy {
|
impl CutPolicy for DefaultCutPolicy {
|
||||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
||||||
let b = machine_st.b;
|
let addr = machine_st[r].clone();
|
||||||
|
cut_body(machine_st, addr)
|
||||||
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
|
|
||||||
if b > b0 {
|
|
||||||
machine_st.b = b0;
|
|
||||||
machine_st.tidy_trail();
|
|
||||||
machine_st.or_stack.truncate(machine_st.b);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
machine_st.fail = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1821,7 +1821,7 @@ impl MachineState {
|
|||||||
self.allocate(num_cells),
|
self.allocate(num_cells),
|
||||||
&ControlInstruction::CallClause(ClauseType::CallN, arity, _, lco) => {
|
&ControlInstruction::CallClause(ClauseType::CallN, arity, _, lco) => {
|
||||||
self.last_call = lco;
|
self.last_call = lco;
|
||||||
try_or_fail!(self, call_policy.call_n(self, arity, code_dirs));
|
try_or_fail!(self, call_policy.call_n(self, arity, Box::new(code_dirs)));
|
||||||
},
|
},
|
||||||
&ControlInstruction::CallClause(ClauseType::BuiltIn(ref ct), _, _, lco) => {
|
&ControlInstruction::CallClause(ClauseType::BuiltIn(ref ct), _, _, lco) => {
|
||||||
self.last_call = lco;
|
self.last_call = lco;
|
||||||
@@ -1833,7 +1833,7 @@ impl MachineState {
|
|||||||
| &ControlInstruction::CallClause(ClauseType::Op(ref name, _, ref idx), arity, _, lco) => {
|
| &ControlInstruction::CallClause(ClauseType::Op(ref name, _, ref idx), arity, _, lco) => {
|
||||||
self.last_call = lco;
|
self.last_call = lco;
|
||||||
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
|
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
|
||||||
code_dirs));
|
Box::new(code_dirs)));
|
||||||
},
|
},
|
||||||
&ControlInstruction::CallClause(ClauseType::System(ref ct), _, _, lco) => {
|
&ControlInstruction::CallClause(ClauseType::System(ref ct), _, _, lco) => {
|
||||||
self.last_call = lco;
|
self.last_call = lco;
|
||||||
@@ -1947,7 +1947,8 @@ impl MachineState {
|
|||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&CutInstruction::GetLevelAndUnify(r) => {
|
&CutInstruction::GetLevelAndUnify(r) => {
|
||||||
let b0 = Addr::Con(Constant::Usize(self.b0));
|
// let b0 = Addr::Con(Constant::Usize(self.b0));
|
||||||
|
let b0 = self[perm_v!(1)].clone();
|
||||||
let a = self[r].clone();
|
let a = self[r].clone();
|
||||||
|
|
||||||
self.unify(a, b0);
|
self.unify(a, b0);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use prolog::ast::*;
|
|||||||
use prolog::machine::machine_errors::*;
|
use prolog::machine::machine_errors::*;
|
||||||
use prolog::machine::machine_state::*;
|
use prolog::machine::machine_state::*;
|
||||||
use prolog::num::{ToPrimitive, Zero};
|
use prolog::num::{ToPrimitive, Zero};
|
||||||
use prolog::num::bigint::BigInt;
|
use prolog::num::bigint::{BigInt};
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -180,13 +180,21 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn system_call(&mut self, ct: &SystemClauseType,
|
pub(super) fn system_call<'a>(&mut self, ct: &SystemClauseType,
|
||||||
code_dirs: CodeDirs,
|
code_dirs: CodeDirs<'a>,
|
||||||
call_policy: &mut Box<CallPolicy>,
|
call_policy: &mut Box<CallPolicy>,
|
||||||
cut_policy: &mut Box<CutPolicy>,)
|
cut_policy: &mut Box<CutPolicy>,)
|
||||||
-> CallResult
|
-> CallResult
|
||||||
{
|
{
|
||||||
match ct {
|
match ct {
|
||||||
|
// this system call is only to be used within the builtins module.
|
||||||
|
// TODO: in the future I'd like to use serde to serialize/deserialize builtins
|
||||||
|
// and thereby avoid this kludge, but for now it's ok.
|
||||||
|
&SystemClauseType::CallWithDefaultPolicy =>
|
||||||
|
if let Some(builtins) = code_dirs.modules.get(&clause_name!("builtins")) {
|
||||||
|
let mut call_policy = DefaultCallPolicy {};
|
||||||
|
return call_policy.call_n(self, 1, Box::new(builtins));
|
||||||
|
},
|
||||||
&SystemClauseType::CheckCutPoint => {
|
&SystemClauseType::CheckCutPoint => {
|
||||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
@@ -243,20 +251,24 @@ impl MachineState {
|
|||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
|
if call_policy.downcast_ref::<CWILCallPolicy>().is_err() {
|
||||||
CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
|
CWILCallPolicy::new_in_place(call_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (a1, a2.clone()) {
|
match (a1, a2.clone()) {
|
||||||
(Addr::Con(Constant::Usize(bp)),
|
(Addr::Con(Constant::Usize(bp)),
|
||||||
Addr::Con(Constant::Number(Number::Integer(n)))) =>
|
Addr::Con(Constant::Number(Number::Integer(n)))) =>
|
||||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
|
||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let count = call_policy.add_limit(n, bp);
|
let count = call_policy.add_limit(n, bp);
|
||||||
self[temp_v!(3)] = Addr::Con(Constant::Number(Number::Integer(count)));
|
let count = Addr::Con(Constant::Number(Number::Integer(count)));
|
||||||
|
|
||||||
|
let a3 = self[temp_v!(3)].clone();
|
||||||
|
|
||||||
|
self.unify(a3, count);
|
||||||
},
|
},
|
||||||
None => panic!("install_inference_counter: should have installed \\
|
None => panic!("install_inference_counter: should have installed \\
|
||||||
CallWithInferenceLimitCallPolicy.")
|
CWILCallPolicy.")
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let stub = MachineError::functor_stub(clause_name!("call_with_inference_limit"), 3);
|
let stub = MachineError::functor_stub(clause_name!("call_with_inference_limit"), 3);
|
||||||
@@ -268,7 +280,7 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => {
|
&SystemClauseType::RemoveCallPolicyCheck => {
|
||||||
let restore_default =
|
let restore_default =
|
||||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
|
||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
@@ -283,29 +295,32 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => panic!("remove_call_policy_check: requires \\
|
None => panic!("remove_call_policy_check: requires \\
|
||||||
CallWithInferenceLimitCallPolicy.")
|
CWILCallPolicy.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(new_policy) = restore_default {
|
if let Some(new_policy) = restore_default {
|
||||||
*call_policy = new_policy;
|
*call_policy = new_policy;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&SystemClauseType::RemoveInferenceCounter => {
|
&SystemClauseType::RemoveInferenceCounter =>
|
||||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
|
||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
||||||
let count = call_policy.remove_limit(bp);
|
let count = call_policy.remove_limit(bp);
|
||||||
self[temp_v!(2)] = Addr::Con(Constant::Number(Number::Integer(count)));
|
let count = Addr::Con(Constant::Number(Number::Integer(count)));
|
||||||
|
|
||||||
|
let a2 = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
|
self.unify(a2, count);
|
||||||
} else {
|
} else {
|
||||||
panic!("remove_inference_counter: expected Usize in A1.");
|
panic!("remove_inference_counter: expected Usize in A1.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => panic!("remove_inference_counters: requires \\
|
None => panic!("remove_inference_counter: requires \\
|
||||||
CallWithInferenceLimitCallPolicy.")
|
CWILCallPolicy.")
|
||||||
};
|
},
|
||||||
},
|
|
||||||
&SystemClauseType::RestoreCutPolicy => {
|
&SystemClauseType::RestoreCutPolicy => {
|
||||||
let restore_default =
|
let restore_default =
|
||||||
if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
|
if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
|
||||||
@@ -321,10 +336,8 @@ impl MachineState {
|
|||||||
&SystemClauseType::SetCutPoint(r) => if cut_policy.cut(self, r) {
|
&SystemClauseType::SetCutPoint(r) => if cut_policy.cut(self, r) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
&SystemClauseType::SetCutPointByDefault(r) => {
|
&SystemClauseType::SetCutPointByDefault(r) =>
|
||||||
let mut cut_policy = DefaultCutPolicy {};
|
deref_cut(self, r),
|
||||||
cut_policy.cut(self, r);
|
|
||||||
},
|
|
||||||
&SystemClauseType::InferenceLevel => {
|
&SystemClauseType::InferenceLevel => {
|
||||||
let a1 = self[temp_v!(1)].clone();
|
let a1 = self[temp_v!(1)].clone();
|
||||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
@@ -382,12 +395,18 @@ impl MachineState {
|
|||||||
|
|
||||||
self.write_constant_to_var(addr, c);
|
self.write_constant_to_var(addr, c);
|
||||||
},
|
},
|
||||||
&SystemClauseType::GetCutPoint => {
|
&SystemClauseType::GetBValue => {
|
||||||
let a1 = self[temp_v!(1)].clone();
|
let a1 = self[temp_v!(1)].clone();
|
||||||
let a2 = Addr::Con(Constant::Usize(self.b));
|
let a2 = Addr::Con(Constant::Usize(self.b));
|
||||||
|
|
||||||
self.unify(a1, a2);
|
self.unify(a1, a2);
|
||||||
},
|
},
|
||||||
|
&SystemClauseType::GetCutPoint => {
|
||||||
|
let a1 = self[temp_v!(1)].clone();
|
||||||
|
let a2 = Addr::Con(Constant::Usize(self.b0));
|
||||||
|
|
||||||
|
self.unify(a1, a2);
|
||||||
|
},
|
||||||
&SystemClauseType::InstallNewBlock => {
|
&SystemClauseType::InstallNewBlock => {
|
||||||
self.install_new_block(temp_v!(1));
|
self.install_new_block(temp_v!(1));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1618,7 +1618,6 @@ fn test_queries_on_setup_call_cleanup()
|
|||||||
[["Y = 1", "X = 1"]]);
|
[["Y = 1", "X = 1"]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_queries_on_call_with_inference_limit()
|
fn test_queries_on_call_with_inference_limit()
|
||||||
{
|
{
|
||||||
@@ -1739,4 +1738,3 @@ fn test_queries_on_call_with_inference_limit()
|
|||||||
[["R = inference_limit_exceeded", "X = _1"]]);
|
[["R = inference_limit_exceeded", "X = _1"]]);
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
Reference in New Issue
Block a user