]> Repositorios git - scryer-prolog.git/commitdiff
revert arithmetic code
authorMark Thom <[email protected]>
Sun, 8 Dec 2019 07:17:55 +0000 (00:17 -0700)
committerMark Thom <[email protected]>
Sun, 8 Dec 2019 07:17:55 +0000 (00:17 -0700)
src/prolog/arithmetic.rs
src/prolog/codegen.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/machine/stack.rs [new file with mode: 0644]

index 1bd4d7c93c1dbd1318b88bd3b83e3594e596cc49..4c126d774d530b317a0e24e75015b9595f48ad0a 100644 (file)
@@ -1,6 +1,5 @@
 use prolog_parser::ast::*;
 
-use crate::prolog::allocator::Allocator;
 use crate::prolog::clause_types::*;
 use crate::prolog::fixtures::*;
 use crate::prolog::forms::*;
@@ -70,7 +69,7 @@ impl<'a> ArithInstructionIterator<'a> {
 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> {
@@ -97,8 +96,8 @@ 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))),
             };
@@ -108,10 +107,10 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
     }
 }
 
-pub struct ArithmeticEvaluator {
+pub struct ArithmeticEvaluator<'a> {
+    bindings: &'a AllocVarDict,
     interm: Vec<ArithmeticTerm>,
     interm_c: usize,
-    arg_c: usize
 }
 
 pub trait ArithmeticTermIter<'a> {
@@ -128,12 +127,12 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
     }
 }
 
-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
         }
     }
 
@@ -284,33 +283,27 @@ impl ArithmeticEvaluator {
         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)?));
@@ -318,22 +311,8 @@ impl ArithmeticEvaluator {
             }
         }
 
-        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.
index dacf055e920b65f67e4a375aa82253e527bf059a..0b5d6f63cc31a4ddbe1b18f2cc3a111610278bc6 100644 (file)
@@ -360,10 +360,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                     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);
@@ -498,14 +496,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
     }
 
     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(
@@ -515,17 +511,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         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))))
@@ -534,9 +533,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                 }
             }
             &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(),
@@ -550,9 +546,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                 }
             }
             &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(),
@@ -566,9 +559,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                 }
             }
             &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(),
@@ -584,7 +574,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
             _ => 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("!")));
index 1e3086d58cc367feeb0f02af13048e0725cd4dcb..6c6ec160efb32e239a8e44dc40eb0d4a99a95e46 100644 (file)
@@ -421,7 +421,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 +467,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;
index a23a43579d6fe4ba821001e4b0dee834796c7cd9..0af5e57881589b37ebe53d4f4e93480fdb37ae03 100644 (file)
@@ -2081,7 +2081,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 +3105,7 @@ impl MachineState {
 
         and_frame.prelude.e  = self.e;
         and_frame.prelude.cp = self.cp;
-        
+
         self.e = e;
         self.p += 1;
     }
@@ -3113,7 +3113,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 +3240,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 +3279,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;
index 97d69a2591b328b32192ddfb6223159dcbf4a898..5e613c7c828941651e1f4c9620e113e06a407249 100644 (file)
@@ -739,7 +739,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;
diff --git a/src/prolog/machine/stack.rs b/src/prolog/machine/stack.rs
new file mode 100644 (file)
index 0000000..12fce17
--- /dev/null
@@ -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>()
+        });
+    }
+}