]> Repositorios git - scryer-prolog.git/commitdiff
handle machine heap/stack allocation error
authorSkgland <[email protected]>
Wed, 19 Nov 2025 21:08:42 +0000 (22:08 +0100)
committerBennet Bleßmann <[email protected]>
Wed, 19 Nov 2025 21:17:24 +0000 (22:17 +0100)
20 files changed:
src/arena.rs
src/atom_table.rs
src/functor_macro.rs
src/machine/attributed_variables.rs
src/machine/copier.rs
src/machine/dispatch.rs
src/machine/heap.rs
src/machine/lib_machine/mod.rs
src/machine/loader.rs
src/machine/machine_errors.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mock_wam.rs
src/machine/mod.rs
src/machine/stack.rs
src/machine/system_calls.rs
src/macros.rs
src/offset_table.rs
src/raw_block.rs
src/read.rs

index 09c5272856c86af0e7417d523b1f157d4a888ddb..c27ed5f46c1508ace4e5570a5fd2a27410a82b0a 100644 (file)
@@ -3,6 +3,7 @@
 
 #[cfg(feature = "http")]
 use crate::http::{HttpListener, HttpResponse};
+use crate::machine::heap::AllocError;
 use crate::machine::loader::LiveLoadState;
 use crate::machine::streams::*;
 use crate::offset_table::*;
