Merge branch 'status' into eamsden/integrate-pma-merge-tmp

This commit is contained in:
Edward Amsden 2023-12-11 08:52:48 -06:00
commit 7d0def5178
12 changed files with 950 additions and 259 deletions

View File

@ -9,6 +9,7 @@ use crate::jets::warm::Warm;
use crate::jets::JetErr;
use crate::mem::unifying_equality;
use crate::mem::NockStack;
use crate::mem::Preserve;
use crate::newt::Newt;
use crate::noun;
use crate::noun::{Atom, Cell, IndirectAtom, Noun, Slots, D, T};
@ -254,20 +255,59 @@ enum NockWork {
Work12(Nock12),
}
pub struct ContextSnapshot {
cold: Cold,
warm: Warm,
}
pub struct Context {
pub stack: NockStack,
// For printing slogs; if None, print to stdout; Option slated to be removed
pub newt: Newt,
pub cold: Cold,
pub warm: Warm,
pub hot: Hot,
// XX: persistent memo cache
// Per-event cache; option to share cache with virtualized events
pub cache: Hamt<Noun>,
pub scry_stack: Noun,
pub trace_info: Option<TraceInfo>,
}
impl Context {
pub fn save(&self) -> ContextSnapshot {
ContextSnapshot {
cold: self.cold,
warm: self.warm,
}
}
pub fn restore(&mut self, saved: &ContextSnapshot) {
self.cold = saved.cold;
self.warm = saved.warm;
}
/**
* For jets that need a stack frame internally.
*
* This ensures that the frame is cleaned up even if the closure short-circuites to an error
* result using e.g. the ? syntax. We need this method separately from with_frame to allow the
* jet to use the entire context without the borrow checker complaining about the mutable
* references.
*/
pub unsafe fn with_stack_frame<F, O>(&mut self, slots: usize, f: F) -> O
where
F: FnOnce(&mut Context) -> O,
O: Preserve,
{
self.stack.frame_push(slots);
let mut ret = f(self);
ret.preserve(&mut self.stack);
self.cache.preserve(&mut self.stack);
self.cold.preserve(&mut self.stack);
self.warm.preserve(&mut self.stack);
self.stack.frame_pop();
ret
}
}
#[derive(Clone, Copy, Debug)]
pub enum Error {
ScryBlocked(Noun), // path
@ -276,6 +316,26 @@ pub enum Error {
NonDeterministic(Noun), // trace
}
impl Preserve for Error {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self {
Error::ScryBlocked(ref mut path) => path.preserve(stack),
Error::ScryCrashed(ref mut trace) => trace.preserve(stack),
Error::Deterministic(ref mut trace) => trace.preserve(stack),
Error::NonDeterministic(ref mut trace) => trace.preserve(stack),
}
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
match self {
Error::ScryBlocked(ref path) => path.assert_in_stack(stack),
Error::ScryCrashed(ref trace) => trace.assert_in_stack(stack),
Error::Deterministic(ref trace) => trace.assert_in_stack(stack),
Error::NonDeterministic(ref trace) => trace.assert_in_stack(stack),
}
}
}
impl From<noun::Error> for Error {
fn from(_: noun::Error) -> Self {
Error::Deterministic(D(0))
@ -301,6 +361,7 @@ fn debug_assertions(stack: &mut NockStack, noun: Noun) {
pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result {
let terminator = Arc::clone(&TERMINATOR);
let orig_subject = subject; // for debugging
let snapshot = context.save();
let virtual_frame: *const u64 = context.stack.get_frame_pointer();
let mut res: Noun = D(0);
@ -858,7 +919,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
match nock {
Ok(res) => Ok(res),
Err(err) => Err(exit(context, virtual_frame, err)),
Err(err) => Err(exit(context, &snapshot, virtual_frame, err)),
}
}
@ -1075,10 +1136,16 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> result::Res
Ok(())
}
fn exit(context: &mut Context, virtual_frame: *const u64, error: Error) -> Error {
fn exit(
context: &mut Context,
snapshot: &ContextSnapshot,
virtual_frame: *const u64,
error: Error,
) -> Error {
unsafe {
let stack = &mut context.stack;
context.restore(snapshot);
let stack = &mut context.stack;
let mut preserve = match error {
Error::ScryBlocked(path) => path,
Error::Deterministic(t) | Error::NonDeterministic(t) | Error::ScryCrashed(t) => {
@ -1088,10 +1155,9 @@ fn exit(context: &mut Context, virtual_frame: *const u64, error: Error) -> Error
}
};
while (stack).get_frame_pointer() != virtual_frame {
(stack).preserve(&mut preserve);
// (stack).preserve(&mut context.cold);
(stack).frame_pop();
while stack.get_frame_pointer() != virtual_frame {
stack.preserve(&mut preserve);
stack.frame_pop();
}
match error {
@ -1225,8 +1291,9 @@ unsafe fn write_trace(context: &mut Context) {
let trace_stack = *(context.stack.local_noun_pointer(1) as *mut *const TraceStack);
// Abort writing to trace file if we encountered an error. This should
// result in a well-formed partial trace file.
if let Err(e) = write_nock_trace(&mut context.stack, info, trace_stack) {
eprintln!("\rserf: error writing nock trace to file: {:?}", e);
if let Err(_e) = write_nock_trace(&mut context.stack, info, trace_stack) {
// XX: need NockStack allocated string interpolation
// eprintln!("\rserf: error writing nock trace to file: {:?}", e);
context.trace_info = None;
}
}
@ -1291,31 +1358,21 @@ mod hint {
&mut jet_res,
)
} {
// XX: need string interpolation without allocation, then delete eprintln
// XX: need NockStack allocated string interpolation
// let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, nock_res, jet_res);
eprintln!(
"\rjet {} failed, raw: {:?}, jetted: {}",
jet_name, nock_res, jet_res
);
let tape = tape(stack, "jet mismatch");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
mean_push(stack, mean);
// let mean = T(stack, &[D(tas!(b"mean")), tape]);
// mean_push(stack, mean);
Some(Err(Error::Deterministic(D(0))))
} else {
Some(Ok(nock_res))
}
}
Err(error) => {
let stack = &mut context.stack;
// XX: need string interpolation without allocation, then delete eprintln
// XX: need NockStack allocated string interpolation
// let stack = &mut context.stack;
// let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, err, jet_res);
eprintln!(
"\rjet {} failed, raw: {:?}, jetted: {}",
jet_name, error, jet_res
);
let tape = tape(stack, "jet mismatch");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
mean_push(stack, mean);
// let mean = T(stack, &[D(tas!(b"mean")), tape]);
// mean_push(stack, mean);
match error {
Error::NonDeterministic(_) => {
@ -1331,12 +1388,11 @@ mod hint {
}
Err(JetErr::Punt) => None,
Err(err) => {
let stack = &mut context.stack;
// XX: need string interpolation without allocation
// XX: need NockStack allocated string interpolation
// let stack = &mut context.stack;
// let tape = tape(stack, "{} jet error in {}", err, jet_name);
let tape = tape(stack, "jet error");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
mean_push(stack, mean);
// let mean = T(stack, &[D(tas!(b"mean")), tape]);
// mean_push(stack, mean);
Some(Err(err.into()))
}
}

View File

@ -10,6 +10,7 @@ pub mod lock;
pub mod lute;
pub mod math;
pub mod nock;
pub mod parse;
pub mod serial;
pub mod sort;
pub mod tree;
@ -19,20 +20,21 @@ 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::hot::{Hot, URBIT_HOT_STATE};
use crate::jets::list::*;
use crate::jets::lute::*;
use crate::jets::math::*;
use crate::jets::nock::*;
use crate::jets::serial::*;
use crate::jets::sort::*;
use crate::jets::lock::aes::*;
use crate::jets::lock::ed::*;
use crate::jets::lock::sha::*;
use crate::jets::lute::*;
use crate::jets::math::*;
use crate::jets::nock::*;
use crate::jets::parse::*;
use crate::jets::serial::*;
use crate::jets::sort::*;
use crate::jets::tree::*;
use crate::jets::warm::Warm;
use crate::mem::NockStack;
use crate::mem::{NockStack, Preserve};
use crate::newt::Newt;
use crate::noun::{self, Noun, Slots, D};
use ares_macros::tas;
@ -53,6 +55,22 @@ pub enum JetErr {
Fail(Error), // Error; do not retry
}
impl Preserve for JetErr {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self {
JetErr::Punt => {}
JetErr::Fail(ref mut err) => err.preserve(stack),
}
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
match self {
JetErr::Punt => {}
JetErr::Fail(ref err) => err.assert_in_stack(stack),
}
}
}
impl From<Error> for JetErr {
fn from(err: Error) -> Self {
Self::Fail(err)
@ -148,6 +166,7 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
tas!(b"sivc_de") => Some(jet_sivc_de),
//
_ => {
// XX: need NockStack allocated string interpolation
// eprintln!("Unknown jet: {:?}", jet_name);
None
}
@ -166,7 +185,8 @@ pub fn get_jet_test_mode(_jet_name: Noun) -> bool {
pub mod util {
use super::*;
use crate::noun::{Noun, D};
use crate::interpreter::interpret;
use crate::noun::{Noun, D, T};
use bitvec::prelude::{BitSlice, Lsb0};
use std::result;
@ -267,6 +287,23 @@ pub mod util {
Ok(())
}
pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> {
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)]);
interpret(context, core, formula).map_err(JetErr::Fail)
}
pub fn slam(context: &mut Context, gate: Noun, sample: Noun) -> result::Result<Noun, JetErr> {
let core: Noun = T(
&mut context.stack,
&[
gate.as_cell()?.head(),
sample,
gate.as_cell()?.tail().as_cell()?.tail(),
],
);
kick(context, core, D(2))
}
pub mod test {
use super::*;
use crate::hamt::Hamt;
@ -280,7 +317,7 @@ pub mod util {
let newt = Newt::new_mock();
let cold = Cold::new(&mut stack);
let warm = Warm::new(&mut stack);
let hot = Hot::init(&mut stack);
let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
let cache = Hamt::<Noun>::new(&mut stack);
Context {
@ -306,7 +343,11 @@ pub mod util {
}
pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
assert_jet_door(context, jet, sam, D(0), res)
}
pub fn assert_jet_door(context: &mut Context, jet: Jet, sam: Noun, pay: Noun, res: Noun) {
let sam = T(&mut context.stack, &[D(0), sam, pay]);
let jet_res = assert_no_alloc(|| jet(context, sam).unwrap());
assert_noun_eq(&mut context.stack, jet_res, res);
}

View File

@ -4,8 +4,9 @@ use ares_macros::tas;
use either::Either::{self, Left, Right};
use std::ptr::null_mut;
// const A_50: Either<u64, (u64, u64)> = Right((b"a", 50));
const K_139: Either<&[u8], (u64, u64)> = Right((tas!(b"k"), 139));
/** Root for Hoon %k.139
*/
pub const K_139: Either<&[u8], (u64, u64)> = Right((tas!(b"k"), 139));
// // This is the const state all in one spot as literals
// #[allow(clippy::complexity)]
@ -57,8 +58,14 @@ const K_139: Either<&[u8], (u64, u64)> = Right((tas!(b"k"), 139));
// (&[A_50, Left(b"mink")], 1, jet_mink),
// ];
/**
* (path, axis in battery, jet function pointer)
* see the [Jet] typedef in ares::jets for the proper prototype
*/
pub type HotEntry = (&'static [Either<&'static [u8], (u64, u64)>], u64, Jet);
#[allow(clippy::complexity)]
const TRUE_HOT_STATE: &[(&[Either<&[u8], (u64, u64)>], u64, Jet)] = &[
pub const URBIT_HOT_STATE: &[HotEntry] = &[
(&[K_139, Left(b"one"), Left(b"add")], 1, jet_add),
(&[K_139, Left(b"one"), Left(b"dec")], 1, jet_dec),
(&[K_139, Left(b"one"), Left(b"div")], 1, jet_div),
@ -269,6 +276,170 @@ const TRUE_HOT_STATE: &[(&[Either<&[u8], (u64, u64)>], u64, Jet)] = &[
jet_sha1,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"last"),
],
1,
jet_last,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"bend"),
Left(b"fun"),
],
1,
jet_bend,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"comp"),
Left(b"fun"),
],
1,
jet_comp,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"glue"),
Left(b"fun"),
],
1,
jet_glue,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"pfix"),
],
1,
jet_pfix,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"pose"),
],
1,
jet_pose,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"sfix"),
],
1,
jet_sfix,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"easy"),
Left(b"fun"),
],
1,
jet_easy,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"here"),
Left(b"fun"),
],
1,
jet_here,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"just"),
Left(b"fun"),
],
1,
jet_just,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"mask"),
Left(b"fun"),
],
1,
jet_mask,
),
//
(
&[
K_139,
Left(b"one"),
Left(b"two"),
Left(b"tri"),
Left(b"qua"),
Left(b"stag"),
Left(b"fun"),
],
1,
jet_stag,
),
//
(
&[
K_139,
@ -595,10 +766,10 @@ const TRUE_HOT_STATE: &[(&[Either<&[u8], (u64, u64)>], u64, Jet)] = &[
pub struct Hot(*mut HotMem);
impl Hot {
pub fn init(stack: &mut NockStack) -> Self {
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> Self {
unsafe {
let mut next = Hot(null_mut());
for (htap, axe, jet) in TRUE_HOT_STATE {
for (htap, axe, jet) in constant_hot_state {
let mut a_path = D(0);
for i in *htap {
match i {

View File

@ -1,33 +1,12 @@
/** Virtualization jets
*/
use crate::hamt::Hamt;
use crate::interpreter::{interpret, Context, Error};
use crate::interpreter::Context;
use crate::jets::util::slot;
use crate::jets::{JetErr, Result};
use crate::noun::{Cell, Noun, D, NO, T, YES};
use crate::noun::{Noun, D, NO, T};
crate::gdb!();
// Deterministic scry crashes should have the following behaviour:
//
// root <-- bail, %crud
// mink <-- return Deterministic
// scry <-- return ScryCrashed
//
// root <-- bail, %crud
// mink <-- return Deterministic
// mink <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry <-- return ScryCrashed
//
// root
// mink <-- return Tone
// mink <-- return Deterministic
// mink <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry
//
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
// mink sample = [nock scry_namespace]
@ -36,45 +15,8 @@ pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
let v_formula = slot(arg, 5)?;
let scry_handler = slot(arg, 3)?;
let old_cache = context.cache;
let old_scry_stack = context.scry_stack;
context.cache = Hamt::<Noun>::new(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry_handler, old_scry_stack]);
match util::mink(context, v_subject, v_formula) {
Ok(noun) => {
context.cache = old_cache;
context.scry_stack = old_scry_stack;
Ok(noun)
}
Err(error) => match error {
Error::NonDeterministic(_) => Err(JetErr::Fail(error)),
Error::ScryCrashed(trace) => {
// When we enter a +mink call, we record the state of the scry handler stack at the
// time (i.e. the Noun representing (list scry)). Each scry will pop the head off of
// this scry handler stack and calls interpret(), using the rest of the scry handler
// stack in the event that it scries again recursively. When a scry succeeds, it
// replaces the scry handler that it used by pushing it back onto the top of the
// scry handler stack. However, it never does so when it fails. Therefore, we can
// tell which particular virtualization instance failed by comparing the scry
// handler stack at the time of failure (i.e. the scry handler stack in the context
// after a failed scry) with the scry handler stack at the time of the virtualization
// call. Thus, whenever a virtualized interpret() call fails with a
// Error::ScryCrashed, jet_mink() compares the two scry handler stack Nouns> If they
// are identical, jet_mink() bails with Error::Deterministic. Otherwise, it forwards
// the Error::ScryCrashed to the senior virtualization call.
if unsafe { context.scry_stack.raw_equals(old_scry_stack) } {
Err(JetErr::Fail(Error::Deterministic(trace)))
} else {
Err(JetErr::Fail(error))
}
}
Error::Deterministic(_) | Error::ScryBlocked(_) => {
panic!("scry: mink: unhandled errors in helper")
}
},
}
// Implicit error conversion
Ok(util::mink(context, v_subject, v_formula, scry_handler)?)
}
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result {
@ -90,18 +32,15 @@ pub fn jet_mure(context: &mut Context, subject: Noun) -> Result {
let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
match interpret(context, tap, fol) {
Ok(res) => {
context.scry_stack = context.scry_stack.as_cell()?.tail();
Ok(T(&mut context.stack, &[D(0), res]))
match util::mink(context, tap, fol, scry) {
Ok(tone) => {
if unsafe { tone.as_cell()?.head().raw_equals(D(0)) } {
Ok(tone)
} else {
Ok(D(0))
}
}
Err(error) => match error {
// Since we are using the pass-through scry handler, we know for a fact that a scry
// crash must have come from a senior virtualization context.
Error::NonDeterministic(_) | Error::ScryCrashed(_) => Err(JetErr::Fail(error)),
Error::Deterministic(_) | Error::ScryBlocked(_) => Ok(D(0)),
},
Err(err) => Err(JetErr::Fail(err)),
}
}
@ -110,37 +49,32 @@ pub fn jet_mute(context: &mut Context, subject: Noun) -> Result {
let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
match interpret(context, tap, fol) {
Ok(res) => {
context.scry_stack = context.scry_stack.as_cell()?.tail();
Ok(T(&mut context.stack, &[YES, res]))
let tone = util::mink(context, tap, fol, scry);
match util::mook(context, tone?.as_cell()?, false) {
Ok(toon) => {
match toon.head() {
x if unsafe { x.raw_equals(D(0)) } => Ok(toon.as_noun()),
x if unsafe { x.raw_equals(D(1)) } => {
// XX: Need to check that result is actually of type path
// return [[%leaf "mute.hunk"] ~] if not
let bon = util::smyt(&mut context.stack, toon.tail())?;
Ok(T(&mut context.stack, &[NO, bon, D(0)]))
}
x if unsafe { x.raw_equals(D(2)) } => Ok(T(&mut context.stack, &[NO, toon.tail()])),
_ => panic!("serf: mook: invalid toon"),
}
}
Err(error) => match error {
// Since we are using the pass-through scry handler, we know for a fact that a scry
// crash must have come from a senior virtualization context.
Error::NonDeterministic(_) | Error::ScryCrashed(_) => Err(JetErr::Fail(error)),
Error::ScryBlocked(path) => {
// XX: Need to check that result is actually of type path
// return [[%leaf "mute.hunk"] ~] if not
let bon = util::smyt(&mut context.stack, path)?;
Ok(T(&mut context.stack, &[NO, bon, D(0)]))
}
Error::Deterministic(trace) => {
let ton = Cell::new(&mut context.stack, D(2), trace);
let tun = util::mook(context, ton, false)?;
Ok(T(&mut context.stack, &[NO, tun.tail()]))
}
},
Err(err) => Err(JetErr::Fail(err)),
}
}
pub mod util {
use crate::hamt::Hamt;
use crate::interpreter::{interpret, Context, Error};
use crate::jets;
use crate::jets::bits::util::rip;
use crate::jets::form::util::scow;
use crate::jets::JetErr;
use crate::mem::NockStack;
use crate::noun::{tape, Cell, Noun, D, T};
use ares_macros::tas;
@ -157,7 +91,7 @@ pub mod util {
/// The classic "pass-through" scry handler.
pub fn pass_thru_scry(stack: &mut NockStack) -> Noun {
// > .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
// .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
// [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0]
let sig = T(stack, &[D(1), D(0)]);
let sam = T(stack, &[D(0), D(6)]);
@ -176,13 +110,94 @@ pub mod util {
T(stack, &[dos, gat])
}
pub fn mink(context: &mut Context, subject: Noun, formula: Noun) -> Result<Noun, Error> {
/// The "always-fail" scry
pub fn null_scry(stack: &mut NockStack) -> Noun {
// .* 0 != => ~ |=(^ ~)
// [[1 0] [0 0] 0]
let sig = T(stack, &[D(1), D(0)]);
let zap = T(stack, &[D(0), D(0)]);
T(stack, &[sig, zap, D(0)])
}
// Deterministic scry crashes should have the following behaviour:
//
// root <-- bail, %crud
// mink <-- return Deterministic
// scry <-- return ScryCrashed
//
// root <-- bail, %crud
// mink <-- return Deterministic
// mink <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry <-- return ScryCrashed
//
// root
// mink <-- return Tone
// mink <-- return Deterministic
// mink <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry <-- return ScryCrashed
// scry
//
pub fn mink(
context: &mut Context,
subject: Noun,
formula: Noun,
scry: Noun,
) -> Result<Noun, Error> {
let cache_snapshot = context.cache;
let scry_snapshot = context.scry_stack;
context.cache = Hamt::<Noun>::new(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
match interpret(context, subject, formula) {
Ok(res) => Ok(T(&mut context.stack, &[D(0), res])),
Ok(res) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(0), res]))
}
Err(err) => match err {
Error::ScryBlocked(path) => Ok(T(&mut context.stack, &[D(1), path])),
Error::Deterministic(trace) => Ok(T(&mut context.stack, &[D(2), trace])),
Error::NonDeterministic(_) | Error::ScryCrashed(_) => Err(err),
Error::ScryBlocked(path) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(1), path]))
}
Error::Deterministic(trace) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(2), trace]))
}
Error::ScryCrashed(trace) => {
context.cache = cache_snapshot;
// When we enter a +mink call, we record the state of the scry handler stack at the
// time (i.e. the Noun representing (list scry)). Each scry will pop the head off of
// this scry handler stack and calls interpret(), using the rest of the scry handler
// stack in the event that it scries again recursively. When a scry succeeds, it
// replaces the scry handler that it used by pushing it back onto the top of the
// scry handler stack. However, it never does so when it fails. Therefore, we can
// tell which particular virtualization instance failed by comparing the scry
// handler stack at the time of failure (i.e. the scry handler stack in the context
// after a failed scry) with the scry handler stack at the time of the virtualization
// call. Thus, whenever a virtualized interpret() call fails with a
// Error::ScryCrashed, jet_mink() compares the two scry handler stack Nouns> If they
// are identical, jet_mink() bails with Error::Deterministic. Otherwise, it forwards
// the Error::ScryCrashed to the senior virtualization call.
if unsafe { context.scry_stack.raw_equals(scry_snapshot) } {
Err(Error::Deterministic(trace))
} else {
Err(err)
}
}
Error::NonDeterministic(_) => {
// We choose to restore the cache and scry stack even on NonDeterministic errors
// to keep the logic all in one place (as opposed to having the serf reset them
// manually ONLY for NonDeterministic errors).
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Err(err)
}
},
}
}
@ -190,14 +205,14 @@ pub mod util {
/** Consume $tone, produce $toon
*/
// XX: should write a jet_mook wrapper for this function
pub fn mook(context: &mut Context, tone: Cell, flop: bool) -> result::Result<Cell, JetErr> {
pub fn mook(context: &mut Context, tone: Cell, flop: bool) -> result::Result<Cell, Error> {
let tag = tone.head().as_direct()?;
let original_list = tone.tail();
if (tag.data() != 2) | unsafe { original_list.raw_equals(D(0)) } {
return Ok(tone);
} else if original_list.atom().is_some() {
return Err(JetErr::Fail(Error::Deterministic(D(0))));
return Err(Error::Deterministic(D(0)));
}
// XX: trim traces longer than 1024 frames
@ -235,17 +250,17 @@ pub mod util {
}
Right(_cell) => {
// 'tank: {
// if let Ok(tone) = mink(context, dat, cell.head()) {
// if let Some(cell) = tone.cell() {
// if cell.head().raw_equals(D(0)) {
// // XX: need to check that this is
// // actually a path;
// // return leaf+"mook.mean" if not
// break 'tank cell.tail();
// let scry = null_scry(context);
// if let Ok(tone) = mink(context, dat, cell.head(), scry) {
// if let Some(cell) = tone.cell() {
// if cell.head().raw_equals(D(0)) {
// // XX: need to check that this is
// // actually a path;
// // return leaf+"mook.mean" if not
// break 'tank cell.tail();
// }
// }
// }
// }
{
let stack = &mut context.stack;
let tape = tape(stack, "####");

448
rust/ares/src/jets/parse.rs Normal file
View File

@ -0,0 +1,448 @@
/** Parsing jets
*/
use crate::interpreter::Context;
use crate::jets::util::{kick, slam, slot};
use crate::jets::Result;
use crate::noun::{Noun, D, T};
crate::gdb!();
//
// Tracing
//
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let zyc = slot(sam, 2)?;
let naz = slot(sam, 3)?;
util::last(zyc, naz)
}
//
// Combinators
//
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
let van = slot(subject, 7)?;
let raq = slot(van, 6)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let yit = slam(context, sab, quq_vex)?.as_cell()?;
let p_yit = yit.head();
let q_yit = yit.tail();
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?;
if unsafe { vux.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex]))
} else {
let q_vux = vux.as_cell()?.tail();
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit]))
}
}
}
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
let van = slot(subject, 7)?;
let raq = slot(van, 6)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let yit = slam(context, sab, quq_vex)?.as_cell()?;
let p_yit = yit.head();
let q_yit = yit.tail();
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?;
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit]))
}
}
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
let van = slot(subject, 7)?;
let bus = slot(van, 6)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let yit = slam(context, bus, quq_vex)?.as_cell()?;
let p_yit = yit.head();
let q_yit = yit.tail();
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail();
let wam = slam(context, sab, quq_yit)?.as_cell()?;
let p_wam = wam.head();
let q_wam = wam.tail();
let goy = util::last(yur, p_wam)?;
if unsafe { q_wam.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[goy, D(0)]))
} else {
let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
let puq_wam = uq_wam.head();
let quq_wam = uq_wam.tail();
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam]);
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam]))
}
}
}
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let quq_vex = uq_vex.tail();
let yit = slam(context, sab, quq_vex)?.as_cell()?;
let p_yit = yit.head();
let q_yit = yit.tail();
// XX: Why don't we just return yit? When would p_vex ever be the later of the two?
let arg = util::last(p_vex, p_yit)?;
Ok(T(&mut context.stack, &[arg, q_yit]))
}
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { !q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let roq = kick(context, sab, D(2))?.as_cell()?;
let yur = util::last(p_vex, roq.head())?;
Ok(T(&mut context.stack, &[yur, roq.tail()]))
}
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let yit = slam(context, sab, quq_vex)?.as_cell()?;
let p_yit = yit.head();
let q_yit = yit.tail();
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail();
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit]))
}
}
//
// Rule Builders
//
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let huf = slot(van, 6)?;
Ok(T(
&mut context.stack,
&[tub.as_cell()?.head(), D(0), huf, tub],
))
}
pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let hez = slot(van, 12)?;
let sef = slot(van, 13)?;
let p_tub = tub.as_cell()?.head();
let vex = slam(context, sef, tub)?.as_cell()?;
let p_vex = vex.head();
let q_vex = vex.tail();
// XX fixes Vere's jet mismatch with Hoon 139.
if unsafe { q_vex.raw_equals(D(0)) } {
return Ok(vex.as_noun());
}
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let pquq_vex = quq_vex.as_cell()?.head();
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex]);
let gud = T(&mut context.stack, &[inner_gud, puq_vex]);
let wag = slam(context, hez, gud)?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
}
pub fn jet_just(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let daf = slot(van, 6)?;
let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail();
if unsafe { q_tub.raw_equals(D(0)) || !daf.raw_equals(q_tub.as_cell()?.head()) } {
util::fail(context, p_tub)
} else {
util::next(context, tub)
}
}
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let mut bud = slot(van, 6)?;
let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail();
if unsafe { q_tub.raw_equals(D(0)) } {
return util::fail(context, p_tub);
}
let iq_tub = q_tub.as_cell()?.head();
while unsafe { !bud.raw_equals(D(0)) } {
let cell = bud.as_cell()?;
if unsafe { cell.head().raw_equals(iq_tub) } {
return util::next(context, tub);
}
bud = cell.tail();
}
util::fail(context, p_tub)
}
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let gob = slot(van, 12)?;
let sef = slot(van, 13)?;
let vex = slam(context, sef, tub)?.as_cell()?;
let p_vex = vex.head();
let q_vex = vex.tail();
if unsafe { q_vex.raw_equals(D(0)) } {
Ok(vex.as_noun())
} else {
let uq_vex = q_vex.as_cell()?.tail().as_cell()?;
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let wag = T(&mut context.stack, &[gob, puq_vex]);
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
}
}
pub mod util {
use crate::interpreter::{inc, Context};
use crate::jets::Result;
use crate::noun::{Noun, D, T};
use std::cmp::Ordering;
pub fn last(zyc: Noun, naz: Noun) -> Result {
let zyl = zyc.as_cell()?;
let nal = naz.as_cell()?;
let zyll = zyl.head().as_direct()?.data();
let zylc = zyl.tail().as_direct()?.data();
let nall = nal.head().as_direct()?.data();
let nalc = nal.tail().as_direct()?.data();
match zyll.cmp(&nall) {
Ordering::Equal => {
if zylc > nalc {
Ok(zyc)
} else {
Ok(naz)
}
}
Ordering::Greater => Ok(zyc),
Ordering::Less => Ok(naz),
}
}
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn next(context: &mut Context, tub: Noun) -> Result {
let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail();
if unsafe { q_tub.raw_equals(D(0)) } {
return fail(context, p_tub);
}
let iq_tub = q_tub.as_cell()?.head();
let tq_tub = q_tub.as_cell()?.tail();
let zac = lust(context, iq_tub, p_tub)?;
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub]))
}
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result {
let p_naz = naz.as_cell()?.head().as_atom()?;
let q_naz = naz.as_cell()?.tail().as_atom()?;
if unsafe { weq.raw_equals(D(10)) } {
let arg = inc(&mut context.stack, p_naz).as_noun();
Ok(T(&mut context.stack, &[arg, D(1)]))
} else {
let arg = inc(&mut context.stack, q_naz).as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg]))
}
}
pub fn fail(context: &mut Context, hair: Noun) -> Result {
Ok(T(&mut context.stack, &[hair, D(0)]))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::noun::{D, T};
use crate::serialization::cue;
use ibig::ubig;
// XX: need unit tests for:
// +last
// +bend
// +comp
// +glue
// +pfix
// +pose
// +sfix
// +here
// +just
// +mask
// +stag
#[test]
fn test_easy() {
let c = &mut init_context();
// ((easy 'a') [[1 1] "abc"])
// [[1 1] "abc"]
let sam_jam = A(&mut c.stack, &ubig!(3205468216717221061))
.as_atom()
.unwrap();
let sam = cue(&mut c.stack, sam_jam);
// [p=[p=1 q=1] q=[~ [p='a' q=[p=[p=1 q=1] q="abc"]]]]
let ans_jam = A(&mut c.stack, &ubig!(1720922644868600060465749189))
.as_atom()
.unwrap();
let ans = cue(&mut c.stack, ans_jam);
let ctx = T(&mut c.stack, &[D(0), D(97), D(0)]);
assert_jet_door(c, jet_easy, sam, ctx, ans);
// ((easy %foo) [[1 1] "abc"])
// [[1 1] "abc"]
let sam_jam = A(&mut c.stack, &ubig!(3205468216717221061))
.as_atom()
.unwrap();
let sam = cue(&mut c.stack, sam_jam);
// [p=[p=1 q=1] q=[~ [p=%foo q=[p=[p=1 q=1] q="abc"]]]]
let ans_jam = A(&mut c.stack, &ubig!(3609036366588910247778413036281029))
.as_atom()
.unwrap();
let ans = cue(&mut c.stack, ans_jam);
let ctx = T(&mut c.stack, &[D(0), D(0x6f6f66), D(0)]);
assert_jet_door(c, jet_easy, sam, ctx, ans);
}
}

