use prolog_parser::ast::*;
-use crate::prolog::allocator::Allocator;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
pub enum ArithTermRef<'a> {
Constant(&'a Constant),
Op(ClauseName, usize), // name, arity.
- Var(Level, &'a Cell<VarReg>, Rc<Var>),
+ Var(&'a Cell<VarReg>, Rc<Var>),
}
impl<'a> Iterator for ArithInstructionIterator<'a> {
}
}
TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))),
- TermIterState::Var(lvl, cell, var) => {
- return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone())))
+ TermIterState::Var(_, cell, var) => {
+ return Some(Ok(ArithTermRef::Var(cell, var.clone())))
}
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
};
}
}
-pub struct ArithmeticEvaluator {
+pub struct ArithmeticEvaluator<'a> {
+ bindings: &'a AllocVarDict,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
- arg_c: usize
}
pub trait ArithmeticTermIter<'a> {
}
}
-impl ArithmeticEvaluator {
- pub fn new(target_int: usize, arg_c: usize) -> Self {
+impl<'a> ArithmeticEvaluator<'a> {
+ pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
ArithmeticEvaluator {
+ bindings,
interm: Vec::new(),
interm_c: target_int,
- arg_c
}
}
Ok(())
}
- pub fn eval<'a, Iter, TermMarker>(
- &mut self,
- marker: &mut TermMarker,
- src: Iter,
- term_loc: GenContext,
- ) -> Result<ArithCont, ArithmeticError>
+ pub fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
where
Iter: ArithmeticTermIter<'a>,
- TermMarker: Allocator<'a>
{
let mut code = vec![];
for term_ref in src.iter()? {
match term_ref? {
ArithTermRef::Constant(c) => self.push_constant(c)?,
- ArithTermRef::Var(lvl, cell, name) => {
- match marker.bindings().get(&name) {
- Some(&VarData::Temp(_, t, _)) if t != 0 => {},
- Some(&VarData::Perm(p)) if p != 0 => {},
- _ => return Err(ArithmeticError::UninstantiatedVar),
- }
+ ArithTermRef::Var(cell, name) => {
+ let r = if cell.get().norm().reg_num() == 0 {
+ match self.bindings.get(&name) {
+ Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
+ Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
+ _ => return Err(ArithmeticError::UninstantiatedVar),
+ }
+ } else {
+ cell.get().norm()
+ };
- let mut target = vec![];
- marker.mark_var(name.clone(), lvl, cell, term_loc, &mut target);
- code.extend(target.into_iter().map(Line::Query));
-
- self.interm.push(ArithmeticTerm::Reg(cell.get().norm()));
+ self.interm.push(ArithmeticTerm::Reg(r));
}
ArithTermRef::Op(name, arity) => {
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
}
}
- if let GenContext::Last(_) = term_loc {
- self.tempify_perm_reg();
- }
-
Ok((code, self.interm.pop()))
}
-
- fn tempify_perm_reg(&mut self) {
- if let Some(interm) = self.interm.pop() {
- if let ArithmeticTerm::Reg(RegType::Perm(_)) = interm {
- self.interm.push(ArithmeticTerm::Reg(RegType::Temp(self.arg_c)));
- } else {
- self.interm.push(interm);
- }
- }
- }
}
// integer division rounding function -- 9.1.3.1.
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
}
- self.marker.reset_arg(2);
-
- let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1, term_loc, 1)?;
- let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2, term_loc, 2)?;
+ let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
+ let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
code.append(&mut lcode);
code.append(&mut rcode);
}
fn call_arith_eval(
- &mut self,
+ &self,
term: &'a Term,
target_int: usize,
- term_loc: GenContext,
- arg_c: usize
) -> Result<ArithCont, ArithmeticError> {
- let mut evaluator = ArithmeticEvaluator::new(target_int, arg_c);
- evaluator.eval(&mut self.marker, term, term_loc)
+ let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int);
+ evaluator.eval(term)
}
fn compile_is_call(
term_loc: GenContext,
use_default_call_policy: bool,
) -> Result<(), ParserError> {
- self.marker.reset_arg(2);
+ let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
+ code.append(&mut acode);
Ok(match terms[0].as_ref() {
&Term::Var(ref vr, ref name) => {
let mut target = vec![];
- self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
- code.extend(target.into_iter().map(Line::Query));
+ self.marker.reset_arg(2);
+ self.marker
+ .mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
- let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?;
- code.extend(acode.into_iter());
+ if !target.is_empty() {
+ code.extend(target.into_iter().map(Line::Query));
+ }
if use_default_call_policy {
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
}
}
&Term::Constant(_, ref c @ Constant::Integer(_)) => {
- let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?;
- code.extend(acode.into_iter());
-
code.push(Line::Query(put_constant!(
Level::Shallow,
c.clone(),
}
}
&Term::Constant(_, ref c @ Constant::Float(_)) => {
- let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?;
- code.extend(acode.into_iter());
-
code.push(Line::Query(put_constant!(
Level::Shallow,
c.clone(),
}
}
&Term::Constant(_, ref c @ Constant::Rational(_)) => {
- let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?;
- code.extend(acode.into_iter());
-
code.push(Line::Query(put_constant!(
Level::Shallow,
c.clone(),
_ => code.push(fail!()),
})
}
-
+
#[inline]
fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell<VarReg>) {
let r = self.marker.get(Rc::new(String::from("!")));
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;
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;
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;
and_frame.prelude.e = self.e;
and_frame.prelude.cp = self.cp;
-
+
self.e = e;
self.p += 1;
}
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;
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;
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;
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;
--- /dev/null
+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
+}
+
+/* The Stack is dropped manually at the discretion of the WAM, despite
+ having no Drop implementation. That's because it needs to know whether
+ the top frame is an AND frame or an OR frame. The WAM can
+ tell it. */
+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);
+ ptr::write(frame_ptr, mem::zeroed::<AndFrame>());
+
+ 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);
+ ptr::write(frame_ptr, mem::zeroed::<OrFrame>());
+
+ 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>()
+ });
+ }
+}