revert arithmetic code
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
use prolog_parser::ast::*;
|
use prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::allocator::Allocator;
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::prolog::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
@@ -70,7 +69,7 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
pub enum ArithTermRef<'a> {
|
pub enum ArithTermRef<'a> {
|
||||||
Constant(&'a Constant),
|
Constant(&'a Constant),
|
||||||
Op(ClauseName, usize), // name, arity.
|
Op(ClauseName, usize), // name, arity.
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
Var(&'a Cell<VarReg>, Rc<Var>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||||
@@ -97,8 +96,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))),
|
TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))),
|
||||||
TermIterState::Var(lvl, cell, var) => {
|
TermIterState::Var(_, cell, var) => {
|
||||||
return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone())))
|
return Some(Ok(ArithTermRef::Var(cell, var.clone())))
|
||||||
}
|
}
|
||||||
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
|
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
|
||||||
};
|
};
|
||||||
@@ -108,10 +107,10 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArithmeticEvaluator {
|
pub struct ArithmeticEvaluator<'a> {
|
||||||
|
bindings: &'a AllocVarDict,
|
||||||
interm: Vec<ArithmeticTerm>,
|
interm: Vec<ArithmeticTerm>,
|
||||||
interm_c: usize,
|
interm_c: usize,
|
||||||
arg_c: usize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ArithmeticTermIter<'a> {
|
pub trait ArithmeticTermIter<'a> {
|
||||||
@@ -128,12 +127,12 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArithmeticEvaluator {
|
impl<'a> ArithmeticEvaluator<'a> {
|
||||||
pub fn new(target_int: usize, arg_c: usize) -> Self {
|
pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
|
||||||
ArithmeticEvaluator {
|
ArithmeticEvaluator {
|
||||||
|
bindings,
|
||||||
interm: Vec::new(),
|
interm: Vec::new(),
|
||||||
interm_c: target_int,
|
interm_c: target_int,
|
||||||
arg_c
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,33 +283,27 @@ impl ArithmeticEvaluator {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval<'a, Iter, TermMarker>(
|
pub fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
|
||||||
&mut self,
|
|
||||||
marker: &mut TermMarker,
|
|
||||||
src: Iter,
|
|
||||||
term_loc: GenContext,
|
|
||||||
) -> Result<ArithCont, ArithmeticError>
|
|
||||||
where
|
where
|
||||||
Iter: ArithmeticTermIter<'a>,
|
Iter: ArithmeticTermIter<'a>,
|
||||||
TermMarker: Allocator<'a>
|
|
||||||
{
|
{
|
||||||
let mut code = vec![];
|
let mut code = vec![];
|
||||||
|
|
||||||
for term_ref in src.iter()? {
|
for term_ref in src.iter()? {
|
||||||
match term_ref? {
|
match term_ref? {
|
||||||
ArithTermRef::Constant(c) => self.push_constant(c)?,
|
ArithTermRef::Constant(c) => self.push_constant(c)?,
|
||||||
ArithTermRef::Var(lvl, cell, name) => {
|
ArithTermRef::Var(cell, name) => {
|
||||||
match marker.bindings().get(&name) {
|
let r = if cell.get().norm().reg_num() == 0 {
|
||||||
Some(&VarData::Temp(_, t, _)) if t != 0 => {},
|
match self.bindings.get(&name) {
|
||||||
Some(&VarData::Perm(p)) if p != 0 => {},
|
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
|
||||||
_ => return Err(ArithmeticError::UninstantiatedVar),
|
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
|
||||||
}
|
_ => return Err(ArithmeticError::UninstantiatedVar),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cell.get().norm()
|
||||||
|
};
|
||||||
|
|
||||||
let mut target = vec![];
|
self.interm.push(ArithmeticTerm::Reg(r));
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
ArithTermRef::Op(name, arity) => {
|
ArithTermRef::Op(name, arity) => {
|
||||||
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
|
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
|
||||||
@@ -318,22 +311,8 @@ impl ArithmeticEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let GenContext::Last(_) = term_loc {
|
|
||||||
self.tempify_perm_reg();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((code, self.interm.pop()))
|
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.
|
// integer division rounding function -- 9.1.3.1.
|
||||||
|
|||||||
@@ -360,10 +360,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
|
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)?;
|
||||||
|
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 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)?;
|
|
||||||
|
|
||||||
code.append(&mut lcode);
|
code.append(&mut lcode);
|
||||||
code.append(&mut rcode);
|
code.append(&mut rcode);
|
||||||
@@ -498,14 +496,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call_arith_eval(
|
fn call_arith_eval(
|
||||||
&mut self,
|
&self,
|
||||||
term: &'a Term,
|
term: &'a Term,
|
||||||
target_int: usize,
|
target_int: usize,
|
||||||
term_loc: GenContext,
|
|
||||||
arg_c: usize
|
|
||||||
) -> Result<ArithCont, ArithmeticError> {
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
let mut evaluator = ArithmeticEvaluator::new(target_int, arg_c);
|
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int);
|
||||||
evaluator.eval(&mut self.marker, term, term_loc)
|
evaluator.eval(term)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_is_call(
|
fn compile_is_call(
|
||||||
@@ -515,17 +511,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
use_default_call_policy: bool,
|
use_default_call_policy: bool,
|
||||||
) -> Result<(), ParserError> {
|
) -> 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() {
|
Ok(match terms[0].as_ref() {
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
let mut target = vec![];
|
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)?;
|
if !target.is_empty() {
|
||||||
code.extend(acode.into_iter());
|
code.extend(target.into_iter().map(Line::Query));
|
||||||
|
}
|
||||||
|
|
||||||
if use_default_call_policy {
|
if use_default_call_policy {
|
||||||
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
||||||
@@ -534,9 +533,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Integer(_)) => {
|
&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!(
|
code.push(Line::Query(put_constant!(
|
||||||
Level::Shallow,
|
Level::Shallow,
|
||||||
c.clone(),
|
c.clone(),
|
||||||
@@ -550,9 +546,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Float(_)) => {
|
&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!(
|
code.push(Line::Query(put_constant!(
|
||||||
Level::Shallow,
|
Level::Shallow,
|
||||||
c.clone(),
|
c.clone(),
|
||||||
@@ -566,9 +559,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Rational(_)) => {
|
&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!(
|
code.push(Line::Query(put_constant!(
|
||||||
Level::Shallow,
|
Level::Shallow,
|
||||||
c.clone(),
|
c.clone(),
|
||||||
@@ -584,7 +574,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
_ => code.push(fail!()),
|
_ => code.push(fail!()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell<VarReg>) {
|
fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell<VarReg>) {
|
||||||
let r = self.marker.get(Rc::new(String::from("!")));
|
let r = self.marker.get(Rc::new(String::from("!")));
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
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.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 old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
@@ -467,7 +467,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
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.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 old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
|
|||||||
@@ -2081,7 +2081,7 @@ impl MachineState {
|
|||||||
self.stack.truncate_to_frame(self.b);
|
self.stack.truncate_to_frame(self.b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
||||||
let mut seen = IndexSet::new();
|
let mut seen = IndexSet::new();
|
||||||
let mut fail = false;
|
let mut fail = false;
|
||||||
@@ -3105,7 +3105,7 @@ impl MachineState {
|
|||||||
|
|
||||||
and_frame.prelude.e = self.e;
|
and_frame.prelude.e = self.e;
|
||||||
and_frame.prelude.cp = self.cp;
|
and_frame.prelude.cp = self.cp;
|
||||||
|
|
||||||
self.e = e;
|
self.e = e;
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
@@ -3113,7 +3113,7 @@ impl MachineState {
|
|||||||
pub(super) fn deallocate(&mut self) {
|
pub(super) fn deallocate(&mut self) {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
let frame = self.stack.index_and_frame(e);
|
let frame = self.stack.index_and_frame(e);
|
||||||
|
|
||||||
self.cp = frame.prelude.cp;
|
self.cp = frame.prelude.cp;
|
||||||
self.e = frame.prelude.e;
|
self.e = frame.prelude.e;
|
||||||
|
|
||||||
@@ -3240,7 +3240,7 @@ impl MachineState {
|
|||||||
or_frame.prelude.e = self.e;
|
or_frame.prelude.e = self.e;
|
||||||
or_frame.prelude.cp = self.cp;
|
or_frame.prelude.cp = self.cp;
|
||||||
or_frame.prelude.b = self.b;
|
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.tr = self.tr;
|
||||||
or_frame.prelude.pstr_tr = self.pstr_tr;
|
or_frame.prelude.pstr_tr = self.pstr_tr;
|
||||||
or_frame.prelude.h = self.heap.h;
|
or_frame.prelude.h = self.heap.h;
|
||||||
@@ -3279,7 +3279,7 @@ impl MachineState {
|
|||||||
or_frame.prelude.e = self.e;
|
or_frame.prelude.e = self.e;
|
||||||
or_frame.prelude.cp = self.cp;
|
or_frame.prelude.cp = self.cp;
|
||||||
or_frame.prelude.b = self.b;
|
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.tr = self.tr;
|
||||||
or_frame.prelude.pstr_tr = self.pstr_tr;
|
or_frame.prelude.pstr_tr = self.pstr_tr;
|
||||||
or_frame.prelude.h = self.heap.h;
|
or_frame.prelude.h = self.heap.h;
|
||||||
|
|||||||
@@ -739,7 +739,7 @@ impl MachineState {
|
|||||||
let b = self.b;
|
let b = self.b;
|
||||||
|
|
||||||
self.b0 = self.stack.index_or_frame(b).prelude.b0;
|
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 {
|
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
|
||||||
self.fail = p == 0;
|
self.fail = p == 0;
|
||||||
|
|||||||
387
src/prolog/machine/stack.rs
Normal file
387
src/prolog/machine/stack.rs
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
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>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user