From 98d7c14c8c9a17da751ba96b86c41af52b169e14 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Fri, 22 Sep 2023 17:32:15 -0500 Subject: [PATCH 01/15] jets: cold/hot/warm dashboards (not yet integrated) --- rust/ares/src/hamt.rs | 1 + rust/ares/src/interpreter.rs | 25 +- rust/ares/src/jets.rs | 3 + rust/ares/src/jets/cold.rs | 434 +++++++++++++++++++++++++++++++++++ rust/ares/src/jets/hot.rs | 102 ++++++++ rust/ares/src/jets/warm.rs | 71 ++++++ 6 files changed, 624 insertions(+), 12 deletions(-) create mode 100644 rust/ares/src/jets/cold.rs create mode 100644 rust/ares/src/jets/hot.rs create mode 100644 rust/ares/src/jets/warm.rs diff --git a/rust/ares/src/hamt.rs b/rust/ares/src/hamt.rs index 9087cf7f..8733f620 100644 --- a/rust/ares/src/hamt.rs +++ b/rust/ares/src/hamt.rs @@ -255,6 +255,7 @@ assert_eq_size!(&[(Noun, ())], Leaf<()>); // Our custom stem type is the same size as a fat pointer to `Entry`s assert_eq_size!(&[Entry<()>], Stem<()>); +#[derive(Copy, Clone)] pub struct Hamt(Stem); impl Hamt { diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 4e35d9f5..42b943f7 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -726,28 +726,29 @@ pub fn raw_slot(noun: Noun, axis: u64) -> Noun { slot(noun, DirectAtom::new(axis).unwrap().as_bitslice()) } -pub fn slot(mut noun: Noun, axis: &BitSlice) -> Noun { +pub fn slot_result(mut noun: Noun, axis: &BitSlice) -> Result { let mut cursor = if let Some(x) = axis.last_one() { - x + Ok(x) } else { - panic!("0 is not allowed as an axis") - }; + Err(()) + }?; loop { if cursor == 0 { break; }; cursor -= 1; - if let Ok(cell) = noun.as_cell() { - if axis[cursor] { - noun = cell.tail(); - } else { - noun = cell.head(); - } + let cell = noun.as_cell()?; + if axis[cursor] { + noun = cell.tail(); } else { - panic!("Axis tried to descend through atom: {}", noun); + noun = cell.head(); }; } - noun + Ok(noun) +} + +pub fn slot(mut noun: Noun, axis: &BitSlice) -> Noun { + slot_result(noun, axis).expect("Invalid axis into noun.") } fn edit( diff --git a/rust/ares/src/jets.rs b/rust/ares/src/jets.rs index 85534f73..97d7e137 100644 --- a/rust/ares/src/jets.rs +++ b/rust/ares/src/jets.rs @@ -1,4 +1,7 @@ +pub mod cold; +pub mod hot; pub mod math; +pub mod warm; use crate::jets::math::*; use crate::mem::NockStack; diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs new file mode 100644 index 00000000..b29e593a --- /dev/null +++ b/rust/ares/src/jets/cold.rs @@ -0,0 +1,434 @@ +use crate::hamt::{Hamt}; +use crate::interpreter::slot_result; +use crate::mem::{unifying_equality, NockStack, Preserve}; +use crate::noun::{Atom, DirectAtom, Noun, D, T}; +use bitvec::prelude::BitSlice; +use std::ptr::copy_nonoverlapping; +use std::ptr::null_mut; + +#[derive(Copy, Clone)] +pub struct Batteries(*mut BatteriesMem); + +const NO_BATTERIES: Batteries = Batteries(null_mut()); + +#[derive(Copy, Clone)] +struct BatteriesMem { + battery: Noun, + parent_axis: Atom, + parent_batteries: Batteries, +} + +impl Preserve for Batteries { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + if self.0.is_null() { + return; + }; + let mut ptr: *mut *mut BatteriesMem = &mut self.0; + loop { + if stack.is_in_frame(*ptr) { + (**ptr).parent_axis.preserve(stack); + let dest_mem: *mut BatteriesMem = stack.struct_alloc_in_previous_frame(1); + copy_nonoverlapping(*ptr, dest_mem, 1); + if (*dest_mem).parent_batteries.0.is_null() { + break; + }; + ptr = &mut ((*dest_mem).parent_batteries.0); + } else { + break; + } + } + } +} + +impl Iterator for Batteries { + type Item = (*mut Noun, Atom); + fn next(&mut self) -> Option { + if self.0.is_null() { + None + } else { + unsafe { + let res = ( + &mut (*(self.0)).battery as *mut Noun, + (*(self.0)).parent_axis, + ); + *self = (*(self.0)).parent_batteries; + Some(res) + } + } + } +} + +impl Batteries { + pub fn matches(self, stack: &mut NockStack, mut core: Noun) -> bool { + for (battery, parent_axis) in self { + if let Ok(d) = parent_axis.as_direct() { + if d.data() == 0 { + if unsafe { !unifying_equality(stack, &mut core, battery) } { + return false; + }; + }; + }; + if let Ok(mut core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { + if unsafe { !unifying_equality(stack, &mut core, battery) } { + return false; + }; + if let Ok(core_parent) = slot_result(core, parent_axis.as_bitslice()) { + core = core_parent; + continue; + } else { + return false; + } + } else { + return false; + } + } + true + } +} + +#[derive(Copy, Clone)] +struct BatteriesList(*mut BatteriesListMem); + +const BATTERIES_LIST_NIL: BatteriesList = BatteriesList(null_mut()); + +#[derive(Copy, Clone)] +struct BatteriesListMem { + batteries: Batteries, + next: BatteriesList, +} + +impl Preserve for BatteriesList { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + if self.0.is_null() { + return; + }; + let mut ptr: *mut *mut BatteriesListMem = &mut self.0; + loop { + if stack.is_in_frame(*ptr) { + (**ptr).batteries.preserve(stack); + let dest_mem: *mut BatteriesListMem = stack.struct_alloc_in_previous_frame(1); + copy_nonoverlapping(*ptr, dest_mem, 1); + if (*dest_mem).next.0.is_null() { + break; + }; + ptr = &mut ((*dest_mem).next.0); + } else { + break; + } + } + } +} + +impl Iterator for BatteriesList { + type Item = Batteries; + fn next(&mut self) -> Option { + if self.0.is_null() { + None + } else { + unsafe { + let mem = *(self.0); + let res = mem.batteries; + *self = mem.next; + Some(res) + } + } + } +} + +impl BatteriesList { + fn matches(self, stack: &mut NockStack, mut core: Noun) -> Option { + for batteries in self { + if batteries.matches(stack, core) { + return Some(batteries); + } + } + None + } +} + +#[derive(Copy, Clone)] +struct NounList(*mut NounListMem); + +const NOUN_LIST_NIL: NounList = NounList(null_mut()); + +#[derive(Copy, Clone)] +struct NounListMem { + element: Noun, + next: NounList, +} + +impl Preserve for NounList { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + if self.0.is_null() { + return; + }; + let mut ptr: *mut *mut NounListMem = &mut (*self).0; + loop { + if stack.is_in_frame(*ptr) { + (**ptr).element.preserve(stack); + let dest_mem: *mut NounListMem = stack.struct_alloc_in_previous_frame(1); + copy_nonoverlapping(*ptr, dest_mem, 1); + if (*dest_mem).next.0.is_null() { + break; + }; + ptr = &mut ((*dest_mem).next.0); + } else { + break; + } + } + } +} + +impl Iterator for NounList { + type Item = *mut Noun; + fn next(&mut self) -> Option { + if self.0.is_null() { + None + } else { + unsafe { + let res = &mut (*(self.0)).element; + *self = (*(self.0)).next; + Some(res) + } + } + } +} + +pub struct Cold(*mut ColdMem); + +struct ColdMem { + /// key: outermost battery + /// value: registered path to core + battery_to_paths: Hamt, + /// Roots + /// key: root noun + /// value: root path + root_to_paths: Hamt, + /// key: register path to core + /// value: linked list of sequences of nested batteries + path_to_batteries: Hamt, +} + +impl Preserve for Cold { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + (*(self.0)).battery_to_paths.preserve(stack); + (*(self.0)).root_to_paths.preserve(stack); + (*(self.0)).path_to_batteries.preserve(stack); + let new_dest: *mut ColdMem = stack.struct_alloc_in_previous_frame(1); + copy_nonoverlapping(self.0, new_dest, 1); + self.0 = new_dest; + } +} + +impl Cold { + /// register a core, return a boolean of whether we actually needed to register (false -> + /// already registered) + /// + /// XX TODO validate chum + pub fn register( + &mut self, + stack: &mut NockStack, + mut core: Noun, + parent_axis: Atom, + mut chum: Noun, + ) -> Result { + let mut battery = slot_result(core, BitSlice::from_element(&2u64))?; + let mut parent = slot_result(core, parent_axis.as_bitslice())?; + + unsafe { + // Are we registering a root? + 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) { + for mut a_path in paths { + if unsafe { unifying_equality(stack, &mut root_path, a_path) } { + return Ok(false); // it's already in here + } + } + } + let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1); + *batteries_mem_ptr = BatteriesMem { + battery: core, + parent_axis: DirectAtom::new_unchecked(0).as_atom(), + parent_batteries: NO_BATTERIES, + }; + + let current_batteries_list: BatteriesList = (*(self.0)) + .path_to_batteries + .lookup(stack, &mut root_path) + .unwrap_or(BATTERIES_LIST_NIL); + + let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1); + *batteries_list_mem_ptr = BatteriesListMem { + batteries: Batteries(batteries_mem_ptr), + next: current_batteries_list, + }; + + let current_paths_list: NounList = (*(self.0)) + .root_to_paths + .lookup(stack, &mut core) + .unwrap_or(NOUN_LIST_NIL); + + let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1); + *paths_list_mem_ptr = NounListMem { + element: root_path, + next: current_paths_list, + }; + + let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1); + *cold_mem_ptr = ColdMem { + battery_to_paths: (*(self.0)).battery_to_paths, + root_to_paths: (*(self.0)).root_to_paths.insert( + stack, + &mut core, + NounList(paths_list_mem_ptr), + ), + path_to_batteries: (*(self.0)).path_to_batteries.insert( + stack, + &mut root_path, + BatteriesList(batteries_list_mem_ptr), + ), + }; + + *self = Cold(cold_mem_ptr); + return Ok(true); + } + } + + // Check if we already registered this core + 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 let Some(batteries_list) = + (*(self.0)).path_to_batteries.lookup(stack, &mut *path) + { + if let Some(_batteries) = batteries_list.matches(stack, core) { + return Ok(false); + } + } + } + } + } + } + + let mut parent_battery = slot_result(parent, BitSlice::from_element(&2u64))?; + + let mut ret: Result = Err(()); // err until we actually found a parent + + let mut path_to_batteries = (*(self.0)).path_to_batteries; + let mut battery_to_paths = (*(self.0)).battery_to_paths; + let mut root_to_paths = (*(self.0)).root_to_paths; + + if let Some(paths) = battery_to_paths.lookup(stack, &mut parent_battery) { + for mut a_path in paths { + // path is a reserved word lol + let battery_list = path_to_batteries + .lookup(stack, &mut *a_path) + .unwrap_or(BATTERIES_LIST_NIL); + if let Some(parent_batteries) = battery_list.matches(stack, core) { + let mut my_path = T(stack, &[chum, *a_path]); + + let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1); + *batteries_mem_ptr = BatteriesMem { + battery: battery, + parent_axis: parent_axis, + parent_batteries: parent_batteries, + }; + + let current_batteries_list = path_to_batteries + .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 { + batteries: Batteries(batteries_mem_ptr), + next: current_batteries_list, + }; + + let current_paths_list = battery_to_paths + .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 { + element: my_path, + next: current_paths_list, + }; + + path_to_batteries = path_to_batteries.insert( + stack, + &mut my_path, + BatteriesList(batteries_list_mem_ptr), + ); + battery_to_paths = battery_to_paths.insert( + stack, + &mut battery, + NounList(paths_list_mem_ptr), + ); + ret = Ok(true); + } + } + }; + + if let Some(paths) = root_to_paths.lookup(stack, &mut parent) { + for mut a_path in paths { + // path is a reserved word lol + let battery_list = path_to_batteries + .lookup(stack, &mut *a_path) + .unwrap_or(BATTERIES_LIST_NIL); + if let Some(parent_batteries) = battery_list.matches(stack, core) { + let mut my_path = T(stack, &[chum, *a_path]); + + let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1); + *batteries_mem_ptr = BatteriesMem { + battery: battery, + parent_axis: parent_axis, + parent_batteries: parent_batteries, + }; + + let current_batteries_list = path_to_batteries + .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 { + batteries: Batteries(batteries_mem_ptr), + next: current_batteries_list, + }; + + let current_paths_list = battery_to_paths + .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 { + element: my_path, + next: current_paths_list, + }; + + path_to_batteries = path_to_batteries.insert( + stack, + &mut my_path, + BatteriesList(batteries_list_mem_ptr), + ); + battery_to_paths = battery_to_paths.insert( + stack, + &mut battery, + NounList(paths_list_mem_ptr), + ); + ret = Ok(true); + } + } + }; + + let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1); + *cold_mem_ptr = ColdMem { + battery_to_paths: battery_to_paths, + root_to_paths: root_to_paths, + path_to_batteries: path_to_batteries, + }; + + *self = Cold(cold_mem_ptr); + ret + } + } +} + diff --git a/rust/ares/src/jets/hot.rs b/rust/ares/src/jets/hot.rs new file mode 100644 index 00000000..7c553d65 --- /dev/null +++ b/rust/ares/src/jets/hot.rs @@ -0,0 +1,102 @@ +use crate::jets::*; +use crate::noun::{Atom, DirectAtom, Noun, D, T}; +use ares_macros::tas; +use either::Either::{self, Left, Right}; +use std::ptr::null_mut; + +const A_50: Either = Right((tas!(b"a"), 50)); + +// This is the const state all in one spot as literals +const HOT_STATE: &[(&[Either], u64, Jet)] = &[ + (&[A_50, Left(tas!(b"dec"))], 1, jet_dec), + (&[A_50, Left(tas!(b"add"))], 1, jet_add), + (&[A_50, Left(tas!(b"sub"))], 1, jet_sub), + (&[A_50, Left(tas!(b"mul"))], 1, jet_mul), + (&[A_50, Left(tas!(b"div"))], 1, jet_div), + (&[A_50, Left(tas!(b"mod"))], 1, jet_mod), + (&[A_50, Left(tas!(b"dvr"))], 1, jet_dvr), + (&[A_50, Left(tas!(b"lth"))], 1, jet_lth), + (&[A_50, Left(tas!(b"lte"))], 1, jet_lte), + (&[A_50, Left(tas!(b"gth"))], 1, jet_gth), + (&[A_50, Left(tas!(b"gte"))], 1, jet_gte), + (&[A_50, Left(tas!(b"bex"))], 1, jet_bex), + (&[A_50, Left(tas!(b"lsh"))], 1, jet_lsh), + (&[A_50, Left(tas!(b"rsh"))], 1, jet_rsh), + (&[A_50, Left(tas!(b"con"))], 1, jet_con), + (&[A_50, Left(tas!(b"dis"))], 1, jet_dis), + (&[A_50, Left(tas!(b"mix"))], 1, jet_mix), + (&[A_50, Left(tas!(b"end"))], 1, jet_end), + (&[A_50, Left(tas!(b"cat"))], 1, jet_cat), + (&[A_50, Left(tas!(b"cut"))], 1, jet_cut), + (&[A_50, Left(tas!(b"can"))], 1, jet_can), + (&[A_50, Left(tas!(b"rep"))], 1, jet_rep), + (&[A_50, Left(tas!(b"rip"))], 1, jet_rip), + (&[A_50, Left(tas!(b"met"))], 1, jet_met), + (&[A_50, Left(tas!(b"mug"))], 1, jet_mug), + (&[A_50, Left(tas!(b"rev"))], 1, jet_rev), +]; + +#[derive(Copy, Clone)] +struct Hot(*mut HotMem); + +impl Hot { + pub fn init(stack: &mut NockStack) -> Self { + unsafe { + let mut next = Hot(null_mut()); + for (htap, axe, jet) in HOT_STATE { + let mut a_path = D(0); + for i in *htap { + match i { + Left(tas) => { + a_path = T( + stack, + &[DirectAtom::new_panic(*tas).as_atom().as_noun(), a_path], + ); + } + Right((tas, ver)) => { + let chum = T( + stack, + &[ + DirectAtom::new_panic(*tas).as_atom().as_noun(), + DirectAtom::new_panic(*ver).as_atom().as_noun(), + ], + ); + a_path = T(stack, &[chum, a_path]); + } + }; + } + let axis = DirectAtom::new_panic(*axe).as_atom(); + let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1); + *hot_mem_ptr = HotMem { + a_path: a_path, + axis: axis, + jet: *jet, + next: next, + }; + next = Hot(hot_mem_ptr); + } + next + } + } +} + +impl Iterator for Hot { + type Item = (Noun, Atom, Jet); // path,axis,jet + fn next(&mut self) -> Option { + if self.0.is_null() { + return None; + } + unsafe { + let res = ((*(self.0)).a_path, (*(self.0)).axis, (*(self.0)).jet); + *self = (*(self.0)).next; + Some(res) + } + } +} + +struct HotMem { + a_path: Noun, + axis: Atom, // Axis of jetted formula in *battery*; + jet: Jet, + next: Hot, +} diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs new file mode 100644 index 00000000..0a2ea5cf --- /dev/null +++ b/rust/ares/src/jets/warm.rs @@ -0,0 +1,71 @@ +use crate::hamt::Hamt; +use crate::jets::cold::Batteries; +use crate::jets::Jet; +use crate::mem::{NockStack, Preserve}; +use crate::noun::Noun; +use std::ptr::copy_nonoverlapping; + +struct Warm(Hamt); + +impl Preserve for Warm { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + self.0.preserve(stack); + } +} + +#[derive(Copy, Clone)] +struct WarmEntry(*mut WarmEntryMem); + +struct WarmEntryMem { + batteries: Batteries, + jet: Jet, + next: WarmEntry, +} + +impl Preserve for WarmEntry { + unsafe fn preserve(&mut self, stack: &mut NockStack) { + if self.0.is_null() { + return; + } + let mut ptr: *mut *mut WarmEntryMem = &mut self.0; + loop { + if stack.is_in_frame(*ptr) { + (**ptr).batteries.preserve(stack); + let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1); + copy_nonoverlapping(*ptr, dest_mem, 1); + if (*dest_mem).next.0.is_null() { + break; + }; + ptr = &mut ((*dest_mem).next.0); + } else { + break; + } + } + } +} + +impl Iterator for WarmEntry { + type Item = (Batteries, Jet); + fn next(&mut self) -> Option { + if self.0.is_null() { + return None; + } + unsafe { + let res = ((*(self.0)).batteries, (*(self.0)).jet); + *self = (*(self.0)).next; + Some(res) + } + } +} + +impl Warm { + pub fn find_jet(&mut self, stack: &mut NockStack, s: &mut Noun, f: &mut Noun) -> Option { + let warm_it = self.0.lookup(stack, f)?; + for (batteries, jet) in warm_it { + if batteries.matches(stack, *s) { + return Some(jet); + } + } + None + } +} From 95e1df9433f1cc3a5540109e0314258cbdc70a2e Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Fri, 22 Sep 2023 17:46:25 -0500 Subject: [PATCH 02/15] jets: lints and formatting --- rust/ares/src/interpreter.rs | 2 +- rust/ares/src/jets/cold.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 42b943f7..7f1d196e 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -747,7 +747,7 @@ pub fn slot_result(mut noun: Noun, axis: &BitSlice) -> Result) -> Noun { +pub fn slot(noun: Noun, axis: &BitSlice) -> Noun { slot_result(noun, axis).expect("Invalid axis into noun.") } diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index b29e593a..7d15be03 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -1,4 +1,4 @@ -use crate::hamt::{Hamt}; +use crate::hamt::Hamt; use crate::interpreter::slot_result; use crate::mem::{unifying_equality, NockStack, Preserve}; use crate::noun::{Atom, DirectAtom, Noun, D, T}; @@ -68,7 +68,7 @@ impl Batteries { }; }; }; - if let Ok(mut core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { + if let Ok(_core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { if unsafe { !unifying_equality(stack, &mut core, battery) } { return false; }; @@ -136,7 +136,7 @@ impl Iterator for BatteriesList { } impl BatteriesList { - fn matches(self, stack: &mut NockStack, mut core: Noun) -> Option { + fn matches(self, stack: &mut NockStack, core: Noun) -> Option { for batteries in self { if batteries.matches(stack, core) { return Some(batteries); @@ -241,8 +241,8 @@ impl Cold { 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) { - for mut a_path in paths { - if unsafe { unifying_equality(stack, &mut root_path, a_path) } { + for a_path in paths { + if unifying_equality(stack, &mut root_path, a_path) { return Ok(false); // it's already in here } } @@ -319,10 +319,10 @@ impl Cold { let mut path_to_batteries = (*(self.0)).path_to_batteries; let mut battery_to_paths = (*(self.0)).battery_to_paths; - let mut root_to_paths = (*(self.0)).root_to_paths; + let root_to_paths = (*(self.0)).root_to_paths; if let Some(paths) = battery_to_paths.lookup(stack, &mut parent_battery) { - for mut a_path in paths { + for a_path in paths { // path is a reserved word lol let battery_list = path_to_batteries .lookup(stack, &mut *a_path) @@ -371,7 +371,7 @@ impl Cold { }; if let Some(paths) = root_to_paths.lookup(stack, &mut parent) { - for mut a_path in paths { + for a_path in paths { // path is a reserved word lol let battery_list = path_to_batteries .lookup(stack, &mut *a_path) @@ -431,4 +431,3 @@ impl Cold { } } } - From 8e857f7c86be6f033941cb7e0c2f0e0556548219 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Fri, 22 Sep 2023 19:57:08 -0500 Subject: [PATCH 03/15] jets: fast dashboard plumbed in: attempt matches on 2 and 9, register on 11 --- rust/ares/src/interpreter.rs | 66 ++++++++++++++++++++++++++++++++---- rust/ares/src/jets/cold.rs | 21 +++++++++++- rust/ares/src/jets/hot.rs | 2 +- rust/ares/src/jets/warm.rs | 54 +++++++++++++++++++++++++---- rust/ares/src/main.rs | 8 ++++- rust/ares/src/serf.rs | 18 ++++++---- 6 files changed, 147 insertions(+), 22 deletions(-) diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 7f1d196e..a13962bd 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -1,5 +1,8 @@ use crate::hamt::Hamt; use crate::jets; +use crate::jets::cold::Cold; +use crate::jets::warm::Warm; +use crate::jets::hot::Hot; use crate::mem::unifying_equality; use crate::mem::NockStack; use crate::newt::Newt; @@ -227,6 +230,9 @@ enum NockWork { pub fn interpret( stack: &mut NockStack, newt: &mut Option<&mut Newt>, // For printing slogs; if None, print to stdout + cold: &mut Cold, + warm: &mut Warm, + hot: Hot, mut subject: Noun, formula: Noun, ) -> Noun { @@ -255,12 +261,16 @@ pub fn interpret( NockWork::Done => { stack.preserve(&mut cache); stack.preserve(&mut res); + stack.preserve(cold); + stack.preserve(warm); stack.frame_pop(); break; } NockWork::Ret => { stack.preserve(&mut cache); stack.preserve(&mut res); + stack.preserve(cold); + stack.preserve(warm); stack.frame_pop(); } NockWork::WorkCons(mut cons) => match cons.todo { @@ -301,6 +311,13 @@ pub fn interpret( push_formula(stack, vale.formula, false); } Todo2::ComputeResult => { + if let Some(jet) = warm.find_jet(stack, &mut vale.subject, &mut res) { // a jet match + if let Ok(jet_res) = jet(stack, vale.subject) { // XX TODO: nondeterministic errors + res = jet_res; + stack.pop::(); + continue; + } + }; if vale.tail { stack.pop::(); subject = vale.subject; @@ -443,7 +460,14 @@ pub fn interpret( push_formula(stack, kale.core, false); } Todo9::ComputeResult => { - let formula = slot(res, kale.axis.as_bitslice()); + let mut formula = slot(res, kale.axis.as_bitslice()); + if let Some(jet) = warm.find_jet(stack, &mut res, &mut formula) { // a jet match + if let Ok(jet_res) = jet(stack, res) { // XX TODO: nondeterministic errors + res = jet_res; + stack.pop::(); + continue; + }; + }; if kale.tail { stack.pop::(); subject = res; @@ -486,7 +510,7 @@ pub fn interpret( Todo11D::ComputeHint => { let hint_cell = Cell::new(stack, dint.tag.as_noun(), dint.hint); if let Ok(found) = - match_pre_hint(stack, newt, subject, hint_cell, formula, &cache) + match_pre_hint(stack, newt, cold, warm, hot, subject, hint_cell, formula, &cache) { res = found; stack.pop::(); @@ -510,7 +534,7 @@ pub fn interpret( } Todo11D::Done => { let hint = Cell::new(stack, dint.tag.as_noun(), dint.hint).as_noun(); - let _ = match_post_hinted(stack, subject, hint, res, &mut cache); + let _ = match_post_hinted(stack, subject, hint, res, &mut cache, cold, warm, hot); stack.pop::(); } }, @@ -530,7 +554,7 @@ pub fn interpret( } Todo11S::Done => { let _ = - match_post_hinted(stack, subject, sint.tag.as_noun(), res, &mut cache); + match_post_hinted(stack, subject, sint.tag.as_noun(), res, &mut cache, cold, warm, hot); stack.pop::(); } }, @@ -723,7 +747,11 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) { /** Note: axis must fit in a direct atom */ pub fn raw_slot(noun: Noun, axis: u64) -> Noun { - slot(noun, DirectAtom::new(axis).unwrap().as_bitslice()) + slot(noun, &BitSlice::from_element(&axis)) +} + +pub fn raw_slot_result(noun: Noun, axis: u64) -> Result { + slot_result(noun, &BitSlice::from_element(&axis)) } pub fn slot_result(mut noun: Noun, axis: &BitSlice) -> Result { @@ -825,6 +853,9 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { fn match_pre_hint( stack: &mut NockStack, newt: &mut Option<&mut Newt>, + cold: &mut Cold, + warm: &mut Warm, + hot: Hot, subject: Noun, cell: Cell, formula: Noun, @@ -836,12 +867,11 @@ fn match_pre_hint( tas!(b"sham") => { let jet_formula = cell.tail().as_cell()?; let jet_name = jet_formula.tail(); - let jet = jets::get_jet(jet_name).ok_or(())?; if let Ok(mut jet_res) = jet(stack, subject) { // if in test mode, check that the jet returns the same result as the raw nock if jets::get_jet_test_mode(jet_name) { - let mut nock_res = interpret(stack, newt, subject, formula); + let mut nock_res = interpret(stack, newt, cold, warm, hot, subject, formula); if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } { eprintln!( "\rJet {} failed, raw: {}, jetted: {}", @@ -901,6 +931,9 @@ fn match_post_hinted( hint: Noun, res: Noun, cache: &mut Hamt, + cold: &mut Cold, + warm: &mut Warm, + hot: Hot ) -> Result<(), ()> { let direct = hint.as_cell()?.head().as_direct()?; match direct.data() { @@ -909,6 +942,25 @@ fn match_post_hinted( let mut key = Cell::new(stack, subject, formula).as_noun(); *cache = cache.insert(stack, &mut key, res); Ok(()) + }, + tas!(b"fast") => { + let clue = raw_slot_result(hint, 2)?; + let chum = raw_slot_result(clue, 2)?; + let parent_formula_op = raw_slot_result(clue, 12)?.as_atom()?.as_direct()?; + let parent_formula_ax = raw_slot_result(clue, 13)?.as_atom()?; + if parent_formula_op.data() == 1 { + if parent_formula_ax.as_direct()?.data() == 0 { + let changed = cold.register(stack, res, parent_formula_ax, chum)?; + if changed { *warm = Warm::init(stack, cold, hot); } + Ok(()) + } else { + Err(()) + } + } else { + let changed = cold.register(stack, res, parent_formula_ax, chum)?; + if changed { *warm = Warm::init(stack, cold, hot); } + Ok(()) + } } _ => Err(()), } diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index 7d15be03..c6f2d75b 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -87,7 +87,7 @@ impl Batteries { } #[derive(Copy, Clone)] -struct BatteriesList(*mut BatteriesListMem); +pub struct BatteriesList(*mut BatteriesListMem); const BATTERIES_LIST_NIL: BatteriesList = BatteriesList(null_mut()); @@ -221,6 +221,25 @@ impl Preserve for Cold { } impl Cold { + pub fn new(stack: &mut NockStack) -> Self { + let battery_to_paths = Hamt::new(); + let root_to_paths = Hamt::new(); + let path_to_batteries = Hamt::new(); + unsafe { + let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1); + *cold_mem_ptr = ColdMem { + battery_to_paths: battery_to_paths, + root_to_paths: root_to_paths, + path_to_batteries: path_to_batteries, + }; + Cold(cold_mem_ptr) + } + } + + pub fn find(&mut self, stack: &mut NockStack, path: &mut Noun) -> BatteriesList { + unsafe { (*(self.0)).path_to_batteries.lookup(stack, path).unwrap_or(BATTERIES_LIST_NIL) } + } + /// register a core, return a boolean of whether we actually needed to register (false -> /// already registered) /// diff --git a/rust/ares/src/jets/hot.rs b/rust/ares/src/jets/hot.rs index 7c553d65..0c59b3b6 100644 --- a/rust/ares/src/jets/hot.rs +++ b/rust/ares/src/jets/hot.rs @@ -37,7 +37,7 @@ const HOT_STATE: &[(&[Either], u64, Jet)] = &[ ]; #[derive(Copy, Clone)] -struct Hot(*mut HotMem); +pub struct Hot(*mut HotMem); impl Hot { pub fn init(stack: &mut NockStack) -> Self { diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index 0a2ea5cf..2cf34f21 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -1,11 +1,13 @@ use crate::hamt::Hamt; -use crate::jets::cold::Batteries; +use crate::interpreter::slot_result; +use crate::jets::cold::{Batteries,Cold}; +use crate::jets::hot::{Hot}; use crate::jets::Jet; use crate::mem::{NockStack, Preserve}; use crate::noun::Noun; -use std::ptr::copy_nonoverlapping; +use std::ptr::{copy_nonoverlapping, null_mut}; -struct Warm(Hamt); +pub struct Warm(Hamt); impl Preserve for Warm { unsafe fn preserve(&mut self, stack: &mut NockStack) { @@ -16,9 +18,12 @@ impl Preserve for Warm { #[derive(Copy, Clone)] struct WarmEntry(*mut WarmEntryMem); +const WARM_ENTRY_NIL: WarmEntry = WarmEntry(null_mut()); + struct WarmEntryMem { batteries: Batteries, jet: Jet, + path: Noun, // useful for profiling/debugging next: WarmEntry, } @@ -31,6 +36,7 @@ impl Preserve for WarmEntry { loop { if stack.is_in_frame(*ptr) { (**ptr).batteries.preserve(stack); + (**ptr).path.preserve(stack); let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(*ptr, dest_mem, 1); if (*dest_mem).next.0.is_null() { @@ -45,13 +51,13 @@ impl Preserve for WarmEntry { } impl Iterator for WarmEntry { - type Item = (Batteries, Jet); + type Item = (Noun, Batteries, Jet); fn next(&mut self) -> Option { if self.0.is_null() { return None; } unsafe { - let res = ((*(self.0)).batteries, (*(self.0)).jet); + let res = ((*(self.0)).path, (*(self.0)).batteries, (*(self.0)).jet); *self = (*(self.0)).next; Some(res) } @@ -59,9 +65,45 @@ impl Iterator for WarmEntry { } impl Warm { + pub fn new() -> Self { + Warm(Hamt::new()) + } + + fn insert(&mut self, stack: &mut NockStack, formula: &mut Noun, path: Noun, batteries: Batteries, jet: Jet) { + 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 { + batteries: batteries, + jet: jet, + path: path, + next: current_warm_entry, + }; + self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr)); + } + } + + pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: Hot) -> Self { + let mut warm = Self::new(); + for (mut path, axis, jet) in hot { + let batteries_list = cold.find(stack, &mut path); + for batteries in batteries_list { + let mut batteries_tmp = batteries; + let (mut battery, _parent_axis) = batteries_tmp.next().expect("IMPOSSIBLE: empty battery entry in cold state"); + if let Ok(mut formula) = unsafe { slot_result(*battery, axis.as_bitslice()) } { + warm.insert(stack, &mut formula, path, batteries, jet); + } else { + eprintln!("Bad axis {} into formula {:?}", axis, battery); + continue + } + } + } + warm + } + pub fn find_jet(&mut self, stack: &mut NockStack, s: &mut Noun, f: &mut Noun) -> Option { let warm_it = self.0.lookup(stack, f)?; - for (batteries, jet) in warm_it { + for (path, batteries, jet) in warm_it { if batteries.matches(stack, *s) { return Some(jet); } diff --git a/rust/ares/src/main.rs b/rust/ares/src/main.rs index 416d2ed7..f46a2d3d 100644 --- a/rust/ares/src/main.rs +++ b/rust/ares/src/main.rs @@ -1,4 +1,7 @@ use ares::interpreter::interpret; +use ares::jets::cold::Cold; +use ares::jets::warm::Warm; +use ares::jets::hot::Hot; use ares::mem::NockStack; use ares::noun::IndirectAtom; use ares::serf::serf; @@ -39,6 +42,9 @@ fn main() -> io::Result<()> { let f = File::open(filename)?; let in_len = f.metadata()?.len(); let mut stack = NockStack::new(8 << 10 << 10, 0); + let mut cold = Cold::new(&mut stack); + let mut warm = Warm::new(); + let hot = Hot::init(&mut stack); let jammed_input = unsafe { let in_map = Mmap::map(&f)?; let word_len = (in_len + 7) >> 3; @@ -52,7 +58,7 @@ fn main() -> io::Result<()> { let input_cell = input .as_cell() .expect("Input must be jam of subject/formula pair"); - let result = interpret(&mut stack, &mut None, input_cell.head(), input_cell.tail()); + let result = interpret(&mut stack, &mut None, &mut cold, &mut warm, hot, input_cell.head(), input_cell.tail()); if let Ok(atom) = result.as_atom() { println!("Result: {}", atom); } diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index 76600502..6112249e 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -1,4 +1,7 @@ use crate::interpreter::{interpret, raw_slot}; +use crate::jets::cold::Cold; +use crate::jets::warm::Warm; +use crate::jets::hot::Hot; use crate::mem::NockStack; use crate::mug::mug_u32; use crate::newt::Newt; @@ -38,6 +41,9 @@ pub fn serf() -> io::Result<()> { let snap = &mut snapshot::double_jam::DoubleJam::new(snap_path); let stack = &mut NockStack::new(96 << 10 << 10, 0); + let mut cold = Cold::new(stack); + let mut warm = Warm::new(); + let hot = Hot::init(stack); let newt = &mut Newt::new(); let (_epoch, mut event_number, mut arvo) = snap.load(stack).unwrap_or((0, 0, D(0))); @@ -67,7 +73,7 @@ pub fn serf() -> io::Result<()> { } tas!(b"peek") => { let sam = raw_slot(writ, 7); - let res = slam(stack, newt, arvo, PEEK_AXIS, sam); + let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, PEEK_AXIS, sam); newt.peek_done(stack, res); } tas!(b"play") => { @@ -76,7 +82,7 @@ pub fn serf() -> io::Result<()> { let lit = raw_slot(writ, 7); let sub = T(stack, &[D(0), D(3)]); let lyf = T(stack, &[D(2), sub, D(0), D(2)]); - let gat = interpret(stack, &mut Some(newt), lit, lyf); + let gat = interpret(stack, &mut Some(newt), &mut cold, &mut warm, hot, lit, lyf); arvo = raw_slot(gat, 7); false } else { @@ -90,7 +96,7 @@ pub fn serf() -> io::Result<()> { while let Ok(cell) = lit.as_cell() { if run { let ovo = cell.head(); - let res = slam(stack, newt, arvo, POKE_AXIS, ovo).as_cell().unwrap(); + let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo).as_cell().unwrap(); arvo = res.tail(); } event_number += 1; @@ -102,7 +108,7 @@ pub fn serf() -> io::Result<()> { } tas!(b"work") => { let ovo = raw_slot(writ, 7); - let res = slam(stack, newt, arvo, POKE_AXIS, ovo).as_cell().unwrap(); + let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo).as_cell().unwrap(); let fec = res.head(); arvo = res.tail(); snap.save(stack, &mut arvo); @@ -118,10 +124,10 @@ pub fn serf() -> io::Result<()> { Ok(()) } -pub fn slam(stack: &mut NockStack, newt: &mut Newt, core: Noun, axis: u64, ovo: Noun) -> Noun { +pub fn slam(stack: &mut NockStack, newt: &mut Newt, cold: &mut Cold, warm: &mut Warm, hot: Hot, core: Noun, axis: u64, ovo: Noun) -> Noun { let pul = T(stack, &[D(9), D(axis), D(0), D(2)]); let sam = T(stack, &[D(6), D(0), D(7)]); let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]); let sub = T(stack, &[core, ovo]); - interpret(stack, &mut Some(newt), sub, fol) + interpret(stack, &mut Some(newt), cold, warm, hot, sub, fol) } From 45eb2fe74481c259632fd9ab99211698faf6c017 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Fri, 22 Sep 2023 23:11:59 -0500 Subject: [PATCH 04/15] jets: dashboard functional --- rust/ares/src/interpreter.rs | 12 +++++------- rust/ares/src/jets/cold.rs | 24 ++++++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index a13962bd..19e2cd05 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -8,7 +8,7 @@ use crate::mem::NockStack; use crate::newt::Newt; use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, T}; use ares_macros::tas; -use assert_no_alloc::assert_no_alloc; +use assert_no_alloc::{assert_no_alloc}; use bitvec::prelude::{BitSlice, Lsb0}; use either::Either::*; @@ -510,7 +510,7 @@ pub fn interpret( Todo11D::ComputeHint => { let hint_cell = Cell::new(stack, dint.tag.as_noun(), dint.hint); if let Ok(found) = - match_pre_hint(stack, newt, cold, warm, hot, subject, hint_cell, formula, &cache) + match_pre_hint(stack, newt, subject, hint_cell, formula, &cache) { res = found; stack.pop::(); @@ -853,9 +853,6 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { fn match_pre_hint( stack: &mut NockStack, newt: &mut Option<&mut Newt>, - cold: &mut Cold, - warm: &mut Warm, - hot: Hot, subject: Noun, cell: Cell, formula: Noun, @@ -864,6 +861,7 @@ fn match_pre_hint( let direct = cell.head().as_direct()?; match direct.data() { // %sham hints are scaffolding until we have a real jet dashboard + /* tas!(b"sham") => { let jet_formula = cell.tail().as_cell()?; let jet_name = jet_formula.tail(); @@ -886,7 +884,7 @@ fn match_pre_hint( eprintln!("\rJet {} failed", jet_name); Err(()) } - } + }*/ tas!(b"memo") => { let formula = unsafe { *stack.local_noun_pointer(2) }; let mut key = Cell::new(stack, subject, formula).as_noun(); @@ -944,7 +942,7 @@ fn match_post_hinted( Ok(()) }, tas!(b"fast") => { - let clue = raw_slot_result(hint, 2)?; + let clue = raw_slot_result(hint, 7)?; let chum = raw_slot_result(clue, 2)?; let parent_formula_op = raw_slot_result(clue, 12)?.as_atom()?.as_direct()?; let parent_formula_ax = raw_slot_result(clue, 13)?.as_atom()?; diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index c6f2d75b..8e900b2c 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -26,13 +26,15 @@ impl Preserve for Batteries { let mut ptr: *mut *mut BatteriesMem = &mut self.0; loop { if stack.is_in_frame(*ptr) { + (**ptr).battery.preserve(stack); (**ptr).parent_axis.preserve(stack); let dest_mem: *mut BatteriesMem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(*ptr, dest_mem, 1); if (*dest_mem).parent_batteries.0.is_null() { break; }; - ptr = &mut ((*dest_mem).parent_batteries.0); + *ptr = dest_mem; + ptr = &mut ((**ptr).parent_batteries.0); } else { break; } @@ -65,11 +67,11 @@ impl Batteries { if d.data() == 0 { if unsafe { !unifying_equality(stack, &mut core, battery) } { return false; - }; + } else { continue; }; }; }; - if let Ok(_core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { - if unsafe { !unifying_equality(stack, &mut core, battery) } { + if let Ok(mut core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { + if unsafe { !unifying_equality(stack, &mut core_battery, battery) } { return false; }; if let Ok(core_parent) = slot_result(core, parent_axis.as_bitslice()) { @@ -111,7 +113,8 @@ impl Preserve for BatteriesList { if (*dest_mem).next.0.is_null() { break; }; - ptr = &mut ((*dest_mem).next.0); + *ptr = dest_mem; + ptr = &mut ((**ptr).next.0); } else { break; } @@ -162,7 +165,7 @@ impl Preserve for NounList { if self.0.is_null() { return; }; - let mut ptr: *mut *mut NounListMem = &mut (*self).0; + let mut ptr: *mut *mut NounListMem = &mut (self.0); loop { if stack.is_in_frame(*ptr) { (**ptr).element.preserve(stack); @@ -171,7 +174,8 @@ impl Preserve for NounList { if (*dest_mem).next.0.is_null() { break; }; - ptr = &mut ((*dest_mem).next.0); + *ptr = dest_mem; + ptr = &mut ((**ptr).next.0); } else { break; } @@ -252,7 +256,6 @@ impl Cold { mut chum: Noun, ) -> Result { let mut battery = slot_result(core, BitSlice::from_element(&2u64))?; - let mut parent = slot_result(core, parent_axis.as_bitslice())?; unsafe { // Are we registering a root? @@ -315,6 +318,7 @@ impl Cold { } } + let mut parent = slot_result(core, parent_axis.as_bitslice())?; // Check if we already registered this core if let Some(paths) = (*(self.0)).battery_to_paths.lookup(stack, &mut battery) { for path in paths { @@ -346,7 +350,7 @@ impl Cold { let battery_list = path_to_batteries .lookup(stack, &mut *a_path) .unwrap_or(BATTERIES_LIST_NIL); - if let Some(parent_batteries) = battery_list.matches(stack, core) { + 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); @@ -395,7 +399,7 @@ impl Cold { let battery_list = path_to_batteries .lookup(stack, &mut *a_path) .unwrap_or(BATTERIES_LIST_NIL); - if let Some(parent_batteries) = battery_list.matches(stack, core) { + 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); From b5d178f635851df33576d0051f3b3573dc39534f Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Fri, 22 Sep 2023 23:12:33 -0500 Subject: [PATCH 05/15] tests: add decfast.jam and decslow.jam, jetted/unjetted decrement of 2 billion --- rust/ares/test_data/decfast.jam | Bin 0 -> 110 bytes rust/ares/test_data/decslow.jam | 1 + 2 files changed, 1 insertion(+) create mode 100644 rust/ares/test_data/decfast.jam create mode 100644 rust/ares/test_data/decslow.jam diff --git a/rust/ares/test_data/decfast.jam b/rust/ares/test_data/decfast.jam new file mode 100644 index 0000000000000000000000000000000000000000..97072fd235069e8af96d78a59afd860fd1e94f97 GIT binary patch literal 110 zcmV-!0FnP0elgI(YT)n-g2mw%1dA;WyKozyCw6HNYR literal 0 HcmV?d00001 diff --git a/rust/ares/test_data/decslow.jam b/rust/ares/test_data/decslow.jam new file mode 100644 index 00000000..0dc72b79 --- /dev/null +++ b/rust/ares/test_data/decslow.jam @@ -0,0 +1 @@ +~1j -p'vil|.B!Td ZdL!Y< [7 ^9{0l >.x*7>wAa&ɐA/1(k \ No newline at end of file From a0d11b305f8b04edc15386de51e7f12754484377 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Sat, 23 Sep 2023 07:36:17 -0500 Subject: [PATCH 06/15] jets: add decflow test case which trips a memory bug in cold state --- rust/ares/test_data/decflow.jam | Bin 0 -> 158 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 rust/ares/test_data/decflow.jam diff --git a/rust/ares/test_data/decflow.jam b/rust/ares/test_data/decflow.jam new file mode 100644 index 0000000000000000000000000000000000000000..7738787add436fda74d3e0fcd0f4b6a18ab7602f GIT binary patch literal 158 zcmV;P0Ac?belgI(YT)n-g2jbj5G=Mh?80rlp4g>9u) zXkibtF*!(v9H#Lwje~3f-z;p79tS+KvT=#;Fpa}++#F1%wZY_$&f*`u){CWF()zz79_(Rs{bGvGKdy-_zl&6 M4155}n)`4P1mkx|4*&oF literal 0 HcmV?d00001 From 8d783d0b3992289237ebf0703704d34d4f8934c3 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Wed, 27 Sep 2023 22:31:17 -0500 Subject: [PATCH 07/15] interpreter: working cold/warm/hot state, and new assertion functions for debugging --- rust/ares/src/hamt.rs | 49 +++++++++++++++++++++-- rust/ares/src/jets/cold.rs | 81 ++++++++++++++++++++++++++++++++------ rust/ares/src/jets/warm.rs | 44 +++++++++++++++++---- rust/ares/src/mem.rs | 63 +++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+), 23 deletions(-) diff --git a/rust/ares/src/hamt.rs b/rust/ares/src/hamt.rs index 8733f620..00de4534 100644 --- a/rust/ares/src/hamt.rs +++ b/rust/ares/src/hamt.rs @@ -258,9 +258,9 @@ assert_eq_size!(&[Entry<()>], Stem<()>); #[derive(Copy, Clone)] pub struct Hamt(Stem); -impl Hamt { +impl Hamt { // Make a new, empty HAMT - pub fn new() -> Hamt { + pub fn new() -> Self { Hamt(Stem { bitmap: 0, typemap: 0, @@ -426,13 +426,56 @@ impl Hamt { } } -impl Default for Hamt { +impl Default for Hamt { fn default() -> Self { Self::new() } } impl Preserve for Hamt { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + stack.struct_is_in(self.0.buffer, self.0.size()); + let mut traversal_stack: [Option<(Stem, u32)>; 6] = [None; 6]; + traversal_stack[0] = Some((self.0, 0)); + let mut traversal_depth = 1; + 'check: loop { + if traversal_depth == 0 { + break; + } + let (stem, mut position) = traversal_stack[traversal_depth - 1] + .expect("Attempted to access uninitialized array element"); + // can we loop over the size and count leading 0s remaining in the bitmap? + 'check_stem: loop { + if position >= 32 { + traversal_depth -= 1; + continue 'check; + } + match stem.entry(position) { + None => { + position += 1; + continue 'check_stem; + } + Some((Left(next_stem), idx)) => { + stack.struct_is_in(next_stem.buffer, next_stem.size()); + assert!(traversal_depth <= 5); // will increment + traversal_stack[traversal_depth - 1].as_mut().unwrap().1 = position + 1; + traversal_stack[traversal_depth] = Some((next_stem, 0)); + traversal_depth += 1; + continue 'check; + } + Some((Right(leaf), idx)) => { + stack.struct_is_in(leaf.buffer, leaf.len); + for pair in leaf.to_mut_slice().iter() { + pair.0.assert_in_stack(stack); + pair.1.assert_in_stack(stack); + } + position += 1; + continue 'check_stem; + } + } + } + } + } unsafe fn preserve(&mut self, stack: &mut NockStack) { if stack.is_in_frame(self.0.buffer) { let dest_buffer = stack.struct_alloc_in_previous_frame(self.0.size()); diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index 8e900b2c..4428a1a1 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -19,6 +19,21 @@ struct BatteriesMem { } impl Preserve for Batteries { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + if self.0.is_null() { + return; + }; + let mut cursor = *self; + loop { + stack.struct_is_in(cursor.0, 1); + (*cursor.0).battery.assert_in_stack(stack); + (*cursor.0).parent_axis.assert_in_stack(stack); + if (*cursor.0).parent_batteries.0.is_null() { + break; + }; + cursor = (*cursor.0).parent_batteries; + }; + } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { return; @@ -30,11 +45,11 @@ impl Preserve for Batteries { (**ptr).parent_axis.preserve(stack); let dest_mem: *mut BatteriesMem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(*ptr, dest_mem, 1); + *ptr = dest_mem; + ptr = &mut ((**ptr).parent_batteries.0); if (*dest_mem).parent_batteries.0.is_null() { break; }; - *ptr = dest_mem; - ptr = &mut ((**ptr).parent_batteries.0); } else { break; } @@ -67,7 +82,9 @@ impl Batteries { if d.data() == 0 { if unsafe { !unifying_equality(stack, &mut core, battery) } { return false; - } else { continue; }; + } else { + continue; + }; }; }; if let Ok(mut core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { @@ -100,6 +117,21 @@ struct BatteriesListMem { } impl Preserve for BatteriesList { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + if self.0.is_null() { + return; + } + let mut cursor = *self; + loop { + stack.struct_is_in(cursor.0, 1); + (*cursor.0).batteries.assert_in_stack(stack); + if (*cursor.0).next.0.is_null() { + break; + }; + cursor = (*cursor.0).next; + } + + } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { return; @@ -110,11 +142,11 @@ impl Preserve for BatteriesList { (**ptr).batteries.preserve(stack); let dest_mem: *mut BatteriesListMem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(*ptr, dest_mem, 1); + *ptr = dest_mem; + ptr = &mut ((**ptr).next.0); if (*dest_mem).next.0.is_null() { break; }; - *ptr = dest_mem; - ptr = &mut ((**ptr).next.0); } else { break; } @@ -161,21 +193,35 @@ struct NounListMem { } impl Preserve for NounList { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + if self.0.is_null() { + return; + }; + let mut cursor = *self; + loop { + stack.struct_is_in(cursor.0, 1); + (*cursor.0).element.assert_in_stack(stack); + if (*cursor.0).next.0.is_null() { + break; + }; + cursor = (*cursor.0).next; + } + } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { return; }; - let mut ptr: *mut *mut NounListMem = &mut (self.0); + let mut ptr: *mut NounList = self; loop { - if stack.is_in_frame(*ptr) { - (**ptr).element.preserve(stack); + if stack.is_in_frame((*ptr).0) { + (*(*ptr).0).element.preserve(stack); let dest_mem: *mut NounListMem = stack.struct_alloc_in_previous_frame(1); - copy_nonoverlapping(*ptr, dest_mem, 1); + copy_nonoverlapping((*ptr).0, dest_mem, 1); + *ptr = NounList(dest_mem); + ptr = &mut ((*(*ptr).0).next); if (*dest_mem).next.0.is_null() { break; }; - *ptr = dest_mem; - ptr = &mut ((**ptr).next.0); } else { break; } @@ -214,6 +260,12 @@ struct ColdMem { } impl Preserve for Cold { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + stack.struct_is_in(self.0, 1); + (*self.0).battery_to_paths.assert_in_stack(stack); + (*self.0).root_to_paths.assert_in_stack(stack); + (*self.0).path_to_batteries.assert_in_stack(stack); + } unsafe fn preserve(&mut self, stack: &mut NockStack) { (*(self.0)).battery_to_paths.preserve(stack); (*(self.0)).root_to_paths.preserve(stack); @@ -241,7 +293,12 @@ impl Cold { } pub fn find(&mut self, stack: &mut NockStack, path: &mut Noun) -> BatteriesList { - unsafe { (*(self.0)).path_to_batteries.lookup(stack, path).unwrap_or(BATTERIES_LIST_NIL) } + unsafe { + (*(self.0)) + .path_to_batteries + .lookup(stack, path) + .unwrap_or(BATTERIES_LIST_NIL) + } } /// register a core, return a boolean of whether we actually needed to register (false -> diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index 2cf34f21..e359e36c 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -1,7 +1,7 @@ use crate::hamt::Hamt; use crate::interpreter::slot_result; -use crate::jets::cold::{Batteries,Cold}; -use crate::jets::hot::{Hot}; +use crate::jets::cold::{Batteries, Cold}; +use crate::jets::hot::Hot; use crate::jets::Jet; use crate::mem::{NockStack, Preserve}; use crate::noun::Noun; @@ -10,6 +10,9 @@ use std::ptr::{copy_nonoverlapping, null_mut}; pub struct Warm(Hamt); impl Preserve for Warm { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + self.0.assert_in_stack(stack); + } unsafe fn preserve(&mut self, stack: &mut NockStack) { self.0.preserve(stack); } @@ -28,6 +31,21 @@ struct WarmEntryMem { } impl Preserve for WarmEntry { + unsafe fn assert_in_stack(&self, stack: &NockStack) { + if self.0.is_null() { + return; + }; + let mut cursor = *self; + loop { + stack.struct_is_in(cursor.0, 1); + (*cursor.0).batteries.assert_in_stack(stack); + (*cursor.0).path.assert_in_stack(stack); + if (*cursor.0).next.0.is_null() { + break; + }; + cursor = (*cursor.0).next; + } + } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { return; @@ -39,10 +57,11 @@ impl Preserve for WarmEntry { (**ptr).path.preserve(stack); let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1); copy_nonoverlapping(*ptr, dest_mem, 1); + *ptr = dest_mem; + ptr = &mut ((*dest_mem).next.0); if (*dest_mem).next.0.is_null() { break; }; - ptr = &mut ((*dest_mem).next.0); } else { break; } @@ -69,10 +88,17 @@ impl Warm { Warm(Hamt::new()) } - fn insert(&mut self, stack: &mut NockStack, formula: &mut Noun, path: Noun, batteries: Batteries, jet: Jet) { + fn insert( + &mut self, + stack: &mut NockStack, + formula: &mut Noun, + path: Noun, + batteries: Batteries, + jet: Jet, + ) { 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); + let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1); *warm_entry_mem_ptr = WarmEntryMem { batteries: batteries, jet: jet, @@ -89,12 +115,14 @@ impl Warm { let batteries_list = cold.find(stack, &mut path); for batteries in batteries_list { let mut batteries_tmp = batteries; - let (mut battery, _parent_axis) = batteries_tmp.next().expect("IMPOSSIBLE: empty battery entry in cold state"); - if let Ok(mut formula) = unsafe { slot_result(*battery, axis.as_bitslice()) } { + let (mut battery, _parent_axis) = batteries_tmp + .next() + .expect("IMPOSSIBLE: empty battery entry in cold state"); + if let Ok(mut formula) = unsafe { slot_result(*battery, axis.as_bitslice()) } { warm.insert(stack, &mut formula, path, batteries, jet); } else { eprintln!("Bad axis {} into formula {:?}", axis, battery); - continue + continue; } } } diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index d39e2ec2..11d603d0 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -1,6 +1,7 @@ use crate::assert_acyclic; use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator}; use crate::snapshot::pma::{pma_in_arena, pma_malloc_w}; +use assert_no_alloc::permit_alloc; use either::Either::{self, Left, Right}; use ibig::Stack; use libc::{c_void, memcmp}; @@ -440,6 +441,58 @@ impl NockStack { assert_acyclic!(*noun); } + pub unsafe fn struct_is_in(&self, ptr: *const T, count: usize ) { + let ap = (if self.pc { + *(self.prev_alloc_pointer_pointer()) + } else { + self.alloc_pointer + }) as usize; + let sp = (if self.pc { + *(self.prev_stack_pointer_pointer()) + } else { + self.stack_pointer + }) as usize; + let (low, hi) = if ap > sp { (sp, ap) } else { (ap, sp) }; + if (ptr as usize) < low && (ptr.add(count) as usize) <= low { + return; + } else if (ptr as usize) >= hi && (ptr.add(count) as usize) > hi { + return; + } + panic!("Use after free: allocation from {:#x} to {:#x}, free space from {:#x} to {:#x}", ptr as usize, ptr.add(count) as usize, low, hi); + } + + unsafe fn noun_in(&self, noun: Noun) { + let mut dbg_stack = Vec::new(); + dbg_stack.push(noun); + let ap = (if self.pc { + *(self.prev_alloc_pointer_pointer()) + } else { + self.alloc_pointer + }) as usize; + let sp = (if self.pc { + *(self.prev_stack_pointer_pointer()) + } else { + self.stack_pointer + }) as usize; + let (low, hi) = if ap > sp { (sp, ap) } else { (ap, sp) }; + loop { + if let Some(subnoun) = dbg_stack.pop() { + if let Ok(a) = subnoun.as_allocated() { + let np = a.to_raw_pointer() as usize; + if np >= low && np < hi { + panic!("noun not in {:?}: {:?}", (low,hi), subnoun); + } + if let Right(c) = a.as_either() { + dbg_stack.push(c.tail()); + dbg_stack.push(c.head()); + } + } + } else { + return; + } + } + } + pub unsafe fn copy_pma(&mut self, noun: &mut Noun) { // copy_pma() should only be called when there is a single stack // frame; these asserts assure that. @@ -866,6 +919,7 @@ impl NounAllocator for NockStack { pub trait Preserve { /// Ensure an object will not be invalidated by popping the NockStack unsafe fn preserve(&mut self, stack: &mut NockStack); + unsafe fn assert_in_stack(&self, stack: &NockStack); } impl Preserve for IndirectAtom { @@ -875,6 +929,9 @@ impl Preserve for IndirectAtom { copy_nonoverlapping(self.to_raw_pointer(), buf, size); *self = IndirectAtom::from_raw_pointer(buf); } + unsafe fn assert_in_stack(&self, stack: &NockStack) { + stack.noun_in(self.as_atom().as_noun()); + } } impl Preserve for Atom { @@ -887,12 +944,18 @@ impl Preserve for Atom { } } } + unsafe fn assert_in_stack(&self, stack: &NockStack) { + stack.noun_in(self.as_noun()); + } } impl Preserve for Noun { unsafe fn preserve(&mut self, stack: &mut NockStack) { stack.copy(self); } + unsafe fn assert_in_stack(&self, stack: &NockStack) { + stack.noun_in(*self); + } } impl Stack for NockStack { From 4e292b88a0342fe655ed8444ea8e39b743c8b8cd Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Wed, 27 Sep 2023 22:32:40 -0500 Subject: [PATCH 08/15] interpreter: formatting --- rust/ares/src/hamt.rs | 68 ++++++++++++++++++------------------ rust/ares/src/interpreter.rs | 48 +++++++++++++++++-------- rust/ares/src/jets/cold.rs | 3 +- rust/ares/src/main.rs | 12 +++++-- rust/ares/src/mem.rs | 12 +++++-- rust/ares/src/serf.rs | 25 ++++++++++--- 6 files changed, 107 insertions(+), 61 deletions(-) diff --git a/rust/ares/src/hamt.rs b/rust/ares/src/hamt.rs index 00de4534..4d340dca 100644 --- a/rust/ares/src/hamt.rs +++ b/rust/ares/src/hamt.rs @@ -434,47 +434,47 @@ impl Default for Hamt { impl Preserve for Hamt { unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.struct_is_in(self.0.buffer, self.0.size()); - let mut traversal_stack: [Option<(Stem, u32)>; 6] = [None; 6]; - traversal_stack[0] = Some((self.0, 0)); - let mut traversal_depth = 1; - 'check: loop { - if traversal_depth == 0 { - break; + stack.struct_is_in(self.0.buffer, self.0.size()); + let mut traversal_stack: [Option<(Stem, u32)>; 6] = [None; 6]; + traversal_stack[0] = Some((self.0, 0)); + let mut traversal_depth = 1; + 'check: loop { + if traversal_depth == 0 { + break; + } + let (stem, mut position) = traversal_stack[traversal_depth - 1] + .expect("Attempted to access uninitialized array element"); + // can we loop over the size and count leading 0s remaining in the bitmap? + 'check_stem: loop { + if position >= 32 { + traversal_depth -= 1; + continue 'check; } - let (stem, mut position) = traversal_stack[traversal_depth - 1] - .expect("Attempted to access uninitialized array element"); - // can we loop over the size and count leading 0s remaining in the bitmap? - 'check_stem: loop { - if position >= 32 { - traversal_depth -= 1; + match stem.entry(position) { + None => { + position += 1; + continue 'check_stem; + } + Some((Left(next_stem), idx)) => { + stack.struct_is_in(next_stem.buffer, next_stem.size()); + assert!(traversal_depth <= 5); // will increment + traversal_stack[traversal_depth - 1].as_mut().unwrap().1 = position + 1; + traversal_stack[traversal_depth] = Some((next_stem, 0)); + traversal_depth += 1; continue 'check; } - match stem.entry(position) { - None => { - position += 1; - continue 'check_stem; - } - Some((Left(next_stem), idx)) => { - stack.struct_is_in(next_stem.buffer, next_stem.size()); - assert!(traversal_depth <= 5); // will increment - traversal_stack[traversal_depth - 1].as_mut().unwrap().1 = position + 1; - traversal_stack[traversal_depth] = Some((next_stem, 0)); - traversal_depth += 1; - continue 'check; - } - Some((Right(leaf), idx)) => { - stack.struct_is_in(leaf.buffer, leaf.len); - for pair in leaf.to_mut_slice().iter() { - pair.0.assert_in_stack(stack); - pair.1.assert_in_stack(stack); - } - position += 1; - continue 'check_stem; + Some((Right(leaf), idx)) => { + stack.struct_is_in(leaf.buffer, leaf.len); + for pair in leaf.to_mut_slice().iter() { + pair.0.assert_in_stack(stack); + pair.1.assert_in_stack(stack); } + position += 1; + continue 'check_stem; } } } + } } unsafe fn preserve(&mut self, stack: &mut NockStack) { if stack.is_in_frame(self.0.buffer) { diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 19e2cd05..abe09cc9 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -1,14 +1,14 @@ use crate::hamt::Hamt; use crate::jets; use crate::jets::cold::Cold; -use crate::jets::warm::Warm; use crate::jets::hot::Hot; +use crate::jets::warm::Warm; use crate::mem::unifying_equality; use crate::mem::NockStack; use crate::newt::Newt; use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, T}; use ares_macros::tas; -use assert_no_alloc::{assert_no_alloc}; +use assert_no_alloc::assert_no_alloc; use bitvec::prelude::{BitSlice, Lsb0}; use either::Either::*; @@ -311,8 +311,10 @@ pub fn interpret( push_formula(stack, vale.formula, false); } Todo2::ComputeResult => { - if let Some(jet) = warm.find_jet(stack, &mut vale.subject, &mut res) { // a jet match - if let Ok(jet_res) = jet(stack, vale.subject) { // XX TODO: nondeterministic errors + if let Some(jet) = warm.find_jet(stack, &mut vale.subject, &mut res) { + // a jet match + if let Ok(jet_res) = jet(stack, vale.subject) { + // XX TODO: nondeterministic errors res = jet_res; stack.pop::(); continue; @@ -461,8 +463,10 @@ pub fn interpret( } Todo9::ComputeResult => { let mut formula = slot(res, kale.axis.as_bitslice()); - if let Some(jet) = warm.find_jet(stack, &mut res, &mut formula) { // a jet match - if let Ok(jet_res) = jet(stack, res) { // XX TODO: nondeterministic errors + if let Some(jet) = warm.find_jet(stack, &mut res, &mut formula) { + // a jet match + if let Ok(jet_res) = jet(stack, res) { + // XX TODO: nondeterministic errors res = jet_res; stack.pop::(); continue; @@ -534,7 +538,9 @@ pub fn interpret( } Todo11D::Done => { let hint = Cell::new(stack, dint.tag.as_noun(), dint.hint).as_noun(); - let _ = match_post_hinted(stack, subject, hint, res, &mut cache, cold, warm, hot); + let _ = match_post_hinted( + stack, subject, hint, res, &mut cache, cold, warm, hot, + ); stack.pop::(); } }, @@ -553,8 +559,16 @@ pub fn interpret( } } Todo11S::Done => { - let _ = - match_post_hinted(stack, subject, sint.tag.as_noun(), res, &mut cache, cold, warm, hot); + let _ = match_post_hinted( + stack, + subject, + sint.tag.as_noun(), + res, + &mut cache, + cold, + warm, + hot, + ); stack.pop::(); } }, @@ -931,7 +945,7 @@ fn match_post_hinted( cache: &mut Hamt, cold: &mut Cold, warm: &mut Warm, - hot: Hot + hot: Hot, ) -> Result<(), ()> { let direct = hint.as_cell()?.head().as_direct()?; match direct.data() { @@ -940,7 +954,7 @@ fn match_post_hinted( let mut key = Cell::new(stack, subject, formula).as_noun(); *cache = cache.insert(stack, &mut key, res); Ok(()) - }, + } tas!(b"fast") => { let clue = raw_slot_result(hint, 7)?; let chum = raw_slot_result(clue, 2)?; @@ -948,15 +962,19 @@ fn match_post_hinted( let parent_formula_ax = raw_slot_result(clue, 13)?.as_atom()?; if parent_formula_op.data() == 1 { if parent_formula_ax.as_direct()?.data() == 0 { - let changed = cold.register(stack, res, parent_formula_ax, chum)?; - if changed { *warm = Warm::init(stack, cold, hot); } - Ok(()) + let changed = cold.register(stack, res, parent_formula_ax, chum)?; + if changed { + *warm = Warm::init(stack, cold, hot); + } + Ok(()) } else { Err(()) } } else { let changed = cold.register(stack, res, parent_formula_ax, chum)?; - if changed { *warm = Warm::init(stack, cold, hot); } + if changed { + *warm = Warm::init(stack, cold, hot); + } Ok(()) } } diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index 4428a1a1..9a7245c2 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -32,7 +32,7 @@ impl Preserve for Batteries { break; }; cursor = (*cursor.0).parent_batteries; - }; + } } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { @@ -130,7 +130,6 @@ impl Preserve for BatteriesList { }; cursor = (*cursor.0).next; } - } unsafe fn preserve(&mut self, stack: &mut NockStack) { if self.0.is_null() { diff --git a/rust/ares/src/main.rs b/rust/ares/src/main.rs index f46a2d3d..6b06a50c 100644 --- a/rust/ares/src/main.rs +++ b/rust/ares/src/main.rs @@ -1,7 +1,7 @@ use ares::interpreter::interpret; use ares::jets::cold::Cold; -use ares::jets::warm::Warm; use ares::jets::hot::Hot; +use ares::jets::warm::Warm; use ares::mem::NockStack; use ares::noun::IndirectAtom; use ares::serf::serf; @@ -58,7 +58,15 @@ fn main() -> io::Result<()> { let input_cell = input .as_cell() .expect("Input must be jam of subject/formula pair"); - let result = interpret(&mut stack, &mut None, &mut cold, &mut warm, hot, input_cell.head(), input_cell.tail()); + let result = interpret( + &mut stack, + &mut None, + &mut cold, + &mut warm, + hot, + input_cell.head(), + input_cell.tail(), + ); if let Ok(atom) = result.as_atom() { println!("Result: {}", atom); } diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 11d603d0..a221bf21 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -441,7 +441,7 @@ impl NockStack { assert_acyclic!(*noun); } - pub unsafe fn struct_is_in(&self, ptr: *const T, count: usize ) { + pub unsafe fn struct_is_in(&self, ptr: *const T, count: usize) { let ap = (if self.pc { *(self.prev_alloc_pointer_pointer()) } else { @@ -458,7 +458,13 @@ impl NockStack { } else if (ptr as usize) >= hi && (ptr.add(count) as usize) > hi { return; } - panic!("Use after free: allocation from {:#x} to {:#x}, free space from {:#x} to {:#x}", ptr as usize, ptr.add(count) as usize, low, hi); + panic!( + "Use after free: allocation from {:#x} to {:#x}, free space from {:#x} to {:#x}", + ptr as usize, + ptr.add(count) as usize, + low, + hi + ); } unsafe fn noun_in(&self, noun: Noun) { @@ -480,7 +486,7 @@ impl NockStack { if let Ok(a) = subnoun.as_allocated() { let np = a.to_raw_pointer() as usize; if np >= low && np < hi { - panic!("noun not in {:?}: {:?}", (low,hi), subnoun); + panic!("noun not in {:?}: {:?}", (low, hi), subnoun); } if let Right(c) = a.as_either() { dbg_stack.push(c.tail()); diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index 6112249e..4a8a6ae1 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -1,7 +1,7 @@ use crate::interpreter::{interpret, raw_slot}; use crate::jets::cold::Cold; -use crate::jets::warm::Warm; use crate::jets::hot::Hot; +use crate::jets::warm::Warm; use crate::mem::NockStack; use crate::mug::mug_u32; use crate::newt::Newt; @@ -82,7 +82,8 @@ pub fn serf() -> io::Result<()> { let lit = raw_slot(writ, 7); let sub = T(stack, &[D(0), D(3)]); let lyf = T(stack, &[D(2), sub, D(0), D(2)]); - let gat = interpret(stack, &mut Some(newt), &mut cold, &mut warm, hot, lit, lyf); + let gat = + interpret(stack, &mut Some(newt), &mut cold, &mut warm, hot, lit, lyf); arvo = raw_slot(gat, 7); false } else { @@ -96,7 +97,10 @@ pub fn serf() -> io::Result<()> { while let Ok(cell) = lit.as_cell() { if run { let ovo = cell.head(); - let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo).as_cell().unwrap(); + let res = + slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo) + .as_cell() + .unwrap(); arvo = res.tail(); } event_number += 1; @@ -108,7 +112,9 @@ pub fn serf() -> io::Result<()> { } tas!(b"work") => { let ovo = raw_slot(writ, 7); - let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo).as_cell().unwrap(); + let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo) + .as_cell() + .unwrap(); let fec = res.head(); arvo = res.tail(); snap.save(stack, &mut arvo); @@ -124,7 +130,16 @@ pub fn serf() -> io::Result<()> { Ok(()) } -pub fn slam(stack: &mut NockStack, newt: &mut Newt, cold: &mut Cold, warm: &mut Warm, hot: Hot, core: Noun, axis: u64, ovo: Noun) -> Noun { +pub fn slam( + stack: &mut NockStack, + newt: &mut Newt, + cold: &mut Cold, + warm: &mut Warm, + hot: Hot, + core: Noun, + axis: u64, + ovo: Noun, +) -> Noun { let pul = T(stack, &[D(9), D(axis), D(0), D(2)]); let sam = T(stack, &[D(6), D(0), D(7)]); let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]); From 2db74f9c0f4a8e0fee2a747b8479e0559b483e74 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Wed, 27 Sep 2023 22:55:00 -0500 Subject: [PATCH 09/15] interpreter: address lints for fast hints --- rust/ares/src/hamt.rs | 4 ++-- rust/ares/src/interpreter.rs | 14 +++++++++----- rust/ares/src/jets/cold.rs | 34 +++++++++++++++------------------- rust/ares/src/jets/hot.rs | 7 ++++--- rust/ares/src/jets/warm.rs | 11 ++++++----- rust/ares/src/mem.rs | 7 +++---- rust/ares/src/serf.rs | 1 + 7 files changed, 40 insertions(+), 38 deletions(-) diff --git a/rust/ares/src/hamt.rs b/rust/ares/src/hamt.rs index 4d340dca..f4f88527 100644 --- a/rust/ares/src/hamt.rs +++ b/rust/ares/src/hamt.rs @@ -455,7 +455,7 @@ impl Preserve for Hamt { position += 1; continue 'check_stem; } - Some((Left(next_stem), idx)) => { + Some((Left(next_stem), _idx)) => { stack.struct_is_in(next_stem.buffer, next_stem.size()); assert!(traversal_depth <= 5); // will increment traversal_stack[traversal_depth - 1].as_mut().unwrap().1 = position + 1; @@ -463,7 +463,7 @@ impl Preserve for Hamt { traversal_depth += 1; continue 'check; } - Some((Right(leaf), idx)) => { + Some((Right(leaf), _idx)) => { stack.struct_is_in(leaf.buffer, leaf.len); for pair in leaf.to_mut_slice().iter() { pair.0.assert_in_stack(stack); diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index abe09cc9..536d62ce 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -1,5 +1,5 @@ use crate::hamt::Hamt; -use crate::jets; + use crate::jets::cold::Cold; use crate::jets::hot::Hot; use crate::jets::warm::Warm; @@ -761,13 +761,15 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) { /** Note: axis must fit in a direct atom */ pub fn raw_slot(noun: Noun, axis: u64) -> Noun { - slot(noun, &BitSlice::from_element(&axis)) + slot(noun, BitSlice::from_element(&axis)) } +#[allow(clippy::result_unit_err)] pub fn raw_slot_result(noun: Noun, axis: u64) -> Result { - slot_result(noun, &BitSlice::from_element(&axis)) + slot_result(noun, BitSlice::from_element(&axis)) } +#[allow(clippy::result_unit_err)] pub fn slot_result(mut noun: Noun, axis: &BitSlice) -> Result { let mut cursor = if let Some(x) = axis.last_one() { Ok(x) @@ -866,10 +868,10 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { /** Match hints which apply before the formula is evaluated */ fn match_pre_hint( stack: &mut NockStack, - newt: &mut Option<&mut Newt>, + _newt: &mut Option<&mut Newt>, subject: Noun, cell: Cell, - formula: Noun, + _formula: Noun, cache: &Hamt, ) -> Result { let direct = cell.head().as_direct()?; @@ -913,6 +915,7 @@ fn match_pre_hint( } /** Match static hints and dynamic hints after they're evaluated */ +#[allow(clippy::too_many_arguments)] fn match_post_hint( stack: &mut NockStack, newt: &mut Option<&mut Newt>, @@ -937,6 +940,7 @@ fn match_post_hint( } } +#[allow(clippy::too_many_arguments)] fn match_post_hinted( stack: &mut NockStack, subject: Noun, diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index 9a7245c2..914b811b 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -170,13 +170,8 @@ impl Iterator for BatteriesList { } impl BatteriesList { - fn matches(self, stack: &mut NockStack, core: Noun) -> Option { - for batteries in self { - if batteries.matches(stack, core) { - return Some(batteries); - } - } - None + fn matches(mut self, stack: &mut NockStack, core: Noun) -> Option { + self.find(|&batteries| batteries.matches(stack, core)) } } @@ -283,9 +278,9 @@ impl Cold { unsafe { let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1); *cold_mem_ptr = ColdMem { - battery_to_paths: battery_to_paths, - root_to_paths: root_to_paths, - path_to_batteries: path_to_batteries, + battery_to_paths, + root_to_paths, + path_to_batteries, }; Cold(cold_mem_ptr) } @@ -304,6 +299,7 @@ impl Cold { /// already registered) /// /// XX TODO validate chum + #[allow(clippy::result_unit_err)] pub fn register( &mut self, stack: &mut NockStack, @@ -411,9 +407,9 @@ impl Cold { let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1); *batteries_mem_ptr = BatteriesMem { - battery: battery, - parent_axis: parent_axis, - parent_batteries: parent_batteries, + battery, + parent_axis, + parent_batteries, }; let current_batteries_list = path_to_batteries @@ -460,9 +456,9 @@ impl Cold { let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1); *batteries_mem_ptr = BatteriesMem { - battery: battery, - parent_axis: parent_axis, - parent_batteries: parent_batteries, + battery, + parent_axis, + parent_batteries, }; let current_batteries_list = path_to_batteries @@ -500,9 +496,9 @@ impl Cold { let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1); *cold_mem_ptr = ColdMem { - battery_to_paths: battery_to_paths, - root_to_paths: root_to_paths, - path_to_batteries: path_to_batteries, + battery_to_paths, + root_to_paths, + path_to_batteries, }; *self = Cold(cold_mem_ptr); diff --git a/rust/ares/src/jets/hot.rs b/rust/ares/src/jets/hot.rs index 0c59b3b6..f0aba3b7 100644 --- a/rust/ares/src/jets/hot.rs +++ b/rust/ares/src/jets/hot.rs @@ -7,6 +7,7 @@ use std::ptr::null_mut; const A_50: Either = Right((tas!(b"a"), 50)); // This is the const state all in one spot as literals +#[allow(clippy::complexity)] const HOT_STATE: &[(&[Either], u64, Jet)] = &[ (&[A_50, Left(tas!(b"dec"))], 1, jet_dec), (&[A_50, Left(tas!(b"add"))], 1, jet_add), @@ -68,10 +69,10 @@ impl Hot { let axis = DirectAtom::new_panic(*axe).as_atom(); let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1); *hot_mem_ptr = HotMem { - a_path: a_path, - axis: axis, + a_path, + axis, jet: *jet, - next: next, + next, }; next = Hot(hot_mem_ptr); } diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index e359e36c..18a819c2 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -84,6 +84,7 @@ impl Iterator for WarmEntry { } impl Warm { + #[allow(clippy::new_without_default)] pub fn new() -> Self { Warm(Hamt::new()) } @@ -100,9 +101,9 @@ impl Warm { unsafe { let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1); *warm_entry_mem_ptr = WarmEntryMem { - batteries: batteries, - jet: jet, - path: path, + batteries, + jet, + path, next: current_warm_entry, }; self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr)); @@ -115,7 +116,7 @@ impl Warm { let batteries_list = cold.find(stack, &mut path); for batteries in batteries_list { let mut batteries_tmp = batteries; - let (mut battery, _parent_axis) = batteries_tmp + let (battery, _parent_axis) = batteries_tmp .next() .expect("IMPOSSIBLE: empty battery entry in cold state"); if let Ok(mut formula) = unsafe { slot_result(*battery, axis.as_bitslice()) } { @@ -131,7 +132,7 @@ impl Warm { pub fn find_jet(&mut self, stack: &mut NockStack, s: &mut Noun, f: &mut Noun) -> Option { let warm_it = self.0.lookup(stack, f)?; - for (path, batteries, jet) in warm_it { + for (_path, batteries, jet) in warm_it { if batteries.matches(stack, *s) { return Some(jet); } diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index a221bf21..1ceb0b54 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -1,7 +1,7 @@ use crate::assert_acyclic; use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator}; use crate::snapshot::pma::{pma_in_arena, pma_malloc_w}; -use assert_no_alloc::permit_alloc; + use either::Either::{self, Left, Right}; use ibig::Stack; use libc::{c_void, memcmp}; @@ -453,9 +453,8 @@ impl NockStack { self.stack_pointer }) as usize; let (low, hi) = if ap > sp { (sp, ap) } else { (ap, sp) }; - if (ptr as usize) < low && (ptr.add(count) as usize) <= low { - return; - } else if (ptr as usize) >= hi && (ptr.add(count) as usize) > hi { + if ((ptr as usize) < low && (ptr.add(count) as usize) <= low) + || ((ptr as usize) >= hi && (ptr.add(count) as usize) > hi) { return; } panic!( diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index 4a8a6ae1..ea250ede 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -130,6 +130,7 @@ pub fn serf() -> io::Result<()> { Ok(()) } +#[allow(clippy::too_many_arguments)] pub fn slam( stack: &mut NockStack, newt: &mut Newt, From 2ded72085431b2f2e7ec4539af258536bd0aef23 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Wed, 27 Sep 2023 22:56:04 -0500 Subject: [PATCH 10/15] interpreter: formatting --- rust/ares/src/mem.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 1ceb0b54..6e1d85a3 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -454,7 +454,8 @@ impl NockStack { }) as usize; let (low, hi) = if ap > sp { (sp, ap) } else { (ap, sp) }; if ((ptr as usize) < low && (ptr.add(count) as usize) <= low) - || ((ptr as usize) >= hi && (ptr.add(count) as usize) > hi) { + || ((ptr as usize) >= hi && (ptr.add(count) as usize) > hi) + { return; } panic!( From 994c6574760bb3a6061481f32047fd58fa63837e Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Thu, 28 Sep 2023 11:08:48 -0500 Subject: [PATCH 11/15] interpreter: fix memo cache --- rust/ares/src/interpreter.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 536d62ce..a21ad0b0 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -539,7 +539,7 @@ pub fn interpret( Todo11D::Done => { let hint = Cell::new(stack, dint.tag.as_noun(), dint.hint).as_noun(); let _ = match_post_hinted( - stack, subject, hint, res, &mut cache, cold, warm, hot, + stack, subject, dint.body, hint, res, &mut cache, cold, warm, hot, ); stack.pop::(); } @@ -562,6 +562,7 @@ pub fn interpret( let _ = match_post_hinted( stack, subject, + sint.body, sint.tag.as_noun(), res, &mut cache, @@ -871,7 +872,7 @@ fn match_pre_hint( _newt: &mut Option<&mut Newt>, subject: Noun, cell: Cell, - _formula: Noun, + formula: Noun, cache: &Hamt, ) -> Result { let direct = cell.head().as_direct()?; @@ -902,7 +903,6 @@ fn match_pre_hint( } }*/ tas!(b"memo") => { - let formula = unsafe { *stack.local_noun_pointer(2) }; let mut key = Cell::new(stack, subject, formula).as_noun(); if let Some(res) = cache.lookup(stack, &mut key) { Ok(res) @@ -944,6 +944,7 @@ fn match_post_hint( fn match_post_hinted( stack: &mut NockStack, subject: Noun, + formula: Noun, hint: Noun, res: Noun, cache: &mut Hamt, @@ -954,7 +955,6 @@ fn match_post_hinted( let direct = hint.as_cell()?.head().as_direct()?; match direct.data() { tas!(b"memo") => { - let formula = unsafe { *stack.local_noun_pointer(2) }; let mut key = Cell::new(stack, subject, formula).as_noun(); *cache = cache.insert(stack, &mut key, res); Ok(()) From 3022bf9ce668b061638d3928d8a30896f4abad17 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Sun, 1 Oct 2023 18:12:05 -0500 Subject: [PATCH 12/15] nouns: function to assert a noun doesn't contain any forwarding pointers --- rust/ares/src/noun.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rust/ares/src/noun.rs b/rust/ares/src/noun.rs index 2b646baa..a7f57493 100644 --- a/rust/ares/src/noun.rs +++ b/rust/ares/src/noun.rs @@ -895,6 +895,20 @@ impl Noun { Noun { raw } } + pub unsafe fn assert_no_forwarding_pointers(self) { + let mut dbg_stack = Vec::new(); + dbg_stack.push(self); + while !dbg_stack.is_empty() { + let noun = dbg_stack.pop().unwrap(); + if noun.raw & FORWARDING_MASK == FORWARDING_TAG { + panic!("Noun {:#x} has a forwarding pointer as a child", self.raw); + } else if let Ok(cell) = noun.as_cell() { + dbg_stack.push(cell.tail()); + dbg_stack.push(cell.head()); + } + } + } + /** Produce the total size of a noun, in words * * This counts the total size, see mass_frame() to count the size in the current frame. From 9bc4e7ee9ca5e9801ccba905ba00f1496588be21 Mon Sep 17 00:00:00 2001 From: Edward Amsden Date: Mon, 2 Oct 2023 04:42:55 -0500 Subject: [PATCH 13/15] interpreter: feature flag for sham hints --- rust/ares/Cargo.toml | 1 + rust/ares/src/interpreter.rs | 51 ++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/rust/ares/Cargo.toml b/rust/ares/Cargo.toml index 74dd12e0..93bbb512 100644 --- a/rust/ares/Cargo.toml +++ b/rust/ares/Cargo.toml @@ -39,3 +39,4 @@ opt-level = 3 [features] check_acyclic=[] +sham_hints=[] diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index a21ad0b0..5f079067 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -1,5 +1,5 @@ use crate::hamt::Hamt; - +use crate::jets; use crate::jets::cold::Cold; use crate::jets::hot::Hot; use crate::jets::warm::Warm; @@ -514,7 +514,7 @@ pub fn interpret( Todo11D::ComputeHint => { let hint_cell = Cell::new(stack, dint.tag.as_noun(), dint.hint); if let Ok(found) = - match_pre_hint(stack, newt, subject, hint_cell, formula, &cache) + match_pre_hint(stack, newt, cold, warm, hot, subject, hint_cell, formula, &cache) { res = found; stack.pop::(); @@ -869,7 +869,10 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { /** Match hints which apply before the formula is evaluated */ fn match_pre_hint( stack: &mut NockStack, - _newt: &mut Option<&mut Newt>, + newt: &mut Option<&mut Newt>, + cold: &mut Cold, + warm: &mut Warm, + hot: Hot, subject: Noun, cell: Cell, formula: Noun, @@ -877,31 +880,33 @@ fn match_pre_hint( ) -> Result { let direct = cell.head().as_direct()?; match direct.data() { - // %sham hints are scaffolding until we have a real jet dashboard - /* tas!(b"sham") => { - let jet_formula = cell.tail().as_cell()?; - let jet_name = jet_formula.tail(); - let jet = jets::get_jet(jet_name).ok_or(())?; - if let Ok(mut jet_res) = jet(stack, subject) { - // if in test mode, check that the jet returns the same result as the raw nock - if jets::get_jet_test_mode(jet_name) { - let mut nock_res = interpret(stack, newt, cold, warm, hot, subject, formula); - if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } { - eprintln!( - "\rJet {} failed, raw: {}, jetted: {}", - jet_name, nock_res, jet_res - ); - return Err(()); + if cfg!(feature="sham_hints") { + let jet_formula = cell.tail().as_cell()?; + let jet_name = jet_formula.tail(); + let jet = jets::get_jet(jet_name).ok_or(())?; + if let Ok(mut jet_res) = jet(stack, subject) { + // if in test mode, check that the jet returns the same result as the raw nock + if jets::get_jet_test_mode(jet_name) { + let mut nock_res = interpret(stack, newt, cold, warm, hot, subject, formula); + if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } { + eprintln!( + "\rJet {} failed, raw: {}, jetted: {}", + jet_name, nock_res, jet_res + ); + return Err(()); + } } + Ok(jet_res) + } else { + // Print jet errors and punt to Nock + eprintln!("\rJet {} failed", jet_name); + Err(()) } - Ok(jet_res) } else { - // Print jet errors and punt to Nock - eprintln!("\rJet {} failed", jet_name); - Err(()) + Err(()) // sham jets disabled } - }*/ + } tas!(b"memo") => { let mut key = Cell::new(stack, subject, formula).as_noun(); if let Some(res) = cache.lookup(stack, &mut key) { From e006316a329165f1da6ccee906ec20b890bf4f92 Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Fri, 13 Oct 2023 12:15:05 -0600 Subject: [PATCH 14/15] fix compilation errors --- rust/ares/src/interpreter.rs | 109 ++++++++++++++++++++++------------- rust/ares/src/jets.rs | 21 ++++++- rust/ares/src/jets/cold.rs | 35 +++++++---- rust/ares/src/jets/warm.rs | 9 ++- rust/ares/src/main.rs | 12 ++-- rust/ares/src/noun.rs | 14 ----- rust/ares/src/serf.rs | 8 +-- 7 files changed, 127 insertions(+), 81 deletions(-) diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index d45579df..e8a314ef 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -2,10 +2,11 @@ use crate::assert_acyclic; use crate::assert_no_forwarding_pointers; use crate::assert_no_junior_pointers; use crate::hamt::Hamt; -use crate::jets::JetErr; +use crate::jets::cold; use crate::jets::cold::Cold; use crate::jets::hot::Hot; use crate::jets::warm::Warm; +use crate::jets::JetErr; use crate::mem::unifying_equality; use crate::mem::NockStack; use crate::newt::Newt; @@ -243,7 +244,7 @@ pub struct Context<'a, 'b, 'c, 'd, 'e, 'f> { // XX: persistent memo cache pub cold: &'d mut Cold, pub warm: &'e mut Warm, - pub hot: &'f mut Hot, + pub hot: &'f Hot, } #[derive(Debug)] @@ -268,6 +269,12 @@ impl From for NockErr { } } +impl From for NockErr { + fn from(_: cold::Error) -> Self { + NockErr::Deterministic + } +} + impl From for NockErr { fn from(e: JetErr) -> Self { match e { @@ -397,12 +404,16 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res } Todo2::ComputeResult => { // XX: why are these mut? - if let Some(jet) = warm.find_jet(stack, &mut vale.subject, &mut res) { + if let Some(jet) = + context + .warm + .find_jet(context.stack, &mut vale.subject, &mut res) + { // a jet match - if let Ok(jet_res) = jet(stack, vale.subject) { + if let Ok(jet_res) = jet(context, vale.subject) { // XX TODO: nondeterministic errors res = jet_res; - stack.pop::(); + context.stack.pop::(); continue; } }; @@ -567,14 +578,16 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res push_formula(context.stack, kale.core, false)?; } Todo9::ComputeResult => { - if let Ok(formula) = res.slot_atom(kale.axis) { + if let Ok(mut formula) = res.slot_atom(kale.axis) { // XX: why mut? - if let Some(jet) = warm.find_jet(stack, &mut res, &mut formula) { + if let Some(jet) = + context.warm.find_jet(context.stack, &mut res, &mut formula) + { // a jet match - if let Ok(jet_res) = jet(stack, res) { + if let Ok(jet_res) = jet(context, res) { // XX TODO: nondeterministic errors res = jet_res; - stack.pop::(); + context.stack.pop::(); continue; }; }; @@ -675,10 +688,17 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res } } Todo11D::Done => { - if let Some(found) = - hint::match_post_nock(context, subject, dint.tag, dint.body, res) - { - res = found; + match hint::match_post_nock( + context, + subject, + dint.tag, + Some(dint.hint), + dint.body, + res, + ) { + Ok(Some(found)) => res = found, + Err(err) => break Err(err), + _ => {} } context.stack.pop::(); } @@ -705,10 +725,12 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res } } Todo11S::Done => { - if let Some(found) = - hint::match_post_nock(context, subject, sint.tag, sint.body, res) - { - res = found; + match hint::match_post_nock( + context, subject, sint.tag, None, sint.body, res, + ) { + Ok(Some(found)) => res = found, + Err(err) => break Err(err), + _ => {} } context.stack.pop::(); } @@ -1077,7 +1099,7 @@ mod hint { // XX: handle IndirectAtom tags match tag.as_direct()?.data() { tas!(b"sham") => { - if cfg!(feature="sham_hints") { + if cfg!(feature = "sham_hints") { let jet_formula = hint.as_cell()?; // XX: what is the head here? let jet_name = jet_formula.tail(); @@ -1094,7 +1116,11 @@ mod hint { Ok(mut nock_res) => { let stack = &mut context.stack; if unsafe { - !unifying_equality(stack, &mut nock_res, &mut jet_res) + !unifying_equality( + stack, + &mut nock_res, + &mut jet_res, + ) } { // XX: need string interpolation without allocation, then delete eprintln // let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, nock_res, jet_res); @@ -1146,7 +1172,7 @@ mod hint { Ok(None) } } else { - Ok(None) + Ok(None) } } tas!(b"memo") => { @@ -1249,14 +1275,15 @@ mod hint { context: &mut Context, subject: Noun, tag: Atom, + hint: Option, body: Noun, res: Noun, - ) -> Option { + ) -> Result, NockErr> { let stack = &mut context.stack; let cache = &mut context.cache; // XX: handle IndirectAtom tags - match tag.direct()?.data() { + match tag.as_direct()?.data() { tas!(b"memo") => { let mut key = Cell::new(*stack, subject, body).as_noun(); **cache = (*cache).insert(stack, &mut key, res); @@ -1265,31 +1292,33 @@ mod hint { mean_pop(stack); } tas!(b"fast") => { - let clue = raw_slot_result(hint, 7)?; - let chum = raw_slot_result(clue, 2)?; - let parent_formula_op = raw_slot_result(clue, 12)?.as_atom()?.as_direct()?; - let parent_formula_ax = raw_slot_result(clue, 13)?.as_atom()?; - if parent_formula_op.data() == 1 { - if parent_formula_ax.as_direct()?.data() == 0 { - let changed = cold.register(stack, res, parent_formula_ax, chum)?; - if changed { - *warm = Warm::init(stack, cold, hot); + if let Some(hint) = hint { + let clue = hint.slot(3)?; + let chum = clue.slot(2)?; + let parent_formula_op = clue.slot(12)?.as_atom()?.as_direct()?; + let parent_formula_ax = clue.slot(13)?.as_atom()?; + + if parent_formula_op.data() == 1 { + if parent_formula_ax.as_direct()?.data() == 0 { + let changed = + context.cold.register(stack, res, parent_formula_ax, chum)?; + if changed { + *context.warm = Warm::init(stack, context.cold, context.hot); + } + } else { + return Err(NockErr::Deterministic); } - Ok(()) } else { - Err(()) - } - } else { - let changed = cold.register(stack, res, parent_formula_ax, chum)?; - if changed { - *warm = Warm::init(stack, cold, hot); + let changed = context.cold.register(stack, res, parent_formula_ax, chum)?; + if changed { + *context.warm = Warm::init(stack, context.cold, context.hot); + } } - Ok(()) } } _ => {} } - None + Ok(None) } } diff --git a/rust/ares/src/jets.rs b/rust/ares/src/jets.rs index 08f5ab97..cce90aee 100644 --- a/rust/ares/src/jets.rs +++ b/rust/ares/src/jets.rs @@ -12,12 +12,15 @@ pub mod tree; use crate::interpreter::Context; use crate::jets::bits::*; +use crate::jets::cold::Cold; use crate::jets::form::*; use crate::jets::hash::*; +use crate::jets::hot::Hot; use crate::jets::math::*; use crate::jets::nock::*; use crate::jets::text::*; use crate::jets::tree::*; +use crate::jets::warm::Warm; use crate::mem::NockStack; use crate::noun::{self, Noun, Slots}; use ares_macros::tas; @@ -313,10 +316,17 @@ pub mod util { } pub fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) { + let mut cache = Hamt::::new(); + let mut cold = Cold::new(stack); + let mut warm = Warm::new(); + let hot = Hot::init(stack); let mut context = Context { stack, newt: None, - cache: &mut Hamt::::new(), + cache: &mut cache, + cold: &mut cold, + warm: &mut warm, + hot: &hot, }; let sam = T(context.stack, &[D(0), sam, D(0)]); let jet_res = assert_no_alloc(|| jet(&mut context, sam).unwrap()); @@ -334,10 +344,17 @@ pub mod util { } pub fn assert_jet_err(stack: &mut NockStack, jet: Jet, sam: Noun, err: JetErr) { + let mut cache = Hamt::::new(); + let mut cold = Cold::new(stack); + let mut warm = Warm::new(); + let hot = Hot::init(stack); let mut context = Context { stack, newt: None, - cache: &mut Hamt::::new(), + cache: &mut cache, + cold: &mut cold, + warm: &mut warm, + hot: &hot, }; let sam = T(context.stack, &[D(0), sam, D(0)]); let jet_res = jet(&mut context, sam); diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index 914b811b..a234f1ab 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -1,8 +1,7 @@ use crate::hamt::Hamt; -use crate::interpreter::slot_result; use crate::mem::{unifying_equality, NockStack, Preserve}; -use crate::noun::{Atom, DirectAtom, Noun, D, T}; -use bitvec::prelude::BitSlice; +use crate::noun; +use crate::noun::{Atom, DirectAtom, Noun, Slots, D, T}; use std::ptr::copy_nonoverlapping; use std::ptr::null_mut; @@ -87,11 +86,11 @@ impl Batteries { }; }; }; - if let Ok(mut core_battery) = slot_result(core, BitSlice::from_element(&2u64)) { + if let Ok(mut core_battery) = core.slot(2) { if unsafe { !unifying_equality(stack, &mut core_battery, battery) } { return false; }; - if let Ok(core_parent) = slot_result(core, parent_axis.as_bitslice()) { + if let Ok(core_parent) = core.slot_atom(parent_axis) { core = core_parent; continue; } else { @@ -248,8 +247,8 @@ struct ColdMem { /// key: root noun /// value: root path root_to_paths: Hamt, - /// key: register path to core - /// value: linked list of sequences of nested batteries + /// key: registered path to core + /// value: linked list of a sequence of nested batteries path_to_batteries: Hamt, } @@ -270,6 +269,17 @@ impl Preserve for Cold { } } +pub enum Error { + NoParent, + BadNock, +} + +impl From for Error { + fn from(_: noun::Error) -> Self { + Error::BadNock + } +} + impl Cold { pub fn new(stack: &mut NockStack) -> Self { let battery_to_paths = Hamt::new(); @@ -306,8 +316,8 @@ impl Cold { mut core: Noun, parent_axis: Atom, mut chum: Noun, - ) -> Result { - let mut battery = slot_result(core, BitSlice::from_element(&2u64))?; + ) -> Result { + let mut battery = core.slot(2)?; unsafe { // Are we registering a root? @@ -370,7 +380,7 @@ impl Cold { } } - let mut parent = slot_result(core, parent_axis.as_bitslice())?; + 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) { for path in paths { @@ -388,9 +398,10 @@ impl Cold { } } - let mut parent_battery = slot_result(parent, BitSlice::from_element(&2u64))?; + let mut parent_battery = parent.slot(2)?; - let mut ret: Result = Err(()); // err until we actually found a parent + // err until we actually found a parent + let mut ret: Result = Err(Error::NoParent); let mut path_to_batteries = (*(self.0)).path_to_batteries; let mut battery_to_paths = (*(self.0)).battery_to_paths; diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index 18a819c2..77d9806a 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -1,10 +1,9 @@ use crate::hamt::Hamt; -use crate::interpreter::slot_result; use crate::jets::cold::{Batteries, Cold}; use crate::jets::hot::Hot; use crate::jets::Jet; use crate::mem::{NockStack, Preserve}; -use crate::noun::Noun; +use crate::noun::{Noun, Slots}; use std::ptr::{copy_nonoverlapping, null_mut}; pub struct Warm(Hamt); @@ -110,16 +109,16 @@ impl Warm { } } - pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: Hot) -> Self { + pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> Self { let mut warm = Self::new(); - for (mut path, axis, jet) in hot { + for (mut path, axis, jet) in *hot { let batteries_list = cold.find(stack, &mut path); for batteries in batteries_list { let mut batteries_tmp = batteries; let (battery, _parent_axis) = batteries_tmp .next() .expect("IMPOSSIBLE: empty battery entry in cold state"); - if let Ok(mut formula) = unsafe { slot_result(*battery, axis.as_bitslice()) } { + if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } { warm.insert(stack, &mut formula, path, batteries, jet); } else { eprintln!("Bad axis {} into formula {:?}", axis, battery); diff --git a/rust/ares/src/main.rs b/rust/ares/src/main.rs index 2c7ad10b..73ea4f52 100644 --- a/rust/ares/src/main.rs +++ b/rust/ares/src/main.rs @@ -65,13 +65,17 @@ fn main() -> io::Result<()> { let input_cell = input .as_cell() .expect("Input must be jam of subject/formula pair"); + let mut cache = Hamt::::new(); + let mut cold = Cold::new(&mut stack); + let mut warm = Warm::new(); + let hot = Hot::init(&mut stack); let mut context = Context { stack: &mut stack, newt: None, - cache: &mut Hamt::::new(), - cold: &mut Cold::new(&mut stack); - warm: &mut Warm::new(); - hot: &mut Hot::init(&mut stack); + cache: &mut cache, + cold: &mut cold, + warm: &mut warm, + hot: &hot, }; let result = interpret(&mut context, input_cell.head(), input_cell.tail()).expect("nock failed"); diff --git a/rust/ares/src/noun.rs b/rust/ares/src/noun.rs index 1da0878b..232d3918 100644 --- a/rust/ares/src/noun.rs +++ b/rust/ares/src/noun.rs @@ -1045,20 +1045,6 @@ impl Noun { Noun { raw } } - pub unsafe fn assert_no_forwarding_pointers(self) { - let mut dbg_stack = Vec::new(); - dbg_stack.push(self); - while !dbg_stack.is_empty() { - let noun = dbg_stack.pop().unwrap(); - if noun.raw & FORWARDING_MASK == FORWARDING_TAG { - panic!("Noun {:#x} has a forwarding pointer as a child", self.raw); - } else if let Ok(cell) = noun.as_cell() { - dbg_stack.push(cell.tail()); - dbg_stack.push(cell.head()); - } - } - } - /** Produce the total size of a noun, in words * * This counts the total size, see mass_frame() to count the size in the current frame. diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index e389fef0..fdddfe75 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -3,9 +3,9 @@ use crate::interpreter; use crate::interpreter::{inc, interpret, Tone}; use crate::jets::cold::Cold; use crate::jets::hot::Hot; -use crate::jets::warm::Warm; use crate::jets::nock::util::mook; use crate::jets::text::util::lent; +use crate::jets::warm::Warm; use crate::mem::NockStack; use crate::mug::mug_u32; use crate::newt::Newt; @@ -48,9 +48,9 @@ impl Context { let newt = Newt::new(); let cache = Hamt::::new(); - let cold = Cold::new(stack); + let cold = Cold::new(&mut stack); let warm = Warm::new(); - let hot = Hot::init(stack); + let hot = Hot::init(&mut stack); let (epoch, event_num, arvo) = snapshot.load(&mut stack).unwrap_or((0, 0, D(0))); let mug = mug_u32(&mut stack, arvo); @@ -99,7 +99,7 @@ impl Context { cache: &mut self.cache, cold: &mut self.cold, warm: &mut self.warm, - hot: &mut self.hot, + hot: &self.hot, } } From e284b0e97b82f9b15fcd0a5f4db0d933965f39f6 Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Tue, 17 Oct 2023 13:50:41 -0600 Subject: [PATCH 15/15] Address PR review --- hoon/scaffolding/playpen.hoon | 13 +-- rust/ares/src/hamt.rs | 9 +- rust/ares/src/interpreter.rs | 153 +++++++++++++++++++++------------- rust/ares/src/jets.rs | 2 + rust/ares/src/jets/cold.rs | 61 ++++++++------ rust/ares/src/jets/hot.rs | 41 +++++---- rust/ares/src/jets/nock.rs | 4 +- rust/ares/src/jets/warm.rs | 2 +- rust/ares/src/mem.rs | 10 +-- 9 files changed, 173 insertions(+), 122 deletions(-) diff --git a/hoon/scaffolding/playpen.hoon b/hoon/scaffolding/playpen.hoon index 0eb9e78d..1939da6b 100644 --- a/hoon/scaffolding/playpen.hoon +++ b/hoon/scaffolding/playpen.hoon @@ -226,6 +226,7 @@ ++ lent :: length ~/ %lent |= a=(list) + ~> %sham.%lent ^- @ =+ b=0 |- @@ -579,7 +580,6 @@ ++ dor :: tree order ~/ %dor |= [a=* b=*] - ~> %sham.%dor ^- ? ?: =(a b) & ?. ?=(@ a) @@ -593,7 +593,6 @@ ++ gor :: mug order ~/ %gor |= [a=* b=*] - ~> %sham.%gor ^- ? =+ [c=(mug a) d=(mug b)] ?: =(c d) @@ -603,7 +602,6 @@ ++ mor :: more mug order ~/ %mor |= [a=* b=*] - ~> %sham.%mor ^- ? =+ [c=(mug (mug a)) d=(mug (mug b))] ?: =(c d) @@ -626,13 +624,11 @@ ++ in ~/ %in =| a=(tree) :: (set) - ~> %sham.%in |@ ++ apt =< $ ~/ %apt =| [l=(unit) r=(unit)] - ~> %sham.%apt |. ^- ? ?~ a & ?& ?~(l & (gor n.a u.l)) @@ -644,7 +640,6 @@ ++ del ~/ %del |* b=* - ~> %sham.%del |- ^+ a ?~ a ~ @@ -662,7 +657,6 @@ ++ put ~/ %put |* b=* - ~> %sham.%put |- ^+ a ?~ a [b ~ ~] @@ -686,13 +680,11 @@ ++ by ~/ %by =| a=(tree (pair)) :: (map) - ~> %sham.%by =* node ?>(?=(^ a) n.a) |@ ++ del ~/ %del |* b=* - ~> %sham.%del |- ^+ a ?~ a ~ @@ -711,7 +703,6 @@ =< $ ~/ %apt =| [l=(unit) r=(unit)] - ~> %sham.%apt |. ^- ? ?~ a & ?& ?~(l & &((gor p.n.a u.l) !=(p.n.a u.l))) @@ -725,7 +716,6 @@ ++ get ~/ %get |* b=* - ~> %sham.%get => .(b `_?>(?=(^ a) p.n.a)`b) |- ^- (unit _?>(?=(^ a) q.n.a)) ?~ a @@ -739,7 +729,6 @@ ++ put ~/ %put |* [b=* c=*] - ~> %sham.%put |- ^+ a ?~ a [[b c] ~ ~] diff --git a/rust/ares/src/hamt.rs b/rust/ares/src/hamt.rs index 32e4d5cb..5c631730 100644 --- a/rust/ares/src/hamt.rs +++ b/rust/ares/src/hamt.rs @@ -434,7 +434,7 @@ impl Default for Hamt { impl Preserve for Hamt { unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.struct_is_in(self.0.buffer, self.0.size()); + stack.assert_struct_is_in(self.0.buffer, self.0.size()); let mut traversal_stack: [Option<(Stem, u32)>; 6] = [None; 6]; traversal_stack[0] = Some((self.0, 0)); let mut traversal_depth = 1; @@ -456,15 +456,15 @@ impl Preserve for Hamt { continue 'check_stem; } Some((Left(next_stem), _idx)) => { - stack.struct_is_in(next_stem.buffer, next_stem.size()); + stack.assert_struct_is_in(next_stem.buffer, next_stem.size()); assert!(traversal_depth <= 5); // will increment - traversal_stack[traversal_depth - 1].as_mut().unwrap().1 = position + 1; + traversal_stack[traversal_depth - 1] = Some((stem, position + 1)); traversal_stack[traversal_depth] = Some((next_stem, 0)); traversal_depth += 1; continue 'check; } Some((Right(leaf), _idx)) => { - stack.struct_is_in(leaf.buffer, leaf.len); + stack.assert_struct_is_in(leaf.buffer, leaf.len); for pair in leaf.to_mut_slice().iter() { pair.0.assert_in_stack(stack); pair.1.assert_in_stack(stack); @@ -476,6 +476,7 @@ impl Preserve for Hamt { } } } + unsafe fn preserve(&mut self, stack: &mut NockStack) { if stack.is_in_frame(self.0.buffer) { let dest_buffer = stack.struct_alloc_in_previous_frame(self.0.size()); diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index e8a314ef..c10fb847 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -235,16 +235,16 @@ enum NockWork { Work11S(Nock11S), } -pub struct Context<'a, 'b, 'c, 'd, 'e, 'f> { +pub struct Context<'a> { pub stack: &'a mut NockStack, // For printing slogs; if None, print to stdout; Option slated to be removed - pub newt: Option<&'b mut Newt>, + pub newt: Option<&'a mut Newt>, // Per-event cache; option to share cache with virtualized events - pub cache: &'c mut Hamt, + pub cache: &'a mut Hamt, // XX: persistent memo cache - pub cold: &'d mut Cold, - pub warm: &'e mut Warm, - pub hot: &'f Hot, + pub cold: &'a mut Cold, + pub warm: &'a mut Warm, + pub hot: &'a Hot, } #[derive(Debug)] @@ -333,7 +333,6 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.preserve(context.cold); context.stack.preserve(context.warm); context.stack.preserve(&mut res); - context.stack.frame_pop(); debug_assertions(context.stack, orig_subject); @@ -403,18 +402,21 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res push_formula(context.stack, vale.formula, false)?; } Todo2::ComputeResult => { - // XX: why are these mut? if let Some(jet) = context .warm .find_jet(context.stack, &mut vale.subject, &mut res) { - // a jet match - if let Ok(jet_res) = jet(context, vale.subject) { - // XX TODO: nondeterministic errors - res = jet_res; - context.stack.pop::(); - continue; + match jet(context, vale.subject) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } } }; @@ -579,18 +581,22 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res } Todo9::ComputeResult => { if let Ok(mut formula) = res.slot_atom(kale.axis) { - // XX: why mut? if let Some(jet) = context.warm.find_jet(context.stack, &mut res, &mut formula) { - // a jet match - if let Ok(jet_res) = jet(context, res) { - // XX TODO: nondeterministic errors - res = jet_res; - context.stack.pop::(); - continue; - }; + match jet(context, res) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } + } }; + if kale.tail { context.stack.pop::(); subject = res; @@ -674,10 +680,11 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.pop::(); } Ok(None) => { - dint.todo = Todo11D::Done; if dint.tail { context.stack.pop::(); } else { + dint.todo = Todo11D::Done; + dint.hint = res; *context.stack.top() = NockWork::Work11D(dint); } push_formula(context.stack, dint.body, dint.tail)?; @@ -711,10 +718,10 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.pop::(); } Ok(None) => { - sint.todo = Todo11S::Done; if sint.tail { context.stack.pop::(); } else { + sint.todo = Todo11S::Done; *context.stack.top() = NockWork::Work11S(sint); } push_formula(context.stack, sint.body, sint.tail)?; @@ -1067,7 +1074,8 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom { mod hint { use super::*; use crate::jets; - use crate::jets::nock::util::mook; + use crate::jets::cold; + use crate::jets::nock::util::{mook, LEAF}; use crate::mem::unifying_equality; use crate::noun::{tape, Atom, Cell, Noun, D, T}; use crate::serf::TERMINATOR; @@ -1195,19 +1203,12 @@ mod hint { // XX: handle IndirectAtom tags match tag.as_direct()?.data() { tas!(b"slog") => { - let (_, hint_res) = hint.ok_or(NockErr::Deterministic)?; - let slog_cell = hint_res.as_cell()?; + let (_form, clue) = hint.ok_or(NockErr::Deterministic)?; + let slog_cell = clue.as_cell()?; let pri = slog_cell.head().as_direct()?.data(); let tank = slog_cell.tail(); - if context.newt.is_none() { - eprintln!("raw slog: {} {}", pri, tank); - } else { - context - .newt - .as_mut() - .unwrap() - .slog(context.stack, pri, tank); - } + + slog(context.stack, &mut context.newt, pri, tank); Ok(None) } tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { @@ -1217,8 +1218,8 @@ mod hint { } let stack = &mut context.stack; - let (_, hint_res) = hint.ok_or(NockErr::Deterministic)?; - let noun = T(*stack, &[tag.as_noun(), hint_res]); + let (_form, clue) = hint.ok_or(NockErr::Deterministic)?; + let noun = T(*stack, &[tag.as_noun(), clue]); mean_push(stack, noun); Ok(None) } @@ -1246,11 +1247,7 @@ mod hint { } let cell = list.as_cell().unwrap(); - if context.newt.is_none() { - eprintln!("raw slog: {} {}", 0, cell.head()); - } else { - context.newt.as_mut().unwrap().slog(stack, 0, cell.head()); - } + slog(stack, &mut context.newt, 0, cell.head()); list = cell.tail(); } @@ -1281,6 +1278,7 @@ mod hint { ) -> Result, NockErr> { let stack = &mut context.stack; let cache = &mut context.cache; + let newt = &mut context.newt; // XX: handle IndirectAtom tags match tag.as_direct()?.data() { @@ -1292,28 +1290,50 @@ mod hint { mean_pop(stack); } tas!(b"fast") => { - if let Some(hint) = hint { - let clue = hint.slot(3)?; - let chum = clue.slot(2)?; - let parent_formula_op = clue.slot(12)?.as_atom()?.as_direct()?; - let parent_formula_ax = clue.slot(13)?.as_atom()?; - - if parent_formula_op.data() == 1 { - if parent_formula_ax.as_direct()?.data() == 0 { - let changed = - context.cold.register(stack, res, parent_formula_ax, chum)?; - if changed { - *context.warm = Warm::init(stack, context.cold, context.hot); + if let Some(clue) = hint { + let cold_res: cold::Result = { + let chum = clue.slot(2)?; + let parent_formula_op = clue.slot(12)?.as_atom()?.as_direct()?; + let parent_formula_ax = clue.slot(13)?.as_atom()?; + + if parent_formula_op.data() == 1 { + if parent_formula_ax.as_direct()?.data() == 0 { + context.cold.register(stack, res, parent_formula_ax, chum) + } else { + // XX: Need better message in slog; need better slogging tools + // format!("invalid root parent axis: {} {}", chum, parent_formula_ax) + let tape = + tape(*stack, "serf: cold: register: invalid root parent axis"); + slog_leaf(stack, newt, tape); + Ok(false) } } else { - return Err(NockErr::Deterministic); + context.cold.register(stack, res, parent_formula_ax, chum) } - } else { - let changed = context.cold.register(stack, res, parent_formula_ax, chum)?; - if changed { - *context.warm = Warm::init(stack, context.cold, context.hot); + }; + + match cold_res { + Ok(true) => *context.warm = Warm::init(stack, context.cold, context.hot), + Err(cold::Error::NoParent) => { + // XX: Need better message in slog; need better slogging tools + // format!("could not find parent battery at given axis: {} {}", chum, parent_formula_ax) + let tape = tape( + *stack, + "serf: cold: register: could not find parent battery at given axis", + ); + slog_leaf(stack, newt, tape); + } + Err(cold::Error::BadNock) => { + // XX: Need better message in slog; need better slogging tools + // format!("bad clue formula: {}", clue) + let tape = tape(*stack, "serf: cold: register: bad clue formula"); + slog_leaf(stack, newt, tape); } + _ => {} } + } else { + let tape = tape(*stack, "serf: cold: register: no clue for %fast"); + slog_leaf(stack, newt, tape); } } _ => {} @@ -1321,4 +1341,17 @@ mod hint { Ok(None) } + + fn slog_leaf(stack: &mut NockStack, newt: &mut Option<&mut Newt>, tape: Noun) { + let tank = T(stack, &[LEAF, tape]); + slog(stack, newt, 0u64, tank); + } + + fn slog(stack: &mut NockStack, newt: &mut Option<&mut Newt>, pri: u64, tank: Noun) { + if newt.is_none() { + eprintln!("raw slog: {} {}", pri, tank); + } else { + newt.as_mut().unwrap().slog(stack, pri, tank); + } + } } diff --git a/rust/ares/src/jets.rs b/rust/ares/src/jets.rs index cce90aee..53a349f0 100644 --- a/rust/ares/src/jets.rs +++ b/rust/ares/src/jets.rs @@ -316,6 +316,7 @@ pub mod util { } pub fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) { + // XX: consider making a mock context singleton that tests can use let mut cache = Hamt::::new(); let mut cold = Cold::new(stack); let mut warm = Warm::new(); @@ -344,6 +345,7 @@ pub mod util { } pub fn assert_jet_err(stack: &mut NockStack, jet: Jet, sam: Noun, err: JetErr) { + // XX: consider making a mock context singleton that tests can use let mut cache = Hamt::::new(); let mut cold = Cold::new(stack); let mut warm = Warm::new(); diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index a234f1ab..c3bff84f 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -5,6 +5,19 @@ use crate::noun::{Atom, DirectAtom, Noun, Slots, D, T}; use std::ptr::copy_nonoverlapping; use std::ptr::null_mut; +pub enum Error { + NoParent, + BadNock, +} + +impl From for Error { + fn from(_: noun::Error) -> Self { + Error::BadNock + } +} + +pub type Result = std::result::Result; + #[derive(Copy, Clone)] pub struct Batteries(*mut BatteriesMem); @@ -24,7 +37,7 @@ impl Preserve for Batteries { }; let mut cursor = *self; loop { - stack.struct_is_in(cursor.0, 1); + stack.assert_struct_is_in(cursor.0, 1); (*cursor.0).battery.assert_in_stack(stack); (*cursor.0).parent_axis.assert_in_stack(stack); if (*cursor.0).parent_batteries.0.is_null() { @@ -76,13 +89,20 @@ impl Iterator for Batteries { impl Batteries { pub fn matches(self, stack: &mut NockStack, mut core: Noun) -> bool { + let mut root_found: bool = false; + for (battery, parent_axis) in self { + if root_found { + panic!("cold: core matched to root, but more data remains in path"); + } + if let Ok(d) = parent_axis.as_direct() { if d.data() == 0 { - if unsafe { !unifying_equality(stack, &mut core, battery) } { - return false; - } else { + if unsafe { unifying_equality(stack, &mut core, battery) } { + root_found = true; continue; + } else { + return false; }; }; }; @@ -100,6 +120,11 @@ impl Batteries { return false; } } + + if !root_found { + panic!("cold: core matched exactly, but never matched root"); + } + true } } @@ -122,7 +147,7 @@ impl Preserve for BatteriesList { } let mut cursor = *self; loop { - stack.struct_is_in(cursor.0, 1); + stack.assert_struct_is_in(cursor.0, 1); (*cursor.0).batteries.assert_in_stack(stack); if (*cursor.0).next.0.is_null() { break; @@ -192,7 +217,7 @@ impl Preserve for NounList { }; let mut cursor = *self; loop { - stack.struct_is_in(cursor.0, 1); + stack.assert_struct_is_in(cursor.0, 1); (*cursor.0).element.assert_in_stack(stack); if (*cursor.0).next.0.is_null() { break; @@ -241,7 +266,7 @@ pub struct Cold(*mut ColdMem); struct ColdMem { /// key: outermost battery - /// value: registered path to core + /// value: possible registered paths for core battery_to_paths: Hamt, /// Roots /// key: root noun @@ -254,7 +279,7 @@ struct ColdMem { impl Preserve for Cold { unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.struct_is_in(self.0, 1); + stack.assert_struct_is_in(self.0, 1); (*self.0).battery_to_paths.assert_in_stack(stack); (*self.0).root_to_paths.assert_in_stack(stack); (*self.0).path_to_batteries.assert_in_stack(stack); @@ -269,17 +294,6 @@ impl Preserve for Cold { } } -pub enum Error { - NoParent, - BadNock, -} - -impl From for Error { - fn from(_: noun::Error) -> Self { - Error::BadNock - } -} - impl Cold { pub fn new(stack: &mut NockStack) -> Self { let battery_to_paths = Hamt::new(); @@ -308,7 +322,7 @@ impl Cold { /// register a core, return a boolean of whether we actually needed to register (false -> /// already registered) /// - /// XX TODO validate chum + /// XX: validate chum Noun as $chum #[allow(clippy::result_unit_err)] pub fn register( &mut self, @@ -316,9 +330,7 @@ impl Cold { mut core: Noun, parent_axis: Atom, mut chum: Noun, - ) -> Result { - let mut battery = core.slot(2)?; - + ) -> Result { unsafe { // Are we registering a root? if let Ok(parent_axis_direct) = parent_axis.as_direct() { @@ -380,6 +392,7 @@ 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) { @@ -401,7 +414,7 @@ impl Cold { let mut parent_battery = parent.slot(2)?; // err until we actually found a parent - let mut ret: Result = Err(Error::NoParent); + let mut ret: Result = Err(Error::NoParent); let mut path_to_batteries = (*(self.0)).path_to_batteries; let mut battery_to_paths = (*(self.0)).battery_to_paths; diff --git a/rust/ares/src/jets/hot.rs b/rust/ares/src/jets/hot.rs index f0aba3b7..78ca9edc 100644 --- a/rust/ares/src/jets/hot.rs +++ b/rust/ares/src/jets/hot.rs @@ -9,32 +9,45 @@ const A_50: Either = Right((tas!(b"a"), 50)); // This is the const state all in one spot as literals #[allow(clippy::complexity)] const HOT_STATE: &[(&[Either], u64, Jet)] = &[ - (&[A_50, Left(tas!(b"dec"))], 1, jet_dec), (&[A_50, Left(tas!(b"add"))], 1, jet_add), - (&[A_50, Left(tas!(b"sub"))], 1, jet_sub), - (&[A_50, Left(tas!(b"mul"))], 1, jet_mul), + (&[A_50, Left(tas!(b"dec"))], 1, jet_dec), (&[A_50, Left(tas!(b"div"))], 1, jet_div), - (&[A_50, Left(tas!(b"mod"))], 1, jet_mod), (&[A_50, Left(tas!(b"dvr"))], 1, jet_dvr), - (&[A_50, Left(tas!(b"lth"))], 1, jet_lth), - (&[A_50, Left(tas!(b"lte"))], 1, jet_lte), (&[A_50, Left(tas!(b"gth"))], 1, jet_gth), (&[A_50, Left(tas!(b"gte"))], 1, jet_gte), + (&[A_50, Left(tas!(b"lte"))], 1, jet_lte), + (&[A_50, Left(tas!(b"lth"))], 1, jet_lth), + (&[A_50, Left(tas!(b"mod"))], 1, jet_mod), + (&[A_50, Left(tas!(b"mul"))], 1, jet_mul), + (&[A_50, Left(tas!(b"sub"))], 1, jet_sub), + // + (&[A_50, Left(tas!(b"cap"))], 1, jet_cap), + (&[A_50, Left(tas!(b"mas"))], 1, jet_mas), + // + (&[A_50, Left(tas!(b"lent"))], 1, jet_lent), + // (&[A_50, Left(tas!(b"bex"))], 1, jet_bex), + (&[A_50, Left(tas!(b"can"))], 1, jet_can), + (&[A_50, Left(tas!(b"cat"))], 1, jet_cat), + (&[A_50, Left(tas!(b"cut"))], 1, jet_cut), + (&[A_50, Left(tas!(b"end"))], 1, jet_end), (&[A_50, Left(tas!(b"lsh"))], 1, jet_lsh), + (&[A_50, Left(tas!(b"met"))], 1, jet_met), + (&[A_50, Left(tas!(b"rap"))], 1, jet_rap), + (&[A_50, Left(tas!(b"rep"))], 1, jet_rep), + (&[A_50, Left(tas!(b"rev"))], 1, jet_rev), + (&[A_50, Left(tas!(b"rip"))], 1, jet_rip), (&[A_50, Left(tas!(b"rsh"))], 1, jet_rsh), + // (&[A_50, Left(tas!(b"con"))], 1, jet_con), (&[A_50, Left(tas!(b"dis"))], 1, jet_dis), (&[A_50, Left(tas!(b"mix"))], 1, jet_mix), - (&[A_50, Left(tas!(b"end"))], 1, jet_end), - (&[A_50, Left(tas!(b"cat"))], 1, jet_cat), - (&[A_50, Left(tas!(b"cut"))], 1, jet_cut), - (&[A_50, Left(tas!(b"can"))], 1, jet_can), - (&[A_50, Left(tas!(b"rep"))], 1, jet_rep), - (&[A_50, Left(tas!(b"rip"))], 1, jet_rip), - (&[A_50, Left(tas!(b"met"))], 1, jet_met), + // (&[A_50, Left(tas!(b"mug"))], 1, jet_mug), - (&[A_50, Left(tas!(b"rev"))], 1, jet_rev), + // + (&[A_50, Left(tas!(b"scow"))], 1, jet_scow), + // + (&[A_50, Left(tas!(b"mink"))], 1, jet_mink), ]; #[derive(Copy, Clone)] diff --git a/rust/ares/src/jets/nock.rs b/rust/ares/src/jets/nock.rs index ed22fc81..a3dc4609 100644 --- a/rust/ares/src/jets/nock.rs +++ b/rust/ares/src/jets/nock.rs @@ -29,8 +29,8 @@ pub mod util { use ares_macros::tas; use std::result; - const LEAF: Noun = D(tas!(b"leaf")); - const ROSE: Noun = D(tas!(b"rose")); + pub const LEAF: Noun = D(tas!(b"leaf")); + pub const ROSE: Noun = D(tas!(b"rose")); pub fn mink(context: &mut Context, subject: Noun, formula: Noun) -> jets::Result { // XX: no partial traces; all of our traces go down to the "home road" diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index 77d9806a..4a3b52d1 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -36,7 +36,7 @@ impl Preserve for WarmEntry { }; let mut cursor = *self; loop { - stack.struct_is_in(cursor.0, 1); + stack.assert_struct_is_in(cursor.0, 1); (*cursor.0).batteries.assert_in_stack(stack); (*cursor.0).path.assert_in_stack(stack); if (*cursor.0).next.0.is_null() { diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 9d3baad8..90cb32e7 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -468,7 +468,7 @@ impl NockStack { assert_no_junior_pointers!(self, *noun); } - pub unsafe fn struct_is_in(&self, ptr: *const T, count: usize) { + pub unsafe fn assert_struct_is_in(&self, ptr: *const T, count: usize) { let ap = (if self.pc { *(self.prev_alloc_pointer_pointer()) } else { @@ -494,7 +494,7 @@ impl NockStack { ); } - unsafe fn noun_in(&self, noun: Noun) { + unsafe fn assert_noun_in(&self, noun: Noun) { let mut dbg_stack = Vec::new(); dbg_stack.push(noun); let ap = (if self.pc { @@ -1085,7 +1085,7 @@ impl Preserve for IndirectAtom { *self = IndirectAtom::from_raw_pointer(buf); } unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.noun_in(self.as_atom().as_noun()); + stack.assert_noun_in(self.as_atom().as_noun()); } } @@ -1100,7 +1100,7 @@ impl Preserve for Atom { } } unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.noun_in(self.as_noun()); + stack.assert_noun_in(self.as_noun()); } } @@ -1109,7 +1109,7 @@ impl Preserve for Noun { stack.copy(self); } unsafe fn assert_in_stack(&self, stack: &NockStack) { - stack.noun_in(*self); + stack.assert_noun_in(*self); } }