From 797777a7ac4ece9a3afc1ce62e6e257c3048518e Mon Sep 17 00:00:00 2001 From: Chris Allen Date: Wed, 6 Nov 2024 16:49:32 -0600 Subject: [PATCH] stack push_east/push_west --- rust/sword/src/hamt.rs | 69 ++++++------ rust/sword/src/interpreter.rs | 56 +++++----- rust/sword/src/jets.rs | 3 +- rust/sword/src/jets/cold.rs | 162 ++++++++++++++++------------ rust/sword/src/jets/hash.rs | 2 +- rust/sword/src/jets/list.rs | 4 +- rust/sword/src/jets/lute.rs | 14 +-- rust/sword/src/jets/parse.rs | 2 +- rust/sword/src/jets/sort.rs | 12 +-- rust/sword/src/jets/warm.rs | 18 ++-- rust/sword/src/mem.rs | 53 +++++---- rust/sword/src/mug.rs | 17 +-- rust/sword/src/persist.rs | 44 ++++---- rust/sword/src/serf.rs | 17 +-- rust/sword/src/serialization.rs | 52 ++++----- rust/sword/src/site.rs | 17 +-- rust/sword/src/unifying_equality.rs | 26 +++-- 17 files changed, 318 insertions(+), 250 deletions(-) diff --git a/rust/sword/src/hamt.rs b/rust/sword/src/hamt.rs index 6cb6f95..0d0a4f0 100644 --- a/rust/sword/src/hamt.rs +++ b/rust/sword/src/hamt.rs @@ -70,27 +70,27 @@ impl MutHamt { } } - pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> Option { + pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> AllocResult> { 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 None; + break Ok(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 Some(pair.1); + if unifying_equality(stack, n, &mut pair.0)? { + break 'lookup Ok(Some(pair.1)); } } - break None; + break Ok(None); } } } @@ -99,7 +99,7 @@ impl MutHamt { pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> { 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 { @@ -126,7 +126,7 @@ 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; } @@ -145,7 +145,7 @@ impl MutHamt { } else { assert!(leaf.len == 1); let new_stem = stack.struct_alloc::>(1)?; - let leaf_mug = mug_u32(stack, (*leaf.buffer).0); + 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; @@ -308,15 +308,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) -> Option { + pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> AllocResult> { 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 None; + break Ok(None); } Some((Left(next_stem), _idx)) => { stem = next_stem; @@ -324,11 +324,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 Some(pair.1); + if unsafe { unifying_equality(stack, n, &mut pair.0)? } { + break 'lookup Ok(Some(pair.1)); } } - break None; + break Ok(None); } } } @@ -338,7 +338,7 @@ impl Hamt { /// 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); + 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) }?; @@ -395,7 +395,7 @@ 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) { + 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; @@ -448,7 +448,7 @@ impl Hamt { *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), @@ -609,13 +609,13 @@ impl Preserve for Hamt { } impl Persist for Hamt { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { if pma_contains(self.0, 1) { - return 0; + return Ok(0); } let mut bytes: usize = size_of::>(); if pma_contains((*self.0).buffer, (*self.0).size()) { - return bytes; + return Ok(bytes); }; bytes += (*self.0).size() * size_of::>(); @@ -632,7 +632,7 @@ impl Persist for Hamt { assert!(depth < 6); if traversal[depth].bitmap == 0 { if depth == 0 { - break bytes; + break Ok(bytes); } depth -= 1; continue; @@ -680,8 +680,8 @@ impl Persist for Hamt { bytes += size_of::<(Noun, T)>() * leaf.len; while leaf.len > 0 { - bytes += (*leaf.buffer).0.space_needed(stack); - bytes += (*leaf.buffer).1.space_needed(stack); + bytes += (*leaf.buffer).0.space_needed(stack)?; + bytes += (*leaf.buffer).1.space_needed(stack)?; leaf.buffer = leaf.buffer.add(1); leaf.len -= 1; } @@ -689,9 +689,9 @@ impl Persist for Hamt { } } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { if pma_contains(self.0, 1) { - return; + return Ok(()); } let stem_ptr = *buffer as *mut Stem; copy_nonoverlapping(self.0, stem_ptr, 1); @@ -700,7 +700,7 @@ impl Persist for Hamt { let stem_buffer_size = (*stem_ptr).size(); if stem_buffer_size == 0 || pma_contains((*stem_ptr).buffer, stem_buffer_size) { - return; + return Ok(()); } let stem_buffer_ptr = *buffer as *mut Entry; copy_nonoverlapping((*stem_ptr).buffer, stem_buffer_ptr, stem_buffer_size); @@ -785,15 +785,16 @@ impl Persist for Hamt { while leaf_idx < (*leaf_ptr).len { (*(*leaf_ptr).buffer.add(leaf_idx)) .0 - .copy_to_buffer(stack, buffer); + .copy_to_buffer(stack, buffer)?; (*(*leaf_ptr).buffer.add(leaf_idx)) .1 - .copy_to_buffer(stack, buffer); + .copy_to_buffer(stack, buffer)?; leaf_idx += 1; } } } + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -950,13 +951,13 @@ mod test { 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); + let lu = hamt.lookup(&mut stack, &mut n).expect("lookup failed due to OOM"); 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)); + let lu = hamt.lookup(&mut stack, &mut D(2)).expect("lookup failed due to OOM"); let lu_value = unsafe { lu.expect("lookup failed").as_raw() }; assert_eq!(lu_value, 3); } @@ -983,15 +984,15 @@ mod test { let t = D(317365951); hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); - let lu = hamt.lookup(&mut stack, &mut D(0)); + let lu = hamt.lookup(&mut stack, &mut D(0)).expect("lookup failed due to OOM"); 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)); + let lu = hamt.lookup(&mut stack, &mut D(87699370)).expect("lookup failed due to OOM"); 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)); + let lu = hamt.lookup(&mut stack, &mut D(317365951)).expect("lookup failed due to OOM"); let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() }; assert_eq!(lu_value, 317365951); } diff --git a/rust/sword/src/interpreter.rs b/rust/sword/src/interpreter.rs index 5c6b276..3e16607 100644 --- a/rust/sword/src/interpreter.rs +++ b/rust/sword/src/interpreter.rs @@ -435,7 +435,7 @@ pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result< // 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 @@ -568,7 +568,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun debug_assertions(stack, res); mean_frame_push(stack, 0); - *stack.push() = NockWork::Ret; + *stack.push()? = NockWork::Ret; push_formula(stack, res, true)?; } } @@ -626,7 +626,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun Todo5::TestEquals => { let stack = &mut context.stack; let saved_value_ptr = &mut five.left; - res = if unifying_equality(stack, &mut res, saved_value_ptr) { + res = if unifying_equality(stack, &mut res, saved_value_ptr)? { D(0) } else { D(1) @@ -724,7 +724,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun 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; @@ -748,7 +748,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun // jetted code. if context.trace_info.is_some() { if let Some(path) = - context.cold.matches(stack, &mut res) + context.cold.matches(stack, &mut res)? { append_trace(stack, path); }; @@ -767,7 +767,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun subject = res; mean_frame_push(stack, 0); - *stack.push() = NockWork::Ret; + *stack.push()? = NockWork::Ret; push_formula(stack, formula, true)?; // We could trace on 2 as well, but 2 only comes from Hoon via @@ -775,7 +775,7 @@ unsafe fn work(terminator: Arc, context: &mut Context, formula: Noun // jetted code. if context.trace_info.is_some() { if let Some(path) = - context.cold.matches(stack, &mut res) + context.cold.matches(stack, &mut res)? { append_trace(stack, path); }; @@ -1016,7 +1016,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result { - *stack.push() = NockWork::WorkCons(NockCons { + *stack.push()? = NockWork::WorkCons(NockCons { todo: TodoCons::ComputeHead, head: formula_cell.head(), tail: formula_cell.tail(), @@ -1027,20 +1027,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(), @@ -1052,20 +1052,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(), @@ -1078,7 +1078,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(), @@ -1096,7 +1096,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(), @@ -1109,7 +1109,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(), @@ -1123,7 +1123,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(), @@ -1142,7 +1142,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(), @@ -1174,7 +1174,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(), @@ -1194,7 +1194,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(), @@ -1446,10 +1446,16 @@ 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 { - !unifying_equality( + let eq_res = 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); @@ -1503,7 +1509,7 @@ mod hint { Err(_) => return Some(BAIL_EXIT), }; let mut key = key.as_noun(); - context.cache.lookup(stack, &mut key).map(Ok) + context.cache.lookup(stack, &mut key).transpose().map(|r| r.map_err(From::from)) } _ => None, } diff --git a/rust/sword/src/jets.rs b/rust/sword/src/jets.rs index 6c26506..9f6210f 100644 --- a/rust/sword/src/jets.rs +++ b/rust/sword/src/jets.rs @@ -306,13 +306,14 @@ pub mod util { kick(context, core, D(2)) } + #[cfg(test)] pub mod test { use super::*; use crate::hamt::Hamt; use crate::interpreter::Slogger; use crate::mem::{AllocResult, NockStack}; use crate::noun::{Atom, Noun, D, T}; - use crate::unifying_equality::unifying_equality; + use crate::unifying_equality::test::unifying_equality; use assert_no_alloc::assert_no_alloc; use ibig::UBig; diff --git a/rust/sword/src/jets/cold.rs b/rust/sword/src/jets/cold.rs index d581ead..a38f87e 100644 --- a/rust/sword/src/jets/cold.rs +++ b/rust/sword/src/jets/cold.rs @@ -28,19 +28,19 @@ pub type Result = std::result::Result; // Batteries is a core hierarchy (e.g. a path of parent batteries to a root) #[derive(Copy, Clone)] -pub struct Batteries(*mut BatteriesMem); +pub struct Batteries(pub *mut BatteriesMem); const NO_BATTERIES: Batteries = Batteries(null_mut()); #[derive(Copy, Clone)] -struct BatteriesMem { +pub(crate) struct BatteriesMem { battery: Noun, - parent_axis: Atom, + pub(crate) parent_axis: Atom, parent_batteries: Batteries, } impl Persist for Batteries { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { let mut bytes = 0; let mut batteries = *self; @@ -52,14 +52,14 @@ impl Persist for Batteries { break; } bytes += size_of::(); - bytes += (*batteries.0).battery.space_needed(stack); - bytes += (*batteries.0).parent_axis.space_needed(stack); + bytes += (*batteries.0).battery.space_needed(stack)?; + bytes += (*batteries.0).parent_axis.space_needed(stack)?; batteries = (*batteries.0).parent_batteries; } - bytes + Ok(bytes) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { let mut dest = self; loop { if dest.0.is_null() { @@ -81,6 +81,7 @@ impl Persist for Batteries { dest.0 = batteries_mem_ptr; dest = &mut (*dest.0).parent_batteries; } + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -150,7 +151,7 @@ impl Iterator for Batteries { } impl Batteries { - pub fn matches(self, stack: &mut NockStack, mut core: Noun) -> bool { + pub fn matches(self, stack: &mut NockStack, mut core: Noun) -> AllocResult { let mut root_found: bool = false; for (battery, parent_axis) in self { @@ -160,26 +161,26 @@ impl Batteries { if let Ok(d) = parent_axis.as_direct() { if d.data() == 0 { - if unsafe { unifying_equality(stack, &mut core, battery) } { + if unsafe { unifying_equality(stack, &mut core, battery)? } { root_found = true; continue; } else { - return false; + return Ok(false); }; }; }; if let Ok(mut core_battery) = core.slot(2) { - if unsafe { !unifying_equality(stack, &mut core_battery, battery) } { - return false; + if unsafe { !unifying_equality(stack, &mut core_battery, battery)? } { + return Ok(false); }; if let Ok(core_parent) = core.slot_atom(parent_axis) { core = core_parent; continue; } else { - return false; + return Ok(false); } } else { - return false; + return Ok(false); } } @@ -187,7 +188,7 @@ impl Batteries { panic!("cold: core matched exactly, but never matched root"); } - true + Ok(true) } } @@ -205,7 +206,7 @@ struct BatteriesListMem { } impl Persist for BatteriesList { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { let mut bytes = 0; let mut list = *self; loop { @@ -216,14 +217,14 @@ impl Persist for BatteriesList { break; } bytes += size_of::(); - bytes += (*list.0).batteries.space_needed(stack); + bytes += (*list.0).batteries.space_needed(stack)?; list = (*list.0).next; } - bytes + Ok(bytes) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { let mut dest = self; loop { @@ -242,6 +243,7 @@ impl Persist for BatteriesList { (*dest.0).batteries.copy_to_buffer(stack, buffer); dest = &mut (*dest.0).next; } + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -307,8 +309,20 @@ impl Iterator for BatteriesList { } impl BatteriesList { - fn matches(mut self, stack: &mut NockStack, core: Noun) -> Option { - self.find(|&batteries| batteries.matches(stack, core)) + fn matches(self, stack: &mut NockStack, core: Noun) -> AllocResult> { + for batteries in self { + match batteries.matches(stack, core) { + Ok(matched) => { + if matched { + return Ok(Some(batteries)); + } else { + continue; + } + }, + Err(err) => return Err(err), + } + } + Ok(None) } } @@ -326,7 +340,7 @@ pub(crate) struct NounListMem { } impl Persist for NounList { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { let mut bytes: usize = 0; let mut list = *self; @@ -339,14 +353,14 @@ impl Persist for NounList { } bytes += size_of::(); - bytes += (*list.0).element.space_needed(stack); + bytes += (*list.0).element.space_needed(stack)?; list = (*list.0).next; } - bytes + Ok(bytes) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { let mut dest = self; loop { @@ -366,6 +380,7 @@ impl Persist for NounList { dest = &mut (*dest.0).next; } + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -455,21 +470,21 @@ struct ColdMem { } impl Persist for Cold { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { if pma_contains(self.0, 1) { - return 0; + return Ok(0); } let mut bytes = size_of::(); - bytes += (*self.0).battery_to_paths.space_needed(stack); - bytes += (*self.0).root_to_paths.space_needed(stack); - bytes += (*self.0).path_to_batteries.space_needed(stack); - bytes + bytes += (*self.0).battery_to_paths.space_needed(stack)?; + bytes += (*self.0).root_to_paths.space_needed(stack)?; + bytes += (*self.0).path_to_batteries.space_needed(stack)?; + Ok(bytes) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { if pma_contains(self.0, 1) { - return; + return Ok(()); } let cold_mem_ptr = *buffer as *mut ColdMem; @@ -478,9 +493,10 @@ impl Persist for Cold { self.0 = cold_mem_ptr; - (*self.0).battery_to_paths.copy_to_buffer(stack, buffer); - (*self.0).root_to_paths.copy_to_buffer(stack, buffer); - (*self.0).path_to_batteries.copy_to_buffer(stack, buffer); + (*self.0).battery_to_paths.copy_to_buffer(stack, buffer)?; + (*self.0).root_to_paths.copy_to_buffer(stack, buffer)?; + (*self.0).path_to_batteries.copy_to_buffer(stack, buffer)?; + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -553,32 +569,39 @@ impl Cold { } } - pub fn find(&mut self, stack: &mut NockStack, path: &mut Noun) -> BatteriesList { - unsafe { + pub fn find(&mut self, stack: &mut NockStack, path: &mut Noun) -> AllocResult { + Ok(unsafe { (*(self.0)) .path_to_batteries - .lookup(stack, path) + .lookup(stack, path)? .unwrap_or(BATTERIES_LIST_NIL) - } + }) } /** Try to match a core directly to the cold state, print the resulting path if found */ - pub fn matches(&mut self, stack: &mut NockStack, core: &mut Noun) -> Option { - let mut battery = (*core).slot(2).ok()?; + pub fn matches(&mut self, stack: &mut NockStack, core: &mut Noun) -> crate::noun::Result> { + let mut battery = (*core).slot(2)?; unsafe { let paths = (*(self.0)).battery_to_paths.lookup(stack, &mut battery)?; - for path in paths { - if let Some(batteries_list) = - (*(self.0)).path_to_batteries.lookup(stack, &mut (*path)) - { - if let Some(_batt) = batteries_list.matches(stack, *core) { - return Some(*path); + if let Some(paths) = paths { + for path in paths { + if let Some(batteries_list) = (*(self.0)).path_to_batteries.lookup(stack, &mut (*path))? + { + if let Some(_batt) = batteries_list.matches(stack, *core)? { + return Ok(Some(*path)); + } else { + return Ok(None); + } + } else { + return Ok(None); } } + Ok(None) + } else { + Ok(None) } - }; - None + } } /// register a core, return a boolean of whether we actually needed to register (false -> @@ -598,9 +621,9 @@ impl Cold { if let Ok(parent_axis_direct) = parent_axis.as_direct() { if parent_axis_direct.data() == 0 { let mut root_path = T(stack, &[chum, D(0)])?; - if let Some(paths) = (*(self.0)).root_to_paths.lookup(stack, &mut core) { + if let Some(paths) = (*(self.0)).root_to_paths.lookup(stack, &mut core)? { for a_path in paths { - if unifying_equality(stack, &mut root_path, a_path) { + if unifying_equality(stack, &mut root_path, a_path)? { return Ok(false); // it's already in here } } @@ -614,7 +637,7 @@ impl Cold { let current_batteries_list: BatteriesList = (*(self.0)) .path_to_batteries - .lookup(stack, &mut root_path) + .lookup(stack, &mut root_path)? .unwrap_or(BATTERIES_LIST_NIL); let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?; @@ -625,7 +648,7 @@ impl Cold { let current_paths_list: NounList = (*(self.0)) .root_to_paths - .lookup(stack, &mut core) + .lookup(stack, &mut core)? .unwrap_or(NOUN_LIST_NIL); let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?; @@ -657,14 +680,14 @@ impl Cold { let mut battery = core.slot(2)?; let mut parent = core.slot_atom(parent_axis)?; // Check if we already registered this core - if let Some(paths) = (*(self.0)).battery_to_paths.lookup(stack, &mut battery) { + if let Some(paths) = (*(self.0)).battery_to_paths.lookup(stack, &mut battery)? { for path in paths { if let Ok(path_cell) = (*path).as_cell() { - if unifying_equality(stack, &mut path_cell.head(), &mut chum) { + if unifying_equality(stack, &mut path_cell.head(), &mut chum)? { if let Some(batteries_list) = - (*(self.0)).path_to_batteries.lookup(stack, &mut *path) + (*(self.0)).path_to_batteries.lookup(stack, &mut *path)? { - if let Some(_batteries) = batteries_list.matches(stack, core) { + if let Some(_batteries) = batteries_list.matches(stack, core)? { return Ok(false); } } @@ -682,13 +705,13 @@ impl Cold { let mut battery_to_paths = (*(self.0)).battery_to_paths; let root_to_paths = (*(self.0)).root_to_paths; - if let Some(paths) = battery_to_paths.lookup(stack, &mut parent_battery) { + if let Some(paths) = battery_to_paths.lookup(stack, &mut parent_battery)? { for a_path in paths { // path is a reserved word lol let battery_list = path_to_batteries - .lookup(stack, &mut *a_path) + .lookup(stack, &mut *a_path)? .unwrap_or(BATTERIES_LIST_NIL); - if let Some(parent_batteries) = battery_list.matches(stack, parent) { + if let Some(parent_batteries) = battery_list.matches(stack, parent)? { let mut my_path = T(stack, &[chum, *a_path])?; let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1)?; @@ -699,7 +722,7 @@ impl Cold { }; let current_batteries_list = path_to_batteries - .lookup(stack, &mut my_path) + .lookup(stack, &mut my_path)? .unwrap_or(BATTERIES_LIST_NIL); let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?; *batteries_list_mem_ptr = BatteriesListMem { @@ -708,7 +731,7 @@ impl Cold { }; let current_paths_list = battery_to_paths - .lookup(stack, &mut battery) + .lookup(stack, &mut battery)? .unwrap_or(NOUN_LIST_NIL); let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?; *paths_list_mem_ptr = NounListMem { @@ -731,13 +754,13 @@ impl Cold { } }; - if let Some(paths) = root_to_paths.lookup(stack, &mut parent) { + if let Some(paths) = root_to_paths.lookup(stack, &mut parent)? { for a_path in paths { // path is a reserved word lol let battery_list = path_to_batteries - .lookup(stack, &mut *a_path) + .lookup(stack, &mut *a_path)? .unwrap_or(BATTERIES_LIST_NIL); - if let Some(parent_batteries) = battery_list.matches(stack, parent) { + if let Some(parent_batteries) = battery_list.matches(stack, parent)? { let mut my_path = T(stack, &[chum, *a_path])?; let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1)?; @@ -748,7 +771,7 @@ impl Cold { }; let current_batteries_list = path_to_batteries - .lookup(stack, &mut my_path) + .lookup(stack, &mut my_path)? .unwrap_or(BATTERIES_LIST_NIL); let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?; *batteries_list_mem_ptr = BatteriesListMem { @@ -757,7 +780,7 @@ impl Cold { }; let current_paths_list = battery_to_paths - .lookup(stack, &mut battery) + .lookup(stack, &mut battery)? .unwrap_or(NOUN_LIST_NIL); let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?; *paths_list_mem_ptr = NounListMem { @@ -1187,6 +1210,7 @@ pub(crate) mod test { use std::iter::FromIterator; use super::*; + use crate::unifying_equality::test::unifying_equality; use crate::{ hamt::Hamt, mem::NockStack, diff --git a/rust/sword/src/jets/hash.rs b/rust/sword/src/jets/hash.rs index ac70f19..efd1ec7 100644 --- a/rust/sword/src/jets/hash.rs +++ b/rust/sword/src/jets/hash.rs @@ -10,7 +10,7 @@ crate::gdb!(); pub fn jet_mug(context: &mut Context, subject: Noun) -> Result { let arg = slot(subject, 6)?; - Ok(mug(&mut context.stack, arg).as_noun()) + Ok(mug(&mut context.stack, arg)?.as_noun()) } #[cfg(test)] diff --git a/rust/sword/src/jets/list.rs b/rust/sword/src/jets/list.rs index 4ba7aec..a46abb1 100644 --- a/rust/sword/src/jets/list.rs +++ b/rust/sword/src/jets/list.rs @@ -24,7 +24,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result { let mut gate = slot(sample, 3)?; let mut prod = slot(gate, 13)?; - let site = Site::new(context, &mut gate); + let site = Site::new(context, &mut gate)?; loop { if let Ok(list_cell) = list.as_cell() { list = list_cell.tail(); @@ -61,7 +61,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result { // Since the gate doesn't change, we can do a single jet check and use that through the whole // loop - let site = Site::new(context, &mut gate); + let site = Site::new(context, &mut gate)?; loop { if let Ok(list_cell) = list.as_cell() { list = list_cell.tail(); diff --git a/rust/sword/src/jets/lute.rs b/rust/sword/src/jets/lute.rs index 2d5b605..5bd9a2a 100644 --- a/rust/sword/src/jets/lute.rs +++ b/rust/sword/src/jets/lute.rs @@ -27,7 +27,7 @@ pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result { let fun = 141 + tas!(b"crop") + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -57,7 +57,7 @@ pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result { let fun = 141 + tas!(b"fish") + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -86,7 +86,7 @@ pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result { let fun = 141 + tas!(b"fuse") + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -108,7 +108,7 @@ pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result { let vet = slot(van, 59).map_or(NONE, |x| x); let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -139,7 +139,7 @@ pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result { let fun = 141 + tas!(b"mull") + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -174,7 +174,7 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result { let fun = (141 + tas!(b"dext")) + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; @@ -207,7 +207,7 @@ pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result { let fun = 141 + tas!(b"rest") + (flag << 8); let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat])?; - match context.cache.lookup(&mut context.stack, &mut key) { + match context.cache.lookup(&mut context.stack, &mut key)? { Some(pro) => Ok(pro), None => { let pro = interpret(context, subject, slot(subject, 2)?)?; diff --git a/rust/sword/src/jets/parse.rs b/rust/sword/src/jets/parse.rs index d7ad919..e0e5b8c 100644 --- a/rust/sword/src/jets/parse.rs +++ b/rust/sword/src/jets/parse.rs @@ -565,7 +565,7 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result { let puq_vex = slot(q_vex, 6)?; let quq_vex = slot(q_vex, 7)?; - *(context.stack.push::()) = StirPair { + *(context.stack.push::()?) = StirPair { har: p_vex, res: puq_vex, }; diff --git a/rust/sword/src/jets/sort.rs b/rust/sword/src/jets/sort.rs index 2d1712d..eb4d191 100644 --- a/rust/sword/src/jets/sort.rs +++ b/rust/sword/src/jets/sort.rs @@ -24,8 +24,8 @@ pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result { let a = slot(sam, 2)?; let b = slot(sam, 3)?; - let c = mug(stack, a); - let d = mug(stack, b); + let c = mug(stack, a)?; + let d = mug(stack, b)?; match c.data().cmp(&d.data()) { Ordering::Greater => Ok(NO), @@ -41,11 +41,11 @@ pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result { let a = slot(sam, 2)?; let b = slot(sam, 3)?; - let c = mug(stack, a); - let d = mug(stack, b); + let c = mug(stack, a)?; + let d = mug(stack, b)?; - let e = mug(stack, c.as_noun()); - let f = mug(stack, d.as_noun()); + let e = mug(stack, c.as_noun())?; + let f = mug(stack, d.as_noun())?; match e.data().cmp(&f.data()) { Ordering::Greater => Ok(NO), diff --git a/rust/sword/src/jets/warm.rs b/rust/sword/src/jets/warm.rs index b657f48..5a288f2 100644 --- a/rust/sword/src/jets/warm.rs +++ b/rust/sword/src/jets/warm.rs @@ -98,7 +98,7 @@ impl Warm { batteries: Batteries, jet: Jet, ) -> AllocResult<()> { - let current_warm_entry = self.0.lookup(stack, formula).unwrap_or(WARM_ENTRY_NIL); + let current_warm_entry = self.0.lookup(stack, formula)?.unwrap_or(WARM_ENTRY_NIL); unsafe { let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1)?; *warm_entry_mem_ptr = WarmEntryMem { @@ -115,7 +115,7 @@ impl Warm { pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> AllocResult { let mut warm = Self::new(stack)?; for (mut path, axis, jet) in *hot { - let batteries_list = cold.find(stack, &mut path); + let batteries_list = cold.find(stack, &mut path)?; for batteries in batteries_list { let mut batteries_tmp = batteries; let (battery, _parent_axis) = batteries_tmp @@ -141,13 +141,17 @@ impl Warm { stack: &mut NockStack, s: &mut Noun, f: &mut Noun, - ) -> Option<(Jet, Noun)> { + ) -> AllocResult> { let warm_it = self.0.lookup(stack, f)?; - for (path, batteries, jet) in warm_it { - if batteries.matches(stack, *s) { - return Some((jet, path)); + for warm_entry in warm_it { + unsafe { + let jet = (*warm_entry.0).jet; + let path = (*warm_entry.0).path; + if (*warm_entry.0).batteries.matches(stack, *s)? { + return Ok(Some((jet, path))); + } } } - None + Ok(None) } } diff --git a/rust/sword/src/mem.rs b/rust/sword/src/mem.rs index 96190d9..5e30203 100644 --- a/rust/sword/src/mem.rs +++ b/rust/sword/src/mem.rs @@ -90,7 +90,7 @@ pub enum AllocationType { /// Non-size parameters for validating an allocation #[derive(Debug, Clone)] pub struct Allocation { - pub direction: ArenaOrientation, + pub orientation: ArenaOrientation, pub alloc_type: AllocationType, pub pc: bool, } @@ -180,7 +180,7 @@ impl NockStack { pub(crate) fn get_alloc_config(&self, alloc_type: AllocationType) -> Allocation { Allocation { - direction: if self.is_west() { + orientation: if self.is_west() { ArenaOrientation::West } else { ArenaOrientation::East @@ -235,7 +235,7 @@ impl NockStack { // east: // noun_ptr <= *prev_alloc_ptr - size // West: the stack pointer must not overlap the alloc pointer - let (target_point, limit_point, direction) = match (alloc.alloc_type, alloc.direction) { + let (target_point, limit_point, direction) = match (alloc.alloc_type, alloc.orientation) { // West + Alloc, alloc is decreasing (AllocationType::Alloc, ArenaOrientation::West) => { let start_point = self.alloc_pointer as usize; @@ -664,7 +664,7 @@ impl NockStack { } } - unsafe fn copy(&mut self, noun: &mut Noun) { + unsafe fn copy(&mut self, noun: &mut Noun) -> AllocResult<()> { assert_acyclic!(*noun); assert_no_forwarding_pointers!(*noun); assert_no_junior_pointers!(self, *noun); @@ -674,9 +674,9 @@ impl NockStack { let noun_ptr = noun as *mut Noun; // Add two slots to the lightweight stack // Set the first new slot to the noun to be copied - *(self.push::()) = *noun; + *(self.push::()?) = *noun; // Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change - *(self.push::<*mut Noun>()) = noun_ptr; + *(self.push::<*mut Noun>()?) = noun_ptr; loop { if self.stack_is_empty() { break; @@ -735,10 +735,10 @@ impl NockStack { (*alloc).metadata = (*cell.to_raw_pointer()).metadata; // Push the tail and the head to the work stack - *(self.push::()) = cell.tail(); - *(self.push::<*mut Noun>()) = &mut (*alloc).tail; - *(self.push::()) = cell.head(); - *(self.push::<*mut Noun>()) = &mut (*alloc).head; + *(self.push::()?) = cell.tail(); + *(self.push::<*mut Noun>()?) = &mut (*alloc).tail; + *(self.push::()?) = cell.head(); + *(self.push::<*mut Noun>()?) = &mut (*alloc).head; // Set the forwarding pointer cell.set_forwarding_pointer(alloc); @@ -760,6 +760,7 @@ impl NockStack { assert_acyclic!(*noun); assert_no_forwarding_pointers!(*noun); assert_no_junior_pointers!(self, *noun); + Ok(()) } // TODO: #684: Add OOM checks here? Unsure. @@ -923,7 +924,7 @@ impl NockStack { * this violates the _east/_west naming convention somewhat, since e.g. * a west frame when pc == false has a west-oriented lightweight stack, * but when pc == true it becomes east-oriented.*/ - pub unsafe fn push(&mut self) -> *mut T { + pub unsafe fn push(&mut self) -> AllocResult<*mut T> { if self.is_west() && !self.pc || !self.is_west() && self.pc { self.push_west::() } else { @@ -934,37 +935,49 @@ impl NockStack { /** Push onto a west-oriented lightweight stack, moving the stack_pointer. */ // TODO: #684: Add OOM checks here // TODO: Basic alloc function - unsafe fn push_west(&mut self) -> *mut T { + unsafe fn push_west(&mut self) -> AllocResult<*mut T> { + let words = word_size_of::(); + let () = self.alloc_would_oom_(Allocation { orientation: ArenaOrientation::West, alloc_type: AllocationType::Push, pc: self.pc }, words)?; let ap = if self.pc { *(self.prev_alloc_pointer_pointer()) } else { self.alloc_pointer }; let alloc = self.stack_pointer; - let new_sp = self.stack_pointer.add(word_size_of::()); + let new_sp = self.stack_pointer.add(words); if new_sp > ap { - ptr::null_mut() + // Previously we would return a null pointer in this error case. + // Now that we have the alloc_would_oom methods, this shouldn't ever happen. + // ptr::null_mut() + // If it does, somehow, happen, we should panic. + panic!("Out of memory, alloc_would_oom didn't catch it. memory_state: {:#?}", self.memory_state(Some(words))); } else { self.stack_pointer = new_sp; - alloc as *mut T + Ok(alloc as *mut T) } } /** Push onto an east-oriented ligthweight stack, moving the stack_pointer */ // TODO: #684: Add OOM checks here // TODO: Basic alloc function - unsafe fn push_east(&mut self) -> *mut T { + unsafe fn push_east(&mut self) -> AllocResult<*mut T> { + let words = word_size_of::(); + let () = self.alloc_would_oom_(Allocation { orientation: ArenaOrientation::West, alloc_type: AllocationType::Push, pc: self.pc }, words)?; let ap = if self.pc { *(self.prev_alloc_pointer_pointer()) } else { self.alloc_pointer }; - let alloc = self.stack_pointer.sub(word_size_of::()); + let alloc = self.stack_pointer.sub(words); if alloc < ap { - ptr::null_mut() + // Previously we would return a null pointer in this error case. + // Now that we have the alloc_would_oom methods, this shouldn't ever happen. + // ptr::null_mut() + // If it does, somehow, happen, we should panic. + panic!("Out of memory, alloc_would_oom didn't catch it. memory_state: {:#?}", self.memory_state(Some(words))); } else { self.stack_pointer = alloc; - alloc as *mut T + Ok(alloc as *mut T) } } @@ -1283,7 +1296,7 @@ mod test { use super::*; use crate::{ - jets::cold::{test::{make_noun_list, make_test_stack}, NounList, Nounable}, mem::NockStack, noun::D, unifying_equality::unifying_equality, + jets::cold::{test::{make_noun_list, make_test_stack}, NounList, Nounable}, mem::NockStack, noun::D, unifying_equality::test::unifying_equality, }; // cargo test -- test_noun_list_alloc --nocapture diff --git a/rust/sword/src/mug.rs b/rust/sword/src/mug.rs index 77d7942..2af0303 100644 --- a/rust/sword/src/mug.rs +++ b/rust/sword/src/mug.rs @@ -128,9 +128,9 @@ pub fn mug_u32_one(noun: Noun) -> Option { } } -pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 { +pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> AllocResult { if let Some(mug) = get_mug(noun) { - return mug; + return Ok(mug); } assert_acyclic!(noun); @@ -139,7 +139,7 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 { stack.frame_push(0); unsafe { - *(stack.push()) = noun; + *(stack.push()?) = noun; } loop { if stack.stack_is_empty() { @@ -174,8 +174,8 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 { continue; } _ => { - *(stack.push()) = cell.tail(); - *(stack.push()) = cell.head(); + *(stack.push()?) = cell.tail(); + *(stack.push()?) = cell.head(); continue; } } @@ -193,9 +193,10 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 { assert_no_forwarding_pointers!(noun); assert_no_junior_pointers!(stack, noun); - get_mug(noun).expect("Noun should have a mug once it is mugged.") + // TODO: Purge this expect. + Ok(get_mug(noun).expect("Noun should have a mug once it is mugged.")) } -pub fn mug(stack: &mut NockStack, noun: Noun) -> DirectAtom { - unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun) as u64) } +pub fn mug(stack: &mut NockStack, noun: Noun) -> AllocResult { + Ok(unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun)? as u64) }) } diff --git a/rust/sword/src/persist.rs b/rust/sword/src/persist.rs index 7c0e8c2..bc4c280 100644 --- a/rust/sword/src/persist.rs +++ b/rust/sword/src/persist.rs @@ -1,4 +1,4 @@ -use crate::mem::NockStack; +use crate::mem::{AllocResult, NockStack}; use crate::noun::{Allocated, Atom, Cell, CellMemory, IndirectAtom, Noun}; use either::Either::{Left, Right}; use std::convert::TryInto; @@ -116,20 +116,20 @@ pub unsafe fn pma_dirty(ptr: *mut T, count: usize) { pub trait Persist { /// Count how much space is needed, in bytes. May set marks so long as marks are cleaned up by /// [copy_into_buffer] - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize; + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult; /// Copy into the provided buffer, which may be assumed to be at least as large as the size /// returned by [space_needed] on the same structure. - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8); + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()>; /// Persist an object into the PMA using [space_needed] and [copy_to_buffer], returning /// a [u64] (probably a pointer or tagged pointer) that can be saved into metadata. - unsafe fn save_to_pma(&mut self, stack: &mut NockStack) -> u64 { + unsafe fn save_to_pma(&mut self, stack: &mut NockStack) -> AllocResult { unsafe { - let space = self.space_needed(stack); + let space = self.space_needed(stack)?; if space == 0 { - return self.handle_to_u64(); + return Ok(self.handle_to_u64()); } let space_as_pages = (space + (BT_PAGESIZE as usize - 1)) >> BT_PAGEBITS; @@ -139,7 +139,7 @@ pub trait Persist { self.copy_to_buffer(stack, &mut buffer); let space_isize: isize = space.try_into().unwrap(); assert!(buffer.offset_from(orig_buffer) == space_isize); - self.handle_to_u64() + Ok(self.handle_to_u64()) } } @@ -161,17 +161,17 @@ unsafe fn unmark(a: Allocated) { } impl Persist for Atom { - unsafe fn space_needed(&mut self, _stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, _stack: &mut NockStack) -> AllocResult { if let Ok(indirect) = self.as_indirect() { let count = indirect.raw_size(); if !pma_contains(indirect.to_raw_pointer(), count) && !mark(indirect.as_allocated()) { - return count * size_of::(); + return Ok(count * size_of::()); } } - 0 + Ok(0) } - unsafe fn copy_to_buffer(&mut self, _stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, _stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { if let Ok(mut indirect) = self.as_indirect() { let count = indirect.raw_size(); if !pma_contains(indirect.to_raw_pointer(), count) { @@ -188,6 +188,7 @@ impl Persist for Atom { } } } + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -200,10 +201,10 @@ impl Persist for Atom { } impl Persist for Noun { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { let mut space = 0usize; stack.frame_push(0); - *(stack.push::()) = *self; + *(stack.push::()?) = *self; loop { if stack.stack_is_empty() { break; @@ -213,25 +214,25 @@ impl Persist for Noun { match noun.as_either_atom_cell() { Left(mut atom) => { - space += atom.space_needed(stack); + space += atom.space_needed(stack)?; } Right(cell) => { if !pma_contains(cell.to_raw_pointer(), 1) && !mark(cell.as_allocated()) { space += size_of::(); - (*stack.push::()) = cell.tail(); - (*stack.push::()) = cell.head(); + (*stack.push::()?) = cell.tail(); + (*stack.push::()?) = cell.head(); } } } } stack.frame_pop(); - space + Ok(space) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { let mut buffer_u64 = (*buffer) as *mut u64; stack.frame_push(0); - *(stack.push::<*mut Noun>()) = self as *mut Noun; + *(stack.push::<*mut Noun>()?) = self as *mut Noun; loop { if stack.stack_is_empty() { @@ -275,8 +276,8 @@ impl Persist for Noun { *dest = Cell::from_raw_pointer(new_cell_mem).as_noun(); - *(stack.push::<*mut Noun>()) = &mut (*new_cell_mem).tail; - *(stack.push::<*mut Noun>()) = &mut (*new_cell_mem).head; + *(stack.push::<*mut Noun>()?) = &mut (*new_cell_mem).tail; + *(stack.push::<*mut Noun>()?) = &mut (*new_cell_mem).head; buffer_u64 = new_cell_mem.add(1) as *mut u64; } @@ -286,6 +287,7 @@ impl Persist for Noun { } *buffer = buffer_u64 as *mut u8; stack.frame_pop(); + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { diff --git a/rust/sword/src/serf.rs b/rust/sword/src/serf.rs index 804054c..7325038 100644 --- a/rust/sword/src/serf.rs +++ b/rust/sword/src/serf.rs @@ -37,15 +37,15 @@ enum BTMetaField { struct Snapshot(pub *mut SnapshotMem); impl Persist for Snapshot { - unsafe fn space_needed(&mut self, stack: &mut NockStack) -> usize { + unsafe fn space_needed(&mut self, stack: &mut NockStack) -> AllocResult { let mut arvo = (*(self.0)).arvo; let mut cold = (*(self.0)).cold; - let arvo_space_needed = arvo.space_needed(stack); - let cold_space_needed = cold.space_needed(stack); - (((size_of::() + 7) >> 3) << 3) + arvo_space_needed + cold_space_needed + let arvo_space_needed = arvo.space_needed(stack)?; + let cold_space_needed = cold.space_needed(stack)?; + Ok((((size_of::() + 7) >> 3) << 3) + arvo_space_needed + cold_space_needed) } - unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) { + unsafe fn copy_to_buffer(&mut self, stack: &mut NockStack, buffer: &mut *mut u8) -> AllocResult<()> { let snapshot_buffer = *buffer as *mut SnapshotMem; std::ptr::copy_nonoverlapping(self.0, snapshot_buffer, 1); *self = Snapshot(snapshot_buffer); @@ -58,6 +58,7 @@ impl Persist for Snapshot { let mut cold = (*snapshot_buffer).cold; cold.copy_to_buffer(stack, buffer); (*snapshot_buffer).cold = cold; + Ok(()) } unsafe fn handle_to_u64(&self) -> u64 { @@ -131,7 +132,7 @@ impl Context { self.nock_context.cold = (*snapshot.0).cold; handle - }; + }?; pma_meta_set( BTMetaField::SnapshotVersion as usize, PMA_CURRENT_SNAPSHOT_VERSION, @@ -163,7 +164,7 @@ impl Context { let hot = Hot::init(&mut stack, constant_hot_state)?; let warm = Warm::init(&mut stack, &mut cold, &hot)?; - let mug = mug_u32(&mut stack, arvo); + let mug = mug_u32(&mut stack, arvo)?; let slogger = newt.slogger().expect("Newt should make slogger"); let nock_context = interpreter::Context { @@ -206,7 +207,7 @@ impl Context { self.nock_context.scry_stack = D(0); // XX save to PMA - self.mug = mug_u32(&mut self.nock_context.stack, self.arvo); + self.mug = mug_u32(&mut self.nock_context.stack, self.arvo)?; Ok(()) } diff --git a/rust/sword/src/serialization.rs b/rust/sword/src/serialization.rs index 8768063..6939a62 100644 --- a/rust/sword/src/serialization.rs +++ b/rust/sword/src/serialization.rs @@ -109,7 +109,7 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice) -> Resu unsafe { stack.with_frame(0, |stack: &mut NockStack| { - *(stack.push::()) = + *(stack.push::()?) = CueStackEntry::DestinationPointer(&mut result as *mut Noun); loop { if stack.stack_is_empty() { @@ -127,7 +127,7 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice) -> Resu let mut backref_noun = Atom::new(stack, rub_backref(&mut cursor, buffer)?)?.as_noun(); *dest_ptr = backref_map - .lookup(stack, &mut backref_noun) + .lookup(stack, &mut backref_noun)? .ok_or(Deterministic(Exit, D(0)))?; } else { // 10 tag: cell @@ -136,13 +136,13 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice) -> Resu let mut backref_atom = Atom::new(stack, (cursor - 2) as u64)?.as_noun(); backref_map.insert(stack, &mut backref_atom, *dest_ptr); - *(stack.push()) = CueStackEntry::BackRef( + *(stack.push()?) = CueStackEntry::BackRef( cursor as u64 - 2, dest_ptr as *const Noun, ); - *(stack.push()) = + *(stack.push()?) = CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail); - *(stack.push()) = + *(stack.push()?) = CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head); } } else { @@ -284,14 +284,14 @@ pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult { }; stack.frame_push(0); unsafe { - *(stack.push::()) = noun; + *(stack.push::()?) = noun; }; 'jam: loop { if stack.stack_is_empty() { break; } else { let mut noun = unsafe { *(stack.top::()) }; - if let Some(backref) = backref_map.lookup(stack, &mut noun) { + if let Some(backref) = backref_map.lookup(stack, &mut noun)? { match noun.as_either_atom_cell() { Left(atom) => { let atom_size = met0_usize(atom); @@ -324,8 +324,8 @@ pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult { jam_cell(stack, &mut state); unsafe { stack.pop::(); - *(stack.push::()) = cell.tail(); - *(stack.push::()) = cell.head(); + *(stack.push::()?) = cell.tail(); + *(stack.push::()?) = cell.head(); }; continue; } @@ -545,7 +545,7 @@ mod tests { let mut stack = setup_stack(); let mut rng_clone = rng.clone(); - let (original, total_size) = generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone); + let (original, total_size) = generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone).unwrap(); println!( "Total size of all generated nouns: {:.2} KB", @@ -563,7 +563,7 @@ mod tests { assert_noun_eq(&mut stack, cued, original); } - fn generate_random_noun(stack: &mut NockStack, bits: usize, rng: &mut StdRng) -> (Noun, usize) { + fn generate_random_noun(stack: &mut NockStack, bits: usize, rng: &mut StdRng) -> AllocResult<(Noun, usize)> { const MAX_DEPTH: usize = 100; // Adjust this value as needed fn inner( stack: &mut NockStack, @@ -571,7 +571,7 @@ mod tests { rng: &mut StdRng, depth: usize, accumulated_size: usize, - ) -> (Noun, usize) { + ) -> AllocResult<(Noun, usize)> { let mut done = false; if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 { // println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0); @@ -584,25 +584,25 @@ mod tests { let noun = atom.as_noun(); (noun, accumulated_size + noun.mass()) } else { - let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size); - let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size); + let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size)?; + let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size)?; let cell = Cell::new(stack, left, right).unwrap(); let noun = cell.as_noun(); (noun, noun.mass()) }; - if unsafe { result.0.space_needed(stack) } > stack.size() { + if unsafe { result.0.space_needed(stack)? } > stack.size() { eprintln!( "Stack size exceeded with noun size {:.2} KB", result.0.mass() as f64 / 1024.0 ); unsafe { let top_noun = *stack.top::(); - (top_noun, result.1) + Ok((top_noun, result.1)) } } else { - result + Ok(result) } } @@ -613,18 +613,18 @@ mod tests { stack: &mut NockStack, depth: usize, rng: &mut StdRng, - ) -> (Noun, usize) { + ) -> AllocResult<(Noun, usize)> { if depth == 0 { - let (noun, size) = generate_random_noun(stack, 100, rng); - (noun, size) + let (noun, size) = generate_random_noun(stack, 100, rng)?; + Ok((noun, size)) } else { - let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng); - let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng); + let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?; + let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?; let cell = Cell::new(stack, left, right).unwrap(); let mut noun = cell.as_noun(); let total_size = left_size + right_size + noun.mass(); - if unsafe { noun.space_needed(stack) } > stack.size() { + if unsafe { noun.space_needed(stack)? } > stack.size() { eprintln!( "Stack size exceeded at depth {} with noun size {:.2} KB", depth, @@ -632,11 +632,11 @@ mod tests { ); unsafe { let top_noun = *stack.top::(); - (top_noun, total_size) + Ok((top_noun, total_size)) } } else { // println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth); - (noun, total_size) + Ok((noun, total_size)) } } } @@ -662,7 +662,7 @@ mod tests { let mut rng = StdRng::seed_from_u64(1); // Create an atom with a very large value to potentially cause overflow - let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng); + let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng).unwrap(); // Attempt to jam and then cue the large atom in the big stack let jammed = jam(&mut big_stack, large_atom).unwrap(); diff --git a/rust/sword/src/site.rs b/rust/sword/src/site.rs index 7f7a403..3b6840a 100644 --- a/rust/sword/src/site.rs +++ b/rust/sword/src/site.rs @@ -5,6 +5,7 @@ use bitvec::slice::BitSlice; use crate::interpreter::{interpret, Context}; use crate::jets::util::slot; use crate::jets::{Jet, JetErr}; +use crate::mem::AllocResult; use crate::noun::{Noun, D, T}; /// Return Err if the computation crashed or should punt to Nock @@ -19,13 +20,13 @@ pub struct Site { impl Site { /// Prepare a locally cached gate to call repeatedly. - pub fn new(ctx: &mut Context, core: &mut Noun) -> Site { + pub fn new(ctx: &mut Context, core: &mut Noun) -> AllocResult { let mut battery = slot(*core, 2).unwrap(); let context = slot(*core, 7).unwrap(); let warm_result = ctx .warm - .find_jet(&mut ctx.stack, core, &mut battery) + .find_jet(&mut ctx.stack, core, &mut battery)? .filter(|(_jet, mut path)| { // check that 7 is a prefix of the parent battery axis, // to ensure that the sample (axis 6) is not part of the jet match. @@ -34,10 +35,12 @@ impl Site { // jet and we only actually match one of them, but we check all of them and run // unjetted if any have an axis outside 7. let axis_7_bits: &BitSlice = BitSlice::from_element(&7u64); - let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path); + // TODO: This panic is ugly but the code is awkward. + let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path).ok().expect("OOM'd on ctx.cold.find in Site::new"); let mut ret = true; for mut batteries in batteries_list { - if let Some((_battery, parent_axis)) = batteries.next() { + if let Some((_, parent_axis)) = batteries.next() { + // let parent_axis = unsafe { (*battery.0).parent_axis }; let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3]; if parent_axis_prefix_bits == axis_7_bits { continue; @@ -51,13 +54,13 @@ impl Site { } } ret - }); - Site { + }); + Ok(Site { battery, context, jet: warm_result.map(|(jet, _)| jet), path: warm_result.map(|(_, path)| path).unwrap_or(D(0)), - } + }) } } diff --git a/rust/sword/src/unifying_equality.rs b/rust/sword/src/unifying_equality.rs index 267a2f0..0c0830b 100644 --- a/rust/sword/src/unifying_equality.rs +++ b/rust/sword/src/unifying_equality.rs @@ -1,6 +1,7 @@ use crate::assert_acyclic; use crate::assert_no_forwarding_pointers; use crate::assert_no_junior_pointers; +use crate::mem::AllocResult; use crate::mem::{NockStack, ALLOC, FRAME, STACK}; use crate::noun::Noun; use crate::persist::{pma_contains, pma_dirty}; @@ -23,7 +24,18 @@ macro_rules! assert_no_junior_pointers { ( $x:expr, $y:expr ) => {}; } -pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool { +#[cfg(test)] +pub(crate) mod test { + use crate::mem::NockStack; + use crate::noun::Noun; + + /// Tests only, not part of the actual implementation. Use this outside of #[cfg(test)] and I will sic the linter on you. + pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool { + super::unifying_equality(stack, a, b).expect("OOM error in test::unifying_equality") + } +} + +pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> AllocResult { /* This version of unifying equality is not like that of vere. * Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug * equality) and then unifies the nouns at the top level if they are equal. @@ -56,18 +68,18 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou // If the nouns are already word-equal we have nothing to do if (*a).raw_equals(*b) { - return true; + return Ok(true); }; // If the nouns have cached mugs which are disequal we have nothing to do if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) { if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) { if a_mug != b_mug { - return false; + return Ok(false); }; }; }; stack.frame_push(0); - *(stack.push::<(*mut Noun, *mut Noun)>()) = (a, b); + *(stack.push::<(*mut Noun, *mut Noun)>()?) = (a, b); loop { if stack.stack_is_empty() { break; @@ -145,9 +157,9 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou * If both sides are equal, then we will discover pointer * equality when we return and unify the cell. */ - *(stack.push::<(*mut Noun, *mut Noun)>()) = + *(stack.push::<(*mut Noun, *mut Noun)>()?) = (x_cell.tail_as_mut(), y_cell.tail_as_mut()); - *(stack.push::<(*mut Noun, *mut Noun)>()) = + *(stack.push::<(*mut Noun, *mut Noun)>()?) = (x_cell.head_as_mut(), y_cell.head_as_mut()); continue; } @@ -169,7 +181,7 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou assert_no_junior_pointers!(stack, *a); assert_no_junior_pointers!(stack, *b); - (*a).raw_equals(*b) + Ok((*a).raw_equals(*b)) } unsafe fn senior_pointer_first(