From a0368bc39ac620b867a105ca0c9bc12824abcd9d Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 24 Feb 2024 22:16:10 +0100 Subject: [PATCH] feat: switch to own fork of wasmparser Signed-off-by: Henry Gressmann --- Cargo.lock | 116 ++++++++++++++++-- crates/parser/Cargo.toml | 2 +- crates/parser/README.md | 4 +- crates/parser/src/conversion.rs | 76 ++++++++---- crates/parser/src/lib.rs | 34 ++++- .../tinywasm/src/runtime/interpreter/mod.rs | 6 +- 6 files changed, 197 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf9afe3..4fddf4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,19 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +dependencies = [ + "cfg-if", + "const-random", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -196,9 +209,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "serde", @@ -395,6 +408,26 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" +[[package]] +name = "const-random" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -523,7 +556,7 @@ dependencies = [ "cranelift-entity", "fxhash", "hashbrown 0.12.3", - "indexmap", + "indexmap 1.9.3", "log", "smallvec", ] @@ -850,6 +883,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "eyre" version = "0.6.12" @@ -1020,7 +1059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] @@ -1059,7 +1098,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] @@ -1067,6 +1106,9 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.9", +] [[package]] name = "hermit-abi" @@ -1149,6 +1191,16 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + [[package]] name = "indexmap-nostd" version = "0.4.0" @@ -1678,7 +1730,7 @@ dependencies = [ "bytecheck 0.6.12", "bytes", "hashbrown 0.12.3", - "indexmap", + "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -1974,6 +2026,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -2035,7 +2096,7 @@ version = "0.4.1" dependencies = [ "log", "tinywasm-types", - "wasmparser-nostd", + "tinywasm-wasmparser", ] [[package]] @@ -2057,6 +2118,19 @@ dependencies = [ "rkyv", ] +[[package]] +name = "tinywasm-wasmparser" +version = "0.200.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fce1b3563499af272f7e88c8b0357e740e62c2bcf59f134992698d35af96da" +dependencies = [ + "ahash 0.8.9", + "bitflags 2.4.2", + "hashbrown 0.14.3", + "indexmap 2.2.3", + "semver", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2282,7 +2356,7 @@ dependencies = [ "bytes", "cfg-if", "derivative", - "indexmap", + "indexmap 1.9.3", "js-sys", "more-asserts", "rustc-demangle", @@ -2388,7 +2462,7 @@ dependencies = [ "bytecheck 0.6.12", "enum-iterator", "enumset", - "indexmap", + "indexmap 1.9.3", "more-asserts", "rkyv", "target-lexicon", @@ -2410,7 +2484,7 @@ dependencies = [ "derivative", "enum-iterator", "fnv", - "indexmap", + "indexmap 1.9.3", "lazy_static", "libc", "mach", @@ -2460,7 +2534,7 @@ version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" dependencies = [ - "indexmap", + "indexmap 1.9.3", "url", ] @@ -2767,3 +2841,23 @@ dependencies = [ "once_cell", "pkg-config", ] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 0fee8e1..73eec99 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace=true [dependencies] # fork of wasmparser with no_std support, see https://github.com/bytecodealliance/wasmtime/issues/3495 -wasmparser={version="0.100", package="wasmparser-nostd", default-features=false} +wasmparser={version="0.200.2", package="tinywasm-wasmparser", default-features=false} log={version="0.4", optional=true} tinywasm-types={version="0.4.0", path="../types", default-features=false} diff --git a/crates/parser/README.md b/crates/parser/README.md index 8ac7a30..563cd6b 100644 --- a/crates/parser/README.md +++ b/crates/parser/README.md @@ -1,7 +1,7 @@ # `tinywasm-parser` -This crate provides a parser that can parse WebAssembly modules into a TinyWasm module. It is based on -[`wasmparser_nostd`](https://crates.io/crates/wasmparser_nostd) and used by [`tinywasm`](https://crates.io/crates/tinywasm). +This crate provides a parser that can parse WebAssembly modules into a TinyWasm module. +It uses [my fork](https://crates.io/crates/tinywasm-wasmparser) of the [`wasmparser`](https://crates.io/crates/wasmparser) crate that has been modified to be compatible with `no_std` environments. ## Features diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 68567f3..f81b9e7 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -15,26 +15,34 @@ pub(crate) fn convert_module_elements<'a, T: IntoIterator) -> Result { let kind = match element.kind { wasmparser::ElementKind::Active { table_index, offset_expr } => tinywasm_types::ElementKind::Active { - table: table_index, + table: table_index.unwrap_or(0), offset: process_const_operators(offset_expr.get_operators_reader())?, }, wasmparser::ElementKind::Passive => tinywasm_types::ElementKind::Passive, wasmparser::ElementKind::Declared => tinywasm_types::ElementKind::Declared, }; - let items = match element.items { + match element.items { wasmparser::ElementItems::Functions(funcs) => { - funcs.into_iter().map(|func| Ok(ElementItem::Func(func?))).collect::>>()?.into_boxed_slice() + let items = funcs + .into_iter() + .map(|func| Ok(ElementItem::Func(func?))) + .collect::>>()? + .into_boxed_slice(); + + Ok(tinywasm_types::Element { kind, items, ty: ValType::RefFunc, range: element.range }) } - wasmparser::ElementItems::Expressions(exprs) => exprs - .into_iter() - .map(|expr| Ok(ElementItem::Expr(process_const_operators(expr?.get_operators_reader())?))) - .collect::>>()? - .into_boxed_slice(), - }; + wasmparser::ElementItems::Expressions(ty, exprs) => { + let items = exprs + .into_iter() + .map(|expr| Ok(ElementItem::Expr(process_const_operators(expr?.get_operators_reader())?))) + .collect::>>()? + .into_boxed_slice(); - Ok(tinywasm_types::Element { kind, items, ty: convert_valtype(&element.ty), range: element.range }) + Ok(tinywasm_types::Element { kind, items, ty: convert_reftype(&ty), range: element.range }) + } + } } pub(crate) fn convert_module_data_sections<'a, T: IntoIterator>>>( @@ -71,7 +79,11 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result ImportKind::Function(ty), - wasmparser::TypeRef::Table(ty) => ImportKind::Table(convert_module_table(ty)?), + wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType { + element_type: convert_reftype(&ty.element_type), + size_initial: ty.initial, + size_max: ty.maximum, + }), wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)?), wasmparser::TypeRef::Global(ty) => { ImportKind::Global(GlobalType { mutable: ty.mutable, ty: convert_valtype(&ty.content_type) }) @@ -103,16 +115,16 @@ pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> Result>>( +pub(crate) fn convert_module_tables<'a, T: IntoIterator>>>( table_types: T, ) -> Result> { let table_type = table_types.into_iter().map(|table| convert_module_table(table?)).collect::>>()?; Ok(table_type) } -pub(crate) fn convert_module_table(table: wasmparser::TableType) -> Result { - let ty = convert_valtype(&table.element_type); - Ok(TableType { element_type: ty, size_initial: table.initial, size_max: table.maximum }) +pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result { + let ty = convert_reftype(&table.ty.element_type); + Ok(TableType { element_type: ty, size_initial: table.ty.initial, size_max: table.ty.maximum }) } pub(crate) fn convert_module_globals<'a, T: IntoIterator>>>( @@ -168,8 +180,15 @@ pub(crate) fn convert_module_code( Ok(CodeSection { locals: locals.into_boxed_slice(), body }) } -pub(crate) fn convert_module_type(ty: wasmparser::Type) -> Result { - let wasmparser::Type::Func(ty) = ty; +pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result { + let mut types = ty.types(); + + if types.len() != 1 { + return Err(crate::ParseError::UnsupportedOperator( + "Expected exactly one type in the type section".to_string(), + )); + } + let ty = types.next().unwrap().unwrap_func(); let params = ty.params().iter().map(|p| Ok(convert_valtype(p))).collect::>>()?.into_boxed_slice(); @@ -188,6 +207,14 @@ pub(crate) fn convert_blocktype(blocktype: wasmparser::BlockType) -> BlockArgs { } } +pub(crate) fn convert_reftype(reftype: &wasmparser::RefType) -> ValType { + match reftype { + _ if reftype.is_func_ref() => ValType::RefFunc, + _ if reftype.is_extern_ref() => ValType::RefExtern, + _ => unimplemented!("Unsupported reference type: {:?}", reftype), + } +} + pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType { use wasmparser::ValType::*; match valtype { @@ -195,9 +222,8 @@ pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType { I64 => ValType::I64, F32 => ValType::F32, F64 => ValType::F64, + Ref(r) => convert_reftype(r), V128 => unimplemented!("128-bit values are not supported yet"), - FuncRef => ValType::RefFunc, - ExternRef => ValType::RefExtern, } } @@ -217,7 +243,7 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result) -> Result { match op { - wasmparser::Operator::RefNull { ty } => Ok(ConstInstruction::RefNull(convert_valtype(&ty))), + wasmparser::Operator::RefNull { hty } => Ok(ConstInstruction::RefNull(convert_heaptype(hty))), wasmparser::Operator::RefFunc { function_index } => Ok(ConstInstruction::RefFunc(function_index)), wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(value)), wasmparser::Operator::I64Const { value } => Ok(ConstInstruction::I64Const(value)), @@ -228,6 +254,14 @@ pub(crate) fn process_const_operator(op: wasmparser::Operator<'_>) -> Result ValType { + match heap { + wasmparser::HeapType::Func => ValType::RefFunc, + wasmparser::HeapType::Extern => ValType::RefExtern, + _ => unimplemented!("Unsupported heap type: {:?}", heap), + } +} + pub(crate) fn process_operators( ops: OperatorsReader<'_>, mut validator: FuncValidator, @@ -357,7 +391,7 @@ pub(crate) fn process_operators( I64Const { value } => Instruction::I64Const(value), F32Const { value } => Instruction::F32Const(f32::from_bits(value.bits())), F64Const { value } => Instruction::F64Const(f64::from_bits(value.bits())), - RefNull { ty } => Instruction::RefNull(convert_valtype(&ty)), + RefNull { hty } => Instruction::RefNull(convert_heaptype(hty)), RefIsNull => Instruction::RefIsNull, RefFunc { function_index } => Instruction::RefFunc(function_index), I32Load { memarg } => Instruction::I32Load(convert_memarg(memarg)), diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 8cc34db..72b3f81 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -32,7 +32,7 @@ use alloc::{string::ToString, vec::Vec}; pub use error::*; use module::ModuleReader; use tinywasm_types::{TypedWasmFunction, WasmFunction}; -use wasmparser::Validator; +use wasmparser::{Validator, WasmFeatures}; pub use tinywasm_types::TinyWasmModule; @@ -46,10 +46,38 @@ impl Parser { Self {} } + fn create_validator(&self) -> Validator { + let features = WasmFeatures { + bulk_memory: true, + floats: true, + function_references: true, + multi_value: true, + mutable_global: true, + reference_types: true, + sign_extension: true, + saturating_float_to_int: true, + + component_model: false, + component_model_nested_names: false, + component_model_values: false, + exceptions: false, + extended_const: false, + gc: false, + memory64: false, + memory_control: false, + relaxed_simd: false, + simd: false, + tail_call: false, + threads: false, + multi_memory: false, // should be working mostly + }; + Validator::new_with_features(features) + } + /// Parse a [`TinyWasmModule`] from bytes pub fn parse_module_bytes(&self, wasm: impl AsRef<[u8]>) -> Result { let wasm = wasm.as_ref(); - let mut validator = Validator::new(); + let mut validator = self.create_validator(); let mut reader = ModuleReader::new(); for payload in wasmparser::Parser::new(0).parse_all(wasm) { @@ -79,7 +107,7 @@ impl Parser { pub fn parse_module_stream(&self, mut stream: impl std::io::Read) -> Result { use alloc::format; - let mut validator = Validator::new(); + let mut validator = self.create_validator(); let mut reader = ModuleReader::new(); let mut buffer = Vec::new(); let mut parser = wasmparser::Parser::new(0); diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 78f6ed2..b06152d 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -203,7 +203,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M BlockFrame::new( cf.instr_ptr, cf.instr_ptr + *end_offset, - stack.values.len(), // - params, + stack.values.len(), BlockType::If, args, module, @@ -219,7 +219,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let label = BlockFrame::new( cf.instr_ptr + *else_offset, cf.instr_ptr + *end_offset, - stack.values.len(), // - params, + stack.values.len(), BlockType::Else, args, module, @@ -236,7 +236,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M BlockFrame::new( cf.instr_ptr, cf.instr_ptr + *end_offset, - stack.values.len(), // - params, + stack.values.len(), BlockType::Loop, args, module,