View File

@ -7,6 +7,7 @@ use crate::noun::{Noun, Slots};
use std::ptr::{copy_nonoverlapping, null_mut};
/// key = formula
#[derive(Copy, Clone)]
pub struct Warm(Hamt<WarmEntry>);
impl Preserve for Warm {
@ -122,7 +123,8 @@ impl Warm {
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);
// XX: need NockStack allocated string interpolation
// eprintln!("Bad axis {} into formula {:?}", axis, battery);
continue;
}
}

View File

@ -1,24 +1,10 @@
use ares::hamt::Hamt;
use ares::interpreter::{interpret, Context};
use ares::jets::cold::Cold;
use ares::jets::hot::Hot;
use ares::jets::warm::Warm;
use ares::mem::NockStack;
use ares::newt::Newt;
use ares::noun::{IndirectAtom, Noun, D};
use ares::jets::hot::URBIT_HOT_STATE;
use ares::serf::serf;
use ares::serialization::{cue, jam};
use memmap::Mmap;
use memmap::MmapMut;
use std::env;
use std::fs::File;
use std::fs::OpenOptions;
use std::io;
use std::mem;
use std::ptr::copy_nonoverlapping;
use std::ptr::write_bytes;
fn main() -> io::Result<()> {
// debug
// eprintln!("serf: pid {}", std::process::id());
// if unsafe { libc::kill(std::process::id() as i32, libc::SIGSTOP) } != 0 {
// panic!("Could not stop ourselves.");
@ -43,61 +29,8 @@ fn main() -> io::Result<()> {
}
if filename == "serf" {
return serf();
return serf(URBIT_HOT_STATE);
}
let output_filename = format!("{}.out", filename);
let f = File::open(filename)?;
let in_len = f.metadata()?.len();
let mut stack = NockStack::new(8 << 10 << 10, 0);
let jammed_input = unsafe {
let in_map = Mmap::map(&f)?;
let word_len = (in_len + 7) >> 3;
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize);
write_bytes(dest.add(word_len as usize - 1), 0, 1);
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
mem::drop(in_map);
atom.normalize_as_atom()
};
let input = cue(&mut stack, jammed_input);
let input_cell = input
.as_cell()
.expect("Input must be jam of subject/formula pair");
let newt = Newt::new_mock();
let cache = Hamt::<Noun>::new(&mut stack);
let cold = Cold::new(&mut stack);
let warm = Warm::new(&mut stack);
let hot = Hot::init(&mut stack);
let mut context = Context {
stack,
newt,
cache,
cold,
warm,
hot,
scry_stack: D(0),
trace_info: None,
};
let result =
interpret(&mut context, input_cell.head(), input_cell.tail()).expect("nock failed");
if let Ok(atom) = result.as_atom() {
println!("Result: {}", atom);
}
let jammed_result = jam(&mut context.stack, result);
let f_out = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(output_filename)?;
f_out.set_len((jammed_result.size() << 3) as u64)?;
unsafe {
let mut out_map = MmapMut::map_mut(&f_out)?;
copy_nonoverlapping(
jammed_result.data_pointer() as *mut u8,
out_map.as_mut_ptr(),
jammed_result.size() << 3,
);
out_map.flush()?;
};
Ok(())
panic!("Ares can only run as a serf!");
}

