separate constraint checks and code addition into separate phases in machine::compile

This commit is contained in:
Mark Thom
2019-03-05 00:17:56 -07:00
parent e51e816178
commit 14f05a67e3
2 changed files with 102 additions and 67 deletions

View File

@@ -149,7 +149,8 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession
let mut compiler = ListingCompiler::new(&wam.code_repo); let mut compiler = ListingCompiler::new(&wam.code_repo);
let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl)); 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 EvalSession::EntrySuccess
}, },
@@ -165,6 +166,57 @@ pub struct GatherResult {
addition_results: ExpansionAdditionResult addition_results: ExpansionAdditionResult
} }
pub struct ClauseCodeGenerator {
len_offset: usize,
code: Code,
pi_to_loc: HashMap<PredicateKey, usize>
}
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 { pub struct ListingCompiler {
non_counted_bt_preds: HashSet<PredicateKey>, non_counted_bt_preds: HashSet<PredicateKey>,
module: Option<Module>, module: Option<Module>,
@@ -173,6 +225,27 @@ pub struct ListingCompiler {
orig_goal_expansion_lens: (usize, usize) 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 { impl ListingCompiler {
#[inline] #[inline]
pub fn new(code_repo: &CodeRepo) -> Self { pub fn new(code_repo: &CodeRepo) -> Self {
@@ -270,45 +343,6 @@ impl ListingCompiler {
.unwrap_or(ClauseName::BuiltIn("user")) .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) pub(crate)
fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine, fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine,
code_dir: &mut CodeDir) code_dir: &mut CodeDir)
@@ -336,25 +370,6 @@ impl ListingCompiler {
Ok(code) 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) { fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) {
self.non_counted_bt_preds.insert((name, arity)); self.non_counted_bt_preds.insert((name, arity));
} }
@@ -525,10 +540,25 @@ fn compile_work<R: Read>(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::UserTermExpansion, flags));
try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)); try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
try_eval_session!(compiler.add_code(wam, module_code, indices)); if let Some(module) = compiler.module.take() {
try_eval_session!(compiler.add_code(wam, toplvl_code, results.toplevel_indices)); let mut clause_code_generator = ClauseCodeGenerator::new(toplvl_code.len());
try_eval_session!(compiler.add_clause_code(results.dynamic_clause_map, wam)); 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);
}
EvalSession::EntrySuccess EvalSession::EntrySuccess
} }

View File

@@ -208,9 +208,9 @@ impl Machine {
self.machine_st.flags 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) { match ClauseType::from(key.0.clone(), key.1, None) {
ClauseType::Named(..) | ClauseType::Op(..) => {}, ClauseType::Named(..) | ClauseType::Op(..) => {},
_ => { _ => {
@@ -234,12 +234,18 @@ impl Machine {
let err_str = format!("{}/{} from module {}", key.0, key.1, let err_str = format!("{}/{} from module {}", key.0, key.1,
existing_idx.module_name().as_str()); existing_idx.module_name().as_str());
let err_str = clause_name!(err_str, self.indices.atom_tbl()); let err_str = clause_name!(err_str, self.indices.atom_tbl());
return Err(SessionError::CannotOverwriteImport(err_str)); 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. // error detection has finished, so update the master index of keys.
for (key, idx) in code_dir { for (key, idx) in code_dir {
if let Some(ref mut master_idx) = self.indices.code_dir.get_mut(&key) { if let Some(ref mut master_idx) = self.indices.code_dir.get_mut(&key) {
@@ -252,11 +258,10 @@ impl Machine {
continue; 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()); self.code_repo.code.extend(code.into_iter());
Ok(())
} }
#[inline] #[inline]