From cf741f365cb262d45f77c7848103c77cebdb9030 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 2 Apr 2018 13:50:01 -0600 Subject: [PATCH] limit hash lookups to metacall --- src/prolog/ast.rs | 53 ++++++++--- src/prolog/builtins.rs | 98 +++++++++---------- src/prolog/io.rs | 116 ++++++++++++++++++++--- src/prolog/machine/machine_state.rs | 103 ++++++++++---------- src/prolog/machine/machine_state_impl.rs | 9 +- src/prolog/machine/mod.rs | 15 ++- src/prolog/macros.rs | 16 +++- src/prolog/parser | 2 +- 8 files changed, 269 insertions(+), 143 deletions(-) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 89857418..d2c8d4d6 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -136,7 +136,7 @@ pub type OpDirKey = (ClauseName, Fixity); // name and fixity -> operator type and precedence. pub type OpDir = HashMap; -pub type CodeDir = HashMap; +pub type CodeDir = HashMap; pub type TermDir = HashMap; @@ -198,11 +198,19 @@ pub trait SubModuleUser { } if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) { + if let Some(ref mut global_code_data) = self.code_dir().get_mut(&(name.clone(), arity)) { + global_code_data.1 = code_data.1.clone(); + global_code_data.0.set(code_data.0.get()); + + return true; // done to appease the borrow checker. + } + self.code_dir().insert((name, arity), code_data.clone()); - true } else { - false + return false; } + + true } fn use_qualified_module(&mut self, submodule: &Module, exports: Vec) -> EvalSession @@ -698,8 +706,8 @@ pub enum ClauseType { Is, KeySort, NotEq, - Op(ClauseName, Fixity), - Named(ClauseName), + Op(ClauseName, Fixity, CodeIndex), + Named(ClauseName, CodeIndex), SetupCallCleanup, Sort, Throw, @@ -776,7 +784,7 @@ impl ClauseType { &ClauseType::Compare | &ClauseType::CompareTerm(_) | &ClauseType::Inlined(InlinedClauseType::CompareNumber(_)) | &ClauseType::NotEq | &ClauseType::Is | &ClauseType::Eq => Some(Fixity::In), - &ClauseType::Op(_, fixity) => Some(fixity), + &ClauseType::Op(_, fixity, _) => Some(fixity), _ => None } } @@ -800,8 +808,8 @@ impl ClauseType { &ClauseType::Is => clause_name!("is"), &ClauseType::KeySort => clause_name!("keysort"), &ClauseType::NotEq => clause_name!("\\=="), - &ClauseType::Op(ref name, _) => name.clone(), - &ClauseType::Named(ref name) => name.clone(), + &ClauseType::Op(ref name, ..) => name.clone(), + &ClauseType::Named(ref name, ..) => name.clone(), &ClauseType::SetupCallCleanup => clause_name!("setup_call_cleanup"), &ClauseType::Sort => clause_name!("sort"), &ClauseType::Throw => clause_name!("throw") @@ -835,9 +843,9 @@ impl ClauseType { ("sort", 2) => ClauseType::Sort, ("throw", 1) => ClauseType::Throw, _ => if let Some(fixity) = fixity { - ClauseType::Op(name, fixity) + ClauseType::Op(name, fixity, CodeIndex::default()) } else { - ClauseType::Named(name) + ClauseType::Named(name, CodeIndex::default()) } } } @@ -1385,6 +1393,21 @@ impl HeapCellValue { } } +#[derive(Clone)] +pub struct CodeIndex(pub Rc>, pub ClauseName); + +impl CodeIndex { + pub fn is_undefined(&self) -> bool { + self.0.get() == 0 && self.1 == clause_name!("") + } +} + +impl From<(usize, ClauseName)> for CodeIndex { + fn from(value: (usize, ClauseName)) -> Self { + CodeIndex(Rc::new(Cell::new(value.0)), value.1) + } +} + #[derive(Clone, PartialEq)] pub enum CodePtr { DirEntry(usize, ClauseName), // offset, resident module name. @@ -1414,6 +1437,12 @@ impl PartialOrd for CodePtr { } } +impl Default for CodeIndex { + fn default() -> Self { + CodeIndex(Rc::new(Cell::new(0)), clause_name!("")) + } +} + impl Default for CodePtr { fn default() -> Self { CodePtr::TopLevel(0, 0) @@ -1541,9 +1570,9 @@ impl<'a> TermIterState<'a> { TermIterState::AnonVar(lvl), &Term::Clause(ref cell, ref name, ref subterms, fixity) => { let ct = if let Some(fixity) = fixity { - ClauseType::Op(name.clone(), fixity) + ClauseType::Op(name.clone(), fixity, CodeIndex::default()) } else { - ClauseType::Named(name.clone()) + ClauseType::Named(name.clone(), CodeIndex::default()) }; TermIterState::Clause(lvl, 0, cell, ct, subterms) diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 88c5a5b3..b42d3876 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -688,62 +688,64 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir) // there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62 // (an extra register is needed for the predicate name) for arity in 0 .. 63 { - code_dir.insert((clause_name!("call"), arity), (0, builtin.clone())); + code_dir.insert((clause_name!("call"), arity), CodeIndex::from((0, builtin.clone()))); } - code_dir.insert((clause_name!("atomic"), 1), (1, builtin.clone())); - code_dir.insert((clause_name!("var"), 1), (3, builtin.clone())); - code_dir.insert((clause_name!("false"), 0), (61, builtin.clone())); - code_dir.insert((clause_name!("\\+"), 1), (62, builtin.clone())); - code_dir.insert((clause_name!("duplicate_term"), 2), (71, builtin.clone())); - code_dir.insert((clause_name!("catch"), 3), (5, builtin.clone())); - code_dir.insert((clause_name!("throw"), 1), (59, builtin.clone())); - code_dir.insert((clause_name!("="), 2), (73, builtin.clone())); - code_dir.insert((clause_name!("true"), 0), (75, builtin.clone())); + code_dir.insert((clause_name!("atomic"), 1), CodeIndex::from((1, builtin.clone()))); + code_dir.insert((clause_name!("var"), 1), CodeIndex::from((3, builtin.clone()))); + code_dir.insert((clause_name!("false"), 0), CodeIndex::from((61, builtin.clone()))); + code_dir.insert((clause_name!("\\+"), 1), CodeIndex::from((62, builtin.clone()))); + code_dir.insert((clause_name!("duplicate_term"), 2), CodeIndex::from((71, builtin.clone()))); + code_dir.insert((clause_name!("catch"), 3), CodeIndex::from((5, builtin.clone()))); + code_dir.insert((clause_name!("throw"), 1), CodeIndex::from((59, builtin.clone()))); + code_dir.insert((clause_name!("="), 2), CodeIndex::from((73, builtin.clone()))); + code_dir.insert((clause_name!("true"), 0), CodeIndex::from((75, builtin.clone()))); - code_dir.insert((clause_name!(","), 2), (76, builtin.clone())); - code_dir.insert((clause_name!(";"), 2), (120, builtin.clone())); - code_dir.insert((clause_name!("->"), 2), (138, builtin.clone())); + code_dir.insert((clause_name!(","), 2), CodeIndex::from((76, builtin.clone()))); + code_dir.insert((clause_name!(";"), 2), CodeIndex::from((120, builtin.clone()))); + code_dir.insert((clause_name!("->"), 2), CodeIndex::from((138, builtin.clone()))); - code_dir.insert((clause_name!("functor"), 3), (146, builtin.clone())); - code_dir.insert((clause_name!("arg"), 3), (150, builtin.clone())); - code_dir.insert((clause_name!("integer"), 1), (147, builtin.clone())); - code_dir.insert((clause_name!("display"), 1), (192, builtin.clone())); + code_dir.insert((clause_name!("functor"), 3), CodeIndex::from((146, builtin.clone()))); + code_dir.insert((clause_name!("arg"), 3), CodeIndex::from((150, builtin.clone()))); + code_dir.insert((clause_name!("integer"), 1), CodeIndex::from((147, builtin.clone()))); + code_dir.insert((clause_name!("display"), 1), CodeIndex::from((192, builtin.clone()))); - code_dir.insert((clause_name!("is"), 2), (194, builtin.clone())); - code_dir.insert((clause_name!(">"), 2), (196, builtin.clone())); - code_dir.insert((clause_name!("<"), 2), (198, builtin.clone())); - code_dir.insert((clause_name!(">="), 2), (200, builtin.clone())); - code_dir.insert((clause_name!("=<"), 2), (202, builtin.clone())); - code_dir.insert((clause_name!("=\\="), 2), (204, builtin.clone())); - code_dir.insert((clause_name!("=:="), 2), (206, builtin.clone())); - code_dir.insert((clause_name!("=.."), 2), (208, builtin.clone())); + code_dir.insert((clause_name!("is"), 2), CodeIndex::from((194, builtin.clone()))); + code_dir.insert((clause_name!(">"), 2), CodeIndex::from((196, builtin.clone()))); + code_dir.insert((clause_name!("<"), 2), CodeIndex::from((198, builtin.clone()))); + code_dir.insert((clause_name!(">="), 2), CodeIndex::from((200, builtin.clone()))); + code_dir.insert((clause_name!("=<"), 2), CodeIndex::from((202, builtin.clone()))); + code_dir.insert((clause_name!("=\\="), 2), CodeIndex::from((204, builtin.clone()))); + code_dir.insert((clause_name!("=:="), 2), CodeIndex::from((206, builtin.clone()))); + code_dir.insert((clause_name!("=.."), 2), CodeIndex::from((208, builtin.clone()))); - code_dir.insert((clause_name!("length"), 2), (261, builtin.clone())); - code_dir.insert((clause_name!("setup_call_cleanup"), 3), (294, builtin.clone())); - code_dir.insert((clause_name!("call_with_inference_limit"), 3), (393, builtin.clone())); + code_dir.insert((clause_name!("length"), 2), CodeIndex::from((261, builtin.clone()))); + code_dir.insert((clause_name!("setup_call_cleanup"), 3), + CodeIndex::from((294, builtin.clone()))); + code_dir.insert((clause_name!("call_with_inference_limit"), 3), + CodeIndex::from((393, builtin.clone()))); - code_dir.insert((clause_name!("compound"), 1), (372, builtin.clone())); - code_dir.insert((clause_name!("rational"), 1), (374, builtin.clone())); - code_dir.insert((clause_name!("string"), 1), (376, builtin.clone())); - code_dir.insert((clause_name!("float"), 1), (378, builtin.clone())); - code_dir.insert((clause_name!("nonvar"), 1), (380, builtin.clone())); + code_dir.insert((clause_name!("compound"), 1), CodeIndex::from((372, builtin.clone()))); + code_dir.insert((clause_name!("rational"), 1), CodeIndex::from((374, builtin.clone()))); + code_dir.insert((clause_name!("string"), 1), CodeIndex::from((376, builtin.clone()))); + code_dir.insert((clause_name!("float"), 1), CodeIndex::from((378, builtin.clone()))); + code_dir.insert((clause_name!("nonvar"), 1), CodeIndex::from((380, builtin.clone()))); - code_dir.insert((clause_name!("ground"), 1), (384, builtin.clone())); - code_dir.insert((clause_name!("=="), 2), (385, builtin.clone())); - code_dir.insert((clause_name!("\\=="), 2), (386, builtin.clone())); - code_dir.insert((clause_name!("@>="), 2), (387, builtin.clone())); - code_dir.insert((clause_name!("@=<"), 2), (388, builtin.clone())); - code_dir.insert((clause_name!("@>"), 2), (389, builtin.clone())); - code_dir.insert((clause_name!("@<"), 2), (390, builtin.clone())); - code_dir.insert((clause_name!("=@="), 2), (391, builtin.clone())); - code_dir.insert((clause_name!("\\=@="), 2), (392, builtin.clone())); - code_dir.insert((clause_name!("compare"), 3), (464, builtin.clone())); - code_dir.insert((clause_name!("atom"), 1), (465, builtin.clone())); - code_dir.insert((clause_name!("sort"), 2), (467, builtin.clone())); - code_dir.insert((clause_name!("keysort"), 2), (468, builtin.clone())); - code_dir.insert((clause_name!("acyclic_term"), 1), (469, builtin.clone())); - code_dir.insert((clause_name!("cyclic_term"), 1), (470, builtin.clone())); + code_dir.insert((clause_name!("ground"), 1), CodeIndex::from((384, builtin.clone()))); + code_dir.insert((clause_name!("=="), 2), CodeIndex::from((385, builtin.clone()))); + code_dir.insert((clause_name!("\\=="), 2), CodeIndex::from((386, builtin.clone()))); + code_dir.insert((clause_name!("@>="), 2), CodeIndex::from((387, builtin.clone()))); + code_dir.insert((clause_name!("@=<"), 2), CodeIndex::from((388, builtin.clone()))); + code_dir.insert((clause_name!("@>"), 2), CodeIndex::from((389, builtin.clone()))); + code_dir.insert((clause_name!("@<"), 2), CodeIndex::from((390, builtin.clone()))); + code_dir.insert((clause_name!("=@="), 2), CodeIndex::from((391, builtin.clone()))); + code_dir.insert((clause_name!("\\=@="), 2), CodeIndex::from((392, builtin.clone()))); + code_dir.insert((clause_name!("compare"), 3), CodeIndex::from((464, builtin.clone()))); + code_dir.insert((clause_name!("atom"), 1), CodeIndex::from((465, builtin.clone()))); + code_dir.insert((clause_name!("sort"), 2), CodeIndex::from((467, builtin.clone()))); + code_dir.insert((clause_name!("keysort"), 2), CodeIndex::from((468, builtin.clone()))); + code_dir.insert((clause_name!("acyclic_term"), 1), CodeIndex::from((469, builtin.clone()))); + code_dir.insert((clause_name!("cyclic_term"), 1), CodeIndex::from((470, builtin.clone()))); (code_dir, op_dir) } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 76e1b8f1..293d5484 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -103,6 +103,16 @@ impl fmt::Display for CompareTermQT { } } +impl fmt::Display for ClauseType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) => + write!(f, "{}:{}/{}", idx.1, name, idx.0.get()), + ref ct => + write!(f, "{}", ct.name()) + } + } +} impl fmt::Display for ControlInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -110,9 +120,9 @@ impl fmt::Display for ControlInstruction { &ControlInstruction::Allocate(num_cells) => write!(f, "allocate {}", num_cells), &ControlInstruction::CallClause(ref ct, arity, pvs, true) => - write!(f, "execute {}/{}, {}", ct.name(), arity, pvs), + write!(f, "execute {}/{}, {}", ct, arity, pvs), &ControlInstruction::CallClause(ref ct, arity, pvs, false) => - write!(f, "call {}/{}, {}", ct.name(), arity, pvs), + write!(f, "call {}/{}, {}", ct, arity, pvs), &ControlInstruction::CheckCpExecute => write!(f, "check_cp_execute"), &ControlInstruction::Deallocate => @@ -162,7 +172,7 @@ impl fmt::Display for BuiltInInstruction { &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2), &BuiltInInstruction::DefaultRetryMeElse(o) => - write!(f, "default_retry_me_else {}", o), + write!(f, "default_retry_me_else {}", o), &BuiltInInstruction::DefaultSetCutPoint(r) => write!(f, "default_set_cp {}", r), &BuiltInInstruction::DefaultTrustMe => @@ -421,6 +431,58 @@ pub fn read() -> Input { } } +pub(crate) trait TLInfo { + fn update_entry_index(&self, &ClauseName, usize, CodeIndex, &mut CodeIndex, usize); + + // give the correct CodePtr offsets to CallClause's whose types are + // Named and Op. Enable late binding by setting to the default. + fn label_clauses(&self, code_size: usize, code_dir: &mut CodeDir, code: &mut Code) + { + for line in code.iter_mut() { + if let &mut Line::Control(ControlInstruction::CallClause(ref mut ct, a1, ..)) = line { + match ct { + &mut ClauseType::Named(ref n1, ref mut cp) + | &mut ClauseType::Op(ref n1, _, ref mut cp) => { + let entry = code_dir.entry((n1.clone(), a1)).or_insert(CodeIndex::default()); + self.update_entry_index(n1, a1, entry.clone(), cp, code_size); + }, + _ => {} + } + } + } + } +} + +struct DeclInfo { name: ClauseName, arity: usize, module_name: ClauseName } + +impl TLInfo for DeclInfo { + fn update_entry_index(&self, n1: &ClauseName, a1: usize, mut entry: CodeIndex, + cp: &mut CodeIndex, code_size: usize) + { + let (name, arity) = (self.name.clone(), self.arity); + + if entry.0.get() == 0 { + if &name == n1 && arity == a1 { + // *entry = default(); // implement logical view update semantics. + entry.0.set(code_size); + } + } + + entry.1 = self.module_name.clone(); + *cp = entry; + } +} + +struct QueryInfo {} + +impl TLInfo for QueryInfo { + fn update_entry_index(&self, _: &ClauseName, _: usize, entry: CodeIndex, + cp: &mut CodeIndex, _: usize) + { + *cp = entry; + } +} + // throw errors if declaration or query found. fn compile_relation(tl: &TopLevel) -> Result { @@ -438,9 +500,9 @@ fn compile_relation(tl: &TopLevel) -> Result } } -// set first jmp_by_call or jmp_by_index instruction to code.len() - idx, -// where idx is the place it occurs. It only does this to the *first* uninitialized -// jmp index it encounters, then returns. +// set first jmp_by_call or jmp_by_index instruction to code.len() - +// idx, where idx is the place it occurs. It only does this to the +// *first* uninitialized jmp index it encounters, then returns. fn set_first_index(code: &mut Code) { let code_len = code.len(); @@ -466,7 +528,8 @@ fn compile_appendix(code: &mut Code, queue: Vec) -> Result<(), ParserE Ok(()) } -fn compile_query(terms: Vec, queue: Vec) +fn compile_query(terms: Vec, queue: Vec, code_size: usize, + code_dir: &mut CodeDir) -> Result<(Code, AllocVarDict), ParserError> { let mut cg = CodeGenerator::::new(); @@ -474,6 +537,9 @@ fn compile_query(terms: Vec, queue: Vec) compile_appendix(&mut code, queue)?; + let query_info = QueryInfo {}; + query_info.label_clauses(code_size, code_dir, &mut code); + Ok((code, cg.take_vars())) } @@ -491,15 +557,22 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec) -> EvalSe TopLevel::Declaration(_) => EvalSession::from(ParserError::InvalidModuleDecl), _ => { + let name = try_eval_session!(if let Some(name) = tl.name() { + Ok(name) + } else { + Err(EvalError::NamelessEntry) + }); + let mut code = try_eval_session!(compile_relation(&tl)); try_eval_session!(compile_appendix(&mut code, queue)); + let decl_info = DeclInfo { name: name.clone(), arity: tl.arity(), + module_name: clause_name!("user") }; + + decl_info.label_clauses(wam.code_size(), &mut wam.code_dir, &mut code); + if !code.is_empty() { - if let Some(name) = tl.name() { - wam.add_user_code(name, tl.arity(), code, tl.as_predicate().unwrap()) - } else { - EvalSession::from(EvalError::NamelessEntry) - } + wam.add_user_code(name, tl.arity(), code, tl.as_predicate().unwrap()) } else { EvalSession::from(EvalError::ImpermissibleEntry(String::from("no code generated."))) } @@ -511,7 +584,7 @@ pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession { match tl { TopLevelPacket::Query(terms, queue) => - match compile_query(terms, queue) { + match compile_query(terms, queue, wam.code_size(), &mut wam.code_dir) { Ok((mut code, vars)) => wam.submit_query(code, vars), Err(e) => EvalSession::from(e) }, @@ -525,7 +598,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession fn get_module_name(module: &Option) -> ClauseName { match module { &Some(ref module) => module.module_decl.name.clone(), - _ => ClauseName::BuiltIn("builtin") + _ => ClauseName::BuiltIn("user") } } @@ -583,8 +656,21 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession try_eval_session!(compile_appendix(&mut decl_code, queue)); + let name = try_eval_session!(if let Some(name) = decl.name() { + Ok(name) + } else { + Err(EvalError::NamelessEntry) + }); + + let module_name = get_module_name(&module); + + let decl_info = DeclInfo { name, arity: decl.arity(), module_name }; + decl_info.label_clauses(p, &mut code_dir, &mut decl_code); + code.extend(decl_code.into_iter()); - code_dir.insert((decl.name().unwrap(), decl.arity()), (p, get_module_name(&module))); + + let index = CodeIndex::from((p, get_module_name(&module))); + code_dir.insert((decl_info.name.clone(), decl_info.arity), index); } } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index a0893580..27f94a68 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -28,16 +28,12 @@ impl<'a> CodeDirs<'a> { let module_name = p.module_name(); match module_name { - ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") => - self.code_dir, - _ => - &self.modules.get(&module_name).unwrap().code_dir + ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") => self.code_dir, + _ => &self.modules.get(&module_name).unwrap().code_dir } } - pub(crate) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr) - -> Option<(usize, ClauseName)> - { + pub(super) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr) -> Option { let code_dir = self.get_current_code_dir(p); code_dir.get(&(name, arity)).cloned() } @@ -215,54 +211,46 @@ pub struct MachineState { pub(crate) type CallResult = Result<(), Vec>; pub(crate) trait CallPolicy: Any { - fn context_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>, - name: ClauseName, arity: usize, lco: bool) - -> CallResult + fn context_call(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex, lco: bool) + -> CallResult { if lco { - self.try_execute(machine_st, code_dirs, name, arity) + self.try_execute(machine_st, arity, idx) } else { - self.try_call(machine_st, code_dirs, name, arity) + self.try_call(machine_st, arity, idx) } } - - fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>, - name: ClauseName, arity: usize) - -> CallResult - { - let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p); - match compiled_tl_index { - Some(compiled_tl_index) => { - let module_name = compiled_tl_index.1.clone(); + fn try_call(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex) -> CallResult + { + if idx.is_undefined() { + machine_st.fail = true; + } else { + let compiled_tl_index = idx.0.get(); + let module_name = idx.1; - machine_st.cp = machine_st.p.clone() + 1; - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name); - }, - None => machine_st.fail = true - }; + machine_st.cp = machine_st.p.clone() + 1; + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + } Ok(()) } - fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>, - name: ClauseName, arity: usize) + fn try_execute<'a>(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex) -> CallResult - { - let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p); - - match compiled_tl_index { - Some(compiled_tl_index) => { - let module_name = compiled_tl_index.1.clone(); + { + if idx.is_undefined() { + machine_st.fail = true; + } else { + let compiled_tl_index = idx.0.get(); + let module_name = idx.1; - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name); - }, - None => machine_st.fail = true - }; + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + } Ok(()) } @@ -396,7 +384,7 @@ pub(crate) trait CallPolicy: Any { { match ct { &ClauseType::AcyclicTerm => { - let addr = machine_st[temp_v!(1)].clone(); + let addr = machine_st[temp_v!(1)].clone(); machine_st.fail = machine_st.is_cyclic_term(addr); return_from_clause!(lco, machine_st) }, @@ -422,21 +410,26 @@ pub(crate) trait CallPolicy: Any { Ok(()) }, - &ClauseType::CallN => + &ClauseType::CallN => { if let Some((name, arity)) = machine_st.setup_call_n(arity) { - self.context_call(machine_st, code_dirs, name, arity, lco) - } else { - Ok(()) - }, + if let Some(idx) = code_dirs.get(name, arity, &machine_st.p.clone()) { + return self.context_call(machine_st, arity, idx, lco); + } else { + machine_st.fail = true; + } + } + + Ok(()) + }, &ClauseType::Compare => { let a1 = machine_st[temp_v!(1)].clone(); let a2 = machine_st[temp_v!(2)].clone(); let a3 = machine_st[temp_v!(3)].clone(); let c = Addr::Con(match machine_st.compare_term_test(&a2, &a3) { - Ordering::Greater => atom!(">", machine_st.atom_tbl), - Ordering::Equal => atom!("=", machine_st.atom_tbl), - Ordering::Less => atom!("<", machine_st.atom_tbl) + Ordering::Greater => atom!(">"), + Ordering::Equal => atom!("="), + Ordering::Less => atom!("<") }); machine_st.unify(a1, c); @@ -454,7 +447,7 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(lco, machine_st) }, &ClauseType::CyclicTerm => { - let addr = machine_st[temp_v!(1)].clone(); + let addr = machine_st[temp_v!(1)].clone(); machine_st.fail = !machine_st.is_cyclic_term(addr); return_from_clause!(lco, machine_st) }, @@ -522,12 +515,12 @@ pub(crate) trait CallPolicy: Any { if !lco { machine_st.cp = machine_st.p.clone() + 1; } - + machine_st.goto_throw(); Ok(()) }, - &ClauseType::Named(ref name) | &ClauseType::Op(ref name, _) => - self.context_call(machine_st, code_dirs, name.clone(), arity, lco), + &ClauseType::Named(_, ref idx) | &ClauseType::Op(_, _, ref idx) => + self.context_call(machine_st, arity, idx.clone(), lco), &ClauseType::CallWithInferenceLimit => { machine_st.goto_ptr(CodePtr::DirEntry(393, clause_name!("builtin")), 3, lco); Ok(()) diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 5b97e455..bbdcae7d 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -909,11 +909,14 @@ impl MachineState { self.registers[arity - 1] = pred; if let Some((name, arity)) = self.setup_call_n(arity - 1) { - try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity)); + if let Some(idx) = code_dirs.get(name, arity, &self.p.clone()) { + try_or_fail!(self, call_policy.try_execute(self, arity, idx)); + return; + } } - } else { - self.fail = true; } + + self.fail = true; } pub(super) fn goto_throw(&mut self) { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 6e6bc1ec..b1d35baa 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -25,8 +25,8 @@ pub struct Machine { call_policy: Box, cut_policy: Box, code: Code, - code_dir: CodeDir, - pub op_dir: OpDir, + pub(super) code_dir: CodeDir, + pub(super) op_dir: OpDir, term_dir: TermDir, modules: HashMap, cached_query: Option @@ -87,7 +87,7 @@ impl Machine { let name = name.defrock_brackets(); match self.code_dir.get(&(name.clone(), arity)).cloned() { - Some((_, ref mod_name)) if mod_name == &module_name => { + Some(CodeIndex (_, ref mod_name)) if mod_name == &module_name => { self.code_dir.remove(&(name.clone(), arity)); // remove or respecify ops. @@ -179,7 +179,7 @@ impl Machine { -> EvalSession { match self.code_dir.get(&(name.clone(), arity)) { - Some(&(_, ref mod_name)) if mod_name == &clause_name!("builtin") => + Some(&CodeIndex (_, ref mod_name)) if mod_name == &clause_name!("builtin") => return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))), _ => {} }; @@ -188,7 +188,12 @@ impl Machine { self.code.extend(code.into_iter()); self.term_dir.insert((name.clone(), arity), pred); - self.code_dir.insert((name, arity), (offset, clause_name!("user"))); + + let entry = self.code_dir.entry((name, arity)) + .or_insert(CodeIndex::from((offset, clause_name!("user")))); + + entry.0.set(offset); + entry.1 = clause_name!("user"); EvalSession::EntrySuccess } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 85a25760..c48418ea 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -124,10 +124,14 @@ macro_rules! put_var { macro_rules! put_structure { ($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => ( - QueryInstruction::PutStructure(ClauseType::Op(clause_name!($atom), $fix), $arity, $r) + QueryInstruction::PutStructure(ClauseType::Op(clause_name!($atom), $fix, CodeIndex::default()), + $arity, + $r) ); ($atom:expr, $arity:expr, $r:expr, None) => ( - QueryInstruction::PutStructure(ClauseType::Named(clause_name!($atom)), $arity, $r) + QueryInstruction::PutStructure(ClauseType::Named(clause_name!($atom), CodeIndex::default()), + $arity, + $r) ) } @@ -393,10 +397,14 @@ macro_rules! get_constant { macro_rules! get_structure { ($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => ( - FactInstruction::GetStructure(ClauseType::Op(clause_name!($atom), $fix), $arity, $r) + FactInstruction::GetStructure(ClauseType::Op(clause_name!($atom), $fix, CodeIndex::default()), + $arity, + $r) ); ($atom:expr, $arity:expr, $r:expr, None) => ( - FactInstruction::GetStructure(ClauseType::Named(clause_name!($atom)), $arity, $r) + FactInstruction::GetStructure(ClauseType::Named(clause_name!($atom), CodeIndex::default()), + $arity, + $r) ) } diff --git a/src/prolog/parser b/src/prolog/parser index a61db9f4..2dfd48a1 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit a61db9f45e3c9c476944435e88abca0abe189cc2 +Subproject commit 2dfd48a1ef8e63de74798d131920a25bc2fe6c8b -- 2.54.0