View File

@ -589,10 +589,12 @@ impl NockStack {
*/
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> O
where
F: FnOnce() -> O,
F: FnOnce(&mut NockStack) -> O,
O: Preserve,
{
self.frame_push(num_locals);
let ret = f();
let mut ret = f(self);
ret.preserve(self);
self.frame_pop();
ret
}
@ -1059,3 +1061,19 @@ impl Stack for NockStack {
self.layout_alloc(layout)
}
}
impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self.as_mut() {
Ok(t_ref) => t_ref.preserve(stack),
Err(e_ref) => e_ref.preserve(stack),
}
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
match self.as_ref() {
Ok(t_ref) => t_ref.assert_in_stack(stack),
Err(e_ref) => e_ref.assert_in_stack(stack),
}
}
}

View File

@ -2,7 +2,7 @@ use crate::hamt::Hamt;
use crate::interpreter;
use crate::interpreter::{inc, interpret, Error};
use crate::jets::cold::Cold;
use crate::jets::hot::Hot;
use crate::jets::hot::{Hot, HotEntry};
use crate::jets::list::util::{lent, zing};
use crate::jets::nock::util::mook;
use crate::jets::warm::Warm;
@ -79,17 +79,20 @@ struct SnapshotMem {
const PMA_CURRENT_SNAPSHOT_VERSION: u64 = 1;
struct Context {
struct Context<'a> {
epoch: u64,
event_num: u64,
pma: PMA,
arvo: Noun,
mug: u32,
constant_hot_state: &'a [HotEntry],
nock_context: interpreter::Context,
}
impl Context {
pub fn load(snap_path: PathBuf, trace_info: Option<TraceInfo>) -> Context {
impl<'a> Context<'a> {
pub fn load(snap_path: PathBuf, trace_info: Option<TraceInfo>,
constant_hot_state: &[HotEntry],
) -> Context {
let mut pma = PMA::open(snap_path).expect("serf: pma open failed");
let snapshot_version = pma.meta_get(BTMetaField::SnapshotVersion as usize);
@ -102,7 +105,7 @@ impl Context {
_ => panic!("Unsupported snapshot version"),
};
Context::new(trace_info, pma, snapshot)
Context::new(trace_info, pma, snapshot, constant_hot_state)
}
pub fn save(&mut self) {
@ -134,7 +137,9 @@ impl Context {
self.pma.meta_set(BTMetaField::Snapshot as usize, handle);
}
fn new(trace_info: Option<TraceInfo>, pma: PMA, snapshot: Option<Snapshot>) -> Self {
fn new(trace_info: Option<TraceInfo>, pma: PMA, snapshot: Option<Snapshot>,
constant_hot_state: &'a [HotEntry],
) -> Self {
let mut stack = NockStack::new(1024 << 10 << 10, 0);
let newt = Newt::new();
let cache = Hamt::<Noun>::new(&mut stack);
@ -151,9 +156,8 @@ impl Context {
}
};
let mut hot = Hot::init(&mut stack);
let mut hot = Hot::init(&mut stack, constant_hot_state);
let warm = Warm::init(&mut stack, &mut cold, &mut hot);
let mug = mug_u32(&mut stack, arvo);
let nock_context = interpreter::Context {
@ -174,6 +178,7 @@ impl Context {
arvo,
mug,
nock_context,
constant_hot_state,
}
}
@ -197,7 +202,7 @@ impl Context {
// Then, save the stack and reset to the saved stack for each event, thus avoiding the need
// to recreate the hot state each event, since it does not change over the execution of the
// interpreter.
self.nock_context.hot = Hot::init(&mut self.nock_context.stack);
self.nock_context.hot = Hot::init(&mut self.nock_context.stack, self.constant_hot_state);
// XX the above trick won't work for the warm state, since it changes whenever the cold
// state does. One possibility is to just save the warm and hot states in the snapshot
@ -306,7 +311,7 @@ lazy_static! {
* This is suitable for talking to the king process. To test, change the arg_c[0] line in
* u3_lord_init in vere to point at this binary and start vere like normal.
*/
pub fn serf() -> io::Result<()> {
pub fn serf(constant_hot_state: &[HotEntry]) -> io::Result<()> {
// Register SIGINT signal hook to set flag first time, shutdown second time
signal_hook::flag::register_conditional_shutdown(SIGINT, 1, Arc::clone(&TERMINATOR))?;
signal_hook::flag::register(SIGINT, Arc::clone(&TERMINATOR))?;
@ -335,13 +340,14 @@ pub fn serf() -> io::Result<()> {
None
};
if let Some(ref mut info) = trace_info.as_mut() {
if let Err(e) = write_metadata(info) {
eprintln!("\rError initializing trace file: {:?}", e);
if let Err(_e) = write_metadata(info) {
// XX: need NockStack allocated string interpolation
// eprintln!("\rError initializing trace file: {:?}", e);
trace_info = None;
}
}
let mut context = Context::load(snap_path, trace_info);
let mut context = Context::load(snap_path, trace_info, constant_hot_state);
context.ripe();
// Can't use for loop because it borrows newt
@ -576,6 +582,7 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
clear_interrupt();
let stack = &mut context.nock_context.stack;
context.nock_context.cache = Hamt::<Noun>::new(stack);
// crud ovo = [+(now) [%$ %arvo ~] [%crud goof ovo]]
let job_cell = job.as_cell().expect("serf: work: job not a cell");
let job_now = job_cell.head().as_atom().expect("serf: work: now not atom");

View File

@ -99,8 +99,9 @@ pub fn write_metadata(info: &mut TraceInfo) -> Result<(), Error> {
///
/// This should result in a well-formed partial trace file.
pub fn write_serf_trace_safe(info: &mut Option<TraceInfo>, name: &str, start: Instant) {
if let Err(e) = write_serf_trace(info.as_mut().unwrap(), name, start) {
eprintln!("\rserf: error writing event trace to file: {:?}", e);
if let Err(_e) = write_serf_trace(info.as_mut().unwrap(), name, start) {
// XX: need NockStack allocated string interpolation
// eprintln!("\rserf: error writing event trace to file: {:?}", e);
*info = None;
}
}

View File

@ -29,7 +29,6 @@
"rustfmt"
"rust-src"
])
pkgs.autoconf-archive
pkgs.cargo-watch
pkgs.bacon
pkgs.iconv

View File

@ -1,5 +1,5 @@
{ stdenv, fetchFromGitHub, autoreconfHook, pkg-config, openssl, cryptopp, secp256k1, libaes_siv }:
let rev = "375fa7e6a730d8aa517ca981b2b7b505bf4e1103";
{ stdenv, fetchFromGitHub, autoreconfHook, autoconf-archive, pkg-config, openssl, cryptopp, secp256k1, libaes_siv }:
let rev = "43479c3262a11e20da5f6218f3b0b3d63931ceea";
in stdenv.mkDerivation {
pname = "urcrypt";
version = "git-${rev}";
@ -7,14 +7,14 @@ in stdenv.mkDerivation {
inherit rev;
owner = "urbit";
repo = "urcrypt";
hash = "sha256:1c3cqmwr5mys4v9y0834hxqfr6aynm2gav7730bjzfvrdc21ijqa";
hash = "sha256-GkhqvhDyhsdzjWpR8uqmhdRdhxdpmLGWXtIUZPAbWZs=";
};
preConfigure = ''
./autogen.sh
'';
# preConfigure = ''
# ./autogen.sh
# '';
nativeBuildInputs = [autoreconfHook pkg-config];
nativeBuildInputs = [autoreconfHook autoconf-archive pkg-config];
buildInputs = [openssl cryptopp secp256k1 libaes_siv];
}