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