#[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::*;
#[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()?,
+ })
}
}
#![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::*;
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,
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()
}
#[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());
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
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);
}
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);
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();
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) => {
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,
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);
* 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;
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);
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);
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();
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)?;
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());
});
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 => {
);
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 => {
}
}
&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);
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);
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);
);
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 => {
use crate::atom_table::*;
use crate::functor_macro::*;
+use crate::machine::machine_errors::CompilationError;
use crate::machine::{ArenaHeaderTag, Fixnum, Integer};
use crate::types::*;
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,
}
}
- 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);
};
break;
} else if !self.grow() {
- return Err(self.resource_error_offset());
+ return Err(AllocError);
}
}
}
}
}
- 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 {
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);
}
}
// 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:
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, .. } =
// 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, .. } =
// 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();
break;
} else if !self.grow() {
- return Err(self.resource_error_offset());
+ return Err(AllocError);
}
}
}
}
// 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;
break;
} else if !self.grow() {
- return Err(self.resource_error_offset());
+ return Err(AllocError);
}
}
}
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);
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)?;
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::{
// 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(),
)));
}
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;
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.
.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)
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;
}
};
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::*;
}
// 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();
}
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;
}
};
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::*;
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 {
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;
}
#[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)
}
}
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);
}
#[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)?;
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::*;
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,
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,
}
}
- 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;
self.e = e;
self.p += 1;
+
+ Ok(())
}
pub fn bind(&mut self, r1: Ref, a2: HeapCellValue) {
name: Atom,
arity: usize,
r: Ref,
- ) -> Result<(), usize> {
+ ) -> Result<(), AllocError> {
let h = self.heap.cell_len();
let mut writer = self.heap.reserve(arity + 1)?;
}
#[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)
}
}
#[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)
}
}
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::*;
use std::env;
use std::io::Read;
use std::path::PathBuf;
+use std::process::ExitCode;
use std::sync::atomic::AtomicBool;
use std::sync::OnceLock;
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;
}
#[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;
}
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;
}
self.machine_st.p += offset;
+ Ok(())
}
#[inline(always)]
use core::marker::PhantomData;
+use std::ptr::NonNull;
+use crate::machine::heap::AllocError;
use crate::raw_block::*;
use crate::types::*;
}
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>();
}
let and_frame = self.index_and_frame_mut(e);
and_frame.prelude.num_cells = num_cells;
- e
+ Ok(e)
}
}
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>();
}
let or_frame = self.index_or_frame_mut(b);
or_frame.prelude.num_cells = num_cells;
- b
+ Ok(b)
}
}
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!(
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);
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 {
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::*;
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))
&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)?;
&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;
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;
}
self.e = e;
- self.p
+ Ok(self.p)
}
pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option<AtomOrString> {
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(())
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 {
}
#[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
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())
}
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;
}
#[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])
}
#[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])
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(())
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(())
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 {
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")
}
}
- 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() {
($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;
}
}
($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
}
}
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;
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"]
impl<T: fmt::Debug + RawBlockTraits> Default for OffsetTableImpl<T> {
fn default() -> Self {
- Self::new()
+ Self::new().unwrap()
}
}
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 {
}
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 {
use std::cell::UnsafeCell;
use std::ptr;
+use crate::machine::heap::AllocError;
+
pub trait RawBlockTraits {
fn init_size() -> usize;
fn align() -> usize;
}
#[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)
}
}
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 {
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)?;
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()?;