merge with master
This commit is contained in:
@@ -83,7 +83,7 @@ fn load_module<R: Read>(
|
||||
// this impromptu definition (namely, its exports) will be filled out later.
|
||||
let module_decl = ModuleDecl { name: listing_src, exports: vec![] };
|
||||
|
||||
let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone());
|
||||
let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone());
|
||||
let module_name = module.module_decl.name.clone();
|
||||
|
||||
module.is_impromptu_module = true;
|
||||
@@ -94,6 +94,7 @@ fn load_module<R: Read>(
|
||||
|
||||
results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results))
|
||||
.or_else(|e| {
|
||||
wam.indices.take_module(module_name.clone());
|
||||
compiler.print_error(&e);
|
||||
Err(e)
|
||||
})?;
|
||||
@@ -201,6 +202,24 @@ pub fn compile_appendix(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_trivial_goal(name: &ClauseName, pred: &mut Predicate)
|
||||
{
|
||||
let var = Box::new(Term::Var(Cell::default(), Rc::new(String::from("X"))));
|
||||
let body = QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::from(clause_name!("$at_end_of_expansion"), 0, None),
|
||||
vec![],
|
||||
false
|
||||
);
|
||||
|
||||
let rule = Rule {
|
||||
head: (name.clone(), vec![var.clone(), var], body),
|
||||
clauses: vec![]
|
||||
};
|
||||
|
||||
pred.0.push(PredicateClause::Rule(rule, 0, 0));
|
||||
}
|
||||
|
||||
impl CodeRepo {
|
||||
pub fn compile_hook(
|
||||
&mut self,
|
||||
@@ -209,13 +228,17 @@ impl CodeRepo {
|
||||
) -> Result<(), ParserError> {
|
||||
let key = (hook.name(), hook.arity());
|
||||
|
||||
match self.term_dir.get(&key) {
|
||||
Some(preds) => {
|
||||
match self.term_dir.get_mut(&key) {
|
||||
Some(ref mut preds) => {
|
||||
append_trivial_goal(&key.0, &mut preds.0);
|
||||
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
|
||||
let mut code = cg.compile_predicate(&(preds.0).0)?;
|
||||
|
||||
compile_appendix(&mut code, &preds.1, false, flags)?;
|
||||
|
||||
(preds.0).0.pop();
|
||||
|
||||
Ok(match hook {
|
||||
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
|
||||
self.term_expanders = code
|
||||
@@ -225,7 +248,26 @@ impl CodeRepo {
|
||||
}
|
||||
})
|
||||
}
|
||||
None => Ok(()),
|
||||
None => Ok(match hook {
|
||||
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
|
||||
if self.term_expanders.is_empty() {
|
||||
let mut preds = Predicate::new();
|
||||
append_trivial_goal(&key.0, &mut preds);
|
||||
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
|
||||
self.term_expanders = cg.compile_predicate(&preds.0)?;
|
||||
}
|
||||
}
|
||||
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
|
||||
if self.goal_expanders.is_empty() {
|
||||
let mut preds = Predicate::new();
|
||||
append_trivial_goal(&key.0, &mut preds);
|
||||
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
|
||||
self.goal_expanders = cg.compile_predicate(&preds.0)?;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,8 +691,8 @@ impl ListingCompiler {
|
||||
let idx = code_dir
|
||||
.entry((name.clone(), arity))
|
||||
.or_insert(CodeIndex::default());
|
||||
|
||||
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
|
||||
|
||||
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
|
||||
|
||||
self.localize_self_calls(name, arity, &mut decl_code, p);
|
||||
code.extend(decl_code.into_iter());
|
||||
@@ -728,7 +770,7 @@ impl ListingCompiler {
|
||||
),
|
||||
);
|
||||
|
||||
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
|
||||
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
|
||||
}
|
||||
|
||||
fn process_decl(
|
||||
@@ -749,7 +791,7 @@ impl ListingCompiler {
|
||||
.code_repo
|
||||
.compile_hook(hook, flags)
|
||||
.map_err(SessionError::from);
|
||||
|
||||
|
||||
wam.code_repo.truncate_terms(key, len, queue_len);
|
||||
|
||||
result
|
||||
@@ -940,13 +982,16 @@ fn compile_work_impl(
|
||||
if let Some(ref mut module) = &mut compiler.module {
|
||||
// compile the module-level goal and term expansions and store
|
||||
// their locations to the module's code_dir.
|
||||
let decls = module.take_local_expansions();
|
||||
|
||||
let mut decls = module.take_local_expansions();
|
||||
|
||||
if !decls.is_empty() {
|
||||
append_trivial_goal(&clause_name!("term_expansion"), &mut decls[0].0);
|
||||
append_trivial_goal(&clause_name!("goal_expansion"), &mut decls[1].0);
|
||||
|
||||
results.worker_results.extend(decls.into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let module_code = compiler.generate_code(
|
||||
results.worker_results,
|
||||
wam,
|
||||
@@ -999,7 +1044,7 @@ fn compile_work_impl(
|
||||
|
||||
wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?;
|
||||
wam.indices.insert_module(module);
|
||||
} else {
|
||||
} else {
|
||||
add_module_code(wam, module, module_code, indices);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ impl MachineError {
|
||||
],
|
||||
SharedOpDesc::new(400, YFX)
|
||||
));
|
||||
|
||||
stub.append(&mut functor!(
|
||||
":",
|
||||
2,
|
||||
|
||||
@@ -211,6 +211,8 @@ pub enum IndexPtr {
|
||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||
Undefined,
|
||||
Index(usize),
|
||||
UserGoalExpansion,
|
||||
UserTermExpansion
|
||||
}
|
||||
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
@@ -234,7 +236,7 @@ impl CodeIndex {
|
||||
module_name
|
||||
))))
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn module_name(&self) -> ClauseName {
|
||||
self.0.borrow().1.clone()
|
||||
@@ -418,7 +420,7 @@ impl Add<usize> for CodePtr {
|
||||
| p @ CodePtr::VerifyAttrInterrupt(_)
|
||||
| p @ CodePtr::DynamicTransaction(..) => p,
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::CallN(_, local, _) | CodePtr::BuiltInClause(_, local) => {
|
||||
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
|
||||
CodePtr::Local(local + rhs)
|
||||
}
|
||||
}
|
||||
@@ -467,7 +469,7 @@ pub struct IndexStore {
|
||||
pub(super) op_dir: OpDir,
|
||||
}
|
||||
|
||||
impl IndexStore {
|
||||
impl IndexStore {
|
||||
pub fn predicate_exists(
|
||||
&self,
|
||||
name: ClauseName,
|
||||
@@ -491,6 +493,19 @@ impl IndexStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_term_and_goal_expansion_indices(&mut self) {
|
||||
self.code_dir.insert((clause_name!("term_expansion"), 2),
|
||||
CodeIndex(Rc::new(RefCell::new(
|
||||
(IndexPtr::UserTermExpansion,
|
||||
clause_name!("user"))
|
||||
))));
|
||||
self.code_dir.insert((clause_name!("goal_expansion"), 2),
|
||||
CodeIndex(Rc::new(RefCell::new(
|
||||
(IndexPtr::UserGoalExpansion,
|
||||
clause_name!("user"))
|
||||
))));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
|
||||
self.dynamic_code_dir.swap_remove(&(module, name, arity));
|
||||
|
||||
@@ -261,6 +261,7 @@ pub struct MachineState {
|
||||
pub(super) last_call: bool,
|
||||
pub(crate) heap_locs: HeapVarDict,
|
||||
pub(crate) flags: MachineFlags,
|
||||
pub(crate) at_end_of_expansion: bool
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
@@ -316,17 +317,17 @@ impl MachineState {
|
||||
Ok(codes)
|
||||
}
|
||||
|
||||
pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
|
||||
pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
|
||||
self.cp.assign_if_local(self.p.clone() + 1);
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = dir_entry!(p);
|
||||
self.p = CodePtr::Local(p);
|
||||
}
|
||||
|
||||
pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
|
||||
pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) {
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = dir_entry!(p);
|
||||
self.p = CodePtr::Local(p);
|
||||
}
|
||||
|
||||
pub(super) fn module_lookup(
|
||||
@@ -342,9 +343,9 @@ impl MachineState {
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
if last_call {
|
||||
self.execute_at_index(arity, compiled_tl_index);
|
||||
self.execute_at_index(arity, dir_entry!(compiled_tl_index));
|
||||
} else {
|
||||
self.call_at_index(arity, compiled_tl_index);
|
||||
self.call_at_index(arity, dir_entry!(compiled_tl_index));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
@@ -353,6 +354,24 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
return Ok(());
|
||||
}
|
||||
IndexPtr::UserTermExpansion => {
|
||||
if last_call {
|
||||
self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||
} else {
|
||||
self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
IndexPtr::UserGoalExpansion => {
|
||||
if last_call {
|
||||
self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||
} else {
|
||||
self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -390,9 +409,9 @@ fn try_in_situ(
|
||||
) -> CallResult {
|
||||
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
|
||||
if last_call {
|
||||
machine_st.execute_at_index(arity, p);
|
||||
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||
} else {
|
||||
machine_st.call_at_index(arity, p);
|
||||
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||
}
|
||||
|
||||
machine_st.p = in_situ_dir_entry!(p);
|
||||
@@ -421,7 +440,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||
|
||||
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.clone() + offset;
|
||||
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset;
|
||||
|
||||
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -467,7 +486,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||
|
||||
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.clone() + 1;
|
||||
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + 1;
|
||||
|
||||
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -504,7 +523,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
for i in 1 .. n + 1 {
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||
}
|
||||
|
||||
|
||||
machine_st.num_of_args = n;
|
||||
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||
@@ -583,7 +602,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
|
||||
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
|
||||
machine_st.truncate_stack();
|
||||
|
||||
|
||||
machine_st.hb = machine_st.heap.h;
|
||||
machine_st.p += 1;
|
||||
|
||||
@@ -619,7 +638,13 @@ pub(crate) trait CallPolicy: Any {
|
||||
IndexPtr::Undefined =>
|
||||
return try_in_situ(machine_st, name, arity, indices, false),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
machine_st.call_at_index(arity, compiled_tl_index)
|
||||
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index))
|
||||
}
|
||||
IndexPtr::UserTermExpansion => {
|
||||
machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||
}
|
||||
IndexPtr::UserGoalExpansion => {
|
||||
machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +665,13 @@ pub(crate) trait CallPolicy: Any {
|
||||
IndexPtr::Undefined =>
|
||||
return try_in_situ(machine_st, name, arity, indices, true),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
machine_st.execute_at_index(arity, compiled_tl_index)
|
||||
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
|
||||
}
|
||||
IndexPtr::UserTermExpansion => {
|
||||
machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||
}
|
||||
IndexPtr::UserGoalExpansion => {
|
||||
machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,19 +871,19 @@ pub(crate) trait CallPolicy: Any {
|
||||
) -> CallResult {
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
match ClauseType::from(name.clone(), arity, None) {
|
||||
ClauseType::BuiltIn(built_in) => {
|
||||
machine_st.setup_built_in_call(built_in.clone());
|
||||
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
|
||||
}
|
||||
ClauseType::CallN => {
|
||||
machine_st.handle_internal_call_n(arity);
|
||||
|
||||
if machine_st.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
|
||||
}
|
||||
ClauseType::BuiltIn(built_in) => {
|
||||
machine_st.setup_built_in_call(built_in.clone());
|
||||
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
|
||||
}
|
||||
ClauseType::Inlined(inlined) => {
|
||||
machine_st.execute_inlined(&inlined);
|
||||
|
||||
@@ -874,7 +905,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
||||
|
||||
return Err(machine_st
|
||||
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
|
||||
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1093,10 +1124,10 @@ impl SCCCutPolicy {
|
||||
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
|
||||
if machine_st.b < b_cutoff {
|
||||
let (idx, arity) = if machine_st.block < prev_block {
|
||||
(self.r_c_w_h, 0)
|
||||
(dir_entry!(self.r_c_w_h), 0)
|
||||
} else {
|
||||
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
|
||||
(self.r_c_wo_h, 1)
|
||||
(dir_entry!(self.r_c_wo_h), 1)
|
||||
};
|
||||
|
||||
if machine_st.last_call {
|
||||
|
||||
@@ -75,6 +75,7 @@ impl MachineState {
|
||||
last_call: false,
|
||||
heap_locs: HeapVarDict::new(),
|
||||
flags: MachineFlags::default(),
|
||||
at_end_of_expansion: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +106,7 @@ impl MachineState {
|
||||
last_call: false,
|
||||
heap_locs: HeapVarDict::new(),
|
||||
flags: MachineFlags::default(),
|
||||
at_end_of_expansion: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1988,6 +1990,19 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_ball(&mut self) {
|
||||
self.ball.reset();
|
||||
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
self.ball.boundary = self.heap.h;
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
|
||||
addr,
|
||||
AttrVarPolicy::DeepCopy,
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
|
||||
let arity = arity + 1;
|
||||
let pred = self.registers[1].clone();
|
||||
@@ -2004,19 +2019,6 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
}
|
||||
|
||||
pub(super) fn set_ball(&mut self) {
|
||||
self.ball.reset();
|
||||
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
self.ball.boundary = self.heap.h;
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
|
||||
addr,
|
||||
AttrVarPolicy::DeepCopy,
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
|
||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
||||
let addr = self.store(self.deref(self.registers[arity].clone()));
|
||||
@@ -2081,7 +2083,7 @@ impl MachineState {
|
||||
self.stack.truncate_to_frame(self.b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
||||
let mut seen = IndexSet::new();
|
||||
let mut fail = false;
|
||||
@@ -3105,7 +3107,7 @@ impl MachineState {
|
||||
|
||||
and_frame.prelude.e = self.e;
|
||||
and_frame.prelude.cp = self.cp;
|
||||
|
||||
|
||||
self.e = e;
|
||||
self.p += 1;
|
||||
}
|
||||
@@ -3113,7 +3115,7 @@ impl MachineState {
|
||||
pub(super) fn deallocate(&mut self) {
|
||||
let e = self.e;
|
||||
let frame = self.stack.index_and_frame(e);
|
||||
|
||||
|
||||
self.cp = frame.prelude.cp;
|
||||
self.e = frame.prelude.e;
|
||||
|
||||
@@ -3240,7 +3242,7 @@ impl MachineState {
|
||||
or_frame.prelude.e = self.e;
|
||||
or_frame.prelude.cp = self.cp;
|
||||
or_frame.prelude.b = self.b;
|
||||
or_frame.prelude.bp = self.p.clone() + 1;
|
||||
or_frame.prelude.bp = self.p.local() + 1;
|
||||
or_frame.prelude.tr = self.tr;
|
||||
or_frame.prelude.pstr_tr = self.pstr_tr;
|
||||
or_frame.prelude.h = self.heap.h;
|
||||
@@ -3279,7 +3281,7 @@ impl MachineState {
|
||||
or_frame.prelude.e = self.e;
|
||||
or_frame.prelude.cp = self.cp;
|
||||
or_frame.prelude.b = self.b;
|
||||
or_frame.prelude.bp = self.p.clone() + offset;
|
||||
or_frame.prelude.bp = self.p.local() + offset;
|
||||
or_frame.prelude.tr = self.tr;
|
||||
or_frame.prelude.pstr_tr = self.pstr_tr;
|
||||
or_frame.prelude.h = self.heap.h;
|
||||
|
||||
@@ -272,7 +272,8 @@ impl Machine {
|
||||
self.run_query();
|
||||
}
|
||||
|
||||
pub fn new(prolog_stream: PrologStream) -> Self {
|
||||
pub fn new(prolog_stream: PrologStream) -> Self
|
||||
{
|
||||
let mut wam = Machine {
|
||||
machine_st: MachineState::new(),
|
||||
inner_heap: Heap::with_capacity(256 * 256),
|
||||
@@ -285,6 +286,8 @@ impl Machine {
|
||||
|
||||
let atom_tbl = wam.indices.atom_tbl.clone();
|
||||
|
||||
wam.indices.add_term_and_goal_expansion_indices();
|
||||
|
||||
compile_listing(
|
||||
&mut wam,
|
||||
parsing_stream(BUILTINS.as_bytes()),
|
||||
@@ -739,7 +742,7 @@ impl MachineState {
|
||||
let b = self.b;
|
||||
|
||||
self.b0 = self.stack.index_or_frame(b).prelude.b0;
|
||||
self.p = self.stack.index_or_frame(b).prelude.bp.clone();
|
||||
self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
|
||||
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
|
||||
self.fail = p == 0;
|
||||
|
||||
@@ -108,17 +108,7 @@ impl Module {
|
||||
let goal_expansions =
|
||||
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
|
||||
|
||||
let mut result = vec![];
|
||||
|
||||
if !(term_expansions.0).0.is_empty() {
|
||||
result.push(term_expansions);
|
||||
}
|
||||
|
||||
if !(goal_expansions.0).0.is_empty() {
|
||||
result.push(goal_expansions);
|
||||
}
|
||||
|
||||
result
|
||||
vec![term_expansions, goal_expansions]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
381
src/prolog/machine/stack.rs
Normal file
381
src/prolog/machine/stack.rs
Normal file
@@ -0,0 +1,381 @@
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
|
||||
const STACK_ALIGN: usize = mem::align_of::<Addr>();
|
||||
const INIT_STACK_SIZE: usize = 10 * 1024 * 1024;
|
||||
|
||||
const fn prelude_size<Prelude>() -> usize {
|
||||
let size = mem::size_of::<Prelude>();
|
||||
let align = mem::align_of::<Addr>();
|
||||
|
||||
(size & !(align - 1)) + align
|
||||
}
|
||||
|
||||
pub struct Stack {
|
||||
size: usize,
|
||||
base: *const u8,
|
||||
top: *const u8,
|
||||
_marker: PhantomData<Addr>,
|
||||
}
|
||||
|
||||
impl Drop for Stack {
|
||||
fn drop(&mut self) {
|
||||
self.drop_in_place();
|
||||
self.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FramePrelude {
|
||||
is_or_frame: u8,
|
||||
pub num_cells: usize,
|
||||
}
|
||||
|
||||
pub struct AndFramePrelude {
|
||||
pub univ_prelude: FramePrelude,
|
||||
pub e: usize,
|
||||
pub cp: LocalCodePtr,
|
||||
pub interrupt_cp: LocalCodePtr,
|
||||
}
|
||||
|
||||
pub struct AndFrame {
|
||||
pub prelude: AndFramePrelude,
|
||||
_marker: PhantomData<Addr>,
|
||||
}
|
||||
|
||||
impl AndFrame {
|
||||
pub fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for AndFrame {
|
||||
type Output = Addr;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for AndFrame {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AndFrame {
|
||||
fn drop(&mut self) {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset;
|
||||
|
||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
||||
let index_offset = idx * mem::size_of::<Addr>();
|
||||
let ptr = (ptr + index_offset) as *mut Addr;
|
||||
|
||||
ptr::drop_in_place(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OrFramePrelude {
|
||||
pub univ_prelude: FramePrelude,
|
||||
pub e: usize,
|
||||
pub cp: LocalCodePtr,
|
||||
pub b: usize,
|
||||
pub bp: LocalCodePtr,
|
||||
pub tr: usize,
|
||||
pub pstr_tr: usize,
|
||||
pub h: usize,
|
||||
pub b0: usize,
|
||||
pub attr_var_init_queue_b: usize,
|
||||
pub attr_var_init_bindings_b: usize,
|
||||
}
|
||||
|
||||
pub struct OrFrame {
|
||||
pub prelude: OrFramePrelude,
|
||||
_marker: PhantomData<Addr>
|
||||
}
|
||||
|
||||
impl Index<usize> for OrFrame {
|
||||
type Output = Addr;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
let index_offset = index * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for OrFrame {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
let index_offset = index * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OrFrame {
|
||||
fn drop(&mut self) {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset;
|
||||
|
||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
||||
let index_offset = idx * mem::size_of::<Addr>();
|
||||
let ptr = (ptr + index_offset) as *mut Addr;
|
||||
|
||||
ptr::drop_in_place(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OrFrame {
|
||||
pub fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new() -> Self {
|
||||
let mut stack = Stack { size: 0, base: ptr::null(), top: ptr::null(),
|
||||
_marker: PhantomData };
|
||||
|
||||
unsafe { stack.grow(); }
|
||||
stack
|
||||
}
|
||||
|
||||
fn empty_stack() -> Self {
|
||||
Stack { size: 0, base: ptr::null(), top: ptr::null(),
|
||||
_marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Stack {
|
||||
mem::replace(self, Stack::empty_stack())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn free_space(&self) -> usize {
|
||||
debug_assert!(self.top >= self.base,
|
||||
"self.top = {:?} < {:?} = self.base",
|
||||
self.top, self.base);
|
||||
|
||||
self.size - (self.top as usize - self.base as usize)
|
||||
}
|
||||
|
||||
unsafe fn grow(&mut self) {
|
||||
if self.size == 0 {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(INIT_STACK_SIZE, STACK_ALIGN);
|
||||
|
||||
self.base = alloc::alloc(layout) as *const _;
|
||||
self.top = self.base as *const _;
|
||||
self.size = INIT_STACK_SIZE;
|
||||
|
||||
self.top = self.top.offset(mem::align_of::<Addr>() as isize);
|
||||
} else {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size, STACK_ALIGN);
|
||||
let top_dist = self.top as usize - self.base as usize;
|
||||
|
||||
self.base = alloc::realloc(self.base as *mut _, layout, self.size*2) as *const _;
|
||||
self.top = (self.base as usize + top_dist) as *const _;
|
||||
self.size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn new_frame_ptr(&mut self, frame_size: usize) -> *const u8 {
|
||||
loop {
|
||||
if self.free_space() >= frame_size {
|
||||
return (self.top as usize + frame_size) as *const _;
|
||||
} else {
|
||||
self.grow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
|
||||
let frame_size = AndFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let new_top = self.new_frame_ptr(frame_size);
|
||||
|
||||
for idx in 0 .. num_cells {
|
||||
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||
ptr::write((self.top as usize + offset) as *mut Addr, Addr::HeapCell(0));
|
||||
}
|
||||
|
||||
let and_frame = &mut *(self.top as *mut AndFrame);
|
||||
|
||||
and_frame.prelude.univ_prelude.is_or_frame = 0;
|
||||
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
let e = self.top as usize - self.base as usize;
|
||||
self.top = new_top;
|
||||
e
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
||||
let frame_size = OrFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let new_top = self.new_frame_ptr(frame_size);
|
||||
|
||||
for idx in 0 .. num_cells {
|
||||
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||
ptr::write((self.top as usize + offset) as *mut Addr, Addr::HeapCell(0));
|
||||
}
|
||||
|
||||
let or_frame = &mut *(self.top as *mut OrFrame);
|
||||
|
||||
or_frame.prelude.univ_prelude.is_or_frame = 1;
|
||||
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
let b = self.top as usize - self.base as usize;
|
||||
self.top = new_top;
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_and_frame(&self, e: usize) -> &AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.base as usize + e;
|
||||
&*(ptr as *const AndFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.base as usize + e;
|
||||
&mut *(ptr as *mut AndFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_or_frame(&self, b: usize) -> &OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.base as usize + b;
|
||||
&*(ptr as *const OrFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.base as usize + b;
|
||||
&mut *(ptr as *mut OrFrame)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size, STACK_ALIGN);
|
||||
alloc::dealloc(self.base as *mut u8, layout);
|
||||
|
||||
self.top = ptr::null();
|
||||
self.base = ptr::null();
|
||||
self.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn truncate_to_frame(&mut self, b: usize) {
|
||||
if b == 0 {
|
||||
self.truncate(mem::align_of::<Addr>());
|
||||
} else {
|
||||
let univ_prelude = self.index_or_frame(b).prelude.univ_prelude;
|
||||
let size = OrFrame::size_of(univ_prelude.num_cells);
|
||||
|
||||
self.truncate(b + size);
|
||||
}
|
||||
}
|
||||
|
||||
fn truncate(&mut self, b: usize) {
|
||||
let mut b = b + self.base as usize;
|
||||
let base = b;
|
||||
|
||||
unsafe {
|
||||
while b as *const _ < self.top {
|
||||
let univ_prelude = ptr::read(b as *const FramePrelude);
|
||||
|
||||
let offset = if univ_prelude.is_or_frame == 0 {
|
||||
let frame_ptr = b as *mut AndFrame;
|
||||
let frame = &mut *frame_ptr;
|
||||
let size_of_frame = AndFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
||||
|
||||
ptr::drop_in_place(frame_ptr);
|
||||
|
||||
b + size_of_frame
|
||||
} else {
|
||||
debug_assert!(univ_prelude.is_or_frame == 1);
|
||||
|
||||
let frame_ptr = b as *mut OrFrame;
|
||||
let frame = &mut *frame_ptr;
|
||||
let size_of_frame = OrFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
||||
|
||||
ptr::drop_in_place(frame_ptr);
|
||||
|
||||
b + size_of_frame
|
||||
};
|
||||
|
||||
b = offset;
|
||||
}
|
||||
|
||||
if base < self.top as usize {
|
||||
self.top = base as *const _;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_in_place(&mut self) {
|
||||
self.truncate(mem::align_of::<Addr>());
|
||||
|
||||
debug_assert!(if self.top.is_null() {
|
||||
self.top == self.base
|
||||
} else {
|
||||
self.top as usize == self.base as usize + mem::align_of::<Addr>()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -637,6 +637,11 @@ impl MachineState {
|
||||
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
||||
return Ok(());
|
||||
}
|
||||
&SystemClauseType::AtEndOfExpansion => {
|
||||
if self.cp == LocalCodePtr::TopLevel(0, 0) {
|
||||
self.at_end_of_expansion = true;
|
||||
}
|
||||
}
|
||||
&SystemClauseType::AtomChars => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
|
||||
@@ -772,9 +777,9 @@ impl MachineState {
|
||||
let p = self.attr_var_init.project_attrs_loc;
|
||||
|
||||
if self.last_call {
|
||||
self.execute_at_index(2, p);
|
||||
self.execute_at_index(2, dir_entry!(p));
|
||||
} else {
|
||||
self.call_at_index(2, p);
|
||||
self.call_at_index(2, dir_entry!(p));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
@@ -1010,7 +1015,10 @@ impl MachineState {
|
||||
|
||||
match subsection {
|
||||
Some(dynamic_predicate_info) => {
|
||||
self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p);
|
||||
self.execute_at_index(
|
||||
2,
|
||||
dir_entry!(dynamic_predicate_info.clauses_subsection_p)
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
None => self.fail = true,
|
||||
@@ -1628,6 +1636,16 @@ impl MachineState {
|
||||
}
|
||||
};
|
||||
}
|
||||
&SystemClauseType::ModuleExists => {
|
||||
let module = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match module {
|
||||
Addr::Con(Constant::Atom(ref name, _)) => {
|
||||
self.fail = !indices.modules.contains_key(name);
|
||||
}
|
||||
_ => unreachable!()
|
||||
};
|
||||
}
|
||||
&SystemClauseType::ModuleOf => {
|
||||
let module = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
@@ -1645,7 +1663,9 @@ impl MachineState {
|
||||
|
||||
self.unify(target, module);
|
||||
}
|
||||
_ => self.fail = true,
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
_ => self.fail = true,
|
||||
};
|
||||
@@ -1944,7 +1964,10 @@ impl MachineState {
|
||||
|
||||
match subsection {
|
||||
Some(dynamic_predicate_info) => {
|
||||
self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p);
|
||||
self.execute_at_index(
|
||||
2,
|
||||
dir_entry!(dynamic_predicate_info.clauses_subsection_p)
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -343,7 +343,7 @@ impl MachineState {
|
||||
// this prevents clashes between underscored variable names
|
||||
// in the same query.
|
||||
fn reset_with_heap_preservation(&mut self) {
|
||||
let heap = self.heap.take();
|
||||
let heap = self.heap.take();
|
||||
self.reset();
|
||||
self.heap = heap;
|
||||
}
|
||||
@@ -364,6 +364,9 @@ impl MachineState {
|
||||
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
||||
wam.code_repo.cached_query = code;
|
||||
|
||||
self.cp = LocalCodePtr::TopLevel(0, 0);
|
||||
self.at_end_of_expansion = false;
|
||||
|
||||
self.query_stepper(
|
||||
&mut wam.indices,
|
||||
&mut wam.policies,
|
||||
@@ -371,8 +374,8 @@ impl MachineState {
|
||||
&mut readline::input_stream(),
|
||||
);
|
||||
|
||||
if self.fail {
|
||||
self.reset_with_heap_preservation();
|
||||
if self.fail || self.at_end_of_expansion {
|
||||
self.reset_with_heap_preservation();
|
||||
None
|
||||
} else {
|
||||
let TermWriteResult { var_dict, .. } = term_write_result;
|
||||
@@ -380,7 +383,7 @@ impl MachineState {
|
||||
self.heap_locs = var_dict;
|
||||
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
||||
|
||||
self.reset_with_heap_preservation();
|
||||
self.reset_with_heap_preservation();
|
||||
Some(output.result())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,6 +678,26 @@ impl RelationWorker {
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
("\\+", 1) => {
|
||||
terms.push(Box::new(Term::Constant(
|
||||
Cell::default(),
|
||||
Constant::Atom(clause_name!("$fail"), None)
|
||||
)));
|
||||
|
||||
let conq = Term::Constant(
|
||||
Cell::default(),
|
||||
Constant::Atom(clause_name!("true"), None)
|
||||
);
|
||||
|
||||
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
|
||||
let terms = vec![Box::new(prec), Box::new(conq)];
|
||||
|
||||
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
|
||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
("$get_level", 1) => {
|
||||
if let Term::Var(_, ref var) = *terms[0] {
|
||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
||||
@@ -693,7 +713,7 @@ impl RelationWorker {
|
||||
let ct = indices.get_clause_type(name, terms.len(), fixity);
|
||||
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
|
||||
}
|
||||
},
|
||||
}
|
||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::CallN,
|
||||
|
||||
Reference in New Issue
Block a user