From 44c385ba35bb6507eeaff859e9c0ee5cda4193bf Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 12 May 2026 10:46:43 -0700 Subject: [PATCH 01/12] feat: evaluator --- fix/src/evaluator.rs | 226 +++++++++++++++++++++++++++++++++++++++++++ fix/src/main.rs | 177 ++++++--------------------------- 2 files changed, 253 insertions(+), 150 deletions(-) create mode 100644 fix/src/evaluator.rs diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs new file mode 100644 index 0000000..1e87398 --- /dev/null +++ b/fix/src/evaluator.rs @@ -0,0 +1,226 @@ +use fixhandle::rawhandle::{Encode, FixHandle, Object, Ref, Thunk, TreeName}; + +use fixruntime::{ + fixruntime::FixRuntime, + runtime::{CouponCollector, DeterministicEquivRuntime, Executor}, +}; + +use common::bitpack::BitPack; +use kernel::prelude::*; + +fn coupon_type(runtime: &mut FixRuntime, handle: &FixHandle) -> &'static str { + let mut arr = [0u8; 4]; + let blob = runtime.get_blob(handle).expect("Coupon type not a blob"); + blob.read(0, &mut arr); + let num = u32::from_le_bytes(arr); + match num { + 0 => "Eq", + 1 => "Eval", + 2 => "Apply", + 3 => "Force", + 4 => "Think", + 5 => "Storage", + _ => panic!(), + } +} + +pub fn show_coupon(runtime: &mut FixRuntime, handle: &FixHandle) { + let lhs = get_coupon_lhs(runtime, handle); + let rhs = get_coupon_rhs(runtime, handle); + + let coupon_content = runtime.get_tree(handle).expect("Coupon not a tree"); + + let entry: Blob = coupon_content + .get(1) + .try_into() + .expect("author not a handle"); + let mut handle_scratch: [u8; 32] = [0; 32]; + entry.read(0, &mut handle_scratch); + let handle = FixHandle::unpack(handle_scratch); + let ctype = coupon_type(runtime, &handle); + + log::info!("type is: {ctype:?}"); + log::info!("lhs is: {lhs:?}"); + log::info!("rhs is: {rhs:?}"); +} + +fn get_tree_entry(tree: &Tuple, idx: usize) -> FixHandle { + let mut scratch: [u8; 32] = [0; 32]; + let entry: Blob = tree.get(idx).try_into().expect("tree entry not a blob"); + entry.read(0, &mut scratch); + FixHandle::unpack(scratch) +} + +pub fn get_coupon_lhs(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { + let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); + get_tree_entry(&coupon_content, 2) +} + +pub fn get_coupon_rhs(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { + let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); + get_tree_entry(&coupon_content, 3) +} + +fn apply(runtime: &mut FixRuntime, combination: &TreeName) -> FixHandle { + let handle = FixHandle::Object(Object::TreeObj(*combination)); + runtime.execute(&handle) +} + +fn lift(_runtime: &mut FixRuntime, handle: &FixHandle) -> FixHandle { + match handle { + FixHandle::Ref(r) => match r { + Ref::TreeRef(t) => FixHandle::Object(Object::TreeObj(*t)), + Ref::BlobRef(b) => FixHandle::Object(Object::BlobObj(*b)), + }, + _ => *handle, + } +} + +fn lower(_runtime: &mut FixRuntime, handle: &FixHandle) -> FixHandle { + match handle { + FixHandle::Object(r) => match r { + Object::TreeObj(t) => FixHandle::Ref(Ref::TreeRef(*t)), + Object::BlobObj(b) => FixHandle::Ref(Ref::BlobRef(*b)), + }, + _ => *handle, + } +} + +fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { + match thunk { + Thunk::Identification(_) => todo!(), + Thunk::Selection(_) => todo!(), + Thunk::Application(tree) => { + let eval_coupon = eval(runtime, FixHandle::Object(Object::TreeObj(*tree))); + let rhs = get_coupon_rhs(runtime, &eval_coupon); + let rhs = rhs.unwrap_object().unwrap_tree_obj(); + let apply_coupon = apply(runtime, &rhs); + + let mut coupons = Tuple::new(2); + coupons.set(0, Blob::new(eval_coupon.pack())); + coupons.set(1, Blob::new(apply_coupon.pack())); + let coupons = runtime.create_tree(coupons); + let result = get_coupon_rhs(runtime, &apply_coupon); + runtime.trade( + fixruntime::runtime::CouponTrades::ThinkApplication, + coupons, + FixHandle::Thunk(*thunk), + result, + ) + } + } +} + +fn force(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { + let think_coupon = think(runtime, thunk); + let result = get_coupon_rhs(runtime, &think_coupon); + match result { + FixHandle::Object(_) | FixHandle::Ref(_) => { + let mut coupons = Tuple::new(1); + coupons.set(0, Blob::new(think_coupon.pack())); + let coupons = runtime.create_tree(coupons); + + runtime.trade( + fixruntime::runtime::CouponTrades::ThinkToForce, + coupons, + FixHandle::Thunk(*thunk), + result, + ) + } + FixHandle::Thunk(_) | FixHandle::Encode(_) => todo!(), + } +} + +fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { + match encode { + Encode::Strict(thunk) => { + let force_coupon = force(runtime, thunk); + let result = get_coupon_rhs(runtime, &force_coupon); + let result = lift(runtime, &result); + + let mut coupons = Tuple::new(1); + coupons.set(0, Blob::new(force_coupon.pack())); + let coupons = runtime.create_tree(coupons); + + runtime.trade( + fixruntime::runtime::CouponTrades::ForceToEncodeStric, + coupons, + FixHandle::Encode(*encode), + result, + ) + } + Encode::Shallow(_) => todo!(), + } +} + +fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { + let tree_handle = FixHandle::from(Object::from(*handle)); + let tree = runtime.get_tree(&tree_handle).unwrap(); + + let mut coupons = Tuple::new(tree.len()); + let mut new_tree = Tuple::new(tree.len()); + + for i in 0..tree.len() { + let eval_coupon = eval(runtime, get_tree_entry(&tree, i)); + coupons.set(i, Blob::new(eval_coupon.pack())); + new_tree.set(i, Blob::new(get_coupon_rhs(runtime, &eval_coupon).pack())); + } + + let coupons = runtime.create_tree(coupons); + let new_tree = runtime.create_tree(new_tree); + + runtime.trade( + fixruntime::runtime::CouponTrades::EvalTreeObj, + coupons, + tree_handle, + new_tree, + ) +} + +pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { + match handle { + FixHandle::Thunk(_) | FixHandle::Ref(_) => todo!(), + FixHandle::Object(obj) => match obj { + Object::BlobObj(_) => { + let coupons = Tuple::new(0); + let coupons = runtime.create_tree(coupons); + runtime.trade( + fixruntime::runtime::CouponTrades::EvalBlobObj, + coupons, + handle, + handle, + ) + } + Object::TreeObj(tree) => eval_tree(runtime, &tree), + }, + FixHandle::Encode(e) => { + let eq_coupon = encode(runtime, &e); + let result = get_coupon_rhs(runtime, &eq_coupon); + let eval_coupon = eval(runtime, result); + + let eq_lhs = get_coupon_lhs(runtime, &eq_coupon); + let eq_rhs = get_coupon_rhs(runtime, &eq_coupon); + let mut coupons = Tuple::new(1); + coupons.set(0, Blob::new(eq_coupon.pack())); + let coupons = runtime.create_tree(coupons); + let eq_coupon = runtime.trade( + fixruntime::runtime::CouponTrades::EqSym, + coupons, + eq_rhs, + eq_lhs, + ); + let result = get_coupon_rhs(runtime, &eval_coupon); + + let mut coupons = Tuple::new(2); + coupons.set(0, Blob::new(eval_coupon.pack())); + coupons.set(1, Blob::new(eq_coupon.pack())); + let coupons = runtime.create_tree(coupons); + return runtime.trade( + fixruntime::runtime::CouponTrades::EvalEq, + coupons, + handle, + result, + ); + } + } +} diff --git a/fix/src/main.rs b/fix/src/main.rs index 603a448..02c70f0 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -12,14 +12,16 @@ use kernel::prelude::*; #[cfg(feature = "testing-mode")] mod testing; +mod evaluator; + use common::bitpack::BitPack; use fixruntime::{ - fixruntime::FixRuntime, - runtime::{CouponCollector, DeterministicEquivRuntime, Executor}, - storage::ObjectStore, + fixruntime::FixRuntime, runtime::DeterministicEquivRuntime, storage::ObjectStore, }; +use crate::evaluator::{eval, get_coupon_rhs, show_coupon}; + extern crate alloc; //use crate::runtime::handle; @@ -27,87 +29,22 @@ extern crate alloc; const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); const COUPON: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/coupon")); -fn coupon_type(runtime: &mut FixRuntime, handle: &FixHandle) -> &'static str { - let mut arr = [0u8; 4]; - let blob = runtime.get_blob(handle).expect("Coupon type not a blob"); - blob.read(0, &mut arr); - let num = u32::from_le_bytes(arr); - match num { - 0 => "Eq", - 1 => "Eval", - 2 => "Apply", - 3 => "Force", - 4 => "Think", - 5 => "Storage", - _ => panic!(), - } -} - -fn get_coupon_lhs(coupon_content: &Tuple) -> FixHandle { - let mut handle_scratch: [u8; 32] = [0; 32]; - let entry: Blob = coupon_content - .get(2) - .try_into() - .expect("author not a handle"); - entry.read(0, &mut handle_scratch); - FixHandle::unpack(handle_scratch) -} - -fn get_coupon_lhs_h(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { - let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); - get_coupon_lhs(&coupon_content) -} - -fn get_coupon_rhs(coupon_content: &Tuple) -> FixHandle { - let mut handle_scratch: [u8; 32] = [0; 32]; - let entry: Blob = coupon_content - .get(3) - .try_into() - .expect("author not a handle"); - entry.read(0, &mut handle_scratch); - FixHandle::unpack(handle_scratch) -} - -fn get_coupon_rhs_h(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { - let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); - get_coupon_rhs(&coupon_content) -} - -fn show_coupon(runtime: &mut FixRuntime, handle: &FixHandle) { - let coupon_content = runtime.get_tree(handle).expect("Coupon not a tree"); - - let entry: Blob = coupon_content - .get(1) - .try_into() - .expect("author not a handle"); - let mut handle_scratch: [u8; 32] = [0; 32]; - entry.read(0, &mut handle_scratch); - let handle = FixHandle::unpack(handle_scratch); - - let ctype = coupon_type(runtime, &handle); - let lhs = get_coupon_lhs(&coupon_content); - let rhs = get_coupon_rhs(&coupon_content); - - log::info!("type is: {ctype:?}"); - log::info!("lhs is: {lhs:?}"); - log::info!("rhs is: {rhs:?}"); -} - #[kmain] async fn main(_: &[usize]) { - log::info!("creating object store"); let mut store = ObjectStore::new(); - log::info!("creating fix runtime"); let mut runtime = FixRuntime::new(&mut store, COUPON); + log::info!("runnning + (+ 3 4) 1024"); log::info!("creating resource limits"); let dummy = runtime.create_blob_i64(0xcafeb0ba); log::info!("creating function"); let function = runtime.create_blob(MODULE.into()); - log::info!("creating addend 7"); - let addend1 = runtime.create_blob_i64(7); + log::info!("creating addend 3"); + let addend1 = runtime.create_blob_i64(3); + log::info!("creating addend 4"); + let addend2 = runtime.create_blob_i64(4); log::info!("creating addend 1024"); - let addend2 = runtime.create_blob_i64(1024); + let addend3 = runtime.create_blob_i64(1024); let mut scratch = Tuple::new(4); scratch.set(0, Blob::new(dummy.pack())); @@ -115,87 +52,27 @@ async fn main(_: &[usize]) { scratch.set(2, Blob::new(addend1.pack())); scratch.set(3, Blob::new(addend2.pack())); let combination = runtime.create_tree(scratch); - let apply_coupon = runtime.execute(&combination); let application = FixHandle::Thunk(Thunk::Application( combination.unwrap_object().unwrap_tree_obj(), )); + let encode = FixHandle::Encode(Encode::Strict(application.unwrap_thunk())); - let coupons = runtime.create_tree(Tuple::new(0)); - let eval_dummy = runtime.trade( - fixruntime::runtime::CouponTrades::EvalBlobObj, - coupons, - dummy, - dummy, - ); - let eval_function = runtime.trade( - fixruntime::runtime::CouponTrades::EvalBlobObj, - coupons, - function, - function, - ); - let eval_addend1 = runtime.trade( - fixruntime::runtime::CouponTrades::EvalBlobObj, - coupons, - addend1, - addend1, - ); - let eval_addend2 = runtime.trade( - fixruntime::runtime::CouponTrades::EvalBlobObj, - coupons, - addend2, - addend2, - ); - - let mut coupons = Tuple::new(4); - coupons.set(0, Blob::new(eval_dummy.pack())); - coupons.set(1, Blob::new(eval_function.pack())); - coupons.set(2, Blob::new(eval_addend1.pack())); - coupons.set(3, Blob::new(eval_addend2.pack())); - let coupons = runtime.create_tree(coupons); - - let eval_coupon = runtime.trade( - fixruntime::runtime::CouponTrades::EvalTreeObj, - coupons, - combination, - combination, - ); - - let mut coupons = Tuple::new(2); - coupons.set(0, Blob::new(eval_coupon.pack())); - coupons.set(1, Blob::new(apply_coupon.pack())); - let coupons = runtime.create_tree(coupons); - let rhs = get_coupon_rhs_h(&mut runtime, &apply_coupon); - let think_coupon = runtime.trade( - fixruntime::runtime::CouponTrades::ThinkApplication, - coupons, - application, - rhs, - ); - - let mut coupons = Tuple::new(1); - coupons.set(0, Blob::new(think_coupon.pack())); - let coupons = runtime.create_tree(coupons); - let force_coupon = runtime.trade( - fixruntime::runtime::CouponTrades::ThinkToForce, - coupons, - application, - rhs, - ); - + let mut scratch = Tuple::new(4); + scratch.set(0, Blob::new(dummy.pack())); + scratch.set(1, Blob::new(function.pack())); + scratch.set(2, Blob::new(encode.pack())); + scratch.set(3, Blob::new(addend3.pack())); + let combination = runtime.create_tree(scratch); + let application = FixHandle::Thunk(Thunk::Application( + combination.unwrap_object().unwrap_tree_obj(), + )); let encode = FixHandle::Encode(Encode::Strict(application.unwrap_thunk())); - let mut coupons = Tuple::new(1); - coupons.set(0, Blob::new(force_coupon.pack())); - let coupons = runtime.create_tree(coupons); - let eq_coupon = runtime.trade( - fixruntime::runtime::CouponTrades::ForceToEncodeStric, - coupons, - encode, - rhs, - ); - - show_coupon(&mut runtime, &eq_coupon); - - let result_blob = get_coupon_rhs_h(&mut runtime, &eq_coupon); + + let eval_coupon = eval(&mut runtime, encode); + + show_coupon(&mut runtime, &eval_coupon); + + let result_blob = get_coupon_rhs(&mut runtime, &eval_coupon); let result_blob = runtime .get_blob(&result_blob) .expect("Result is not a Blob"); From 665b3e513f0240b4b5f7b4b3ecdf6a4a8bea491d Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 12 May 2026 11:34:25 -0700 Subject: [PATCH 02/12] refactor: cleanup --- fix/handle/src/rawhandle.rs | 26 ++++++++++++ fix/runtime/src/fixruntime.rs | 15 ++++++- fix/runtime/src/runtime.rs | 49 ++++++++++++++++++++++- fix/shell/src/shell.rs | 29 +++++--------- fix/src/evaluator.rs | 75 +++++------------------------------ fix/src/main.rs | 23 +++++------ 6 files changed, 117 insertions(+), 100 deletions(-) diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index 6248f19..289676c 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -2,6 +2,11 @@ pub use common::bitpack::BitPack; use derive_more::{From, TryInto, TryUnwrap, Unwrap}; +#[derive(Copy, Clone, Debug)] +pub enum Error { + Unwrap, +} + const fn ceil_log2(n: u32) -> u32 { if n <= 1 { 0 @@ -266,6 +271,27 @@ pub enum Value { Thunk(Thunk), } +pub fn create_application_thunk(handle: &FixHandle) -> Result { + let result = handle + .try_unwrap_object_ref() + .map_err(|_| Error::Unwrap) + .and_then(|h| h.try_unwrap_tree_obj_ref().map_err(|_| Error::Unwrap)) + .or_else(|_| { + handle + .try_unwrap_ref_ref() + .map_err(|_| Error::Unwrap) + .and_then(|h| h.try_unwrap_tree_ref_ref().map_err(|_| Error::Unwrap)) + })?; + + Ok(FixHandle::Thunk(Thunk::Application(*result))) +} + +pub fn create_strict_encode(handle: &FixHandle) -> Result { + let result = handle.try_unwrap_thunk().map_err(|_| Error::Unwrap)?; + + Ok(FixHandle::Encode(Encode::Strict(result))) +} + #[cfg(test)] mod tests { diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 3061051..f21df70 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -4,7 +4,7 @@ use crate::{ bottom::FixShellBottom, // data::{BlobData, TreeData}, - runtime::{CouponCollector, CouponTrades, DeterministicEquivRuntime, Executor}, + runtime::{CouponHelper, CouponTrades, DeterministicEquivRuntime, Executor}, storage::{ObjectStore, Storage}, }; use bytemuck::bytes_of; @@ -130,7 +130,18 @@ impl<'a> Executor for FixRuntime<'a> { } } -impl<'a> CouponCollector for FixRuntime<'a> { +impl<'a> CouponHelper for FixRuntime<'a> { + fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize { + blob.read(offset, buf) + } + + fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle { + let mut scratch: [u8; 32] = [0; 32]; + let entry: Blob = tree.get(offset).try_into().expect("tree entry not a blob"); + entry.read(0, &mut scratch); + FixHandle::unpack(scratch) + } + fn trade( &mut self, trade_type: CouponTrades, diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 7ee2779..82819bb 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -7,7 +7,7 @@ pub trait DeterministicEquivRuntime { type BlobData: Clone + core::fmt::Debug; type TreeData: Clone + core::fmt::Debug; type Handle: Clone + core::fmt::Debug; - type Error; + type Error: core::fmt::Debug; fn create_blob_i32(&mut self, data: u32) -> Self::Handle; fn create_blob_i64(&mut self, data: u64) -> Self::Handle; @@ -48,7 +48,10 @@ pub enum CouponTrades { EqSelf = 12, } -pub trait CouponCollector { +pub trait CouponHelper: DeterministicEquivRuntime { + fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize; + fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle; + fn trade( &mut self, trade_type: CouponTrades, @@ -56,4 +59,46 @@ pub trait CouponCollector { lhs: FixHandle, rhs: FixHandle, ) -> FixHandle; + + fn coupon_type(&mut self, handle: &Self::Handle) -> &'static str { + let mut arr = [0u8; 4]; + let blob = self.get_blob(handle).expect("Coupon type not a blob"); + Self::read_blob(&blob, 0, &mut arr); + let num = u32::from_le_bytes(arr); + match num { + 0 => "Eq", + 1 => "Eval", + 2 => "Apply", + 3 => "Force", + 4 => "Think", + 5 => "Storage", + _ => panic!(), + } + } + + fn show_coupon(&mut self, handle: &Self::Handle) { + let ctype = self.get_coupon_type(handle); + let lhs = self.get_coupon_lhs(handle); + let rhs = self.get_coupon_rhs(handle); + + log::info!("type is: {ctype:?}"); + log::info!("lhs is: {lhs:?}"); + log::info!("rhs is: {rhs:?}"); + } + + fn get_coupon_type(&mut self, coupon: &Self::Handle) -> &'static str { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + let handle = Self::get_tree_entry(&coupon_content, 1); + self.coupon_type(&handle) + } + + fn get_coupon_lhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + Self::get_tree_entry(&coupon_content, 2) + } + + fn get_coupon_rhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + Self::get_tree_entry(&coupon_content, 3) + } } diff --git a/fix/shell/src/shell.rs b/fix/shell/src/shell.rs index c1b4c98..05e2318 100644 --- a/fix/shell/src/shell.rs +++ b/fix/shell/src/shell.rs @@ -10,7 +10,10 @@ use arcane::{ use core::arch::x86_64::*; use core::ffi::c_void; -use fixhandle::rawhandle::{BitPack, Encode, FixHandle, Handle, Object, Thunk, TreeName}; +use fixhandle::rawhandle::{ + BitPack, Encode, FixHandle, Handle, Object, Thunk, TreeName, create_application_thunk, + create_strict_encode, +}; use user::ArcaError; use user::Ref; use user::Runtime; @@ -181,20 +184,9 @@ impl DeterministicEquivRuntime for FixShellPhysical { fn create_application_thunk(handle: Self::Handle) -> Self::Handle { let handle = FixHandle::unpack(handle); - - let result = handle - .try_unwrap_object_ref() - .map_err(|_| ArcaError::BadType) - .and_then(|h| h.try_unwrap_tree_obj_ref().map_err(|_| ArcaError::BadType)) - .or_else(|_| { - handle - .try_unwrap_ref_ref() - .map_err(|_| ArcaError::BadType) - .and_then(|h| h.try_unwrap_tree_ref_ref().map_err(|_| ArcaError::BadType)) - }); - - if let Ok(tree) = result { - FixHandle::Thunk(Thunk::Application(*tree)).pack() + let result = create_application_thunk(&handle); + if let Ok(thunk) = result { + thunk.pack() } else { arca_log("create_application_thunk: input handle is not a TreeObj or TreeRef"); panic!() @@ -203,11 +195,10 @@ impl DeterministicEquivRuntime for FixShellPhysical { fn create_strict_encode(handle: Self::Handle) -> Self::Handle { let handle = FixHandle::unpack(handle); + let result = create_strict_encode(&handle); - let result = handle.try_unwrap_thunk(); - - if let Ok(thunk) = result { - FixHandle::Encode(Encode::Strict(thunk)).pack() + if let Ok(encode) = result { + encode.pack() } else { arca_log("create_strict_encode: input handle is not a Thunk"); panic!() diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index 1e87398..78ecd25 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -2,65 +2,12 @@ use fixhandle::rawhandle::{Encode, FixHandle, Object, Ref, Thunk, TreeName}; use fixruntime::{ fixruntime::FixRuntime, - runtime::{CouponCollector, DeterministicEquivRuntime, Executor}, + runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, }; use common::bitpack::BitPack; use kernel::prelude::*; -fn coupon_type(runtime: &mut FixRuntime, handle: &FixHandle) -> &'static str { - let mut arr = [0u8; 4]; - let blob = runtime.get_blob(handle).expect("Coupon type not a blob"); - blob.read(0, &mut arr); - let num = u32::from_le_bytes(arr); - match num { - 0 => "Eq", - 1 => "Eval", - 2 => "Apply", - 3 => "Force", - 4 => "Think", - 5 => "Storage", - _ => panic!(), - } -} - -pub fn show_coupon(runtime: &mut FixRuntime, handle: &FixHandle) { - let lhs = get_coupon_lhs(runtime, handle); - let rhs = get_coupon_rhs(runtime, handle); - - let coupon_content = runtime.get_tree(handle).expect("Coupon not a tree"); - - let entry: Blob = coupon_content - .get(1) - .try_into() - .expect("author not a handle"); - let mut handle_scratch: [u8; 32] = [0; 32]; - entry.read(0, &mut handle_scratch); - let handle = FixHandle::unpack(handle_scratch); - let ctype = coupon_type(runtime, &handle); - - log::info!("type is: {ctype:?}"); - log::info!("lhs is: {lhs:?}"); - log::info!("rhs is: {rhs:?}"); -} - -fn get_tree_entry(tree: &Tuple, idx: usize) -> FixHandle { - let mut scratch: [u8; 32] = [0; 32]; - let entry: Blob = tree.get(idx).try_into().expect("tree entry not a blob"); - entry.read(0, &mut scratch); - FixHandle::unpack(scratch) -} - -pub fn get_coupon_lhs(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { - let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); - get_tree_entry(&coupon_content, 2) -} - -pub fn get_coupon_rhs(runtime: &mut FixRuntime, coupon: &FixHandle) -> FixHandle { - let coupon_content = runtime.get_tree(coupon).expect("Coupon not a tree"); - get_tree_entry(&coupon_content, 3) -} - fn apply(runtime: &mut FixRuntime, combination: &TreeName) -> FixHandle { let handle = FixHandle::Object(Object::TreeObj(*combination)); runtime.execute(&handle) @@ -92,7 +39,7 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { Thunk::Selection(_) => todo!(), Thunk::Application(tree) => { let eval_coupon = eval(runtime, FixHandle::Object(Object::TreeObj(*tree))); - let rhs = get_coupon_rhs(runtime, &eval_coupon); + let rhs = runtime.get_coupon_rhs(&eval_coupon); let rhs = rhs.unwrap_object().unwrap_tree_obj(); let apply_coupon = apply(runtime, &rhs); @@ -100,7 +47,7 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { coupons.set(0, Blob::new(eval_coupon.pack())); coupons.set(1, Blob::new(apply_coupon.pack())); let coupons = runtime.create_tree(coupons); - let result = get_coupon_rhs(runtime, &apply_coupon); + let result = runtime.get_coupon_rhs(&apply_coupon); runtime.trade( fixruntime::runtime::CouponTrades::ThinkApplication, coupons, @@ -113,7 +60,7 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { fn force(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let think_coupon = think(runtime, thunk); - let result = get_coupon_rhs(runtime, &think_coupon); + let result = runtime.get_coupon_rhs(&think_coupon); match result { FixHandle::Object(_) | FixHandle::Ref(_) => { let mut coupons = Tuple::new(1); @@ -135,7 +82,7 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { match encode { Encode::Strict(thunk) => { let force_coupon = force(runtime, thunk); - let result = get_coupon_rhs(runtime, &force_coupon); + let result = runtime.get_coupon_rhs(&force_coupon); let result = lift(runtime, &result); let mut coupons = Tuple::new(1); @@ -161,9 +108,9 @@ fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { let mut new_tree = Tuple::new(tree.len()); for i in 0..tree.len() { - let eval_coupon = eval(runtime, get_tree_entry(&tree, i)); + let eval_coupon = eval(runtime, FixRuntime::<'_>::get_tree_entry(&tree, i)); coupons.set(i, Blob::new(eval_coupon.pack())); - new_tree.set(i, Blob::new(get_coupon_rhs(runtime, &eval_coupon).pack())); + new_tree.set(i, Blob::new(runtime.get_coupon_rhs(&eval_coupon).pack())); } let coupons = runtime.create_tree(coupons); @@ -195,11 +142,11 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { }, FixHandle::Encode(e) => { let eq_coupon = encode(runtime, &e); - let result = get_coupon_rhs(runtime, &eq_coupon); + let result = runtime.get_coupon_rhs(&eq_coupon); let eval_coupon = eval(runtime, result); - let eq_lhs = get_coupon_lhs(runtime, &eq_coupon); - let eq_rhs = get_coupon_rhs(runtime, &eq_coupon); + let eq_lhs = runtime.get_coupon_lhs(&eq_coupon); + let eq_rhs = runtime.get_coupon_rhs(&eq_coupon); let mut coupons = Tuple::new(1); coupons.set(0, Blob::new(eq_coupon.pack())); let coupons = runtime.create_tree(coupons); @@ -209,7 +156,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { eq_rhs, eq_lhs, ); - let result = get_coupon_rhs(runtime, &eval_coupon); + let result = runtime.get_coupon_rhs(&eval_coupon); let mut coupons = Tuple::new(2); coupons.set(0, Blob::new(eval_coupon.pack())); diff --git a/fix/src/main.rs b/fix/src/main.rs index 02c70f0..6f5584c 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -6,7 +6,7 @@ #![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] #![allow(dead_code)] -use fixhandle::rawhandle::{Encode, FixHandle, Thunk}; +use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; use kernel::prelude::*; #[cfg(feature = "testing-mode")] @@ -17,10 +17,11 @@ mod evaluator; use common::bitpack::BitPack; use fixruntime::{ - fixruntime::FixRuntime, runtime::DeterministicEquivRuntime, storage::ObjectStore, + fixruntime::FixRuntime, runtime::CouponHelper, runtime::DeterministicEquivRuntime, + storage::ObjectStore, }; -use crate::evaluator::{eval, get_coupon_rhs, show_coupon}; +use crate::evaluator::eval; extern crate alloc; @@ -52,10 +53,8 @@ async fn main(_: &[usize]) { scratch.set(2, Blob::new(addend1.pack())); scratch.set(3, Blob::new(addend2.pack())); let combination = runtime.create_tree(scratch); - let application = FixHandle::Thunk(Thunk::Application( - combination.unwrap_object().unwrap_tree_obj(), - )); - let encode = FixHandle::Encode(Encode::Strict(application.unwrap_thunk())); + let application = create_application_thunk(&combination).unwrap(); + let encode = create_strict_encode(&application).unwrap(); let mut scratch = Tuple::new(4); scratch.set(0, Blob::new(dummy.pack())); @@ -63,16 +62,14 @@ async fn main(_: &[usize]) { scratch.set(2, Blob::new(encode.pack())); scratch.set(3, Blob::new(addend3.pack())); let combination = runtime.create_tree(scratch); - let application = FixHandle::Thunk(Thunk::Application( - combination.unwrap_object().unwrap_tree_obj(), - )); - let encode = FixHandle::Encode(Encode::Strict(application.unwrap_thunk())); + let application = create_application_thunk(&combination).unwrap(); + let encode = create_strict_encode(&application).unwrap(); let eval_coupon = eval(&mut runtime, encode); - show_coupon(&mut runtime, &eval_coupon); + runtime.show_coupon(&eval_coupon); - let result_blob = get_coupon_rhs(&mut runtime, &eval_coupon); + let result_blob = runtime.get_coupon_rhs(&eval_coupon); let result_blob = runtime .get_blob(&result_blob) .expect("Result is not a Blob"); From 7ca4c891a567704ee317759b048091b6c6ade16f Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 12 May 2026 14:29:05 -0700 Subject: [PATCH 03/12] feat: make TreeData also arca blob --- fix/runtime/src/bottom.rs | 12 +++----- fix/runtime/src/fixruntime.rs | 46 ++++++++++++++++------------- fix/runtime/src/runtime.rs | 42 ++++++++++++++++++++++++++- fix/runtime/src/storage.rs | 10 +++---- fix/shell/src/lib.rs | 3 +- fix/shell/src/shell.rs | 20 ++++--------- fix/src/evaluator.rs | 54 ++++++++++++++++++----------------- fix/src/main.rs | 26 +++++++++-------- 8 files changed, 125 insertions(+), 88 deletions(-) diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index c605994..0742cb5 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -4,7 +4,7 @@ use crate::{ // data::{BlobData, RawData, TreeData}, fixruntime::FixRuntime, - runtime::{DeterministicEquivRuntime, Executor}, + runtime::{DeterministicEquivRuntime, Executor, CouponHelper}, }; use arca::Runtime; @@ -38,7 +38,7 @@ pub struct FixShellBottom<'a, 'b> { impl<'a, 'b> DeterministicEquivRuntime for FixShellBottom<'a, 'b> { type BlobData = Blob; - type TreeData = Tuple; + type TreeData = Blob; type Handle = Blob; type Error = Error; @@ -126,7 +126,7 @@ impl<'a, 'b> FixShellBottom<'a, 'b> { k.apply(self.create_blob(b)) } b"create_tree" => { - let Some(Value::Tuple(t)) = args.pop() else { + let Some(Value::Blob(t)) = args.pop() else { panic!() }; k.apply(self.create_tree(t)) @@ -179,11 +179,7 @@ impl<'a, 'b> FixShellBottom<'a, 'b> { impl<'a, 'b> Executor for FixShellBottom<'a, 'b> { fn execute(&mut self, combination: &FixHandle) -> FixHandle { let tree = self.parent.get_tree(combination).unwrap(); - let function_handle = tree.get(1); - let function_handle = Blob::try_from(function_handle).unwrap(); - let mut bytes = [0; 32]; - function_handle.read(0, &mut bytes); - let function_handle = FixHandle::unpack(bytes); + let function_handle = FixRuntime::<'_>::get_tree_entry(&tree, 1); let elf = self.parent.get_blob(&function_handle).unwrap(); let f = common::elfloader::load_elf(&elf).expect("Failed to load elf"); diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index f21df70..979faff 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -11,7 +11,8 @@ use bytemuck::bytes_of; use common::bitpack::BitPack; use derive_more::TryUnwrapError; use fixhandle::rawhandle::{FixHandle, Object, TreeName}; -use kernel::types::{Blob, Tuple}; +use kernel::types::{Blob}; +use kernel::prelude::*; #[derive(Debug)] pub enum Error { @@ -40,7 +41,7 @@ impl<'a> FixRuntime<'a> { impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { type BlobData = Blob; - type TreeData = Tuple; + type TreeData = Blob; type Handle = FixHandle; type Error = Error; @@ -58,7 +59,7 @@ impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { Object::from(self.store.create_blob(data)).into() } - fn create_tree(&mut self, data: Tuple) -> Self::Handle { + fn create_tree(&mut self, data: Blob) -> Self::Handle { Object::from(self.store.create_tree(data)).into() } @@ -115,13 +116,15 @@ impl<'a> Executor for FixRuntime<'a> { fn execute(&mut self, combination: &FixHandle) -> FixHandle { let mut bottom = FixShellBottom { parent: self }; let res = bottom.execute(combination); - let mut apply_coupon: Tuple = Tuple::new(4); - apply_coupon.set(0, Blob::new(self.coupon.pack())); - apply_coupon.set(1, Blob::new(self.create_blob_i32(2).pack())); - apply_coupon.set(2, Blob::new(combination.pack())); - apply_coupon.set(3, Blob::new(res.pack())); + + let mut apply_coupon = Vec::with_capacity(32 * 4); + apply_coupon.extend_from_slice(&self.coupon.pack()); + apply_coupon.extend_from_slice(&self.create_blob_i32(2).pack()); + apply_coupon.extend_from_slice(&combination.pack()); + apply_coupon.extend_from_slice(&res.pack()); + Object::from(TreeName::Tag( - self.create_tree(apply_coupon) + self.create_tree(Blob::new(apply_coupon)) .unwrap_object() .unwrap_tree_obj() .unwrap_not_tag(), @@ -137,11 +140,14 @@ impl<'a> CouponHelper for FixRuntime<'a> { fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle { let mut scratch: [u8; 32] = [0; 32]; - let entry: Blob = tree.get(offset).try_into().expect("tree entry not a blob"); - entry.read(0, &mut scratch); + tree.read(offset * 32, &mut scratch); FixHandle::unpack(scratch) } + fn get_tree_len(tree: &Self::TreeData) -> usize { + tree.len() / 32 + } + fn trade( &mut self, trade_type: CouponTrades, @@ -149,15 +155,15 @@ impl<'a> CouponHelper for FixRuntime<'a> { lhs: FixHandle, rhs: FixHandle, ) -> FixHandle { - let mut combination = Tuple::new(6); - combination.set(0, Blob::new(self.create_blob_i32(0).pack())); - combination.set(1, Blob::new(self.coupon.pack())); - combination.set(2, Blob::new(self.create_blob_i32(trade_type as u32).pack())); - combination.set(3, Blob::new(coupons.pack())); - combination.set(4, Blob::new(lhs.pack())); - combination.set(5, Blob::new(rhs.pack())); - - let combination = self.create_tree(combination); + let mut combination = Vec::with_capacity(32 * 6); + combination.extend_from_slice(&self.create_blob_i32(0).pack()); + combination.extend_from_slice(&self.coupon.pack()); + combination.extend_from_slice(&self.create_blob_i32(trade_type as u32).pack()); + combination.extend_from_slice(&coupons.pack()); + combination.extend_from_slice(&lhs.pack()); + combination.extend_from_slice(&rhs.pack()); + + let combination = self.create_tree(Blob::new(combination)); let mut bottom = FixShellBottom { parent: self }; bottom.execute(&combination) } diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 82819bb..6812ce5 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -1,8 +1,9 @@ use core::clone::Clone; use core::result::Result; -use fixhandle::rawhandle::FixHandle; +use fixhandle::rawhandle::{FixHandle, Encode, Thunk, Object}; +#[allow(unused)] pub trait DeterministicEquivRuntime { type BlobData: Clone + core::fmt::Debug; type TreeData: Clone + core::fmt::Debug; @@ -23,14 +24,17 @@ pub trait DeterministicEquivRuntime { fn is_equal(lhs: &Self::Handle, rhs: &Self::Handle) -> bool; } +#[allow(unused)] pub trait ExecutionRuntime: DeterministicEquivRuntime { fn request_execution(&mut self, combination: &Self::Handle) -> Result<(), Self::Error>; } +#[allow(unused)] pub trait Executor { fn execute(&mut self, combination: &FixHandle) -> FixHandle; } +#[allow(unused)] #[repr(u32)] pub enum CouponTrades { EqTree = 0, @@ -48,9 +52,11 @@ pub enum CouponTrades { EqSelf = 12, } +#[allow(unused)] pub trait CouponHelper: DeterministicEquivRuntime { fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize; fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle; + fn get_tree_len(tree: &Self::TreeData) -> usize; fn trade( &mut self, @@ -102,3 +108,37 @@ pub trait CouponHelper: DeterministicEquivRuntime { Self::get_tree_entry(&coupon_content, 3) } } + +#[allow(unused)] +pub trait Visitor : CouponHelper { + fn visit(&mut self, handle: FixHandle, callback: &mut F) + where F: FnMut(&mut Self, &FixHandle), + { + match handle { + FixHandle::Encode(e) => { + match e { + Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback) + } + }, + FixHandle::Ref(_) => todo!(), + FixHandle::Thunk(t) => { + match t { + Thunk::Application(tree) => self.visit(FixHandle::Object(Object::from(tree)), callback), + _ => todo!() + } + }, + FixHandle::Object(obj) => { + match obj { + Object::BlobObj(_) => {}, + Object::TreeObj(_) => { + let tree_data = self.get_tree(&handle).unwrap(); + for i in 0..Self::get_tree_len(&tree_data) { + self.visit(Self::get_tree_entry(&tree_data, i), callback); + } + } + } + } + }; + callback(self, &handle); + } +} diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index c9f9bd5..a4e9183 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -43,9 +43,9 @@ impl RawObjectStore { pub trait Storage { fn create_blob(&mut self, data: Blob) -> BlobName; - fn create_tree(&mut self, data: Tuple) -> TreeName; + fn create_tree(&mut self, data: Blob) -> TreeName; fn get_blob(&self, handle: &BlobName) -> Blob; - fn get_tree(&self, handle: &TreeName) -> Tuple; + fn get_tree(&self, handle: &TreeName) -> Blob; } #[derive(Default, Debug)] @@ -66,8 +66,8 @@ impl Storage for ObjectStore { BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) } - fn create_tree(&mut self, data: Tuple) -> TreeName { - let len = data.len(); + fn create_tree(&mut self, data: Blob) -> TreeName { + let len = data.len() / 32; let local_id = self.store.create(data.into()); TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) } @@ -86,7 +86,7 @@ impl Storage for ObjectStore { } } - fn get_tree(&self, handle: &TreeName) -> Tuple { + fn get_tree(&self, handle: &TreeName) -> Blob { match handle { TreeName::NotTag(t) | TreeName::Tag(t) => match t { Handle::VirtualHandle(_) => todo!(), diff --git a/fix/shell/src/lib.rs b/fix/shell/src/lib.rs index 7abf8f0..a27ae61 100644 --- a/fix/shell/src/lib.rs +++ b/fix/shell/src/lib.rs @@ -105,9 +105,8 @@ pub fn main() -> ! { panic!() }; - let procedure: Blob = tree.get(1).try_into().unwrap(); let procedure_ref = &raw mut _PROCEDURE; - procedure.read(0, &mut *procedure_ref); + tree.read(32, &mut *procedure_ref); } let wasm_rt_externref_t { bytes: result } = diff --git a/fix/shell/src/shell.rs b/fix/shell/src/shell.rs index 05e2318..a5fef3d 100644 --- a/fix/shell/src/shell.rs +++ b/fix/shell/src/shell.rs @@ -30,7 +30,7 @@ pub struct FixShell; impl DeterministicEquivRuntime for FixShellPhysical { type BlobData = Blob; - type TreeData = Tuple; + type TreeData = Blob; type Handle = [u8; 32]; type Error = ArcaError; @@ -99,7 +99,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { } fn get_tree(handle: Self::Handle) -> Result { - let result: Tuple = Function::symbolic("get_tree") + let result: Blob = Function::symbolic("get_tree") .apply(Runtime::create_blob(&handle)) .call_with_current_continuation() .try_into() @@ -230,7 +230,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { impl DeterministicEquivRuntime for FixShell { type BlobData = Blob; - type TreeData = Tuple; + type TreeData = Blob; type Handle = [u8; 32]; type Error = ArcaError; @@ -364,10 +364,7 @@ pub unsafe fn fixpoint_attach_tree(addr: *mut c_void, handle: [u8; 32]) -> usize unsafe { arca_compat_mmap(addr, len * 32, __MODE_read_write); let slice = core::slice::from_raw_parts_mut(addr as *mut u8, len * 32); - for i in 0..len { - let element: Blob = tree.get(i).try_into().unwrap(); - element.read(0, &mut slice[i * 32..(i + 1) * 32]); - } + tree.read(0, slice) }; len } @@ -379,15 +376,10 @@ pub unsafe fn fixpoint_attach_tree(addr: *mut c_void, handle: [u8; 32]) -> usize /// [addr] must refer to an region of memory which is large enough for the specified [len]; /// Each entry of the tree takes 32 bytes. pub unsafe fn fixpoint_create_tree(addr: *const c_void, len: usize) -> [u8; 32] { - let mut scratch = Runtime::create_tuple(len); unsafe { let slice = core::slice::from_raw_parts(addr as *const u8, len * 32); - for i in 0..len { - let element = Runtime::create_blob(&slice[i * 32..(i + 1) * 32]); - scratch.set(i, element); - } - }; - FixShell::create_tree(scratch) + FixShell::create_tree(Blob::new(slice)) + } } /// Creates a tag from a region of memory. Returns the handle, diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index 78ecd25..7b36fae 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -43,10 +43,10 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let rhs = rhs.unwrap_object().unwrap_tree_obj(); let apply_coupon = apply(runtime, &rhs); - let mut coupons = Tuple::new(2); - coupons.set(0, Blob::new(eval_coupon.pack())); - coupons.set(1, Blob::new(apply_coupon.pack())); - let coupons = runtime.create_tree(coupons); + let mut coupons = Vec::with_capacity(32 * 2); + coupons.extend_from_slice(&eval_coupon.pack()); + coupons.extend_from_slice(&apply_coupon.pack()); + let coupons = runtime.create_tree(Blob::new(coupons)); let result = runtime.get_coupon_rhs(&apply_coupon); runtime.trade( fixruntime::runtime::CouponTrades::ThinkApplication, @@ -63,9 +63,9 @@ fn force(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let result = runtime.get_coupon_rhs(&think_coupon); match result { FixHandle::Object(_) | FixHandle::Ref(_) => { - let mut coupons = Tuple::new(1); - coupons.set(0, Blob::new(think_coupon.pack())); - let coupons = runtime.create_tree(coupons); + let mut coupons = Vec::with_capacity(32); + coupons.extend_from_slice(&think_coupon.pack()); + let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( fixruntime::runtime::CouponTrades::ThinkToForce, @@ -85,9 +85,9 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { let result = runtime.get_coupon_rhs(&force_coupon); let result = lift(runtime, &result); - let mut coupons = Tuple::new(1); - coupons.set(0, Blob::new(force_coupon.pack())); - let coupons = runtime.create_tree(coupons); + let mut coupons = Vec::with_capacity(32); + coupons.extend_from_slice(&force_coupon.pack()); + let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( fixruntime::runtime::CouponTrades::ForceToEncodeStric, @@ -103,18 +103,19 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { let tree_handle = FixHandle::from(Object::from(*handle)); let tree = runtime.get_tree(&tree_handle).unwrap(); + let tree_len = FixRuntime::<'_>::get_tree_len(&tree); - let mut coupons = Tuple::new(tree.len()); - let mut new_tree = Tuple::new(tree.len()); + let mut coupons = Vec::with_capacity(tree_len * 32); + let mut new_tree = Vec::with_capacity(tree_len * 32); - for i in 0..tree.len() { + for i in 0..tree_len { let eval_coupon = eval(runtime, FixRuntime::<'_>::get_tree_entry(&tree, i)); - coupons.set(i, Blob::new(eval_coupon.pack())); - new_tree.set(i, Blob::new(runtime.get_coupon_rhs(&eval_coupon).pack())); + coupons.extend_from_slice(&eval_coupon.pack()); + new_tree.extend_from_slice(&runtime.get_coupon_rhs(&eval_coupon).pack()); } - let coupons = runtime.create_tree(coupons); - let new_tree = runtime.create_tree(new_tree); + let coupons = runtime.create_tree(Blob::new(coupons)); + let new_tree = runtime.create_tree(Blob::new(new_tree)); runtime.trade( fixruntime::runtime::CouponTrades::EvalTreeObj, @@ -129,8 +130,8 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { FixHandle::Thunk(_) | FixHandle::Ref(_) => todo!(), FixHandle::Object(obj) => match obj { Object::BlobObj(_) => { - let coupons = Tuple::new(0); - let coupons = runtime.create_tree(coupons); + let coupons = vec![0u8; 0]; + let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( fixruntime::runtime::CouponTrades::EvalBlobObj, coupons, @@ -147,9 +148,10 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { let eq_lhs = runtime.get_coupon_lhs(&eq_coupon); let eq_rhs = runtime.get_coupon_rhs(&eq_coupon); - let mut coupons = Tuple::new(1); - coupons.set(0, Blob::new(eq_coupon.pack())); - let coupons = runtime.create_tree(coupons); + + let mut coupons = Vec::with_capacity(32); + coupons.extend_from_slice(&eq_coupon.pack()); + let coupons = runtime.create_tree(Blob::new(coupons)); let eq_coupon = runtime.trade( fixruntime::runtime::CouponTrades::EqSym, coupons, @@ -158,10 +160,10 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { ); let result = runtime.get_coupon_rhs(&eval_coupon); - let mut coupons = Tuple::new(2); - coupons.set(0, Blob::new(eval_coupon.pack())); - coupons.set(1, Blob::new(eq_coupon.pack())); - let coupons = runtime.create_tree(coupons); + let mut coupons = Vec::with_capacity(2 * 32); + coupons.extend_from_slice(&eval_coupon.pack()); + coupons.extend_from_slice(&eq_coupon.pack()); + let coupons = runtime.create_tree(Blob::new(coupons)); return runtime.trade( fixruntime::runtime::CouponTrades::EvalEq, coupons, diff --git a/fix/src/main.rs b/fix/src/main.rs index 6f5584c..5e05c5a 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -47,21 +47,23 @@ async fn main(_: &[usize]) { log::info!("creating addend 1024"); let addend3 = runtime.create_blob_i64(1024); - let mut scratch = Tuple::new(4); - scratch.set(0, Blob::new(dummy.pack())); - scratch.set(1, Blob::new(function.pack())); - scratch.set(2, Blob::new(addend1.pack())); - scratch.set(3, Blob::new(addend2.pack())); - let combination = runtime.create_tree(scratch); + let mut scratch = Vec::with_capacity(4 * 32); + + scratch.extend_from_slice(&dummy.pack()); + scratch.extend_from_slice(&function.pack()); + scratch.extend_from_slice(&addend1.pack()); + scratch.extend_from_slice(&addend2.pack()); + + let combination = runtime.create_tree(Blob::new(scratch)); let application = create_application_thunk(&combination).unwrap(); let encode = create_strict_encode(&application).unwrap(); - let mut scratch = Tuple::new(4); - scratch.set(0, Blob::new(dummy.pack())); - scratch.set(1, Blob::new(function.pack())); - scratch.set(2, Blob::new(encode.pack())); - scratch.set(3, Blob::new(addend3.pack())); - let combination = runtime.create_tree(scratch); + let mut scratch = Vec::with_capacity(4 * 32); + scratch.extend_from_slice(&dummy.pack()); + scratch.extend_from_slice(&function.pack()); + scratch.extend_from_slice(&encode.pack()); + scratch.extend_from_slice(&addend3.pack()); + let combination = runtime.create_tree(Blob::new(scratch)); let application = create_application_thunk(&combination).unwrap(); let encode = create_strict_encode(&application).unwrap(); From c42a890952eb26503f455af5a8b00b7e5e60df31 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 12 May 2026 18:37:13 -0700 Subject: [PATCH 04/12] feat: evaluator from hypervisor --- .github/workflows/compile.yml | 3 +- Cargo.lock | 68 ++++++++++--- Cargo.toml | 4 +- fix/evaluator/Cargo.toml | 19 ++++ fix/evaluator/src/fixruntime.rs | 146 ++++++++++++++++++++++++++++ fix/evaluator/src/main.rs | 78 +++++++++++++++ fix/evaluator/src/vmmruntime.rs | 164 ++++++++++++++++++++++++++++++++ fix/runtime/src/bottom.rs | 2 +- fix/runtime/src/fixruntime.rs | 2 +- fix/runtime/src/lib.rs | 1 + fix/runtime/src/runtime.rs | 37 ++++--- fix/runtime/src/storage.rs | 44 +++++++++ fix/src/evaluator.rs | 4 +- fix/src/main.rs | 75 +++++---------- vmm/src/runtime.rs | 3 +- 15 files changed, 558 insertions(+), 92 deletions(-) create mode 100644 fix/evaluator/Cargo.toml create mode 100644 fix/evaluator/src/fixruntime.rs create mode 100644 fix/evaluator/src/main.rs create mode 100644 fix/evaluator/src/vmmruntime.rs diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index a54b40f..bebd6ad 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -63,4 +63,5 @@ jobs: sudo -su $USER /home/runner/.cargo/bin/cargo test -p kernel --target=x86_64-unknown-none --verbose - name: Test Fix run: | - sudo -su $USER /home/runner/.cargo/bin/cargo run -p fix --target=x86_64-unknown-none + sudo -su $USER /home/runner/.cargo/bin/cargo build -p fix --target=x86_64-unknown-none + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- $(find . -name "addblob" | tail -n 1) target/x86_64-unknown-none/debug/fix diff --git a/Cargo.lock b/Cargo.lock index 8f973f0..092efad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", - "anstyle-parse", + "anstyle-parse 0.2.7", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse 1.0.0", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -47,6 +62,15 @@ dependencies = [ "utf8parse", ] +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + [[package]] name = "anstyle-query" version = "1.1.5" @@ -326,9 +350,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -424,7 +448,7 @@ version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ - "anstream", + "anstream 0.6.21", "anstyle", "clap_lex", "strsim", @@ -622,9 +646,9 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -632,11 +656,11 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ - "anstream", + "anstream 1.0.0", "anstyle", "env_filter", "jiff", @@ -659,6 +683,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "evaluator" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytemuck", + "clap", + "common", + "env_logger", + "fixhandle", + "log", + "vmm", +] + [[package]] name = "event-listener" version = "5.4.1" @@ -999,9 +1037,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.18" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" dependencies = [ "jiff-static", "log", @@ -1012,9 +1050,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.18" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" dependencies = [ "proc-macro2", "quote", @@ -1414,9 +1452,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 993a3df..197fa21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/runtime", "fix/handle", "fix/shell" ] -default-members = [ "common", "vmm", "macros", "arca", "fix/handle" ] +members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/runtime", "fix/handle", "fix/shell", "fix/evaluator" ] +default-members = [ "common", "vmm", "macros", "arca", "fix/handle", "fix/evaluator" ] resolver = "2" diff --git a/fix/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml new file mode 100644 index 0000000..53166a6 --- /dev/null +++ b/fix/evaluator/Cargo.toml @@ -0,0 +1,19 @@ +cargo-features = ["per-package-target"] + +[package] +name = "evaluator" +version = "0.1.0" +edition = "2024" + +[dependencies] +fixhandle = { path = "../handle" } +vmm = {path = "../../vmm"} +clap = { version = "4.5.48", features = ["derive"] } +anyhow = "1.0.97" +env_logger = "0.11.10" +log = "0.4.29" +common = { path = "../../common" } +bytemuck = "1.25.0" + +[build-dependencies] +anyhow = "1.0.97" diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs new file mode 100644 index 0000000..ad58f82 --- /dev/null +++ b/fix/evaluator/src/fixruntime.rs @@ -0,0 +1,146 @@ +use core::result::Result; +use core::{clone::Clone, panic}; + +use common::bitpack::BitPack; +use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; + +#[allow(unused)] +pub trait DeterministicEquivRuntime { + type Handle: Clone + core::fmt::Debug; + type Error: core::fmt::Debug; + + fn create_blob_i32(&mut self, data: u32) -> Self::Handle; + fn create_blob_i64(&mut self, data: u64) -> Self::Handle; + fn create_blob(&mut self, data: &[u8]) -> Self::Handle; + fn create_tree(&mut self, data: &[u8]) -> Self::Handle; + + fn get_blob(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; + fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; +} + +#[allow(unused)] +#[repr(u32)] +pub enum CouponTrades { + EqTree = 0, + EqApplication = 1, + ForceResultEq = 2, + EqStrictEncode = 3, + ThinkApplication = 4, + ThinkToForce = 5, + ForceToEncodeStric = 6, + EvalEq = 7, + EvalBlobObj = 8, + EvalTreeObj = 9, + EqSym = 10, + EqTrans = 11, + EqSelf = 12, +} + +#[allow(unused)] +pub trait CouponHelper: DeterministicEquivRuntime { + fn read_blob(blob: &[u8], offset: usize, buf: &mut [u8]) -> usize { + let n = (blob.len() - offset).min(buf.len()); + buf[..n].copy_from_slice(&blob[offset..offset + n]); + n + } + + fn get_tree_entry(tree: &[u8], offset: usize) -> Self::Handle { + let mut scratch: [u8; 32] = [0; 32]; + if offset < Self::get_tree_len(tree) { + scratch.copy_from_slice(&tree[offset * 32..(offset + 1) * 32]); + } else { + panic!(); + } + + FixHandle::unpack(scratch) + } + + fn get_tree_len(tree: &[u8]) -> usize { + tree.len() / 32 + } + + fn coupon_type(&mut self, handle: &Self::Handle) -> &'static str { + let mut arr = [0u8; 4]; + let blob = self.get_blob(handle).expect("Coupon type not a blob"); + Self::read_blob(blob, 0, &mut arr); + let num = u32::from_le_bytes(arr); + match num { + 0 => "Eq", + 1 => "Eval", + 2 => "Apply", + 3 => "Force", + 4 => "Think", + 5 => "Storage", + _ => panic!(), + } + } + + fn show_coupon(&mut self, handle: &Self::Handle) { + let ctype = self.get_coupon_type(handle); + let lhs = self.get_coupon_lhs(handle); + let rhs = self.get_coupon_rhs(handle); + + log::info!("type is: {ctype:?}"); + log::info!("lhs is: {lhs:?}"); + log::info!("rhs is: {rhs:?}"); + } + + fn get_coupon_type(&mut self, coupon: &Self::Handle) -> &'static str { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + let handle = Self::get_tree_entry(coupon_content, 1); + self.coupon_type(&handle) + } + + fn get_coupon_lhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + Self::get_tree_entry(coupon_content, 2) + } + + fn get_coupon_rhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + Self::get_tree_entry(coupon_content, 3) + } +} + +#[allow(unused)] +pub trait CouponCollector { + fn trade( + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle; +} + +#[allow(unused)] +pub trait Visitor: CouponHelper { + fn visit(&self, handle: FixHandle, callback: &mut F) + where + F: FnMut(&Self, &FixHandle), + { + match handle { + FixHandle::Encode(e) => match e { + Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback), + }, + FixHandle::Ref(_) => todo!(), + FixHandle::Thunk(t) => match t { + Thunk::Application(tree) => { + self.visit(FixHandle::Object(Object::from(tree)), callback) + } + _ => todo!(), + }, + FixHandle::Object(obj) => match obj { + Object::BlobObj(_) => {} + Object::TreeObj(_) => { + let tree_data = self.get_tree(&handle).unwrap(); + for i in 0..Self::get_tree_len(tree_data) { + let child = Self::get_tree_entry(tree_data, i); + self.visit(Self::get_tree_entry(tree_data, i), callback); + } + } + }, + }; + callback(self, &handle); + } +} diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs new file mode 100644 index 0000000..10dc97f --- /dev/null +++ b/fix/evaluator/src/main.rs @@ -0,0 +1,78 @@ +#![feature(allocator_api)] +#![feature(ptr_metadata)] + +use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime}; +use common::bitpack::BitPack; +use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; +use std::path::PathBuf; + +use crate::vmmruntime::VmmRuntime; +use clap::Parser; + +mod fixruntime; +mod vmmruntime; + +#[derive(Parser, Debug)] +struct Args { + module: PathBuf, + kernel: PathBuf, + #[arg(short, long)] + smp: Option, + #[arg(short, long, default_value = "3")] + cid: usize, +} + +fn main() -> anyhow::Result<()> { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + + let args = Args::parse(); + let smp = args + .smp + // .or_else(|| std::thread::available_parallelism().ok().map(|x| x.get())) + .unwrap_or(1); + let cid = args.cid; + + let bin = std::fs::read(args.kernel)?; + let module = std::fs::read(args.module)?; + + let mut rt = VmmRuntime::new(smp, cid, bin); + + let dummy = rt.create_blob_i64(0xcafeb0ba); + let function = rt.create_blob(module.as_slice()); + let addend1 = rt.create_blob_i64(3); + let addend2 = rt.create_blob_i64(4); + let addend3 = rt.create_blob_i64(1024); + + let mut scratch = Vec::with_capacity(4 * 32); + scratch.extend_from_slice(&dummy.pack()); + scratch.extend_from_slice(&function.pack()); + scratch.extend_from_slice(&addend1.pack()); + scratch.extend_from_slice(&addend2.pack()); + + let combination = rt.create_tree(scratch.as_slice()); + let application = create_application_thunk(&combination).unwrap(); + let encode = create_strict_encode(&application).unwrap(); + + let mut scratch = Vec::with_capacity(4 * 32); + scratch.extend_from_slice(&dummy.pack()); + scratch.extend_from_slice(&function.pack()); + scratch.extend_from_slice(&encode.pack()); + scratch.extend_from_slice(&addend3.pack()); + + let combination = rt.create_tree(scratch.as_slice()); + let application = create_application_thunk(&combination).unwrap(); + let encode = create_strict_encode(&application).unwrap(); + + let result = rt.eval(encode); + rt.show_coupon(&result); + + let result_blob = rt.get_coupon_rhs(&result); + let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); + let mut arr = [0u8; 8]; + arr.copy_from_slice(result_blob); + let num = u64::from_le_bytes(arr); + log::info!("{:?}", num); + assert_eq!(num, 1031); + + Ok(()) +} diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs new file mode 100644 index 0000000..47a6ba2 --- /dev/null +++ b/fix/evaluator/src/vmmruntime.rs @@ -0,0 +1,164 @@ +use core::slice; +use std::{mem, ptr}; + +use common::BuddyAllocator; +use common::bitpack::BitPack; +use fixhandle::rawhandle::{BlobName, FixHandle, Handle, Object, PhysicalHandle, TreeName}; +use vmm::runtime::Runtime; + +use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime}; + +pub struct VmmRuntime { + runtime: Runtime, + store: Vec>, +} + +impl VmmRuntime { + pub fn new(smp: usize, cid: usize, bin: Vec) -> Self { + Self { + runtime: Runtime::new(cid, smp, 1 << 34, bin.into()), + store: Vec::new(), + } + } + + fn create(&mut self, data: Box<[u8], BuddyAllocator>) -> usize { + let idx = self.store.len(); + self.store.push(data); + idx + } + + fn get(&self, idx: usize) -> &[u8] { + &self.store[idx] + } + + fn get_by_handle(&self, handle: Handle) -> &[u8] { + match handle { + Handle::VirtualHandle(_) | Handle::CanonicalHandle(_) => todo!(), + Handle::PhysicalHandle(physical_handle) => self.get(physical_handle.local_id()), + } + } +} + +impl DeterministicEquivRuntime for VmmRuntime { + type Handle = FixHandle; + type Error = (); + + fn create_blob_i32(&mut self, data: u32) -> FixHandle { + let x = data.to_le_bytes().to_vec().into_boxed_slice(); + self.create_blob(&x) + } + + fn create_blob_i64(&mut self, data: u64) -> FixHandle { + let x = data.to_le_bytes().to_vec().into_boxed_slice(); + self.create_blob(&x) + } + + fn create_blob(&mut self, data: &[u8]) -> FixHandle { + let len = data.len(); + let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); + let blob = BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); + Object::from(blob).into() + } + + fn create_tree(&mut self, data: &[u8]) -> FixHandle { + let len = data.len() / 32; + let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); + let tree = TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); + Object::from(tree).into() + } + + fn get_blob(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error> { + let b = handle + .try_unwrap_object_ref() + .map_err(|_| ())? + .try_unwrap_blob_obj_ref() + .map_err(|_| ())? + .unwrap_blob(); + Ok(self.get_by_handle(b)) + } + fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error> { + let t = handle + .try_unwrap_object_ref() + .map_err(|_| ())? + .try_unwrap_tree_obj_ref() + .map_err(|_| ())?; + match t { + TreeName::NotTag(tree) | TreeName::Tag(tree) => Ok(self.get_by_handle(*tree)), + } + } +} + +impl VmmRuntime { + fn into_raw_parts(input: Box<[T], BuddyAllocator>) -> (usize, usize) { + let (data, _) = Box::into_raw_with_allocator(input); + let len = ptr::metadata(data); + let offset = BuddyAllocator.to_offset(data); + (offset, len) + } + + fn from_raw_parts(offset: usize, len: usize) -> Box<[T], BuddyAllocator> { + let data = BuddyAllocator.from_offset(offset); + unsafe { + let slice = slice::from_raw_parts_mut(data, len); + Box::from_raw_in(slice, BuddyAllocator) + } + } + + fn load(&mut self) -> Box<[(usize, usize)], BuddyAllocator> { + let mut res = Vec::with_capacity_in(2 * 8 * self.store.len(), BuddyAllocator); + + let v = mem::take(&mut self.store); + + for entry in v.into_iter() { + res.push(Self::into_raw_parts(entry)); + } + + res.into_boxed_slice() + } + + fn unload(&mut self, input: Box<[(usize, usize)], BuddyAllocator>) { + for (offset, len) in input.into_iter() { + self.store.push(Self::from_raw_parts(offset, len)); + } + } + + pub fn eval(&mut self, handle: FixHandle) -> FixHandle { + let handle_scratch: Box<[u8], _> = Box::new_in(handle.pack(), BuddyAllocator); + let output_store: Box<[usize], _> = Box::new_in([0; 2], BuddyAllocator); + + let (handle_scratch_offset, handle_scratch_len) = Self::into_raw_parts(handle_scratch); + let (store_offset, store_len) = Self::into_raw_parts(self.load()); + let (output_store_offset, output_store_len) = Self::into_raw_parts(output_store); + + let args = [ + handle_scratch_offset, + handle_scratch_len, + store_offset, + store_len, + output_store_offset, + output_store_len, + ]; + self.runtime.run(&args); + + let output_store: Box<[usize], BuddyAllocator> = + Self::from_raw_parts(output_store_offset, output_store_len); + let output_store_slice: &[usize; 2] = output_store + .as_ref() + .try_into() + .expect("Failed to convert output store back"); + self.unload(Self::from_raw_parts( + output_store_slice[0], + output_store_slice[1], + )); + + let handle_scratch: Box<[u8], BuddyAllocator> = + Self::from_raw_parts(handle_scratch_offset, handle_scratch_len); + let handle_slice: &[u8; 32] = handle_scratch + .as_ref() + .try_into() + .expect("Failed to convert handle_slice back"); + FixHandle::unpack(*handle_slice) + } +} + +impl CouponHelper for VmmRuntime {} diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index 0742cb5..886421c 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -4,7 +4,7 @@ use crate::{ // data::{BlobData, RawData, TreeData}, fixruntime::FixRuntime, - runtime::{DeterministicEquivRuntime, Executor, CouponHelper}, + runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, }; use arca::Runtime; diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 979faff..4fda94d 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -11,8 +11,8 @@ use bytemuck::bytes_of; use common::bitpack::BitPack; use derive_more::TryUnwrapError; use fixhandle::rawhandle::{FixHandle, Object, TreeName}; -use kernel::types::{Blob}; use kernel::prelude::*; +use kernel::types::Blob; #[derive(Debug)] pub enum Error { diff --git a/fix/runtime/src/lib.rs b/fix/runtime/src/lib.rs index 5c9bf67..fdcdcc6 100644 --- a/fix/runtime/src/lib.rs +++ b/fix/runtime/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(dead_code)] +#![feature(ptr_metadata)] pub mod bottom; // pub mod data; diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 6812ce5..8643a7f 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -1,7 +1,7 @@ use core::clone::Clone; use core::result::Result; -use fixhandle::rawhandle::{FixHandle, Encode, Thunk, Object}; +use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; #[allow(unused)] pub trait DeterministicEquivRuntime { @@ -110,34 +110,31 @@ pub trait CouponHelper: DeterministicEquivRuntime { } #[allow(unused)] -pub trait Visitor : CouponHelper { +pub trait Visitor: CouponHelper { fn visit(&mut self, handle: FixHandle, callback: &mut F) - where F: FnMut(&mut Self, &FixHandle), + where + F: FnMut(&mut Self, &FixHandle), { match handle { - FixHandle::Encode(e) => { - match e { - Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback) - } + FixHandle::Encode(e) => match e { + Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback), }, FixHandle::Ref(_) => todo!(), - FixHandle::Thunk(t) => { - match t { - Thunk::Application(tree) => self.visit(FixHandle::Object(Object::from(tree)), callback), - _ => todo!() + FixHandle::Thunk(t) => match t { + Thunk::Application(tree) => { + self.visit(FixHandle::Object(Object::from(tree)), callback) } + _ => todo!(), }, - FixHandle::Object(obj) => { - match obj { - Object::BlobObj(_) => {}, - Object::TreeObj(_) => { - let tree_data = self.get_tree(&handle).unwrap(); - for i in 0..Self::get_tree_len(&tree_data) { - self.visit(Self::get_tree_entry(&tree_data, i), callback); - } + FixHandle::Object(obj) => match obj { + Object::BlobObj(_) => {} + Object::TreeObj(_) => { + let tree_data = self.get_tree(&handle).unwrap(); + for i in 0..Self::get_tree_len(&tree_data) { + self.visit(Self::get_tree_entry(&tree_data, i), callback); } } - } + }, }; callback(self, &handle); } diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index a4e9183..4db1a64 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -1,4 +1,5 @@ // use crate::data::{BlobData, RawData, TreeData}; +use core::{mem, ptr, slice}; use fixhandle::rawhandle::{BlobName, Handle, PhysicalHandle, TreeName}; use kernel::prelude::*; @@ -100,3 +101,46 @@ impl Storage for ObjectStore { } } } + +impl ObjectStore { + pub fn into_raw_parts(input: Box<[T]>) -> (usize, usize) { + let data = Box::into_raw(input); + let len = ptr::metadata(data); + let offset = if len > 0 { + BuddyAllocator.to_offset(data) + } else { + 0 + }; + (offset, len) + } + + pub fn from_raw_parts(offset: usize, len: usize) -> Box<[T]> { + let data = BuddyAllocator.from_offset(offset); + unsafe { + let slice = slice::from_raw_parts_mut(data, len); + Box::from_raw(slice) + } + } + + pub fn load(&mut self, input: Box<[(usize, usize)]>) { + for (offset, len) in input.into_iter() { + let x = Self::from_raw_parts(offset, len); + self.store.create(Blob::new(x).into()); + } + log::info!("Loaded {:?} objects", self.store.table.len()); + } + + pub fn unload(&mut self) -> Box<[(usize, usize)]> { + let mut res = Vec::with_capacity(2 * 8 * self.store.table.len()); + + let v = mem::take(&mut self.store.table); + + for entry in v.into_iter() { + let blob: Blob = entry.inner.try_into().unwrap(); + let blob = blob.into_inner().into_inner(); + res.push(Self::into_raw_parts(blob)); + } + + res.into_boxed_slice() + } +} diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index 7b36fae..f4aa3fa 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -164,12 +164,12 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { coupons.extend_from_slice(&eval_coupon.pack()); coupons.extend_from_slice(&eq_coupon.pack()); let coupons = runtime.create_tree(Blob::new(coupons)); - return runtime.trade( + runtime.trade( fixruntime::runtime::CouponTrades::EvalEq, coupons, handle, result, - ); + ) } } } diff --git a/fix/src/main.rs b/fix/src/main.rs index 5e05c5a..1ddf985 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -6,7 +6,7 @@ #![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] #![allow(dead_code)] -use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; +use fixhandle::rawhandle::FixHandle; use kernel::prelude::*; #[cfg(feature = "testing-mode")] @@ -16,10 +16,7 @@ mod evaluator; use common::bitpack::BitPack; -use fixruntime::{ - fixruntime::FixRuntime, runtime::CouponHelper, runtime::DeterministicEquivRuntime, - storage::ObjectStore, -}; +use fixruntime::{fixruntime::FixRuntime, storage::ObjectStore}; use crate::evaluator::eval; @@ -31,53 +28,33 @@ const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); const COUPON: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/coupon")); #[kmain] -async fn main(_: &[usize]) { - let mut store = ObjectStore::new(); - let mut runtime = FixRuntime::new(&mut store, COUPON); - - log::info!("runnning + (+ 3 4) 1024"); - log::info!("creating resource limits"); - let dummy = runtime.create_blob_i64(0xcafeb0ba); - log::info!("creating function"); - let function = runtime.create_blob(MODULE.into()); - log::info!("creating addend 3"); - let addend1 = runtime.create_blob_i64(3); - log::info!("creating addend 4"); - let addend2 = runtime.create_blob_i64(4); - log::info!("creating addend 1024"); - let addend3 = runtime.create_blob_i64(1024); - - let mut scratch = Vec::with_capacity(4 * 32); +async fn main(args: &[usize]) { + let args: &[usize; 6] = args.try_into().unwrap(); + let (handle_scratch_offset, handle_scratch_len) = (args[0], args[1]); + let (store_offset, store_len) = (args[2], args[3]); + let (output_store_offset, output_store_len) = (args[4], args[5]); - scratch.extend_from_slice(&dummy.pack()); - scratch.extend_from_slice(&function.pack()); - scratch.extend_from_slice(&addend1.pack()); - scratch.extend_from_slice(&addend2.pack()); + let mut handle_scratch: Box<[u8]> = + ObjectStore::from_raw_parts(handle_scratch_offset, handle_scratch_len); + let handle_slice: &mut [u8; 32] = handle_scratch.as_mut().try_into().unwrap(); + let input_handle = FixHandle::unpack(*handle_slice); - let combination = runtime.create_tree(Blob::new(scratch)); - let application = create_application_thunk(&combination).unwrap(); - let encode = create_strict_encode(&application).unwrap(); + let input_store: Box<[(usize, usize)]> = ObjectStore::from_raw_parts(store_offset, store_len); + let mut output_store: Box<[usize]> = + ObjectStore::from_raw_parts(output_store_offset, output_store_len); - let mut scratch = Vec::with_capacity(4 * 32); - scratch.extend_from_slice(&dummy.pack()); - scratch.extend_from_slice(&function.pack()); - scratch.extend_from_slice(&encode.pack()); - scratch.extend_from_slice(&addend3.pack()); - let combination = runtime.create_tree(Blob::new(scratch)); - let application = create_application_thunk(&combination).unwrap(); - let encode = create_strict_encode(&application).unwrap(); - - let eval_coupon = eval(&mut runtime, encode); + let mut store = ObjectStore::new(); + store.load(input_store); + let mut runtime = FixRuntime::new(&mut store, COUPON); - runtime.show_coupon(&eval_coupon); + let eval_coupon = eval(&mut runtime, input_handle); - let result_blob = runtime.get_coupon_rhs(&eval_coupon); - let result_blob = runtime - .get_blob(&result_blob) - .expect("Result is not a Blob"); - let mut arr = [0u8; 8]; - result_blob.read(0, &mut arr); - let num = u64::from_le_bytes(arr); - log::info!("{:?}", num); - assert_eq!(num, 1031); + let output_store_slice: &mut [usize; 2] = output_store + .as_mut() + .try_into() + .expect("Failed to convert output store back"); + let (output_store_offset, output_store_len) = ObjectStore::into_raw_parts(store.unload()); + output_store_slice[0] = output_store_offset; + output_store_slice[1] = output_store_len; + handle_slice.copy_from_slice(&eval_coupon.pack()); } diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 3a5b0b0..2053a33 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -193,7 +193,8 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc let args = &[regs.rdi, regs.rsi, regs.rcx, regs.r10, regs.r8, regs.r9]; match code { hypercall::EXIT => { - ExitCode::from(args[0] as u8).exit_process(); + return; + // ExitCode::from(args[0] as u8).exit_process(); } hypercall::LOG => { let record: *const common::LogRecord = From 4b3fb186795ec497d362e12e86942e405402fa5c Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 13:13:27 -0700 Subject: [PATCH 05/12] fix: move common definitions to common.rs --- fix/runtime/src/common.rs | 25 +++++++++++++++++++++++++ fix/runtime/src/fixruntime.rs | 3 ++- fix/runtime/src/lib.rs | 1 + fix/runtime/src/runtime.rs | 19 +------------------ fix/src/evaluator.rs | 15 ++++++++------- 5 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 fix/runtime/src/common.rs diff --git a/fix/runtime/src/common.rs b/fix/runtime/src/common.rs new file mode 100644 index 0000000..dbc63df --- /dev/null +++ b/fix/runtime/src/common.rs @@ -0,0 +1,25 @@ +#[allow(unused)] +#[repr(u32)] +pub enum CouponTrades { + EqTree = 0, + EqApplication = 1, + ForceResultEq = 2, + EqStrictEncode = 3, + ThinkApplication = 4, + ThinkToForce = 5, + ForceToEncodeStric = 6, + EvalEq = 7, + EvalBlobObj = 8, + EvalTreeObj = 9, + EqSym = 10, + EqTrans = 11, + EqSelf = 12, +} + +#[allow(unused)] +#[repr(usize)] +pub enum FixOp { + Eval = 0, + Trade = 1, + Apply = 2, +} diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 4fda94d..5a5bae2 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -4,8 +4,9 @@ use crate::{ bottom::FixShellBottom, // data::{BlobData, TreeData}, - runtime::{CouponHelper, CouponTrades, DeterministicEquivRuntime, Executor}, + runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, storage::{ObjectStore, Storage}, + common::CouponTrades, }; use bytemuck::bytes_of; use common::bitpack::BitPack; diff --git a/fix/runtime/src/lib.rs b/fix/runtime/src/lib.rs index fdcdcc6..3eac9aa 100644 --- a/fix/runtime/src/lib.rs +++ b/fix/runtime/src/lib.rs @@ -7,3 +7,4 @@ pub mod bottom; pub mod fixruntime; pub mod runtime; pub mod storage; +pub mod common; diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 8643a7f..4d9756f 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -2,6 +2,7 @@ use core::clone::Clone; use core::result::Result; use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; +use crate::common::CouponTrades; #[allow(unused)] pub trait DeterministicEquivRuntime { @@ -34,24 +35,6 @@ pub trait Executor { fn execute(&mut self, combination: &FixHandle) -> FixHandle; } -#[allow(unused)] -#[repr(u32)] -pub enum CouponTrades { - EqTree = 0, - EqApplication = 1, - ForceResultEq = 2, - EqStrictEncode = 3, - ThinkApplication = 4, - ThinkToForce = 5, - ForceToEncodeStric = 6, - EvalEq = 7, - EvalBlobObj = 8, - EvalTreeObj = 9, - EqSym = 10, - EqTrans = 11, - EqSelf = 12, -} - #[allow(unused)] pub trait CouponHelper: DeterministicEquivRuntime { fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize; diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index f4aa3fa..8c4d8dd 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -3,6 +3,7 @@ use fixhandle::rawhandle::{Encode, FixHandle, Object, Ref, Thunk, TreeName}; use fixruntime::{ fixruntime::FixRuntime, runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, + common::CouponTrades, }; use common::bitpack::BitPack; @@ -49,7 +50,7 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let coupons = runtime.create_tree(Blob::new(coupons)); let result = runtime.get_coupon_rhs(&apply_coupon); runtime.trade( - fixruntime::runtime::CouponTrades::ThinkApplication, + CouponTrades::ThinkApplication, coupons, FixHandle::Thunk(*thunk), result, @@ -68,7 +69,7 @@ fn force(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( - fixruntime::runtime::CouponTrades::ThinkToForce, + CouponTrades::ThinkToForce, coupons, FixHandle::Thunk(*thunk), result, @@ -90,7 +91,7 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( - fixruntime::runtime::CouponTrades::ForceToEncodeStric, + CouponTrades::ForceToEncodeStric, coupons, FixHandle::Encode(*encode), result, @@ -118,7 +119,7 @@ fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { let new_tree = runtime.create_tree(Blob::new(new_tree)); runtime.trade( - fixruntime::runtime::CouponTrades::EvalTreeObj, + CouponTrades::EvalTreeObj, coupons, tree_handle, new_tree, @@ -133,7 +134,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { let coupons = vec![0u8; 0]; let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( - fixruntime::runtime::CouponTrades::EvalBlobObj, + CouponTrades::EvalBlobObj, coupons, handle, handle, @@ -153,7 +154,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { coupons.extend_from_slice(&eq_coupon.pack()); let coupons = runtime.create_tree(Blob::new(coupons)); let eq_coupon = runtime.trade( - fixruntime::runtime::CouponTrades::EqSym, + CouponTrades::EqSym, coupons, eq_rhs, eq_lhs, @@ -165,7 +166,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { coupons.extend_from_slice(&eq_coupon.pack()); let coupons = runtime.create_tree(Blob::new(coupons)); runtime.trade( - fixruntime::runtime::CouponTrades::EvalEq, + CouponTrades::EvalEq, coupons, handle, result, From 92c037be4058c67d043530f1bafea0a7cc0b1e83 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 13:34:19 -0700 Subject: [PATCH 06/12] feat: skip resource entry for now --- fix/evaluator/src/main.rs | 7 ++----- fix/runtime/src/bottom.rs | 2 +- fix/runtime/src/fixruntime.rs | 5 ++--- fix/runtime/src/lib.rs | 2 +- fix/runtime/src/runtime.rs | 2 +- fix/shell/src/lib.rs | 2 +- fix/src/evaluator.rs | 30 +++++------------------------- fix/wasm/addblob.wat | 4 ++-- fix/wasm/coupon.wat | 10 +++++----- 9 files changed, 20 insertions(+), 44 deletions(-) diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 10dc97f..04d10bc 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -37,14 +37,12 @@ fn main() -> anyhow::Result<()> { let mut rt = VmmRuntime::new(smp, cid, bin); - let dummy = rt.create_blob_i64(0xcafeb0ba); let function = rt.create_blob(module.as_slice()); let addend1 = rt.create_blob_i64(3); let addend2 = rt.create_blob_i64(4); let addend3 = rt.create_blob_i64(1024); - let mut scratch = Vec::with_capacity(4 * 32); - scratch.extend_from_slice(&dummy.pack()); + let mut scratch = Vec::with_capacity(3 * 32); scratch.extend_from_slice(&function.pack()); scratch.extend_from_slice(&addend1.pack()); scratch.extend_from_slice(&addend2.pack()); @@ -53,8 +51,7 @@ fn main() -> anyhow::Result<()> { let application = create_application_thunk(&combination).unwrap(); let encode = create_strict_encode(&application).unwrap(); - let mut scratch = Vec::with_capacity(4 * 32); - scratch.extend_from_slice(&dummy.pack()); + let mut scratch = Vec::with_capacity(3 * 32); scratch.extend_from_slice(&function.pack()); scratch.extend_from_slice(&encode.pack()); scratch.extend_from_slice(&addend3.pack()); diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index 886421c..941540e 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -179,7 +179,7 @@ impl<'a, 'b> FixShellBottom<'a, 'b> { impl<'a, 'b> Executor for FixShellBottom<'a, 'b> { fn execute(&mut self, combination: &FixHandle) -> FixHandle { let tree = self.parent.get_tree(combination).unwrap(); - let function_handle = FixRuntime::<'_>::get_tree_entry(&tree, 1); + let function_handle = FixRuntime::<'_>::get_tree_entry(&tree, 0); let elf = self.parent.get_blob(&function_handle).unwrap(); let f = common::elfloader::load_elf(&elf).expect("Failed to load elf"); diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 5a5bae2..8d4708b 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -3,10 +3,10 @@ use crate::{ bottom::FixShellBottom, + common::CouponTrades, // data::{BlobData, TreeData}, runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, storage::{ObjectStore, Storage}, - common::CouponTrades, }; use bytemuck::bytes_of; use common::bitpack::BitPack; @@ -156,8 +156,7 @@ impl<'a> CouponHelper for FixRuntime<'a> { lhs: FixHandle, rhs: FixHandle, ) -> FixHandle { - let mut combination = Vec::with_capacity(32 * 6); - combination.extend_from_slice(&self.create_blob_i32(0).pack()); + let mut combination = Vec::with_capacity(32 * 5); combination.extend_from_slice(&self.coupon.pack()); combination.extend_from_slice(&self.create_blob_i32(trade_type as u32).pack()); combination.extend_from_slice(&coupons.pack()); diff --git a/fix/runtime/src/lib.rs b/fix/runtime/src/lib.rs index 3eac9aa..c193531 100644 --- a/fix/runtime/src/lib.rs +++ b/fix/runtime/src/lib.rs @@ -4,7 +4,7 @@ pub mod bottom; // pub mod data; +pub mod common; pub mod fixruntime; pub mod runtime; pub mod storage; -pub mod common; diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 4d9756f..27590c7 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -1,8 +1,8 @@ use core::clone::Clone; use core::result::Result; -use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; use crate::common::CouponTrades; +use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; #[allow(unused)] pub trait DeterministicEquivRuntime { diff --git a/fix/shell/src/lib.rs b/fix/shell/src/lib.rs index a27ae61..81cd60c 100644 --- a/fix/shell/src/lib.rs +++ b/fix/shell/src/lib.rs @@ -106,7 +106,7 @@ pub fn main() -> ! { }; let procedure_ref = &raw mut _PROCEDURE; - tree.read(32, &mut *procedure_ref); + tree.read(0, &mut *procedure_ref); } let wasm_rt_externref_t { bytes: result } = diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index 8c4d8dd..6054f63 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -1,9 +1,9 @@ use fixhandle::rawhandle::{Encode, FixHandle, Object, Ref, Thunk, TreeName}; use fixruntime::{ + common::CouponTrades, fixruntime::FixRuntime, runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, - common::CouponTrades, }; use common::bitpack::BitPack; @@ -118,12 +118,7 @@ fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { let coupons = runtime.create_tree(Blob::new(coupons)); let new_tree = runtime.create_tree(Blob::new(new_tree)); - runtime.trade( - CouponTrades::EvalTreeObj, - coupons, - tree_handle, - new_tree, - ) + runtime.trade(CouponTrades::EvalTreeObj, coupons, tree_handle, new_tree) } pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { @@ -133,12 +128,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { Object::BlobObj(_) => { let coupons = vec![0u8; 0]; let coupons = runtime.create_tree(Blob::new(coupons)); - runtime.trade( - CouponTrades::EvalBlobObj, - coupons, - handle, - handle, - ) + runtime.trade(CouponTrades::EvalBlobObj, coupons, handle, handle) } Object::TreeObj(tree) => eval_tree(runtime, &tree), }, @@ -153,24 +143,14 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { let mut coupons = Vec::with_capacity(32); coupons.extend_from_slice(&eq_coupon.pack()); let coupons = runtime.create_tree(Blob::new(coupons)); - let eq_coupon = runtime.trade( - CouponTrades::EqSym, - coupons, - eq_rhs, - eq_lhs, - ); + let eq_coupon = runtime.trade(CouponTrades::EqSym, coupons, eq_rhs, eq_lhs); let result = runtime.get_coupon_rhs(&eval_coupon); let mut coupons = Vec::with_capacity(2 * 32); coupons.extend_from_slice(&eval_coupon.pack()); coupons.extend_from_slice(&eq_coupon.pack()); let coupons = runtime.create_tree(Blob::new(coupons)); - runtime.trade( - CouponTrades::EvalEq, - coupons, - handle, - result, - ) + runtime.trade(CouponTrades::EvalEq, coupons, handle, result) } } } diff --git a/fix/wasm/addblob.wat b/fix/wasm/addblob.wat index 8f654e2..d4f1683 100644 --- a/fix/wasm/addblob.wat +++ b/fix/wasm/addblob.wat @@ -18,10 +18,10 @@ drop (call $attach_blob (i32.const 1) - (table.get $tab_0 (i32.const 2))) + (table.get $tab_0 (i32.const 1))) (call $attach_blob (i32.const 2) - (table.get $tab_0 (i32.const 3))) + (table.get $tab_0 (i32.const 2))) ;; write to rw-memory (i64.store (memory $mem_0) (i32.const 0) diff --git a/fix/wasm/coupon.wat b/fix/wasm/coupon.wat index 7574ca8..f7b36c3 100644 --- a/fix/wasm/coupon.wat +++ b/fix/wasm/coupon.wat @@ -33,7 +33,7 @@ ;; Attach the tag (call $attach_tree (i32.const 1) (local.get $tag)) ;; Check if the tag was authored by us - (call $is_equal (table.get $encode (i32.const 1)) (table.get $coupon_scratch (i32.const 0))) + (call $is_equal (table.get $encode (i32.const 0)) (table.get $coupon_scratch (i32.const 0))) (if (result i32) (then ;; Check if the coupon type matches the input type @@ -71,7 +71,7 @@ (call $is_coupon (local.get $tag) (global.get $Storage)) ) (func $create_coupon (param $type i32) (param $lhs externref) (param $rhs externref) (result externref) - (table.set $output_coupon_scratch (i32.const 0) (table.get $encode (i32.const 1))) + (table.set $output_coupon_scratch (i32.const 0) (table.get $encode (i32.const 0))) (table.set $output_coupon_scratch (i32.const 1) (call $create_blob_i32 (local.get $type))) (table.set $output_coupon_scratch (i32.const 2) (local.get $lhs)) (table.set $output_coupon_scratch (i32.const 3) (local.get $rhs)) @@ -670,15 +670,15 @@ ;; attach coupons (call $attach_tree (i32.const 2) - (table.get $encode (i32.const 3))) + (table.get $encode (i32.const 2))) ;; attach request field (call $attach_blob (i32.const 1) - (table.get $encode (i32.const 2))) + (table.get $encode (i32.const 1))) (call $make_coupon (i32.load $mem_1 (i32.const 0)) + (table.get $encode (i32.const 3)) (table.get $encode (i32.const 4)) - (table.get $encode (i32.const 5)) ) ) (export "coupons" (table $coupons)) From 35470a4344a34c7a723733a4b4d106d648fe53f4 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 15:14:40 -0700 Subject: [PATCH 07/12] feat: add subcommands for fix kernel --- fix/evaluator/src/fixruntime.rs | 32 ++++++------- fix/evaluator/src/main.rs | 83 ++++++++++++++++++++++++++------- fix/evaluator/src/vmmruntime.rs | 45 ++++++++++++++++-- fix/runtime/src/common.rs | 36 ++++++++++++++ fix/src/main.rs | 32 ++++++++++--- vmm/src/runtime.rs | 8 +++- 6 files changed, 189 insertions(+), 47 deletions(-) diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index ad58f82..703218c 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -4,6 +4,8 @@ use core::{clone::Clone, panic}; use common::bitpack::BitPack; use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; +use crate::vmcommon::CouponTrades; + #[allow(unused)] pub trait DeterministicEquivRuntime { type Handle: Clone + core::fmt::Debug; @@ -18,24 +20,6 @@ pub trait DeterministicEquivRuntime { fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; } -#[allow(unused)] -#[repr(u32)] -pub enum CouponTrades { - EqTree = 0, - EqApplication = 1, - ForceResultEq = 2, - EqStrictEncode = 3, - ThinkApplication = 4, - ThinkToForce = 5, - ForceToEncodeStric = 6, - EvalEq = 7, - EvalBlobObj = 8, - EvalTreeObj = 9, - EqSym = 10, - EqTrans = 11, - EqSelf = 12, -} - #[allow(unused)] pub trait CouponHelper: DeterministicEquivRuntime { fn read_blob(blob: &[u8], offset: usize, buf: &mut [u8]) -> usize { @@ -103,7 +87,7 @@ pub trait CouponHelper: DeterministicEquivRuntime { } #[allow(unused)] -pub trait CouponCollector { +pub trait Operator { fn trade( &mut self, trade_type: CouponTrades, @@ -111,6 +95,16 @@ pub trait CouponCollector { lhs: FixHandle, rhs: FixHandle, ) -> FixHandle; + + fn eval ( + &mut self, + handle: FixHandle + ) -> FixHandle; + + fn apply ( + &mut self, + handle: FixHandle + ) -> FixHandle; } #[allow(unused)] diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 04d10bc..a8086e2 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -1,43 +1,38 @@ #![feature(allocator_api)] #![feature(ptr_metadata)] +#![feature(result_option_map_or_default)] -use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime}; +use crate::vmcommon::CouponTrades; +use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; use common::bitpack::BitPack; use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; use std::path::PathBuf; +use std::sync::Arc; use crate::vmmruntime::VmmRuntime; use clap::Parser; +#[path = "../../runtime/src/common.rs"] +mod vmcommon; + mod fixruntime; mod vmmruntime; #[derive(Parser, Debug)] struct Args { - module: PathBuf, kernel: PathBuf, + module: PathBuf, + test: String, #[arg(short, long)] smp: Option, #[arg(short, long, default_value = "3")] cid: usize, } -fn main() -> anyhow::Result<()> { - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); - - let args = Args::parse(); - let smp = args - .smp - // .or_else(|| std::thread::available_parallelism().ok().map(|x| x.get())) - .unwrap_or(1); - let cid = args.cid; - - let bin = std::fs::read(args.kernel)?; - let module = std::fs::read(args.module)?; - +fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { let mut rt = VmmRuntime::new(smp, cid, bin); - let function = rt.create_blob(module.as_slice()); + let function = rt.create_blob(module); let addend1 = rt.create_blob_i64(3); let addend2 = rt.create_blob_i64(4); let addend3 = rt.create_blob_i64(1024); @@ -70,6 +65,62 @@ fn main() -> anyhow::Result<()> { let num = u64::from_le_bytes(arr); log::info!("{:?}", num); assert_eq!(num, 1031); +} + +fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { + let mut rt = VmmRuntime::new(smp, cid, bin); + + let function = rt.create_blob(module); + let addend1 = rt.create_blob_i64(3); + let addend2 = rt.create_blob_i64(4); + + let mut scratch = Vec::with_capacity(3 * 32); + scratch.extend_from_slice(&function.pack()); + scratch.extend_from_slice(&addend1.pack()); + scratch.extend_from_slice(&addend2.pack()); + + let combination = rt.create_tree(scratch.as_slice()); + + let result = rt.apply(combination); + rt.show_coupon(&result); + + let result_blob = rt.get_coupon_rhs(&result); + let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); + let mut arr = [0u8; 8]; + arr.copy_from_slice(result_blob); + let num = u64::from_le_bytes(arr); + log::info!("{:?}", num); + assert_eq!(num, 7); +} + +fn test_trade(smp: usize, cid: usize, bin: Arc<[u8]>) { + let mut rt = VmmRuntime::new(smp, cid, bin); + + let addend = rt.create_blob_i64(3); + let scratch = Vec::with_capacity(0); + let coupons = rt.create_tree(scratch.as_slice()); + + rt.trade(CouponTrades::EvalBlobObj, coupons, addend, addend); +} + +fn main() -> anyhow::Result<()> { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + + let args = Args::parse(); + let smp = args + .smp + // .or_else(|| std::thread::available_parallelism().ok().map(|x| x.get())) + .unwrap_or(1); + let cid = args.cid; + + let bin: Arc<[u8]> = std::fs::read(args.kernel)?.into(); + let module = std::fs::read(args.module)?; + match args.test.as_str() { + "eval" => test_eval(smp, cid, bin, module.as_slice()), + "trade" => test_trade(smp, cid, bin), + "apply" => test_apply(smp, cid, bin, module.as_slice()), + _ => panic!("Unknown test") + } Ok(()) } diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index 47a6ba2..e08b95b 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -1,4 +1,5 @@ use core::slice; +use std::sync::Arc; use std::{mem, ptr}; use common::BuddyAllocator; @@ -6,7 +7,8 @@ use common::bitpack::BitPack; use fixhandle::rawhandle::{BlobName, FixHandle, Handle, Object, PhysicalHandle, TreeName}; use vmm::runtime::Runtime; -use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime}; +use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; +use crate::vmcommon::{FixOp, CouponTrades}; pub struct VmmRuntime { runtime: Runtime, @@ -14,9 +16,9 @@ pub struct VmmRuntime { } impl VmmRuntime { - pub fn new(smp: usize, cid: usize, bin: Vec) -> Self { + pub fn new(smp: usize, cid: usize, bin: Arc<[u8]>) -> Self { Self { - runtime: Runtime::new(cid, smp, 1 << 34, bin.into()), + runtime: Runtime::new(cid, smp, 1 << 34, bin), store: Vec::new(), } } @@ -122,7 +124,7 @@ impl VmmRuntime { } } - pub fn eval(&mut self, handle: FixHandle) -> FixHandle { + fn run(&mut self, opcode: FixOp, coupon_trade: Option, handle: FixHandle) -> FixHandle { let handle_scratch: Box<[u8], _> = Box::new_in(handle.pack(), BuddyAllocator); let output_store: Box<[usize], _> = Box::new_in([0; 2], BuddyAllocator); @@ -131,6 +133,8 @@ impl VmmRuntime { let (output_store_offset, output_store_len) = Self::into_raw_parts(output_store); let args = [ + opcode as usize, + coupon_trade.map_or_default(|t| t as usize), handle_scratch_offset, handle_scratch_len, store_offset, @@ -162,3 +166,36 @@ impl VmmRuntime { } impl CouponHelper for VmmRuntime {} + +impl Operator for VmmRuntime { + fn eval ( + &mut self, + handle: FixHandle + ) -> FixHandle { + self.run(FixOp::Eval, None, handle) + } + + fn trade( + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle { + let mut scratch = Vec::with_capacity(3 * 32); + scratch.extend_from_slice(&coupons.pack()); + scratch.extend_from_slice(&lhs.pack()); + scratch.extend_from_slice(&rhs.pack()); + let scratch = self.create_tree(scratch.as_slice()); + + self.run(FixOp::Trade, Some(trade_type), scratch) + } + + fn apply ( + &mut self, + handle: FixHandle + ) -> FixHandle { + self.run(FixOp::Apply, None, handle) + } + +} diff --git a/fix/runtime/src/common.rs b/fix/runtime/src/common.rs index dbc63df..4589cd1 100644 --- a/fix/runtime/src/common.rs +++ b/fix/runtime/src/common.rs @@ -16,6 +16,29 @@ pub enum CouponTrades { EqSelf = 12, } +impl TryFrom for CouponTrades { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + 0 => Ok(CouponTrades::EqTree), + 1 => Ok(CouponTrades::EqApplication), + 2 => Ok(CouponTrades::ForceResultEq), + 3 => Ok(CouponTrades::EqStrictEncode), + 4 => Ok(CouponTrades::ThinkApplication), + 5 => Ok(CouponTrades::ThinkToForce), + 6 => Ok(CouponTrades::ForceToEncodeStric), + 7 => Ok(CouponTrades::EvalEq), + 8 => Ok(CouponTrades::EvalBlobObj), + 9 => Ok(CouponTrades::EvalTreeObj), + 10 => Ok(CouponTrades::EqSym), + 11 => Ok(CouponTrades::EqTrans), + 12 => Ok(CouponTrades::EqSelf), + _ => Err(()) + } + } +} + #[allow(unused)] #[repr(usize)] pub enum FixOp { @@ -23,3 +46,16 @@ pub enum FixOp { Trade = 1, Apply = 2, } + +impl TryFrom for FixOp { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + 0 => Ok(FixOp::Eval), + 1 => Ok(FixOp::Trade), + 2 => Ok(FixOp::Apply), + _ => Err(()) + } + } +} diff --git a/fix/src/main.rs b/fix/src/main.rs index 1ddf985..2a429a3 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -7,6 +7,10 @@ #![allow(dead_code)] use fixhandle::rawhandle::FixHandle; +use fixruntime::{ + common::{CouponTrades, FixOp}, + runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, +}; use kernel::prelude::*; #[cfg(feature = "testing-mode")] @@ -29,10 +33,11 @@ const COUPON: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/coupon")); #[kmain] async fn main(args: &[usize]) { - let args: &[usize; 6] = args.try_into().unwrap(); - let (handle_scratch_offset, handle_scratch_len) = (args[0], args[1]); - let (store_offset, store_len) = (args[2], args[3]); - let (output_store_offset, output_store_len) = (args[4], args[5]); + let args: &[usize; 8] = args.try_into().unwrap(); + let opcode = FixOp::try_from(args[0]).expect("Failed to parse opcode"); + let (handle_scratch_offset, handle_scratch_len) = (args[2], args[3]); + let (store_offset, store_len) = (args[4], args[5]); + let (output_store_offset, output_store_len) = (args[6], args[7]); let mut handle_scratch: Box<[u8]> = ObjectStore::from_raw_parts(handle_scratch_offset, handle_scratch_len); @@ -47,7 +52,22 @@ async fn main(args: &[usize]) { store.load(input_store); let mut runtime = FixRuntime::new(&mut store, COUPON); - let eval_coupon = eval(&mut runtime, input_handle); + let result = match opcode { + FixOp::Eval => eval(&mut runtime, input_handle), + FixOp::Apply => runtime.execute(&input_handle), + FixOp::Trade => { + let trade_type = CouponTrades::try_from(args[1]).expect("Failed to parse coupon trade"); + + let input_tree = runtime + .get_tree(&input_handle) + .expect("Input handle is not a tree"); + let coupons = FixRuntime::<'_>::get_tree_entry(&input_tree, 0); + let lhs = FixRuntime::<'_>::get_tree_entry(&input_tree, 1); + let rhs = FixRuntime::<'_>::get_tree_entry(&input_tree, 2); + + runtime.trade(trade_type, coupons, lhs, rhs) + } + }; let output_store_slice: &mut [usize; 2] = output_store .as_mut() @@ -56,5 +76,5 @@ async fn main(args: &[usize]) { let (output_store_offset, output_store_len) = ObjectStore::into_raw_parts(store.unload()); output_store_slice[0] = output_store_offset; output_store_slice[1] = output_store_len; - handle_slice.copy_from_slice(&eval_coupon.pack()); + handle_slice.copy_from_slice(&result.pack()); } diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 2053a33..c5b26b2 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -193,8 +193,12 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc let args = &[regs.rdi, regs.rsi, regs.rcx, regs.r10, regs.r8, regs.r9]; match code { hypercall::EXIT => { - return; - // ExitCode::from(args[0] as u8).exit_process(); + let code = args[0] as u8; + if code == 0 { + return; + } else { + ExitCode::from(args[0] as u8).exit_process(); + } } hypercall::LOG => { let record: *const common::LogRecord = From a1a306003fbaca490c47ac034cfe966621d9d070 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 15:22:48 -0700 Subject: [PATCH 08/12] fix: handle empty data properly --- .github/workflows/compile.yml | 4 ++- fix/evaluator/src/fixruntime.rs | 10 ++----- fix/evaluator/src/main.rs | 14 +++++++-- fix/evaluator/src/vmmruntime.rs | 50 ++++++++++++++++++--------------- fix/runtime/src/common.rs | 8 +++--- fix/runtime/src/storage.rs | 12 +++++--- 6 files changed, 56 insertions(+), 42 deletions(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index bebd6ad..2935dee 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -64,4 +64,6 @@ jobs: - name: Test Fix run: | sudo -su $USER /home/runner/.cargo/bin/cargo build -p fix --target=x86_64-unknown-none - sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- $(find . -name "addblob" | tail -n 1) target/x86_64-unknown-none/debug/fix + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) eval + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) apply + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) trade diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index 703218c..57f18a9 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -96,15 +96,9 @@ pub trait Operator { rhs: FixHandle, ) -> FixHandle; - fn eval ( - &mut self, - handle: FixHandle - ) -> FixHandle; + fn eval(&mut self, handle: FixHandle) -> FixHandle; - fn apply ( - &mut self, - handle: FixHandle - ) -> FixHandle; + fn apply(&mut self, handle: FixHandle) -> FixHandle; } #[allow(unused)] diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index a8086e2..0909946 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -2,8 +2,8 @@ #![feature(ptr_metadata)] #![feature(result_option_map_or_default)] -use crate::vmcommon::CouponTrades; use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; +use crate::vmcommon::CouponTrades; use common::bitpack::BitPack; use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; use std::path::PathBuf; @@ -100,7 +100,15 @@ fn test_trade(smp: usize, cid: usize, bin: Arc<[u8]>) { let scratch = Vec::with_capacity(0); let coupons = rt.create_tree(scratch.as_slice()); - rt.trade(CouponTrades::EvalBlobObj, coupons, addend, addend); + let result = rt.trade(CouponTrades::EvalBlobObj, coupons, addend, addend); + rt.show_coupon(&result); + + let result_blob = rt.get_coupon_rhs(&result); + let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); + let mut arr = [0u8; 8]; + arr.copy_from_slice(result_blob); + let num = u64::from_le_bytes(arr); + assert_eq!(num, 3); } fn main() -> anyhow::Result<()> { @@ -119,7 +127,7 @@ fn main() -> anyhow::Result<()> { "eval" => test_eval(smp, cid, bin, module.as_slice()), "trade" => test_trade(smp, cid, bin), "apply" => test_apply(smp, cid, bin, module.as_slice()), - _ => panic!("Unknown test") + _ => panic!("Unknown test"), } Ok(()) diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index e08b95b..772d8a7 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -8,7 +8,7 @@ use fixhandle::rawhandle::{BlobName, FixHandle, Handle, Object, PhysicalHandle, use vmm::runtime::Runtime; use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; -use crate::vmcommon::{FixOp, CouponTrades}; +use crate::vmcommon::{CouponTrades, FixOp}; pub struct VmmRuntime { runtime: Runtime, @@ -94,15 +94,23 @@ impl VmmRuntime { fn into_raw_parts(input: Box<[T], BuddyAllocator>) -> (usize, usize) { let (data, _) = Box::into_raw_with_allocator(input); let len = ptr::metadata(data); - let offset = BuddyAllocator.to_offset(data); + let offset = if len > 0 { + BuddyAllocator.to_offset(data) + } else { + 0 + }; (offset, len) } fn from_raw_parts(offset: usize, len: usize) -> Box<[T], BuddyAllocator> { - let data = BuddyAllocator.from_offset(offset); - unsafe { - let slice = slice::from_raw_parts_mut(data, len); - Box::from_raw_in(slice, BuddyAllocator) + if len == 0 { + Vec::with_capacity_in(0, BuddyAllocator).into_boxed_slice() + } else { + let data = BuddyAllocator.from_offset(offset); + unsafe { + let slice = slice::from_raw_parts_mut(data, len); + Box::from_raw_in(slice, BuddyAllocator) + } } } @@ -124,7 +132,12 @@ impl VmmRuntime { } } - fn run(&mut self, opcode: FixOp, coupon_trade: Option, handle: FixHandle) -> FixHandle { + fn run( + &mut self, + opcode: FixOp, + coupon_trade: Option, + handle: FixHandle, + ) -> FixHandle { let handle_scratch: Box<[u8], _> = Box::new_in(handle.pack(), BuddyAllocator); let output_store: Box<[usize], _> = Box::new_in([0; 2], BuddyAllocator); @@ -168,20 +181,17 @@ impl VmmRuntime { impl CouponHelper for VmmRuntime {} impl Operator for VmmRuntime { - fn eval ( - &mut self, - handle: FixHandle - ) -> FixHandle { + fn eval(&mut self, handle: FixHandle) -> FixHandle { self.run(FixOp::Eval, None, handle) } fn trade( - &mut self, - trade_type: CouponTrades, - coupons: FixHandle, - lhs: FixHandle, - rhs: FixHandle, - ) -> FixHandle { + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle { let mut scratch = Vec::with_capacity(3 * 32); scratch.extend_from_slice(&coupons.pack()); scratch.extend_from_slice(&lhs.pack()); @@ -191,11 +201,7 @@ impl Operator for VmmRuntime { self.run(FixOp::Trade, Some(trade_type), scratch) } - fn apply ( - &mut self, - handle: FixHandle - ) -> FixHandle { + fn apply(&mut self, handle: FixHandle) -> FixHandle { self.run(FixOp::Apply, None, handle) } - } diff --git a/fix/runtime/src/common.rs b/fix/runtime/src/common.rs index 4589cd1..e5932d5 100644 --- a/fix/runtime/src/common.rs +++ b/fix/runtime/src/common.rs @@ -18,7 +18,7 @@ pub enum CouponTrades { impl TryFrom for CouponTrades { type Error = (); - + fn try_from(value: usize) -> Result { match value { 0 => Ok(CouponTrades::EqTree), @@ -34,7 +34,7 @@ impl TryFrom for CouponTrades { 10 => Ok(CouponTrades::EqSym), 11 => Ok(CouponTrades::EqTrans), 12 => Ok(CouponTrades::EqSelf), - _ => Err(()) + _ => Err(()), } } } @@ -49,13 +49,13 @@ pub enum FixOp { impl TryFrom for FixOp { type Error = (); - + fn try_from(value: usize) -> Result { match value { 0 => Ok(FixOp::Eval), 1 => Ok(FixOp::Trade), 2 => Ok(FixOp::Apply), - _ => Err(()) + _ => Err(()), } } } diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index 4db1a64..4ab5026 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -115,10 +115,14 @@ impl ObjectStore { } pub fn from_raw_parts(offset: usize, len: usize) -> Box<[T]> { - let data = BuddyAllocator.from_offset(offset); - unsafe { - let slice = slice::from_raw_parts_mut(data, len); - Box::from_raw(slice) + if len == 0 { + Vec::with_capacity(0).into_boxed_slice() + } else { + let data = BuddyAllocator.from_offset(offset); + unsafe { + let slice = slice::from_raw_parts_mut(data, len); + Box::from_raw(slice) + } } } From 41189a8236f50a200ce2abcae3fd56ad5397b203 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 19:00:53 -0700 Subject: [PATCH 09/12] feat: literal handle --- fix/evaluator/src/fixruntime.rs | 2 +- fix/evaluator/src/vmmruntime.rs | 27 +++++--- fix/handle/src/rawhandle.rs | 118 ++++++++++++++++++++++++++++---- fix/runtime/src/storage.rs | 1 + fix/shell/src/shell.rs | 54 +++++++-------- 5 files changed, 148 insertions(+), 54 deletions(-) diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index 57f18a9..d1d0dca 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -16,7 +16,7 @@ pub trait DeterministicEquivRuntime { fn create_blob(&mut self, data: &[u8]) -> Self::Handle; fn create_tree(&mut self, data: &[u8]) -> Self::Handle; - fn get_blob(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result<&'a [u8], Self::Error>; fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; } diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index 772d8a7..a95ee1f 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -4,7 +4,9 @@ use std::{mem, ptr}; use common::BuddyAllocator; use common::bitpack::BitPack; -use fixhandle::rawhandle::{BlobName, FixHandle, Handle, Object, PhysicalHandle, TreeName}; +use fixhandle::rawhandle::{ + BlobName, FixHandle, Handle, LiteralHandle, Object, PhysicalHandle, TreeName, +}; use vmm::runtime::Runtime; use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; @@ -57,9 +59,14 @@ impl DeterministicEquivRuntime for VmmRuntime { fn create_blob(&mut self, data: &[u8]) -> FixHandle { let len = data.len(); - let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); - let blob = BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); - Object::from(blob).into() + if len <= 30 { + let literal = LiteralHandle::new(data); + Object::from(BlobName::Literal(literal)).into() + } else { + let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); + let blob = BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); + Object::from(blob).into() + } } fn create_tree(&mut self, data: &[u8]) -> FixHandle { @@ -69,15 +76,19 @@ impl DeterministicEquivRuntime for VmmRuntime { Object::from(tree).into() } - fn get_blob(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error> { + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result<&'a [u8], Self::Error> { let b = handle .try_unwrap_object_ref() .map_err(|_| ())? .try_unwrap_blob_obj_ref() - .map_err(|_| ())? - .unwrap_blob(); - Ok(self.get_by_handle(b)) + .map_err(|_| ())?; + + match b { + BlobName::Blob(h) => Ok(self.get_by_handle(*h)), + BlobName::Literal(l) => Ok(l.content()), + } } + fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error> { let t = handle .try_unwrap_object_ref() diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index 289676c..bd5f4f1 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -199,6 +199,52 @@ impl BitPack for CanonicalHandle { } } +#[derive(Debug, Clone, Copy)] +pub struct LiteralHandle { + inner: RawHandle, +} + +impl LiteralHandle { + pub fn new(content: &[u8]) -> Self { + assert!(content.len() <= 30); + + let mut field = [0u8; 32]; + field[..content.len()].copy_from_slice(content); + field[30] = content.len().try_into().expect("size larger than 30"); + let inner = RawHandle::new(field); + Self { inner } + } + + pub fn len(&self) -> usize { + self.inner.content[30] as usize + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn content(&self) -> &[u8] { + let len = self.len(); + &self.inner.content[..len] + } +} + +impl BitPack for LiteralHandle { + const TAGBITS: u32 = 245; + + fn unpack(mut content: [u8; 32]) -> Self { + content[30] &= 0b00011111; + content[31] = 0; + let inner = RawHandle::new(content); + Self { inner } + } + + fn pack(&self) -> [u8; 32] { + self.inner.content + } +} + #[derive(BitPack, Debug, Clone, Copy, From, TryUnwrap)] pub enum Handle { VirtualHandle(VirtualHandle), @@ -211,6 +257,7 @@ pub enum Handle { #[try_unwrap(ref)] pub enum BlobName { Blob(Handle), + Literal(LiteralHandle), } #[derive(BitPack, Debug, Unwrap, Clone, Copy)] @@ -301,13 +348,13 @@ mod tests { #[test] fn test_tag_bits() { assert_eq!(Handle::TAGBITS, 242); - assert_eq!(BlobName::TAGBITS, 242); + assert_eq!(BlobName::TAGBITS, 246); assert_eq!(TreeName::TAGBITS, 243); - assert_eq!(Object::TAGBITS, 244); - assert_eq!(Ref::TAGBITS, 244); - assert_eq!(Thunk::TAGBITS, 246); - assert_eq!(Encode::TAGBITS, 247); - assert_eq!(FixHandle::TAGBITS, 249); + assert_eq!(Object::TAGBITS, 247); + assert_eq!(Ref::TAGBITS, 247); + assert_eq!(Thunk::TAGBITS, 249); + assert_eq!(Encode::TAGBITS, 250); + assert_eq!(FixHandle::TAGBITS, 252); } #[test] @@ -321,14 +368,40 @@ mod tests { assert_eq!(TreeName::TAGMASK.as_array::<32>().unwrap()[30], 0b00000100); assert_eq!(TreeName::TAGMASK.as_array::<32>().unwrap()[31], 0b00000000); - assert_eq!(Thunk::TAGMASK.as_array::<32>().unwrap()[30], 0b00110000); - assert_eq!(Thunk::TAGMASK.as_array::<32>().unwrap()[31], 0b00000000); + assert_eq!(BlobName::TAGMASK.as_array::<32>().unwrap()[30], 0b00100000); + assert_eq!(BlobName::TAGMASK.as_array::<32>().unwrap()[31], 0b00000000); + + assert_eq!(Thunk::TAGMASK.as_array::<32>().unwrap()[30], 0b10000000); + assert_eq!(Thunk::TAGMASK.as_array::<32>().unwrap()[31], 0b00000001); - assert_eq!(Encode::TAGMASK.as_array::<32>().unwrap()[30], 0b01000000); - assert_eq!(Encode::TAGMASK.as_array::<32>().unwrap()[31], 0b00000000); + assert_eq!(Encode::TAGMASK.as_array::<32>().unwrap()[30], 0b00000000); + assert_eq!(Encode::TAGMASK.as_array::<32>().unwrap()[31], 0b00000010); - assert_eq!(FixHandle::TAGMASK.as_array::<32>().unwrap()[30], 0b10000000); - assert_eq!(FixHandle::TAGMASK.as_array::<32>().unwrap()[31], 0b00000001); + assert_eq!(FixHandle::TAGMASK.as_array::<32>().unwrap()[30], 0b00000000); + assert_eq!(FixHandle::TAGMASK.as_array::<32>().unwrap()[31], 0b00001100); + } + + #[test] + fn test_literal() { + let content: usize = 3; + let content = content.to_le_bytes(); + let literal = LiteralHandle::new(&content); + + assert_eq!(literal.len(), 8); + let content = literal.content(); + let x = usize::from_le_bytes(content.try_into().unwrap()); + assert_eq!(x, 3); + + let handle = FixHandle::Ref(Ref::BlobRef(BlobName::Literal(literal))); + let literal = FixHandle::unpack(handle.pack()) + .unwrap_ref() + .unwrap_blob_ref() + .unwrap_literal(); + + assert_eq!(literal.len(), 8); + let content = literal.content(); + let x = usize::from_le_bytes(content.try_into().unwrap()); + assert_eq!(x, 3); } #[test] @@ -348,14 +421,14 @@ mod tests { ))); let res = h.pack(); let field: &u16x16 = unsafe { core::mem::transmute(&res) }; - assert_eq!(field[15], 0b0000000001100001); + assert_eq!(field[15], 0b0000001100000001); let h: FixHandle = FixHandle::Encode(Encode::Shallow(Thunk::Selection(TreeName::NotTag( PhysicalHandle::new(42, 10086).into(), )))); let res = h.pack(); let field: &u16x16 = unsafe { core::mem::transmute(&res) }; - assert_eq!(field[15], 0b0000000111100001); + assert_eq!(field[15], 0b0000111100000001); } #[test] @@ -379,6 +452,23 @@ mod tests { .try_unwrap_physical_handle() .expect("Failed to unwrap to PhysicalHandle"); + let h: FixHandle = FixHandle::Object(Object::TreeObj(TreeName::NotTag( + PhysicalHandle::new(42, 10086).into(), + ))); + let new_h = FixHandle::unpack(h.pack()); + assert_eq!( + new_h + .try_unwrap_object() + .unwrap() + .try_unwrap_tree_obj() + .unwrap() + .unwrap_not_tag() + .try_unwrap_physical_handle() + .unwrap() + .local_id(), + 42 + ); + assert_eq!(res.local_id(), 42); assert_eq!(res.len(), 10086); } diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index 4ab5026..178e1de 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -84,6 +84,7 @@ impl Storage for ObjectStore { .try_into() .unwrap(), }, + BlobName::Literal(h) => Blob::new(h.content()), } } diff --git a/fix/shell/src/shell.rs b/fix/shell/src/shell.rs index a5fef3d..e4dceb7 100644 --- a/fix/shell/src/shell.rs +++ b/fix/shell/src/shell.rs @@ -11,8 +11,8 @@ use arcane::{ use core::arch::x86_64::*; use core::ffi::c_void; use fixhandle::rawhandle::{ - BitPack, Encode, FixHandle, Handle, Object, Thunk, TreeName, create_application_thunk, - create_strict_encode, + BitPack, BlobName, Encode, FixHandle, Handle, LiteralHandle, Object, Thunk, TreeName, + create_application_thunk, create_strict_encode, }; use user::ArcaError; use user::Ref; @@ -35,25 +35,15 @@ impl DeterministicEquivRuntime for FixShellPhysical { type Error = ArcaError; fn create_blob_i32(data: u32) -> Self::Handle { - let result: Blob = Function::symbolic("create_blob_i32") - .apply(data) - .call_with_current_continuation() - .try_into() - .expect("create_blob_i32 failed"); - let mut buf = [0u8; 32]; - Runtime::read_blob(&result, 0, &mut buf); - buf + let literal = LiteralHandle::new(&data.to_le_bytes()); + let handle: FixHandle = Object::from(BlobName::from(literal)).into(); + handle.pack() } fn create_blob_i64(data: u64) -> Self::Handle { - let result: Blob = Function::symbolic("create_blob_i64") - .apply(data) - .call_with_current_continuation() - .try_into() - .expect("create_blob_i64 failed"); - let mut buf = [0u8; 32]; - Runtime::read_blob(&result, 0, &mut buf); - buf + let literal = LiteralHandle::new(&data.to_le_bytes()); + let handle: FixHandle = Object::from(BlobName::from(literal)).into(); + handle.pack() } fn create_blob(data: Self::BlobData) -> Self::Handle { @@ -207,22 +197,24 @@ impl DeterministicEquivRuntime for FixShellPhysical { fn len(handle: Self::Handle) -> usize { let handle = FixHandle::unpack(handle); + let len = |h: &Handle| match h { + Handle::VirtualHandle(virtual_handle) => virtual_handle.len(), + Handle::PhysicalHandle(physical_handle) => physical_handle.len(), + Handle::CanonicalHandle(canonical_handle) => canonical_handle.len(), + }; + let len = handle .try_unwrap_object_ref() .map_err(|_| ArcaError::BadType) - .map(|h| { - let h: &Handle = match h { - fixhandle::rawhandle::Object::BlobObj(blob_name) => blob_name.unwrap_blob_ref(), - fixhandle::rawhandle::Object::TreeObj(tree_name) => match tree_name { - fixhandle::rawhandle::TreeName::NotTag(handle) => handle, - fixhandle::rawhandle::TreeName::Tag(handle) => handle, - }, - }; - match h { - Handle::VirtualHandle(virtual_handle) => virtual_handle.len(), - Handle::PhysicalHandle(physical_handle) => physical_handle.len(), - Handle::CanonicalHandle(canonical_handle) => canonical_handle.len(), - } + .map(|h| match h { + fixhandle::rawhandle::Object::BlobObj(blob_name) => match blob_name { + fixhandle::rawhandle::BlobName::Blob(handle) => len(handle), + fixhandle::rawhandle::BlobName::Literal(literal) => literal.len(), + }, + fixhandle::rawhandle::Object::TreeObj(tree_name) => match tree_name { + fixhandle::rawhandle::TreeName::NotTag(handle) => len(handle), + fixhandle::rawhandle::TreeName::Tag(handle) => len(handle), + }, }); len.expect("len: failed to get size") } From 6e2dbd6a23b064c53446145a77021b2acd866240 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 13 May 2026 19:48:07 -0700 Subject: [PATCH 10/12] feat: better formatting --- fix/evaluator/src/main.rs | 2 -- fix/handle/src/rawhandle.rs | 47 ++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 0909946..1675ed6 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -63,7 +63,6 @@ fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { let mut arr = [0u8; 8]; arr.copy_from_slice(result_blob); let num = u64::from_le_bytes(arr); - log::info!("{:?}", num); assert_eq!(num, 1031); } @@ -89,7 +88,6 @@ fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { let mut arr = [0u8; 8]; arr.copy_from_slice(result_blob); let num = u64::from_le_bytes(arr); - log::info!("{:?}", num); assert_eq!(num, 7); } diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index bd5f4f1..a7a20ee 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -1,5 +1,6 @@ #![allow(clippy::double_parens)] pub use common::bitpack::BitPack; +use core::fmt; use derive_more::{From, TryInto, TryUnwrap, Unwrap}; #[derive(Copy, Clone, Debug)] @@ -120,7 +121,7 @@ impl VirtualHandle { } } -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub struct PhysicalHandle { inner: MachineHandle, } @@ -157,7 +158,13 @@ impl PhysicalHandle { } } -#[derive(Debug, Clone, Copy)] +impl fmt::Debug for PhysicalHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "local_id: {}", self.local_id()) + } +} + +#[derive(Clone, Copy)] pub struct CanonicalHandle { inner: RawHandle, } @@ -184,6 +191,18 @@ impl CanonicalHandle { } } +impl fmt::Debug for CanonicalHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x")?; + + for i in self.inner.content.iter() { + write!(f, "{:02x}", i)?; + } + + Ok(()) + } +} + impl BitPack for CanonicalHandle { const TAGBITS: u32 = 240; @@ -199,7 +218,7 @@ impl BitPack for CanonicalHandle { } } -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub struct LiteralHandle { inner: RawHandle, } @@ -230,6 +249,28 @@ impl LiteralHandle { } } +impl fmt::Debug for LiteralHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let content = self.content(); + + if content.len() == 8 { + let data = u64::from_le_bytes(content.try_into().unwrap()); + write!(f, "0d{}", data)?; + } else if content.len() == 4 { + let data = u32::from_le_bytes(content.try_into().unwrap()); + write!(f, "0d{}", data)?; + } else { + write!(f, "[")?; + for i in content.iter() { + write!(f, "0d{}, ", i)?; + } + write!(f, "]")?; + } + + Ok(()) + } +} + impl BitPack for LiteralHandle { const TAGBITS: u32 = 245; From d35ecad71da7d8c02d2a1d888f5e1b85a28f5495 Mon Sep 17 00:00:00 2001 From: Haibib Kerim <134754041+Haibib@users.noreply.github.com> Date: Wed, 20 May 2026 15:44:44 -0700 Subject: [PATCH 11/12] Fix evaluator (#29) ### PR Description - Added a fake runtime that does naive addition applications - Added a front-end for the CLI that can read and parse commands to send to the backend runtime (fake, real, or other future runtimes). ### Usage fix-cli -- -- fix-cli -- --path ### Examples - cargo run -p evaluator --bin fix-cli fake --path fix/evaluator/add_script.txt - cargo run -p evaluator --bin fix-cli fake -- "print(getBlob(apply(makeTree(makeBlob(+), makeBlobInt(1), apply(makeTree(makeBlob(+), makeBlobInt(2), makeBlobInt(3)))))))" --------- Co-authored-by: Haibib Kerim Co-authored-by: Yuhan Deng --- .github/workflows/compile.yml | 6 +- .gitignore | 1 + Cargo.lock | 1296 +++++++++++++++++++-------- Cargo.toml | 4 +- fix/.cargo/config.toml | 8 + fix/Cargo.toml | 1 + fix/build.rs | 9 +- fix/evaluator/Cargo.toml | 12 + fix/evaluator/README.md | 28 + fix/evaluator/add.txt | 1 + fix/evaluator/apply_script.txt | 7 + fix/evaluator/eval_script.txt | 9 + fix/evaluator/src/bin/cli.rs | 443 +++++++++ fix/evaluator/src/fixruntime.rs | 132 ++- fix/evaluator/src/hybridruntime.rs | 187 ++++ fix/evaluator/src/lexer.rs | 94 ++ fix/evaluator/src/lib.rs | 14 + fix/evaluator/src/main.rs | 19 +- fix/evaluator/src/memoryruntime.rs | 98 ++ fix/evaluator/src/mockruntime.rs | 143 +++ fix/evaluator/src/parser.rs | 131 +++ fix/evaluator/src/storageruntime.rs | 192 ++++ fix/evaluator/src/vmmruntime.rs | 155 +++- fix/evaluator/trade_script.txt | 5 + fix/handle/src/rawhandle.rs | 7 + fix/runtime/Cargo.toml | 2 + fix/runtime/src/bottom.rs | 14 +- fix/runtime/src/common.rs | 23 + fix/runtime/src/fixruntime.rs | 185 +++- fix/runtime/src/runtime.rs | 120 +-- fix/runtime/src/storage.rs | 162 ++-- fix/src/evaluator.rs | 25 +- fix/src/main.rs | 30 +- kernel/src/kvmclock.rs | 1 + 34 files changed, 2921 insertions(+), 643 deletions(-) create mode 100644 fix/.cargo/config.toml create mode 100644 fix/evaluator/README.md create mode 100644 fix/evaluator/add.txt create mode 100644 fix/evaluator/apply_script.txt create mode 100644 fix/evaluator/eval_script.txt create mode 100644 fix/evaluator/src/bin/cli.rs create mode 100644 fix/evaluator/src/hybridruntime.rs create mode 100644 fix/evaluator/src/lexer.rs create mode 100644 fix/evaluator/src/lib.rs create mode 100644 fix/evaluator/src/memoryruntime.rs create mode 100644 fix/evaluator/src/mockruntime.rs create mode 100644 fix/evaluator/src/parser.rs create mode 100644 fix/evaluator/src/storageruntime.rs create mode 100644 fix/evaluator/trade_script.txt diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 2935dee..df01ff8 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -64,6 +64,6 @@ jobs: - name: Test Fix run: | sudo -su $USER /home/runner/.cargo/bin/cargo build -p fix --target=x86_64-unknown-none - sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) eval - sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) apply - sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) trade + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator --bin evaluator -- target/x86_64-unknown-none/debug/fix target/x86_64-unknown-none/addblob eval + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator --bin evaluator -- target/x86_64-unknown-none/debug/fix target/x86_64-unknown-none/addblob apply + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator --bin evaluator -- target/x86_64-unknown-none/debug/fix target/x86_64-unknown-none/addblob trade diff --git a/.gitignore b/.gitignore index 43f4569..e7aa5ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target .build +.fix diff --git a/Cargo.lock b/Cargo.lock index 092efad..3f8d3da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -17,21 +29,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse 0.2.7", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - [[package]] name = "anstream" version = "1.0.0" @@ -39,7 +36,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", - "anstyle-parse 1.0.0", + "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -49,18 +46,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" @@ -77,7 +65,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -88,20 +76,20 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "ar_archive_writer" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" dependencies = [ "object", ] @@ -120,9 +108,21 @@ version = "0.1.0" dependencies = [ "autotools", "bindgen", - "derive_more", + "derive_more 2.1.1", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-channel" version = "2.5.0" @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -175,7 +175,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", @@ -233,7 +233,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -278,7 +278,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "cexpr", "clang-sys", "itertools", @@ -322,9 +322,41 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] name = "block2" @@ -348,11 +380,37 @@ dependencies = [ "piper", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "byteorder" @@ -362,15 +420,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.57" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "shlex", @@ -399,9 +457,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "num-traits", "serde", @@ -434,9 +492,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -444,11 +502,11 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "anstream 0.6.21", + "anstream", "anstyle", "clap_lex", "strsim", @@ -456,9 +514,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -468,15 +526,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -492,9 +550,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "common" @@ -503,13 +561,13 @@ dependencies = [ "arca", "async-channel", "async-lock", - "derive_more", + "derive_more 2.1.1", "elf", "hashbrown 0.15.5", "libc", "log", "macros", - "nix", + "nix 0.30.1", "rand", "snafu", ] @@ -523,6 +581,39 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.10.0" @@ -543,6 +634,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "critical-section" version = "1.2.0" @@ -555,33 +655,117 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctrlc" -version = "3.5.1" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ "dispatch2", - "nix", - "windows-sys 0.61.2", + "nix 0.31.3", + "windows-sys", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", ] [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + [[package]] name = "derive_more" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "derive_more-impl", + "derive_more-impl 2.1.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -590,7 +774,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", + "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", @@ -598,13 +782,24 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "dispatch2" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "block2", "libc", "objc2", @@ -612,9 +807,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "elevate" @@ -644,6 +839,26 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_filter" version = "1.0.1" @@ -660,7 +875,7 @@ version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ - "anstream 1.0.0", + "anstream", "anstyle", "env_filter", "jiff", @@ -680,7 +895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -688,11 +903,15 @@ name = "evaluator" version = "0.1.0" dependencies = [ "anyhow", + "blake3", "bytemuck", "clap", "common", "env_logger", "fixhandle", + "hashbrown 0.17.1", + "hex", + "io", "log", "vmm", ] @@ -720,9 +939,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" @@ -741,12 +960,13 @@ dependencies = [ "autotools", "bindgen", "bitfield-struct 0.11.0", + "blake3", "bytemuck", "cc", "chrono", "cmake", "common", - "derive_more", + "derive_more 2.1.1", "fixhandle", "fixruntime", "fixshell", @@ -762,12 +982,22 @@ dependencies = [ "user", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixhandle" version = "0.1.0" dependencies = [ "common", - "derive_more", + "derive_more 2.1.1", ] [[package]] @@ -778,13 +1008,15 @@ dependencies = [ "arcane", "async-lock", "bitfield-struct 0.11.0", + "blake3", "bytemuck", "chrono", "chumsky", "common", - "derive_more", + "derive_more 2.1.1", "fixhandle", "futures", + "hashbrown 0.17.1", "kernel", "log", "macros", @@ -808,17 +1040,29 @@ dependencies = [ "user", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -831,9 +1075,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -841,15 +1085,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -858,9 +1102,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -877,9 +1121,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -888,21 +1132,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -912,10 +1156,87 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] +[[package]] +name = "galloc" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d95f9357f55c811d9b1f5c7bb1ef3b3f0094dee912a2bdb5155eb46611d8f87" +dependencies = [ + "gear-dlmalloc", +] + +[[package]] +name = "gcore" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015093eb24aa69f98f6474a9547a51a1a9230204e55a1778e9c8588cd8ee6047" +dependencies = [ + "arrayvec", + "gear-core-errors", + "gear-stack-buffer", + "gprimitives", + "gsys", + "paste", + "thiserror", +] + +[[package]] +name = "gear-core-errors" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a068b7e99afbedd710b959a20c8ac91b2cc77f8a0ce87af687b673bfbf26a809" +dependencies = [ + "enum-iterator", + "parity-scale-codec", + "scale-decode", + "scale-encode", + "scale-info", + "thiserror", +] + +[[package]] +name = "gear-dlmalloc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b88fcd5524e7ab9f156c17b14e754d6ba122ef9b00586d632d2ae3dbc7bfadb" +dependencies = [ + "libc", + "libc-print", + "page_size", + "static_assertions", + "str-buf", +] + +[[package]] +name = "gear-ss58" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94745919b16a98a5b8d7b7766bcb9127eb8bf013eff098ad828e452744bee6e6" +dependencies = [ + "blake2", + "bs58", + "hex", +] + +[[package]] +name = "gear-stack-buffer" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d30f39766a97c23c841c55e868d93e01e146ace585aa36b291b4c46b9d0c15" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -934,6 +1255,78 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gmeta" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dfc9f5f43c94987a4185104fdb969485bc023a4a570321b2f007ce61c2f9eda" +dependencies = [ + "blake2", + "derive_more 0.99.20", + "hex", + "scale-info", +] + +[[package]] +name = "gprimitives" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f79911d3caeb051ae07b0d4b57c196fdc6e105f7be7cc51365416d7248ca5ce" +dependencies = [ + "bytemuck", + "derive_more 2.1.1", + "gear-ss58", + "hex", + "primitive-types 0.12.2", + "scale-decode", + "scale-encode", + "scale-info", + "thiserror", +] + +[[package]] +name = "gstd" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232fec5b812a76c016c11faceef031fbe7608bb4db07051744201a2dabff1072" +dependencies = [ + "arrayvec", + "const_format", + "futures", + "galloc", + "gcore", + "gear-core-errors", + "gprimitives", + "gstd-codegen", + "hashbrown 0.14.5", + "hex", + "parity-scale-codec", + "scale-info", + "thiserror", + "waker-fn", +] + +[[package]] +name = "gstd-codegen" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b347d845d9fdc17b47288d082fd7001390d0652acb5d221c29a1b3f16e9a238" +dependencies = [ + "gprimitives", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "gsys" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b08a4ef9c0f6aed528b42117cea34f53af2a4a7f080c04b4356eb63adc9302" +dependencies = [ + "bytemuck", +] + [[package]] name = "hash32" version = "0.2.1" @@ -943,6 +1336,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -951,16 +1354,23 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] [[package]] name = "heapless" @@ -988,6 +1398,38 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "include_directory" version = "0.1.1" @@ -1011,13 +1453,25 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "2.13.0" +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "io" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "aba460b987a14c5de30128ae8c1fb69f60b622b71317dd4f6e187722f09550c1" dependencies = [ - "equivalent", - "hashbrown 0.16.1", + "gmeta", + "gstd", + "parity-scale-codec", + "scale-info", ] [[package]] @@ -1082,6 +1536,21 @@ dependencies = [ "time", ] +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "kvm-bindings" version = "0.13.0" @@ -1097,7 +1566,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e00243d27a20feb05cf001ae52ddc79831ac70c020f215ba1153ff9270b650a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "kvm-bindings", "libc", "vmm-sys-util", @@ -1105,9 +1574,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.180" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libc-print" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "a4a660208db49e35faf57b37484350f1a61072f2a5becf0592af6015d9ddd4b0" +dependencies = [ + "libc", +] [[package]] name = "libloading" @@ -1121,9 +1599,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "lock_api" @@ -1152,9 +1630,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -1179,13 +1657,13 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1204,7 +1682,20 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -1223,9 +1714,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-traits" @@ -1254,9 +1745,9 @@ checksum = "9a6da8d50bd4f4b2e9788c44714a3fa4e465d33fd6a6ad70991db6eb30807dca" [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] @@ -1269,19 +1760,61 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "object" -version = "0.32.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parking" version = "2.2.1" @@ -1289,22 +1822,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "piper" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", "fastrand", @@ -1322,20 +1855,20 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -1378,29 +1911,51 @@ dependencies = [ "syn", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "scale-info", + "uint 0.9.5", +] + +[[package]] +name = "primitive-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" +dependencies = [ + "fixed-hash", + "uint 0.10.0", +] + [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" dependencies = [ "ar_archive_writer", "cc", @@ -1408,9 +1963,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1423,9 +1978,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", @@ -1458,8 +2013,8 @@ checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.13", - "regex-syntax 0.8.8", + "regex-automata 0.4.14", + "regex-syntax 0.8.10", ] [[package]] @@ -1475,13 +2030,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.8", + "regex-syntax 0.8.10", ] [[package]] @@ -1492,9 +2047,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rlimit" @@ -1513,9 +2068,15 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustc-std-workspace-alloc" @@ -1540,15 +2101,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1557,6 +2118,104 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "scale-bits" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27243ab0d2d6235072b017839c5f0cd1a3b1ce45c0f7a715363b0c7d36c76c94" +dependencies = [ + "parity-scale-codec", + "scale-type-resolver", +] + +[[package]] +name = "scale-decode" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6ed61699ad4d54101ab5a817169259b5b0efc08152f8632e61482d8a27ca3d" +dependencies = [ + "parity-scale-codec", + "primitive-types 0.13.1", + "scale-bits", + "scale-decode-derive", + "scale-type-resolver", + "smallvec", + "thiserror", +] + +[[package]] +name = "scale-decode-derive" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cb245f7fdb489e7ba43a616cbd34427fe3ba6fe0edc1d0d250085e6c84f3ec" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scale-encode" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a976d73564a59e482b74fd5d95f7518b79ca8c8ca5865398a4d629dd15ee50" +dependencies = [ + "parity-scale-codec", + "primitive-types 0.13.1", + "scale-bits", + "scale-encode-derive", + "scale-type-resolver", + "smallvec", + "thiserror", +] + +[[package]] +name = "scale-encode-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17020f2d59baabf2ddcdc20a4e567f8210baf089b8a8d4785f5fd5e716f92038" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scale-info" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" +dependencies = [ + "cfg-if", + "derive_more 1.0.0", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scale-type-resolver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" +dependencies = [ + "smallvec", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1565,9 +2224,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -1627,9 +2286,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smol" @@ -1671,12 +2336,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -1705,28 +2370,46 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stacker" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" dependencies = [ "cc", "cfg-if", "libc", "psm", - "windows-sys 0.59.0", + "windows-sys", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceb97b7225c713c2fd4db0153cb6b3cab244eb37900c3f634ed4d43310d8c34" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1744,18 +2427,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1768,7 +2451,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2210811179577da3d54eb69ab0b50490ee40491a25d95b8c6011ba40771cb721" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "cfg-if", "libc", "log", @@ -1778,9 +2461,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "num-conv", @@ -1791,15 +2474,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -1807,7 +2490,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1837,18 +2520,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", "toml_datetime", @@ -1858,9 +2541,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] @@ -1876,6 +2559,36 @@ dependencies = [ "syn", ] +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicase" version = "2.9.0" @@ -1884,15 +2597,15 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-xid" @@ -1919,6 +2632,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "vmm" version = "0.1.0" @@ -1940,7 +2659,7 @@ dependencies = [ "kvm-ioctls", "libc", "log", - "nix", + "nix 0.30.1", "regex", "rlimit", "rustc-demangle", @@ -1963,14 +2682,20 @@ dependencies = [ [[package]] name = "vsock" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2da6e4ac76cd19635dce0f98985378bb62f8044ee2ff80abd2a7334b920ed63" +checksum = "6ba782755fc073877e567c2253c0be48e4aa9a254c232d36d3985dfae0bd5205" dependencies = [ "libc", - "nix", + "nix 0.31.3", ] +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1979,9 +2704,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ "wit-bindgen", ] @@ -2116,24 +2841,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -2143,39 +2850,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link 0.2.1", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows-threading" version = "0.1.0" @@ -2185,131 +2859,35 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "zerocopy" -version = "0.8.34" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.34" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 197fa21..3ad6a60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/runtime", "fix/handle", "fix/shell", "fix/evaluator" ] -default-members = [ "common", "vmm", "macros", "arca", "fix/handle", "fix/evaluator" ] +members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/runtime", "fix/handle", "fix/shell", "fix/evaluator"] +default-members = [ "common", "vmm", "macros", "arca", "fix/handle", "fix/evaluator"] resolver = "2" diff --git a/fix/.cargo/config.toml b/fix/.cargo/config.toml new file mode 100644 index 0000000..d1ab66c --- /dev/null +++ b/fix/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.x86_64-unknown-none] +rustflags = [ + "-C", "force-frame-pointers=on", + "-C", "code-model=large", + "-C", "relocation-model=static", + # "-C", "target-feature=+crt-static", +] +runner = "cargo run -p evaluator --bin fix-cli -- hybrid" diff --git a/fix/Cargo.toml b/fix/Cargo.toml index 4df65c9..12bae71 100644 --- a/fix/Cargo.toml +++ b/fix/Cargo.toml @@ -36,6 +36,7 @@ user = { path = "../user", artifact = "bin", target = "x86_64-unknown-none" } async-lock = { version = "3.4.1", default-features = false } bytemuck = "1.24.0" bitfield-struct = "0.11.0" +blake3 = { version = "1.8.5", default-features = false } [build-dependencies] fixshell = { path = "shell", artifact="staticlib", target = "x86_64-unknown-none" } diff --git a/fix/build.rs b/fix/build.rs index dfd523a..c606798 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -1,9 +1,10 @@ -use std::env; use std::fs::create_dir_all; use std::io::ErrorKind; +use std::os::unix::fs::symlink; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::OnceLock; +use std::{env, fs}; use anyhow::{Result, anyhow}; use cmake::Config; @@ -169,7 +170,11 @@ fn main() -> Result<()> { let wasm = wat2wasm(&wat)?; let (c, h) = wasm2c(&wasm)?; let elf = c2elf(&c, &h)?; - std::fs::write(dst, elf)?; + std::fs::write(&dst, elf)?; + + let link = Path::new(&out_dir).ancestors().nth(4).unwrap().join(base); + let _ = fs::remove_file(&link); + symlink(dst, link)?; } let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap(); diff --git a/fix/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 53166a6..4c7c7c1 100644 --- a/fix/evaluator/Cargo.toml +++ b/fix/evaluator/Cargo.toml @@ -4,6 +4,7 @@ cargo-features = ["per-package-target"] name = "evaluator" version = "0.1.0" edition = "2024" +default-run = "evaluator" [dependencies] fixhandle = { path = "../handle" } @@ -14,6 +15,17 @@ env_logger = "0.11.10" log = "0.4.29" common = { path = "../../common" } bytemuck = "1.25.0" +blake3 = "1.8.5" +io = "0.0.2" +hex = "0.4.3" +hashbrown = "0.17.1" [build-dependencies] anyhow = "1.0.97" + +[lib] +path = "src/lib.rs" + +[[bin]] +name = "fix-cli" +path = "src/bin/cli.rs" diff --git a/fix/evaluator/README.md b/fix/evaluator/README.md new file mode 100644 index 0000000..8204019 --- /dev/null +++ b/fix/evaluator/README.md @@ -0,0 +1,28 @@ +### Commands + +| Name | Arguments | Return value | Description | +|---|---|---|---| +| `create_blob` | `Int(num), String("text"), Path("path")` | `handle` | creates blob in the runtime from the given primitive values | +| `create_tree` | `handle, ...` | `handle` | creates a tree from one or more runtime handles | +| `get_blob` | `handle` | `blobData` | fetches blob payload from runtime | +| `get_tree` | `handle` | `treeData` | fetches tree payload from runtime | +| `apply` | `handle` | `handle` | applies the first member to all subsequent members as operands + +Inline comments using `//` + +### Usage + +fix-cli -- -- +fix-cli -- --path + +### Examples + +- cargo run -p evaluator --bin fix-cli hybrid --path fix/evaluator/add_script.txt +- cargo run -p evaluator --bin fix-cli mock -- 'print(get_blob(apply(create_tree(create_blob(String("+")), create_blob(Int(1)), apply(create_tree(create_blob(Path("fix/evaluator/add.txt")), create_blob(Int(2)), create_blob(Int(3))))))))' + +### Runtimes + +- MemoryRuntime: Stores all blobs and trees in memory. Holds ownership so `get_blob()` and `get_tree()` only return references +- StorageRuntime: Writes all blobs and trees to ".fix/objects/". Holds no ownership so `get_blob()` and `get_tree()` return boxed bytes read from ".fix/objects/" +- HybridRuntime: Uses MemoryRuntime but supports "flush" and "flush_handle" operations to recursively write in-memory blobs and trees to ".fix/objects/" +- MockRuntime: Uses memory runtime and does naive addition for applications in `apply()` \ No newline at end of file diff --git a/fix/evaluator/add.txt b/fix/evaluator/add.txt new file mode 100644 index 0000000..9b26e9b --- /dev/null +++ b/fix/evaluator/add.txt @@ -0,0 +1 @@ ++ \ No newline at end of file diff --git a/fix/evaluator/apply_script.txt b/fix/evaluator/apply_script.txt new file mode 100644 index 0000000..245ba1a --- /dev/null +++ b/fix/evaluator/apply_script.txt @@ -0,0 +1,7 @@ +a = create_blob(Int(2)); +b = create_blob(Int(3)); +c = create_blob(Path("../target/x86_64-unknown-none/addblob")); +d = create_tree(c, a, b); +e = apply(d); +show_coupon(e); +e diff --git a/fix/evaluator/eval_script.txt b/fix/evaluator/eval_script.txt new file mode 100644 index 0000000..2a19532 --- /dev/null +++ b/fix/evaluator/eval_script.txt @@ -0,0 +1,9 @@ +a = create_blob(Int(2)); +b = create_blob(Int(3)); +c = create_blob(Path("../target/x86_64-unknown-none/addblob")); +d = create_tree(c, a, b); +e = create_blob(Int(1)); +f = create_strict_encode(create_application_thunk(d)) +g = create_tree(c, e, f); +h = eval(create_strict_encode(create_application_thunk(g))); +h diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs new file mode 100644 index 0000000..057292b --- /dev/null +++ b/fix/evaluator/src/bin/cli.rs @@ -0,0 +1,443 @@ +use common::bitpack::BitPack; +use evaluator::{ + fixruntime::{ + CouponHelper, DeterministicEquivRuntime, ExpandHandle, Expr, Operator, Statement, Value, + }, + hybridruntime::HybridRuntime, + lexer::Lexer, + mockruntime::MockRuntime, + parser::Parser as ExprParser, + vmcommon::CouponTrades, +}; +use fixhandle::rawhandle::{FixHandle, create_application_thunk, create_strict_encode}; +use std::{ + collections::BTreeMap, + env, fmt, fs, + io::{self, Read}, + process, +}; + +use clap::Parser; +use std::path::PathBuf; +use std::sync::Arc; + +#[derive(Parser, Debug)] +#[command( + override_usage = "fix-cli hybrid [--smp ] [--cid ] -- [--path | ]" +)] +struct Args { + kernel: PathBuf, + #[arg(short, long)] + smp: Option, + #[arg(short, long, default_value = "3")] + cid: usize, +} + +fn main() { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + + // Skip executable path + let mut args = env::args().skip(1); + + let runtime_name = match args.next() { + Some(val) => val, + None => { + eprintln!("Error - usage: fix-cli -- | --path "); + process::exit(1); + } + }; + + let (runtime_args, command_args) = split_args(args.collect()); + let result = match runtime_name.as_str() { + "mock" => match read_commands(command_args) { + Ok(commands) => MockRuntime::new().run(&commands), + Err(error) => { + eprintln!("Error - {error}"); + process::exit(1); + } + }, + "hybrid" => { + let runtime_config = Args::parse_from( + std::iter::once(String::from("fix-cli hybrid")).chain(runtime_args), + ); + + let commands = match read_commands(command_args) { + Ok(commands) => commands, + Err(error) => { + eprintln!("Error - {error}"); + process::exit(1); + } + }; + + let smp = runtime_config.smp.unwrap_or(1); + let cid = runtime_config.cid; + + let bin: Arc<[u8]> = match std::fs::read(runtime_config.kernel) { + Ok(bin) => bin.into(), + Err(error) => { + eprintln!("Error - {error}"); + process::exit(1); + } + }; + HybridRuntime::new(smp, cid, bin).run(&commands) + } + // "storage" => run(StorageRuntime::new(), &commands), + other => Err(format!("expected 'mock|hybrid' but got '{other}'")), + }; + + if let Err(error) = result { + eprintln!("Error - {error}"); + process::exit(1); + } +} + +fn split_args(args: Vec) -> (Vec, Vec) { + match args.iter().position(|arg| arg == "--") { + Some(idx) => (args[..idx].to_vec(), args[idx + 1..].to_vec()), + None => (Vec::new(), args), + } +} + +trait Run { + fn run(&mut self, commands: &str) -> Result<(), String> + where + Self: CouponHelper + Operator + ExpandHandle, + ::Error: fmt::Debug, + for<'a> Self::BlobData<'a>: AsRef<[u8]>, + for<'a> Self::TreeData<'a>: AsRef<[u8]>, + { + let (output, output_handle) = Evaluator::new(self).evaluate_commands(commands)?; + println!("{output}"); + if let Some(h) = output_handle { + println!("{h:?}"); + } + Ok(()) + } +} + +impl Run for MockRuntime {} + +impl Run for HybridRuntime { + fn run(&mut self, commands: &str) -> Result<(), String> { + let (output, output_handle) = Evaluator::new(self).evaluate_commands(commands)?; + println!("{output}"); + if let Some(h) = output_handle { + let flushed = self.flush_handle(h).map_err(|e| format!("{e:?}"))?; + let h = flushed; + println!("{h:?}"); + } + Ok(()) + } +} + +fn read_commands(args: Vec) -> Result { + let args: Vec = args.into_iter().filter(|arg| arg != "--").collect(); + + match args.as_slice() { + [flag, path] if flag == "--path" => { + fs::read_to_string(path).map_err(|error| format!("can't read file '{path}': {error}")) + } + [flag, ..] if flag == "--path" => Err(String::from("expected path")), + [] => { + let mut commands = String::new(); + io::stdin() + .read_to_string(&mut commands) + .map_err(|error| error.to_string())?; + Ok(commands) + } + _ => Ok(args.join(" ")), + } +} + +#[derive(Clone)] +struct RuntimeTree { + inner: Vec, +} + +impl fmt::Debug for RuntimeTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let d = self.inner.as_slice(); + let len = HybridRuntime::get_tree_len(d); + write!(f, "[")?; + for i in 0..len { + let e = HybridRuntime::get_tree_entry(d, i); + write!(f, "{e:?}")?; + + if i != len - 1 { + writeln!(f, ",")?; + } else { + write!(f, "]")?; + } + } + Ok(()) + } +} + +impl From> for RuntimeTree { + fn from(value: Vec) -> Self { + Self { inner: value } + } +} + +type RuntimeValue = Value, RuntimeTree>; + +struct Evaluator<'a, R: DeterministicEquivRuntime + ?Sized> { + runtime: &'a mut R, + variables: BTreeMap, +} + +impl<'a, R: ?Sized> Evaluator<'a, R> +where + R: CouponHelper + Operator + ExpandHandle, + for<'b> R::BlobData<'b>: AsRef<[u8]>, + for<'b> R::TreeData<'b>: AsRef<[u8]>, +{ + fn new(runtime: &'a mut R) -> Self { + Self { + runtime, + variables: BTreeMap::new(), + } + } + + fn evaluate_commands(&mut self, commands: &str) -> Result<(String, Option), String> { + let tokens = Lexer::new(commands).tokenize()?; + let program = ExprParser::new(&tokens).parse_program()?; + + let mut output = String::new(); + let mut output_handle: Option = None; + for statement in program { + if let Some(text) = self.evaluate_statement(statement)? { + match text { + Value::String(s) => { + if !output.is_empty() { + output.push('\n') + } + output.push_str(&s); + } + Value::Handle(h) => output_handle = Some(h), + _ => todo!(), + }; + } + } + Ok((output, output_handle)) + } + + fn evaluate_statement(&mut self, statement: Statement) -> Result, String> { + match statement { + Statement::Assign { name, expr } => { + let value = self.evaluate_expr(expr)?; + self.variables.insert(name, value); + Ok(None) + } + Statement::Print(expr) => Ok(Some(Value::String(format!( + "{}", + self.evaluate_expr(expr)? + )))), + Statement::ShowCoupon(expr) => { + if let Value::Handle(h) = self.evaluate_expr(expr)? { + Ok(Some(Value::String(self.runtime.show_coupon(&h)))) + } else { + Err("not a coupon to show".to_string()) + } + } + Statement::Expr(expr) => { + let result = self.evaluate_expr(expr)?; + Ok(Some(result)) + } + } + } + + fn evaluate_expr(&mut self, expr: Expr) -> Result { + match expr { + Expr::Number(number) => Ok(Value::Int(number)), + Expr::String(string) => Ok(Value::String(string)), + Expr::Group(expr) => self.evaluate_expr(*expr), + Expr::Identifier(name) => { + if name == "mock" || name == "hybrid" { + return Ok(Value::Unit); + } + self.variables + .get(&name) + .cloned() + .ok_or_else(|| format!("unknown variable: {name}")) + } + Expr::Call { name, args } => self.evaluate_call(&name, args), + } + } + + fn evaluate_call(&mut self, name: &str, args: Vec) -> Result { + match name { + "create_blob" => { + let handle = self.evaluate_primitive(name, args)?; + Ok(Value::Handle(handle)) + } + "create_tree" => { + let mut bytes = Vec::with_capacity(args.len() * 32); + for expr in args { + let value = self.evaluate_expr(expr)?; + bytes.extend_from_slice(&self.make_handle(name, value)?.pack()); + } + Ok(Value::Handle(self.runtime.create_tree(&bytes))) + } + "create_application_thunk" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let handle = create_application_thunk(&handle) + .map_err(|_| "Failed to create application thunk")?; + Ok(Value::Handle(handle)) + } + "create_strict_encode" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let handle = + create_strict_encode(&handle).map_err(|_| "Failed to create strict encode")?; + Ok(Value::Handle(handle)) + } + "get_blob" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let blob = self + .runtime + .get_blob(&handle) + .map_err(|error| format!("{name}: {error:?}"))?; + Ok(Value::BlobData(blob.as_ref().to_vec())) + } + "get_tree" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let tree = self + .runtime + .get_tree(&handle) + .map_err(|e| format!("{name}: {e:?}"))?; + Ok(Value::TreeData(tree.as_ref().to_vec().into())) + } + "apply" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let apply_handle = self.runtime.apply(handle); + Ok(Value::Handle(apply_handle)) + } + "eval" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let eval_handle = self.runtime.eval(handle); + Ok(Value::Handle(eval_handle)) + } + "trade" => { + assert!(args.len() == 4); + let coupon_trade = self + .evaluate_expr(args[0].clone()) + .map_err(|_| "Failed to evaluate coupon trade")?; + let coupon_trade: CouponTrades = match coupon_trade { + Value::String(inner) => CouponTrades::try_from(inner.as_str()) + .map_err(|_| String::from("Invalid coupon trade")), + _ => Err(String::from("Expected string for coupon trade")), + }?; + + let coupons = self.evaluate_expr(args[1].clone())?; + let coupons = self.make_handle(name, coupons)?; + + let lhs = self.evaluate_expr(args[2].clone())?; + let lhs = self.make_handle(name, lhs)?; + + let rhs = self.evaluate_expr(args[3].clone())?; + let rhs = self.make_handle(name, rhs)?; + + let result = self.runtime.trade(coupon_trade, coupons, lhs, rhs); + + Ok(Value::Handle(result)) + } + "coupon_lhs" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let result = self.runtime.get_coupon_lhs(&handle); + Ok(Value::Handle(result)) + } + "coupon_rhs" => { + let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; + let handle = self.make_handle(name, expr)?; + let result = self.runtime.get_coupon_rhs(&handle); + Ok(Value::Handle(result)) + } + "handle" => { + assert!(args.len() == 1); + let handle = self + .evaluate_expr(args[0].clone()) + .map_err(|_| "Failed to evaluate shortened handle string")?; + match handle { + Value::String(inner) => Ok(Value::Handle( + self.runtime + .get_handle(inner.as_str()) + .map_err(|_| "Failed to expand handle")?, + )), + _ => Err(String::from("Expected string for coupon trade")), + } + } + "tag" => { + assert!(args.len() == 1); + let handle = self + .evaluate_expr(args[0].clone()) + .map_err(|_| "Failed to evaluate shortened handle string")?; + match handle { + Value::String(inner) => Ok(Value::Handle( + self.runtime + .get_tag(inner.as_str()) + .map_err(|_| "Failed to expand tag")?, + )), + _ => Err(String::from("Expected string for coupon trade")), + } + } + "print" => self.evaluate_expr(self.get_arg(name, &args)?.clone()), + "mock" | "hybrid" => { + if args.is_empty() { + Ok(Value::Unit) + } else { + Err(format!("{name}: unexpected args")) + } + } + _ => Err(format!("unknown function: {name}")), + } + } + + fn evaluate_primitive(&mut self, name: &str, args: Vec) -> Result { + let Expr::Call { name, args } = self.get_arg(name, &args)? else { + return Err(String::from("Expected primitive for create_blob()")); + }; + + let [inner] = args.as_slice() else { + return Err(format!("{name}: primitive takes 1 argument")); + }; + match self.evaluate_expr(inner.clone())? { + Value::Int(number) if name == "Int" => Ok(self.runtime.create_blob_i64(number as u64)), + Value::String(string) if name == "String" => { + Ok(self.runtime.create_blob(string.as_bytes())) + } + Value::String(path) => { + let blob = fs::read(&path) + .map_err(|error| format!("{name}: can't read file {path:?}: {error}"))?; + Ok(self.runtime.create_blob(&blob)) + } + other => Err(format!( + "{name}: expected Int(), String(\"text\"), or Path(\"...\"), got {other:?}" + )), + } + } + + fn make_handle(&self, name: &str, value: RuntimeValue) -> Result { + match value { + Value::Handle(handle) => Ok(handle), + other => Err(format!("{name}: got {other} for handle")), + } + } + + fn get_arg<'b>(&self, name: &str, args: &'b [Expr]) -> Result<&'b Expr, String> { + let [expr] = args else { + return Err(self.wrong_arity(name, 1, args.len())); + }; + Ok(expr) + } + + fn wrong_arity(&self, name: &str, expected: usize, found: usize) -> String { + format!("{name}: got {found} arguments but expected {expected}") + } +} diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index d1d0dca..eeaeb43 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -1,27 +1,36 @@ -use core::result::Result; -use core::{clone::Clone, panic}; - use common::bitpack::BitPack; +use core::{clone::Clone, fmt, panic, result::Result}; use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; +use std::ops::Deref; use crate::vmcommon::CouponTrades; #[allow(unused)] pub trait DeterministicEquivRuntime { - type Handle: Clone + core::fmt::Debug; - type Error: core::fmt::Debug; + type BlobData<'a>: Deref + Clone + fmt::Debug + where + Self: 'a; + type TreeData<'a>: Deref + Clone + fmt::Debug + where + Self: 'a; + type Handle: Clone + fmt::Debug; + type Error: fmt::Debug; fn create_blob_i32(&mut self, data: u32) -> Self::Handle; fn create_blob_i64(&mut self, data: u64) -> Self::Handle; fn create_blob(&mut self, data: &[u8]) -> Self::Handle; fn create_tree(&mut self, data: &[u8]) -> Self::Handle; - fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result<&'a [u8], Self::Error>; - fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error>; + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error>; + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error>; } #[allow(unused)] -pub trait CouponHelper: DeterministicEquivRuntime { +pub trait CouponHelper: DeterministicEquivRuntime +where + for<'a> Self::BlobData<'a>: AsRef<[u8]>, + for<'a> Self::TreeData<'a>: AsRef<[u8]>, +{ fn read_blob(blob: &[u8], offset: usize, buf: &mut [u8]) -> usize { let n = (blob.len() - offset).min(buf.len()); buf[..n].copy_from_slice(&blob[offset..offset + n]); @@ -43,10 +52,10 @@ pub trait CouponHelper: DeterministicEquivRuntime { tree.len() / 32 } - fn coupon_type(&mut self, handle: &Self::Handle) -> &'static str { + fn coupon_type(&self, handle: &Self::Handle) -> &'static str { let mut arr = [0u8; 4]; let blob = self.get_blob(handle).expect("Coupon type not a blob"); - Self::read_blob(blob, 0, &mut arr); + Self::read_blob(blob.as_ref(), 0, &mut arr); let num = u32::from_le_bytes(arr); match num { 0 => "Eq", @@ -59,30 +68,28 @@ pub trait CouponHelper: DeterministicEquivRuntime { } } - fn show_coupon(&mut self, handle: &Self::Handle) { + fn show_coupon(&mut self, handle: &Self::Handle) -> String { let ctype = self.get_coupon_type(handle); let lhs = self.get_coupon_lhs(handle); let rhs = self.get_coupon_rhs(handle); - log::info!("type is: {ctype:?}"); - log::info!("lhs is: {lhs:?}"); - log::info!("rhs is: {rhs:?}"); + format!("{lhs:?} --{ctype}-- {rhs:?}") } - fn get_coupon_type(&mut self, coupon: &Self::Handle) -> &'static str { + fn get_coupon_type(&self, coupon: &Self::Handle) -> &'static str { let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - let handle = Self::get_tree_entry(coupon_content, 1); + let handle = Self::get_tree_entry(coupon_content.as_ref(), 1); self.coupon_type(&handle) } - fn get_coupon_lhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + fn get_coupon_lhs(&self, coupon: &Self::Handle) -> Self::Handle { let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - Self::get_tree_entry(coupon_content, 2) + Self::get_tree_entry(coupon_content.as_ref(), 2) } - fn get_coupon_rhs(&mut self, coupon: &Self::Handle) -> Self::Handle { + fn get_coupon_rhs(&self, coupon: &Self::Handle) -> Self::Handle { let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - Self::get_tree_entry(coupon_content, 3) + Self::get_tree_entry(coupon_content.as_ref(), 3) } } @@ -102,7 +109,11 @@ pub trait Operator { } #[allow(unused)] -pub trait Visitor: CouponHelper { +pub trait Visitor: CouponHelper +where + for<'a> Self::BlobData<'a>: AsRef<[u8]>, + for<'a> Self::TreeData<'a>: AsRef<[u8]>, +{ fn visit(&self, handle: FixHandle, callback: &mut F) where F: FnMut(&Self, &FixHandle), @@ -122,9 +133,9 @@ pub trait Visitor: CouponHelper { Object::BlobObj(_) => {} Object::TreeObj(_) => { let tree_data = self.get_tree(&handle).unwrap(); - for i in 0..Self::get_tree_len(tree_data) { - let child = Self::get_tree_entry(tree_data, i); - self.visit(Self::get_tree_entry(tree_data, i), callback); + for i in 0..Self::get_tree_len(tree_data.as_ref()) { + let child = Self::get_tree_entry(tree_data.as_ref(), i); + self.visit(child, callback); } } }, @@ -132,3 +143,76 @@ pub trait Visitor: CouponHelper { callback(self, &handle); } } + +#[allow(unused)] +pub trait ExpandHandle { + type Error: fmt::Debug; + fn get_handle(&mut self, handle: &str) -> Result; + fn get_tag(&mut self, handle: &str) -> Result; +} + +#[derive(Debug)] +pub enum RuntimeError { + OOB, + TypeMismatch, + UnexpectedFunction, + FileError, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Token { + Identifier(String), + Number(i64), + String(String), + LParen, + RParen, + Comma, + Semicolon, + Equals, + Eof, +} + +#[derive(Debug, Clone)] +pub enum Expr { + Number(i64), + Identifier(String), + String(String), + Call { name: String, args: Vec }, + Group(Box), +} + +#[derive(Debug, Clone)] +pub enum Statement { + Assign { name: String, expr: Expr }, + Print(Expr), + ShowCoupon(Expr), + Expr(Expr), +} + +#[derive(Debug, Clone)] +pub enum Value { + Handle(H), + BlobData(B), + TreeData(T), + Int(i64), + String(String), + Unit, +} + +impl fmt::Display for Value +where + H: fmt::Debug, + B: fmt::Debug, + T: fmt::Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Handle(handle) => write!(formatter, "{handle:?}"), + Self::BlobData(data) => write!(formatter, "{data:?}"), + Self::TreeData(data) => write!(formatter, "{data:?}"), + Self::Int(value) => write!(formatter, "{value}"), + Self::String(value) => write!(formatter, "{value}"), + Self::Unit => write!(formatter, "()"), + } + } +} diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs new file mode 100644 index 0000000..e0f658d --- /dev/null +++ b/fix/evaluator/src/hybridruntime.rs @@ -0,0 +1,187 @@ +use crate::{ + fixruntime::{CouponHelper, DeterministicEquivRuntime, ExpandHandle, Operator, RuntimeError}, + storageruntime::StorageRuntime, + vmcommon::CouponTrades, + vmmruntime::VmmRuntime, +}; +use common::bitpack::BitPack; +use fixhandle::rawhandle::{ + BlobName, Encode, FixHandle, Object, Thunk, TreeName, create_application_thunk, + create_strict_encode, +}; +use std::{collections::HashMap, sync::Arc}; + +pub struct HybridRuntime { + vmm_runtime: VmmRuntime, + storage_runtime: StorageRuntime, + // Packed FixHandle to packed CanonicalHandle if flushed or packed FixHandle if literal + flushed: HashMap<[u8; 32], [u8; 32]>, + store: Vec, +} + +impl HybridRuntime { + pub fn new(smp: usize, cid: usize, bin: Arc<[u8]>) -> Self { + Self { + vmm_runtime: VmmRuntime::new(smp, cid, bin), + storage_runtime: StorageRuntime::new(), + flushed: HashMap::new(), + store: Vec::new(), + } + } + + pub fn flush_handle(&mut self, handle: FixHandle) -> Result { + let packed_handle = handle.pack(); + + if let Some(flushed_handle) = self.flushed.get(&packed_handle) { + return Ok(FixHandle::unpack(*flushed_handle)); + } + + let canonical_handle = match handle { + FixHandle::Object(Object::BlobObj(blob_name)) => match blob_name { + // Store packed handle for literals + BlobName::Literal(_) => handle, + // Write non-literals to storage + BlobName::Blob(_) => { + let blob = self.vmm_runtime.get_blob(&handle)?; + self.storage_runtime.create_blob(blob) + } + }, + FixHandle::Object(Object::TreeObj(in_treename)) => { + let tree = self.vmm_runtime.get_tree(&handle)?; + let mut children = Vec::with_capacity(Self::get_tree_len(tree)); + for i in 0..Self::get_tree_len(tree) { + let child = Self::get_tree_entry(tree, i); + children.push(child); + } + let mut bytes = Vec::with_capacity(tree.len()); + for child in children { + let flushed = self.flush_handle(child)?; + bytes.extend_from_slice(&flushed.pack()); + } + + let treename = self + .storage_runtime + .create_tree(&bytes) + .unwrap_object() + .unwrap_tree_obj() + .unwrap_not_tag(); + let treename = match in_treename { + TreeName::Tag(_) => { + let result = TreeName::Tag(treename); + self.storage_runtime + .create_tag(&result) + .expect("Failed to create tag"); + result + } + TreeName::NotTag(_) => TreeName::NotTag(treename), + }; + FixHandle::Object(Object::TreeObj(treename)) + } + FixHandle::Encode(Encode::Strict(tree)) => { + let inner = self.flush_handle(FixHandle::Thunk(tree))?; + create_strict_encode(&inner).expect("strict encode flush failed") + } + FixHandle::Encode(Encode::Shallow(_tree)) => todo!(""), + FixHandle::Thunk(Thunk::Application(tree)) => { + let tree_handle = FixHandle::Object(Object::from(tree)); + let flushed_tree = self.flush_handle(tree_handle)?; + create_application_thunk(&flushed_tree).expect("application thunk flush failed") + } + FixHandle::Thunk(_) => todo!(""), + FixHandle::Ref(_) => todo!(""), + }; + + self.flushed.insert(packed_handle, canonical_handle.pack()); + Ok(canonical_handle) + } + + #[allow(unused)] + fn flush(&mut self) { + for handle in self.store.clone() { + let _ = self.flush_handle(handle); + } + } +} + +impl DeterministicEquivRuntime for HybridRuntime { + type BlobData<'a> = &'a [u8]; + type TreeData<'a> = &'a [u8]; + type Handle = FixHandle; + type Error = RuntimeError; + + fn create_blob_i32(&mut self, data: u32) -> Self::Handle { + let bytes = data.to_le_bytes(); + self.create_blob(&bytes) + } + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + let bytes = data.to_le_bytes(); + self.create_blob(&bytes) + } + + fn create_blob(&mut self, data: &[u8]) -> Self::Handle { + self.vmm_runtime.create_blob(data) + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + self.vmm_runtime.create_tree(data) + } + + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + self.vmm_runtime.get_blob(handle) + } + + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + self.vmm_runtime.get_tree(handle) + } +} + +impl CouponHelper for HybridRuntime {} + +impl Operator for HybridRuntime { + fn apply(&mut self, handle: FixHandle) -> FixHandle { + self.vmm_runtime.apply(handle) + } + + fn eval(&mut self, handle: FixHandle) -> FixHandle { + self.vmm_runtime.eval(handle) + } + + fn trade( + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle { + self.vmm_runtime.trade(trade_type, coupons, lhs, rhs) + } +} + +impl ExpandHandle for HybridRuntime { + type Error = RuntimeError; + + fn get_handle(&mut self, handle: &str) -> Result { + let full_handle = self.storage_runtime.get_handle(handle)?; + match full_handle { + FixHandle::Object(Object::BlobObj(_)) => { + let blob = self.storage_runtime.get_blob(&full_handle)?; + Ok(self.create_blob(&blob)) + } + FixHandle::Object(Object::TreeObj(_)) => { + let tree = self.storage_runtime.get_tree(&full_handle)?; + Ok(self.create_tree(&tree)) + } + _ => Err(RuntimeError::TypeMismatch), + } + } + + fn get_tag(&mut self, handle: &str) -> Result { + let full_handle = self.storage_runtime.get_tag_handle(handle)?; + let tag_content = self.storage_runtime.get_tag(&full_handle)?; + let result = self.create_tree(&tag_content); + Ok(FixHandle::Object(Object::TreeObj(TreeName::Tag( + result.unwrap_object().unwrap_tree_obj().unwrap_not_tag(), + )))) + } +} diff --git a/fix/evaluator/src/lexer.rs b/fix/evaluator/src/lexer.rs new file mode 100644 index 0000000..cf575fe --- /dev/null +++ b/fix/evaluator/src/lexer.rs @@ -0,0 +1,94 @@ +use crate::fixruntime::Token; +use std::iter::Peekable; +use std::str::Chars; + +pub struct Lexer<'a> { + characters: Peekable>, +} + +impl<'a> Lexer<'a> { + pub fn new(input: &'a str) -> Self { + Self { + characters: input.chars().peekable(), + } + } + + pub fn tokenize(mut self) -> Result, String> { + let mut tokens = Vec::new(); + loop { + let token = self.next_token()?; + if token == Token::Eof { + tokens.push(token); + break; + } + tokens.push(token); + } + Ok(tokens) + } + + pub fn next_token(&mut self) -> Result { + // skip whitespace + self.take(String::new(), |ch| ch.is_whitespace()); + let Some(character) = self.characters.next() else { + return Ok(Token::Eof); + }; + + let token = match character { + ';' => Token::Semicolon, + '(' => Token::LParen, + ')' => Token::RParen, + ',' => Token::Comma, + '=' => Token::Equals, + '"' => { + let text = self.take(String::new(), |ch| ch != '"'); + if self.characters.next() != Some('"') { + return Err(String::from("unterminated string")); + } + Token::String(text) + } + // Inline comments + '/' => { + if self.characters.next() == Some('/') { + self.take(String::new(), |ch| ch != '\n'); + return self.next_token(); + } + return Err(String::from("unexpected character: '/'")); + } + // Negative numbers + '-' if self.peek(|character| character.is_ascii_digit()) => { + let number = self.take(String::new(), |ch| ch.is_ascii_digit()); + Token::Number(-number.parse::().map_err(|error| error.to_string())?) + } + character if character.is_ascii_digit() => { + let number = self.take(String::from(character), |ch| ch.is_ascii_digit()); + Token::Number(number.parse::().map_err(|error| error.to_string())?) + } + character if Self::is_identifier(character) => { + Token::Identifier(self.take(String::from(character), Self::is_identifier)) + } + other => return Err(format!("unexpected character: {other:?}")), + }; + Ok(token) + } + + fn peek(&mut self, function: F) -> bool + where + F: FnOnce(&char) -> bool, + { + self.characters.peek().is_some_and(function) + } + + fn take(&mut self, mut text: String, mut condition: F) -> String + where + F: FnMut(char) -> bool, + { + while let Some(next) = self.characters.next_if(|&ch| condition(ch)) { + text.push(next); + } + text + } + + fn is_identifier(character: char) -> bool { + character.is_ascii_alphabetic() || character == '_' + } +} diff --git a/fix/evaluator/src/lib.rs b/fix/evaluator/src/lib.rs new file mode 100644 index 0000000..bf9bc27 --- /dev/null +++ b/fix/evaluator/src/lib.rs @@ -0,0 +1,14 @@ +#![feature(allocator_api)] +#![feature(ptr_metadata)] +#![feature(result_option_map_or_default)] +#[path = "../../runtime/src/common.rs"] +pub mod vmcommon; + +pub mod fixruntime; +pub mod hybridruntime; +pub mod lexer; +pub mod memoryruntime; +pub mod mockruntime; +pub mod parser; +pub mod storageruntime; +pub mod vmmruntime; diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 1675ed6..4b70533 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -1,22 +1,17 @@ +#![allow(unused)] #![feature(allocator_api)] #![feature(ptr_metadata)] #![feature(result_option_map_or_default)] -use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; -use crate::vmcommon::CouponTrades; use common::bitpack::BitPack; +use evaluator::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; use std::path::PathBuf; use std::sync::Arc; -use crate::vmmruntime::VmmRuntime; use clap::Parser; - -#[path = "../../runtime/src/common.rs"] -mod vmcommon; - -mod fixruntime; -mod vmmruntime; +use evaluator::vmcommon::CouponTrades; +use evaluator::vmmruntime::VmmRuntime; #[derive(Parser, Debug)] struct Args { @@ -56,7 +51,7 @@ fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { let encode = create_strict_encode(&application).unwrap(); let result = rt.eval(encode); - rt.show_coupon(&result); + log::info!("{}", rt.show_coupon(&result)); let result_blob = rt.get_coupon_rhs(&result); let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); @@ -81,7 +76,7 @@ fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { let combination = rt.create_tree(scratch.as_slice()); let result = rt.apply(combination); - rt.show_coupon(&result); + log::info!("{}", rt.show_coupon(&result)); let result_blob = rt.get_coupon_rhs(&result); let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); @@ -99,7 +94,7 @@ fn test_trade(smp: usize, cid: usize, bin: Arc<[u8]>) { let coupons = rt.create_tree(scratch.as_slice()); let result = rt.trade(CouponTrades::EvalBlobObj, coupons, addend, addend); - rt.show_coupon(&result); + log::info!("{}", rt.show_coupon(&result)); let result_blob = rt.get_coupon_rhs(&result); let result_blob = rt.get_blob(&result_blob).expect("Result is not a Blob"); diff --git a/fix/evaluator/src/memoryruntime.rs b/fix/evaluator/src/memoryruntime.rs new file mode 100644 index 0000000..1f2018d --- /dev/null +++ b/fix/evaluator/src/memoryruntime.rs @@ -0,0 +1,98 @@ +use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; +use fixhandle::rawhandle::{ + BlobName, FixHandle, Handle, LiteralHandle, Object, PhysicalHandle, TreeName, +}; + +pub struct MemoryRuntime { + store: Vec>, +} + +impl Default for MemoryRuntime { + fn default() -> Self { + Self::new() + } +} + +impl MemoryRuntime { + pub fn new() -> Self { + Self { store: Vec::new() } + } + + fn create(&mut self, data: &[u8]) -> usize { + let index = self.store.len(); + self.store.push(Box::from(data)); + index + } + + fn get(&self, idx: usize) -> &[u8] { + &self.store[idx] + } + + pub fn get_by_handle(&self, handle: Handle) -> &[u8] { + match handle { + Handle::VirtualHandle(_) | Handle::CanonicalHandle(_) => todo!(), + Handle::PhysicalHandle(physical_handle) => self.get(physical_handle.local_id()), + } + } +} + +impl DeterministicEquivRuntime for MemoryRuntime { + type BlobData<'a> = &'a [u8]; + type TreeData<'a> = &'a [u8]; + type Handle = FixHandle; + type Error = RuntimeError; + + fn create_blob_i32(&mut self, data: u32) -> Self::Handle { + self.create_blob(&data.to_le_bytes()) + } + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + self.create_blob(&data.to_le_bytes()) + } + + fn create_blob(&mut self, data: &[u8]) -> Self::Handle { + if data.len() <= 30 { + let literal = LiteralHandle::new(data); + Object::from(BlobName::Literal(literal)).into() + } else { + let blob = BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new( + self.create(data), + data.len(), + ))); + Object::from(blob).into() + } + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + let tree = TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new( + self.create(data), + data.len() / 32, + ))); + Object::from(tree).into() + } + + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + let blob = handle + .try_unwrap_object_ref() + .map_err(|_| RuntimeError::TypeMismatch)? + .try_unwrap_blob_obj_ref() + .map_err(|_| RuntimeError::TypeMismatch)?; + + match blob { + BlobName::Blob(h) => Ok(self.get_by_handle(*h)), + BlobName::Literal(literal) => Ok(literal.content()), + } + } + + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + let tree = handle + .try_unwrap_object_ref() + .map_err(|_| RuntimeError::TypeMismatch)? + .try_unwrap_tree_obj_ref() + .map_err(|_| RuntimeError::TypeMismatch)?; + + match tree { + TreeName::NotTag(h) | TreeName::Tag(h) => Ok(self.get_by_handle(*h)), + } + } +} diff --git a/fix/evaluator/src/mockruntime.rs b/fix/evaluator/src/mockruntime.rs new file mode 100644 index 0000000..f98cd4b --- /dev/null +++ b/fix/evaluator/src/mockruntime.rs @@ -0,0 +1,143 @@ +use crate::{ + fixruntime::{CouponHelper, DeterministicEquivRuntime, ExpandHandle, Operator, RuntimeError}, + memoryruntime::MemoryRuntime, + vmcommon::CouponTrades, +}; +use fixhandle::rawhandle::FixHandle; + +pub struct MockRuntime { + memory_runtime: MemoryRuntime, +} + +impl Default for MockRuntime { + fn default() -> Self { + Self::new() + } +} + +impl MockRuntime { + pub fn new() -> Self { + Self { + memory_runtime: MemoryRuntime::new(), + } + } +} + +impl DeterministicEquivRuntime for MockRuntime { + type BlobData<'a> = &'a [u8]; + type TreeData<'a> = &'a [u8]; + type Handle = FixHandle; + type Error = RuntimeError; + + fn create_blob_i32(&mut self, data: u32) -> Self::Handle { + self.memory_runtime.create_blob_i32(data) + } + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + self.memory_runtime.create_blob_i64(data) + } + + fn create_blob(&mut self, data: &[u8]) -> Self::Handle { + self.memory_runtime.create_blob(data) + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + self.memory_runtime.create_tree(data) + } + + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + self.memory_runtime.get_blob(handle) + } + + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + self.memory_runtime.get_tree(handle) + } +} + +impl CouponHelper for MockRuntime {} + +impl Operator for MockRuntime { + fn trade( + &mut self, + _trade_type: CouponTrades, + _coupons: FixHandle, + _lhs: FixHandle, + _rhs: FixHandle, + ) -> FixHandle { + todo!() + } + + fn eval(&mut self, _handle: FixHandle) -> FixHandle { + todo!() + } + + fn apply(&mut self, handle: FixHandle) -> FixHandle { + let span = self.get_tree(&handle).unwrap(); + if span.len() < 3 { + panic!() + // return Err(RuntimeError::OOB); + } + + let tree_entry = Self::get_tree_entry(span, 0); + let function = self.get_blob(&tree_entry).unwrap(); + if function != b"+" { + panic!() + // return Err(RuntimeError::UnexpectedFunction); + } + + let left_bytes: [u8; 8] = self + .get_blob(&Self::get_tree_entry(span, 1)) + .unwrap() + .try_into() + .map_err(|_| RuntimeError::OOB) + .unwrap(); + let left = u64::from_le_bytes(left_bytes); + let right_bytes: [u8; 8] = self + .get_blob(&Self::get_tree_entry(span, 2)) + .unwrap() + .try_into() + .map_err(|_| RuntimeError::OOB) + .unwrap(); + let right = u64::from_le_bytes(right_bytes); + + self.create_blob_i64(left + right) + } +} + +impl ExpandHandle for MockRuntime { + type Error = (); + + fn get_handle(&mut self, _handle: &str) -> Result { + todo!() + } + + fn get_tag(&mut self, _handle: &str) -> Result { + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use common::bitpack::BitPack; + #[test] + fn test_add() { + let mut mock_runtime = MockRuntime::new(); + + let one_literal = mock_runtime.create_blob_i64(1); + let two_literal = mock_runtime.create_blob_i64(2); + let plus_literal = mock_runtime.create_blob(b"+"); + + let mut tree_bytes = Vec::new(); + tree_bytes.extend_from_slice(&plus_literal.pack()); + tree_bytes.extend_from_slice(&one_literal.pack()); + tree_bytes.extend_from_slice(&two_literal.pack()); + let tree = mock_runtime.create_tree(&tree_bytes); + let result = mock_runtime.apply(tree); + + assert_eq!( + mock_runtime.get_blob(&result).expect("valid result blob"), + 3_i64.to_le_bytes() + ); + } +} diff --git a/fix/evaluator/src/parser.rs b/fix/evaluator/src/parser.rs new file mode 100644 index 0000000..cca1f6f --- /dev/null +++ b/fix/evaluator/src/parser.rs @@ -0,0 +1,131 @@ +use crate::fixruntime::{Expr, Statement, Token}; + +pub struct Parser<'a> { + tokens: &'a [Token], + position: usize, +} + +impl<'a> Parser<'a> { + pub fn new(tokens: &'a [Token]) -> Self { + Self { + tokens, + position: 0, + } + } + + pub fn parse_program(&mut self) -> Result, String> { + let mut program = Vec::new(); + loop { + self.skip_separators(); + if self.peek(self.position) == Some(&Token::Eof) { + break; + } + program.push(self.parse_statement()?); + self.skip_separators(); + } + Ok(program) + } + + pub fn parse_statement(&mut self) -> Result { + // 'print()' is special built-in + match (self.peek(self.position), self.peek(self.position + 1)) { + (Some(Token::Identifier(name)), Some(Token::LParen)) if name == "print" => { + // consume 'print''(' + self.advance(); + self.advance(); + let expr = self.parse_expr()?; + self.expect(&Token::RParen, "expected ')' for print")?; + Ok(Statement::Print(expr)) + } + (Some(Token::Identifier(name)), Some(Token::LParen)) if name == "show_coupon" => { + // consume 'show_coupon''(' + self.advance(); + self.advance(); + let expr = self.parse_expr()?; + self.expect(&Token::RParen, "expected ')' for show_coupon")?; + Ok(Statement::ShowCoupon(expr)) + } + (Some(Token::Identifier(name)), Some(Token::Equals)) => { + let name = name.clone(); + // consume 'identifier' '=' + self.advance(); + self.advance(); + Ok(Statement::Assign { + name, + expr: self.parse_expr()?, + }) + } + _ => Ok(Statement::Expr(self.parse_expr()?)), + } + } + + fn parse_expr(&mut self) -> Result { + let mut expr = self.parse_primitive()?; + + while self.matches(&Token::LParen) { + let Expr::Identifier(name) = expr else { + return Err(String::from("functions must be named")); + }; + + // arguments for function calls + let mut args = Vec::new(); + if self.peek(self.position) != Some(&Token::RParen) { + loop { + args.push(self.parse_expr()?); + if !self.matches(&Token::Comma) { + break; + } + } + } + self.expect(&Token::RParen, "expected ')' for function call")?; + expr = Expr::Call { name, args }; + } + + Ok(expr) + } + + fn parse_primitive(&mut self) -> Result { + match self.advance() { + Token::Number(value) => Ok(Expr::Number(value)), + Token::Identifier(value) => Ok(Expr::Identifier(value)), + Token::String(value) => Ok(Expr::String(value)), + Token::LParen => { + let expr = self.parse_expr()?; + self.expect(&Token::RParen, "expected ')' for grouping")?; + Ok(Expr::Group(Box::new(expr))) + } + token => Err(format!("unexpected token: {token:?}")), + } + } + + fn skip_separators(&mut self) { + while self.matches(&Token::Semicolon) {} + } + + fn expect(&mut self, token: &Token, message: &str) -> Result<(), String> { + if self.matches(token) { + Ok(()) + } else { + Err(String::from(message)) + } + } + + fn matches(&mut self, token: &Token) -> bool { + if self.peek(self.position) == Some(token) { + self.position += 1; + true + } else { + false + } + } + + fn peek(&self, position: usize) -> Option<&Token> { + self.tokens.get(position) + } + + fn advance(&mut self) -> Token { + let token = self.peek(self.position).cloned().unwrap_or(Token::Eof); + self.position += 1; + token + } +} diff --git a/fix/evaluator/src/storageruntime.rs b/fix/evaluator/src/storageruntime.rs new file mode 100644 index 0000000..2bf682f --- /dev/null +++ b/fix/evaluator/src/storageruntime.rs @@ -0,0 +1,192 @@ +use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; +use common::bitpack::BitPack; +use fixhandle::rawhandle::{ + BlobName, CanonicalHandle, FixHandle, Handle, LiteralHandle, Object, TreeName, +}; +use std::{fmt::Write, fs, io, os::unix::fs::symlink, path::PathBuf}; + +use hex::FromHex; + +pub struct StorageRuntime { + objects_dir: PathBuf, + tags_dir: PathBuf, +} + +impl Default for StorageRuntime { + fn default() -> Self { + Self::new() + } +} + +impl StorageRuntime { + pub fn new() -> Self { + let objects_dir = PathBuf::from(".fix/objects"); + let tags_dir = PathBuf::from(".fix/tags"); + fs::create_dir_all(&objects_dir).expect("failed to create objects directory"); + fs::create_dir_all(&tags_dir).expect("failed to create objects directory"); + Self { + objects_dir, + tags_dir, + } + } + + fn read(&self, handle: &[u8]) -> Result, RuntimeError> { + let path = self.objects_dir.join(Self::hexadecimal_encode(handle)); + fs::read(path) + .map(|bytes| bytes.into_boxed_slice()) + .map_err(|_| RuntimeError::FileError) + } + + fn read_tag(&self, handle: &[u8]) -> Result, RuntimeError> { + let path = self.tags_dir.join(Self::hexadecimal_encode(handle)); + fs::read(path) + .map(|bytes| bytes.into_boxed_slice()) + .map_err(|_| RuntimeError::FileError) + } + + fn hash(data: &[u8]) -> [u8; 32] { + let mut hasher = blake3::Hasher::new(); + hasher.update(data); + *hasher.finalize().as_bytes() + } + + fn hexadecimal_encode(handle: &[u8]) -> String { + let mut hex_name = String::with_capacity(handle.len() * 2); + for &byte in handle { + write!(&mut hex_name, "{:02x}", byte).expect("valid hex encode"); + } + hex_name + } + + fn hexadecimal_decode(handle: &str) -> [u8; 32] { + <[u8; 32]>::from_hex(handle).expect("Failed to decode hex") + } +} + +impl DeterministicEquivRuntime for StorageRuntime { + type BlobData<'a> = Box<[u8]>; + type TreeData<'a> = Box<[u8]>; + type Handle = FixHandle; + type Error = RuntimeError; + + fn create_blob_i32(&mut self, data: u32) -> Self::Handle { + self.create_blob(&data.to_le_bytes()) + } + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + self.create_blob(&data.to_le_bytes()) + } + + fn create_blob(&mut self, data: &[u8]) -> Self::Handle { + if data.len() <= 30 { + Object::from(BlobName::Literal(LiteralHandle::new(data))).into() + } else { + let handle = CanonicalHandle::new(Self::hash(data), data.len() as u64); + let handle: FixHandle = + Object::from(BlobName::Blob(Handle::CanonicalHandle(handle))).into(); + let path = self + .objects_dir + .join(Self::hexadecimal_encode(&handle.pack())); + fs::write(&path, data).expect("failed to write runtime object"); + handle + } + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + let handle = CanonicalHandle::new(Self::hash(data), data.len() as u64); + let handle: FixHandle = + Object::from(TreeName::NotTag(Handle::CanonicalHandle(handle))).into(); + let path = self + .objects_dir + .join(Self::hexadecimal_encode(&handle.pack())); + fs::write(&path, data).expect("failed to write runtime object"); + handle + } + + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + self.read(&handle.pack()) + } + + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { + let data = self.read(&handle.pack())?; + if data.len() % 32 != 0 { + return Err(Self::Error::OOB); + } + Ok(data) + } +} + +impl StorageRuntime { + pub fn create_tag(&mut self, handle: &TreeName) -> Result<(), RuntimeError> { + match handle { + TreeName::NotTag(_) => Err(RuntimeError::TypeMismatch), + TreeName::Tag(Handle::CanonicalHandle(canonical)) => { + let tree_handle: FixHandle = + Object::from(TreeName::NotTag(Handle::CanonicalHandle(*canonical))).into(); + let tag_handle: FixHandle = + Object::from(TreeName::Tag(Handle::CanonicalHandle(*canonical))).into(); + let tree_path = self + .objects_dir + .join(Self::hexadecimal_encode(&tree_handle.pack())); + let tag_path = self + .tags_dir + .join(Self::hexadecimal_encode(&tag_handle.pack())); + let tree_path = PathBuf::from("../../").join(tree_path); + let _ = fs::remove_file(&tag_path); + symlink(tree_path, tag_path).map_err(|_| RuntimeError::FileError) + } + TreeName::Tag(_) => Err(RuntimeError::TypeMismatch), + } + } + + pub fn get_tag(&self, handle: &FixHandle) -> Result, RuntimeError> { + let data = self.read_tag(&handle.pack())?; + if data.len() % 32 != 0 { + return Err(RuntimeError::OOB); + } + Ok(data) + } + + fn find_handle(root: &PathBuf, short: &str) -> io::Result { + assert_eq!(short.len(), 8); + + let mut matches = Vec::new(); + + for entry in fs::read_dir(root)? { + let entry = entry?; + if entry.file_type()?.is_dir() { + continue; + } + + let name = entry.file_name(); + let Some(name) = name.to_str() else { continue }; + + if name.len() == 64 && name[..8].eq_ignore_ascii_case(short) { + matches.push(String::from( + entry.path().file_name().unwrap().to_str().unwrap(), + )); + } + } + + match matches.len() { + 1 => { + let str = matches.pop().unwrap(); + let res = Self::hexadecimal_decode(str.as_str()); + Ok(FixHandle::unpack(res)) + } + 0 => Err(std::io::Error::other(format!("no match for {short}"))), + _ => Err(std::io::Error::other(format!( + "ambiguous prefix {short}: {} matches", + matches.len() + ))), + } + } + + pub fn get_handle(&self, handle: &str) -> Result { + Self::find_handle(&self.objects_dir, handle).map_err(|_| RuntimeError::FileError) + } + + pub fn get_tag_handle(&self, handle: &str) -> Result { + Self::find_handle(&self.tags_dir, handle).map_err(|_| RuntimeError::FileError) + } +} diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index a95ee1f..270cdb0 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -5,83 +5,163 @@ use std::{mem, ptr}; use common::BuddyAllocator; use common::bitpack::BitPack; use fixhandle::rawhandle::{ - BlobName, FixHandle, Handle, LiteralHandle, Object, PhysicalHandle, TreeName, + BlobName, CanonicalHandle, FixHandle, Handle, LiteralHandle, Object, TreeName, }; +use hashbrown::HashMap; use vmm::runtime::Runtime; -use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; +use crate::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}; use crate::vmcommon::{CouponTrades, FixOp}; pub struct VmmRuntime { runtime: Runtime, - store: Vec>, + store: HashMap<[u8; 32], Box<[u8], BuddyAllocator>>, + executed: bool, +} + +pub trait FixData: From> { + fn inner(self) -> Box<[u8], BuddyAllocator>; + fn len(&self) -> u64; + fn is_empty(&self) -> bool { + self.len() == 0 + } } impl VmmRuntime { pub fn new(smp: usize, cid: usize, bin: Arc<[u8]>) -> Self { Self { runtime: Runtime::new(cid, smp, 1 << 34, bin), - store: Vec::new(), + store: HashMap::new(), + executed: false, } } - fn create(&mut self, data: Box<[u8], BuddyAllocator>) -> usize { - let idx = self.store.len(); - self.store.push(data); - idx + fn create_raw(&mut self, data: Box<[u8], BuddyAllocator>) -> [u8; 32] { + let hash = blake3::hash(data.as_ref()); + let canonical = CanonicalHandle::new(*hash.as_bytes(), 0); + self.store.insert(canonical.hash(), data); + canonical.hash() } - fn get(&self, idx: usize) -> &[u8] { - &self.store[idx] + fn create(&mut self, data: T) -> CanonicalHandle { + let len = data.len(); + let hash = self.create_raw(data.inner()); + CanonicalHandle::new(hash, len) + } + + fn get(&self, key: &[u8; 32]) -> &[u8] { + self.store + .get(key) + .expect("Failed to retrieve data") + .as_ref() } fn get_by_handle(&self, handle: Handle) -> &[u8] { match handle { - Handle::VirtualHandle(_) | Handle::CanonicalHandle(_) => todo!(), - Handle::PhysicalHandle(physical_handle) => self.get(physical_handle.local_id()), + Handle::VirtualHandle(_) | Handle::PhysicalHandle(_) => todo!(), + Handle::CanonicalHandle(c) => self.get(&c.hash()), + } + } +} + +#[derive(Debug)] +pub struct FixBlobData { + inner: Box<[u8], BuddyAllocator>, +} + +impl FixData for FixBlobData { + fn inner(self) -> Box<[u8], BuddyAllocator> { + self.inner + } + + fn len(&self) -> u64 { + self.inner.len() as u64 + } +} + +impl From> for FixBlobData { + fn from(value: Box<[u8], BuddyAllocator>) -> Self { + Self { inner: value } + } +} + +#[derive(Debug)] +pub struct FixTreeData { + inner: Box<[u8], BuddyAllocator>, +} + +impl FixData for FixTreeData { + fn inner(self) -> Box<[u8], BuddyAllocator> { + self.inner + } + + fn len(&self) -> u64 { + (self.inner.len() / 32) as u64 + } +} + +impl From> for FixTreeData { + fn from(value: Box<[u8], BuddyAllocator>) -> Self { + Self { inner: value } + } +} + +impl FixTreeData { + pub fn get(&self, offset: usize) -> FixHandle { + let mut scratch: [u8; 32] = [0; 32]; + if offset < self.len() as usize { + scratch.copy_from_slice(&self.inner[offset * 32..(offset + 1) * 32]); + } else { + panic!(); } + + FixHandle::unpack(scratch) } } impl DeterministicEquivRuntime for VmmRuntime { + type BlobData<'a> = &'a [u8]; + type TreeData<'a> = &'a [u8]; type Handle = FixHandle; - type Error = (); + type Error = RuntimeError; fn create_blob_i32(&mut self, data: u32) -> FixHandle { - let x = data.to_le_bytes().to_vec().into_boxed_slice(); - self.create_blob(&x) + let bytes = data.to_le_bytes(); + self.create_blob(&bytes) } fn create_blob_i64(&mut self, data: u64) -> FixHandle { - let x = data.to_le_bytes().to_vec().into_boxed_slice(); - self.create_blob(&x) + let bytes = data.to_le_bytes(); + self.create_blob(&bytes) } - fn create_blob(&mut self, data: &[u8]) -> FixHandle { + fn create_blob(&mut self, data: Self::BlobData<'_>) -> FixHandle { let len = data.len(); if len <= 30 { let literal = LiteralHandle::new(data); Object::from(BlobName::Literal(literal)).into() } else { - let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); - let blob = BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); + let data = data.to_vec_in(BuddyAllocator).into_boxed_slice(); + let data: FixBlobData = data.into(); + let canonical = self.create(data); + let blob = BlobName::Blob(Handle::CanonicalHandle(canonical)); Object::from(blob).into() } } - fn create_tree(&mut self, data: &[u8]) -> FixHandle { - let len = data.len() / 32; - let local_id = self.create(data.to_vec_in(BuddyAllocator).into_boxed_slice()); - let tree = TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))); - Object::from(tree).into() + fn create_tree(&mut self, data: Self::TreeData<'_>) -> FixHandle { + let data = data.to_vec_in(BuddyAllocator).into_boxed_slice(); + let data: FixTreeData = data.into(); + let canonical = self.create(data); + Object::from(TreeName::NotTag(Handle::CanonicalHandle(canonical))).into() } - fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result<&'a [u8], Self::Error> { + fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { let b = handle .try_unwrap_object_ref() - .map_err(|_| ())? + .map_err(|_| RuntimeError::TypeMismatch)? .try_unwrap_blob_obj_ref() - .map_err(|_| ())?; + .map_err(|_| RuntimeError::TypeMismatch)?; match b { BlobName::Blob(h) => Ok(self.get_by_handle(*h)), @@ -89,12 +169,12 @@ impl DeterministicEquivRuntime for VmmRuntime { } } - fn get_tree(&self, handle: &Self::Handle) -> Result<&[u8], Self::Error> { + fn get_tree<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { let t = handle .try_unwrap_object_ref() - .map_err(|_| ())? + .map_err(|_| RuntimeError::TypeMismatch)? .try_unwrap_tree_obj_ref() - .map_err(|_| ())?; + .map_err(|_| RuntimeError::TypeMismatch)?; match t { TreeName::NotTag(tree) | TreeName::Tag(tree) => Ok(self.get_by_handle(*tree)), } @@ -130,8 +210,8 @@ impl VmmRuntime { let v = mem::take(&mut self.store); - for entry in v.into_iter() { - res.push(Self::into_raw_parts(entry)); + for (_key, value) in v.into_iter() { + res.push(Self::into_raw_parts(value)); } res.into_boxed_slice() @@ -139,7 +219,8 @@ impl VmmRuntime { fn unload(&mut self, input: Box<[(usize, usize)], BuddyAllocator>) { for (offset, len) in input.into_iter() { - self.store.push(Self::from_raw_parts(offset, len)); + let x = Self::from_raw_parts(offset, len); + self.create_raw(x); } } @@ -149,6 +230,12 @@ impl VmmRuntime { coupon_trade: Option, handle: FixHandle, ) -> FixHandle { + if self.executed { + panic!("Multiple apply/eval/trade not supported yet.") + } + + self.executed = true; + let handle_scratch: Box<[u8], _> = Box::new_in(handle.pack(), BuddyAllocator); let output_store: Box<[usize], _> = Box::new_in([0; 2], BuddyAllocator); diff --git a/fix/evaluator/trade_script.txt b/fix/evaluator/trade_script.txt new file mode 100644 index 0000000..ee5c20f --- /dev/null +++ b/fix/evaluator/trade_script.txt @@ -0,0 +1,5 @@ +a = create_blob(Int(2)); +b = create_blob(Int(2)); +c = trade("EvalBlobObj", create_tree(), a, b); +show_coupon(c); +c diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index a7a20ee..9d164d6 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -180,6 +180,13 @@ impl CanonicalHandle { Self { inner } } + pub fn hash(&self) -> [u8; 32] { + let hash_64: &[u64; 4] = unsafe { core::mem::transmute(&self.inner.content) }; + unsafe { + core::mem::transmute::<[u64; 4], [u8; 32]>([hash_64[0], hash_64[1], hash_64[2], 0]) + } + } + pub fn len(&self) -> usize { let field: &[u64; 4] = unsafe { core::mem::transmute(&self.inner.content) }; (field[3] & 0xffffffffffff).try_into().unwrap() diff --git a/fix/runtime/Cargo.toml b/fix/runtime/Cargo.toml index 86cedb6..2fca18f 100644 --- a/fix/runtime/Cargo.toml +++ b/fix/runtime/Cargo.toml @@ -36,3 +36,5 @@ user = { path = "../../user", artifact = "bin", target = "x86_64-unknown-none" } async-lock = { version = "3.4.1", default-features = false } bytemuck = "1.24.0" bitfield-struct = "0.11.0" +blake3 = { version = "1.8.5", default-features = false } +hashbrown = { version = "0.17.1", features = ["alloc", "core"] } diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index 941540e..2a78220 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -3,8 +3,8 @@ use crate::{ // data::{BlobData, RawData, TreeData}, - fixruntime::FixRuntime, - runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, + fixruntime::{FixBlobData, FixRuntime, FixTreeData}, + runtime::{DeterministicEquivRuntime, Executor}, }; use arca::Runtime; @@ -51,23 +51,25 @@ impl<'a, 'b> DeterministicEquivRuntime for FixShellBottom<'a, 'b> { } fn create_blob(&mut self, data: Self::BlobData) -> Self::Handle { - pack_handle(&self.parent.create_blob(data)) + pack_handle(&self.parent.create_blob(FixBlobData::new(data))) } fn create_tree(&mut self, data: Self::TreeData) -> Self::Handle { - pack_handle(&self.parent.create_tree(data)) + pack_handle(&self.parent.create_tree(FixTreeData::new(data))) } fn get_blob(&self, handle: &Self::Handle) -> Result { self.parent .get_blob(&unpack_handle(handle)) .map_err(|_| Error::FixRuntimeError) + .map(|d| d.into()) } fn get_tree(&self, handle: &Self::Handle) -> Result { self.parent .get_tree(&unpack_handle(handle)) .map_err(|_| Error::FixRuntimeError) + .map(|d| d.into()) } fn is_blob(handle: &Self::Handle) -> bool { @@ -179,8 +181,8 @@ impl<'a, 'b> FixShellBottom<'a, 'b> { impl<'a, 'b> Executor for FixShellBottom<'a, 'b> { fn execute(&mut self, combination: &FixHandle) -> FixHandle { let tree = self.parent.get_tree(combination).unwrap(); - let function_handle = FixRuntime::<'_>::get_tree_entry(&tree, 0); - let elf = self.parent.get_blob(&function_handle).unwrap(); + let function_handle = tree.get(0); + let elf: Blob = self.parent.get_blob(&function_handle).unwrap().into(); let f = common::elfloader::load_elf(&elf).expect("Failed to load elf"); let f = Runtime::apply_function(f, Value::from(pack_handle(combination))); diff --git a/fix/runtime/src/common.rs b/fix/runtime/src/common.rs index e5932d5..2c5c218 100644 --- a/fix/runtime/src/common.rs +++ b/fix/runtime/src/common.rs @@ -39,6 +39,29 @@ impl TryFrom for CouponTrades { } } +impl TryFrom<&str> for CouponTrades { + type Error = (); + + fn try_from(value: &str) -> Result { + match value { + "EqTree" => Ok(CouponTrades::EqTree), + "EqApplication" => Ok(CouponTrades::EqApplication), + "ForceResultEq" => Ok(CouponTrades::ForceResultEq), + "EqStrictEncode" => Ok(CouponTrades::EqStrictEncode), + "ThinkApplication" => Ok(CouponTrades::ThinkApplication), + "ThinkToForce" => Ok(CouponTrades::ThinkToForce), + "ForceToEncodeStrict" => Ok(CouponTrades::ForceToEncodeStric), + "EvalEq" => Ok(CouponTrades::EvalEq), + "EvalBlobObj" => Ok(CouponTrades::EvalBlobObj), + "EvalTreeObj" => Ok(CouponTrades::EvalTreeObj), + "EqSym" => Ok(CouponTrades::EqSym), + "EqTrans" => Ok(CouponTrades::EqTrans), + "EqSelf" => Ok(CouponTrades::EqSelf), + _ => Err(()), + } + } +} + #[allow(unused)] #[repr(usize)] pub enum FixOp { diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 8d4708b..0ea0b58 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -5,8 +5,8 @@ use crate::{ bottom::FixShellBottom, common::CouponTrades, // data::{BlobData, TreeData}, - runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, - storage::{ObjectStore, Storage}, + runtime::{DeterministicEquivRuntime, Executor}, + storage::{FixData, ObjectStore, Storage}, }; use bytemuck::bytes_of; use common::bitpack::BitPack; @@ -27,40 +27,136 @@ impl From> for Error { } } +#[derive(Debug, Clone)] +pub struct FixBlobData { + inner: Blob, +} + +impl FixData for FixBlobData { + fn inner(self) -> Value { + self.inner.into() + } + + fn len(&self) -> u64 { + self.inner.len() as u64 + } +} + +impl From for FixBlobData { + fn from(value: Value) -> Self { + match value { + Value::Blob(b) => FixBlobData { inner: b }, + _ => todo!(), + } + } +} + +impl AsRef<[u8]> for FixBlobData { + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl FixBlobData { + pub fn new(inner: Blob) -> Self { + Self { inner } + } + + pub fn read(&self, offset: usize, buf: &mut [u8]) -> usize { + self.inner.read(offset, buf) + } +} + +#[derive(Debug, Clone)] +pub struct FixTreeData { + inner: Blob, +} + +impl FixData for FixTreeData { + fn inner(self) -> Value { + self.inner.into() + } + + fn len(&self) -> u64 { + self.inner.len() as u64 / 32 + } +} + +impl From for FixTreeData { + fn from(value: Value) -> Self { + match value { + Value::Blob(b) => FixTreeData { inner: b }, + _ => todo!(), + } + } +} + +impl AsRef<[u8]> for FixTreeData { + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl FixTreeData { + pub fn new(inner: Blob) -> Self { + Self { inner } + } + + pub fn get(&self, offset: usize) -> FixHandle { + let mut scratch: [u8; 32] = [0; 32]; + self.inner.read(offset * 32, &mut scratch); + FixHandle::unpack(scratch) + } +} + +impl From for Blob { + fn from(val: FixBlobData) -> Self { + val.inner + } +} + +impl From for Blob { + fn from(val: FixTreeData) -> Self { + val.inner + } +} + #[derive(Debug)] pub struct FixRuntime<'a> { - store: &'a mut ObjectStore, + store: &'a mut ObjectStore, coupon: FixHandle, } impl<'a> FixRuntime<'a> { - pub fn new(store: &'a mut ObjectStore, coupon: &[u8]) -> Self { - let coupon = Object::from(store.create_blob(coupon.into())).into(); + pub fn new(store: &'a mut ObjectStore, coupon: &[u8]) -> Self { + let coupon = Object::from(store.create_blob(FixBlobData::new(coupon.into()))).into(); Self { store, coupon } } } impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { - type BlobData = Blob; - type TreeData = Blob; + type BlobData = FixBlobData; + type TreeData = FixTreeData; type Handle = FixHandle; type Error = Error; fn create_blob_i32(&mut self, data: u32) -> Self::Handle { let buf = bytes_of(&data); - Object::from(self.store.create_blob(buf.into())).into() + let blob = Blob::new(buf); + Object::from(self.store.create_blob(FixBlobData::new(blob))).into() } fn create_blob_i64(&mut self, data: u64) -> Self::Handle { let buf = bytes_of(&data); - Object::from(self.store.create_blob(buf.into())).into() + let blob = Blob::new(buf); + Object::from(self.store.create_blob(FixBlobData::new(blob))).into() } - fn create_blob(&mut self, data: Blob) -> Self::Handle { + fn create_blob(&mut self, data: FixBlobData) -> Self::Handle { Object::from(self.store.create_blob(data)).into() } - fn create_tree(&mut self, data: Blob) -> Self::Handle { + fn create_tree(&mut self, data: FixTreeData) -> Self::Handle { Object::from(self.store.create_tree(data)).into() } @@ -79,7 +175,8 @@ impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { .map_err(Error::from)? .try_unwrap_tree_obj_ref() .map_err(Error::from)?; - Ok(self.store.get_tree(t)) + let tree = self.store.get_tree(t); + Ok(tree) } fn is_blob(handle: &Self::Handle) -> bool { @@ -125,7 +222,7 @@ impl<'a> Executor for FixRuntime<'a> { apply_coupon.extend_from_slice(&res.pack()); Object::from(TreeName::Tag( - self.create_tree(Blob::new(apply_coupon)) + self.create_tree(FixTreeData::new(Blob::new(apply_coupon))) .unwrap_object() .unwrap_tree_obj() .unwrap_not_tag(), @@ -134,22 +231,8 @@ impl<'a> Executor for FixRuntime<'a> { } } -impl<'a> CouponHelper for FixRuntime<'a> { - fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize { - blob.read(offset, buf) - } - - fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle { - let mut scratch: [u8; 32] = [0; 32]; - tree.read(offset * 32, &mut scratch); - FixHandle::unpack(scratch) - } - - fn get_tree_len(tree: &Self::TreeData) -> usize { - tree.len() / 32 - } - - fn trade( +impl FixRuntime<'_> { + pub fn trade( &mut self, trade_type: CouponTrades, coupons: FixHandle, @@ -163,8 +246,50 @@ impl<'a> CouponHelper for FixRuntime<'a> { combination.extend_from_slice(&lhs.pack()); combination.extend_from_slice(&rhs.pack()); - let combination = self.create_tree(Blob::new(combination)); + let combination = self.create_tree(FixTreeData::new(Blob::new(combination))); let mut bottom = FixShellBottom { parent: self }; bottom.execute(&combination) } + + fn coupon_type(&mut self, handle: &FixHandle) -> &'static str { + let mut arr = [0u8; 4]; + let blob = self.get_blob(handle).expect("Coupon type not a blob"); + blob.read(0, &mut arr); + let num = u32::from_le_bytes(arr); + match num { + 0 => "Eq", + 1 => "Eval", + 2 => "Apply", + 3 => "Force", + 4 => "Think", + 5 => "Storage", + _ => panic!(), + } + } + + pub fn show_coupon(&mut self, handle: &FixHandle) { + let ctype = self.get_coupon_type(handle); + let lhs = self.get_coupon_lhs(handle); + let rhs = self.get_coupon_rhs(handle); + + log::info!("type is: {ctype:?}"); + log::info!("lhs is: {lhs:?}"); + log::info!("rhs is: {rhs:?}"); + } + + fn get_coupon_type(&mut self, coupon: &FixHandle) -> &'static str { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + let handle = coupon_content.get(1); + self.coupon_type(&handle) + } + + pub fn get_coupon_lhs(&mut self, coupon: &FixHandle) -> FixHandle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + coupon_content.get(2) + } + + pub fn get_coupon_rhs(&mut self, coupon: &FixHandle) -> FixHandle { + let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); + coupon_content.get(3) + } } diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs index 27590c7..0edf1f0 100644 --- a/fix/runtime/src/runtime.rs +++ b/fix/runtime/src/runtime.rs @@ -1,8 +1,7 @@ use core::clone::Clone; use core::result::Result; -use crate::common::CouponTrades; -use fixhandle::rawhandle::{Encode, FixHandle, Object, Thunk}; +use fixhandle::rawhandle::FixHandle; #[allow(unused)] pub trait DeterministicEquivRuntime { @@ -35,90 +34,33 @@ pub trait Executor { fn execute(&mut self, combination: &FixHandle) -> FixHandle; } -#[allow(unused)] -pub trait CouponHelper: DeterministicEquivRuntime { - fn read_blob(blob: &Self::BlobData, offset: usize, buf: &mut [u8]) -> usize; - fn get_tree_entry(tree: &Self::TreeData, offset: usize) -> Self::Handle; - fn get_tree_len(tree: &Self::TreeData) -> usize; - - fn trade( - &mut self, - trade_type: CouponTrades, - coupons: FixHandle, - lhs: FixHandle, - rhs: FixHandle, - ) -> FixHandle; - - fn coupon_type(&mut self, handle: &Self::Handle) -> &'static str { - let mut arr = [0u8; 4]; - let blob = self.get_blob(handle).expect("Coupon type not a blob"); - Self::read_blob(&blob, 0, &mut arr); - let num = u32::from_le_bytes(arr); - match num { - 0 => "Eq", - 1 => "Eval", - 2 => "Apply", - 3 => "Force", - 4 => "Think", - 5 => "Storage", - _ => panic!(), - } - } - - fn show_coupon(&mut self, handle: &Self::Handle) { - let ctype = self.get_coupon_type(handle); - let lhs = self.get_coupon_lhs(handle); - let rhs = self.get_coupon_rhs(handle); - - log::info!("type is: {ctype:?}"); - log::info!("lhs is: {lhs:?}"); - log::info!("rhs is: {rhs:?}"); - } - - fn get_coupon_type(&mut self, coupon: &Self::Handle) -> &'static str { - let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - let handle = Self::get_tree_entry(&coupon_content, 1); - self.coupon_type(&handle) - } - - fn get_coupon_lhs(&mut self, coupon: &Self::Handle) -> Self::Handle { - let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - Self::get_tree_entry(&coupon_content, 2) - } - - fn get_coupon_rhs(&mut self, coupon: &Self::Handle) -> Self::Handle { - let coupon_content = self.get_tree(coupon).expect("Coupon not a tree"); - Self::get_tree_entry(&coupon_content, 3) - } -} - -#[allow(unused)] -pub trait Visitor: CouponHelper { - fn visit(&mut self, handle: FixHandle, callback: &mut F) - where - F: FnMut(&mut Self, &FixHandle), - { - match handle { - FixHandle::Encode(e) => match e { - Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback), - }, - FixHandle::Ref(_) => todo!(), - FixHandle::Thunk(t) => match t { - Thunk::Application(tree) => { - self.visit(FixHandle::Object(Object::from(tree)), callback) - } - _ => todo!(), - }, - FixHandle::Object(obj) => match obj { - Object::BlobObj(_) => {} - Object::TreeObj(_) => { - let tree_data = self.get_tree(&handle).unwrap(); - for i in 0..Self::get_tree_len(&tree_data) { - self.visit(Self::get_tree_entry(&tree_data, i), callback); - } - } - }, - }; - callback(self, &handle); - } -} +//#[allow(unused)] +//pub trait Visitor: CouponHelper { +// fn visit(&mut self, handle: FixHandle, callback: &mut F) +// where +// F: FnMut(&mut Self, &FixHandle), +// { +// match handle { +// FixHandle::Encode(e) => match e { +// Encode::Strict(t) | Encode::Shallow(t) => self.visit(FixHandle::Thunk(t), callback), +// }, +// FixHandle::Ref(_) => todo!(), +// FixHandle::Thunk(t) => match t { +// Thunk::Application(tree) => { +// self.visit(FixHandle::Object(Object::from(tree)), callback) +// } +// _ => todo!(), +// }, +// FixHandle::Object(obj) => match obj { +// Object::BlobObj(_) => {} +// Object::TreeObj(_) => { +// let tree_data = self.get_tree(&handle).unwrap(); +// for i in 0..Self::get_tree_len(&tree_data) { +// self.visit(Self::get_tree_entry(&tree_data, i), callback); +// } +// } +// }, +// }; +// callback(self, &handle); +// } +//} diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index 178e1de..169315b 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -1,109 +1,154 @@ // use crate::data::{BlobData, RawData, TreeData}; -use core::{mem, ptr, slice}; -use fixhandle::rawhandle::{BlobName, Handle, PhysicalHandle, TreeName}; +use core::{marker::PhantomData, mem, ptr, slice}; +use fixhandle::rawhandle::{BlobName, CanonicalHandle, Handle, LiteralHandle, TreeName}; +use hashbrown::HashMap; use kernel::prelude::*; +#[allow(unused)] #[derive(Debug)] struct RefCnt { inner: T, count: usize, } +#[allow(unused)] impl RefCnt { fn new(inner: T) -> Self { Self { inner, count: 0 } } } +pub trait FixData: From { + fn inner(self) -> Value; + fn len(&self) -> u64; + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[derive(Debug)] -struct RawObjectStore { - table: Vec>, +struct RawObjectStore { + store: HashMap<[u8; 32], Value>, } -impl Default for RawObjectStore { +impl Default for RawObjectStore { fn default() -> Self { - Self { table: vec![] } + Self { + store: HashMap::new(), + } } } -impl RawObjectStore { +impl RawObjectStore { fn new() -> Self { Self::default() } - fn create(&mut self, data: Data) -> usize { - let idx = self.table.len(); - self.table.push(RefCnt::new(data)); - idx + fn create_raw(&mut self, data: Blob) { + let hash = blake3::hash(data.as_ref()); + let bytes = hash.as_bytes(); + let canonical = CanonicalHandle::new(*bytes, 0); + self.store.insert(canonical.hash(), data.into()); } - fn get(&self, idx: usize) -> Data { - self.table[idx].inner.clone() + fn create>(&mut self, data: T) -> CanonicalHandle { + let hash = blake3::hash(data.as_ref()); + let hash = *hash.as_bytes(); + let handle = CanonicalHandle::new(hash, data.len()); + self.store.insert(handle.hash(), data.inner()); + handle } -} -pub trait Storage { - fn create_blob(&mut self, data: Blob) -> BlobName; - fn create_tree(&mut self, data: Blob) -> TreeName; - fn get_blob(&self, handle: &BlobName) -> Blob; - fn get_tree(&self, handle: &TreeName) -> Blob; + fn get(&self, key: &[u8; 32]) -> Value { + self.store + .get(key) + .expect("Failed to retrieve data") + .clone() + } } -#[derive(Default, Debug)] -pub struct ObjectStore { - store: RawObjectStore, +pub trait Storage, FixTreeData: FixData + AsRef<[u8]>> { + fn create_blob(&mut self, data: FixBlobData) -> BlobName; + fn create_tree(&mut self, data: FixTreeData) -> TreeName; + fn get_blob(&self, handle: &BlobName) -> FixBlobData; + fn get_tree(&self, handle: &TreeName) -> FixTreeData; } -impl ObjectStore { - pub fn new() -> Self { - Self::default() - } +#[derive(Debug)] +pub struct ObjectStore, FixTreeData: FixData + AsRef<[u8]>> { + store: RawObjectStore, + _blob: PhantomData, + _tree: PhantomData, } -impl Storage for ObjectStore { - fn create_blob(&mut self, data: Blob) -> BlobName { - let len = data.len(); - let local_id = self.store.create(data.into()); - BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) +impl, FixTreeData: FixData + AsRef<[u8]>> + Storage for ObjectStore +{ + fn create_blob(&mut self, data: FixBlobData) -> BlobName { + if data.len() < 30 { + BlobName::Literal(LiteralHandle::new(data.as_ref())) + } else { + let canonical = self.store.create(data); + BlobName::Blob(Handle::CanonicalHandle(canonical)) + } } - fn create_tree(&mut self, data: Blob) -> TreeName { - let len = data.len() / 32; - let local_id = self.store.create(data.into()); - TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) + fn create_tree(&mut self, data: FixTreeData) -> TreeName { + let canonical = self.store.create(data); + TreeName::NotTag(Handle::CanonicalHandle(canonical)) } - fn get_blob(&self, handle: &BlobName) -> Blob { + fn get_blob(&self, handle: &BlobName) -> FixBlobData { match handle { BlobName::Blob(h) => match h { Handle::VirtualHandle(_) => todo!(), - Handle::CanonicalHandle(_) => todo!(), - Handle::PhysicalHandle(physical_handle) => self - .store - .get(physical_handle.local_id()) - .try_into() - .unwrap(), + Handle::CanonicalHandle(c) => self.store.get(&c.hash()).into(), + Handle::PhysicalHandle(_) => todo!(), }, - BlobName::Literal(h) => Blob::new(h.content()), + BlobName::Literal(l) => { + let data: Value = Blob::new(l.content()).into(); + data.into() + } } } - fn get_tree(&self, handle: &TreeName) -> Blob { + fn get_tree(&self, handle: &TreeName) -> FixTreeData { match handle { TreeName::NotTag(t) | TreeName::Tag(t) => match t { Handle::VirtualHandle(_) => todo!(), - Handle::CanonicalHandle(_) => todo!(), - Handle::PhysicalHandle(physical_handle) => self - .store - .get(physical_handle.local_id()) - .try_into() - .unwrap(), + Handle::CanonicalHandle(c) => self.store.get(&c.hash()).into(), + Handle::PhysicalHandle(_) => todo!(), }, } } } -impl ObjectStore { +impl, FixTreeData: FixData + AsRef<[u8]>> Default + for ObjectStore +{ + fn default() -> Self { + Self::new() + } +} + +impl, FixTreeData: FixData + AsRef<[u8]>> + ObjectStore +{ + fn into(v: Value) -> Box<[u8]> { + match v { + Value::Blob(b) => b.into_inner().into_inner(), + _ => todo!(), + } + } + + pub fn new() -> Self { + Self { + store: RawObjectStore::default(), + _blob: Default::default(), + _tree: Default::default(), + } + } + pub fn into_raw_parts(input: Box<[T]>) -> (usize, usize) { let data = Box::into_raw(input); let len = ptr::metadata(data); @@ -130,20 +175,19 @@ impl ObjectStore { pub fn load(&mut self, input: Box<[(usize, usize)]>) { for (offset, len) in input.into_iter() { let x = Self::from_raw_parts(offset, len); - self.store.create(Blob::new(x).into()); + self.store.create_raw(Blob::new(x)); } - log::info!("Loaded {:?} objects", self.store.table.len()); + log::info!("Loaded {:?} objects", self.store.store.len()); } pub fn unload(&mut self) -> Box<[(usize, usize)]> { - let mut res = Vec::with_capacity(2 * 8 * self.store.table.len()); + let mut res = Vec::with_capacity(2 * 8 * self.store.store.len()); - let v = mem::take(&mut self.store.table); + let v = mem::take(&mut self.store.store); - for entry in v.into_iter() { - let blob: Blob = entry.inner.try_into().unwrap(); - let blob = blob.into_inner().into_inner(); - res.push(Self::into_raw_parts(blob)); + for (_key, value) in v.into_iter() { + let value: Box<[u8]> = Self::into(value); + res.push(Self::into_raw_parts(value)); } res.into_boxed_slice() diff --git a/fix/src/evaluator.rs b/fix/src/evaluator.rs index 6054f63..3875efa 100644 --- a/fix/src/evaluator.rs +++ b/fix/src/evaluator.rs @@ -2,8 +2,9 @@ use fixhandle::rawhandle::{Encode, FixHandle, Object, Ref, Thunk, TreeName}; use fixruntime::{ common::CouponTrades, - fixruntime::FixRuntime, - runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, + fixruntime::{FixRuntime, FixTreeData}, + runtime::{DeterministicEquivRuntime, Executor}, + storage::FixData, }; use common::bitpack::BitPack; @@ -47,7 +48,7 @@ fn think(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { let mut coupons = Vec::with_capacity(32 * 2); coupons.extend_from_slice(&eval_coupon.pack()); coupons.extend_from_slice(&apply_coupon.pack()); - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); let result = runtime.get_coupon_rhs(&apply_coupon); runtime.trade( CouponTrades::ThinkApplication, @@ -66,7 +67,7 @@ fn force(runtime: &mut FixRuntime, thunk: &Thunk) -> FixHandle { FixHandle::Object(_) | FixHandle::Ref(_) => { let mut coupons = Vec::with_capacity(32); coupons.extend_from_slice(&think_coupon.pack()); - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); runtime.trade( CouponTrades::ThinkToForce, @@ -88,7 +89,7 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { let mut coupons = Vec::with_capacity(32); coupons.extend_from_slice(&force_coupon.pack()); - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); runtime.trade( CouponTrades::ForceToEncodeStric, @@ -104,19 +105,19 @@ fn encode(runtime: &mut FixRuntime, encode: &Encode) -> FixHandle { fn eval_tree(runtime: &mut FixRuntime, handle: &TreeName) -> FixHandle { let tree_handle = FixHandle::from(Object::from(*handle)); let tree = runtime.get_tree(&tree_handle).unwrap(); - let tree_len = FixRuntime::<'_>::get_tree_len(&tree); + let tree_len = tree.len() as usize; let mut coupons = Vec::with_capacity(tree_len * 32); let mut new_tree = Vec::with_capacity(tree_len * 32); for i in 0..tree_len { - let eval_coupon = eval(runtime, FixRuntime::<'_>::get_tree_entry(&tree, i)); + let eval_coupon = eval(runtime, tree.get(i)); coupons.extend_from_slice(&eval_coupon.pack()); new_tree.extend_from_slice(&runtime.get_coupon_rhs(&eval_coupon).pack()); } - let coupons = runtime.create_tree(Blob::new(coupons)); - let new_tree = runtime.create_tree(Blob::new(new_tree)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); + let new_tree = runtime.create_tree(FixTreeData::new(Blob::new(new_tree))); runtime.trade(CouponTrades::EvalTreeObj, coupons, tree_handle, new_tree) } @@ -127,7 +128,7 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { FixHandle::Object(obj) => match obj { Object::BlobObj(_) => { let coupons = vec![0u8; 0]; - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); runtime.trade(CouponTrades::EvalBlobObj, coupons, handle, handle) } Object::TreeObj(tree) => eval_tree(runtime, &tree), @@ -142,14 +143,14 @@ pub fn eval(runtime: &mut FixRuntime, handle: FixHandle) -> FixHandle { let mut coupons = Vec::with_capacity(32); coupons.extend_from_slice(&eq_coupon.pack()); - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); let eq_coupon = runtime.trade(CouponTrades::EqSym, coupons, eq_rhs, eq_lhs); let result = runtime.get_coupon_rhs(&eval_coupon); let mut coupons = Vec::with_capacity(2 * 32); coupons.extend_from_slice(&eval_coupon.pack()); coupons.extend_from_slice(&eq_coupon.pack()); - let coupons = runtime.create_tree(Blob::new(coupons)); + let coupons = runtime.create_tree(FixTreeData::new(Blob::new(coupons))); runtime.trade(CouponTrades::EvalEq, coupons, handle, result) } } diff --git a/fix/src/main.rs b/fix/src/main.rs index 2a429a3..9c906e4 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -9,7 +9,7 @@ use fixhandle::rawhandle::FixHandle; use fixruntime::{ common::{CouponTrades, FixOp}, - runtime::{CouponHelper, DeterministicEquivRuntime, Executor}, + runtime::{DeterministicEquivRuntime, Executor}, }; use kernel::prelude::*; @@ -20,7 +20,9 @@ mod evaluator; use common::bitpack::BitPack; -use fixruntime::{fixruntime::FixRuntime, storage::ObjectStore}; +use fixruntime::{ + fixruntime::FixBlobData, fixruntime::FixRuntime, fixruntime::FixTreeData, storage::ObjectStore, +}; use crate::evaluator::eval; @@ -39,14 +41,19 @@ async fn main(args: &[usize]) { let (store_offset, store_len) = (args[4], args[5]); let (output_store_offset, output_store_len) = (args[6], args[7]); - let mut handle_scratch: Box<[u8]> = - ObjectStore::from_raw_parts(handle_scratch_offset, handle_scratch_len); + let mut handle_scratch: Box<[u8]> = ObjectStore::::from_raw_parts( + handle_scratch_offset, + handle_scratch_len, + ); let handle_slice: &mut [u8; 32] = handle_scratch.as_mut().try_into().unwrap(); let input_handle = FixHandle::unpack(*handle_slice); - let input_store: Box<[(usize, usize)]> = ObjectStore::from_raw_parts(store_offset, store_len); - let mut output_store: Box<[usize]> = - ObjectStore::from_raw_parts(output_store_offset, output_store_len); + let input_store: Box<[(usize, usize)]> = + ObjectStore::::from_raw_parts(store_offset, store_len); + let mut output_store: Box<[usize]> = ObjectStore::::from_raw_parts( + output_store_offset, + output_store_len, + ); let mut store = ObjectStore::new(); store.load(input_store); @@ -61,9 +68,9 @@ async fn main(args: &[usize]) { let input_tree = runtime .get_tree(&input_handle) .expect("Input handle is not a tree"); - let coupons = FixRuntime::<'_>::get_tree_entry(&input_tree, 0); - let lhs = FixRuntime::<'_>::get_tree_entry(&input_tree, 1); - let rhs = FixRuntime::<'_>::get_tree_entry(&input_tree, 2); + let coupons = input_tree.get(0); + let lhs = input_tree.get(1); + let rhs = input_tree.get(2); runtime.trade(trade_type, coupons, lhs, rhs) } @@ -73,7 +80,8 @@ async fn main(args: &[usize]) { .as_mut() .try_into() .expect("Failed to convert output store back"); - let (output_store_offset, output_store_len) = ObjectStore::into_raw_parts(store.unload()); + let (output_store_offset, output_store_len) = + ObjectStore::::into_raw_parts(store.unload()); output_store_slice[0] = output_store_offset; output_store_slice[1] = output_store_len; handle_slice.copy_from_slice(&result.pack()); diff --git a/kernel/src/kvmclock.rs b/kernel/src/kvmclock.rs index 51b888a..e761392 100644 --- a/kernel/src/kvmclock.rs +++ b/kernel/src/kvmclock.rs @@ -108,6 +108,7 @@ fn info_and_tsc_to_duration(info: CpuTimeInfo, tsc: u64) -> Duration { time >> -info.tsc_shift }; let time = time.widening_mul(info.tsc_to_system_mul as u64); + let time = (time as u64, (time >> 64) as u64); let time = (time.0 >> 32) | (time.1 << 32); let time = time.wrapping_add(info.system_time); Duration::from_nanos(time) From 4526c68e302dfba4e321d165eaeca406f4cc285c Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 20 May 2026 15:59:55 -0700 Subject: [PATCH 12/12] update readme --- fix/evaluator/README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/fix/evaluator/README.md b/fix/evaluator/README.md index 8204019..a507d3b 100644 --- a/fix/evaluator/README.md +++ b/fix/evaluator/README.md @@ -6,7 +6,16 @@ | `create_tree` | `handle, ...` | `handle` | creates a tree from one or more runtime handles | | `get_blob` | `handle` | `blobData` | fetches blob payload from runtime | | `get_tree` | `handle` | `treeData` | fetches tree payload from runtime | -| `apply` | `handle` | `handle` | applies the first member to all subsequent members as operands +| `apply` | `handle` | `handle` | applies the handle as the combination tree | +| `eval` | `handle` | `handle` | evals the handle | +| `trade` | `(trade_type: String, coupons: handle, lhs: handle, rhs: handle)` | `handle` | makes a coupon trade | +| `print` | `blobData` or `treeData` | () | prints the data | +| `show_coupon` | `handle` (must be a coupon) | () | shows the content of a coupon | +| `coupon_lhs` | `handle` (must be a coupon) | `handle` | returns the left hand side of a coupon | +| `coupon_rhs` | `handle` (must be a coupon) | `handle` | returns the right hand side of a coupon | +| `handle` | `"text"` where `text` is the first 8 digits of the hex-encoded handle name | `handle` | loads a canonical handle from `.fix` | +| `tag` | `"text"` where `text` is the first 8 digits of the hex-encoded tag name | `handle` | loads a canonical tag from `.fix` | + Inline comments using `//` @@ -17,12 +26,17 @@ fix-cli -- --path ### Examples -- cargo run -p evaluator --bin fix-cli hybrid --path fix/evaluator/add_script.txt -- cargo run -p evaluator --bin fix-cli mock -- 'print(get_blob(apply(create_tree(create_blob(String("+")), create_blob(Int(1)), apply(create_tree(create_blob(Path("fix/evaluator/add.txt")), create_blob(Int(2)), create_blob(Int(3))))))))' +- `cd fix; cargo run -p fix --target=x86_64-unknown-none -- -- --path evaluator/eval_script.txt` +- `cd fix; cargo run -p fix --target=x86_64-unknown-none -- -- --path evaluator/apply_script.txt` +- `cd fix; cargo run -p fix --target=x86_64-unknown-none -- -- --path evaluator/trade_script.txt` +- `cargo run -p evaluator --bin fix-cli hybrid ../target/x86_64-unknown-none/debug/fix -- \'eval(create_blob(Int(2)))\'` +- `cargo run -p evaluator --bin fix-cli hybrid ../target/x86_64-unknown-none/debug/fix -- \'a = create_blob(Int(2)); trade("EvalBlobObj", create_tree(), a, a)\'` +- `cargo run -p evaluator --bin fix-cli hybrid ../target/x86_64-unknown-none/debug/fix -- \'apply(create_tree(create_blob(Path("target/x86_64-unknown-none/addblob", create_blob(Int(2)), create_blob(Int(3))))))\'` +- `cargo run -p evaluator --bin fix-cli mock -- 'print(get_blob(coupon_rhs(apply(create_tree(create_blob(String("+")), create_blob(Int(1)), apply(create_tree(create_blob(Path("fix/evaluator/add.txt")), create_blob(Int(2)), create_blob(Int(3)))))))))'` ### Runtimes -- MemoryRuntime: Stores all blobs and trees in memory. Holds ownership so `get_blob()` and `get_tree()` only return references -- StorageRuntime: Writes all blobs and trees to ".fix/objects/". Holds no ownership so `get_blob()` and `get_tree()` return boxed bytes read from ".fix/objects/" -- HybridRuntime: Uses MemoryRuntime but supports "flush" and "flush_handle" operations to recursively write in-memory blobs and trees to ".fix/objects/" -- MockRuntime: Uses memory runtime and does naive addition for applications in `apply()` \ No newline at end of file +- MemoryRuntime: Stores all blobs and trees in memory. Holds ownership so `create_blob()` and `create_tree()` only return references +- StorageRuntime: Writes all blobs and trees to ".fix/objects/". Holds no ownership so `create_blob()` and `create_tree()` return boxed bytes read from ".fix/objects/" +- HybridRuntime: Runs `eval`, `trade` and `apply` in an instance of Fix-over-Arca. Uses MemoryRuntime but supports "flush" and "flush_handle" operations to recursively write in-memory blobs and trees to ".fix/objects/" +- MockRuntime: Uses memory runtime and does naive addition for applications in `apply()`