From 977f962a53f47421da4f56004dd9ab76dc14e209 Mon Sep 17 00:00:00 2001 From: Haibib Kerim Date: Tue, 12 May 2026 19:19:34 -0700 Subject: [PATCH 01/14] added evaluator frontend and runtime --- .gitignore | 1 + Cargo.lock | 42 ++++ Cargo.toml | 4 +- fix/evaluator/Cargo.toml | 10 + fix/evaluator/README.md | 28 +++ fix/evaluator/add.txt | 1 + fix/evaluator/add_script.txt | 8 + fix/evaluator/src/bin/cli.rs | 297 ++++++++++++++++++++++++++++ fix/evaluator/src/fixruntime.rs | 123 ++++++++++-- fix/evaluator/src/hybridruntime.rs | 124 ++++++++++++ fix/evaluator/src/lexer.rs | 94 +++++++++ fix/evaluator/src/lib.rs | 14 ++ fix/evaluator/src/main.rs | 13 +- fix/evaluator/src/memoryruntime.rs | 98 +++++++++ fix/evaluator/src/mockruntime.rs | 103 ++++++++++ fix/evaluator/src/parser.rs | 123 ++++++++++++ fix/evaluator/src/storageruntime.rs | 87 ++++++++ fix/evaluator/src/vmmruntime.rs | 30 +-- 18 files changed, 1154 insertions(+), 46 deletions(-) create mode 100644 fix/evaluator/README.md create mode 100644 fix/evaluator/add.txt create mode 100644 fix/evaluator/add_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 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..8ac0da3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,18 @@ dependencies = [ "derive_more", ] +[[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" @@ -326,6 +338,20 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[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 = "block2" version = "0.6.2" @@ -523,6 +549,12 @@ dependencies = [ "crossbeam-utils", ] +[[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.10.0" @@ -543,6 +575,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" @@ -688,6 +729,7 @@ name = "evaluator" version = "0.1.0" dependencies = [ "anyhow", + "blake3", "bytemuck", "clap", "common", 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/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 53166a6..7ae399a 100644 --- a/fix/evaluator/Cargo.toml +++ b/fix/evaluator/Cargo.toml @@ -14,6 +14,16 @@ env_logger = "0.11.10" log = "0.4.29" common = { path = "../../common" } bytemuck = "1.25.0" +blake3 = "1.8.5" [build-dependencies] anyhow = "1.0.97" + +[lib] +path = "src/lib.rs" + +[[bin]] +name = "fix-cli" +path = "src/bin/cli.rs" + +default-run = "fix-cli" \ No newline at end of file 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/add_script.txt b/fix/evaluator/add_script.txt new file mode 100644 index 0000000..fba8d10 --- /dev/null +++ b/fix/evaluator/add_script.txt @@ -0,0 +1,8 @@ +a = create_blob(Int(2)); +b = create_blob(Int(3)); +c = create_blob(Path("/home/yuhan/arca/target/x86_64-unknown-none/debug/build/fix-d7fc060e57fb79d3/out/addblob")); +d = create_tree(c, a, b); +e = create_blob(Int(1)); +f = create_tree(c, e, apply(d)); +g = apply(f); +print(get_blob(apply(f))); \ No newline at end of file diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs new file mode 100644 index 0000000..9c6cb3c --- /dev/null +++ b/fix/evaluator/src/bin/cli.rs @@ -0,0 +1,297 @@ +use common::bitpack::BitPack; +use evaluator::{ + fixruntime::{DeterministicEquivRuntime, Expr, Statement, Value}, + hybridruntime::HybridRuntime, + lexer::Lexer, + mockruntime::MockRuntime, + parser::Parser as ExprParser, +}; +use fixhandle::rawhandle::FixHandle; +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() { + // 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) => run(MockRuntime::new(), &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); + } + }; + run(HybridRuntime::new(smp, cid, bin), &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), + } +} + +fn run(mut runtime: R, commands: &str) -> Result<(), String> +where + R: DeterministicEquivRuntime, + ::Error: fmt::Debug, + for<'a> R::BlobData<'a>: AsRef<[u8]>, + for<'a> R::TreeData<'a>: AsRef<[u8]>, +{ + let output = evaluate_commands(&mut runtime, commands)?; + print!("{output}"); + 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(" ")), + } +} + +pub fn evaluate_commands(runtime: &mut R, commands: &str) -> Result +where + R: DeterministicEquivRuntime, + ::Error: fmt::Debug, + for<'a> R::BlobData<'a>: Clone + fmt::Debug, + for<'a> R::TreeData<'a>: Clone + fmt::Debug, +{ + let tokens = Lexer::new(commands).tokenize()?; + let program = ExprParser::new(&tokens).parse_program()?; + let mut evaluator = Evaluator::new(runtime); + + let mut output = String::new(); + for statement in program { + if let Some(text) = evaluator.evaluate_statement(statement)? { + output.push_str(&text); + } + } + Ok(output) +} + +type RuntimeValue = Value, Vec>; + +struct Evaluator<'a, R: DeterministicEquivRuntime> { + runtime: &'a mut R, + variables: BTreeMap, +} + +impl<'a, R> Evaluator<'a, R> +where + R: DeterministicEquivRuntime, + ::Error: fmt::Debug, + for<'b> R::BlobData<'b>: Clone + fmt::Debug, + for<'b> R::TreeData<'b>: Clone + fmt::Debug, +{ + fn new(runtime: &'a mut R) -> Self { + Self { + runtime, + variables: BTreeMap::new(), + } + } + + 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(format!("result: {}\n", self.evaluate_expr(expr)?))), + Statement::Expr(expr) => { + self.evaluate_expr(expr)?; + Ok(None) + } + } + } + + 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))) + } + "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())) + } + "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) + .map_err(|e| format!("{name}: {e:?}"))?; + Ok(Value::Handle(apply_handle)) + } + "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(&number.to_le_bytes())) + } + 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..5ec0a5f 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -1,27 +1,41 @@ -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>; + + // Placeholder + fn apply(&mut self, handle: &Self::Handle) -> Result { + Ok(handle.clone()) + } } #[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 +57,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", @@ -69,20 +83,20 @@ pub trait CouponHelper: DeterministicEquivRuntime { log::info!("rhs is: {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 +116,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 +140,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 +150,68 @@ pub trait Visitor: CouponHelper { callback(self, &handle); } } + +#[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), + 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..5907075 --- /dev/null +++ b/fix/evaluator/src/hybridruntime.rs @@ -0,0 +1,124 @@ +use crate::{ + fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError}, + storageruntime::StorageRuntime, + vmmruntime::VmmRuntime, +}; +use common::bitpack::BitPack; +use fixhandle::rawhandle::{BlobName, FixHandle, Object}; +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(), + } + } + + fn flush_handle(&mut self, handle: FixHandle) -> Result<[u8; 32], RuntimeError> { + let packed_handle = handle.pack(); + + if let Some(flushed_handle) = self.flushed.get(&packed_handle) { + return Ok(*flushed_handle); + } + + let canonical_handle = match handle { + FixHandle::Object(Object::BlobObj(blob_name)) => match blob_name { + // Store packed handle for literals + BlobName::Literal(_) => packed_handle, + // Write non-literals to storage + BlobName::Blob(_) => { + let blob_handle = FixHandle::Object(Object::BlobObj(blob_name)); + let blob = self.vmm_runtime.get_blob(&blob_handle)?; + self.storage_runtime.create_blob(blob).pack() + } + }, + FixHandle::Object(Object::TreeObj(_)) => { + 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); + } + + self.storage_runtime.create_tree(&bytes).pack() + } + _ => todo!(), + }; + + self.flushed.insert(packed_handle, canonical_handle); + Ok(canonical_handle) + } + + fn flush(&mut self) { + for handle in self.store.clone() { + let _ = self.flush_handle(handle); + } + } +} + +impl Drop for HybridRuntime { + fn drop(&mut self) { + self.flush(); + } +} + +impl CouponHelper for HybridRuntime {} + +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 { + let handle = self.vmm_runtime.create_blob(data); + self.store.push(handle); + handle + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + let handle = self.vmm_runtime.create_tree(data); + self.store.push(handle); + handle + } + + 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) + } + + fn apply(&mut self, handle: &Self::Handle) -> Result { + self.vmm_runtime.apply(handle) + } +} 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..6b354de 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -1,22 +1,15 @@ #![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 { 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..409a082 --- /dev/null +++ b/fix/evaluator/src/mockruntime.rs @@ -0,0 +1,103 @@ +use crate::{ + fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError}, + memoryruntime::MemoryRuntime, +}; +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) + } + + fn apply(&mut self, handle: &Self::Handle) -> Result { + let span = self.get_tree(handle)?; + if span.len() < 3 { + return Err(RuntimeError::OOB); + } + + let tree_entry = Self::get_tree_entry(span, 0); + let function = self.get_blob(&tree_entry)?; + if function != b"+" { + return Err(RuntimeError::UnexpectedFunction); + } + + let left_bytes: [u8; 8] = self + .get_blob(&Self::get_tree_entry(span, 1))? + .try_into() + .map_err(|_| RuntimeError::OOB)?; + let left = u64::from_le_bytes(left_bytes); + let right_bytes: [u8; 8] = self + .get_blob(&Self::get_tree_entry(span, 2))? + .try_into() + .map_err(|_| RuntimeError::OOB)?; + let right = u64::from_le_bytes(right_bytes); + + Ok(self.create_blob_i64(left + right)) + } +} + +impl CouponHelper for MockRuntime {} + +#[cfg(test)] +mod tests { + use super::*; + #[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(Rc::from(*b"+")); + + let tree = mock_runtime.create_tree(Rc::from([plus_literal, one_literal, two_literal])); + let result = mock_runtime.apply(&tree).expect("valid apply addition"); + + assert_eq!( + mock_runtime.get_blob(&result).expect("valid result blob"), + Rc::from(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..3b01225 --- /dev/null +++ b/fix/evaluator/src/parser.rs @@ -0,0 +1,123 @@ +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::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..7164c76 --- /dev/null +++ b/fix/evaluator/src/storageruntime.rs @@ -0,0 +1,87 @@ +use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; +use common::bitpack::BitPack; +use fixhandle::rawhandle::CanonicalHandle; +use std::{fmt::Write, fs, path::PathBuf}; + +pub struct StorageRuntime { + objects_dir: PathBuf, +} + +impl Default for StorageRuntime { + fn default() -> Self { + Self::new() + } +} + +impl StorageRuntime { + pub fn new() -> Self { + let objects_dir = PathBuf::from(".fix/objects"); + fs::create_dir_all(&objects_dir).expect("failed to create objects directory"); + Self { objects_dir } + } + + fn write(&self, data: &[u8]) -> CanonicalHandle { + let handle = CanonicalHandle::new(Self::hash(data), data.len() as u64); + let path = self + .objects_dir + .join(Self::hexadecimal_encode(&handle.pack())); + fs::write(&path, data).expect("failed to write runtime object"); + handle + } + + 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 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 + } +} + +impl DeterministicEquivRuntime for StorageRuntime { + type BlobData<'a> = Box<[u8]>; + type TreeData<'a> = Box<[u8]>; + type Handle = CanonicalHandle; + 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 { + self.write(data) + } + + fn create_tree(&mut self, data: &[u8]) -> Self::Handle { + self.write(data) + } + + 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) + } +} diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index a95ee1f..08ca3d6 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -9,7 +9,7 @@ use fixhandle::rawhandle::{ }; 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 { @@ -44,20 +44,22 @@ impl VmmRuntime { } 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); @@ -69,19 +71,19 @@ impl DeterministicEquivRuntime for VmmRuntime { } } - fn create_tree(&mut self, data: &[u8]) -> FixHandle { + fn create_tree(&mut self, data: Self::TreeData<'_>) -> 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<'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 +91,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)), } From e67d4eb8da83889da7f3c43abfe8dd26323ab10e Mon Sep 17 00:00:00 2001 From: Haibib Kerim Date: Thu, 14 May 2026 14:14:39 -0700 Subject: [PATCH 02/14] add hybrid runtime to main.rs --- .github/workflows/compile.yml | 6 +-- fix/evaluator/src/bin/cli.rs | 13 +++---- fix/evaluator/src/fixruntime.rs | 5 --- fix/evaluator/src/hybridruntime.rs | 57 +++++++++++++++++++++++----- fix/evaluator/src/main.rs | 11 ++---- fix/evaluator/src/mockruntime.rs | 60 +++++++++++++++++++++--------- 6 files changed, 102 insertions(+), 50 deletions(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 2935dee..6c4a943 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 $(find . -name "addblob" | tail -n 1) eval + sudo -su $USER /home/runner/.cargo/bin/cargo run -p evaluator --bin 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 --bin evaluator -- target/x86_64-unknown-none/debug/fix $(find . -name "addblob" | tail -n 1) trade diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index 9c6cb3c..aa400bb 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -1,6 +1,6 @@ use common::bitpack::BitPack; use evaluator::{ - fixruntime::{DeterministicEquivRuntime, Expr, Statement, Value}, + fixruntime::{DeterministicEquivRuntime, Expr, Operator, Statement, Value}, hybridruntime::HybridRuntime, lexer::Lexer, mockruntime::MockRuntime, @@ -95,7 +95,7 @@ fn split_args(args: Vec) -> (Vec, Vec) { fn run(mut runtime: R, commands: &str) -> Result<(), String> where - R: DeterministicEquivRuntime, + R: DeterministicEquivRuntime + Operator, ::Error: fmt::Debug, for<'a> R::BlobData<'a>: AsRef<[u8]>, for<'a> R::TreeData<'a>: AsRef<[u8]>, @@ -126,7 +126,7 @@ fn read_commands(args: Vec) -> Result { pub fn evaluate_commands(runtime: &mut R, commands: &str) -> Result where - R: DeterministicEquivRuntime, + R: DeterministicEquivRuntime + Operator, ::Error: fmt::Debug, for<'a> R::BlobData<'a>: Clone + fmt::Debug, for<'a> R::TreeData<'a>: Clone + fmt::Debug, @@ -153,7 +153,7 @@ struct Evaluator<'a, R: DeterministicEquivRuntime> { impl<'a, R> Evaluator<'a, R> where - R: DeterministicEquivRuntime, + R: DeterministicEquivRuntime + Operator, ::Error: fmt::Debug, for<'b> R::BlobData<'b>: Clone + fmt::Debug, for<'b> R::TreeData<'b>: Clone + fmt::Debug, @@ -233,10 +233,7 @@ where "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) - .map_err(|e| format!("{name}: {e:?}"))?; + let apply_handle = self.runtime.apply(handle); Ok(Value::Handle(apply_handle)) } "print" => self.evaluate_expr(self.get_arg(name, &args)?.clone()), diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index 5ec0a5f..78a55ff 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -23,11 +23,6 @@ pub trait DeterministicEquivRuntime { 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>; - - // Placeholder - fn apply(&mut self, handle: &Self::Handle) -> Result { - Ok(handle.clone()) - } } #[allow(unused)] diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 5907075..910dbe0 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -1,10 +1,13 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, storageruntime::StorageRuntime, + vmcommon::CouponTrades, vmmruntime::VmmRuntime, }; use common::bitpack::BitPack; -use fixhandle::rawhandle::{BlobName, FixHandle, Object}; +use fixhandle::rawhandle::{ + BlobName, Encode, FixHandle, Object, Thunk, create_application_thunk, create_strict_encode, +}; use std::{collections::HashMap, sync::Arc}; pub struct HybridRuntime { @@ -46,21 +49,33 @@ impl HybridRuntime { FixHandle::Object(Object::TreeObj(_)) => { 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); } - self.storage_runtime.create_tree(&bytes).pack() } - _ => todo!(), + FixHandle::Encode(Encode::Strict(tree)) => { + let inner = self.flush_handle(FixHandle::Thunk(tree))?; + create_strict_encode(&FixHandle::unpack(inner)) + .expect("strict encode flush failed") + .pack() + } + FixHandle::Encode(Encode::Shallow(_tree)) => todo!(""), + FixHandle::Thunk(Thunk::Application(tree)) => { + let tree_handle = FixHandle::Object(Object::from(tree)); + let flushed_tree = FixHandle::unpack(self.flush_handle(tree_handle)?); + create_application_thunk(&flushed_tree) + .expect("application thunk flush failed") + .pack() + } + FixHandle::Thunk(_) => todo!(""), + FixHandle::Ref(_) => todo!(""), }; self.flushed.insert(packed_handle, canonical_handle); @@ -80,8 +95,6 @@ impl Drop for HybridRuntime { } } -impl CouponHelper for HybridRuntime {} - impl DeterministicEquivRuntime for HybridRuntime { type BlobData<'a> = &'a [u8]; type TreeData<'a> = &'a [u8]; @@ -117,8 +130,32 @@ impl DeterministicEquivRuntime for HybridRuntime { 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 eval(&mut self, handle: FixHandle) -> FixHandle { + let output_handle = self.vmm_runtime.eval(handle); + self.store.push(output_handle); + output_handle + } + + fn trade( + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle { + let output_handle = self.vmm_runtime.trade(trade_type, coupons, lhs, rhs); + self.store.push(output_handle); + output_handle + } - fn apply(&mut self, handle: &Self::Handle) -> Result { - self.vmm_runtime.apply(handle) + fn apply(&mut self, handle: FixHandle) -> FixHandle { + let output_handle = self.vmm_runtime.apply(handle); + self.store.push(output_handle); + output_handle } } diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 6b354de..5706584 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -1,6 +1,3 @@ -#![feature(allocator_api)] -#![feature(ptr_metadata)] -#![feature(result_option_map_or_default)] use common::bitpack::BitPack; use evaluator::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; @@ -8,8 +5,8 @@ use std::path::PathBuf; use std::sync::Arc; use clap::Parser; +use evaluator::hybridruntime::HybridRuntime; use evaluator::vmcommon::CouponTrades; -use evaluator::vmmruntime::VmmRuntime; #[derive(Parser, Debug)] struct Args { @@ -23,7 +20,7 @@ struct Args { } fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { - let mut rt = VmmRuntime::new(smp, cid, bin); + let mut rt = HybridRuntime::new(smp, cid, bin); let function = rt.create_blob(module); let addend1 = rt.create_blob_i64(3); @@ -60,7 +57,7 @@ fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { } fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { - let mut rt = VmmRuntime::new(smp, cid, bin); + let mut rt = HybridRuntime::new(smp, cid, bin); let function = rt.create_blob(module); let addend1 = rt.create_blob_i64(3); @@ -85,7 +82,7 @@ fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { } fn test_trade(smp: usize, cid: usize, bin: Arc<[u8]>) { - let mut rt = VmmRuntime::new(smp, cid, bin); + let mut rt = HybridRuntime::new(smp, cid, bin); let addend = rt.create_blob_i64(3); let scratch = Vec::with_capacity(0); diff --git a/fix/evaluator/src/mockruntime.rs b/fix/evaluator/src/mockruntime.rs index 409a082..db223da 100644 --- a/fix/evaluator/src/mockruntime.rs +++ b/fix/evaluator/src/mockruntime.rs @@ -1,6 +1,7 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, memoryruntime::MemoryRuntime, + vmcommon::CouponTrades, }; use fixhandle::rawhandle::FixHandle; @@ -51,53 +52,78 @@ impl DeterministicEquivRuntime for MockRuntime { 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 apply(&mut self, handle: &Self::Handle) -> Result { - let span = self.get_tree(handle)?; + fn eval(&mut self, _handle: FixHandle) -> FixHandle { + todo!() + } + + fn apply(&mut self, handle: FixHandle) -> FixHandle { + let span = self.get_tree(&handle).expect("Tree exists"); if span.len() < 3 { - return Err(RuntimeError::OOB); + panic!("Tree OOB"); } let tree_entry = Self::get_tree_entry(span, 0); - let function = self.get_blob(&tree_entry)?; + let function = self + .get_blob(&tree_entry) + .expect("Tree has addition function"); if function != b"+" { - return Err(RuntimeError::UnexpectedFunction); + panic!("First element not additon"); } let left_bytes: [u8; 8] = self - .get_blob(&Self::get_tree_entry(span, 1))? + .get_blob(&Self::get_tree_entry(span, 1)) + .expect("Left i64 OOB") .try_into() - .map_err(|_| RuntimeError::OOB)?; + .expect("Left i64 improper size"); let left = u64::from_le_bytes(left_bytes); let right_bytes: [u8; 8] = self - .get_blob(&Self::get_tree_entry(span, 2))? + .get_blob(&Self::get_tree_entry(span, 2)) + .expect("Right i64 OOB") .try_into() - .map_err(|_| RuntimeError::OOB)?; + .expect("Right i64 improper size"); let right = u64::from_le_bytes(right_bytes); - Ok(self.create_blob_i64(left + right)) + self.create_blob_i64(left + right) } } -impl CouponHelper for MockRuntime {} - #[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(Rc::from(*b"+")); + let plus_literal = mock_runtime.create_blob(b"+"); - let tree = mock_runtime.create_tree(Rc::from([plus_literal, one_literal, two_literal])); - let result = mock_runtime.apply(&tree).expect("valid apply addition"); + 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"), - Rc::from(3_i64.to_le_bytes()) + 3_i64.to_le_bytes() ); } } From 2ef6e1a6aec9cbf5007c84d753e71210ecacc2f6 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 14 May 2026 13:15:23 -0700 Subject: [PATCH 03/14] feat: create symlink to wasm outputs --- .github/workflows/compile.yml | 6 +++--- fix/build.rs | 9 +++++++-- fix/evaluator/add_script.txt | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 6c4a943..e1429ef 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 --bin 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 --bin 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 --bin 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 -- 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 -- 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 -- target/x86_64-unknown-none/debug/fix target/x86_64-unknown-none/addblob trade 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/add_script.txt b/fix/evaluator/add_script.txt index fba8d10..d763e1e 100644 --- a/fix/evaluator/add_script.txt +++ b/fix/evaluator/add_script.txt @@ -1,8 +1,8 @@ a = create_blob(Int(2)); b = create_blob(Int(3)); -c = create_blob(Path("/home/yuhan/arca/target/x86_64-unknown-none/debug/build/fix-d7fc060e57fb79d3/out/addblob")); +c = create_blob(Path("../target/x86_64-unknown-none/addblob")); d = create_tree(c, a, b); e = create_blob(Int(1)); f = create_tree(c, e, apply(d)); g = apply(f); -print(get_blob(apply(f))); \ No newline at end of file +print(get_blob(apply(f))); From b6311261bb99a2fae647565631a33dff3622a2b9 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 14 May 2026 15:47:29 -0700 Subject: [PATCH 04/14] feat: change fix runner to evaluator --- fix/.cargo/config.toml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 fix/.cargo/config.toml diff --git a/fix/.cargo/config.toml b/fix/.cargo/config.toml new file mode 100644 index 0000000..7ec5ddc --- /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 evaluator --" From 4d2306e6d3e8f4e43dc01d31cf5248c793bc9548 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 14 May 2026 18:40:47 -0700 Subject: [PATCH 05/14] feat: add create_thunk and create_encode and eval --- .../{add_script.txt => apply_script.txt} | 7 +- fix/evaluator/eval_script.txt | 10 +++ fix/evaluator/src/bin/cli.rs | 79 ++++++++++++++----- fix/evaluator/src/fixruntime.rs | 7 +- fix/evaluator/src/hybridruntime.rs | 40 ++++------ fix/evaluator/src/main.rs | 19 +++-- fix/evaluator/src/mockruntime.rs | 36 ++++----- fix/evaluator/src/parser.rs | 8 ++ fix/evaluator/src/vmmruntime.rs | 8 ++ 9 files changed, 134 insertions(+), 80 deletions(-) rename fix/evaluator/{add_script.txt => apply_script.txt} (58%) create mode 100644 fix/evaluator/eval_script.txt diff --git a/fix/evaluator/add_script.txt b/fix/evaluator/apply_script.txt similarity index 58% rename from fix/evaluator/add_script.txt rename to fix/evaluator/apply_script.txt index d763e1e..245ba1a 100644 --- a/fix/evaluator/add_script.txt +++ b/fix/evaluator/apply_script.txt @@ -2,7 +2,6 @@ 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_tree(c, e, apply(d)); -g = apply(f); -print(get_blob(apply(f))); +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..30450a4 --- /dev/null +++ b/fix/evaluator/eval_script.txt @@ -0,0 +1,10 @@ +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))); +show_coupon(h); +h diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index aa400bb..e546f2f 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -1,12 +1,12 @@ use common::bitpack::BitPack; use evaluator::{ - fixruntime::{DeterministicEquivRuntime, Expr, Operator, Statement, Value}, + fixruntime::{DeterministicEquivRuntime, Expr, Statement, Value, CouponHelper, Operator}, hybridruntime::HybridRuntime, lexer::Lexer, mockruntime::MockRuntime, parser::Parser as ExprParser, }; -use fixhandle::rawhandle::FixHandle; +use fixhandle::rawhandle::{FixHandle, create_application_thunk, create_strict_encode}; use std::{ collections::BTreeMap, env, fmt, fs, @@ -95,13 +95,16 @@ fn split_args(args: Vec) -> (Vec, Vec) { fn run(mut runtime: R, commands: &str) -> Result<(), String> where - R: DeterministicEquivRuntime + Operator, + R: CouponHelper + Operator, ::Error: fmt::Debug, for<'a> R::BlobData<'a>: AsRef<[u8]>, for<'a> R::TreeData<'a>: AsRef<[u8]>, { - let output = evaluate_commands(&mut runtime, commands)?; + let (output, output_handle) = evaluate_commands(&mut runtime, commands)?; print!("{output}"); + if let Some(h) = output_handle { + println!("{h:?}"); + } Ok(()) } @@ -124,24 +127,28 @@ fn read_commands(args: Vec) -> Result { } } -pub fn evaluate_commands(runtime: &mut R, commands: &str) -> Result +pub fn evaluate_commands(runtime: &mut R, commands: &str) -> Result<(String, Option), String> where - R: DeterministicEquivRuntime + Operator, - ::Error: fmt::Debug, - for<'a> R::BlobData<'a>: Clone + fmt::Debug, - for<'a> R::TreeData<'a>: Clone + fmt::Debug, + R: Operator + CouponHelper, + for<'a> R::BlobData<'a>: AsRef<[u8]>, + for<'a> R::TreeData<'a>: AsRef<[u8]>, { let tokens = Lexer::new(commands).tokenize()?; let program = ExprParser::new(&tokens).parse_program()?; let mut evaluator = Evaluator::new(runtime); let mut output = String::new(); + let mut output_handle: Option = None; for statement in program { if let Some(text) = evaluator.evaluate_statement(statement)? { - output.push_str(&text); + match text { + Value::String(s) => { output.push_str(&s); output.push('\n') }, + Value::Handle(h) => output_handle = Some(h), + _ => todo!() + }; } } - Ok(output) + Ok((output, output_handle)) } type RuntimeValue = Value, Vec>; @@ -153,10 +160,9 @@ struct Evaluator<'a, R: DeterministicEquivRuntime> { impl<'a, R> Evaluator<'a, R> where - R: DeterministicEquivRuntime + Operator, - ::Error: fmt::Debug, - for<'b> R::BlobData<'b>: Clone + fmt::Debug, - for<'b> R::TreeData<'b>: Clone + fmt::Debug, + R: CouponHelper + Operator, + for<'b> R::BlobData<'b>: AsRef<[u8]>, + for<'b> R::TreeData<'b>: AsRef<[u8]>, { fn new(runtime: &'a mut R) -> Self { Self { @@ -165,17 +171,26 @@ where } } - fn evaluate_statement(&mut self, statement: Statement) -> Result, String> { + 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(format!("result: {}\n", self.evaluate_expr(expr)?))), + Statement::Print(expr) => Ok(Some(Value::String(format!("result: {}\n", 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) => { - self.evaluate_expr(expr)?; - Ok(None) + let result = self.evaluate_expr(expr)?; + Ok(Some(result)) } } } @@ -212,6 +227,18 @@ where } 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)?; @@ -233,9 +260,19 @@ where "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); + 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)) + } "print" => self.evaluate_expr(self.get_arg(name, &args)?.clone()), "mock" | "hybrid" => { if args.is_empty() { @@ -258,7 +295,7 @@ where }; match self.evaluate_expr(inner.clone())? { Value::Int(number) if name == "Int" => { - Ok(self.runtime.create_blob(&number.to_le_bytes())) + Ok(self.runtime.create_blob_i64(number as u64)) } Value::String(string) if name == "String" => { Ok(self.runtime.create_blob(string.as_bytes())) diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index 78a55ff..00a5e86 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -68,14 +68,12 @@ where } } - 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(&self, coupon: &Self::Handle) -> &'static str { @@ -180,6 +178,7 @@ pub enum Expr { pub enum Statement { Assign { name: String, expr: Expr }, Print(Expr), + ShowCoupon(Expr), Expr(Expr), } diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 910dbe0..37ecae4 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -1,8 +1,8 @@ use crate::{ fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, storageruntime::StorageRuntime, - vmcommon::CouponTrades, vmmruntime::VmmRuntime, + vmcommon::CouponTrades, }; use common::bitpack::BitPack; use fixhandle::rawhandle::{ @@ -112,15 +112,11 @@ impl DeterministicEquivRuntime for HybridRuntime { } fn create_blob(&mut self, data: &[u8]) -> Self::Handle { - let handle = self.vmm_runtime.create_blob(data); - self.store.push(handle); - handle + self.vmm_runtime.create_blob(data) } fn create_tree(&mut self, data: &[u8]) -> Self::Handle { - let handle = self.vmm_runtime.create_tree(data); - self.store.push(handle); - handle + self.vmm_runtime.create_tree(data) } fn get_blob<'a>(&'a self, handle: &'a Self::Handle) -> Result, Self::Error> { @@ -135,27 +131,21 @@ impl DeterministicEquivRuntime for HybridRuntime { impl CouponHelper for HybridRuntime {} impl Operator for HybridRuntime { - fn eval(&mut self, handle: FixHandle) -> FixHandle { - let output_handle = self.vmm_runtime.eval(handle); - self.store.push(output_handle); - output_handle + fn apply(&mut self, handle: FixHandle) -> FixHandle { + self.vmm_runtime.apply(handle) } - fn trade( - &mut self, - trade_type: CouponTrades, - coupons: FixHandle, - lhs: FixHandle, - rhs: FixHandle, - ) -> FixHandle { - let output_handle = self.vmm_runtime.trade(trade_type, coupons, lhs, rhs); - self.store.push(output_handle); - output_handle + fn eval(&mut self, handle: FixHandle) -> FixHandle { + self.vmm_runtime.eval(handle) } - fn apply(&mut self, handle: FixHandle) -> FixHandle { - let output_handle = self.vmm_runtime.apply(handle); - self.store.push(output_handle); - output_handle + fn trade( + &mut self, + _trade_type: CouponTrades, + _coupons: FixHandle, + _lhs: FixHandle, + _rhs: FixHandle, + ) -> FixHandle { + todo!() } } diff --git a/fix/evaluator/src/main.rs b/fix/evaluator/src/main.rs index 5706584..4b70533 100644 --- a/fix/evaluator/src/main.rs +++ b/fix/evaluator/src/main.rs @@ -1,3 +1,8 @@ +#![allow(unused)] +#![feature(allocator_api)] +#![feature(ptr_metadata)] +#![feature(result_option_map_or_default)] + use common::bitpack::BitPack; use evaluator::fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator}; use fixhandle::rawhandle::{create_application_thunk, create_strict_encode}; @@ -5,8 +10,8 @@ use std::path::PathBuf; use std::sync::Arc; use clap::Parser; -use evaluator::hybridruntime::HybridRuntime; use evaluator::vmcommon::CouponTrades; +use evaluator::vmmruntime::VmmRuntime; #[derive(Parser, Debug)] struct Args { @@ -20,7 +25,7 @@ struct Args { } fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { - let mut rt = HybridRuntime::new(smp, cid, bin); + let mut rt = VmmRuntime::new(smp, cid, bin); let function = rt.create_blob(module); let addend1 = rt.create_blob_i64(3); @@ -46,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"); @@ -57,7 +62,7 @@ fn test_eval(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { } fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { - let mut rt = HybridRuntime::new(smp, cid, bin); + let mut rt = VmmRuntime::new(smp, cid, bin); let function = rt.create_blob(module); let addend1 = rt.create_blob_i64(3); @@ -71,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"); @@ -82,14 +87,14 @@ fn test_apply(smp: usize, cid: usize, bin: Arc<[u8]>, module: &[u8]) { } fn test_trade(smp: usize, cid: usize, bin: Arc<[u8]>) { - let mut rt = HybridRuntime::new(smp, cid, bin); + 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()); 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/mockruntime.rs b/fix/evaluator/src/mockruntime.rs index db223da..2465927 100644 --- a/fix/evaluator/src/mockruntime.rs +++ b/fix/evaluator/src/mockruntime.rs @@ -1,5 +1,5 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError, Operator}, memoryruntime::MemoryRuntime, vmcommon::CouponTrades, }; @@ -58,12 +58,12 @@ impl CouponHelper for MockRuntime {} impl Operator for MockRuntime { 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 { todo!() } @@ -72,30 +72,28 @@ impl Operator for MockRuntime { } fn apply(&mut self, handle: FixHandle) -> FixHandle { - let span = self.get_tree(&handle).expect("Tree exists"); + let span = self.get_tree(&handle).unwrap(); if span.len() < 3 { - panic!("Tree OOB"); + panic!() + // return Err(RuntimeError::OOB); } let tree_entry = Self::get_tree_entry(span, 0); - let function = self - .get_blob(&tree_entry) - .expect("Tree has addition function"); + let function = self.get_blob(&tree_entry).unwrap(); if function != b"+" { - panic!("First element not additon"); + panic!() + // return Err(RuntimeError::UnexpectedFunction); } let left_bytes: [u8; 8] = self - .get_blob(&Self::get_tree_entry(span, 1)) - .expect("Left i64 OOB") + .get_blob(&Self::get_tree_entry(span, 1)).unwrap() .try_into() - .expect("Left i64 improper size"); + .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)) - .expect("Right i64 OOB") + .get_blob(&Self::get_tree_entry(span, 2)).unwrap() .try_into() - .expect("Right i64 improper size"); + .map_err(|_| RuntimeError::OOB).unwrap(); let right = u64::from_le_bytes(right_bytes); self.create_blob_i64(left + right) diff --git a/fix/evaluator/src/parser.rs b/fix/evaluator/src/parser.rs index 3b01225..cca1f6f 100644 --- a/fix/evaluator/src/parser.rs +++ b/fix/evaluator/src/parser.rs @@ -37,6 +37,14 @@ impl<'a> Parser<'a> { 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' '=' diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index 08ca3d6..f71124c 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -15,6 +15,7 @@ use crate::vmcommon::{CouponTrades, FixOp}; pub struct VmmRuntime { runtime: Runtime, store: Vec>, + executed: bool, } impl VmmRuntime { @@ -22,6 +23,7 @@ impl VmmRuntime { Self { runtime: Runtime::new(cid, smp, 1 << 34, bin), store: Vec::new(), + executed: false, } } @@ -151,6 +153,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); From 1788cbd14f7f7fba7f3af01dea7d921e0be5666c Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 14 May 2026 19:22:18 -0700 Subject: [PATCH 06/14] fix: flushing --- fix/evaluator/src/bin/cli.rs | 82 +++++++++++++++++------------ fix/evaluator/src/hybridruntime.rs | 30 ++++++----- fix/evaluator/src/storageruntime.rs | 29 +++++----- 3 files changed, 81 insertions(+), 60 deletions(-) diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index e546f2f..2b41cd9 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -45,7 +45,7 @@ fn main() { let (runtime_args, command_args) = split_args(args.collect()); let result = match runtime_name.as_str() { "mock" => match read_commands(command_args) { - Ok(commands) => run(MockRuntime::new(), &commands), + Ok(commands) => MockRuntime::new().run(&commands), Err(error) => { eprintln!("Error - {error}"); process::exit(1); @@ -74,7 +74,7 @@ fn main() { process::exit(1); } }; - run(HybridRuntime::new(smp, cid, bin), &commands) + HybridRuntime::new(smp, cid, bin).run(&commands) } // "storage" => run(StorageRuntime::new(), &commands), other => Err(format!("expected 'mock|hybrid' but got '{other}'")), @@ -93,20 +93,38 @@ fn split_args(args: Vec) -> (Vec, Vec) { } } -fn run(mut runtime: R, commands: &str) -> Result<(), String> -where - R: CouponHelper + Operator, - ::Error: fmt::Debug, - for<'a> R::BlobData<'a>: AsRef<[u8]>, - for<'a> R::TreeData<'a>: AsRef<[u8]>, +trait Run { + fn run(&mut self, commands: &str) -> Result<(), String> + where + Self: CouponHelper + Operator, + ::Error: fmt::Debug, + for<'a> Self::BlobData<'a>: AsRef<[u8]>, + for<'a> Self::TreeData<'a>: AsRef<[u8]>, { - let (output, output_handle) = evaluate_commands(&mut runtime, commands)?; + let (output, output_handle) = Evaluator::new(self).evaluate_commands(commands)?; print!("{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)?; + print!("{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(); @@ -127,20 +145,35 @@ fn read_commands(args: Vec) -> Result { } } -pub fn evaluate_commands(runtime: &mut R, commands: &str) -> Result<(String, Option), String> +type RuntimeValue = Value, Vec>; + +struct Evaluator<'a, R: DeterministicEquivRuntime + ?Sized> { + runtime: &'a mut R, + variables: BTreeMap, +} + +impl<'a, R: ?Sized> Evaluator<'a, R> where - R: Operator + CouponHelper, - for<'a> R::BlobData<'a>: AsRef<[u8]>, - for<'a> R::TreeData<'a>: AsRef<[u8]>, + R: CouponHelper + Operator, + 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 evaluator = Evaluator::new(runtime); let mut output = String::new(); let mut output_handle: Option = None; for statement in program { - if let Some(text) = evaluator.evaluate_statement(statement)? { + if let Some(text) = self.evaluate_statement(statement)? { match text { Value::String(s) => { output.push_str(&s); output.push('\n') }, Value::Handle(h) => output_handle = Some(h), @@ -151,25 +184,6 @@ where Ok((output, output_handle)) } -type RuntimeValue = Value, Vec>; - -struct Evaluator<'a, R: DeterministicEquivRuntime> { - runtime: &'a mut R, - variables: BTreeMap, -} - -impl<'a, R> Evaluator<'a, R> -where - R: CouponHelper + Operator, - 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_statement(&mut self, statement: Statement) -> Result, String> { diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 37ecae4..4b5af7a 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -6,7 +6,7 @@ use crate::{ }; use common::bitpack::BitPack; use fixhandle::rawhandle::{ - BlobName, Encode, FixHandle, Object, Thunk, create_application_thunk, create_strict_encode, + BlobName, TreeName, Encode, FixHandle, Object, Thunk, create_application_thunk, create_strict_encode }; use std::{collections::HashMap, sync::Arc}; @@ -28,25 +28,25 @@ impl HybridRuntime { } } - fn flush_handle(&mut self, handle: FixHandle) -> Result<[u8; 32], RuntimeError> { + 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(*flushed_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(_) => packed_handle, + BlobName::Literal(_) => handle, // Write non-literals to storage BlobName::Blob(_) => { let blob_handle = FixHandle::Object(Object::BlobObj(blob_name)); let blob = self.vmm_runtime.get_blob(&blob_handle)?; - self.storage_runtime.create_blob(blob).pack() + self.storage_runtime.create_blob(blob) } }, - FixHandle::Object(Object::TreeObj(_)) => { + 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) { @@ -56,29 +56,33 @@ impl HybridRuntime { let mut bytes = Vec::with_capacity(tree.len()); for child in children { let flushed = self.flush_handle(child)?; - bytes.extend_from_slice(&flushed); + bytes.extend_from_slice(&flushed.pack()); } - self.storage_runtime.create_tree(&bytes).pack() + + let treename = self.storage_runtime.create_tree(&bytes).unwrap_object().unwrap_tree_obj().unwrap_not_tag(); + let treename = match in_treename { + TreeName::Tag(_) => TreeName::Tag(treename), + 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(&FixHandle::unpack(inner)) + create_strict_encode(&inner) .expect("strict encode flush failed") - .pack() } FixHandle::Encode(Encode::Shallow(_tree)) => todo!(""), FixHandle::Thunk(Thunk::Application(tree)) => { let tree_handle = FixHandle::Object(Object::from(tree)); - let flushed_tree = FixHandle::unpack(self.flush_handle(tree_handle)?); + let flushed_tree = self.flush_handle(tree_handle)?; create_application_thunk(&flushed_tree) .expect("application thunk flush failed") - .pack() } FixHandle::Thunk(_) => todo!(""), FixHandle::Ref(_) => todo!(""), }; - self.flushed.insert(packed_handle, canonical_handle); + self.flushed.insert(packed_handle, canonical_handle.pack()); Ok(canonical_handle) } diff --git a/fix/evaluator/src/storageruntime.rs b/fix/evaluator/src/storageruntime.rs index 7164c76..37e9e04 100644 --- a/fix/evaluator/src/storageruntime.rs +++ b/fix/evaluator/src/storageruntime.rs @@ -1,6 +1,6 @@ use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; use common::bitpack::BitPack; -use fixhandle::rawhandle::CanonicalHandle; +use fixhandle::rawhandle::{BlobName, TreeName, CanonicalHandle, FixHandle, Object, Handle}; use std::{fmt::Write, fs, path::PathBuf}; pub struct StorageRuntime { @@ -20,15 +20,6 @@ impl StorageRuntime { Self { objects_dir } } - fn write(&self, data: &[u8]) -> CanonicalHandle { - let handle = CanonicalHandle::new(Self::hash(data), data.len() as u64); - let path = self - .objects_dir - .join(Self::hexadecimal_encode(&handle.pack())); - fs::write(&path, data).expect("failed to write runtime object"); - handle - } - fn read(&self, handle: &[u8]) -> Result, RuntimeError> { let path = self.objects_dir.join(Self::hexadecimal_encode(handle)); fs::read(path) @@ -54,7 +45,7 @@ impl StorageRuntime { impl DeterministicEquivRuntime for StorageRuntime { type BlobData<'a> = Box<[u8]>; type TreeData<'a> = Box<[u8]>; - type Handle = CanonicalHandle; + type Handle = FixHandle; type Error = RuntimeError; fn create_blob_i32(&mut self, data: u32) -> Self::Handle { @@ -66,11 +57,23 @@ impl DeterministicEquivRuntime for StorageRuntime { } fn create_blob(&mut self, data: &[u8]) -> Self::Handle { - self.write(data) + 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 { - self.write(data) + 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> { From 3b09d257ef990d82ecbaa5ef21dae2e056865827 Mon Sep 17 00:00:00 2001 From: Haibib Kerim Date: Thu, 14 May 2026 20:17:03 -0700 Subject: [PATCH 07/14] formatting --- fix/evaluator/Cargo.toml | 5 +- fix/evaluator/src/bin/cli.rs | 103 ++++++++++++++-------------- fix/evaluator/src/hybridruntime.rs | 32 +++++---- fix/evaluator/src/mockruntime.rs | 26 ++++--- fix/evaluator/src/storageruntime.rs | 8 ++- 5 files changed, 90 insertions(+), 84 deletions(-) diff --git a/fix/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 7ae399a..0dbebfd 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" } @@ -24,6 +25,4 @@ path = "src/lib.rs" [[bin]] name = "fix-cli" -path = "src/bin/cli.rs" - -default-run = "fix-cli" \ No newline at end of file +path = "src/bin/cli.rs" \ No newline at end of file diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index 2b41cd9..ad5c5c3 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -1,6 +1,6 @@ use common::bitpack::BitPack; use evaluator::{ - fixruntime::{DeterministicEquivRuntime, Expr, Statement, Value, CouponHelper, Operator}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, Expr, Operator, Statement, Value}, hybridruntime::HybridRuntime, lexer::Lexer, mockruntime::MockRuntime, @@ -94,36 +94,35 @@ fn split_args(args: Vec) -> (Vec, Vec) { } trait Run { - fn run(&mut self, commands: &str) -> Result<(), String> - where - Self: CouponHelper + Operator, - ::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)?; - print!("{output}"); - if let Some(h) = output_handle { - println!("{h:?}"); + fn run(&mut self, commands: &str) -> Result<(), String> + where + Self: CouponHelper + Operator, + ::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)?; + print!("{output}"); + if let Some(h) = output_handle { + println!("{h:?}"); + } + Ok(()) } - 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)?; - print!("{output}"); - if let Some(h) = output_handle { - let flushed = self.flush_handle(h).map_err(|e| format!("{e:?}"))?; + let (output, output_handle) = Evaluator::new(self).evaluate_commands(commands)?; + print!("{output}"); + if let Some(h) = output_handle { + let flushed = self.flush_handle(h).map_err(|e| format!("{e:?}"))?; let h = flushed; - println!("{h:?}"); - } - Ok(()) + println!("{h:?}"); + } + Ok(()) } - } fn read_commands(args: Vec) -> Result { @@ -165,39 +164,41 @@ where } } - fn evaluate_commands(&mut self, commands: &str) -> Result<(String, Option), String> -{ - let tokens = Lexer::new(commands).tokenize()?; - let program = ExprParser::new(&tokens).parse_program()?; + 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) => { output.push_str(&s); output.push('\n') }, - Value::Handle(h) => output_handle = Some(h), - _ => todo!() - }; + 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) => { + output.push_str(&s); + output.push('\n') + } + Value::Handle(h) => output_handle = Some(h), + _ => todo!(), + }; + } } + Ok((output, output_handle)) } - Ok((output, output_handle)) -} - - fn evaluate_statement(&mut self, statement: Statement) -> Result, String> - { + 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!("result: {}\n", self.evaluate_expr(expr)?)))), + Statement::Print(expr) => Ok(Some(Value::String(format!( + "result: {}\n", + 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()) } @@ -244,13 +245,15 @@ where "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")?; + 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")?; + let handle = + create_strict_encode(&handle).map_err(|_| "Failed to create strict encode")?; Ok(Value::Handle(handle)) } "get_blob" => { @@ -274,17 +277,13 @@ where "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); + 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); + let eval_handle = self.runtime.eval(handle); Ok(Value::Handle(eval_handle)) } "print" => self.evaluate_expr(self.get_arg(name, &args)?.clone()), @@ -308,9 +307,7 @@ where 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::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())) } diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 4b5af7a..760d5ed 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -1,12 +1,13 @@ use crate::{ fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, storageruntime::StorageRuntime, - vmmruntime::VmmRuntime, vmcommon::CouponTrades, + vmmruntime::VmmRuntime, }; use common::bitpack::BitPack; use fixhandle::rawhandle::{ - BlobName, TreeName, Encode, FixHandle, Object, Thunk, create_application_thunk, create_strict_encode + BlobName, Encode, FixHandle, Object, Thunk, TreeName, create_application_thunk, + create_strict_encode, }; use std::{collections::HashMap, sync::Arc}; @@ -59,24 +60,27 @@ impl HybridRuntime { bytes.extend_from_slice(&flushed.pack()); } - let treename = self.storage_runtime.create_tree(&bytes).unwrap_object().unwrap_tree_obj().unwrap_not_tag(); + let treename = self + .storage_runtime + .create_tree(&bytes) + .unwrap_object() + .unwrap_tree_obj() + .unwrap_not_tag(); let treename = match in_treename { TreeName::Tag(_) => TreeName::Tag(treename), - TreeName::NotTag(_) => TreeName::NotTag(treename) + 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") + 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") + create_application_thunk(&flushed_tree).expect("application thunk flush failed") } FixHandle::Thunk(_) => todo!(""), FixHandle::Ref(_) => todo!(""), @@ -144,12 +148,12 @@ impl Operator for HybridRuntime { } 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 { todo!() } } diff --git a/fix/evaluator/src/mockruntime.rs b/fix/evaluator/src/mockruntime.rs index 2465927..2b858df 100644 --- a/fix/evaluator/src/mockruntime.rs +++ b/fix/evaluator/src/mockruntime.rs @@ -1,5 +1,5 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, RuntimeError, Operator}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, memoryruntime::MemoryRuntime, vmcommon::CouponTrades, }; @@ -58,12 +58,12 @@ impl CouponHelper for MockRuntime {} impl Operator for MockRuntime { 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 { todo!() } @@ -86,14 +86,18 @@ impl Operator for MockRuntime { } let left_bytes: [u8; 8] = self - .get_blob(&Self::get_tree_entry(span, 1)).unwrap() + .get_blob(&Self::get_tree_entry(span, 1)) + .unwrap() .try_into() - .map_err(|_| RuntimeError::OOB).unwrap(); + .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() + .get_blob(&Self::get_tree_entry(span, 2)) + .unwrap() .try_into() - .map_err(|_| RuntimeError::OOB).unwrap(); + .map_err(|_| RuntimeError::OOB) + .unwrap(); let right = u64::from_le_bytes(right_bytes); self.create_blob_i64(left + right) diff --git a/fix/evaluator/src/storageruntime.rs b/fix/evaluator/src/storageruntime.rs index 37e9e04..524230c 100644 --- a/fix/evaluator/src/storageruntime.rs +++ b/fix/evaluator/src/storageruntime.rs @@ -1,6 +1,6 @@ use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; use common::bitpack::BitPack; -use fixhandle::rawhandle::{BlobName, TreeName, CanonicalHandle, FixHandle, Object, Handle}; +use fixhandle::rawhandle::{BlobName, CanonicalHandle, FixHandle, Handle, Object, TreeName}; use std::{fmt::Write, fs, path::PathBuf}; pub struct StorageRuntime { @@ -58,7 +58,8 @@ impl DeterministicEquivRuntime for StorageRuntime { fn create_blob(&mut self, data: &[u8]) -> Self::Handle { let handle = CanonicalHandle::new(Self::hash(data), data.len() as u64); - let handle: FixHandle = Object::from(BlobName::Blob(Handle::CanonicalHandle(handle))).into(); + let handle: FixHandle = + Object::from(BlobName::Blob(Handle::CanonicalHandle(handle))).into(); let path = self .objects_dir .join(Self::hexadecimal_encode(&handle.pack())); @@ -68,7 +69,8 @@ impl DeterministicEquivRuntime for StorageRuntime { 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 handle: FixHandle = + Object::from(TreeName::NotTag(Handle::CanonicalHandle(handle))).into(); let path = self .objects_dir .join(Self::hexadecimal_encode(&handle.pack())); From 59651ff75e7815c638b2a278ce1a9bb98520e4ce Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 14 May 2026 21:06:25 -0700 Subject: [PATCH 08/14] feat: add trade --- fix/evaluator/Cargo.toml | 2 +- fix/evaluator/src/bin/cli.rs | 22 ++++++++++++++++++++++ fix/evaluator/src/hybridruntime.rs | 14 +++++++------- fix/evaluator/trade_script.txt | 5 +++++ fix/runtime/src/common.rs | 23 +++++++++++++++++++++++ 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 fix/evaluator/trade_script.txt diff --git a/fix/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 0dbebfd..32ea4cc 100644 --- a/fix/evaluator/Cargo.toml +++ b/fix/evaluator/Cargo.toml @@ -25,4 +25,4 @@ path = "src/lib.rs" [[bin]] name = "fix-cli" -path = "src/bin/cli.rs" \ No newline at end of file +path = "src/bin/cli.rs" diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index ad5c5c3..dc3f1d6 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -5,6 +5,7 @@ use evaluator::{ lexer::Lexer, mockruntime::MockRuntime, parser::Parser as ExprParser, + vmcommon::CouponTrades, }; use fixhandle::rawhandle::{FixHandle, create_application_thunk, create_strict_encode}; use std::{ @@ -286,6 +287,27 @@ where 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)) + } "print" => self.evaluate_expr(self.get_arg(name, &args)?.clone()), "mock" | "hybrid" => { if args.is_empty() { diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 760d5ed..3d06ff2 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -148,12 +148,12 @@ impl Operator for HybridRuntime { } fn trade( - &mut self, - _trade_type: CouponTrades, - _coupons: FixHandle, - _lhs: FixHandle, - _rhs: FixHandle, - ) -> FixHandle { - todo!() + &mut self, + trade_type: CouponTrades, + coupons: FixHandle, + lhs: FixHandle, + rhs: FixHandle, + ) -> FixHandle { + self.vmm_runtime.trade(trade_type, coupons, lhs, rhs) } } 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/runtime/src/common.rs b/fix/runtime/src/common.rs index e5932d5..f1ff2de 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), + "ForceToEncodeStric" => 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 { From afe7487d63e81e159f9fb4f39d166052fcb45752 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Fri, 15 May 2026 13:00:58 -0700 Subject: [PATCH 09/14] feat: add tags directory --- fix/evaluator/src/hybridruntime.rs | 13 ++++++------- fix/evaluator/src/storageruntime.rs | 24 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index 3d06ff2..c123b9b 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -67,7 +67,11 @@ impl HybridRuntime { .unwrap_tree_obj() .unwrap_not_tag(); let treename = match in_treename { - TreeName::Tag(_) => TreeName::Tag(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)) @@ -90,6 +94,7 @@ impl HybridRuntime { Ok(canonical_handle) } + #[allow(unused)] fn flush(&mut self) { for handle in self.store.clone() { let _ = self.flush_handle(handle); @@ -97,12 +102,6 @@ impl HybridRuntime { } } -impl Drop for HybridRuntime { - fn drop(&mut self) { - self.flush(); - } -} - impl DeterministicEquivRuntime for HybridRuntime { type BlobData<'a> = &'a [u8]; type TreeData<'a> = &'a [u8]; diff --git a/fix/evaluator/src/storageruntime.rs b/fix/evaluator/src/storageruntime.rs index 524230c..f1f0e28 100644 --- a/fix/evaluator/src/storageruntime.rs +++ b/fix/evaluator/src/storageruntime.rs @@ -1,10 +1,11 @@ use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; use common::bitpack::BitPack; use fixhandle::rawhandle::{BlobName, CanonicalHandle, FixHandle, Handle, Object, TreeName}; -use std::{fmt::Write, fs, path::PathBuf}; +use std::{fmt::Write, fs, os::unix::fs::symlink, path::PathBuf}; pub struct StorageRuntime { objects_dir: PathBuf, + tags_dir: PathBuf, } impl Default for StorageRuntime { @@ -16,8 +17,10 @@ impl Default for StorageRuntime { 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"); - Self { objects_dir } + fs::create_dir_all(&tags_dir).expect("failed to create objects directory"); + Self { objects_dir, tags_dir } } fn read(&self, handle: &[u8]) -> Result, RuntimeError> { @@ -90,3 +93,20 @@ impl DeterministicEquivRuntime for StorageRuntime { 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 tree_path = self.objects_dir.join(Self::hexadecimal_encode(&tree_handle.pack())); + let tag_path = self.tags_dir.join(Self::hexadecimal_encode(&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), + } + } +} From b6a5083a7575953b791dd3d2c0794f372e408b77 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Fri, 15 May 2026 15:49:37 -0700 Subject: [PATCH 10/14] feat: janky canonical coupon collector --- .github/workflows/compile.yml | 6 +- Cargo.lock | 700 +++++++++++++++++++++++++++- fix/.cargo/config.toml | 2 +- fix/Cargo.toml | 1 + fix/evaluator/Cargo.toml | 2 + fix/evaluator/src/bin/cli.rs | 57 ++- fix/evaluator/src/fixruntime.rs | 7 + fix/evaluator/src/hybridruntime.rs | 73 ++- fix/evaluator/src/mockruntime.rs | 14 +- fix/evaluator/src/storageruntime.rs | 112 ++++- fix/runtime/Cargo.toml | 1 + fix/runtime/src/common.rs | 4 +- fix/runtime/src/fixruntime.rs | 33 +- vmm/src/runtime.rs | 1 + 14 files changed, 954 insertions(+), 59 deletions(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index e1429ef..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 target/x86_64-unknown-none/addblob eval - sudo -su $USER /home/runner/.cargo/bin/cargo run -p 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 -- target/x86_64-unknown-none/debug/fix target/x86_64-unknown-none/addblob 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/Cargo.lock b/Cargo.lock index 8ac0da3..351289b 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" @@ -120,7 +132,7 @@ version = "0.1.0" dependencies = [ "autotools", "bindgen", - "derive_more", + "derive_more 2.1.1", ] [[package]] @@ -338,6 +350,15 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake3" version = "1.8.5" @@ -352,6 +373,15 @@ dependencies = [ "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" version = "0.6.2" @@ -374,11 +404,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" @@ -529,7 +585,7 @@ dependencies = [ "arca", "async-channel", "async-lock", - "derive_more", + "derive_more 2.1.1", "elf", "hashbrown 0.15.5", "libc", @@ -549,12 +605,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" @@ -596,6 +679,22 @@ 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" @@ -607,6 +706,41 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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" @@ -616,13 +750,46 @@ 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]] @@ -631,7 +798,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", @@ -639,6 +806,17 @@ 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" @@ -685,6 +863,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" @@ -735,6 +933,8 @@ dependencies = [ "common", "env_logger", "fixhandle", + "hex", + "io", "log", "vmm", ] @@ -783,12 +983,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", @@ -804,12 +1005,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]] @@ -820,11 +1031,12 @@ dependencies = [ "arcane", "async-lock", "bitfield-struct 0.11.0", + "blake3", "bytemuck", "chrono", "chumsky", "common", - "derive_more", + "derive_more 2.1.1", "fixhandle", "futures", "kernel", @@ -850,6 +1062,12 @@ 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" @@ -958,6 +1176,84 @@ dependencies = [ "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" @@ -976,6 +1272,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" @@ -985,6 +1353,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" @@ -1030,6 +1408,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" @@ -1062,6 +1472,18 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "io" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba460b987a14c5de30128ae8c1fb69f60b622b71317dd4f6e187722f09550c1" +dependencies = [ + "gmeta", + "gstd", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1124,6 +1546,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" @@ -1151,6 +1588,15 @@ version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +[[package]] +name = "libc-print" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a660208db49e35faf57b37484350f1a61072f2a5becf0592af6015d9ddd4b0" +dependencies = [ + "libc", +] + [[package]] name = "libloading" version = "0.8.9" @@ -1318,18 +1764,66 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1420,6 +1914,28 @@ 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" @@ -1559,6 +2075,12 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[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" version = "1.0.1" @@ -1599,6 +2121,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" @@ -1673,6 +2293,12 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "smol" version = "2.0.2" @@ -1758,12 +2384,30 @@ dependencies = [ "windows-sys 0.59.0", ] +[[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" @@ -1918,6 +2562,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" @@ -1961,6 +2635,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" @@ -2013,6 +2693,12 @@ dependencies = [ "nix", ] +[[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" diff --git a/fix/.cargo/config.toml b/fix/.cargo/config.toml index 7ec5ddc..d1ab66c 100644 --- a/fix/.cargo/config.toml +++ b/fix/.cargo/config.toml @@ -5,4 +5,4 @@ rustflags = [ "-C", "relocation-model=static", # "-C", "target-feature=+crt-static", ] -runner = "cargo run -p evaluator --bin evaluator --" +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/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 32ea4cc..14613a2 100644 --- a/fix/evaluator/Cargo.toml +++ b/fix/evaluator/Cargo.toml @@ -16,6 +16,8 @@ log = "0.4.29" common = { path = "../../common" } bytemuck = "1.25.0" blake3 = "1.8.5" +io = "0.0.2" +hex = "0.4.3" [build-dependencies] anyhow = "1.0.97" diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index dc3f1d6..a75fcaa 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -1,6 +1,8 @@ use common::bitpack::BitPack; use evaluator::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, Expr, Operator, Statement, Value}, + fixruntime::{ + CouponHelper, DeterministicEquivRuntime, ExpandHandle, Expr, Operator, Statement, Value, + }, hybridruntime::HybridRuntime, lexer::Lexer, mockruntime::MockRuntime, @@ -97,7 +99,7 @@ fn split_args(args: Vec) -> (Vec, Vec) { trait Run { fn run(&mut self, commands: &str) -> Result<(), String> where - Self: CouponHelper + Operator, + Self: CouponHelper + Operator + ExpandHandle, ::Error: fmt::Debug, for<'a> Self::BlobData<'a>: AsRef<[u8]>, for<'a> Self::TreeData<'a>: AsRef<[u8]>, @@ -154,7 +156,7 @@ struct Evaluator<'a, R: DeterministicEquivRuntime + ?Sized> impl<'a, R: ?Sized> Evaluator<'a, R> where - R: CouponHelper + Operator, + R: CouponHelper + Operator + ExpandHandle, for<'b> R::BlobData<'b>: AsRef<[u8]>, for<'b> R::TreeData<'b>: AsRef<[u8]>, { @@ -289,10 +291,13 @@ where } "trade" => { assert!(args.len() == 4); - let coupon_trade= self.evaluate_expr(args[0].clone()).map_err(|_| "Failed to evaluate coupon trade")?; + 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")) + 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())?; @@ -308,6 +313,46 @@ where 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() { diff --git a/fix/evaluator/src/fixruntime.rs b/fix/evaluator/src/fixruntime.rs index 00a5e86..eeaeb43 100644 --- a/fix/evaluator/src/fixruntime.rs +++ b/fix/evaluator/src/fixruntime.rs @@ -144,6 +144,13 @@ where } } +#[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, diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index c123b9b..b6dc3bf 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -1,12 +1,12 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, + 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, + BlobName, Encode, FixHandle, Handle, Object, Thunk, TreeName, create_application_thunk, create_strict_encode, }; use std::{collections::HashMap, sync::Arc}; @@ -41,13 +41,24 @@ impl HybridRuntime { // Store packed handle for literals BlobName::Literal(_) => handle, // Write non-literals to storage - BlobName::Blob(_) => { - let blob_handle = FixHandle::Object(Object::BlobObj(blob_name)); - let blob = self.vmm_runtime.get_blob(&blob_handle)?; - self.storage_runtime.create_blob(blob) - } + BlobName::Blob(h) => match h { + Handle::CanonicalHandle(_) => handle, + _ => { + let blob_handle = FixHandle::Object(Object::BlobObj(blob_name)); + let blob = self.vmm_runtime.get_blob(&blob_handle)?; + self.storage_runtime.create_blob(blob) + } + }, }, FixHandle::Object(Object::TreeObj(in_treename)) => { + let h = match in_treename { + TreeName::Tag(h) | TreeName::NotTag(h) => h, + }; + + if let Handle::CanonicalHandle(_) = h { + return Ok(handle); + } + 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) { @@ -67,11 +78,13 @@ impl HybridRuntime { .unwrap_tree_obj() .unwrap_not_tag(); let treename = match in_treename { - TreeName::Tag(_) => { + TreeName::Tag(_) => { let result = TreeName::Tag(treename); - self.storage_runtime.create_tag(&result).expect("Failed to create tag"); + self.storage_runtime + .create_tag(&result) + .expect("Failed to create tag"); result - }, + } TreeName::NotTag(_) => TreeName::NotTag(treename), }; FixHandle::Object(Object::TreeObj(treename)) @@ -147,12 +160,40 @@ impl Operator for HybridRuntime { } 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 { 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/mockruntime.rs b/fix/evaluator/src/mockruntime.rs index 2b858df..f98cd4b 100644 --- a/fix/evaluator/src/mockruntime.rs +++ b/fix/evaluator/src/mockruntime.rs @@ -1,5 +1,5 @@ use crate::{ - fixruntime::{CouponHelper, DeterministicEquivRuntime, Operator, RuntimeError}, + fixruntime::{CouponHelper, DeterministicEquivRuntime, ExpandHandle, Operator, RuntimeError}, memoryruntime::MemoryRuntime, vmcommon::CouponTrades, }; @@ -104,6 +104,18 @@ impl Operator for MockRuntime { } } +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::*; diff --git a/fix/evaluator/src/storageruntime.rs b/fix/evaluator/src/storageruntime.rs index f1f0e28..2bf682f 100644 --- a/fix/evaluator/src/storageruntime.rs +++ b/fix/evaluator/src/storageruntime.rs @@ -1,7 +1,11 @@ use crate::fixruntime::{DeterministicEquivRuntime, RuntimeError}; use common::bitpack::BitPack; -use fixhandle::rawhandle::{BlobName, CanonicalHandle, FixHandle, Handle, Object, TreeName}; -use std::{fmt::Write, fs, os::unix::fs::symlink, path::PathBuf}; +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, @@ -20,7 +24,10 @@ impl StorageRuntime { 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 } + Self { + objects_dir, + tags_dir, + } } fn read(&self, handle: &[u8]) -> Result, RuntimeError> { @@ -30,6 +37,13 @@ impl StorageRuntime { .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); @@ -43,6 +57,10 @@ impl StorageRuntime { } hex_name } + + fn hexadecimal_decode(handle: &str) -> [u8; 32] { + <[u8; 32]>::from_hex(handle).expect("Failed to decode hex") + } } impl DeterministicEquivRuntime for StorageRuntime { @@ -60,14 +78,18 @@ impl DeterministicEquivRuntime for StorageRuntime { } fn create_blob(&mut self, data: &[u8]) -> Self::Handle { - 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 + 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 { @@ -99,14 +121,72 @@ impl StorageRuntime { 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 tree_path = self.objects_dir.join(Self::hexadecimal_encode(&tree_handle.pack())); - let tag_path = self.tags_dir.join(Self::hexadecimal_encode(&handle.pack())); + 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), + } + 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/runtime/Cargo.toml b/fix/runtime/Cargo.toml index 86cedb6..5beb98c 100644 --- a/fix/runtime/Cargo.toml +++ b/fix/runtime/Cargo.toml @@ -36,3 +36,4 @@ 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 } diff --git a/fix/runtime/src/common.rs b/fix/runtime/src/common.rs index f1ff2de..2c5c218 100644 --- a/fix/runtime/src/common.rs +++ b/fix/runtime/src/common.rs @@ -50,14 +50,14 @@ impl TryFrom<&str> for CouponTrades { "EqStrictEncode" => Ok(CouponTrades::EqStrictEncode), "ThinkApplication" => Ok(CouponTrades::ThinkApplication), "ThinkToForce" => Ok(CouponTrades::ThinkToForce), - "ForceToEncodeStric" => Ok(CouponTrades::ForceToEncodeStric), + "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(()) + _ => Err(()), } } } diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 8d4708b..1a259d2 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -11,7 +11,7 @@ use crate::{ use bytemuck::bytes_of; use common::bitpack::BitPack; use derive_more::TryUnwrapError; -use fixhandle::rawhandle::{FixHandle, Object, TreeName}; +use fixhandle::rawhandle::{BlobName, CanonicalHandle, FixHandle, Handle, Object, TreeName}; use kernel::prelude::*; use kernel::types::Blob; @@ -30,13 +30,22 @@ impl From> for Error { #[derive(Debug)] pub struct FixRuntime<'a> { store: &'a mut ObjectStore, - coupon: FixHandle, + coupon_canonical: FixHandle, + coupon_physical: 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(); - Self { store, coupon } + let hash = blake3::hash(coupon); + let handle = CanonicalHandle::new(*hash.as_bytes(), coupon.len() as u64); + let coupon_canonical: FixHandle = + Object::from(BlobName::Blob(Handle::CanonicalHandle(handle))).into(); + let coupon_physical = Object::from(store.create_blob(coupon.into())).into(); + Self { + store, + coupon_canonical, + coupon_physical, + } } } @@ -65,6 +74,12 @@ impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { } fn get_blob(&self, handle: &Self::Handle) -> Result { + let handle = if handle.pack() == self.coupon_canonical.pack() { + self.coupon_physical + } else { + *handle + }; + let b = handle .try_unwrap_object_ref() .map_err(Error::from)? @@ -79,7 +94,11 @@ 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); + + let mut scratch: [u8; 32] = [0; 32]; + tree.read(0 * 32, &mut scratch); + Ok(tree) } fn is_blob(handle: &Self::Handle) -> bool { @@ -119,7 +138,7 @@ impl<'a> Executor for FixRuntime<'a> { let res = bottom.execute(combination); let mut apply_coupon = Vec::with_capacity(32 * 4); - apply_coupon.extend_from_slice(&self.coupon.pack()); + apply_coupon.extend_from_slice(&self.coupon_canonical.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()); @@ -157,7 +176,7 @@ impl<'a> CouponHelper for FixRuntime<'a> { rhs: FixHandle, ) -> FixHandle { let mut combination = Vec::with_capacity(32 * 5); - combination.extend_from_slice(&self.coupon.pack()); + combination.extend_from_slice(&self.coupon_canonical.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()); diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index c5b26b2..f9bdb59 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -234,6 +234,7 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc message.1, ); + println!("{message}"); log::logger().log( &log::Record::builder() .level(level) From d1e51e26e5a94a8ff4e068af493fd7d2ea2e1cb7 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Fri, 15 May 2026 16:21:23 -0700 Subject: [PATCH 11/14] feat: prettier tree printing --- fix/evaluator/src/bin/cli.rs | 44 ++++++++++++++++++++++++++++++----- fix/runtime/src/fixruntime.rs | 3 --- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index a75fcaa..dc2b514 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -105,7 +105,7 @@ trait Run { for<'a> Self::TreeData<'a>: AsRef<[u8]>, { let (output, output_handle) = Evaluator::new(self).evaluate_commands(commands)?; - print!("{output}"); + println!("{output}"); if let Some(h) = output_handle { println!("{h:?}"); } @@ -118,7 +118,7 @@ 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)?; - print!("{output}"); + println!("{output}"); if let Some(h) = output_handle { let flushed = self.flush_handle(h).map_err(|e| format!("{e:?}"))?; let h = flushed; @@ -147,7 +147,37 @@ fn read_commands(args: Vec) -> Result { } } -type RuntimeValue = Value, Vec>; +#[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, @@ -177,8 +207,10 @@ where if let Some(text) = self.evaluate_statement(statement)? { match text { Value::String(s) => { + if !output.is_empty() { + output.push('\n') + } output.push_str(&s); - output.push('\n') } Value::Handle(h) => output_handle = Some(h), _ => todo!(), @@ -196,7 +228,7 @@ where Ok(None) } Statement::Print(expr) => Ok(Some(Value::String(format!( - "result: {}\n", + "{}", self.evaluate_expr(expr)? )))), Statement::ShowCoupon(expr) => { @@ -275,7 +307,7 @@ where .runtime .get_tree(&handle) .map_err(|e| format!("{name}: {e:?}"))?; - Ok(Value::TreeData(tree.as_ref().to_vec())) + Ok(Value::TreeData(tree.as_ref().to_vec().into())) } "apply" => { let expr = self.evaluate_expr(self.get_arg(name, &args)?.clone())?; diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 1a259d2..04ed37b 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -95,9 +95,6 @@ impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { .try_unwrap_tree_obj_ref() .map_err(Error::from)?; let tree = self.store.get_tree(t); - - let mut scratch: [u8; 32] = [0; 32]; - tree.read(0 * 32, &mut scratch); Ok(tree) } From 9f0cfb43d2d075b7f3b355edf7299325ee1d3e24 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 20 May 2026 15:24:23 -0700 Subject: [PATCH 12/14] feat: canonicalhandle only runtime --- Cargo.lock | 23 +++- fix/evaluator/Cargo.toml | 1 + fix/evaluator/eval_script.txt | 1 - fix/evaluator/src/bin/cli.rs | 2 + fix/evaluator/src/hybridruntime.rs | 22 +-- fix/evaluator/src/vmmruntime.rs | 117 +++++++++++++--- fix/handle/src/rawhandle.rs | 7 + fix/runtime/Cargo.toml | 1 + fix/runtime/src/bottom.rs | 14 +- fix/runtime/src/fixruntime.rs | 207 ++++++++++++++++++++++------- fix/runtime/src/runtime.rs | 120 +++++------------ fix/runtime/src/storage.rs | 158 ++++++++++++++-------- fix/src/evaluator.rs | 25 ++-- fix/src/main.rs | 30 +++-- vmm/src/runtime.rs | 1 - 15 files changed, 463 insertions(+), 266 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 351289b..f1026f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -933,6 +933,7 @@ dependencies = [ "common", "env_logger", "fixhandle", + "hashbrown 0.17.1", "hex", "io", "log", @@ -1039,6 +1040,7 @@ dependencies = [ "derive_more 2.1.1", "fixhandle", "futures", + "hashbrown 0.17.1", "kernel", "log", "macros", @@ -1074,6 +1076,12 @@ 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" @@ -1371,7 +1379,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -1382,6 +1390,19 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "heapless" version = "0.7.17" diff --git a/fix/evaluator/Cargo.toml b/fix/evaluator/Cargo.toml index 14613a2..4c7c7c1 100644 --- a/fix/evaluator/Cargo.toml +++ b/fix/evaluator/Cargo.toml @@ -18,6 +18,7 @@ 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" diff --git a/fix/evaluator/eval_script.txt b/fix/evaluator/eval_script.txt index 30450a4..2a19532 100644 --- a/fix/evaluator/eval_script.txt +++ b/fix/evaluator/eval_script.txt @@ -6,5 +6,4 @@ 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))); -show_coupon(h); h diff --git a/fix/evaluator/src/bin/cli.rs b/fix/evaluator/src/bin/cli.rs index dc2b514..057292b 100644 --- a/fix/evaluator/src/bin/cli.rs +++ b/fix/evaluator/src/bin/cli.rs @@ -34,6 +34,8 @@ struct Args { } 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); diff --git a/fix/evaluator/src/hybridruntime.rs b/fix/evaluator/src/hybridruntime.rs index b6dc3bf..e0f658d 100644 --- a/fix/evaluator/src/hybridruntime.rs +++ b/fix/evaluator/src/hybridruntime.rs @@ -6,7 +6,7 @@ use crate::{ }; use common::bitpack::BitPack; use fixhandle::rawhandle::{ - BlobName, Encode, FixHandle, Handle, Object, Thunk, TreeName, create_application_thunk, + BlobName, Encode, FixHandle, Object, Thunk, TreeName, create_application_thunk, create_strict_encode, }; use std::{collections::HashMap, sync::Arc}; @@ -41,24 +41,12 @@ impl HybridRuntime { // Store packed handle for literals BlobName::Literal(_) => handle, // Write non-literals to storage - BlobName::Blob(h) => match h { - Handle::CanonicalHandle(_) => handle, - _ => { - let blob_handle = FixHandle::Object(Object::BlobObj(blob_name)); - let blob = self.vmm_runtime.get_blob(&blob_handle)?; - self.storage_runtime.create_blob(blob) - } - }, + BlobName::Blob(_) => { + let blob = self.vmm_runtime.get_blob(&handle)?; + self.storage_runtime.create_blob(blob) + } }, FixHandle::Object(Object::TreeObj(in_treename)) => { - let h = match in_treename { - TreeName::Tag(h) | TreeName::NotTag(h) => h, - }; - - if let Handle::CanonicalHandle(_) = h { - return Ok(handle); - } - 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) { diff --git a/fix/evaluator/src/vmmruntime.rs b/fix/evaluator/src/vmmruntime.rs index f71124c..270cdb0 100644 --- a/fix/evaluator/src/vmmruntime.rs +++ b/fix/evaluator/src/vmmruntime.rs @@ -5,8 +5,9 @@ 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, RuntimeError}; @@ -14,37 +15,110 @@ 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]; @@ -67,17 +141,19 @@ impl DeterministicEquivRuntime for VmmRuntime { 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: Self::TreeData<'_>) -> 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() + 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, Self::Error> { @@ -134,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() @@ -143,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); } } 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 5beb98c..2fca18f 100644 --- a/fix/runtime/Cargo.toml +++ b/fix/runtime/Cargo.toml @@ -37,3 +37,4 @@ 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/fixruntime.rs b/fix/runtime/src/fixruntime.rs index 04ed37b..0ea0b58 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -5,13 +5,13 @@ 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; use derive_more::TryUnwrapError; -use fixhandle::rawhandle::{BlobName, CanonicalHandle, FixHandle, Handle, Object, TreeName}; +use fixhandle::rawhandle::{FixHandle, Object, TreeName}; use kernel::prelude::*; use kernel::types::Blob; @@ -27,59 +27,140 @@ 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, - coupon_canonical: FixHandle, - coupon_physical: FixHandle, + store: &'a mut ObjectStore, + coupon: FixHandle, } impl<'a> FixRuntime<'a> { - pub fn new(store: &'a mut ObjectStore, coupon: &[u8]) -> Self { - let hash = blake3::hash(coupon); - let handle = CanonicalHandle::new(*hash.as_bytes(), coupon.len() as u64); - let coupon_canonical: FixHandle = - Object::from(BlobName::Blob(Handle::CanonicalHandle(handle))).into(); - let coupon_physical = Object::from(store.create_blob(coupon.into())).into(); - Self { - store, - coupon_canonical, - coupon_physical, - } + 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() } fn get_blob(&self, handle: &Self::Handle) -> Result { - let handle = if handle.pack() == self.coupon_canonical.pack() { - self.coupon_physical - } else { - *handle - }; - let b = handle .try_unwrap_object_ref() .map_err(Error::from)? @@ -135,13 +216,13 @@ impl<'a> Executor for FixRuntime<'a> { let res = bottom.execute(combination); let mut apply_coupon = Vec::with_capacity(32 * 4); - apply_coupon.extend_from_slice(&self.coupon_canonical.pack()); + 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(Blob::new(apply_coupon)) + self.create_tree(FixTreeData::new(Blob::new(apply_coupon))) .unwrap_object() .unwrap_tree_obj() .unwrap_not_tag(), @@ -150,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, @@ -173,14 +240,56 @@ impl<'a> CouponHelper for FixRuntime<'a> { rhs: FixHandle, ) -> FixHandle { let mut combination = Vec::with_capacity(32 * 5); - combination.extend_from_slice(&self.coupon_canonical.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 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..cbfa8e6 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -1,109 +1,150 @@ // 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 +171,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/vmm/src/runtime.rs b/vmm/src/runtime.rs index f9bdb59..c5b26b2 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -234,7 +234,6 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc message.1, ); - println!("{message}"); log::logger().log( &log::Record::builder() .level(level) From 6bbbd9fb569a3aace70643f5611d0b65a7b2889d Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 20 May 2026 15:26:47 -0700 Subject: [PATCH 13/14] formatting --- fix/runtime/src/storage.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index cbfa8e6..169315b 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -21,7 +21,9 @@ impl RefCnt { pub trait FixData: From { fn inner(self) -> Value; fn len(&self) -> u64; - fn is_empty(&self) -> bool { self.len() == 0 } + fn is_empty(&self) -> bool { + self.len() == 0 + } } #[derive(Debug)] @@ -121,7 +123,9 @@ impl, FixTreeData: FixData + AsRef<[u8]>> } } -impl, FixTreeData: FixData + AsRef<[u8]>> Default for ObjectStore { +impl, FixTreeData: FixData + AsRef<[u8]>> Default + for ObjectStore +{ fn default() -> Self { Self::new() } From 442eada8f27a4ed9e00ea91fd967a05e1f5e0085 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 20 May 2026 15:38:37 -0700 Subject: [PATCH 14/14] nightly --- Cargo.lock | 539 ++++++++++++++--------------------------- kernel/src/kvmclock.rs | 1 + 2 files changed, 185 insertions(+), 355 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1026f2..3f8d3da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,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" @@ -51,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", @@ -61,18 +46,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" @@ -89,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]] @@ -100,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", ] @@ -161,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", @@ -199,7 +175,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -244,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", @@ -257,7 +233,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -302,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", @@ -346,9 +322,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "blake2" @@ -444,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", @@ -481,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", @@ -516,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", @@ -526,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", @@ -538,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", @@ -550,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", ] @@ -574,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" @@ -591,7 +567,7 @@ dependencies = [ "libc", "log", "macros", - "nix", + "nix 0.30.1", "rand", "snafu", ] @@ -697,13 +673,13 @@ dependencies = [ [[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]] @@ -743,9 +719,9 @@ dependencies = [ [[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", ] @@ -819,11 +795,11 @@ dependencies = [ [[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", @@ -831,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" @@ -899,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", @@ -919,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]] @@ -963,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" @@ -1084,9 +1060,9 @@ 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", @@ -1099,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", @@ -1109,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", @@ -1126,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" @@ -1145,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", @@ -1156,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", @@ -1180,7 +1156,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1384,12 +1359,6 @@ dependencies = [ "rustc-std-workspace-core", ] -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - [[package]] name = "hashbrown" version = "0.17.1" @@ -1485,12 +1454,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", ] [[package]] @@ -1597,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", @@ -1605,9 +1574,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.180" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libc-print" @@ -1630,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" @@ -1661,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" @@ -1688,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]] @@ -1713,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", @@ -1732,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" @@ -1763,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", ] @@ -1778,9 +1760,9 @@ 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", ] @@ -1847,21 +1829,15 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +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", @@ -1879,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", ] @@ -1959,27 +1935,27 @@ dependencies = [ [[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", @@ -1987,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", ] @@ -2002,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", @@ -2037,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]] @@ -2054,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]] @@ -2071,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" @@ -2092,9 +2068,9 @@ 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" @@ -2125,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]] @@ -2248,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" @@ -2310,9 +2286,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -2360,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]] @@ -2394,15 +2370,15 @@ 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]] @@ -2431,9 +2407,9 @@ 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", @@ -2451,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", @@ -2475,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", @@ -2485,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", @@ -2498,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", @@ -2514,7 +2490,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -2544,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", @@ -2565,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", ] @@ -2621,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" @@ -2683,7 +2659,7 @@ dependencies = [ "kvm-ioctls", "libc", "log", - "nix", + "nix 0.30.1", "regex", "rlimit", "rustc-demangle", @@ -2706,12 +2682,12 @@ 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]] @@ -2728,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", ] @@ -2865,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" @@ -2892,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" @@ -2934,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/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)