From f9915a75eac532a746b208b0c652e2f07a2142ab Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Tue, 26 Nov 2024 19:18:39 -0600 Subject: [PATCH] Sword OOM round 2: PANIC! in alloc_would_oom_ (#286) * Revert "fix build error in assert_no_alloc (#284)" This reverts commit 14124d804e55b033b0b050af37e5a198ca71a0d4. * Revert "NockStack: explicitly catch OOM (#283)" This reverts commit bd27200ef387fe243615758aa0183efad4069fad. * Panic instead of Result for OOM * panic_any, don't use expect * Buh-bye to PMA + guard * fix tests --------- Co-authored-by: Chris Allen --- rust/assert_no_alloc/src/lib.rs | 1 - rust/ibig/src/add_ops.rs | 60 +- rust/ibig/src/buffer.rs | 33 +- rust/ibig/src/convert.rs | 37 +- rust/ibig/src/div_ops.rs | 76 +- rust/ibig/src/memory.rs | 13 +- rust/ibig/src/mul_ops.rs | 58 +- rust/sword/benches/cue_pill.rs | 4 +- rust/sword/src/flog.rs | 21 +- rust/sword/src/hamt.rs | 156 ++- rust/sword/src/interpreter.rs | 1413 +++++++++++++-------------- rust/sword/src/jets.rs | 173 +--- rust/sword/src/jets/bits.rs | 137 ++- rust/sword/src/jets/cold.rs | 503 +++++----- rust/sword/src/jets/form.rs | 29 +- rust/sword/src/jets/hash.rs | 14 +- rust/sword/src/jets/hot.rs | 24 +- rust/sword/src/jets/list.rs | 56 +- rust/sword/src/jets/lock/aes.rs | 203 ++-- rust/sword/src/jets/lock/ed.rs | 74 +- rust/sword/src/jets/lock/sha.rs | 176 ++-- rust/sword/src/jets/lute.rs | 56 +- rust/sword/src/jets/math.rs | 198 ++-- rust/sword/src/jets/nock.rs | 137 ++- rust/sword/src/jets/parse.rs | 137 ++- rust/sword/src/jets/serial.rs | 16 +- rust/sword/src/jets/sort.rs | 55 +- rust/sword/src/jets/tree.rs | 23 +- rust/sword/src/jets/warm.rs | 55 +- rust/sword/src/lib.rs | 15 +- rust/sword/src/mem.rs | 310 +++--- rust/sword/src/mug.rs | 101 +- rust/sword/src/newt.rs | 307 ------ rust/sword/src/noun.rs | 128 ++- rust/sword/src/serialization.rs | 335 ++++--- rust/sword/src/site.rs | 19 +- rust/sword/src/test_fns.rs | 11 - rust/sword/src/trace.rs | 10 +- rust/sword/src/unifying_equality.rs | 190 ++-- 39 files changed, 2350 insertions(+), 3014 deletions(-) delete mode 100644 rust/sword/src/newt.rs delete mode 100644 rust/sword/src/test_fns.rs diff --git a/rust/assert_no_alloc/src/lib.rs b/rust/assert_no_alloc/src/lib.rs index 66b8f63..4e9d5c7 100644 --- a/rust/assert_no_alloc/src/lib.rs +++ b/rust/assert_no_alloc/src/lib.rs @@ -173,7 +173,6 @@ pub struct AllocDisabler; #[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled impl AllocDisabler { - #[allow(unused_variables)] fn check(&self, layout: Layout) { let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get()); let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get()); diff --git a/rust/ibig/src/add_ops.rs b/rust/ibig/src/add_ops.rs index 012f5ee..f3ee87b 100644 --- a/rust/ibig/src/add_ops.rs +++ b/rust/ibig/src/add_ops.rs @@ -1,20 +1,16 @@ //! Addition and subtraction operators. -use crate::{ - add, - arch::word::Word, - buffer::Buffer, - helper_macros, - ibig::IBig, - memory::Stack, - primitive::{PrimitiveSigned, PrimitiveUnsigned}, - sign::Sign::*, - ubig::{Repr::*, UBig}, -}; -use core::{ - mem, - ops::{Add, AddAssign, Sub, SubAssign}, -}; +use crate::arch::word::Word; +use crate::buffer::Buffer; +use crate::ibig::IBig; +use crate::memory::Stack; +use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned}; +use crate::sign::Sign::*; +use crate::ubig::Repr::*; +use crate::ubig::UBig; +use crate::{add, helper_macros}; +use core::mem; +use core::ops::{Add, AddAssign, Sub, SubAssign}; impl Add for UBig { type Output = UBig; @@ -531,58 +527,58 @@ impl UBig { // given at least 2 words of extra capacity. However, this supports UBigs which have already // been expanded through other operations. #[inline] - pub fn add_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> Result { + pub fn add_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig { let ubig = match (lhs.into_repr(), rhs.into_repr()) { - (Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1)?, - (Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0)?, - (Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1)?, + (Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1), + (Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0), + (Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1), (Large(buffer0), Large(buffer1)) => { if buffer0.len() >= buffer1.len() { - UBig::add_large_stack(stack, buffer0, &buffer1)? + UBig::add_large_stack(stack, buffer0, &buffer1) } else { - UBig::add_large_stack(stack, buffer1, &buffer0)? + UBig::add_large_stack(stack, buffer1, &buffer0) } } }; - Ok(ubig) + ubig } /// Add two `Word`s. #[inline] - fn add_word_stack(stack: &mut S, a: Word, b: Word) -> Result { + fn add_word_stack(stack: &mut S, a: Word, b: Word) -> UBig { let (res, overflow) = a.overflowing_add(b); let ubig = if overflow { - let mut buffer = Buffer::allocate_stack(stack, 2)?; + let mut buffer = Buffer::allocate_stack(stack, 2); buffer.push(res); buffer.push(1); buffer.into() } else { UBig::from_word(res) }; - Ok(ubig) + ubig } /// Add a large number to a `Word`. - fn add_large_word_stack(stack: &mut S, mut buffer: Buffer, rhs: Word) -> Result { + fn add_large_word_stack(stack: &mut S, mut buffer: Buffer, rhs: Word) -> UBig { debug_assert!(buffer.len() >= 2); if add::add_word_in_place(&mut buffer, rhs) { - buffer.push_may_reallocate_stack(stack, 1)?; + buffer.push_may_reallocate_stack(stack, 1); } - Ok(buffer.into()) + buffer.into() } /// Add two large numbers. - fn add_large_stack(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> Result { + fn add_large_stack(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> UBig { let n = buffer.len().min(rhs.len()); let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]); if rhs.len() > n { - buffer.ensure_capacity_stack(stack, rhs.len())?; + buffer.ensure_capacity_stack(stack, rhs.len()); buffer.extend(&rhs[n..]); } if overflow && add::add_one_in_place(&mut buffer[n..]) { - buffer.push_may_reallocate_stack(stack, 1)?; + buffer.push_may_reallocate_stack(stack, 1); } - Ok(buffer.into()) + buffer.into() } /// Add two `Word`s. diff --git a/rust/ibig/src/buffer.rs b/rust/ibig/src/buffer.rs index 2db60bc..4825201 100644 --- a/rust/ibig/src/buffer.rs +++ b/rust/ibig/src/buffer.rs @@ -1,13 +1,14 @@ //! Word buffer. -use crate::{arch::word::Word, memory, memory::Stack, ubig::UBig}; +use crate::arch::word::Word; +use crate::memory; +use crate::memory::Stack; +use crate::ubig::UBig; use alloc::vec::Vec; -use core::{ - iter, - mem::ManuallyDrop, - ops::{Deref, DerefMut}, -}; +use core::iter; +use core::mem::ManuallyDrop; +use core::ops::{Deref, DerefMut}; /// Buffer for Words. /// @@ -21,14 +22,14 @@ use core::{ pub(crate) struct Buffer(ManuallyDrop>); impl Buffer { - pub(crate) fn allocate_stack(stack: &mut S, num_words: usize) -> Result { + pub(crate) fn allocate_stack(stack: &mut S, num_words: usize) -> Buffer { if num_words > Buffer::MAX_CAPACITY { UBig::panic_number_too_large(); } let capacity = Buffer::default_capacity(num_words); unsafe { - let ptr = stack.alloc_layout(memory::array_layout::(capacity))?; - Ok(Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))) + let ptr = stack.alloc_layout(memory::array_layout::(capacity)); + Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity))) } } @@ -44,11 +45,9 @@ impl Buffer { ))) } - pub(crate) fn ensure_capacity_stack(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> { + pub(crate) fn ensure_capacity_stack(&mut self, stack: &mut S, num_words: usize) { if num_words > self.capacity() { self.reallocate_stack(stack, num_words) - } else { - Ok(()) } } @@ -71,12 +70,11 @@ impl Buffer { // } } - fn reallocate_stack(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> { + fn reallocate_stack(&mut self, stack: &mut S, num_words: usize) { assert!(num_words >= self.len()); - let mut new_buffer = Buffer::allocate_stack(stack, num_words)?; + let mut new_buffer = Buffer::allocate_stack(stack, num_words); new_buffer.clone_from(self); *self = new_buffer; - Ok(()) } /// Change capacity to store `num_words` plus some extra space for future growth. @@ -109,10 +107,9 @@ impl Buffer { } #[inline] - pub(crate) fn push_may_reallocate_stack(&mut self, stack: &mut S, word: Word) -> Result<(), S::AllocError> { - self.ensure_capacity_stack(stack, self.len() + 1)?; + pub(crate) fn push_may_reallocate_stack(&mut self, stack: &mut S, word: Word) { + self.ensure_capacity_stack(stack, self.len() + 1); self.push(word); - Ok(()) } /// Append a Word and reallocate if necessary. diff --git a/rust/ibig/src/convert.rs b/rust/ibig/src/convert.rs index 66095b0..17aef86 100644 --- a/rust/ibig/src/convert.rs +++ b/rust/ibig/src/convert.rs @@ -1,15 +1,14 @@ //! Conversions between types. -use crate::{ - arch::word::Word, - buffer::Buffer, - error::OutOfBoundsError, - ibig::IBig, - memory::Stack, - primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES}, - sign::Sign::*, - ubig::{Repr::*, UBig}, -}; +use crate::arch::word::Word; +use crate::buffer::Buffer; +use crate::error::OutOfBoundsError; +use crate::ibig::IBig; +use crate::memory::Stack; +use crate::primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES}; +use crate::sign::Sign::*; +use crate::ubig::Repr::*; +use crate::ubig::UBig; use alloc::vec::Vec; use core::convert::{TryFrom, TryInto}; @@ -31,19 +30,19 @@ impl Default for IBig { impl UBig { #[inline] - pub fn from_le_bytes_stack(stack: &mut S, bytes: &[u8]) -> Result { + pub fn from_le_bytes_stack(stack: &mut S, bytes: &[u8]) -> UBig { let ubig = if bytes.len() <= WORD_BYTES { // fast path UBig::from_word(primitive::word_from_le_bytes_partial(bytes)) } else { - UBig::from_le_bytes_large_stack(stack, bytes)? + UBig::from_le_bytes_large_stack(stack, bytes) }; - Ok(ubig) + ubig } - fn from_le_bytes_large_stack(stack: &mut S, bytes: &[u8]) -> Result { + fn from_le_bytes_large_stack(stack: &mut S, bytes: &[u8]) -> UBig { debug_assert!(bytes.len() > WORD_BYTES); - let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1)?; + let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1); let mut chunks = bytes.chunks_exact(WORD_BYTES); for chunk in &mut chunks { buffer.push(Word::from_le_bytes(chunk.try_into().unwrap())); @@ -51,7 +50,7 @@ impl UBig { if !chunks.remainder().is_empty() { buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder())); } - Ok(buffer.into()) + buffer.into() } /// Construct from little-endian bytes. @@ -553,7 +552,7 @@ impl TryFrom<&IBig> for UBig { impl UBig { #[inline] - pub(crate) fn from_unsigned_stack(stack: &mut S, x: T) -> Result + pub(crate) fn from_unsigned_stack(stack: &mut S, x: T) -> UBig where T: PrimitiveUnsigned, { @@ -561,10 +560,10 @@ impl UBig { Ok(w) => UBig::from_word(w), Err(_) => { let repr = x.to_le_bytes(); - UBig::from_le_bytes_stack(stack, repr.as_ref())? + UBig::from_le_bytes_stack(stack, repr.as_ref()) } }; - Ok(ubig) + ubig } /// Convert an unsigned primitive to [UBig]. diff --git a/rust/ibig/src/div_ops.rs b/rust/ibig/src/div_ops.rs index 31aa121..6213c9a 100644 --- a/rust/ibig/src/div_ops.rs +++ b/rust/ibig/src/div_ops.rs @@ -1,23 +1,19 @@ //! Division operators. -use crate::{ - arch::word::Word, - buffer::Buffer, - div, helper_macros, - ibig::IBig, - memory::{MemoryAllocation, Stack}, - ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid}, - primitive::{PrimitiveSigned, PrimitiveUnsigned}, - shift, - sign::Sign::*, - ubig::{Repr::*, UBig}, -}; -use core::{ - convert::TryFrom, - fmt::Debug, - mem, - ops::{Div, DivAssign, Rem, RemAssign}, -}; +use crate::arch::word::Word; +use crate::buffer::Buffer; +use crate::ibig::IBig; +use crate::memory::{MemoryAllocation, Stack}; +use crate::ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid}; +use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned}; +use crate::sign::Sign::*; +use crate::ubig::Repr::*; +use crate::ubig::UBig; +use crate::{div, helper_macros, shift}; +use core::convert::TryFrom; +use core::fmt::Debug; +use core::mem; +use core::ops::{Div, DivAssign, Rem, RemAssign}; impl Div for UBig { type Output = UBig; @@ -1279,71 +1275,71 @@ impl_div_ibig_signed!(isize); impl UBig { #[inline] - pub fn div_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> Result { + pub fn div_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { (Small(word0), Small(word1)) => UBig::div_word(word0, word1), (Small(_), Large(_)) => UBig::from_word(0), (Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1), (Large(buffer0), Large(buffer1)) => { if buffer0.len() >= buffer1.len() { - UBig::div_large_stack(stack, buffer0, buffer1)? + UBig::div_large_stack(stack, buffer0, buffer1) } else { UBig::from_word(0) } } }; - Ok(ubig_tuple) + ubig_tuple } #[inline] - pub fn rem_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> Result { + pub fn rem_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { (Small(word0), Small(word1)) => UBig::rem_word(word0, word1), (Small(word0), Large(_)) => UBig::from_word(word0), (Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1), (Large(buffer0), Large(buffer1)) => { if buffer0.len() >= buffer1.len() { - UBig::rem_large_stack(stack, buffer0, buffer1)? + UBig::rem_large_stack(stack, buffer0, buffer1) } else { buffer0.into() } } }; - Ok(ubig_tuple) + ubig_tuple } #[inline] - pub fn div_rem_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<(UBig, UBig), S::AllocError> { + pub fn div_rem_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> (UBig, UBig) { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { (Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1), (Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)), (Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1), (Large(buffer0), Large(buffer1)) => { if buffer0.len() >= buffer1.len() { - UBig::div_rem_large_stack(stack, buffer0, buffer1)? + UBig::div_rem_large_stack(stack, buffer0, buffer1) } else { (UBig::from_word(0), buffer0.into()) } } }; - Ok(ubig_tuple) + ubig_tuple } /// `lhs / rhs` - fn div_large_stack(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result { - let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; + fn div_large_stack(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig { + let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs); lhs.erase_front(rhs.len()); - Ok(lhs.into()) + lhs.into() } /// `lhs % rhs` - fn rem_large_stack(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result { - let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; + fn rem_large_stack(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig { + let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs); let n = rhs.len(); rhs.copy_from_slice(&lhs[..n]); let low_bits = shift::shr_in_place(&mut rhs, shift); debug_assert!(low_bits == 0); - Ok(rhs.into()) + rhs.into() } /// `(lhs / rhs, lhs % rhs)` @@ -1351,33 +1347,33 @@ impl UBig { stack: &mut S, mut lhs: Buffer, mut rhs: Buffer, - ) -> Result<(UBig, UBig), S::AllocError> { - let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; + ) -> (UBig, UBig) { + let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs); let n = rhs.len(); rhs.copy_from_slice(&lhs[..n]); let low_bits = shift::shr_in_place(&mut rhs, shift); debug_assert!(low_bits == 0); lhs.erase_front(n); - Ok((lhs.into(), rhs.into())) + (lhs.into(), rhs.into()) } /// lhs = (lhs / rhs, lhs % rhs) /// /// Returns shift. - fn div_rem_in_lhs_stack(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> Result { + fn div_rem_in_lhs_stack(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> u32 { let (shift, fast_div_rhs_top) = div::normalize_large(rhs); let lhs_carry = shift::shl_in_place(lhs, shift); if lhs_carry != 0 { - lhs.push_may_reallocate_stack(stack, lhs_carry)?; + lhs.push_may_reallocate_stack(stack, lhs_carry); } let mut allocation = - MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()))?; + MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len())); let mut memory = allocation.memory(); let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory); if overflow { lhs.push_may_reallocate(1); } - Ok(shift) + shift } /// `lhs / rhs` diff --git a/rust/ibig/src/memory.rs b/rust/ibig/src/memory.rs index 4d01f7f..e054c0e 100644 --- a/rust/ibig/src/memory.rs +++ b/rust/ibig/src/memory.rs @@ -1,7 +1,8 @@ //! Memory allocation. use alloc::alloc::Layout; -use core::{marker::PhantomData, mem, slice}; +use core::marker::PhantomData; +use core::{mem, slice}; /// Chunk of memory directly allocated from the global allocator. pub(crate) struct MemoryAllocation { @@ -10,10 +11,8 @@ pub(crate) struct MemoryAllocation { } pub trait Stack: Sized { - // type AllocError: Debug; // no-std bites me in the keister again - type AllocError; - unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<*mut u64, Self::AllocError>; + unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64; } /// Chunk of memory. @@ -27,7 +26,7 @@ pub(crate) struct Memory<'a> { } impl MemoryAllocation { - pub(crate) fn new_stack(stack: &mut S, layout: Layout) -> Result { + pub(crate) fn new_stack(stack: &mut S, layout: Layout) -> MemoryAllocation { let start = if layout.size() == 0 { // We should use layout.dangling(), but that is unstable. layout.align() as *mut u8 @@ -36,7 +35,7 @@ impl MemoryAllocation { } else { // Safe because size is non-zero. let ptr = unsafe { - let ep = stack.alloc_layout(layout)?; + let ep = stack.alloc_layout(layout); ep as *mut u8 }; if ptr.is_null() { @@ -45,7 +44,7 @@ impl MemoryAllocation { ptr }; - Ok(MemoryAllocation { layout, start }) + MemoryAllocation { layout, start } } /// Allocate memory. diff --git a/rust/ibig/src/mul_ops.rs b/rust/ibig/src/mul_ops.rs index 0c36a23..c2e338d 100644 --- a/rust/ibig/src/mul_ops.rs +++ b/rust/ibig/src/mul_ops.rs @@ -1,20 +1,16 @@ //! Multiplication operators. -use crate::{ - arch::word::Word, - buffer::Buffer, - helper_macros, - ibig::IBig, - memory::{MemoryAllocation, Stack}, - mul, - primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned}, - sign::Sign::{self, *}, - ubig::{Repr::*, UBig}, -}; -use core::{ - mem, - ops::{Mul, MulAssign}, -}; +use crate::arch::word::Word; +use crate::buffer::Buffer; +use crate::ibig::IBig; +use crate::memory::{MemoryAllocation, Stack}; +use crate::primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned}; +use crate::sign::Sign::{self, *}; +use crate::ubig::Repr::*; +use crate::ubig::UBig; +use crate::{helper_macros, mul}; +use core::mem; +use core::ops::{Mul, MulAssign}; use static_assertions::const_assert; impl Mul for UBig { @@ -300,52 +296,52 @@ impl_mul_ibig_primitive!(isize); impl UBig { #[inline] - pub fn mul_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> Result { + pub fn mul_stack(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig { let res = match (lhs.into_repr(), rhs.into_repr()) { - (Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1)?, - (Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0)?, - (Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1)?, - (Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1)?, + (Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1), + (Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0), + (Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1), + (Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1), }; - Ok(res) + res } #[inline] - fn mul_word_stack(stack: &mut S, a: Word, b: Word) -> Result { + fn mul_word_stack(stack: &mut S, a: Word, b: Word) -> UBig { UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b)) } - fn mul_large_word_stack(stack: &mut S, mut buffer: Buffer, a: Word) -> Result { + fn mul_large_word_stack(stack: &mut S, mut buffer: Buffer, a: Word) -> UBig { match a { - 0 => Ok(UBig::from_word(0)), - 1 => Ok(buffer.into()), + 0 => UBig::from_word(0), + 1 => buffer.into(), _ => { let carry = mul::mul_word_in_place(&mut buffer, a); if carry != 0 { - buffer.push_may_reallocate_stack(stack, carry)?; + buffer.push_may_reallocate_stack(stack, carry); } - Ok(buffer.into()) + buffer.into() } } } - pub fn mul_large_stack(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> Result { + pub fn mul_large_stack(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> UBig { debug_assert!(lhs.len() >= 2 && rhs.len() >= 2); // This may be 1 too large. const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1); let res_len = lhs.len() + rhs.len(); - let mut buffer = Buffer::allocate_stack(stack, res_len)?; + let mut buffer = Buffer::allocate_stack(stack, res_len); buffer.push_zeros(res_len); let mut allocation = MemoryAllocation::new_stack( stack, mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())), - )?; + ); let mut memory = allocation.memory(); let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory); assert!(overflow == 0); - Ok(buffer.into()) + buffer.into() } /// Multiply two `Word`s. diff --git a/rust/sword/benches/cue_pill.rs b/rust/sword/benches/cue_pill.rs index 514a4b9..6553dc9 100644 --- a/rust/sword/benches/cue_pill.rs +++ b/rust/sword/benches/cue_pill.rs @@ -17,7 +17,7 @@ fn main() -> io::Result<()> { let jammed_input = unsafe { let in_map = memmap::Mmap::map(&f)?; let word_len = (in_len + 7) >> 3; - let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize).expect("Out of memory condition on IndirectAtom allocation in main()"); + let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize); write_bytes(dest.add(word_len as usize - 1), 0, 8); copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize); mem::drop(in_map); @@ -45,7 +45,7 @@ fn main() -> io::Result<()> { let nuw = SystemTime::now(); - let jammed_output = jam(&mut stack, input).expect("Out of memory condition on jam in main()"); + let jammed_output = jam(&mut stack, input); match nuw.elapsed() { Ok(elapse) => { diff --git a/rust/sword/src/flog.rs b/rust/sword/src/flog.rs index 479f3b1..893af6f 100644 --- a/rust/sword/src/flog.rs +++ b/rust/sword/src/flog.rs @@ -1,5 +1,5 @@ use crate::interpreter::Context; -use crate::mem::{AllocResult, NockStack}; +use crate::mem::NockStack; use crate::noun::{Atom, IndirectAtom}; use std::fmt::Arguments; use std::io::{Result, Write}; @@ -14,27 +14,26 @@ struct NockWriter<'s, 'b> { const INITIAL_CAPACITY_BYTES: usize = 256; impl<'s, 'b> NockWriter<'s, 'b> { - unsafe fn new(stack: &'s mut NockStack) -> AllocResult { - let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES)?; - Ok(NockWriter { + unsafe fn new(stack: &'s mut NockStack) -> Self { + let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES); + NockWriter { stack, buffer, indirect, cursor: 0, - }) + } } unsafe fn finalize(mut self) -> Atom { self.indirect.normalize_as_atom() } - unsafe fn expand(&mut self) -> AllocResult<()> { + unsafe fn expand(&mut self) { let sz = self.buffer.len(); - let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2)?; + let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2); new_buffer[0..sz].copy_from_slice(self.buffer); self.buffer = new_buffer; self.indirect = new_indirect; - Ok(()) } } @@ -42,7 +41,7 @@ impl Write for NockWriter<'_, '_> { fn write(&mut self, buf: &[u8]) -> Result { let sz = buf.len(); while (self.buffer.len() - self.cursor) < sz { - unsafe { self.expand()? }; + unsafe { self.expand() }; } self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf); self.cursor += sz; @@ -55,14 +54,14 @@ impl Write for NockWriter<'_, '_> { } pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result { - let mut nw = unsafe { NockWriter::new(&mut context.stack)? }; + let mut nw = unsafe { NockWriter::new(&mut context.stack) }; nw.write_fmt(fmt)?; Ok(unsafe { nw.finalize() }) } pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> { let cord = nock_fmt(context, fmt)?; - context.slogger.flog(&mut context.stack, cord.as_noun())?; + context.slogger.flog(&mut context.stack, cord.as_noun()); Ok(()) } diff --git a/rust/sword/src/hamt.rs b/rust/sword/src/hamt.rs index 29e593c..9231de4 100644 --- a/rust/sword/src/hamt.rs +++ b/rust/sword/src/hamt.rs @@ -1,4 +1,4 @@ -use crate::mem::{AllocResult, NockStack, Preserve}; +use crate::mem::{NockStack, Preserve}; use crate::mug::mug_u32; use crate::noun::Noun; use crate::unifying_equality::unifying_equality; @@ -59,45 +59,45 @@ impl MutStem { pub struct MutHamt(*mut MutStem); impl MutHamt { - pub fn new(stack: &mut NockStack) -> AllocResult> { + pub fn new(stack: &mut NockStack) -> MutHamt { unsafe { - let new_stem = stack.struct_alloc::>(1)?; + let new_stem = stack.struct_alloc::>(1); (*new_stem).bitmap = 0; (*new_stem).typemap = 0; - Ok(MutHamt(new_stem)) + MutHamt(new_stem) } } - pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> AllocResult> { + pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> Option { let mut stem = self.0; - let mut mug = mug_u32(stack, *n)?; + let mut mug = mug_u32(stack, *n); unsafe { 'lookup: loop { let chunk = mug & 0x1f; mug >>= 5; match (*stem).entry(chunk) { None => { - break Ok(None); + break None; } Some(Left(next_stem)) => { stem = next_stem; } Some(Right(leaf)) => { for pair in leaf.to_mut_slice().iter_mut() { - if unifying_equality(stack, n, &mut pair.0)? { - break 'lookup Ok(Some(pair.1)); + if unifying_equality(stack, n, &mut pair.0) { + break 'lookup Some(pair.1); } } - break Ok(None); + break None; } } } } } - pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> { + pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) { let mut stem = self.0; - let mut mug = mug_u32(stack, *n)?; + let mut mug = mug_u32(stack, *n); let mut depth = 0u8; unsafe { 'insert: loop { @@ -105,7 +105,7 @@ impl MutHamt { mug >>= 5; match (*stem).entry(chunk) { None => { - let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1)?; + let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1); *new_leaf_buffer = (*n, t); (*stem).bitmap |= chunk_to_bit(chunk); (*stem).typemap &= !chunk_to_bit(chunk); @@ -124,13 +124,13 @@ impl MutHamt { } Some(Right(leaf)) => { for pair in leaf.to_mut_slice().iter_mut() { - if unifying_equality(stack, n, &mut pair.0)? { + if unifying_equality(stack, n, &mut pair.0) { pair.1 = t; break 'insert; } } if depth >= 5 { - let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1)?; + let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); *new_leaf_buffer.add(leaf.len) = (*n, t); (*stem).buffer[chunk as usize] = MutEntry { @@ -142,8 +142,8 @@ impl MutHamt { break; } else { assert!(leaf.len == 1); - let new_stem = stack.struct_alloc::>(1)?; - let leaf_mug = mug_u32(stack, (*leaf.buffer).0)?; + let new_stem = stack.struct_alloc::>(1); + let leaf_mug = mug_u32(stack, (*leaf.buffer).0); let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f; (*new_stem).bitmap = chunk_to_bit(leaf_chunk); (*new_stem).typemap = 0; @@ -158,7 +158,6 @@ impl MutHamt { } } } - Ok(()) } } @@ -283,15 +282,15 @@ impl Hamt { unsafe { (*self.0).bitmap == 0 } } // Make a new, empty HAMT - pub fn new(stack: &mut NockStack) -> AllocResult { + pub fn new(stack: &mut NockStack) -> Self { unsafe { - let stem_ptr = stack.struct_alloc::>(1)?; + let stem_ptr = stack.struct_alloc::>(1); *stem_ptr = Stem { bitmap: 0, typemap: 0, buffer: null_mut(), }; - Ok(Hamt(stem_ptr)) + Hamt(stem_ptr) } } @@ -306,15 +305,15 @@ impl Hamt { * A mutable reference is required so that unifying equality can unify the key with a key entry * in the HAMT */ - pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> AllocResult> { + pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> Option { let mut stem = unsafe { *self.0 }; - let mut mug = mug_u32(stack, *n)?; + let mut mug = mug_u32(stack, *n); 'lookup: loop { let chunk = mug & 0x1F; // 5 bits mug >>= 5; match stem.entry(chunk) { None => { - break Ok(None); + break None; } Some((Left(next_stem), _idx)) => { stem = next_stem; @@ -322,11 +321,11 @@ impl Hamt { } Some((Right(leaf), _idx)) => { for pair in unsafe { leaf.to_mut_slice().iter_mut() } { - if unsafe { unifying_equality(stack, n, &mut pair.0)? } { - break 'lookup Ok(Some(pair.1)); + if unsafe { unifying_equality(stack, n, &mut pair.0) } { + break 'lookup Some(pair.1); } } - break Ok(None); + break None; } } } @@ -335,11 +334,11 @@ impl Hamt { // XX a delete function requires a stack, do we need one? /// Make a new HAMT with the value inserted or replaced at the key. - pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult> { - let mut mug = mug_u32(stack, *n)?; + pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> Hamt { + let mut mug = mug_u32(stack, *n); let mut depth = 0u8; let mut stem = unsafe { *self.0 }; - let stem_ret = unsafe { stack.struct_alloc::>(1) }?; + let stem_ret = unsafe { stack.struct_alloc::>(1) }; let mut dest = stem_ret; unsafe { 'insert: loop { @@ -348,10 +347,10 @@ impl Hamt { match stem.entry(chunk) { // No entry found at mug chunk index; add Leaf to current Stem None => { - let new_leaf_buffer = stack.struct_alloc(1)?; + let new_leaf_buffer = stack.struct_alloc(1); *new_leaf_buffer = (*n, t); let split = stem.hypothetical_index(chunk); - let new_buffer = stack.struct_alloc(stem.size() + 1)?; + let new_buffer = stack.struct_alloc(stem.size() + 1); if split > 0 { copy_nonoverlapping(stem.buffer, new_buffer, split); } @@ -373,11 +372,11 @@ impl Hamt { typemap: stem.typemap & !chunk_to_bit(chunk), buffer: new_buffer, }; - break Ok(Hamt(stem_ret)); + break Hamt(stem_ret); } // Stem found at mug chunk index; insert into found Stem Some((Left(next_stem), idx)) => { - let new_buffer = stack.struct_alloc(stem.size())?; + let new_buffer = stack.struct_alloc(stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); *dest = Stem { bitmap: stem.bitmap, @@ -393,11 +392,11 @@ impl Hamt { Some((Right(leaf), idx)) => { // Override existing value for key, if one exists for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() { - if unifying_equality(stack, n, &mut pair.0)? { - let new_leaf_buffer = stack.struct_alloc(leaf.len)?; + if unifying_equality(stack, n, &mut pair.0) { + let new_leaf_buffer = stack.struct_alloc(leaf.len); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); (*new_leaf_buffer.add(ldx)).1 = t; - let new_buffer = stack.struct_alloc(stem.size())?; + let new_buffer = stack.struct_alloc(stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); *new_buffer.add(idx) = Entry { leaf: Leaf { @@ -410,16 +409,16 @@ impl Hamt { typemap: stem.typemap, buffer: new_buffer, }; - break 'insert Ok(Hamt(stem_ret)); + break 'insert Hamt(stem_ret); } } // No existing pair in this Leaf matches the key, and we've maxxed out the // Hamt depth; add the the key-value pair to the list of pairs for this Leaf if depth >= 5 { - let new_leaf_buffer = stack.struct_alloc(leaf.len + 1)?; + let new_leaf_buffer = stack.struct_alloc(leaf.len + 1); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); *new_leaf_buffer.add(leaf.len) = (*n, t); - let new_buffer = stack.struct_alloc(stem.size())?; + let new_buffer = stack.struct_alloc(stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); *new_buffer.add(idx) = Entry { leaf: Leaf { @@ -432,7 +431,7 @@ impl Hamt { typemap: stem.typemap, buffer: new_buffer, }; - break 'insert Ok(Hamt(stem_ret)); + break 'insert Hamt(stem_ret); // No existing pair in this Leaf matches the key, but we haven't maxxed out // the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't // be making a linked list of pairs. Turn the Leaf into a Stem and insert @@ -442,18 +441,18 @@ impl Hamt { // Make a fake node pointing to the old leaf and "insert into it" the // next time around assert!(leaf.len == 1); - let fake_buffer = stack.struct_alloc(1)?; + let fake_buffer = stack.struct_alloc(1); *fake_buffer = Entry { leaf }; // Get the mug chunk for the Noun at the *next* level so that we can // build a fake stem for it - let fake_mug = mug_u32(stack, (*leaf.buffer).0)?; + let fake_mug = mug_u32(stack, (*leaf.buffer).0); let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F; let next_stem = Stem { bitmap: chunk_to_bit(fake_chunk), typemap: 0, buffer: fake_buffer, }; - let new_buffer = stack.struct_alloc(stem.size())?; + let new_buffer = stack.struct_alloc(stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); *dest = Stem { bitmap: stem.bitmap, @@ -518,13 +517,13 @@ impl Preserve for Hamt { } } - unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { - let res = if stack.is_in_frame(self.0) { - let dest_stem = stack.struct_alloc_in_previous_frame(1)?; + unsafe fn preserve(&mut self, stack: &mut NockStack) { + if stack.is_in_frame(self.0) { + let dest_stem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(self.0, dest_stem, 1); self.0 = dest_stem; if stack.is_in_frame((*dest_stem).buffer) { - let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size())?; + let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size()); copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size()); (*dest_stem).buffer = dest_buffer; // Here we're using the Rust stack since the array is a fixed @@ -557,7 +556,7 @@ impl Preserve for Hamt { Some((Left(next_stem), idx)) => { if stack.is_in_frame(next_stem.buffer) { let dest_buffer = - stack.struct_alloc_in_previous_frame(next_stem.size())?; + stack.struct_alloc_in_previous_frame(next_stem.size()); copy_nonoverlapping( next_stem.buffer, dest_buffer, @@ -583,15 +582,15 @@ impl Preserve for Hamt { Some((Right(leaf), idx)) => { if stack.is_in_frame(leaf.buffer) { let dest_buffer = - stack.struct_alloc_in_previous_frame(leaf.len)?; + stack.struct_alloc_in_previous_frame(leaf.len); copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len); let new_leaf = Leaf { len: leaf.len, buffer: dest_buffer, }; for pair in new_leaf.to_mut_slice().iter_mut() { - pair.0.preserve(stack)?; - pair.1.preserve(stack)?; + pair.0.preserve(stack); + pair.1.preserve(stack); } *stem.buffer.add(idx) = Entry { leaf: new_leaf }; } @@ -602,8 +601,7 @@ impl Preserve for Hamt { } } } - }; - Ok(res) + } } } @@ -709,10 +707,10 @@ mod test { let size = 1 << 27; let top_slots = 100; let mut stack = NockStack::new(size, top_slots); - let mut hamt = Hamt::::new(&mut stack).unwrap(); - hamt = hamt.insert(&mut stack, &mut D(0), D(1)).unwrap(); - hamt = hamt.insert(&mut stack, &mut D(2), D(3)).unwrap(); - hamt = hamt.insert(&mut stack, &mut D(4), D(5)).unwrap(); + let mut hamt = Hamt::::new(&mut stack); + hamt = hamt.insert(&mut stack, &mut D(0), D(1)); + hamt = hamt.insert(&mut stack, &mut D(2), D(3)); + hamt = hamt.insert(&mut stack, &mut D(4), D(5)); let mut iter = hamt.iter(); let three = cdr(&mut iter); let one = cdr(&mut iter); @@ -730,10 +728,10 @@ mod test { let size = 1 << 27; let top_slots = 100; let mut stack = NockStack::new(size, top_slots); - let mut hamt = Hamt::::new(&mut stack).unwrap(); + let mut hamt = Hamt::::new(&mut stack); let mut hs = HashSet::new(); for n in 0..100 { - hamt = hamt.insert(&mut stack, &mut D(n), D(n)).unwrap(); + hamt = hamt.insert(&mut stack, &mut D(n), D(n)); hs.insert((n, n)); } let mut iter = hamt.iter(); @@ -748,21 +746,17 @@ mod test { let size = 1 << 27; let top_slots = 100; let mut stack = NockStack::new(size, top_slots); - let mut hamt = Hamt::::new(&mut stack).unwrap(); + let mut hamt = Hamt::::new(&mut stack); let mut n = D(0); let t = D(1); - hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); - let lu = hamt - .lookup(&mut stack, &mut n) - .expect("lookup failed due to OOM"); + hamt = hamt.insert(&mut stack, &mut n, t); + let lu = hamt.lookup(&mut stack, &mut n); let lu_value = unsafe { lu.expect("lookup failed").as_raw() }; assert_eq!(lu_value, 1); let mut n = D(2); let t = D(3); - hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); - let lu = hamt - .lookup(&mut stack, &mut D(2)) - .expect("lookup failed due to OOM"); + hamt = hamt.insert(&mut stack, &mut n, t); + let lu = hamt.lookup(&mut stack, &mut D(2)); let lu_value = unsafe { lu.expect("lookup failed").as_raw() }; assert_eq!(lu_value, 3); } @@ -772,38 +766,32 @@ mod test { let size = 1 << 27; let top_slots = 100; let mut stack = NockStack::new(size, top_slots); - let mut hamt = Hamt::::new(&mut stack).unwrap(); + let mut hamt = Hamt::::new(&mut stack); // 3-way collision // x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072 // x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072 let mut n = D(0); let t = D(0); - hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); + hamt = hamt.insert(&mut stack, &mut n, t); let mut n = D(87699370); let t = D(87699370); - hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); + hamt = hamt.insert(&mut stack, &mut n, t); let mut n = D(317365951); let t = D(317365951); - hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); + hamt = hamt.insert(&mut stack, &mut n, t); - let lu = hamt - .lookup(&mut stack, &mut D(0)) - .expect("lookup failed due to OOM"); + let lu = hamt.lookup(&mut stack, &mut D(0)); let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() }; assert_eq!(lu_value, 0); - let lu = hamt - .lookup(&mut stack, &mut D(87699370)) - .expect("lookup failed due to OOM"); + let lu = hamt.lookup(&mut stack, &mut D(87699370)); let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() }; assert_eq!(lu_value, 87699370); - let lu = hamt - .lookup(&mut stack, &mut D(317365951)) - .expect("lookup failed due to OOM"); + let lu = hamt.lookup(&mut stack, &mut D(317365951)); let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() }; assert_eq!(lu_value, 317365951); } @@ -813,13 +801,13 @@ mod test { let size = 1 << 27; let top_slots = 100; let mut stack = NockStack::new(size, top_slots); - let mut hamt = Hamt::::new(&mut stack).unwrap(); + let mut hamt = Hamt::::new(&mut stack); // 3-way collision // x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072 // x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072 let mut hs = HashSet::new(); for x in &[0, 87699370, 317365951] { - hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)).unwrap(); + hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)); hs.insert((*x, *x)); } for x in hamt.iter() { diff --git a/rust/sword/src/interpreter.rs b/rust/sword/src/interpreter.rs index 20729d5..13f99a9 100644 --- a/rust/sword/src/interpreter.rs +++ b/rust/sword/src/interpreter.rs @@ -3,7 +3,7 @@ use crate::jets::cold::Cold; use crate::jets::hot::Hot; use crate::jets::warm::Warm; use crate::jets::{cold, JetErr}; -use crate::mem::{AllocResult, NockStack, Preserve}; +use crate::mem::{NockStack, Preserve}; use crate::noun::{Atom, Cell, IndirectAtom, Noun, Slots, D, T}; use crate::trace::{write_nock_trace, TraceInfo, TraceStack}; use crate::unifying_equality::unifying_equality; @@ -256,10 +256,10 @@ pub trait Slogger { * pri = debug priority * tank = output as tank */ - fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()>; + fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun); /** Send %flog, raw debug output. */ - fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()>; + fn flog(&mut self, stack: &mut NockStack, cord: Noun); } impl Slogger for Pin<&mut T> @@ -268,14 +268,12 @@ where { // + Unpin // type SlogTarget = T::Target; - fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> { - (*self).deref_mut().flog(stack, cord)?; - Ok(()) + fn flog(&mut self, stack: &mut NockStack, cord: Noun) { + (*self).deref_mut().flog(stack, cord); } - fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> { - (**self).slog(stack, pri, tank)?; - Ok(()) + fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) { + (**self).slog(stack, pri, tank); } } @@ -319,19 +317,19 @@ impl Context { * jet to use the entire context without the borrow checker complaining about the mutable * references. */ - pub unsafe fn with_stack_frame(&mut self, slots: usize, f: F) -> AllocResult + pub unsafe fn with_stack_frame(&mut self, slots: usize, f: F) -> O where F: FnOnce(&mut Context) -> O, O: Preserve, { - self.stack.frame_push(slots)?; + self.stack.frame_push(slots); let mut ret = f(self); - ret.preserve(&mut self.stack)?; - self.cache.preserve(&mut self.stack)?; - self.cold.preserve(&mut self.stack)?; - self.warm.preserve(&mut self.stack)?; + ret.preserve(&mut self.stack); + self.cache.preserve(&mut self.stack); + self.cold.preserve(&mut self.stack); + self.warm.preserve(&mut self.stack); self.stack.frame_pop(); - Ok(ret) + ret } } @@ -343,8 +341,7 @@ pub enum Mote { Meme = tas!(b"meme") as isize, } -/// Interpreter errors, reused in [`JetErr::Fail`] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum Error { ScryBlocked(Noun), // path ScryCrashed(Noun), // trace @@ -352,14 +349,8 @@ pub enum Error { NonDeterministic(Mote, Noun), // mote, trace } -impl From for Error { - fn from(_err: crate::mem::AllocationError) -> Self { - Error::NonDeterministic(Mote::Meme, D(0)) - } -} - impl Preserve for Error { - unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { + unsafe fn preserve(&mut self, stack: &mut NockStack) { match self { Error::ScryBlocked(ref mut path) => path.preserve(stack), Error::ScryCrashed(ref mut trace) => trace.preserve(stack), @@ -390,10 +381,10 @@ impl From for Error { } } -pub type Result = result::Result; +pub type Result = result::Result; -const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0))); -const BAIL_FAIL: Result = Err(Error::NonDeterministic(Mote::Fail, D(0))); +const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0))); +const BAIL_FAIL: Result = Err(Error::NonDeterministic(Mote::Fail, D(0))); #[allow(unused_variables)] fn debug_assertions(stack: &mut NockStack, noun: Noun) { @@ -403,22 +394,22 @@ fn debug_assertions(stack: &mut NockStack, noun: Noun) { } /** Interpret nock */ -pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result { +pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result { let orig_subject = subject; // for debugging let snapshot = context.save(); let virtual_frame: *const u64 = context.stack.get_frame_pointer(); - let res: Noun = D(0); + let mut res: Noun = D(0); // Setup stack for Nock computation unsafe { - context.stack.frame_push(2)?; + context.stack.frame_push(2); // Bottom of mean stack *(context.stack.local_noun_pointer(0)) = D(0); // Bottom of trace stack *(context.stack.local_noun_pointer(1) as *mut *const TraceStack) = std::ptr::null(); - *(context.stack.push()?) = NockWork::Done; + *(context.stack.push()) = NockWork::Done; }; // DO NOT REMOVE THIS COMMENT @@ -434,9 +425,541 @@ pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result< // (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use) let nock = assert_no_alloc(|| { ensure_alloc_counters(|| { - // let stack_pp = context.stack.get_stack_pointer_pointer() as *const *const u64; - // let alloc_pp = context.stack.get_alloc_pointer_pointer() as *const *const u64; - unsafe { work(context, formula, orig_subject, subject, res) } + unsafe { + push_formula(&mut context.stack, formula, true)?; + + loop { + let work: NockWork = *context.stack.top(); + match work { + NockWork::Done => { + write_trace(context); + + let stack = &mut context.stack; + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); + + break Ok(res); + } + NockWork::Ret => { + write_trace(context); + + let stack = &mut context.stack; + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); + } + NockWork::WorkCons(mut cons) => match cons.todo { + TodoCons::ComputeHead => { + cons.todo = TodoCons::ComputeTail; + *context.stack.top() = NockWork::WorkCons(cons); + push_formula(&mut context.stack, cons.head, false)?; + } + TodoCons::ComputeTail => { + cons.todo = TodoCons::Cons; + cons.head = res; + *context.stack.top() = NockWork::WorkCons(cons); + push_formula(&mut context.stack, cons.tail, false)?; + } + TodoCons::Cons => { + let stack = &mut context.stack; + res = T(stack, &[cons.head, res]); + stack.pop::(); + } + }, + NockWork::Work0(zero) => { + if let Ok(noun) = subject.slot_atom(zero.axis) { + res = noun; + context.stack.pop::(); + } else { + // Axis invalid for input Noun + break BAIL_EXIT; + } + } + NockWork::Work1(once) => { + res = once.noun; + context.stack.pop::(); + } + NockWork::Work2(mut vale) => match vale.todo { + Todo2::ComputeSubject => { + vale.todo = Todo2::ComputeFormula; + *context.stack.top() = NockWork::Work2(vale); + push_formula(&mut context.stack, vale.subject, false)?; + } + Todo2::ComputeFormula => { + vale.todo = Todo2::ComputeResult; + vale.subject = res; + *context.stack.top() = NockWork::Work2(vale); + push_formula(&mut context.stack, vale.formula, false)?; + } + Todo2::ComputeResult => { + let stack = &mut context.stack; + if vale.tail { + stack.pop::(); + subject = vale.subject; + push_formula(stack, res, true)?; + } else { + vale.todo = Todo2::RestoreSubject; + std::mem::swap(&mut vale.subject, &mut subject); + *stack.top() = NockWork::Work2(vale); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, res, true)?; + } + } + Todo2::RestoreSubject => { + let stack = &mut context.stack; + + subject = vale.subject; + stack.pop::(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + } + }, + NockWork::Work3(mut thee) => match thee.todo { + Todo3::ComputeChild => { + thee.todo = Todo3::ComputeType; + *context.stack.top() = NockWork::Work3(thee); + push_formula(&mut context.stack, thee.child, false)?; + } + Todo3::ComputeType => { + res = if res.is_cell() { D(0) } else { D(1) }; + context.stack.pop::(); + } + }, + NockWork::Work4(mut four) => match four.todo { + Todo4::ComputeChild => { + four.todo = Todo4::Increment; + *context.stack.top() = NockWork::Work4(four); + push_formula(&mut context.stack, four.child, false)?; + } + Todo4::Increment => { + if let Ok(atom) = res.as_atom() { + res = inc(&mut context.stack, atom).as_noun(); + context.stack.pop::(); + } else { + // Cannot increment (Nock 4) a cell + break BAIL_EXIT; + } + } + }, + NockWork::Work5(mut five) => match five.todo { + Todo5::ComputeLeftChild => { + five.todo = Todo5::ComputeRightChild; + *context.stack.top() = NockWork::Work5(five); + push_formula(&mut context.stack, five.left, false)?; + } + Todo5::ComputeRightChild => { + five.todo = Todo5::TestEquals; + five.left = res; + *context.stack.top() = NockWork::Work5(five); + push_formula(&mut context.stack, five.right, false)?; + } + Todo5::TestEquals => { + let stack = &mut context.stack; + let saved_value_ptr = &mut five.left; + res = if unifying_equality(stack, &mut res, saved_value_ptr) { + D(0) + } else { + D(1) + }; + stack.pop::(); + } + }, + NockWork::Work6(mut cond) => match cond.todo { + Todo6::ComputeTest => { + cond.todo = Todo6::ComputeBranch; + *context.stack.top() = NockWork::Work6(cond); + push_formula(&mut context.stack, cond.test, false)?; + } + Todo6::ComputeBranch => { + let stack = &mut context.stack; + stack.pop::(); + if let Left(direct) = res.as_either_direct_allocated() { + if direct.data() == 0 { + push_formula(stack, cond.zero, cond.tail)?; + } else if direct.data() == 1 { + push_formula(stack, cond.once, cond.tail)?; + } else { + // Test branch of Nock 6 must return 0 or 1 + break BAIL_EXIT; + } + } else { + // Test branch of Nock 6 must return a direct atom + break BAIL_EXIT; + } + } + }, + NockWork::Work7(mut pose) => match pose.todo { + Todo7::ComputeSubject => { + pose.todo = Todo7::ComputeResult; + *context.stack.top() = NockWork::Work7(pose); + push_formula(&mut context.stack, pose.subject, false)?; + } + Todo7::ComputeResult => { + let stack = &mut context.stack; + if pose.tail { + stack.pop::(); + subject = res; + push_formula(stack, pose.formula, true)?; + } else { + pose.todo = Todo7::RestoreSubject; + pose.subject = subject; + *stack.top() = NockWork::Work7(pose); + subject = res; + push_formula(stack, pose.formula, false)?; + } + } + Todo7::RestoreSubject => { + subject = pose.subject; + context.stack.pop::(); + } + }, + NockWork::Work8(mut pins) => match pins.todo { + Todo8::ComputeSubject => { + pins.todo = Todo8::ComputeResult; + *context.stack.top() = NockWork::Work8(pins); + push_formula(&mut context.stack, pins.pin, false)?; + } + Todo8::ComputeResult => { + let stack = &mut context.stack; + if pins.tail { + subject = T(stack, &[res, subject]); + stack.pop::(); + push_formula(stack, pins.formula, true)?; + } else { + pins.todo = Todo8::RestoreSubject; + pins.pin = subject; + *stack.top() = NockWork::Work8(pins); + subject = T(stack, &[res, subject]); + push_formula(stack, pins.formula, false)?; + } + } + Todo8::RestoreSubject => { + subject = pins.pin; + context.stack.pop::(); + } + }, + NockWork::Work9(mut kale) => { + match kale.todo { + Todo9::ComputeCore => { + kale.todo = Todo9::ComputeResult; + *context.stack.top() = NockWork::Work9(kale); + push_formula(&mut context.stack, kale.core, false)?; + } + Todo9::ComputeResult => { + if let Ok(mut formula) = res.slot_atom(kale.axis) { + if !cfg!(feature = "sham_hints") { + if let Some((jet, _path)) = context.warm.find_jet( + &mut context.stack, &mut res, &mut formula, + ) { + match jet(context, res) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } + } + } + }; + + let stack = &mut context.stack; + if kale.tail { + stack.pop::(); + + // We could trace on 2 as well, but 2 only comes from Hoon via + // '.*', so we can assume it's never directly used to invoke + // jetted code. + if context.trace_info.is_some() { + if let Some(path) = + context.cold.matches(stack, &mut res) + { + append_trace(stack, path); + }; + }; + + subject = res; + push_formula(stack, formula, true)?; + } else { + kale.todo = Todo9::RestoreSubject; + kale.core = subject; + *stack.top() = NockWork::Work9(kale); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + subject = res; + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, formula, true)?; + + // We could trace on 2 as well, but 2 only comes from Hoon via + // '.*', so we can assume it's never directly used to invoke + // jetted code. + if context.trace_info.is_some() { + if let Some(path) = + context.cold.matches(stack, &mut res) + { + append_trace(stack, path); + }; + }; + } + } else { + // Axis into core must be atom + break BAIL_EXIT; + } + } + Todo9::RestoreSubject => { + let stack = &mut context.stack; + + subject = kale.core; + stack.pop::(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + } + } + } + NockWork::Work10(mut diet) => { + match diet.todo { + Todo10::ComputeTree => { + diet.todo = Todo10::ComputePatch; // should we compute patch then tree? + *context.stack.top() = NockWork::Work10(diet); + push_formula(&mut context.stack, diet.tree, false)?; + } + Todo10::ComputePatch => { + diet.todo = Todo10::Edit; + diet.tree = res; + *context.stack.top() = NockWork::Work10(diet); + push_formula(&mut context.stack, diet.patch, false)?; + } + Todo10::Edit => { + res = edit( + &mut context.stack, + diet.axis.as_bitslice(), + res, + diet.tree, + ); + context.stack.pop::(); + } + } + } + NockWork::Work11D(mut dint) => match dint.todo { + Todo11D::ComputeHint => { + if let Some(ret) = hint::match_pre_hint( + context, subject, dint.tag, dint.hint, dint.body, + ) { + match ret { + Ok(found) => { + res = found; + context.stack.pop::(); + } + Err(err) => { + break Err(err); + } + } + } else { + dint.todo = Todo11D::ComputeResult; + *context.stack.top() = NockWork::Work11D(dint); + push_formula(&mut context.stack, dint.hint, false)?; + } + } + Todo11D::ComputeResult => { + if let Some(ret) = hint::match_pre_nock( + context, + subject, + dint.tag, + Some((dint.hint, res)), + dint.body, + ) { + match ret { + Ok(found) => { + res = found; + context.stack.pop::(); + } + Err(err) => { + break Err(err); + } + } + } else { + if dint.tail { + context.stack.pop::(); + } else { + dint.todo = Todo11D::Done; + dint.hint = res; + *context.stack.top() = NockWork::Work11D(dint); + } + push_formula(&mut context.stack, dint.body, dint.tail)?; + } + } + Todo11D::Done => { + if let Some(found) = hint::match_post_nock( + context, + subject, + dint.tag, + Some(dint.hint), + dint.body, + res, + ) { + res = found; + } + context.stack.pop::(); + } + }, + NockWork::Work11S(mut sint) => match sint.todo { + Todo11S::ComputeResult => { + if let Some(ret) = hint::match_pre_nock( + context, subject, sint.tag, None, sint.body, + ) { + match ret { + Ok(found) => { + res = found; + context.stack.pop::(); + } + Err(err) => { + break Err(err); + } + } + } else { + if sint.tail { + context.stack.pop::(); + } else { + sint.todo = Todo11S::Done; + *context.stack.top() = NockWork::Work11S(sint); + } + push_formula(&mut context.stack, sint.body, sint.tail)?; + } + } + Todo11S::Done => { + if let Some(found) = hint::match_post_nock( + context, subject, sint.tag, None, sint.body, res, + ) { + res = found; + } + context.stack.pop::(); + } + }, + NockWork::Work12(mut scry) => match scry.todo { + Todo12::ComputeReff => { + let stack = &mut context.stack; + scry.todo = Todo12::ComputePath; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.reff, false)?; + } + Todo12::ComputePath => { + let stack = &mut context.stack; + scry.todo = Todo12::Scry; + scry.reff = res; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.path, false)?; + } + Todo12::Scry => { + if let Some(cell) = context.scry_stack.cell() { + scry.path = res; + let scry_stack = context.scry_stack; + let scry_handler = cell.head(); + let scry_gate = scry_handler.as_cell()?; + let payload = T(&mut context.stack, &[scry.reff, res]); + let scry_core = T( + &mut context.stack, + &[ + scry_gate.head(), + payload, + scry_gate.tail().as_cell()?.tail(), + ], + ); + let scry_form = + T(&mut context.stack, &[D(9), D(2), D(1), scry_core]); + + context.scry_stack = cell.tail(); + // Alternately, we could use scry_core as the subject and [9 2 0 1] as + // the formula. It's unclear if performance will be better with a purely + // static formula. + match interpret(context, D(0), scry_form) { + Ok(noun) => match noun.as_either_atom_cell() { + Left(atom) => { + if atom.as_noun().raw_equals(D(0)) { + break Err(Error::ScryBlocked(scry.path)); + } else { + break Err(Error::ScryCrashed(D(0))); + } + } + Right(cell) => { + match cell.tail().as_either_atom_cell() { + Left(_) => { + let stack = &mut context.stack; + let hunk = T( + stack, + &[ + D(tas!(b"hunk")), + scry.reff, + scry.path, + ], + ); + mean_push(stack, hunk); + break Err(Error::ScryCrashed(D(0))); + } + Right(cell) => { + res = cell.tail(); + context.scry_stack = scry_stack; + context.stack.pop::(); + } + } + } + }, + Err(error) => match error { + Error::Deterministic(_, trace) + | Error::ScryCrashed(trace) => { + break Err(Error::ScryCrashed(trace)); + } + Error::NonDeterministic(_, _) => { + break Err(error); + } + Error::ScryBlocked(_) => { + break BAIL_FAIL; + } + }, + } + } else { + // No scry handler + break BAIL_EXIT; + } + } + }, + }; + } + } }) }); @@ -446,531 +969,13 @@ pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result< } } -unsafe fn work( - context: &mut Context, - formula: Noun, - orig_subject: Noun, - mut subject: Noun, - mut res: Noun, -) -> Result { - push_formula(&mut context.stack, formula, true)?; - loop { - let work: NockWork = *context.stack.top(); - match work { - NockWork::Done => { - write_trace(context); - - let stack = &mut context.stack; - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - stack.preserve(&mut context.cache)?; - stack.preserve(&mut context.cold)?; - stack.preserve(&mut context.warm)?; - stack.preserve(&mut res)?; - stack.frame_pop(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, res); - - break Ok(res); - } - NockWork::Ret => { - write_trace(context); - - let stack = &mut context.stack; - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - stack.preserve(&mut context.cache)?; - stack.preserve(&mut context.cold)?; - stack.preserve(&mut context.warm)?; - stack.preserve(&mut res)?; - stack.frame_pop(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, res); - } - NockWork::WorkCons(mut cons) => match cons.todo { - TodoCons::ComputeHead => { - cons.todo = TodoCons::ComputeTail; - *context.stack.top() = NockWork::WorkCons(cons); - push_formula(&mut context.stack, cons.head, false)?; - } - TodoCons::ComputeTail => { - cons.todo = TodoCons::Cons; - cons.head = res; - *context.stack.top() = NockWork::WorkCons(cons); - push_formula(&mut context.stack, cons.tail, false)?; - } - TodoCons::Cons => { - let stack = &mut context.stack; - res = T(stack, &[cons.head, res])?; - stack.pop::(); - } - }, - NockWork::Work0(zero) => { - if let Ok(noun) = subject.slot_atom(zero.axis) { - res = noun; - context.stack.pop::(); - } else { - // Axis invalid for input Noun - break BAIL_EXIT; - } - } - NockWork::Work1(once) => { - res = once.noun; - context.stack.pop::(); - } - NockWork::Work2(mut vale) => match vale.todo { - Todo2::ComputeSubject => { - vale.todo = Todo2::ComputeFormula; - *context.stack.top() = NockWork::Work2(vale); - push_formula(&mut context.stack, vale.subject, false)?; - } - Todo2::ComputeFormula => { - vale.todo = Todo2::ComputeResult; - vale.subject = res; - *context.stack.top() = NockWork::Work2(vale); - push_formula(&mut context.stack, vale.formula, false)?; - } - Todo2::ComputeResult => { - let stack = &mut context.stack; - if vale.tail { - stack.pop::(); - subject = vale.subject; - push_formula(stack, res, true)?; - } else { - vale.todo = Todo2::RestoreSubject; - std::mem::swap(&mut vale.subject, &mut subject); - *stack.top() = NockWork::Work2(vale); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - mean_frame_push(stack, 0)?; - *stack.push()? = NockWork::Ret; - push_formula(stack, res, true)?; - } - } - Todo2::RestoreSubject => { - let stack = &mut context.stack; - - subject = vale.subject; - stack.pop::(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - } - }, - NockWork::Work3(mut thee) => match thee.todo { - Todo3::ComputeChild => { - thee.todo = Todo3::ComputeType; - *context.stack.top() = NockWork::Work3(thee); - push_formula(&mut context.stack, thee.child, false)?; - } - Todo3::ComputeType => { - res = if res.is_cell() { D(0) } else { D(1) }; - context.stack.pop::(); - } - }, - NockWork::Work4(mut four) => match four.todo { - Todo4::ComputeChild => { - four.todo = Todo4::Increment; - *context.stack.top() = NockWork::Work4(four); - push_formula(&mut context.stack, four.child, false)?; - } - Todo4::Increment => { - if let Ok(atom) = res.as_atom() { - res = inc(&mut context.stack, atom)?.as_noun(); - context.stack.pop::(); - } else { - // Cannot increment (Nock 4) a cell - break BAIL_EXIT; - } - } - }, - NockWork::Work5(mut five) => match five.todo { - Todo5::ComputeLeftChild => { - five.todo = Todo5::ComputeRightChild; - *context.stack.top() = NockWork::Work5(five); - push_formula(&mut context.stack, five.left, false)?; - } - Todo5::ComputeRightChild => { - five.todo = Todo5::TestEquals; - five.left = res; - *context.stack.top() = NockWork::Work5(five); - push_formula(&mut context.stack, five.right, false)?; - } - Todo5::TestEquals => { - let stack = &mut context.stack; - let saved_value_ptr = &mut five.left; - res = if unifying_equality(stack, &mut res, saved_value_ptr)? { - D(0) - } else { - D(1) - }; - stack.pop::(); - } - }, - NockWork::Work6(mut cond) => match cond.todo { - Todo6::ComputeTest => { - cond.todo = Todo6::ComputeBranch; - *context.stack.top() = NockWork::Work6(cond); - push_formula(&mut context.stack, cond.test, false)?; - } - Todo6::ComputeBranch => { - let stack = &mut context.stack; - stack.pop::(); - if let Left(direct) = res.as_either_direct_allocated() { - if direct.data() == 0 { - push_formula(stack, cond.zero, cond.tail)?; - } else if direct.data() == 1 { - push_formula(stack, cond.once, cond.tail)?; - } else { - // Test branch of Nock 6 must return 0 or 1 - break BAIL_EXIT; - } - } else { - // Test branch of Nock 6 must return a direct atom - break BAIL_EXIT; - } - } - }, - NockWork::Work7(mut pose) => match pose.todo { - Todo7::ComputeSubject => { - pose.todo = Todo7::ComputeResult; - *context.stack.top() = NockWork::Work7(pose); - push_formula(&mut context.stack, pose.subject, false)?; - } - Todo7::ComputeResult => { - let stack = &mut context.stack; - if pose.tail { - stack.pop::(); - subject = res; - push_formula(stack, pose.formula, true)?; - } else { - pose.todo = Todo7::RestoreSubject; - pose.subject = subject; - *stack.top() = NockWork::Work7(pose); - subject = res; - push_formula(stack, pose.formula, false)?; - } - } - Todo7::RestoreSubject => { - subject = pose.subject; - context.stack.pop::(); - } - }, - NockWork::Work8(mut pins) => match pins.todo { - Todo8::ComputeSubject => { - pins.todo = Todo8::ComputeResult; - *context.stack.top() = NockWork::Work8(pins); - push_formula(&mut context.stack, pins.pin, false)?; - } - Todo8::ComputeResult => { - let stack = &mut context.stack; - if pins.tail { - subject = T(stack, &[res, subject])?; - stack.pop::(); - push_formula(stack, pins.formula, true)?; - } else { - pins.todo = Todo8::RestoreSubject; - pins.pin = subject; - *stack.top() = NockWork::Work8(pins); - subject = T(stack, &[res, subject])?; - push_formula(stack, pins.formula, false)?; - } - } - Todo8::RestoreSubject => { - subject = pins.pin; - context.stack.pop::(); - } - }, - NockWork::Work9(mut kale) => { - match kale.todo { - Todo9::ComputeCore => { - kale.todo = Todo9::ComputeResult; - *context.stack.top() = NockWork::Work9(kale); - push_formula(&mut context.stack, kale.core, false)?; - } - Todo9::ComputeResult => { - if let Ok(mut formula) = res.slot_atom(kale.axis) { - if !cfg!(feature = "sham_hints") { - if let Some((jet, _path)) = context - .warm - .find_jet(&mut context.stack, &mut res, &mut formula)? - { - match jet(context, res) { - Ok(jet_res) => { - res = jet_res; - context.stack.pop::(); - continue; - } - Err(JetErr::Punt) => {} - Err(err) => { - break Err(err.into()); - } - } - } - }; - - let stack = &mut context.stack; - if kale.tail { - stack.pop::(); - - // We could trace on 2 as well, but 2 only comes from Hoon via - // '.*', so we can assume it's never directly used to invoke - // jetted code. - if context.trace_info.is_some() { - if let Some(path) = context.cold.matches(stack, &mut res)? { - append_trace(stack, path)?; - }; - }; - - subject = res; - push_formula(stack, formula, true)?; - } else { - kale.todo = Todo9::RestoreSubject; - kale.core = subject; - *stack.top() = NockWork::Work9(kale); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - subject = res; - mean_frame_push(stack, 0)?; - *stack.push()? = NockWork::Ret; - push_formula(stack, formula, true)?; - - // We could trace on 2 as well, but 2 only comes from Hoon via - // '.*', so we can assume it's never directly used to invoke - // jetted code. - if context.trace_info.is_some() { - if let Some(path) = context.cold.matches(stack, &mut res)? { - append_trace(stack, path)?; - }; - }; - } - } else { - // Axis into core must be atom - break BAIL_EXIT; - } - } - Todo9::RestoreSubject => { - let stack = &mut context.stack; - - subject = kale.core; - stack.pop::(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - } - } - } - NockWork::Work10(mut diet) => { - match diet.todo { - Todo10::ComputeTree => { - diet.todo = Todo10::ComputePatch; // should we compute patch then tree? - *context.stack.top() = NockWork::Work10(diet); - push_formula(&mut context.stack, diet.tree, false)?; - } - Todo10::ComputePatch => { - diet.todo = Todo10::Edit; - diet.tree = res; - *context.stack.top() = NockWork::Work10(diet); - push_formula(&mut context.stack, diet.patch, false)?; - } - Todo10::Edit => { - res = edit(&mut context.stack, diet.axis.as_bitslice(), res, diet.tree)?; - context.stack.pop::(); - } - } - } - NockWork::Work11D(mut dint) => match dint.todo { - Todo11D::ComputeHint => { - if let Some(ret) = - hint::match_pre_hint(context, subject, dint.tag, dint.hint, dint.body) - { - match ret { - Ok(found) => { - res = found; - context.stack.pop::(); - } - Err(err) => { - break Err(err); - } - } - } else { - dint.todo = Todo11D::ComputeResult; - *context.stack.top() = NockWork::Work11D(dint); - push_formula(&mut context.stack, dint.hint, false)?; - } - } - Todo11D::ComputeResult => { - if let Some(ret) = hint::match_pre_nock( - context, - subject, - dint.tag, - Some((dint.hint, res)), - dint.body, - ) { - match ret { - Ok(found) => { - res = found; - context.stack.pop::(); - } - Err(err) => { - break Err(err); - } - } - } else { - if dint.tail { - context.stack.pop::(); - } else { - dint.todo = Todo11D::Done; - dint.hint = res; - *context.stack.top() = NockWork::Work11D(dint); - } - push_formula(&mut context.stack, dint.body, dint.tail)?; - } - } - Todo11D::Done => { - if let Some(found) = hint::match_post_nock( - context, - subject, - dint.tag, - Some(dint.hint), - dint.body, - res, - )? { - res = found; - } - context.stack.pop::(); - } - }, - NockWork::Work11S(mut sint) => match sint.todo { - Todo11S::ComputeResult => { - if let Some(ret) = - hint::match_pre_nock(context, subject, sint.tag, None, sint.body) - { - match ret { - Ok(found) => { - res = found; - context.stack.pop::(); - } - Err(err) => { - break Err(err); - } - } - } else { - if sint.tail { - context.stack.pop::(); - } else { - sint.todo = Todo11S::Done; - *context.stack.top() = NockWork::Work11S(sint); - } - push_formula(&mut context.stack, sint.body, sint.tail)?; - } - } - Todo11S::Done => { - if let Some(found) = - hint::match_post_nock(context, subject, sint.tag, None, sint.body, res)? - { - res = found; - } - context.stack.pop::(); - } - }, - NockWork::Work12(mut scry) => match scry.todo { - Todo12::ComputeReff => { - let stack = &mut context.stack; - scry.todo = Todo12::ComputePath; - *stack.top() = NockWork::Work12(scry); - push_formula(stack, scry.reff, false)?; - } - Todo12::ComputePath => { - let stack = &mut context.stack; - scry.todo = Todo12::Scry; - scry.reff = res; - *stack.top() = NockWork::Work12(scry); - push_formula(stack, scry.path, false)?; - } - Todo12::Scry => { - if let Some(cell) = context.scry_stack.cell() { - scry.path = res; - let scry_stack = context.scry_stack; - let scry_handler = cell.head(); - let scry_gate = scry_handler.as_cell()?; - let payload = T(&mut context.stack, &[scry.reff, res])?; - let scry_core = T( - &mut context.stack, - &[scry_gate.head(), payload, scry_gate.tail().as_cell()?.tail()], - )?; - let scry_form = T(&mut context.stack, &[D(9), D(2), D(1), scry_core])?; - - context.scry_stack = cell.tail(); - // Alternately, we could use scry_core as the subject and [9 2 0 1] as - // the formula. It's unclear if performance will be better with a purely - // static formula. - match interpret(context, D(0), scry_form) { - Ok(noun) => match noun.as_either_atom_cell() { - Left(atom) => { - if atom.as_noun().raw_equals(D(0)) { - break Err(Error::ScryBlocked(scry.path)); - } else { - break Err(Error::ScryCrashed(D(0))); - } - } - Right(cell) => match cell.tail().as_either_atom_cell() { - Left(_) => { - let stack = &mut context.stack; - let hunk = - T(stack, &[D(tas!(b"hunk")), scry.reff, scry.path])?; - mean_push(stack, hunk)?; - break Err(Error::ScryCrashed(D(0))); - } - Right(cell) => { - res = cell.tail(); - context.scry_stack = scry_stack; - context.stack.pop::(); - } - }, - }, - Err(error) => match error { - Error::Deterministic(_, trace) | Error::ScryCrashed(trace) => { - break Err(Error::ScryCrashed(trace)); - } - Error::NonDeterministic(_, _) => { - break Err(error); - } - Error::ScryBlocked(_) => { - break BAIL_FAIL; - } - }, - } - } else { - // No scry handler - break BAIL_EXIT; - } - } - }, - }; - } -} -fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { +fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { unsafe { if let Ok(formula_cell) = formula.as_cell() { // Formula match formula_cell.head().as_either_atom_cell() { Right(_cell) => { - *stack.push()? = NockWork::WorkCons(NockCons { + *stack.push() = NockWork::WorkCons(NockCons { todo: TodoCons::ComputeHead, head: formula_cell.head(), tail: formula_cell.tail(), @@ -981,20 +986,20 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(axis_atom) = formula_cell.tail().as_atom() { - *stack.push()? = NockWork::Work0(Nock0 { axis: axis_atom }); + *stack.push() = NockWork::Work0(Nock0 { axis: axis_atom }); } else { // Axis for Nock 0 must be an atom return BAIL_EXIT; } } 1 => { - *stack.push()? = NockWork::Work1(Nock1 { + *stack.push() = NockWork::Work1(Nock1 { noun: formula_cell.tail(), }); } 2 => { if let Ok(arg_cell) = formula_cell.tail().as_cell() { - *stack.push()? = NockWork::Work2(Nock2 { + *stack.push() = NockWork::Work2(Nock2 { todo: Todo2::ComputeSubject, subject: arg_cell.head(), formula: arg_cell.tail(), @@ -1006,20 +1011,20 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { - *stack.push()? = NockWork::Work3(Nock3 { + *stack.push() = NockWork::Work3(Nock3 { todo: Todo3::ComputeChild, child: formula_cell.tail(), }); } 4 => { - *stack.push()? = NockWork::Work4(Nock4 { + *stack.push() = NockWork::Work4(Nock4 { todo: Todo4::ComputeChild, child: formula_cell.tail(), }); } 5 => { if let Ok(arg_cell) = formula_cell.tail().as_cell() { - *stack.push()? = NockWork::Work5(Nock5 { + *stack.push() = NockWork::Work5(Nock5 { todo: Todo5::ComputeLeftChild, left: arg_cell.head(), right: arg_cell.tail(), @@ -1032,7 +1037,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(arg_cell) = formula_cell.tail().as_cell() { if let Ok(branch_cell) = arg_cell.tail().as_cell() { - *stack.push()? = NockWork::Work6(Nock6 { + *stack.push() = NockWork::Work6(Nock6 { todo: Todo6::ComputeTest, test: arg_cell.head(), zero: branch_cell.head(), @@ -1050,7 +1055,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(arg_cell) = formula_cell.tail().as_cell() { - *stack.push()? = NockWork::Work7(Nock7 { + *stack.push() = NockWork::Work7(Nock7 { todo: Todo7::ComputeSubject, subject: arg_cell.head(), formula: arg_cell.tail(), @@ -1063,7 +1068,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(arg_cell) = formula_cell.tail().as_cell() { - *stack.push()? = NockWork::Work8(Nock8 { + *stack.push() = NockWork::Work8(Nock8 { todo: Todo8::ComputeSubject, pin: arg_cell.head(), formula: arg_cell.tail(), @@ -1077,7 +1082,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(arg_cell) = formula_cell.tail().as_cell() { if let Ok(axis_atom) = arg_cell.head().as_atom() { - *stack.push()? = NockWork::Work9(Nock9 { + *stack.push() = NockWork::Work9(Nock9 { todo: Todo9::ComputeCore, axis: axis_atom, core: arg_cell.tail(), @@ -1096,7 +1101,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result Result { - *stack.push()? = NockWork::Work11S(Nock11S { + *stack.push() = NockWork::Work11S(Nock11S { todo: Todo11S::ComputeResult, tag: tag_atom, body: arg_cell.tail(), @@ -1128,7 +1133,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(tag_atom) = hint_cell.head().as_atom() { - *stack.push()? = NockWork::Work11D(Nock11D { + *stack.push() = NockWork::Work11D(Nock11D { todo: Todo11D::ComputeHint, tag: tag_atom, hint: hint_cell.tail(), @@ -1148,7 +1153,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { if let Ok(arg_cell) = formula_cell.tail().as_cell() { - *stack.push()? = NockWork::Work12(Nock12 { + *stack.push() = NockWork::Work12(Nock12 { todo: Todo12::ComputeReff, reff: arg_cell.head(), path: arg_cell.tail(), @@ -1199,15 +1204,12 @@ fn exit( let h = *(stack.local_noun_pointer(0)); // XX: Small chance of clobbering something important after OOM? // XX: what if we OOM while making a stack trace - T(stack, &[h, t]).expect("serf: failed to create trace, allocation error") + T(stack, &[h, t]) } }; while stack.get_frame_pointer() != virtual_frame { - // TODO: Is this the right thing to do when preserve fails?" - stack - .preserve(&mut preserve) - .expect("serf: failed to preserve stack"); + stack.preserve(&mut preserve); stack.frame_pop(); } @@ -1222,24 +1224,22 @@ fn exit( /** Push frame onto NockStack while preserving the mean stack. */ -fn mean_frame_push(stack: &mut NockStack, slots: usize) -> AllocResult<()> { +fn mean_frame_push(stack: &mut NockStack, slots: usize) { unsafe { let trace = *(stack.local_noun_pointer(0)); - stack.frame_push(slots + 2)?; + stack.frame_push(slots + 2); *(stack.local_noun_pointer(0)) = trace; *(stack.local_noun_pointer(1) as *mut *const TraceStack) = std::ptr::null(); } - Ok(()) } /** Push onto the mean stack. */ -fn mean_push(stack: &mut NockStack, noun: Noun) -> AllocResult<()> { +fn mean_push(stack: &mut NockStack, noun: Noun) { unsafe { let cur_trace = *(stack.local_noun_pointer(0)); - let new_trace = T(stack, &[noun, cur_trace])?; + let new_trace = T(stack, &[noun, cur_trace]); *(stack.local_noun_pointer(0)) = new_trace; - Ok(()) } } @@ -1259,7 +1259,7 @@ fn edit( edit_axis: &BitSlice, patch: Noun, mut tree: Noun, -) -> AllocResult { +) -> Noun { let mut res = patch; let mut dest: *mut Noun = &mut res; let mut cursor = edit_axis @@ -1276,7 +1276,7 @@ fn edit( cursor -= 1; if edit_axis[cursor] { unsafe { - let (cell, cellmem) = Cell::new_raw_mut(stack)?; + let (cell, cellmem) = Cell::new_raw_mut(stack); *dest = cell.as_noun(); (*cellmem).head = tree_cell.head(); dest = &mut ((*cellmem).tail); @@ -1284,7 +1284,7 @@ fn edit( tree = tree_cell.tail(); } else { unsafe { - let (cell, cellmem) = Cell::new_raw_mut(stack)?; + let (cell, cellmem) = Cell::new_raw_mut(stack); *dest = cell.as_noun(); (*cellmem).tail = tree_cell.tail(); dest = &mut ((*cellmem).head); @@ -1295,10 +1295,10 @@ fn edit( panic!("Invalid axis for edit"); }; } - Ok(res) + res } -pub fn inc(stack: &mut NockStack, atom: Atom) -> AllocResult { +pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { match atom.as_either() { Left(direct) => Atom::new(stack, direct.data() + 1), Right(indirect) => { @@ -1307,17 +1307,17 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> AllocResult { None => { // all ones, make an indirect one word bigger let (new_indirect, new_slice) = - unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size() + 1)? }; + unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size() + 1) }; new_slice.set(indirect_slice.len(), true); - Ok(new_indirect.as_atom()) + new_indirect.as_atom() } Some(first_zero) => { let (new_indirect, new_slice) = - unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size())? }; + unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size()) }; new_slice.set(first_zero, true); new_slice[first_zero + 1..] .copy_from_bitslice(&indirect_slice[first_zero + 1..]); - Ok(new_indirect.as_atom()) + new_indirect.as_atom() } } } @@ -1325,17 +1325,16 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> AllocResult { } /// Push onto the tracing stack -fn append_trace(stack: &mut NockStack, path: Noun) -> AllocResult<()> { +fn append_trace(stack: &mut NockStack, path: Noun) { unsafe { let trace_stack = *(stack.local_noun_pointer(1) as *const *const TraceStack); - let new_trace_entry = stack.struct_alloc(1)?; + let new_trace_entry = stack.struct_alloc(1); *new_trace_entry = TraceStack { path, start: Instant::now(), next: trace_stack, }; *(stack.local_noun_pointer(1) as *mut *const TraceStack) = new_trace_entry; - Ok(()) } } @@ -1381,7 +1380,7 @@ mod hint { tag: Atom, hint: Noun, body: Noun, - ) -> Option> { + ) -> Option { // XX: handle IndirectAtom tags match tag.direct()?.data() { tas!(b"sham") => { @@ -1401,16 +1400,10 @@ mod hint { match interpret(context, subject, body) { Ok(mut nock_res) => { let stack = &mut context.stack; - // This is an awkward expression but - // the entire unsafe { ... } block is a bool expression if unsafe { - let eq_res = unifying_equality( + !unifying_equality( stack, &mut nock_res, &mut jet_res, - ); - match eq_res { - Ok(eq) => !eq, - Err(err) => return Some(Err(From::from(err))), - } + ) } { // XX: need NockStack allocated string interpolation // let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, nock_res, jet_res); @@ -1459,16 +1452,8 @@ mod hint { } tas!(b"memo") => { let stack = &mut context.stack; - let key = match Cell::new(stack, subject, body) { - Ok(key) => key, - Err(_) => return Some(BAIL_EXIT), - }; - let mut key = key.as_noun(); - context - .cache - .lookup(stack, &mut key) - .transpose() - .map(|r| r.map_err(From::from)) + let mut key = Cell::new(stack, subject, body).as_noun(); + context.cache.lookup(stack, &mut key).map(Ok) } _ => None, } @@ -1481,7 +1466,7 @@ mod hint { tag: Atom, hint: Option<(Noun, Noun)>, _body: Noun, - ) -> Option> { + ) -> Option { // XX: handle IndirectAtom tags match tag.direct()?.data() { tas!(b"dont") => { @@ -1501,23 +1486,14 @@ mod hint { let tank = slog_cell.tail(); let s = (*slogger).deref_mut(); - match s.slog(stack, pri, tank) { - Ok(_) => (), - Err(err) => return Some(Err(Error::from(err))), - }; + s.slog(stack, pri, tank); None } tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { let stack = &mut context.stack; let (_form, clue) = hint?; - let noun = match T(stack, &[tag.as_noun(), clue]) { - Ok(noun) => noun, - Err(_) => return Some(BAIL_EXIT), - }; - match mean_push(stack, noun) { - Ok(_) => (), - Err(err) => return Some(Err(Error::from(err))), - } + let noun = T(stack, &[tag.as_noun(), clue]); + mean_push(stack, noun); None } tas!(b"hela") => { @@ -1527,10 +1503,7 @@ mod hint { // recursively work down frames to get the stack trace all // the way to the root. let mean = unsafe { *(context.stack.local_noun_pointer(0)) }; - let tone = match Cell::new(&mut context.stack, D(2), mean) { - Ok(tone) => tone, - Err(_) => return Some(BAIL_EXIT), - }; + let tone = Cell::new(&mut context.stack, D(2), mean); match mook(context, tone, true) { Ok(toon) => { @@ -1551,12 +1524,7 @@ mod hint { } if let Ok(cell) = list.as_cell() { - match slogger.slog(stack, 0, cell.head()) { - Ok(_) => (), - Err(err) => { - return Some(Err(Error::from(err))); - } - }; + slogger.slog(stack, 0, cell.head()); list = cell.tail(); } else { flog!(context, "serf: %hela: list ends without ~"); @@ -1584,121 +1552,90 @@ mod hint { hint: Option, body: Noun, res: Noun, - ) -> Result> { + ) -> Option { + let stack = &mut context.stack; + let slogger = &mut context.slogger; + let cold = &mut context.cold; + let hot = &context.hot; + let cache = &mut context.cache; + // XX: handle IndirectAtom tags - // Yes it has to be a nested closure: Option -> Result