From 14f05a67e32479c52c8583dfe26c0d1bed133ded Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 5 Mar 2019 00:17:56 -0700 Subject: [PATCH] separate constraint checks and code addition into separate phases in machine::compile --- src/prolog/machine/compile.rs | 156 ++++++++++++++++++++-------------- src/prolog/machine/mod.rs | 13 ++- 2 files changed, 102 insertions(+), 67 deletions(-) diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index 77a460b4..d1d20a59 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -149,7 +149,8 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession let mut compiler = ListingCompiler::new(&wam.code_repo); let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl)); - try_eval_session!(compiler.add_code(wam, vec![], indices)); + try_eval_session!(wam.check_toplevel_code(&indices)); + add_toplevel_code(wam, vec![], indices); EvalSession::EntrySuccess }, @@ -165,6 +166,57 @@ pub struct GatherResult { addition_results: ExpansionAdditionResult } +pub struct ClauseCodeGenerator { + len_offset: usize, + code: Code, + pi_to_loc: HashMap +} + +impl ClauseCodeGenerator { + #[inline] + fn new(len_offset: usize) -> Self { + ClauseCodeGenerator { len_offset, code: vec![], pi_to_loc: HashMap::new() } + } + + fn generate_clause_code(&mut self, dynamic_clause_map: DynamicClauseMap, wam: &Machine) + -> Result<(), SessionError> + { + for ((name, arity), heads_and_tails) in dynamic_clause_map { + if heads_and_tails.is_empty() { + continue; + } + + let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| { + let clause = Term::Clause(Cell::default(), clause_name!("clause"), + vec![Box::new(head), Box::new(tail)], + None); + PredicateClause::Fact(clause) + }).collect()); + + let p = self.code.len() + wam.code_size() + self.len_offset; + let mut decl_code = compile_relation(&TopLevel::Predicate(predicate), false, + wam.machine_flags())?; + + compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?; + + self.pi_to_loc.insert((name, arity), p); + self.code.extend(decl_code.into_iter()); + } + + Ok(()) + } + + fn add_clause_code(self, wam: &mut Machine) { + wam.code_repo.code.extend(self.code.into_iter()); + + for ((name, arity), p) in self.pi_to_loc { + let entry = wam.indices.dynamic_code_dir.entry((name, arity)) + .or_insert(DynamicPredicateInfo::default()); + entry.clauses_subsection_p = p; + } + } +} + pub struct ListingCompiler { non_counted_bt_preds: HashSet, module: Option, @@ -173,6 +225,27 @@ pub struct ListingCompiler { orig_goal_expansion_lens: (usize, usize) } +fn add_toplevel_code(wam: &mut Machine, code: Code, mut indices: IndexStore) +{ + let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new()); + let op_dir = mem::replace(&mut indices.op_dir, OpDir::new()); + + wam.add_batched_code(code, code_dir); + wam.add_batched_ops(op_dir); +} + +#[inline] +fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, mut indices: IndexStore) +{ + let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new()); + let op_dir = mem::replace(&mut indices.op_dir, OpDir::new()); + + module.code_dir.extend(as_module_code_dir(code_dir)); + module.op_dir.extend(op_dir.into_iter()); + + wam.add_module(module, code); +} + impl ListingCompiler { #[inline] pub fn new(code_repo: &CodeRepo) -> Self { @@ -270,45 +343,6 @@ impl ListingCompiler { .unwrap_or(ClauseName::BuiltIn("user")) } - fn add_clause_code(&mut self, dynamic_clause_map: DynamicClauseMap, wam: &mut Machine) - -> Result<(), SessionError> - { - let mut code = vec![]; - let mut pi_to_loc = HashMap::new(); - - for ((name, arity), heads_and_tails) in dynamic_clause_map { - if heads_and_tails.is_empty() { - continue; - } - - let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| { - let clause = Term::Clause(Cell::default(), clause_name!("clause"), - vec![Box::new(head), Box::new(tail)], - None); - PredicateClause::Fact(clause) - }).collect()); - - let p = code.len() + wam.code_size(); - let mut decl_code = compile_relation(&TopLevel::Predicate(predicate), false, - wam.machine_flags())?; - - compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?; - - pi_to_loc.insert((name, arity), p); - code.extend(decl_code.into_iter()); - } - - wam.code_repo.code.extend(code.into_iter()); - - for ((name, arity), p) in pi_to_loc { - let entry = wam.indices.dynamic_code_dir.entry((name, arity)) - .or_insert(DynamicPredicateInfo::default()); - entry.clauses_subsection_p = p; - } - - Ok(()) - } - pub(crate) fn generate_code(&mut self, decls: Vec, wam: &Machine, code_dir: &mut CodeDir) @@ -336,25 +370,6 @@ impl ListingCompiler { Ok(code) } - fn add_code(&mut self, wam: &mut Machine, code: Code, mut indices: IndexStore) - -> Result<(), SessionError> - { - let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new()); - let op_dir = mem::replace(&mut indices.op_dir, OpDir::new()); - - if let Some(mut module) = self.module.take() { - module.code_dir.extend(as_module_code_dir(code_dir)); - module.op_dir.extend(op_dir.into_iter()); - - wam.add_module(module, code); - } else { - wam.add_batched_code(code, code_dir)?; - wam.add_batched_ops(op_dir); - } - - Ok(()) - } - fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) { self.non_counted_bt_preds.insert((name, arity)); } @@ -525,11 +540,26 @@ fn compile_work(compiler: &mut ListingCompiler, wam: &mut Machine, src: try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags)); try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)); - try_eval_session!(compiler.add_code(wam, module_code, indices)); - try_eval_session!(compiler.add_code(wam, toplvl_code, results.toplevel_indices)); + if let Some(module) = compiler.module.take() { + let mut clause_code_generator = ClauseCodeGenerator::new(toplvl_code.len()); + + try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam)); + try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices)); + + add_toplevel_code(wam, toplvl_code, results.toplevel_indices); + clause_code_generator.add_clause_code(wam); + add_module_code(wam, module, module_code, indices); + } else { + let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len()); + + try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam)); + try_eval_session!(wam.check_toplevel_code(&indices)); + + // yes, in this case, module_code is actually toplevel code. + add_toplevel_code(wam, module_code, indices); + clause_code_generator.add_clause_code(wam); + } - try_eval_session!(compiler.add_clause_code(results.dynamic_clause_map, wam)); - EvalSession::EntrySuccess } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index b65eea09..bee13631 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -208,9 +208,9 @@ impl Machine { self.machine_st.flags } - pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) -> Result<(), SessionError> + pub fn check_toplevel_code(&self, indices: &IndexStore) -> Result<(), SessionError> { - for (ref key, ref idx) in code_dir.iter() { + for (key, idx) in &indices.code_dir { match ClauseType::from(key.0.clone(), key.1, None) { ClauseType::Named(..) | ClauseType::Op(..) => {}, _ => { @@ -234,12 +234,18 @@ impl Machine { let err_str = format!("{}/{} from module {}", key.0, key.1, existing_idx.module_name().as_str()); let err_str = clause_name!(err_str, self.indices.atom_tbl()); + return Err(SessionError::CannotOverwriteImport(err_str)); } } } } + Ok(()) + } + + pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) + { // error detection has finished, so update the master index of keys. for (key, idx) in code_dir { if let Some(ref mut master_idx) = self.indices.code_dir.get_mut(&key) { @@ -252,11 +258,10 @@ impl Machine { continue; } - self.indices.code_dir.insert(key.clone(), idx.clone()); + self.indices.code_dir.insert(key, idx); } self.code_repo.code.extend(code.into_iter()); - Ok(()) } #[inline] -- 2.54.0