diff --git a/Cargo.lock b/Cargo.lock index 1456976..9b51193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -78,6 +89,40 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "bytecheck" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "cc" version = "1.0.83" @@ -139,12 +184,38 @@ dependencies = [ "once_cell", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + [[package]] name = "hermit-abi" version = "0.3.3" @@ -288,6 +359,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "regex" version = "1.10.2" @@ -317,15 +394,30 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rend" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" +dependencies = [ + "bytecheck", +] + [[package]] name = "rkyv" version = "0.7.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" dependencies = [ + "bitvec", + "bytecheck", + "hashbrown", "ptr_meta", + "rend", "rkyv_derive", "seahash", + "tinyvec", + "uuid", ] [[package]] @@ -384,6 +476,12 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "syn" version = "1.0.109" @@ -406,6 +504,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" version = "1.4.0" @@ -415,6 +519,21 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tinywasm" version = "0.0.0" @@ -466,6 +585,24 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "uuid" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-encoder" version = "0.38.1" @@ -658,3 +795,12 @@ name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index d34aeff..1f34a67 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -10,7 +10,7 @@ path="src/bin.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tinywasm={path="../tinywasm"} +tinywasm={path="../tinywasm", features=["std", "parser"]} argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" diff --git a/crates/cli/src/bin.rs b/crates/cli/src/bin.rs index 2e05f8a..f9c9f63 100644 --- a/crates/cli/src/bin.rs +++ b/crates/cli/src/bin.rs @@ -95,12 +95,16 @@ fn main() -> Result<()> { fn run(module: Module) -> Result<()> { let mut store = tinywasm::Store::default(); - let instance = module.instantiate(&mut store)?; let func = instance.get_typed_func::<(i32, i32), (i32,)>(&store, "add")?; let (res,) = func.call(&mut store, (2, 2))?; info!("{res:?}"); + // let func = instance.get_func(&store, "add")?; + // let params = vec![WasmValue::I32(2), WasmValue::I32(2)]; + // let res = func.call(&mut store, ¶ms)?; + // info!("{res:?}"); + Ok(()) } diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index e45d452..17c5557 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -7,9 +7,10 @@ edition="2021" # fork of wasmparser with no_std support, see https://github.com/bytecodealliance/wasmtime/issues/3495 # TODO: create dependency free parser wasmparser={version="0.100", package="wasmparser-nostd", default-features=false} -log="0.4" +log={version="0.4", optional=true} tinywasm-types={path="../types"} [features] -default=["std"] +default=["std", "logging"] +logging=["log"] std=[] diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index d08df9b..82ceddd 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -1,5 +1,6 @@ use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use tinywasm_types::{BlockArgs, Export, ExternalKind, FuncType, Instruction, MemArg, ValType}; +use wasmparser::{FuncValidator, ValidatorResources}; use crate::{module::CodeSection, Result}; @@ -24,23 +25,28 @@ pub(crate) fn convert_module_export(export: wasmparser::Export) -> Result Result { +pub(crate) fn convert_module_code( + func: wasmparser::FunctionBody, + mut validator: FuncValidator, +) -> Result { let locals_reader = func.get_locals_reader()?; let count = locals_reader.get_count(); let mut locals = Vec::with_capacity(count as usize); - locals.extend( - locals_reader - .into_iter() - .filter_map(|l| l.ok()) - .map(|l| convert_valtype(&l.1)), - ); + + for (i, local) in locals_reader.into_iter().enumerate() { + let local = local?; + for _ in 0..local.0 { + locals.push(convert_valtype(&local.1)); + } + validator.define_locals(i, local.0, local.1)?; + } if locals.len() != count as usize { return Err(crate::ParseError::Other("Invalid local index".to_string())); } let body_reader = func.get_operators_reader()?; - let body = process_operators(body_reader.into_iter())?; + let body = process_operators(body_reader.into_iter(), validator)?; Ok(CodeSection { locals: locals.into_boxed_slice(), @@ -106,12 +112,18 @@ pub(crate) fn convert_memarg(memarg: wasmparser::MemArg) -> MemArg { pub fn process_operators<'a>( ops: impl Iterator, wasmparser::BinaryReaderError>>, + mut validator: FuncValidator, ) -> Result> { let mut instructions = Vec::new(); + let mut offset = 0; for op in ops { + let op = op?; + validator.op(offset, &op)?; + offset += 1; + use wasmparser::Operator::*; - let res = match op? { + let res = match op { BrTable { targets } => { let def = targets.default(); let targets = targets @@ -303,5 +315,7 @@ pub fn process_operators<'a>( instructions.push(res); } + validator.finish(offset)?; + Ok(instructions.into_boxed_slice()) } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 31e8cc8..343350a 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -5,6 +5,17 @@ mod std; extern crate alloc; +// log for logging (optional). +#[cfg(feature = "logging")] +#[allow(clippy::single_component_path_imports)] +use log; + +#[cfg(not(feature = "logging"))] +mod log { + macro_rules! debug ( ($($tt:tt)*) => {{}} ); + pub(crate) use debug; +} + mod conversion; mod error; mod module; diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 5bdbcd8..69bb894 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -1,6 +1,6 @@ +use crate::log::debug; use alloc::{boxed::Box, format, vec::Vec}; use core::fmt::Debug; -use log::debug; use tinywasm_types::{Export, FuncType, Instruction, ValType}; use wasmparser::{Payload, Validator}; @@ -124,9 +124,11 @@ impl ModuleReader { } CodeSectionEntry(function) => { debug!("Found code section entry"); - validator.code_section_entry(&function)?; + let v = validator.code_section_entry(&function)?; + let func_validator = v.into_validator(Default::default()); - self.code_section.push(conversion::convert_module_code(function)?); + self.code_section + .push(conversion::convert_module_code(function, func_validator)?); } ImportSection(_reader) => { return Err(ParseError::UnsupportedSection("Import section".into())); diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index ded786f..421ec37 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -9,12 +9,13 @@ path="src/lib.rs" crate-type=["cdylib", "rlib"] [dependencies] -log="0.4" -tinywasm-parser={path="../parser", default-features=false} +log={version="0.4", optional=true} +tinywasm-parser={path="../parser", default-features=false, optional=true} tinywasm-types={path="../types", default-features=false} - wasmparser={version="0.100", package="wasmparser-nostd", default-features=false} [features] -default=["std"] -std=["tinywasm-parser/std", "tinywasm-types/std"] +default=["std", "parser", "logging"] +logging=["log", "tinywasm-types/logging", "tinywasm-parser?/logging"] +std=["tinywasm-parser?/std", "tinywasm-types/std"] +parser=["tinywasm-parser"] diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs index bc7028d..c186e46 100644 --- a/crates/tinywasm/src/error.rs +++ b/crates/tinywasm/src/error.rs @@ -1,10 +1,17 @@ use alloc::string::{String, ToString}; use core::fmt::Display; + +#[cfg(feature = "parser")] use tinywasm_parser::ParseError; #[derive(Debug)] pub enum Error { + #[cfg(feature = "parser")] ParseError(ParseError), + + #[cfg(feature = "std")] + Io(crate::std::io::Error), + UnsupportedFeature(String), Other(String), @@ -12,26 +19,25 @@ pub enum Error { StackUnderflow, BlockStackUnderflow, CallStackEmpty, - InvalidStore, - - #[cfg(feature = "std")] - Io(crate::std::io::Error), } impl Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { + #[cfg(feature = "parser")] + Self::ParseError(err) => write!(f, "error parsing module: {:?}", err), + + #[cfg(feature = "std")] + Self::Io(err) => write!(f, "I/O error: {}", err), + + Self::Other(message) => write!(f, "unknown error: {}", message), + Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {}", feature), Self::FuncDidNotReturn => write!(f, "function did not return"), Self::BlockStackUnderflow => write!(f, "block stack underflow"), Self::StackUnderflow => write!(f, "stack underflow"), - Self::ParseError(err) => write!(f, "error parsing module: {:?}", err), - Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {}", feature), Self::CallStackEmpty => write!(f, "call stack empty"), - Self::Other(message) => write!(f, "unknown error: {}", message), Self::InvalidStore => write!(f, "invalid store"), - #[cfg(feature = "std")] - Self::Io(err) => write!(f, "I/O error: {}", err), } } } @@ -48,6 +54,7 @@ impl Error { } } +#[cfg(feature = "parser")] impl From for Error { fn from(value: tinywasm_parser::ParseError) -> Self { Self::ParseError(value) diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 03e5cac..c09afb8 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -5,6 +5,17 @@ mod std; extern crate alloc; +// log for logging (optional). +#[cfg(feature = "logging")] +#[allow(clippy::single_component_path_imports)] +use log; + +#[cfg(not(feature = "logging"))] +pub(crate) mod log { + macro_rules! debug ( ($($tt:tt)*) => {{}} ); + pub(crate) use debug; +} + mod error; pub use error::*; @@ -23,6 +34,7 @@ pub use export::ExportInstance; pub mod func; pub use func::{FuncHandle, TypedFuncHandle}; +#[cfg(feature = "parser")] pub use tinywasm_parser as parser; pub use tinywasm_types::*; pub mod runtime; diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs index 41ad860..740b4b7 100644 --- a/crates/tinywasm/src/module.rs +++ b/crates/tinywasm/src/module.rs @@ -14,20 +14,21 @@ impl From for Module { } impl Module { + #[cfg(feature = "parser")] pub fn parse_bytes(wasm: &[u8]) -> Result { let parser = tinywasm_parser::Parser::new(); let data = parser.parse_module_bytes(wasm)?; Ok(data.into()) } - #[cfg(feature = "std")] + #[cfg(all(feature = "parser", feature = "std"))] pub fn parse_file(path: impl AsRef + Clone) -> Result { let parser = tinywasm_parser::Parser::new(); let data = parser.parse_module_file(path)?; Ok(data.into()) } - #[cfg(feature = "std")] + #[cfg(all(feature = "parser", feature = "std"))] pub fn parse_stream(stream: impl crate::std::io::Read) -> Result { let parser = tinywasm_parser::Parser::new(); let data = parser.parse_module_stream(stream)?; diff --git a/crates/tinywasm/src/runtime/executer.rs b/crates/tinywasm/src/runtime/executer.rs index 85a9823..f41ff89 100644 --- a/crates/tinywasm/src/runtime/executer.rs +++ b/crates/tinywasm/src/runtime/executer.rs @@ -1,9 +1,9 @@ use super::{Runtime, Stack}; -use crate::{Error, Result}; +use crate::{log::debug, Error, Result}; use alloc::vec; -use log::debug; use tinywasm_types::Instruction; +#[allow(dead_code)] enum BlockMarker { Top, Loop, diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs index 534d245..fd497ce 100644 --- a/crates/tinywasm/src/runtime/value.rs +++ b/crates/tinywasm/src/runtime/value.rs @@ -1,11 +1,19 @@ +use core::fmt::Debug; + use tinywasm_types::{ValType, WasmValue}; /// A raw wasm value. /// This is the internal representation of all wasm values /// See [`WasmValue`] for the public representation. -#[derive(Debug, Clone, Copy, Default)] +#[derive(Clone, Copy, Default)] pub struct RawWasmValue(u64); +impl Debug for RawWasmValue { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "RawWasmValue({})", self.0) + } +} + impl RawWasmValue { pub fn attach_type(self, ty: ValType) -> WasmValue { match ty { diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index e7f6f92..082723f 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -5,9 +5,10 @@ edition="2021" [dependencies] log={version="0.4", optional=true} -rkyv={version="0.7", optional=true, default-features=false} +rkyv={version="0.7", optional=true, default-features=false, features=["size_32"]} [features] -default=["std"] -std=[] +default=["std", "logging"] +std=["rkyv/std"] serialize=["dep:rkyv", "dep:log"] +logging=["dep:log"] diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 875deaf..90c4f10 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -1,5 +1,17 @@ extern crate alloc; +// log for logging (optional). +// #[cfg(feature = "logging")] +// #[allow(unused_imports)] +// use log; + +// #[cfg(not(feature = "logging"))] +// #[macro_use] +// pub(crate) mod log { +// // macro_rules! debug ( ($($tt:tt)*) => {{}} ); +// // pub(crate) use debug; +// } + mod instructions; use core::fmt::Debug;