add call_with_inference_limit/3

This commit is contained in:
Mark Thom
2018-08-08 00:42:57 -06:00
parent 707e5fcf8b
commit 7016d378d6
9 changed files with 201 additions and 93 deletions

View File

@@ -10,6 +10,7 @@ use prolog::tabled_rc::*;
use downcast::Any;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::mem::swap;
use std::ops::{Index, IndexMut};
@@ -31,6 +32,7 @@ impl Ball {
}
}
#[derive(Clone, Copy)]
pub(crate) struct CodeDirs<'a> {
pub code_dir: &'a CodeDir,
pub op_dir: &'a OpDir,
@@ -60,7 +62,7 @@ impl<'a> CodeDirs<'a> {
.and_then(|ref module| module.code_dir.get(&(name, arity)))
.cloned()
}
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
let r_w_h = clause_name!("run_cleaners_with_handling");
let r_wo_h = clause_name!("run_cleaners_without_handling");
@@ -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> {
state: &'a mut MachineState
}
@@ -391,9 +420,9 @@ pub(crate) trait CallPolicy: Any {
Ok(())
}
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
idx: CodeIndex, code_dirs: CodeDirs)
-> CallResult
fn context_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
-> CallResult
{
if machine_st.last_call {
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,
idx: CodeIndex, code_dirs: CodeDirs)
-> CallResult
fn try_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
-> CallResult
{
match idx.0.borrow().0 {
IndexPtr::Module => {
@@ -412,7 +441,8 @@ pub(crate) trait CallPolicy: Any {
let module_name = idx.0.borrow().1.clone();
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 {
call_at_index(machine_st, module_name, arity, compiled_tl_index);
return Ok(());
@@ -439,7 +469,7 @@ pub(crate) trait CallPolicy: Any {
}
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
{
match idx.0.borrow().0 {
@@ -448,7 +478,8 @@ pub(crate) trait CallPolicy: Any {
let module_name = idx.0.borrow().1.clone();
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 {
execute_at_index(machine_st, module_name, arity, compiled_tl_index);
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
{
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
@@ -631,7 +663,7 @@ pub(crate) trait CallPolicy: Any {
ClauseType::Inlined(inlined) =>
machine_st.execute_inlined(&inlined),
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)?;
} else {
let h = machine_st.heap.h;
@@ -654,37 +686,37 @@ pub(crate) trait CallPolicy: Any {
}
}
impl CallPolicy for CallWithInferenceLimitCallPolicy {
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
arity: usize, idx: CodeIndex, code_dirs: CodeDirs)
-> CallResult
impl CallPolicy for CWILCallPolicy {
fn context_call<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
arity: usize, idx: CodeIndex, code_dirs: Box<CodeDirsAdapter<'a> + 'a>)
-> CallResult
{
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
{
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
{
self.prev_policy.retry(machine_st, offset)?;
self.increment()
self.increment(machine_st)
}
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
{
self.prev_policy.trust_me(machine_st)?;
self.increment()
self.increment(machine_st)
}
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
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,
@@ -692,14 +724,15 @@ impl CallPolicy for CallWithInferenceLimitCallPolicy {
-> CallResult
{
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
{
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 {}
pub(crate) struct CallWithInferenceLimitCallPolicy {
pub(crate) struct CWILCallPolicy {
pub(crate) prev_policy: Box<CallPolicy>,
count: BigUint,
limits: Vec<(BigUint, usize)>
pub(crate) count: BigUint,
limits: Vec<(BigUint, usize)>,
inference_limit_exceeded: bool
}
impl CallWithInferenceLimitCallPolicy {
impl CWILCallPolicy {
pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>)
{
let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
swap(&mut prev_policy, policy);
let new_policy = CallWithInferenceLimitCallPolicy { prev_policy,
count: BigUint::zero(),
limits: vec![] };
let new_policy = CWILCallPolicy { prev_policy,
count: BigUint::zero(),
limits: vec![],
inference_limit_exceeded: false };
*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 self.count == *limit {
self.inference_limit_exceeded = true;
return Err(functor!("inference_limit_exceeded", 1,
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]));
} else {
@@ -782,24 +822,34 @@ pub(crate) trait CutPolicy: Any {
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(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 {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let b = machine_st.b;
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
let addr = machine_st[r].clone();
cut_body(machine_st, addr)
}
}
@@ -867,6 +917,6 @@ impl CutPolicy for SCCCutPolicy {
return true;
}
self.run_cleaners(machine_st)
self.run_cleaners(machine_st)
}
}

View File

@@ -1821,7 +1821,7 @@ impl MachineState {
self.allocate(num_cells),
&ControlInstruction::CallClause(ClauseType::CallN, arity, _, 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) => {
self.last_call = lco;
@@ -1833,7 +1833,7 @@ impl MachineState {
| &ControlInstruction::CallClause(ClauseType::Op(ref name, _, ref idx), arity, _, lco) => {
self.last_call = lco;
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) => {
self.last_call = lco;
@@ -1947,7 +1947,8 @@ impl MachineState {
self.p += 1;
},
&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();
self.unify(a, b0);

View File

@@ -2,7 +2,7 @@ use prolog::ast::*;
use prolog::machine::machine_errors::*;
use prolog::machine::machine_state::*;
use prolog::num::{ToPrimitive, Zero};
use prolog::num::bigint::BigInt;
use prolog::num::bigint::{BigInt};
use std::rc::Rc;
@@ -177,16 +177,24 @@ impl MachineState {
self.p = CodePtr::Local(self.cp.clone());
} else {
self.p += 1;
}
}
}
pub(super) fn system_call(&mut self, ct: &SystemClauseType,
code_dirs: CodeDirs,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,)
-> CallResult
pub(super) fn system_call<'a>(&mut self, ct: &SystemClauseType,
code_dirs: CodeDirs<'a>,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,)
-> CallResult
{
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 => {
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
@@ -207,7 +215,7 @@ impl MachineState {
if let Some(r) = dest.as_var() {
self.bind(r, addr.clone());
self.set_p();
return Ok(());
}
} else {
@@ -243,20 +251,24 @@ impl MachineState {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
if call_policy.downcast_ref::<CWILCallPolicy>().is_err() {
CWILCallPolicy::new_in_place(call_policy);
}
match (a1, a2.clone()) {
(Addr::Con(Constant::Usize(bp)),
Addr::Con(Constant::Number(Number::Integer(n)))) =>
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
Some(call_policy) => {
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 \\
CallWithInferenceLimitCallPolicy.")
CWILCallPolicy.")
},
_ => {
let stub = MachineError::functor_stub(clause_name!("call_with_inference_limit"), 3);
@@ -268,7 +280,7 @@ impl MachineState {
},
&SystemClauseType::RemoveCallPolicyCheck => {
let restore_default =
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
@@ -283,29 +295,32 @@ impl MachineState {
}
},
None => panic!("remove_call_policy_check: requires \\
CallWithInferenceLimitCallPolicy.")
CWILCallPolicy.")
};
if let Some(new_policy) = restore_default {
*call_policy = new_policy;
}
},
&SystemClauseType::RemoveInferenceCounter => {
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
&SystemClauseType::RemoveInferenceCounter =>
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
if let Addr::Con(Constant::Usize(bp)) = a1 {
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 {
panic!("remove_inference_counter: expected Usize in A1.");
}
},
None => panic!("remove_inference_counters: requires \\
CallWithInferenceLimitCallPolicy.")
};
},
None => panic!("remove_inference_counter: requires \\
CWILCallPolicy.")
},
&SystemClauseType::RestoreCutPolicy => {
let restore_default =
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) {
return Ok(());
},
&SystemClauseType::SetCutPointByDefault(r) => {
let mut cut_policy = DefaultCutPolicy {};
cut_policy.cut(self, r);
},
&SystemClauseType::SetCutPointByDefault(r) =>
deref_cut(self, r),
&SystemClauseType::InferenceLevel => {
let a1 = self[temp_v!(1)].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);
},
&SystemClauseType::GetCutPoint => {
&SystemClauseType::GetBValue => {
let a1 = self[temp_v!(1)].clone();
let a2 = Addr::Con(Constant::Usize(self.b));
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 => {
self.install_new_block(temp_v!(1));
},