@@ -486,12 +487,12 @@ unsafe impl Sync for Arena {}
 #[allow(clippy::new_without_default)]
 impl Arena {
     #[inline]
-    pub fn new() -> Self {
-        Arena {
+    pub fn new() -> Result<Self, AllocError> {
+        Ok(Arena {
             base: None,
-            f64_tbl: F64Table::new(),
-            code_index_tbl: CodeIndexTable::new(),
-        }
+            f64_tbl: F64Table::new()?,
+            code_index_tbl: CodeIndexTable::new()?,
+        })
     }
 }
 
index cb4e5230c638548b84fe93c3c22af0a7fe28ce02..d9e970db57dc8d567ed9739614ec7c426bb6ff1b 100644 (file)
@@ -1,6 +1,7 @@
 #![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
 #![allow(unused_parens)] // see mthom/scryer-prolog#3092 and rust-lang/rust#147126
 
+use crate::machine::heap::AllocError;
 use crate::parser::ast::MAX_ARITY;
 use crate::raw_block::*;
 use crate::types::*;
@@ -437,21 +438,21 @@ impl InnerAtomTable {
 
 impl AtomTable {
     #[inline]
-    pub fn new() -> Arc<Self> {
+    pub fn new() -> Result<Arc<Self>, AllocError> {
         let upgraded = global_atom_table().read().unwrap().upgrade();
         // don't inline upgraded, otherwise temporary will be dropped too late in case of None
         if let Some(atom_table) = upgraded {
-            atom_table
+            Ok(atom_table)
         } else {
             let mut guard = global_atom_table().write().unwrap();
             // try to upgrade again in case we lost the race on the write lock
             if let Some(atom_table) = guard.upgrade() {
-                atom_table
+                Ok(atom_table)
             } else {
                 let atom_table = Arc::new(Self {
                     inner: Arcu::new(
                         InnerAtomTable {
-                            block: RawBlock::new(),
+                            block: RawBlock::new()?,
                             table: Arcu::new(IndexSet::new(), GlobalEpochCounterPool),
                         },
                         GlobalEpochCounterPool,
@@ -459,11 +460,16 @@ impl AtomTable {
                     update: Mutex::new(()),
                 });
                 *guard = Arc::downgrade(&atom_table);
-                atom_table
+                Ok(atom_table)
             }
         }
     }
 
+    #[inline]
+    pub fn retrieve() -> Arc<Self> {
+        global_atom_table().read().unwrap().upgrade().unwrap()
+    }
+
     pub fn active_table(&self) -> RcuRef<IndexSet<Atom>, IndexSet<Atom>> {
         self.inner.read().table.read()
     }
index 88e5a5a2910248de1e3ddfcb86bf74c4b2d8d24f..82d6d98eab7dc9cfbb6e699d5f753fcfc70fc8dd 100644 (file)
@@ -551,7 +551,7 @@ mod tests {
 
     #[test]
     fn inlined_atoms() {
-        let atom_table = AtomTable::new();
+        let atom_table = AtomTable::new().unwrap();
         let inlined = AtomTable::build_with(&atom_table, "inline");
 
         assert!(inlined.is_inlined());
index 4aaf45ee815537de271aef670dcbc8a348f2140d..f1b5ba6c3f0b22c81c8b0e405763d396ceeb7954 100644 (file)
@@ -54,7 +54,9 @@ impl MachineState {
         self.attr_var_init.bindings.push((h, addr));
     }
 
-    fn populate_var_and_value_lists(&mut self) -> Result<(HeapCellValue, HeapCellValue), usize> {
+    fn populate_var_and_value_lists(
+        &mut self,
+    ) -> Result<(HeapCellValue, HeapCellValue), AllocError> {
         let size = self.attr_var_init.bindings.len();
 
         let iter = self
@@ -70,7 +72,7 @@ impl MachineState {
         Ok((var_list_addr, value_list_addr))
     }
 
-    fn verify_attributes(&mut self) -> Result<(), usize> {
+    fn verify_attributes(&mut self) -> Result<(), AllocError> {
         for (h, _) in &self.attr_var_init.bindings {
             self.heap[*h] = attr_var_as_cell!(*h);
         }
@@ -110,8 +112,12 @@ impl MachineState {
         attr_vars
     }
 
-    pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) -> Result<(), usize> {
-        self.allocate(arity + 3);
+    pub(super) fn verify_attr_interrupt(
+        &mut self,
+        p: usize,
+        arity: usize,
+    ) -> Result<(), AllocError> {
+        self.allocate(arity + 3)?;
 
         let e = self.e;
         let and_frame = self.stack.index_and_frame_mut(e);
index 965902df608cd1b21f1ea71768596326d7262c40..42359806fb442351224531673913ac87f33d96b2 100644 (file)
@@ -83,16 +83,16 @@ pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
     fn threshold(&self) -> usize;
     // returns the tail location of the pstr on success
     fn as_slice_from<'a>(&'a self, from: usize) -> Box<dyn Iterator<Item = u8> + 'a>;
-    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize>;
-    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize>;
-    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize>;
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, AllocError>;
+    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError>;
+    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), AllocError>;
 }
 
 pub(crate) fn copy_term<T: CopierTarget>(
     target: T,
     addr: HeapCellValue,
     attr_var_policy: AttrVarPolicy,
-) -> Result<usize, usize> {
+) -> Result<usize, AllocError> {
     let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
     let old_threshold = copy_term_state.target.threshold();
 
@@ -149,7 +149,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         self.trail.push((TrailRef::heap_cell(addr), trail_item));
     }
 
-    fn copy_list(&mut self, addr: usize) -> Result<(), usize> {
+    fn copy_list(&mut self, addr: usize) -> Result<(), AllocError> {
         for offset in 0..2 {
             read_heap_cell!(self.target[addr + offset],
                 (HeapCellValueTag::Lis, h) => {
@@ -194,7 +194,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> {
+    fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), AllocError> {
         match self.pstr_loc_locs.range_mut(..=pstr_loc).next_back() {
             Some((
                 _prev_pstr_loc,
@@ -281,7 +281,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_attr_var_lists(&mut self) -> Result<(), usize> {
+    fn copy_attr_var_lists(&mut self) -> Result<(), AllocError> {
         while !self.attr_var_list_locs.is_empty() {
             let mut list_loc_vec = std::mem::take(&mut self.attr_var_list_locs);
 
@@ -300,7 +300,7 @@ impl<T: CopierTarget> CopyTermState<T> {
      * structure which is ensured by this function and not at all by
      * the vanilla copier.
      */
-    fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) -> Result<(), usize> {
+    fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) -> Result<(), AllocError> {
         while let HeapCellValueTag::Lis = list_addr.get_tag() {
             let threshold = self.target.threshold();
             let heap_loc = list_addr.get_value() as usize;
@@ -330,7 +330,11 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) -> Result<(), usize> {
+    fn reinstantiate_var(
+        &mut self,
+        addr: HeapCellValue,
+        frontier: usize,
+    ) -> Result<(), AllocError> {
         read_heap_cell!(addr,
             (HeapCellValueTag::Var, h) => {
                 self.target[frontier] = heap_loc_as_cell!(frontier);
@@ -381,7 +385,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_var(&mut self, addr: HeapCellValue) -> Result<(), usize> {
+    fn copy_var(&mut self, addr: HeapCellValue) -> Result<(), AllocError> {
         let index = addr.get_value() as usize;
         let rd = self.target.deref(addr);
         let ra = self.target.store(rd);
@@ -421,7 +425,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_structure(&mut self, addr: usize) -> Result<(), usize> {
+    fn copy_structure(&mut self, addr: usize) -> Result<(), AllocError> {
         read_heap_cell!(self.target[addr],
             (HeapCellValueTag::Atom, (_name, arity)) => {
                 let threshold = self.target.threshold();
@@ -464,7 +468,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_term_impl(&mut self, addr: HeapCellValue) -> Result<(), usize> {
+    fn copy_term_impl(&mut self, addr: HeapCellValue) -> Result<(), AllocError> {
         self.scan = self.target.threshold();
         let mut writer = self.target.reserve(1)?;
 
@@ -503,7 +507,7 @@ impl<T: CopierTarget> CopyTermState<T> {
         Ok(())
     }
 
-    fn copy_pstrs(&mut self) -> Result<(), usize> {
+    fn copy_pstrs(&mut self) -> Result<(), AllocError> {
         while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() {
             let threshold = heap_index!(self.target.threshold());
 
index fc13d8258f1992092f2347533acecf2fa791267f..d593bedfad41f6774ddec46f1c81819982d1ecc2 100644 (file)
@@ -1051,7 +1051,10 @@ impl Machine {
                                                     });
 
                                                 self.machine_st.num_of_args += 1;
-                                                self.try_me_else(next_i);
+                                                backtrack_on_resource_error!(
+                                                    self.machine_st,
+                                                    self.try_me_else(next_i)
+                                                );
                                                 self.machine_st.num_of_args -= 1;
                                             }
                                             None => {
@@ -1130,7 +1133,10 @@ impl Machine {
                                                 );
 
                                                 self.machine_st.num_of_args += 1;
-                                                self.try_me_else(next_i);
+                                                backtrack_on_resource_error!(
+                                                    self.machine_st,
+                                                    self.try_me_else(next_i)
+                                                );
                                                 self.machine_st.num_of_args -= 1;
                                             }
                                             None => {
@@ -1183,7 +1189,7 @@ impl Machine {
                         }
                     }
                     &Instruction::TryMeElse(offset) => {
-                        self.try_me_else(offset);
+                        backtrack_on_resource_error!(self.machine_st, self.try_me_else(offset));
                     }
                     &Instruction::DefaultRetryMeElse(offset) => {
                         self.retry_me_else(offset);
@@ -1265,7 +1271,10 @@ impl Machine {
                         self.machine_st.p += 1;
                     }
                     &Instruction::Allocate(num_cells) => {
-                        self.machine_st.allocate(num_cells);
+                        backtrack_on_resource_error!(
+                            self.machine_st,
+                            self.machine_st.allocate(num_cells)
+                        );
                     }
                     &Instruction::DefaultCallAcyclicTerm => {
                         let addr = self.deref_register(1);
@@ -3155,7 +3164,10 @@ impl Machine {
                             IndexingLine::IndexedChoice(ref indexed_choice) => {
                                 match indexed_choice[self.machine_st.iip as usize] {
                                     IndexedChoiceInstruction::Try(offset) => {
-                                        self.indexed_try(offset);
+                                        backtrack_on_resource_error!(
+                                            self.machine_st,
+                                            self.indexed_try(offset)
+                                        );
                                     }
                                     IndexedChoiceInstruction::Retry(l) => {
                                         self.retry(l);
@@ -3208,7 +3220,10 @@ impl Machine {
                                                         );
 
                                                         self.machine_st.num_of_args += 1;
-                                                        self.indexed_try(offset);
+                                                        backtrack_on_resource_error!(
+                                                            self.machine_st,
+                                                            self.indexed_try(offset)
+                                                        );
                                                         self.machine_st.num_of_args -= 1;
                                                     }
                                                     None => {
index c6ca9871868e26887c3e1a63bdbd539405870d4a..964d983e90d38e7d6b67e823ac4c8a229fc3347c 100644 (file)
@@ -1,5 +1,6 @@
 use crate::atom_table::*;
 use crate::functor_macro::*;
+use crate::machine::machine_errors::CompilationError;
 use crate::machine::{ArenaHeaderTag, Fixnum, Integer};
 use crate::types::*;
 
@@ -11,6 +12,19 @@ use std::sync::Once;
 
 const ALIGN: usize = Heap::heap_cell_alignment();
 
+#[derive(Debug, Clone)]
+pub struct AllocError;
+
+impl AllocError {
+    pub(crate) fn to_compilation_error(&self, heap: &mut Heap) -> CompilationError {
+        CompilationError::FiniteMemoryInHeap(self.resource_error_offset(heap))
+    }
+
+    pub(crate) fn resource_error_offset(&self, heap: &mut Heap) -> usize {
+        heap.resource_error_offset()
+    }
+}
+
 #[derive(Debug)]
 pub struct Heap {
     inner: InnerHeap,
@@ -612,7 +626,7 @@ impl Heap {
         }
     }
 
-    pub fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize> {
+    pub fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError> {
         let section;
         let len = heap_index!(num_cells);
 
@@ -625,7 +639,7 @@ impl Heap {
                     };
                     break;
                 } else if !self.grow() {
-                    return Err(self.resource_error_offset());
+                    return Err(AllocError);
                 }
             }
         }
@@ -649,7 +663,7 @@ impl Heap {
         }
     }
 
-    pub(crate) fn append(&mut self, other_heap: &impl SizedHeap) -> Result<(), usize> {
+    pub(crate) fn append(&mut self, other_heap: &impl SizedHeap) -> Result<(), AllocError> {
         let other_len = heap_index!(other_heap.cell_len());
 
         loop {
@@ -665,7 +679,7 @@ impl Heap {
                 self.inner.byte_len += heap_index!(other_heap.cell_len());
                 break;
             } else if unsafe { !self.grow() } {
-                return Err(self.resource_error_offset());
+                return Err(AllocError);
             }
         }
 
@@ -742,10 +756,10 @@ impl Heap {
 
     // either succeed & return nothing or fail & return an offset into
     // the heap to a pre-allocated resource error
-    pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), usize> {
+    pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), AllocError> {
         unsafe {
             if self.inner.byte_len == self.inner.byte_cap && !self.grow() {
-                return Err(self.resource_error_offset());
+                return Err(AllocError);
             }
 
             // SAFETY:
@@ -779,7 +793,7 @@ impl Heap {
         Range { start, end }
     }
 
-    pub fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+    pub fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, AllocError> {
         let size_in_heap = Self::compute_pstr_size(src);
         let mut writer = self.reserve(size_in_heap)?;
         let HeapSectionWriteResult { result, .. } =
@@ -794,7 +808,7 @@ impl Heap {
     // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
     // unlike any version of allocate_pstr.
 
-    pub fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+    pub fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, AllocError> {
         let size_in_heap = Self::compute_pstr_size(src);
         let mut writer = self.reserve(size_in_heap + 1)?;
         let HeapSectionWriteResult { result, .. } =
@@ -849,7 +863,7 @@ impl Heap {
 
     // copies only the string, not its tail. returns the cell index of
     // the tail location
-    pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+    pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result<usize, AllocError> {
         let HeapStringScan { string, tail_idx } = self.scan_slice_to_str(pstr_loc);
         let s_len = string.len();
 
@@ -884,7 +898,7 @@ impl Heap {
 
                     break;
                 } else if !self.grow() {
-                    return Err(self.resource_error_offset());
+                    return Err(AllocError);
                 }
             }
         }
@@ -893,7 +907,10 @@ impl Heap {
     }
 
     // src is a cell-indexed range.
-    pub(crate) fn copy_slice_to_end<R: RangeBounds<usize>>(&mut self, src: R) -> Result<(), usize> {
+    pub(crate) fn copy_slice_to_end<R: RangeBounds<usize>>(
+        &mut self,
+        src: R,
+    ) -> Result<(), AllocError> {
         let range = self.slice_range(src);
         let len = range.end - range.start;
 
@@ -911,7 +928,7 @@ impl Heap {
 
                     break;
                 } else if !self.grow() {
-                    return Err(self.resource_error_offset());
+                    return Err(AllocError);
                 }
             }
         }
@@ -970,7 +987,7 @@ impl Heap {
 
     pub(crate) fn functor_writer(
         functor: Vec<FunctorElement>,
-    ) -> impl FnMut(&mut Heap) -> Result<HeapCellValue, usize> {
+    ) -> impl FnMut(&mut Heap) -> Result<HeapCellValue, AllocError> {
         let size = Heap::compute_functor_byte_size(&functor);
         let mut functor_writer = ReservedHeapSection::functor_writer(functor);
 
@@ -1133,7 +1150,7 @@ pub fn sized_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
     heap: &mut Heap,
     size: usize,
     values: impl Iterator<Item = SrcT>,
-) -> Result<HeapCellValue, usize> {
+) -> Result<HeapCellValue, AllocError> {
     if size > 0 {
         let h = heap.cell_len();
         let mut writer = heap.reserve(1 + 2 * size)?;
index 810c607dc87fa90c910cd5421afb16dbb58a088b..b4409aa5b741f48ba99144aca3fbb78af1f1d655 100644 (file)
@@ -4,6 +4,7 @@ use std::rc::Rc;
 
 use crate::atom_table;
 use crate::heap_iter::{stackful_post_order_iter, NonListElider};
+use crate::machine::heap::AllocError;
 use crate::machine::machine_indices::VarKey;
 use crate::machine::mock_wam::CompositeOpDir;
 use crate::machine::{
@@ -445,14 +446,15 @@ impl Iterator for QueryState<'_> {
             // contained in self.machine_st.ball.
             let h = machine.machine_st.heap.cell_len();
 
-            if let Err(resource_err_loc) = machine
+            if let Err(err) = machine
                 .machine_st
                 .heap
                 .append(&machine.machine_st.ball.stub)
             {
+                let resource_error_offset = err.resource_error_offset(&mut machine.machine_st.heap);
                 return Some(Err(Term::from_heapcell(
                     machine,
-                    machine.machine_st.heap[resource_err_loc],
+                    machine.machine_st.heap[resource_error_offset],
                     &mut IndexMap::new(),
                 )));
             }
@@ -553,11 +555,11 @@ impl Machine {
         self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
     }
 
-    pub(crate) fn allocate_stub_choice_point(&mut self) {
+    pub(crate) fn allocate_stub_choice_point(&mut self) -> Result<(), AllocError> {
         // NOTE: create a choice point to terminate the dispatch_loop
         // if an exception is thrown.
 
-        let stub_b = self.machine_st.stack.allocate_or_frame(0);
+        let stub_b = self.machine_st.stack.allocate_or_frame(0)?;
         let or_frame = self.machine_st.stack.index_or_frame_mut(stub_b);
 
         or_frame.prelude.num_cells = 0;
@@ -575,6 +577,8 @@ impl Machine {
         self.machine_st.b = stub_b;
         self.machine_st.hb = self.machine_st.heap.cell_len();
         self.machine_st.block = stub_b;
+
+        Ok(())
     }
 
     /// Runs a query.
@@ -588,7 +592,8 @@ impl Machine {
             .read_term(&op_dir, Tokens::Default)
             .expect("Failed to parse query");
 
-        self.allocate_stub_choice_point();
+        self.allocate_stub_choice_point()
+            .expect("failed to allocate stub choice point");
 
         // Write parsed term to heap
         let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
index fded231b0b97e8e2c6ad66d4f1fd5256ce228f9b..1ad46c88f5cce511c356ceed1ecc284a80aede96 100644 (file)
@@ -2359,8 +2359,8 @@ impl Machine {
 
                 let mut writer = match self.machine_st.heap.reserve(3 + meta_specs.len()) {
                     Ok(writer) => writer,
-                    Err(err_loc) => {
-                        self.machine_st.throw_resource_error(err_loc);
+                    Err(err) => {
+                        self.machine_st.throw_resource_error(err);
                         return;
                     }
                 };
index 9b56b4fb67acb7780ea469b1fdba6670de0ce3c6..4df767bf28e88a397af96891c7d8990ed7bc0f52 100644 (file)
@@ -6,6 +6,7 @@ use crate::parser::ast::*;
 use crate::ffi::{self, FfiError};
 use crate::forms::*;
 use crate::functor_macro::*;
+use crate::machine::heap::AllocError;
 use crate::machine::heap::*;
 use crate::machine::loader::CompilationTarget;
 use crate::machine::machine_state::*;
@@ -763,8 +764,8 @@ impl MachineState {
     }
 
     // throw an error pre-allocated in the heap
-    pub(super) fn throw_resource_error(&mut self, err_loc: usize) {
-        self.registers[1] = str_loc_as_cell!(err_loc);
+    pub(super) fn throw_resource_error(&mut self, err: AllocError) {
+        self.registers[1] = str_loc_as_cell!(err.resource_error_offset(&mut self.heap));
         self.set_ball();
         self.unwind_stack();
     }
@@ -777,8 +778,8 @@ impl MachineState {
 
         self.registers[1] = match writer(&mut self.heap) {
             Ok(loc) => loc,
-            Err(resource_err_loc) => {
-                self.throw_resource_error(resource_err_loc);
+            Err(err) => {
+                self.throw_resource_error(err);
                 return;
             }
         };
index ca88a6eab9ee29c23d8e1d35c11d7994e219329f..b915e3a12a2977d48b0483c51d0b217c01b55f5e 100644 (file)
@@ -5,6 +5,7 @@ use crate::heap_iter::*;
 use crate::heap_print::*;
 use crate::machine::attributed_variables::*;
 use crate::machine::copier::*;
+use crate::machine::heap::AllocError;
 use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
@@ -192,7 +193,7 @@ fn push_var_eq_functors<'a>(
     size: usize,
     iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
     atom_tbl: &AtomTable,
-) -> Result<HeapCellValue, usize> {
+) -> Result<HeapCellValue, AllocError> {
     let src_h = heap.cell_len();
 
     let true_size = if size > 0 {
@@ -257,7 +258,7 @@ impl Ball {
         self.stub.clear();
     }
 
-    pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result<usize, usize> {
+    pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result<usize, AllocError> {
         let h = dest.cell_len();
         let diff = self.boundary as i64 - h as i64;
 
@@ -346,17 +347,17 @@ impl<'a> CopierTarget for CopyTerm<'a> {
     }
 
     #[inline(always)]
-    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, AllocError> {
         self.state.heap.copy_pstr_within(pstr_loc)
     }
 
     #[inline(always)]
-    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize> {
+    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError> {
         self.state.heap.reserve(num_cells)
     }
 
     #[inline(always)]
-    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
+    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), AllocError> {
         self.state.heap.copy_slice_to_end(bounds)
     }
 }
@@ -455,7 +456,7 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
         self.stack
     }
 
-    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, AllocError> {
         debug_assert!(pstr_loc < self.heap.byte_len());
 
         let HeapStringScan { string, tail_idx } = self.heap.scan_slice_to_str(pstr_loc);
@@ -477,11 +478,11 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
     }
 
     #[inline]
-    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize> {
+    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError> {
         self.stub.reserve(num_cells)
     }
 
-    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
+    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), AllocError> {
         let len = bounds.end - bounds.start;
         let mut stub_writer = self.stub.reserve(len)?;
 
index 04fd143f4b5d62768b4253037020741452026949..a4de9f93d7a75e838932d0c5f6a2ad2079f489f0 100644 (file)
@@ -4,6 +4,7 @@ use crate::forms::*;
 use crate::heap_iter::*;
 use crate::machine::attributed_variables::*;
 use crate::machine::copier::*;
+use crate::machine::heap::AllocError;
 use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
@@ -30,8 +31,8 @@ impl MachineState {
         heap.store_resource_error();
 
         MachineState {
-            arena: Arena::new(),
-            atom_tbl: AtomTable::new(),
+            arena: Arena::new().unwrap(),
+            atom_tbl: AtomTable::new().unwrap(),
             pdl: Vec::with_capacity(1024),
             s: HeapPtr::default(),
             s_offset: 0,
@@ -47,7 +48,7 @@ impl MachineState {
             fail: false,
             heap,
             mode: MachineMode::Write,
-            stack: Stack::new(),
+            stack: Stack::new().unwrap(),
             registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used.
             trail: vec![],
             tr: 0,
@@ -174,8 +175,8 @@ impl MachineState {
         }
     }
 
-    pub fn allocate(&mut self, num_cells: usize) {
-        let e = self.stack.allocate_and_frame(num_cells);
+    pub fn allocate(&mut self, num_cells: usize) -> Result<(), AllocError> {
+        let e = self.stack.allocate_and_frame(num_cells)?;
         let and_frame = self.stack.index_and_frame_mut(e);
 
         and_frame.prelude.e = self.e;
@@ -183,6 +184,8 @@ impl MachineState {
 
         self.e = e;
         self.p += 1;
+
+        Ok(())
     }
 
     pub fn bind(&mut self, r1: Ref, a2: HeapCellValue) {
@@ -922,7 +925,7 @@ impl MachineState {
         name: Atom,
         arity: usize,
         r: Ref,
-    ) -> Result<(), usize> {
+    ) -> Result<(), AllocError> {
         let h = self.heap.cell_len();
         let mut writer = self.heap.reserve(arity + 1)?;
 
index df9dbe75644f92b90da3c19b8e958b8b496617f4..7fcc561307c1ca7218de9ba0cdbfb255dfa2c701 100644 (file)
@@ -168,7 +168,7 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
     }
 
     #[inline(always)]
-    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, AllocError> {
         self.wam.machine_st.heap.copy_pstr_within(pstr_loc)
     }
 
@@ -178,12 +178,12 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
     }
 
     #[inline(always)]
-    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize> {
+    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError> {
         self.wam.machine_st.heap.reserve(num_cells)
     }
 
     #[inline(always)]
-    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
+    fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), AllocError> {
         self.wam.machine_st.heap.copy_slice_to_end(bounds)
     }
 }
index db6dae7e82eb2a852bb610b5a7c9b88c780ab2ba..5f5819007f1d46717d78b642a5ed30991e5c75ae 100644 (file)
@@ -38,6 +38,7 @@ use crate::instructions::*;
 use crate::machine::args::*;
 use crate::machine::compile::*;
 use crate::machine::copier::*;
+use crate::machine::heap::AllocError;
 use crate::machine::heap::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
@@ -60,6 +61,7 @@ use std::cmp::Ordering;
 use std::env;
 use std::io::Read;
 use std::path::PathBuf;
+use std::process::ExitCode;
 use std::sync::atomic::AtomicBool;
 use std::sync::OnceLock;
 
@@ -261,7 +263,9 @@ impl Machine {
                 let p = index_ptr.local().unwrap();
 
                 // Leave a halting choice point to backtrack to in case the predicate fails or throws.
-                self.allocate_stub_choice_point();
+                if self.allocate_stub_choice_point().is_err() {
+                    return ExitCode::FAILURE;
+                }
 
                 self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC;
                 self.machine_st.p = p;
@@ -729,10 +733,10 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(super) fn try_me_else(&mut self, offset: usize) {
+    pub(super) fn try_me_else(&mut self, offset: usize) -> Result<(), AllocError> {
         if let Some(offset) = self.next_applicable_clause(offset) {
             let n = self.machine_st.num_of_args;
-            let b = self.machine_st.stack.allocate_or_frame(n);
+            let b = self.machine_st.stack.allocate_or_frame(n)?;
             let or_frame = self.machine_st.stack.index_or_frame_mut(b);
 
             or_frame.prelude.num_cells = n;
@@ -758,13 +762,15 @@ impl Machine {
         }
 
         self.machine_st.p += 1;
+
+        Ok(())
     }
 
     #[inline(always)]
-    pub(super) fn indexed_try(&mut self, offset: usize) {
+    pub(super) fn indexed_try(&mut self, offset: usize) -> Result<(), AllocError> {
         if let Some(iip_offset) = self.next_inner_applicable_clause() {
             let n = self.machine_st.num_of_args;
-            let b = self.machine_st.stack.allocate_or_frame(n);
+            let b = self.machine_st.stack.allocate_or_frame(n)?;
             let or_frame = self.machine_st.stack.index_or_frame_mut(b);
 
             or_frame.prelude.num_cells = n;
@@ -793,6 +799,7 @@ impl Machine {
         }
 
         self.machine_st.p += offset;
+        Ok(())
     }
 
     #[inline(always)]
index 4247149fa0c11b83f81d21a1df93758a36c7631e..98e1dab813dab664f67b42547209e4de34c424f5 100644 (file)
@@ -1,5 +1,7 @@
 use core::marker::PhantomData;
+use std::ptr::NonNull;
 
+use crate::machine::heap::AllocError;
 use crate::raw_block::*;
 use crate::types::*;
 
@@ -159,45 +161,42 @@ impl OrFrame {
 }
 
 impl Stack {
-    pub(crate) fn new() -> Self {
-        Stack {
-            buf: RawBlock::new(),
+    pub(crate) fn new() -> Result<Self, AllocError> {
+        Ok(Stack {
+            buf: RawBlock::new()?,
             _marker: PhantomData,
-        }
+        })
     }
 
     #[inline(always)]
-    unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
+    unsafe fn alloc(&mut self, frame_size: usize) -> Result<NonNull<u8>, AllocError> {
         loop {
             let ptr = self.buf.alloc(frame_size);
-
-            if ptr.is_null() {
-                if !self.buf.grow() {
-                    panic!("growing the stack failed")
-                }
-            } else {
-                return ptr;
+            if let Some(ptr) = NonNull::new(ptr) {
+                return Ok(ptr);
             }
+            self.buf.grow()?;
         }
     }
 
-    pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
+    pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> Result<usize, AllocError> {
         let frame_size = AndFrame::size_of(num_cells);
 
         unsafe {
             let e = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
-            let new_ptr = self.alloc(frame_size);
+            let new_ptr = self.alloc(frame_size)?;
             let mut offset = prelude_size::<AndFramePrelude>();
 
             for idx in 0..num_cells {
-                let cell_ptr = new_ptr.add(offset) as *mut HeapCellValue;
-                ptr::write(cell_ptr, stack_loc_as_cell!(AndFrame, e, idx + 1));
+                let cell_ptr = new_ptr.add(offset).cast::<HeapCellValue>();
+                ptr::write(cell_ptr.as_ptr(), stack_loc_as_cell!(AndFrame, e, idx + 1));
 
                 // Because in the Index and IndexMut inplementations we need to get this from
                 // exposed provenance, we need to expose the provenance here, even though we don't
                 // actually use the value for anything. This is a reminder that `expose_provenance`
                 // isn't just a cast from a pointer to an integer but has actual side effects.
-                cell_ptr.expose_provenance();
+                // FIXME(msrv) remove the as_ptr() call once MSRV reaches 1.89.0
+                cell_ptr.as_ptr().expose_provenance();
 
                 offset += mem::size_of::<HeapCellValue>();
             }
@@ -205,7 +204,7 @@ impl Stack {
             let and_frame = self.index_and_frame_mut(e);
             and_frame.prelude.num_cells = num_cells;
 
-            e
+            Ok(e)
         }
     }
 
@@ -213,23 +212,24 @@ impl Stack {
         unsafe { (*self.buf.ptr.get()).addr() - self.buf.base.addr() }
     }
 
-    pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
+    pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> Result<usize, AllocError> {
         let frame_size = OrFrame::size_of(num_cells);
 
         unsafe {
             let b = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
-            let new_ptr = self.alloc(frame_size);
+            let new_ptr = self.alloc(frame_size)?;
             let mut offset = prelude_size::<OrFramePrelude>();
 
             for idx in 0..num_cells {
-                let cell_ptr = new_ptr.byte_add(offset) as *mut HeapCellValue;
-                ptr::write(cell_ptr, stack_loc_as_cell!(OrFrame, b, idx));
+                let cell_ptr = new_ptr.byte_add(offset).cast::<HeapCellValue>();
+                ptr::write(cell_ptr.as_ptr(), stack_loc_as_cell!(OrFrame, b, idx));
 
                 // Because in the Index and IndexMut inplementations we need to get this from
                 // exposed provenance, we need to expose the provenance here, even though we don't
                 // actually use the value for anything. This is a reminder that `expose_provenance`
                 // isn't just a cast from a pointer to an integer but has actual side effects.
-                cell_ptr.expose_provenance();
+                // FIXME(msrv) remove as_ptr() call once msrv reaches 1.89.0
+                cell_ptr.as_ptr().expose_provenance();
 
                 offset += mem::size_of::<HeapCellValue>();
             }
@@ -237,7 +237,7 @@ impl Stack {
             let or_frame = self.index_or_frame_mut(b);
             or_frame.prelude.num_cells = num_cells;
 
-            b
+            Ok(b)
         }
     }
 
@@ -285,7 +285,7 @@ mod tests {
     fn stack_tests() {
         let mut wam = MockWAM::new();
 
-        let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame!
+        let e = wam.machine_st.stack.allocate_and_frame(10).unwrap(); // create an AND frame!
         let and_frame = wam.machine_st.stack.index_and_frame_mut(e);
 
         assert_eq!(
@@ -303,7 +303,7 @@ mod tests {
 
         assert_eq!(and_frame[5], empty_list_as_cell!());
 
-        let b = wam.machine_st.stack.allocate_or_frame(5);
+        let b = wam.machine_st.stack.allocate_or_frame(5).unwrap();
 
         let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
 
@@ -311,7 +311,7 @@ mod tests {
             assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
         }
 
-        let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
+        let next_e = wam.machine_st.stack.allocate_and_frame(9).unwrap(); // create an AND frame!
         let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
 
         for idx in 0..9 {
index 4e1797a981de80cd183296f84330e92620f889ef..8cc5f83b3bf750bac27eb65656828f0140115cd4 100644 (file)
@@ -17,6 +17,7 @@ use crate::instructions::*;
 use crate::machine;
 use crate::machine::code_walker::*;
 use crate::machine::copier::*;
+use crate::machine::heap::AllocError;
 use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
@@ -635,7 +636,7 @@ impl MachineState {
     pub(crate) fn get_attr_var_list(
         &mut self,
         attr_var: HeapCellValue,
-    ) -> Result<Option<usize>, usize> {
+    ) -> Result<Option<usize>, AllocError> {
         read_heap_cell!(attr_var,
             (HeapCellValueTag::AttrVar, h) => {
                 Ok(Some(h + 1))
@@ -903,7 +904,7 @@ impl MachineState {
         &mut self,
         lh_offset: usize,
         copy_target: HeapCellValue,
-    ) -> Result<FindallCopyInfo, usize> {
+    ) -> Result<FindallCopyInfo, AllocError> {
         let threshold = self.lifted_heap.cell_len() - lh_offset;
         let mut writer = self.lifted_heap.reserve(5)?;
 
@@ -1041,7 +1042,7 @@ impl MachineState {
         &mut self,
         chunk: HeapCellValue,
         return_p: usize,
-    ) -> usize {
+    ) -> Result<usize, AllocError> {
         let chunk = self.store(self.deref(chunk));
 
         let s = chunk.get_value() as usize;
@@ -1053,7 +1054,7 @@ impl MachineState {
         let cp = to_local_code_ptr(&self.heap, p_functor).unwrap();
         let prev_e = self.e;
 
-        let e = self.stack.allocate_and_frame(num_cells);
+        let e = self.stack.allocate_and_frame(num_cells)?;
         let and_frame = self.stack.index_and_frame_mut(e);
 
         and_frame.prelude.e = prev_e;
@@ -1084,7 +1085,7 @@ impl MachineState {
         }
 
         self.e = e;
-        self.p
+        Ok(self.p)
     }
 
     pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option<AtomOrString> {
@@ -2458,7 +2459,14 @@ impl Machine {
                 self.machine_st.p = return_p;
 
                 for chunk in cont_chunks.into_iter().rev() {
-                    return_p = self.machine_st.call_continuation_chunk(chunk, return_p);
+                    match self.machine_st.call_continuation_chunk(chunk, return_p) {
+                        Ok(ret_p) => {
+                            return_p = ret_p;
+                        }
+                        Err(err) => {
+                            self.machine_st.throw_resource_error(err);
+                        }
+                    }
                 }
 
                 Ok(())
@@ -4092,7 +4100,7 @@ impl Machine {
         fn write_op_functors_to_heap(
             heap: &mut Heap,
             op_descs: impl Iterator<Item = (Atom, OpDesc)>,
-        ) -> Result<usize, usize> {
+        ) -> Result<usize, AllocError> {
             let mut num_functors = 0;
 
             for (name, op_desc) in op_descs {
@@ -5130,7 +5138,11 @@ impl Machine {
     }
 
     #[cfg(feature = "ffi")]
-    fn build_struct(&mut self, name: Atom, mut args: Vec<Value>) -> Result<HeapCellValue, usize> {
+    fn build_struct(
+        &mut self,
+        name: Atom,
+        mut args: Vec<Value>,
+    ) -> Result<HeapCellValue, AllocError> {
         args.insert(0, Value::CString(CString::new(&*name.as_str()).unwrap()));
 
         let cells: Vec<_> = args
@@ -5150,7 +5162,7 @@ impl Machine {
                     Value::Struct(name, struct_args) => self.build_struct(name, struct_args)?,
                 })
             })
-            .collect::<Result<_, usize>>()?;
+            .collect::<Result<_, AllocError>>()?;
 
         sized_iter_to_heap_list(&mut self.machine_st.heap, cells.len(), cells.into_iter())
     }
@@ -7579,7 +7591,7 @@ impl Machine {
         false
     }
 
-    fn walk_code_at_ptr(&mut self, index_ptr: usize) -> Result<HeapCellValue, usize> {
+    fn walk_code_at_ptr(&mut self, index_ptr: usize) -> Result<HeapCellValue, AllocError> {
         let orig_h = self.machine_st.heap.cell_len();
         let mut h = orig_h;
 
@@ -8400,7 +8412,7 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(crate) fn load_html(&mut self) -> Result<(), usize> {
+    pub(crate) fn load_html(&mut self) -> Result<(), AllocError> {
         if let Some(string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
@@ -8429,7 +8441,7 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(crate) fn load_xml(&mut self) -> Result<(), usize> {
+    pub(crate) fn load_xml(&mut self) -> Result<(), AllocError> {
         if let Some(string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
@@ -8965,8 +8977,8 @@ impl Machine {
                         Ok(loc) => {
                             unify!(self.machine_st, status_r, loc);
                         }
-                        Err(resource_err_loc) => {
-                            self.machine_st.throw_resource_error(resource_err_loc);
+                        Err(err) => {
+                            self.machine_st.throw_resource_error(err);
                         }
                     }
                     Ok(())
@@ -8983,8 +8995,8 @@ impl Machine {
                                 Ok(loc) => {
                                     unify!(self.machine_st, status_r, loc);
                                 }
-                                Err(resource_err_loc) => {
-                                    self.machine_st.throw_resource_error(resource_err_loc);
+                                Err(err) => {
+                                    self.machine_st.throw_resource_error(err);
                                 }
                             }
                             Ok(())
@@ -9320,7 +9332,7 @@ impl Machine {
     pub(super) fn xml_node_to_term(
         &mut self,
         node: roxmltree::Node,
-    ) -> Result<HeapCellValue, usize> {
+    ) -> Result<HeapCellValue, AllocError> {
         if node.is_text() {
             self.machine_st.heap.allocate_cstr(node.text().unwrap())
         } else {
@@ -9371,7 +9383,7 @@ impl Machine {
     pub(super) fn html_node_to_term(
         &mut self,
         node: ego_tree::NodeRef<'_, scraper::Node>,
-    ) -> Result<HeapCellValue, usize> {
+    ) -> Result<HeapCellValue, AllocError> {
         match node.value() {
             scraper::Node::Document | scraper::Node::Fragment => {
                 unreachable!("we never iterate the root itself only its children")
@@ -9476,7 +9488,7 @@ impl Machine {
         }
     }
 
-    pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> Result<HeapCellValue, usize> {
+    pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> Result<HeapCellValue, AllocError> {
         let buffer = String::from_iter(data.iter().map(|b| *b as char));
 
         if buffer.is_empty() {
index 0bf7b6afc0d5b2e0fe20e0d9e3a89c2c398552f9..92e2179ea5c5b831115948f03122e3d4105d4a36 100644 (file)
@@ -451,8 +451,8 @@ macro_rules! step_or_resource_error {
     ($machine_st:expr, $val:expr) => {{
         match $val {
             Ok(r) => r,
-            Err(err_loc) => {
-                $machine_st.throw_resource_error(err_loc);
+            Err(err) => {
+                $machine_st.throw_resource_error(err);
                 return;
             }
         }
@@ -460,8 +460,8 @@ macro_rules! step_or_resource_error {
     ($machine_st:expr, $val:expr, $fail:block) => {{
         match $val {
             Ok(r) => r,
-            Err(err_loc) => {
-                $machine_st.throw_resource_error(err_loc);
+            Err(err) => {
+                $machine_st.throw_resource_error(err);
                 $fail
             }
         }
index 74967c6060f26e92c118b803d9c7d7553f7ef857..ec3f6031ed67952f10a74ba3918fd55d2d3c3d98 100644 (file)
@@ -10,6 +10,7 @@ use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 use parking_lot::{Mutex, RwLock};
 
+use crate::machine::heap::AllocError;
 use crate::machine::machine_indices::IndexPtr;
 use crate::raw_block::RawBlock;
 use crate::raw_block::RawBlockTraits;
@@ -58,8 +59,10 @@ impl<T: RawBlockTraits> From<Arc<ConcurrentOffsetTable<T>>> for OffsetTableImpl<
 
 impl<T: fmt::Debug + RawBlockTraits> OffsetTableImpl<T> {
     #[inline(always)]
-    pub fn new() -> Self {
-        Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new()))
+    pub fn new() -> Result<Self, AllocError> {
+        Ok(Self(
+            InnerOffsetTableImpl::Serial(SerialOffsetTable::new()?),
+        ))
     }
 
     #[must_use = "the returned concurrent table must be absorbed into the owned OffsetTable"]
@@ -116,7 +119,7 @@ impl<T: fmt::Debug + RawBlockTraits> OffsetTableImpl<T> {
 
 impl<T: fmt::Debug + RawBlockTraits> Default for OffsetTableImpl<T> {
     fn default() -> Self {
-        Self::new()
+        Self::new().unwrap()
     }
 }
 
@@ -201,10 +204,10 @@ impl OffsetTable<IndexPtr> for OffsetTableImpl<IndexPtr> {
 
 impl<T: RawBlockTraits> SerialOffsetTable<T> {
     #[inline]
-    fn new() -> Self {
-        Self {
-            block: RawBlock::new(),
-        }
+    fn new() -> Result<Self, AllocError> {
+        Ok(Self {
+            block: RawBlock::new()?,
+        })
     }
 
     unsafe fn build_with(&mut self, value: T) -> usize {
@@ -374,11 +377,11 @@ pub enum F64Table {
 }
 
 impl F64Table {
-    pub fn new() -> Self {
-        Self::Serial(SerialF64Table {
+    pub fn new() -> Result<Self, AllocError> {
+        Ok(Self::Serial(SerialF64Table {
             indirection_tbl: IndexMap::with_hasher(FxBuildHasher::new()),
-            offset_tbl: SerialOffsetTable::new(),
-        })
+            offset_tbl: SerialOffsetTable::new()?,
+        }))
     }
 
     pub fn build_with(&mut self, value: OrderedFloat<f64>) -> F64Offset {
index 02bea9f00a8dbf7f19dced56a0e8a82cd7b24a32..64346883a9e8f0d1a196b5cffa0ee2a0809f4312 100644 (file)
@@ -4,6 +4,8 @@ use std::alloc;
 use std::cell::UnsafeCell;
 use std::ptr;
 
+use crate::machine::heap::AllocError;
+
 pub trait RawBlockTraits {
     fn init_size() -> usize;
     fn align() -> usize;
@@ -29,65 +31,57 @@ impl<T: RawBlockTraits> RawBlock<T> {
     }
 
     #[allow(clippy::new_without_default)]
-    pub fn new() -> Self {
+    pub fn new() -> Result<Self, AllocError> {
         let mut block = Self::empty_block();
 
         unsafe {
-            block.grow();
+            block.grow()?;
         }
 
-        block
+        Ok(block)
     }
 
-    unsafe fn init_at_size(&mut self, cap: usize) {
+    unsafe fn init_at_size(&mut self, cap: usize) -> Result<(), AllocError> {
         let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
         let new_base = alloc::alloc(layout).cast_const();
         if new_base.is_null() {
-            panic!(
-                "failed to allocate in init_at_size for {}",
-                std::any::type_name::<Self>()
-            );
+            return Err(AllocError);
         }
         self.base = new_base;
         self.top = self.base.add(cap);
         *self.ptr.get_mut() = self.base.cast_mut();
+        Ok(())
     }
 
-    pub unsafe fn grow(&mut self) -> bool {
+    pub unsafe fn grow(&mut self) -> Result<(), AllocError> {
         if self.base.is_null() {
-            self.init_at_size(T::init_size());
-            true
+            self.init_at_size(T::init_size())
         } else {
             let size = self.size();
             let layout = alloc::Layout::from_size_align_unchecked(size, T::align());
 
             let new_base = alloc::realloc(self.base.cast_mut(), layout, size * 2).cast_const();
             if new_base.is_null() {
-                false
+                Err(AllocError)
             } else {
                 self.base = new_base;
                 self.top = self.base.add(size * 2);
                 *self.ptr.get_mut() = self.base.add(size).cast_mut();
-                true
+                Ok(())
             }
         }
     }
 
-    pub unsafe fn grow_new(&self) -> Option<Self> {
+    pub unsafe fn grow_new(&self) -> Result<Self, AllocError> {
         if self.base.is_null() {
-            Some(Self::new())
+            Self::new()
         } else {
             let mut new_block = Self::empty_block();
-            new_block.init_at_size(self.size() * 2);
-            if new_block.base.is_null() {
-                // allocation failed
-                None
-            } else {
-                let allocated = (*self.ptr.get()).addr() - self.base.addr();
-                self.base.copy_to(new_block.base.cast_mut(), allocated);
-                *new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut();
-                Some(new_block)
-            }
+            new_block.init_at_size(self.size() * 2)?;
+            let allocated = (*self.ptr.get()).addr() - self.base.addr();
+            self.base.copy_to(new_block.base.cast_mut(), allocated);
+            *new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut();
+            Ok(new_block)
         }
     }
 
index e9603522fed06351d702dd9d8f0935378b067e80..b8817aa6aca33283b9ac0a089f9c433b9fd2ab53 100644 (file)
@@ -381,7 +381,7 @@ impl<'a> TermWriter<'a> {
     fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> {
         self.heap
             .push_cell(cell)
-            .map_err(CompilationError::FiniteMemoryInHeap)
+            .map_err(|err| err.to_compilation_error(self.heap))
     }
 
     fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
@@ -478,7 +478,7 @@ impl<'a> TermWriter<'a> {
                     let cell = self
                         .heap
                         .allocate_cstr(src)
-                        .map_err(CompilationError::FiniteMemoryInHeap)?;
+                        .map_err(|err| err.to_compilation_error(self.heap))?;
 
                     let new_h = self.heap.cell_len();
                     self.push_cell(cell)?;
@@ -499,7 +499,7 @@ impl<'a> TermWriter<'a> {
                     let cell = self
                         .heap
                         .allocate_pstr(src)
-                        .map_err(CompilationError::FiniteMemoryInHeap)?;
+                        .map_err(|err| err.to_compilation_error(self.heap))?;
 
                     let tail_h = self.heap.cell_len();
                     self.push_stub_addr()?;