From ceda0a31c1d00f282d2cf4502ddc44134962d267 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Tue, 25 Jun 2024 20:48:26 +0200 Subject: [PATCH 01/10] wip: compact value stack Signed-off-by: Henry Gressmann --- crates/parser/src/conversion.rs | 10 +- crates/parser/src/module.rs | 7 +- crates/parser/src/visit.rs | 61 ++- crates/tinywasm/Cargo.toml | 10 + crates/tinywasm/src/func.rs | 11 +- .../tinywasm/src/runtime/interpreter/mod.rs | 304 ++++++++------- crates/tinywasm/src/runtime/mod.rs | 12 +- .../src/runtime/{raw.rs => raw.rs.old} | 0 .../runtime/{raw_simd.rs => raw_simd.rs.old} | 0 .../tinywasm/src/runtime/stack/call_stack.rs | 37 +- crates/tinywasm/src/runtime/stack/mod.rs | 4 +- .../tinywasm/src/runtime/stack/value_stack.rs | 362 ++++++++---------- .../src/runtime/stack/value_stack.rs.old | 266 +++++++++++++ crates/tinywasm/src/store/mod.rs | 2 +- crates/types/src/instructions.rs | 4 +- crates/types/src/value.rs | 12 + 16 files changed, 679 insertions(+), 423 deletions(-) rename crates/tinywasm/src/runtime/{raw.rs => raw.rs.old} (100%) rename crates/tinywasm/src/runtime/{raw_simd.rs => raw_simd.rs.old} (100%) create mode 100644 crates/tinywasm/src/runtime/stack/value_stack.rs.old diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 59c023e..2f6fa37 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -2,7 +2,7 @@ use crate::Result; use crate::{module::Code, visit::process_operators_and_validate}; use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use tinywasm_types::*; -use wasmparser::{FuncValidator, OperatorsReader, ValidatorResources}; +use wasmparser::{FuncValidator, FuncValidatorAllocations, OperatorsReader, ValidatorResources}; pub(crate) fn convert_module_elements<'a, T: IntoIterator>>>( elements: T, @@ -168,8 +168,8 @@ pub(crate) fn convert_module_export(export: wasmparser::Export<'_>) -> Result, - validator: &mut FuncValidator, -) -> Result { + mut validator: FuncValidator, +) -> Result<(Code, FuncValidatorAllocations)> { let locals_reader = func.get_locals_reader()?; let count = locals_reader.get_count(); let pos = locals_reader.original_position(); @@ -187,8 +187,8 @@ pub(crate) fn convert_module_code( locals.into_boxed_slice() }; - let body = process_operators_and_validate(validator, func)?; - Ok((body, locals)) + let (body, allocations) = process_operators_and_validate(validator, func)?; + Ok(((body, locals), allocations)) } pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result { diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 294782c..7cf5da7 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -135,9 +135,10 @@ impl ModuleReader { CodeSectionEntry(function) => { debug!("Found code section entry"); let v = validator.code_section_entry(&function)?; - let mut func_validator = v.into_validator(self.func_validator_allocations.take().unwrap_or_default()); - self.code.push(conversion::convert_module_code(function, &mut func_validator)?); - self.func_validator_allocations = Some(func_validator.into_allocations()); + let func_validator = v.into_validator(self.func_validator_allocations.take().unwrap_or_default()); + let (code, allocations) = conversion::convert_module_code(function, func_validator)?; + self.code.push(code); + self.func_validator_allocations = Some(allocations); } ImportSection(reader) => { if !self.imports.is_empty() { diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index f22e05b..3e2530f 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -4,45 +4,42 @@ use crate::conversion::{convert_heaptype, convert_valtype}; use alloc::string::ToString; use alloc::{boxed::Box, vec::Vec}; use tinywasm_types::{Instruction, MemoryArg}; -use wasmparser::{FuncValidator, FunctionBody, VisitOperator, WasmModuleResources}; +use wasmparser::{FuncValidator, FuncValidatorAllocations, FunctionBody, VisitOperator, WasmModuleResources}; -struct ValidateThenVisit<'a, T, U>(T, &'a mut U); +struct ValidateThenVisit<'a, R: WasmModuleResources>(usize, &'a mut FunctionBuilder); macro_rules! validate_then_visit { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {$( fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { - self.0.$visit($($($arg.clone()),*)?)?; + self.1.validator_visitor(self.0).$visit($($($arg.clone()),*)?)?; self.1.$visit($($($arg),*)?); Ok(()) } )*}; } -impl<'a, T, U> VisitOperator<'a> for ValidateThenVisit<'_, T, U> -where - T: VisitOperator<'a, Output = wasmparser::Result<()>>, - U: VisitOperator<'a, Output = ()>, -{ +impl<'a, R: WasmModuleResources> VisitOperator<'a> for ValidateThenVisit<'_, R> { type Output = Result<()>; wasmparser::for_each_operator!(validate_then_visit); } pub(crate) fn process_operators_and_validate( - validator: &mut FuncValidator, + validator: FuncValidator, body: FunctionBody<'_>, -) -> Result> { +) -> Result<(Box<[Instruction]>, FuncValidatorAllocations)> { let mut reader = body.get_operators_reader()?; let remaining = reader.get_binary_reader().bytes_remaining(); - let mut builder = FunctionBuilder::new(remaining); + let mut builder = FunctionBuilder::new(remaining, validator); + while !reader.eof() { - let validate = validator.visitor(reader.original_position()); - reader.visit_operator(&mut ValidateThenVisit(validate, &mut builder))??; + reader.visit_operator(&mut ValidateThenVisit(reader.original_position(), &mut builder))??; } - validator.finish(reader.original_position())?; + + builder.validator_finish(reader.original_position())?; if !builder.errors.is_empty() { return Err(builder.errors.remove(0)); } - Ok(builder.instructions.into_boxed_slice()) + Ok((builder.instructions.into_boxed_slice(), builder.validator.into_allocations())) } macro_rules! define_operands { @@ -77,15 +74,30 @@ macro_rules! define_mem_operands { )*}; } -pub(crate) struct FunctionBuilder { +pub(crate) struct FunctionBuilder { + validator: FuncValidator, instructions: Vec, label_ptrs: Vec, errors: Vec, } -impl FunctionBuilder { - pub(crate) fn new(instr_capacity: usize) -> Self { +impl FunctionBuilder { + pub(crate) fn validator_visitor<'this>( + &'this mut self, + offset: usize, + ) -> impl VisitOperator> + 'this { + self.validator.visitor(offset) + } + + pub(crate) fn validator_finish(&mut self, offset: usize) -> Result<(), wasmparser::BinaryReaderError> { + self.validator.finish(offset) + } +} + +impl FunctionBuilder { + pub(crate) fn new(instr_capacity: usize, validator: FuncValidator) -> Self { Self { + validator, instructions: Vec::with_capacity(instr_capacity), label_ptrs: Vec::with_capacity(256), errors: Vec::new(), @@ -115,7 +127,7 @@ macro_rules! impl_visit_operator { }; } -impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { +impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuilder { type Output = (); wasmparser::for_each_operator!(impl_visit_operator); @@ -161,7 +173,6 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_unreachable, Instruction::Unreachable, visit_nop, Instruction::Nop, visit_return, Instruction::Return, - visit_drop, Instruction::Drop, visit_select, Instruction::Select(None), visit_i32_eqz, Instruction::I32Eqz, visit_i32_eq, Instruction::I32Eq, @@ -305,6 +316,16 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U } + fn visit_drop(&mut self) -> Self::Output { + match self.validator.get_operand_type(0) { + Some(Some(t)) => { + let t = convert_valtype(&t); + self.instructions.push(Instruction::Drop(t)) + } + _ => unreachable!("this should have been caught by the validator"), + } + } + fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { let arg = MemoryArg { offset: memarg.offset, mem_addr: memarg.memory }; let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 491522c..d3f81c7 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -19,6 +19,16 @@ tinywasm-parser={version="0.7.0", path="../parser", default-features=false, opti tinywasm-types={version="0.7.0", path="../types", default-features=false} libm={version="0.2", default-features=false} +# maybe? +# arrayvec={version="0.7"} instead of the custom implementation +# bumpalo={version="3.16"} +# wide= for simd +# vec1= might be useful? fast .last() and .first() access +# https://github.com/lumol-org/soa-derive could be useful for the memory layout of Stacks + +#https://alic.dev/blog/dense-enums +# https://docs.rs/tagged-pointer/latest/tagged_pointer/ + [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} wast={version="211.0"} diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index a6e16ad..2373536 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,5 +1,5 @@ use crate::runtime::{CallFrame, Stack}; -use crate::{log, runtime::RawWasmValue, unlikely, Function}; +use crate::{log, unlikely, Function}; use crate::{Error, FuncContext, Result, Store}; use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec}; use tinywasm_types::{FuncType, ModuleInstanceAddr, ValType, WasmValue}; @@ -59,8 +59,7 @@ impl FuncHandle { }; // 6. Let f be the dummy frame - let call_frame_params = params.iter().map(|v| RawWasmValue::from(*v)).collect::>(); - let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, &call_frame_params, 0); + let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, ¶ms, 0); // 7. Push the frame f to the call stack // & 8. Push the values to the stack (Not needed since the call frame owns the values) @@ -74,13 +73,13 @@ impl FuncHandle { let result_m = func_ty.results.len(); // 1. Assert: m values are on the top of the stack (Ensured by validation) - assert!(stack.values.len() >= result_m); + // assert!(stack.values.len() >= result_m); // 2. Pop m values from the stack - let res = stack.values.last_n(result_m)?; + let res = stack.values.pop_n_typed(&func_ty.results); // The values are returned as the results of the invocation. - Ok(res.iter().zip(func_ty.results.iter()).map(|(v, ty)| v.attach_type(*ty)).collect()) + Ok(res) } } diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index be3f60a..90f4d8d 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -1,15 +1,15 @@ use alloc::{format, rc::Rc, string::ToString}; -use core::ops::{BitAnd, BitOr, BitXor, ControlFlow, Neg}; +use core::ops::ControlFlow; use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction}; use super::stack::{BlockFrame, BlockType}; -use super::{InterpreterRuntime, RawWasmValue, Stack}; +use super::{InterpreterRuntime, Stack}; use crate::runtime::CallFrame; use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap}; mod macros; mod traits; -use {macros::*, traits::*}; +use macros::*; #[cfg(not(feature = "std"))] mod no_std_floats; @@ -55,8 +55,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { match self.cf.fetch_instr() { Nop => self.exec_noop(), Unreachable => self.exec_unreachable()?, - - Drop => self.exec_drop()?, + Drop(t) => self.exec_drop(t.size())?, Select(_valtype) => self.exec_select()?, Call(v) => self.exec_call_direct(*v)?, CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?, @@ -122,140 +121,140 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64Load32S { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, I64Load32U { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, - I64Eqz => comp_zero!(==, i64, self), - I32Eqz => comp_zero!(==, i32, self), - - I32Eq => comp!(==, i32, self), - I64Eq => comp!(==, i64, self), - F32Eq => comp!(==, f32, self), - F64Eq => comp!(==, f64, self), - - I32Ne => comp!(!=, i32, self), - I64Ne => comp!(!=, i64, self), - F32Ne => comp!(!=, f32, self), - F64Ne => comp!(!=, f64, self), - - I32LtS => comp!(<, i32, self), - I64LtS => comp!(<, i64, self), - I32LtU => comp!(<, u32, self), - I64LtU => comp!(<, u64, self), - F32Lt => comp!(<, f32, self), - F64Lt => comp!(<, f64, self), - - I32LeS => comp!(<=, i32, self), - I64LeS => comp!(<=, i64, self), - I32LeU => comp!(<=, u32, self), - I64LeU => comp!(<=, u64, self), - F32Le => comp!(<=, f32, self), - F64Le => comp!(<=, f64, self), - - I32GeS => comp!(>=, i32, self), - I64GeS => comp!(>=, i64, self), - I32GeU => comp!(>=, u32, self), - I64GeU => comp!(>=, u64, self), - F32Ge => comp!(>=, f32, self), - F64Ge => comp!(>=, f64, self), - - I32GtS => comp!(>, i32, self), - I64GtS => comp!(>, i64, self), - I32GtU => comp!(>, u32, self), - I64GtU => comp!(>, u64, self), - F32Gt => comp!(>, f32, self), - F64Gt => comp!(>, f64, self), - - I64Add => arithmetic!(wrapping_add, i64, self), - I32Add => arithmetic!(wrapping_add, i32, self), - F32Add => arithmetic!(+, f32, self), - F64Add => arithmetic!(+, f64, self), - - I32Sub => arithmetic!(wrapping_sub, i32, self), - I64Sub => arithmetic!(wrapping_sub, i64, self), - F32Sub => arithmetic!(-, f32, self), - F64Sub => arithmetic!(-, f64, self), - - F32Div => arithmetic!(/, f32, self), - F64Div => arithmetic!(/, f64, self), - - I32Mul => arithmetic!(wrapping_mul, i32, self), - I64Mul => arithmetic!(wrapping_mul, i64, self), - F32Mul => arithmetic!(*, f32, self), - F64Mul => arithmetic!(*, f64, self), - - // these can trap - I32DivS => checked_int_arithmetic!(checked_div, i32, self), - I64DivS => checked_int_arithmetic!(checked_div, i64, self), - I32DivU => checked_int_arithmetic!(checked_div, u32, self), - I64DivU => checked_int_arithmetic!(checked_div, u64, self), - - I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, self), - I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, self), - I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, self), - I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, self), - - I32And => arithmetic!(bitand, i32, self), - I64And => arithmetic!(bitand, i64, self), - I32Or => arithmetic!(bitor, i32, self), - I64Or => arithmetic!(bitor, i64, self), - I32Xor => arithmetic!(bitxor, i32, self), - I64Xor => arithmetic!(bitxor, i64, self), - I32Shl => arithmetic!(wasm_shl, i32, self), - I64Shl => arithmetic!(wasm_shl, i64, self), - I32ShrS => arithmetic!(wasm_shr, i32, self), - I64ShrS => arithmetic!(wasm_shr, i64, self), - I32ShrU => arithmetic!(wasm_shr, u32, self), - I64ShrU => arithmetic!(wasm_shr, u64, self), - I32Rotl => arithmetic!(wasm_rotl, i32, self), - I64Rotl => arithmetic!(wasm_rotl, i64, self), - I32Rotr => arithmetic!(wasm_rotr, i32, self), - I64Rotr => arithmetic!(wasm_rotr, i64, self), - - I32Clz => arithmetic_single!(leading_zeros, i32, self), - I64Clz => arithmetic_single!(leading_zeros, i64, self), - I32Ctz => arithmetic_single!(trailing_zeros, i32, self), - I64Ctz => arithmetic_single!(trailing_zeros, i64, self), - I32Popcnt => arithmetic_single!(count_ones, i32, self), - I64Popcnt => arithmetic_single!(count_ones, i64, self), - - F32ConvertI32S => conv!(i32, f32, self), - F32ConvertI64S => conv!(i64, f32, self), - F64ConvertI32S => conv!(i32, f64, self), - F64ConvertI64S => conv!(i64, f64, self), - F32ConvertI32U => conv!(u32, f32, self), - F32ConvertI64U => conv!(u64, f32, self), - F64ConvertI32U => conv!(u32, f64, self), - F64ConvertI64U => conv!(u64, f64, self), - I32Extend8S => conv!(i8, i32, self), - I32Extend16S => conv!(i16, i32, self), - I64Extend8S => conv!(i8, i64, self), - I64Extend16S => conv!(i16, i64, self), - I64Extend32S => conv!(i32, i64, self), - I64ExtendI32U => conv!(u32, i64, self), - I64ExtendI32S => conv!(i32, i64, self), - I32WrapI64 => conv!(i64, i32, self), - - F32DemoteF64 => conv!(f64, f32, self), - F64PromoteF32 => conv!(f32, f64, self), - - F32Abs => arithmetic_single!(abs, f32, self), - F64Abs => arithmetic_single!(abs, f64, self), - F32Neg => arithmetic_single!(neg, f32, self), - F64Neg => arithmetic_single!(neg, f64, self), - F32Ceil => arithmetic_single!(ceil, f32, self), - F64Ceil => arithmetic_single!(ceil, f64, self), - F32Floor => arithmetic_single!(floor, f32, self), - F64Floor => arithmetic_single!(floor, f64, self), - F32Trunc => arithmetic_single!(trunc, f32, self), - F64Trunc => arithmetic_single!(trunc, f64, self), - F32Nearest => arithmetic_single!(tw_nearest, f32, self), - F64Nearest => arithmetic_single!(tw_nearest, f64, self), - F32Sqrt => arithmetic_single!(sqrt, f32, self), - F64Sqrt => arithmetic_single!(sqrt, f64, self), - F32Min => arithmetic!(tw_minimum, f32, self), - F64Min => arithmetic!(tw_minimum, f64, self), - F32Max => arithmetic!(tw_maximum, f32, self), - F64Max => arithmetic!(tw_maximum, f64, self), - F32Copysign => arithmetic!(copysign, f32, self), - F64Copysign => arithmetic!(copysign, f64, self), + // I64Eqz => comp_zero!(==, i64, self), + // I32Eqz => comp_zero!(==, i32, self), + + // I32Eq => comp!(==, i32, self), + // I64Eq => comp!(==, i64, self), + // F32Eq => comp!(==, f32, self), + // F64Eq => comp!(==, f64, self), + + // I32Ne => comp!(!=, i32, self), + // I64Ne => comp!(!=, i64, self), + // F32Ne => comp!(!=, f32, self), + // F64Ne => comp!(!=, f64, self), + + // I32LtS => comp!(<, i32, self), + // I64LtS => comp!(<, i64, self), + // I32LtU => comp!(<, u32, self), + // I64LtU => comp!(<, u64, self), + // F32Lt => comp!(<, f32, self), + // F64Lt => comp!(<, f64, self), + + // I32LeS => comp!(<=, i32, self), + // I64LeS => comp!(<=, i64, self), + // I32LeU => comp!(<=, u32, self), + // I64LeU => comp!(<=, u64, self), + // F32Le => comp!(<=, f32, self), + // F64Le => comp!(<=, f64, self), + + // I32GeS => comp!(>=, i32, self), + // I64GeS => comp!(>=, i64, self), + // I32GeU => comp!(>=, u32, self), + // I64GeU => comp!(>=, u64, self), + // F32Ge => comp!(>=, f32, self), + // F64Ge => comp!(>=, f64, self), + + // I32GtS => comp!(>, i32, self), + // I64GtS => comp!(>, i64, self), + // I32GtU => comp!(>, u32, self), + // I64GtU => comp!(>, u64, self), + // F32Gt => comp!(>, f32, self), + // F64Gt => comp!(>, f64, self), + + // I64Add => arithmetic!(wrapping_add, i64, self), + // I32Add => arithmetic!(wrapping_add, i32, self), + // F32Add => arithmetic!(+, f32, self), + // F64Add => arithmetic!(+, f64, self), + + // I32Sub => arithmetic!(wrapping_sub, i32, self), + // I64Sub => arithmetic!(wrapping_sub, i64, self), + // F32Sub => arithmetic!(-, f32, self), + // F64Sub => arithmetic!(-, f64, self), + + // F32Div => arithmetic!(/, f32, self), + // F64Div => arithmetic!(/, f64, self), + + // I32Mul => arithmetic!(wrapping_mul, i32, self), + // I64Mul => arithmetic!(wrapping_mul, i64, self), + // F32Mul => arithmetic!(*, f32, self), + // F64Mul => arithmetic!(*, f64, self), + + // // these can trap + // I32DivS => checked_int_arithmetic!(checked_div, i32, self), + // I64DivS => checked_int_arithmetic!(checked_div, i64, self), + // I32DivU => checked_int_arithmetic!(checked_div, u32, self), + // I64DivU => checked_int_arithmetic!(checked_div, u64, self), + + // I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, self), + // I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, self), + // I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, self), + // I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, self), + + // I32And => arithmetic!(bitand, i32, self), + // I64And => arithmetic!(bitand, i64, self), + // I32Or => arithmetic!(bitor, i32, self), + // I64Or => arithmetic!(bitor, i64, self), + // I32Xor => arithmetic!(bitxor, i32, self), + // I64Xor => arithmetic!(bitxor, i64, self), + // I32Shl => arithmetic!(wasm_shl, i32, self), + // I64Shl => arithmetic!(wasm_shl, i64, self), + // I32ShrS => arithmetic!(wasm_shr, i32, self), + // I64ShrS => arithmetic!(wasm_shr, i64, self), + // I32ShrU => arithmetic!(wasm_shr, u32, self), + // I64ShrU => arithmetic!(wasm_shr, u64, self), + // I32Rotl => arithmetic!(wasm_rotl, i32, self), + // I64Rotl => arithmetic!(wasm_rotl, i64, self), + // I32Rotr => arithmetic!(wasm_rotr, i32, self), + // I64Rotr => arithmetic!(wasm_rotr, i64, self), + + // I32Clz => arithmetic_single!(leading_zeros, i32, self), + // I64Clz => arithmetic_single!(leading_zeros, i64, self), + // I32Ctz => arithmetic_single!(trailing_zeros, i32, self), + // I64Ctz => arithmetic_single!(trailing_zeros, i64, self), + // I32Popcnt => arithmetic_single!(count_ones, i32, self), + // I64Popcnt => arithmetic_single!(count_ones, i64, self), + + // F32ConvertI32S => conv!(i32, f32, self), + // F32ConvertI64S => conv!(i64, f32, self), + // F64ConvertI32S => conv!(i32, f64, self), + // F64ConvertI64S => conv!(i64, f64, self), + // F32ConvertI32U => conv!(u32, f32, self), + // F32ConvertI64U => conv!(u64, f32, self), + // F64ConvertI32U => conv!(u32, f64, self), + // F64ConvertI64U => conv!(u64, f64, self), + // I32Extend8S => conv!(i8, i32, self), + // I32Extend16S => conv!(i16, i32, self), + // I64Extend8S => conv!(i8, i64, self), + // I64Extend16S => conv!(i16, i64, self), + // I64Extend32S => conv!(i32, i64, self), + // I64ExtendI32U => conv!(u32, i64, self), + // I64ExtendI32S => conv!(i32, i64, self), + // I32WrapI64 => conv!(i64, i32, self), + + // F32DemoteF64 => conv!(f64, f32, self), + // F64PromoteF32 => conv!(f32, f64, self), + + // F32Abs => arithmetic_single!(abs, f32, self), + // F64Abs => arithmetic_single!(abs, f64, self), + // F32Neg => arithmetic_single!(neg, f32, self), + // F64Neg => arithmetic_single!(neg, f64, self), + // F32Ceil => arithmetic_single!(ceil, f32, self), + // F64Ceil => arithmetic_single!(ceil, f64, self), + // F32Floor => arithmetic_single!(floor, f32, self), + // F64Floor => arithmetic_single!(floor, f64, self), + // F32Trunc => arithmetic_single!(trunc, f32, self), + // F64Trunc => arithmetic_single!(trunc, f64, self), + // F32Nearest => arithmetic_single!(tw_nearest, f32, self), + // F64Nearest => arithmetic_single!(tw_nearest, f64, self), + // F32Sqrt => arithmetic_single!(sqrt, f32, self), + // F64Sqrt => arithmetic_single!(sqrt, f64, self), + // F32Min => arithmetic!(tw_minimum, f32, self), + // F64Min => arithmetic!(tw_minimum, f64, self), + // F32Max => arithmetic!(tw_maximum, f32, self), + // F64Max => arithmetic!(tw_maximum, f64, self), + // F32Copysign => arithmetic!(copysign, f32, self), + // F64Copysign => arithmetic!(copysign, f64, self), // no-op instructions since types are erased at runtime I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} @@ -277,14 +276,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { TableGrow(table_idx) => self.exec_table_grow(*table_idx)?, TableFill(table_idx) => self.exec_table_fill(*table_idx)?, - I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, self), - I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, self), - I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, self), - I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, self), - I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, self), - I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, self), - I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, self), - I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, self), + // I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, self), + // I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, self), + // I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, self), + // I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, self), + // I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, self), + // I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, self), + // I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, self), + // I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, self), // custom instructions LocalGet2(a, b) => self.exec_local_get2(*a, *b), @@ -311,9 +310,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { Err(Error::Trap(Trap::Unreachable)) } - fn exec_drop(&mut self) -> Result<()> { - self.stack.values.pop()?; - Ok(()) + fn exec_drop(&mut self, size: usize) -> Result<()> { + self.stack.values.drop(size) } fn exec_select(&mut self) -> Result<()> { let cond: i32 = self.stack.values.pop()?.into(); @@ -326,8 +324,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> Result<()> { - let params = self.stack.values.pop_n(wasm_func.ty.params.len())?; - let new_call_frame = CallFrame::new(wasm_func, owner, params, self.stack.blocks.len() as u32); + let params = self.stack.values.pop_locals(&wasm_func.ty.params); + let new_call_frame = CallFrame::new_raw(wasm_func, owner, ¶ms, self.stack.blocks.len() as u32); self.cf.instr_ptr += 1; // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); @@ -539,7 +537,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push(val.into()); } fn exec_ref_is_null(&mut self) -> Result<()> { - self.stack.values.replace_top(|val| ((i32::from(val) == -1) as i32).into()) + self.stack.values.replace_top::<8>(|val| ((i32::from(val) == -1) as i32).into()) } fn exec_memory_size(&mut self, addr: u32) -> Result<()> { diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs index dc4816b..7027eac 100644 --- a/crates/tinywasm/src/runtime/mod.rs +++ b/crates/tinywasm/src/runtime/mod.rs @@ -1,17 +1,7 @@ mod interpreter; mod stack; -mod raw; - -#[cfg(all(not(feature = "nightly"), feature = "simd"))] -compile_error!("`simd` feature requires nightly"); - -#[cfg(feature = "simd")] -mod raw_simd; - -pub use raw::RawWasmValue; -pub(crate) use stack::CallFrame; -pub(crate) use stack::Stack; +pub(crate) use stack::{CallFrame, RawWasmValue, Stack}; /// The main TinyWasm runtime. /// diff --git a/crates/tinywasm/src/runtime/raw.rs b/crates/tinywasm/src/runtime/raw.rs.old similarity index 100% rename from crates/tinywasm/src/runtime/raw.rs rename to crates/tinywasm/src/runtime/raw.rs.old diff --git a/crates/tinywasm/src/runtime/raw_simd.rs b/crates/tinywasm/src/runtime/raw_simd.rs.old similarity index 100% rename from crates/tinywasm/src/runtime/raw_simd.rs rename to crates/tinywasm/src/runtime/raw_simd.rs.old diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 30957be..30bbfac 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,11 +1,11 @@ +use super::value_stack::{wasmvalue_to_localvalue, RawWasmValue}; use super::BlockType; -use crate::runtime::RawWasmValue; use crate::unlikely; use crate::{Result, Trap}; use alloc::boxed::Box; use alloc::{rc::Rc, vec, vec::Vec}; -use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction}; +use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmValue}; pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024; @@ -41,7 +41,7 @@ pub(crate) struct CallFrame { pub(crate) block_ptr: u32, pub(crate) func_instance: Rc, pub(crate) module_addr: ModuleInstanceAddr, - pub(crate) locals: Box<[RawWasmValue]>, + pub(crate) locals: Box<[[u8; 16]]>, } impl CallFrame { @@ -126,7 +126,18 @@ impl CallFrame { pub(crate) fn new( wasm_func_inst: Rc, owner: ModuleInstanceAddr, - params: &[RawWasmValue], + params: &[WasmValue], + block_ptr: u32, + ) -> Self { + let locals = params.iter().map(|v| wasmvalue_to_localvalue(*v)).collect::>(); + Self::new_raw(wasm_func_inst, owner, &locals, block_ptr) + } + + #[inline(always)] + pub(crate) fn new_raw( + wasm_func_inst: Rc, + owner: ModuleInstanceAddr, + params: &[[u8; 16]], block_ptr: u32, ) -> Self { let locals = { @@ -134,7 +145,7 @@ impl CallFrame { let mut locals = Vec::new(); locals.reserve_exact(total_size); locals.extend(params); - locals.resize_with(total_size, RawWasmValue::default); + locals.resize_with(total_size, Default::default); locals.into_boxed_slice() }; @@ -142,13 +153,21 @@ impl CallFrame { } #[inline(always)] - pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: RawWasmValue) { - self.locals[local_index as usize] = value; + pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: RawWasmValue) { + match N { + 4 | 8 | 16 => { + self.locals[local_index as usize].copy_from_slice(&value.0); + } + _ => unreachable!("Invalid RawWasmValue size"), + } } #[inline(always)] - pub(crate) fn get_local(&self, local_index: LocalAddr) -> RawWasmValue { - self.locals[local_index as usize] + pub(crate) fn get_local(&self, local_index: LocalAddr) -> RawWasmValue { + match N { + 4 | 8 | 16 => RawWasmValue::from(&self.locals[local_index as usize][..N]), + _ => unreachable!("Invalid RawWasmValue size"), + } } #[inline(always)] diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/runtime/stack/mod.rs index 06510ab..f2e506d 100644 --- a/crates/tinywasm/src/runtime/stack/mod.rs +++ b/crates/tinywasm/src/runtime/stack/mod.rs @@ -4,7 +4,7 @@ mod value_stack; pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; pub(crate) use call_stack::{CallFrame, CallStack}; -pub(crate) use value_stack::ValueStack; +pub(crate) use value_stack::{RawWasmValue, ValueStack}; /// A WebAssembly Stack #[derive(Debug)] @@ -16,6 +16,6 @@ pub(crate) struct Stack { impl Stack { pub(crate) fn new(call_frame: CallFrame) -> Self { - Self { values: ValueStack::default(), blocks: BlockStack::default(), call_stack: CallStack::new(call_frame) } + Self { values: ValueStack::new(), blocks: BlockStack::default(), call_stack: CallStack::new(call_frame) } } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 159e366..dfaa451 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -1,269 +1,209 @@ -use crate::{boxvec::BoxVec, cold, runtime::RawWasmValue, unlikely, Error, Result}; use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; -use super::BlockFrame; +use crate::{Error, Result}; pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128; -#[cfg(feature = "simd")] -pub(crate) const SIMD_VALUE_STACK_SIZE: usize = 1024 * 32; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub(crate) struct RawWasmValue(pub(crate) [u8; N]); -#[cfg(feature = "simd")] -use crate::runtime::raw_simd::RawSimdWasmValue; - -#[derive(Debug)] -pub(crate) struct ValueStack { - pub(crate) stack: BoxVec, +impl From<&[u8]> for RawWasmValue { + fn from(bytes: &[u8]) -> Self { + assert!(bytes.len() != N, "Invalid byte length"); + let mut value = [0; N]; + value.copy_from_slice(bytes); + Self(value) + } +} - #[cfg(feature = "simd")] - simd_stack: BoxVec, +pub(crate) fn wasmvalue_to_bytes(value: WasmValue, mut cb: impl FnMut(&[u8])) { + match value { + WasmValue::I32(v) => cb(&v.to_le_bytes()), + WasmValue::I64(v) => cb(&v.to_le_bytes()), + WasmValue::F32(v) => cb(&v.to_le_bytes()), + WasmValue::F64(v) => cb(&v.to_le_bytes()), + WasmValue::V128(v) => cb(&v.to_le_bytes()), + WasmValue::RefExtern(v) => cb(&(v as i64).to_le_bytes()), + WasmValue::RefFunc(v) => cb(&(v as i64).to_le_bytes()), + WasmValue::RefNull(_) => cb(&(-1i64).to_le_bytes()), + } } -impl Default for ValueStack { - fn default() -> Self { - Self { - stack: BoxVec::with_capacity(VALUE_STACK_SIZE), +pub(crate) fn wasmvalue_to_localvalue(value: WasmValue) -> [u8; 16] { + let mut res = [0; 16]; + match value { + WasmValue::I32(v) => res.copy_from_slice(&v.to_le_bytes()), + WasmValue::I64(v) => res.copy_from_slice(&v.to_le_bytes()), + WasmValue::F32(v) => res.copy_from_slice(&v.to_le_bytes()), + WasmValue::F64(v) => res.copy_from_slice(&v.to_le_bytes()), + WasmValue::V128(v) => res.copy_from_slice(&v.to_le_bytes()), + WasmValue::RefExtern(v) => res.copy_from_slice(&(v as i64).to_le_bytes()), + WasmValue::RefFunc(v) => res.copy_from_slice(&(v as i64).to_le_bytes()), + WasmValue::RefNull(_) => res.copy_from_slice(&(-1i64).to_le_bytes()), + } + res +} - #[cfg(feature = "simd")] - simd_stack: BoxVec::with_capacity(SIMD_VALUE_STACK_SIZE), +pub(crate) fn bytes_to_localvalues(bytes: &[u8], tys: &[ValType]) -> Vec<[u8; 16]> { + let mut values = Vec::with_capacity(tys.len()); + let mut offset = 0; + for ty in tys { + match ty.size() { + 4 | 8 | 16 => { + let mut value = [0; 16]; + value[..ty.size()].copy_from_slice(&bytes[offset..offset + ty.size()]); + values.push(value); + } + _ => unreachable!(), } + offset += 16; } + values } -impl ValueStack { - #[inline] - pub(crate) fn extend_from_typed(&mut self, values: &[WasmValue]) { - #[cfg(not(feature = "simd"))] - self.stack.extend(values.iter().map(|v| RawWasmValue::from(*v))); - - #[cfg(feature = "simd")] - { - values.iter().for_each(|v| match v { - WasmValue::V128(v) => self.simd_stack.push(RawSimdWasmValue::from(*v)), - v => self.stack.push(RawWasmValue::from(*v)), - }); - } +pub(crate) fn bytes_to_wasmvalues(bytes: &[u8], tys: &[ValType]) -> Vec { + let mut values = Vec::with_capacity(tys.len()); + let mut offset = 0; + for ty in tys { + let (value, new_offset) = match ty { + ValType::I32 => (WasmValue::I32(i32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())), 4), + ValType::I64 => (WasmValue::I64(i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap())), 8), + ValType::F32 => (WasmValue::F32(f32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())), 4), + ValType::F64 => (WasmValue::F64(f64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap())), 8), + ValType::V128 => (WasmValue::V128(u128::from_le_bytes(bytes[offset..offset + 16].try_into().unwrap())), 16), + ValType::RefExtern => { + let v = i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap()); + (WasmValue::RefExtern(v as u32), 8) + } + ValType::RefFunc => { + let v = i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap()); + (WasmValue::RefFunc(v as u32), 8) + } + }; + values.push(value); + offset += new_offset; } + values +} - #[inline(always)] - pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { - let v = self.last_mut()?; - *v = func(*v); - Ok(()) +#[derive(Debug)] +pub(crate) struct ValueStack { + pub(crate) stack: Vec, +} + +impl ValueStack { + pub(crate) fn new() -> Self { + Self { stack: Vec::with_capacity(VALUE_STACK_SIZE) } } - #[inline(always)] - pub(crate) fn replace_top_trap(&mut self, func: fn(RawWasmValue) -> Result) -> Result<()> { - let v = self.last_mut()?; - *v = func(*v)?; - Ok(()) + pub(crate) fn height(&self) -> usize { + self.stack.len() } - #[inline(always)] - pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> { - let v2 = self.pop()?; - let v1 = self.last_mut()?; - *v1 = func(*v1, v2); + pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { + let value = func(self.pop::()?); + self.push(value); Ok(()) } - #[inline(always)] - pub(crate) fn calculate_trap( + pub(crate) fn replace_top_trap( &mut self, - func: fn(RawWasmValue, RawWasmValue) -> Result, + func: fn(RawWasmValue) -> Result>, ) -> Result<()> { - let v2 = self.pop()?; - let v1 = self.last_mut()?; - *v1 = func(*v1, v2)?; + let value = func(self.pop::()?)?; + self.push(value); Ok(()) } - #[inline(always)] - pub(crate) fn len(&self) -> usize { - self.stack.len() - } - - #[cfg(feature = "simd")] - #[inline(always)] - pub(crate) fn simd_len(&self) -> usize { - self.simd_stack.len() - } - - #[inline] - pub(crate) fn truncate_keep(&mut self, n: u32, end_keep: u32) { - truncate_keep(&mut self.stack, n, end_keep); - } - - #[cfg(feature = "simd")] - #[inline] - pub(crate) fn truncate_keep_simd(&mut self, n: u16, end_keep: u32) { - truncate_keep(&mut self.simd_stack, n as u32, end_keep); - } - - #[inline(always)] - pub(crate) fn push(&mut self, value: RawWasmValue) { - self.stack.push(value); - } - - #[inline(always)] - pub(crate) fn extend_from_slice(&mut self, values: &[RawWasmValue]) { - self.stack.extend_from_slice(values); + pub(crate) fn calculate( + &mut self, + func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue, + ) -> Result<()> { + let v2 = self.pop::()?; + let v1 = self.pop::()?; + self.push(func(v1, v2)); + Ok(()) } - #[inline] - pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { - match self.stack.last_mut() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } - } + pub(crate) fn calculate_trap( + &mut self, + func: fn(RawWasmValue, RawWasmValue) -> Result>, + ) -> Result<()> { + let v2 = self.pop::()?; + let v1 = self.pop::()?; + self.push(func(v1, v2)?); + Ok(()) } - #[inline] - pub(crate) fn last(&self) -> Result<&RawWasmValue> { - match self.stack.last() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } + pub(crate) fn drop(&mut self, len: usize) -> Result<()> { + if len > self.stack.len() { + return Err(Error::ValueStackUnderflow).into(); } + self.stack.truncate(self.stack.len() - len); + Ok(()) } - #[inline(always)] - pub(crate) fn pop(&mut self) -> Result { - match self.stack.pop() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } - } + pub(crate) fn truncate(&mut self, len: usize) { + self.stack.truncate(len); } - #[inline] - pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result> { - #[cfg(not(feature = "simd"))] - return Ok(self.pop_n(types.len())?.iter().zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect()); + /// Truncate the stack to `len`, but still keep `keep` elements at the end. + pub(crate) fn truncate_keep(&mut self, len: usize, keep: usize) { + let total_to_keep = len + keep; + let len = self.height(); + assert!(len >= total_to_keep, "RawWasmValueotal to keep should be less than or equal to self.top"); - #[cfg(feature = "simd")] - { - let mut values = Vec::with_capacity(types.len()); - for ty in types { - match ty { - ValType::V128 => values.push(WasmValue::V128(self.simd_stack.pop().unwrap().into())), - ty => values.push(self.pop()?.attach_type(*ty)), - } - } - Ok(values) + if len <= total_to_keep { + return; // No need to truncate if the current size is already less than or equal to total_to_keep } - } - - #[inline] - pub(crate) fn break_to_results(&mut self, bf: &BlockFrame) { - let end = self.stack.len() - bf.results as usize; - self.stack.drain(bf.stack_ptr as usize..end); - #[cfg(feature = "simd")] - let end = self.simd_stack.len() - bf.simd_results as usize; - #[cfg(feature = "simd")] - self.simd_stack.drain(bf.simd_stack_ptr as usize..end); + let items_to_remove = len - total_to_keep; + let remove_start_index = (len - items_to_remove - keep) as usize; + let remove_end_index = (len - keep) as usize; + self.stack.drain(remove_start_index..remove_end_index); } - #[inline] - pub(crate) fn break_to_params(&mut self, bf: &BlockFrame) { - let end = self.stack.len() - bf.params as usize; - self.stack.drain(bf.stack_ptr as usize..end); - - #[cfg(feature = "simd")] - let end = self.simd_stack.len() - bf.simd_params as usize; - #[cfg(feature = "simd")] - self.simd_stack.drain(bf.simd_stack_ptr as usize..end); - } - - #[inline] - pub(crate) fn last_n(&self, n: usize) -> Result<&[RawWasmValue]> { + pub(crate) fn last(&self) -> Result> { let len = self.stack.len(); - if unlikely(len < n) { + if len < N { return Err(Error::ValueStackUnderflow); } - Ok(&self.stack[len - n..len]) + Ok(RawWasmValue::from(&self.stack[len - N..])) } - #[inline] - pub(crate) fn pop_n(&mut self, n: usize) -> Result<&[RawWasmValue]> { - match self.stack.pop_n(n) { - Some(v) => Ok(v), - None => { - cold(); - Err(Error::ValueStackUnderflow) - } + pub(crate) fn pop(&mut self) -> Result> { + let len = self.stack.len(); + if len < N { + return Err(Error::ValueStackUnderflow); } - } -} -#[inline(always)] -fn truncate_keep(data: &mut BoxVec, n: u32, end_keep: u32) { - let total_to_keep = n + end_keep; - let len = data.len() as u32; - assert!(len >= total_to_keep, "RawWasmValueotal to keep should be less than or equal to self.top"); - - if len <= total_to_keep { - return; // No need to truncate if the current size is already less than or equal to total_to_keep + let mut bytes = [0; N]; + bytes.copy_from_slice(&self.stack[len - N..]); + self.stack.truncate(len - N); + Ok(RawWasmValue(bytes)) } - let items_to_remove = len - total_to_keep; - let remove_start_index = (len - items_to_remove - end_keep) as usize; - let remove_end_index = (len - end_keep) as usize; - data.drain(remove_start_index..remove_end_index); -} - -#[cfg(test)] -mod tests { - use super::*; + pub(crate) fn push(&mut self, value: RawWasmValue) { + self.stack.extend_from_slice(&value.0); + } - #[test] - fn test_value_stack() { - let mut stack = ValueStack::default(); - stack.push(1.into()); - stack.push(2.into()); - stack.push(3.into()); - assert_eq!(stack.len(), 3); - assert_eq!(i32::from(stack.pop().unwrap()), 3); - assert_eq!(stack.len(), 2); - assert_eq!(i32::from(stack.pop().unwrap()), 2); - assert_eq!(stack.len(), 1); - assert_eq!(i32::from(stack.pop().unwrap()), 1); - assert_eq!(stack.len(), 0); + pub(crate) fn pop_n_typed(&mut self, tys: &[ValType]) -> Vec { + let len: usize = tys.iter().map(|ty| ty.size()).sum(); + let values = bytes_to_wasmvalues(&self.stack[self.stack.len() - len..], tys); + self.stack.truncate(self.stack.len() - len); + values } - #[test] - fn test_truncate_keep() { - macro_rules! test_macro { - ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { - $( - let mut stack = ValueStack::default(); - stack.push(1.into()); - stack.push(2.into()); - stack.push(3.into()); - stack.push(4.into()); - stack.push(5.into()); - stack.truncate_keep($n, $end_keep); - assert_eq!(stack.len(), $expected); - )* - }; - } + pub(crate) fn pop_locals(&mut self, locals: &[ValType]) -> Vec<[u8; 16]> { + let len: usize = locals.iter().map(|ty| ty.size()).sum(); + let values = bytes_to_localvalues(&self.stack[self.stack.len() - len..], locals); + self.stack.truncate(self.stack.len() - len); + values + } - test_macro! { - 0, 0, 0, - 1, 0, 1, - 0, 1, 1, - 1, 1, 2, - 2, 1, 3, - 2, 2, 4 - } + pub(crate) fn push_typed(&mut self, values: &[WasmValue]) { + values.iter().for_each(|v| wasmvalue_to_bytes(*v, |bytes| self.stack.extend_from_slice(bytes))); } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs.old b/crates/tinywasm/src/runtime/stack/value_stack.rs.old new file mode 100644 index 0000000..10fe264 --- /dev/null +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs.old @@ -0,0 +1,266 @@ +use crate::{boxvec::BoxVec, cold, runtime::RawWasmValue, unlikely, Error, Result}; +use alloc::vec::Vec; +use tinywasm_types::{ValType, WasmValue}; + +use super::BlockFrame; + +pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128; + +#[cfg(feature = "simd")] +use crate::runtime::raw_simd::RawSimdWasmValue; + +#[derive(Debug)] +pub(crate) struct ValueStack { + pub(crate) stack: BoxVec, + + #[cfg(feature = "simd")] + simd_stack: BoxVec, +} + +impl Default for ValueStack { + fn default() -> Self { + Self { + stack: BoxVec::with_capacity(VALUE_STACK_SIZE), + + #[cfg(feature = "simd")] + simd_stack: BoxVec::with_capacity(SIMD_VALUE_STACK_SIZE), + } + } +} + +impl ValueStack { + #[inline] + pub(crate) fn extend_from_typed(&mut self, values: &[WasmValue]) { + #[cfg(not(feature = "simd"))] + self.stack.extend(values.iter().map(|v| RawWasmValue::from(*v))); + + #[cfg(feature = "simd")] + { + values.iter().for_each(|v| match v { + WasmValue::V128(v) => self.simd_stack.push(RawSimdWasmValue::from(*v)), + v => self.stack.push(RawWasmValue::from(*v)), + }); + } + } + + #[inline(always)] + pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { + let v = self.last_mut()?; + *v = func(*v); + Ok(()) + } + + #[inline(always)] + pub(crate) fn replace_top_trap(&mut self, func: fn(RawWasmValue) -> Result) -> Result<()> { + let v = self.last_mut()?; + *v = func(*v)?; + Ok(()) + } + + #[inline(always)] + pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> { + let v2 = self.pop()?; + let v1 = self.last_mut()?; + *v1 = func(*v1, v2); + Ok(()) + } + + #[inline(always)] + pub(crate) fn calculate_trap( + &mut self, + func: fn(RawWasmValue, RawWasmValue) -> Result, + ) -> Result<()> { + let v2 = self.pop()?; + let v1 = self.last_mut()?; + *v1 = func(*v1, v2)?; + Ok(()) + } + + #[inline(always)] + pub(crate) fn len(&self) -> usize { + self.stack.len() + } + + #[cfg(feature = "simd")] + #[inline(always)] + pub(crate) fn simd_len(&self) -> usize { + self.simd_stack.len() + } + + #[inline] + pub(crate) fn truncate_keep(&mut self, n: u32, end_keep: u32) { + truncate_keep(&mut self.stack, n, end_keep); + } + + #[cfg(feature = "simd")] + #[inline] + pub(crate) fn truncate_keep_simd(&mut self, n: u16, end_keep: u32) { + truncate_keep(&mut self.simd_stack, n as u32, end_keep); + } + + #[inline(always)] + pub(crate) fn push(&mut self, value: RawWasmValue) { + self.stack.push(value); + } + + #[inline(always)] + pub(crate) fn extend_from_slice(&mut self, values: &[RawWasmValue]) { + self.stack.extend_from_slice(values); + } + + #[inline] + pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { + match self.stack.last_mut() { + Some(v) => Ok(v), + None => { + cold(); // cold in here instead of the stack makes a huge performance difference + Err(Error::ValueStackUnderflow) + } + } + } + + #[inline] + pub(crate) fn last(&self) -> Result<&RawWasmValue> { + match self.stack.last() { + Some(v) => Ok(v), + None => { + cold(); // cold in here instead of the stack makes a huge performance difference + Err(Error::ValueStackUnderflow) + } + } + } + + #[inline(always)] + pub(crate) fn pop(&mut self) -> Result { + match self.stack.pop() { + Some(v) => Ok(v), + None => { + cold(); // cold in here instead of the stack makes a huge performance difference + Err(Error::ValueStackUnderflow) + } + } + } + + #[inline] + pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result> { + #[cfg(not(feature = "simd"))] + return Ok(self.pop_n(types.len())?.iter().zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect()); + + #[cfg(feature = "simd")] + { + let mut values = Vec::with_capacity(types.len()); + for ty in types { + match ty { + ValType::V128 => values.push(WasmValue::V128(self.simd_stack.pop().unwrap().into())), + ty => values.push(self.pop()?.attach_type(*ty)), + } + } + Ok(values) + } + } + + #[inline] + pub(crate) fn break_to_results(&mut self, bf: &BlockFrame) { + let end = self.stack.len() - bf.results as usize; + self.stack.drain(bf.stack_ptr as usize..end); + + #[cfg(feature = "simd")] + let end = self.simd_stack.len() - bf.simd_results as usize; + #[cfg(feature = "simd")] + self.simd_stack.drain(bf.simd_stack_ptr as usize..end); + } + + #[inline] + pub(crate) fn break_to_params(&mut self, bf: &BlockFrame) { + let end = self.stack.len() - bf.params as usize; + self.stack.drain(bf.stack_ptr as usize..end); + + #[cfg(feature = "simd")] + let end = self.simd_stack.len() - bf.simd_params as usize; + #[cfg(feature = "simd")] + self.simd_stack.drain(bf.simd_stack_ptr as usize..end); + } + + #[inline] + pub(crate) fn last_n(&self, n: usize) -> Result<&[RawWasmValue]> { + let len = self.stack.len(); + if unlikely(len < n) { + return Err(Error::ValueStackUnderflow); + } + Ok(&self.stack[len - n..len]) + } + + #[inline] + pub(crate) fn pop_n(&mut self, n: usize) -> Result<&[RawWasmValue]> { + match self.stack.pop_n(n) { + Some(v) => Ok(v), + None => { + cold(); + Err(Error::ValueStackUnderflow) + } + } + } +} + +#[inline(always)] +fn truncate_keep(data: &mut BoxVec, n: u32, end_keep: u32) { + let total_to_keep = n + end_keep; + let len = data.len() as u32; + assert!(len >= total_to_keep, "RawWasmValueotal to keep should be less than or equal to self.top"); + + if len <= total_to_keep { + return; // No need to truncate if the current size is already less than or equal to total_to_keep + } + + let items_to_remove = len - total_to_keep; + let remove_start_index = (len - items_to_remove - end_keep) as usize; + let remove_end_index = (len - end_keep) as usize; + data.drain(remove_start_index..remove_end_index); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_value_stack() { + let mut stack = ValueStack::default(); + stack.push(1.into()); + stack.push(2.into()); + stack.push(3.into()); + assert_eq!(stack.len(), 3); + assert_eq!(i32::from(stack.pop().unwrap()), 3); + assert_eq!(stack.len(), 2); + assert_eq!(i32::from(stack.pop().unwrap()), 2); + assert_eq!(stack.len(), 1); + assert_eq!(i32::from(stack.pop().unwrap()), 1); + assert_eq!(stack.len(), 0); + } + + #[test] + fn test_truncate_keep() { + macro_rules! test_macro { + ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { + $( + let mut stack = ValueStack::default(); + stack.push(1.into()); + stack.push(2.into()); + stack.push(3.into()); + stack.push(4.into()); + stack.push(5.into()); + stack.truncate_keep($n, $end_keep); + assert_eq!(stack.len(), $expected); + )* + }; + } + + test_macro! { + 0, 0, 0, + 1, 0, 1, + 0, 1, 1, + 1, 1, 2, + 2, 1, 3, + 2, 2, 4 + } + } +} diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index f72dcab..03ed0e5 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -161,7 +161,7 @@ impl Store { /// Get the global at the actual index in the store #[inline(always)] - pub fn get_global_val(&self, addr: MemAddr) -> Result { + pub(crate) fn get_global_val(&self, addr: MemAddr) -> Result { self.data .globals .get(addr as usize) diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index d67ba83..a038c4b 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -118,10 +118,10 @@ pub enum Instruction { Return, Call(FuncAddr), CallIndirect(TypeAddr, TableAddr), - + // > Parametric Instructions // See - Drop, + Drop(ValType), Select(Option), // > Variable Instructions diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 6c422d0..eeea469 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -147,6 +147,18 @@ impl ValType { matches!(self, ValType::V128) } + pub const fn size(&self) -> usize { + match self { + ValType::I32 => 4, + ValType::I64 => 8, + ValType::F32 => 4, + ValType::F64 => 8, + ValType::V128 => 16, + ValType::RefFunc => 8, + ValType::RefExtern => 8, + } + } + pub(crate) fn to_byte(self) -> u8 { match self { ValType::I32 => 0x7F, From d2dea0524a5cc36260c0ef464dff6b2bf06e05e8 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 26 Jun 2024 21:44:37 +0200 Subject: [PATCH 02/10] wip: compact value stack Signed-off-by: Henry Gressmann --- crates/parser/src/visit.rs | 37 +- crates/tinywasm/src/boxvec.rs | 148 -------- crates/tinywasm/src/func.rs | 6 +- crates/tinywasm/src/lib.rs | 1 - .../src/runtime/interpreter/macros.rs | 44 +-- .../tinywasm/src/runtime/interpreter/mod.rs | 324 +++++++++--------- crates/tinywasm/src/runtime/mod.rs | 8 +- crates/tinywasm/src/runtime/raw.rs.old | 123 ------- crates/tinywasm/src/runtime/raw_simd.rs.old | 27 -- .../tinywasm/src/runtime/stack/block_stack.rs | 15 +- .../tinywasm/src/runtime/stack/call_stack.rs | 29 +- crates/tinywasm/src/runtime/stack/mod.rs | 3 +- .../tinywasm/src/runtime/stack/value_stack.rs | 314 ++++++++--------- .../src/runtime/stack/value_stack.rs.old | 266 -------------- crates/tinywasm/src/runtime/stack/values.rs | 128 +++++++ crates/tinywasm/src/store/global.rs | 8 +- crates/tinywasm/src/store/mod.rs | 32 +- crates/types/src/instructions.rs | 11 +- crates/types/src/value.rs | 12 - 19 files changed, 543 insertions(+), 993 deletions(-) delete mode 100644 crates/tinywasm/src/boxvec.rs delete mode 100644 crates/tinywasm/src/runtime/raw.rs.old delete mode 100644 crates/tinywasm/src/runtime/raw_simd.rs.old delete mode 100644 crates/tinywasm/src/runtime/stack/value_stack.rs.old create mode 100644 crates/tinywasm/src/runtime/stack/values.rs diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 3e2530f..679143c 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -82,10 +82,10 @@ pub(crate) struct FunctionBuilder { } impl FunctionBuilder { - pub(crate) fn validator_visitor<'this>( - &'this mut self, + pub(crate) fn validator_visitor( + &mut self, offset: usize, - ) -> impl VisitOperator> + 'this { + ) -> impl VisitOperator<'_, Output = Result<(), wasmparser::BinaryReaderError>> { self.validator.visitor(offset) } @@ -173,7 +173,6 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild visit_unreachable, Instruction::Unreachable, visit_nop, Instruction::Nop, visit_return, Instruction::Return, - visit_select, Instruction::Select(None), visit_i32_eqz, Instruction::I32Eqz, visit_i32_eq, Instruction::I32Eq, visit_i32_ne, Instruction::I32Ne, @@ -318,14 +317,24 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild fn visit_drop(&mut self) -> Self::Output { match self.validator.get_operand_type(0) { - Some(Some(t)) => { - let t = convert_valtype(&t); - self.instructions.push(Instruction::Drop(t)) - } + Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + tinywasm_types::ValType::I32 => Instruction::Drop32, + tinywasm_types::ValType::F32 => Instruction::Drop32, + tinywasm_types::ValType::I64 => Instruction::Drop64, + tinywasm_types::ValType::F64 => Instruction::Drop64, + tinywasm_types::ValType::V128 => Instruction::Drop128, + tinywasm_types::ValType::RefExtern => Instruction::DropRef, + tinywasm_types::ValType::RefFunc => Instruction::DropRef, + }), _ => unreachable!("this should have been caught by the validator"), } } - + fn visit_select(&mut self) -> Self::Output { + match self.validator.get_operand_type(0) { + Some(Some(t)) => self.visit_typed_select(t), + _ => unreachable!("Unknow type for select"), + } + } fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { let arg = MemoryArg { offset: memarg.offset, mem_addr: memarg.memory }; let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; @@ -539,7 +548,15 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_typed_select(&mut self, ty: wasmparser::ValType) -> Self::Output { - self.instructions.push(Instruction::Select(Some(convert_valtype(&ty)))) + self.instructions.push(match convert_valtype(&ty) { + tinywasm_types::ValType::I32 => Instruction::Select32, + tinywasm_types::ValType::F32 => Instruction::Select32, + tinywasm_types::ValType::I64 => Instruction::Select64, + tinywasm_types::ValType::F64 => Instruction::Select64, + tinywasm_types::ValType::V128 => Instruction::Select128, + tinywasm_types::ValType::RefExtern => Instruction::SelectRef, + tinywasm_types::ValType::RefFunc => Instruction::SelectRef, + }) } define_primitive_operands! { diff --git a/crates/tinywasm/src/boxvec.rs b/crates/tinywasm/src/boxvec.rs deleted file mode 100644 index 9c6732d..0000000 --- a/crates/tinywasm/src/boxvec.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::unlikely; -use alloc::{borrow::Cow, boxed::Box, vec::Vec}; -use core::ops::RangeBounds; - -// A Vec-like type that doesn't deallocate memory when popping elements. -#[derive(Debug)] -pub(crate) struct BoxVec { - pub(crate) data: Box<[T]>, - pub(crate) end: usize, -} - -impl BoxVec { - #[inline(always)] - pub(crate) fn with_capacity(capacity: usize) -> Self { - let mut data = Vec::new(); - data.reserve_exact(capacity); - data.resize_with(capacity, T::default); - Self { data: data.into_boxed_slice(), end: 0 } - } - - #[inline(always)] - pub(crate) fn push(&mut self, value: T) { - assert!(self.end <= self.data.len(), "stack overflow"); - self.data[self.end] = value; - self.end += 1; - } - - #[inline(always)] - pub(crate) fn pop(&mut self) -> Option { - assert!(self.end <= self.data.len(), "invalid stack state (should be impossible)"); - if unlikely(self.end == 0) { - None - } else { - self.end -= 1; - Some(self.data[self.end]) - } - } - - #[inline(always)] - pub(crate) fn len(&self) -> usize { - self.end - } - - #[inline(always)] - pub(crate) fn extend_from_slice(&mut self, values: &[T]) { - let new_end = self.end + values.len(); - assert!(new_end <= self.data.len(), "stack overflow"); - self.data[self.end..new_end].copy_from_slice(values); - self.end = new_end; - } - - #[inline(always)] - pub(crate) fn last_mut(&mut self) -> Option<&mut T> { - assert!(self.end <= self.data.len(), "invalid stack state (should be impossible)"); - if unlikely(self.end == 0) { - None - } else { - Some(&mut self.data[self.end - 1]) - } - } - - #[inline(always)] - pub(crate) fn last(&self) -> Option<&T> { - assert!(self.end <= self.data.len(), "invalid stack state (should be impossible)"); - if unlikely(self.end == 0) { - None - } else { - Some(&self.data[self.end - 1]) - } - } - - #[inline(always)] - pub(crate) fn pop_n(&mut self, n: usize) -> Option<&[T]> { - assert!(self.end <= self.data.len(), "invalid stack state (should be impossible)"); - if unlikely(self.end < n) { - None - } else { - let start = self.end - n; - let end = self.end; - self.end = start; - Some(&self.data[start..end]) - } - } - - #[inline(always)] - pub(crate) fn extend(&mut self, iter: impl Iterator) { - let (lower, _) = iter.size_hint(); - let upper = lower; - let new_end = self.end + upper; - assert!(new_end <= self.data.len(), "stack overflow"); - for (i, value) in iter.enumerate() { - self.data[self.end + i] = value; - } - self.end = new_end; - } - - #[inline(always)] - pub(crate) fn drain(&mut self, range: impl RangeBounds) -> Cow<'_, [T]> { - let start = match range.start_bound() { - core::ops::Bound::Included(&start) => start, - core::ops::Bound::Excluded(&start) => start + 1, - core::ops::Bound::Unbounded => 0, - }; - let end = match range.end_bound() { - core::ops::Bound::Included(&end) => end + 1, - core::ops::Bound::Excluded(&end) => end, - core::ops::Bound::Unbounded => self.end, - }; - - assert!(start <= end); - assert!(end <= self.end); - - if end == self.end { - self.end = start; - return Cow::Borrowed(&self.data[start..end]); - } - - let drain = self.data[start..end].to_vec(); - self.data.copy_within(end..self.end, start); - self.end -= end - start; - Cow::Owned(drain) - } -} - -impl core::ops::Index for BoxVec { - type Output = T; - - #[inline(always)] - fn index(&self, index: usize) -> &T { - &self.data[index] - } -} - -impl core::ops::Index> for BoxVec { - type Output = [T]; - - #[inline(always)] - fn index(&self, index: core::ops::Range) -> &[T] { - &self.data[index] - } -} - -impl core::ops::IndexMut for BoxVec { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut T { - &mut self.data[index] - } -} diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 2373536..7c30e4a 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -59,7 +59,7 @@ impl FuncHandle { }; // 6. Let f be the dummy frame - let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, ¶ms, 0); + let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, 0); // 7. Push the frame f to the call stack // & 8. Push the values to the stack (Not needed since the call frame owns the values) @@ -70,13 +70,13 @@ impl FuncHandle { runtime.exec(store, &mut stack)?; // Once the function returns: - let result_m = func_ty.results.len(); + // let result_m = func_ty.results.len(); // 1. Assert: m values are on the top of the stack (Ensured by validation) // assert!(stack.values.len() >= result_m); // 2. Pop m values from the stack - let res = stack.values.pop_n_typed(&func_ty.results); + let res = stack.values.pop_many(&func_ty.results)?; // The values are returned as the results of the invocation. Ok(res) diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 0ab61f8..9c48ee0 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -100,7 +100,6 @@ pub use module::Module; pub use reference::*; pub use store::*; -mod boxvec; mod func; mod imports; mod instance; diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs index b2042c2..5e725fb 100644 --- a/crates/tinywasm/src/runtime/interpreter/macros.rs +++ b/crates/tinywasm/src/runtime/interpreter/macros.rs @@ -41,12 +41,12 @@ macro_rules! conv { /// Convert a value on the stack with error checking macro_rules! checked_conv_float { // Direct conversion with error checking (two types) - ($from:tt, $to:tt, $self:expr) => { - checked_conv_float!($from, $to, $to, $self) + ($size:expr, $from:tt, $to:tt, $self:expr) => { + checked_conv_float!($size, $from, $to, $to, $self) }; // Conversion with an intermediate unsigned type and error checking (three types) - ($from:tt, $intermediate:tt, $to:tt, $self:expr) => { - $self.stack.values.replace_top_trap(|v| { + ($size:expr, $from:tt, $intermediate:tt, $to:tt, $self:expr) => { + $self.stack.values.replace_top_trap::<$size>(|v| { let (min, max) = float_min_max!($from, $intermediate); let a: $from = v.into(); if unlikely(a.is_nan()) { @@ -62,8 +62,8 @@ macro_rules! checked_conv_float { /// Compare two values on the stack macro_rules! comp { - ($op:tt, $to:ty, $self:ident) => { - $self.stack.values.calculate(|a, b| { + ($op:tt, $size:expr, $to:ty, $self:ident) => { + $self.stack.values.calculate::<$size>(|a, b| { ((<$to>::from(a) $op <$to>::from(b)) as i32).into() })? }; @@ -71,22 +71,22 @@ macro_rules! comp { /// Compare a value on the stack to zero macro_rules! comp_zero { - ($op:tt, $ty:ty, $self:expr) => { - $self.stack.values.replace_top(|v| ((<$ty>::from(v) $op 0) as i32).into())? + ($op:tt, $size:expr, $ty:ty, $self:expr) => { + $self.stack.values.replace_top::<$size>(|v| ((<$ty>::from(v) $op 0) as i32).into())? }; } /// Apply an arithmetic method to two values on the stack macro_rules! arithmetic { - ($op:ident, $to:ty, $self:expr) => { - $self.stack.values.calculate(|a, b| { + ($op:ident, $size:expr, $to:ty, $self:expr) => { + $self.stack.values.calculate::<$size>(|a, b| { (<$to>::from(a).$op(<$to>::from(b)) as $to).into() })? }; // also allow operators such as +, - - ($op:tt, $ty:ty, $self:expr) => { - $self.stack.values.calculate(|a, b| { + ($op:tt, $size:expr, $ty:ty, $self:expr) => { + $self.stack.values.calculate::<$size>(|a, b| { ((<$ty>::from(a) $op <$ty>::from(b)) as $ty).into() })? }; @@ -94,19 +94,19 @@ macro_rules! arithmetic { /// Apply an arithmetic method to a single value on the stack macro_rules! arithmetic_single { - ($op:ident, $ty:ty, $self:expr) => { - arithmetic_single!($op, $ty, $ty, $self) + ($op:ident, $size:expr, $ty:ty, $self:expr) => { + arithmetic_single!($op, $size, $ty, $ty, $self) }; - ($op:ident, $from:ty, $to:ty, $self:expr) => { - $self.stack.values.replace_top(|v| (<$from>::from(v).$op() as $to).into())? + ($op:ident, $size:expr, $from:ty, $to:ty, $self:expr) => { + $self.stack.values.replace_top::<$size>(|v| (<$from>::from(v).$op() as $to).into())? }; } /// Apply an arithmetic operation to two values on the stack with error checking macro_rules! checked_int_arithmetic { - ($op:ident, $to:ty, $self:expr) => { - $self.stack.values.calculate_trap(|a, b| { + ($op:ident, $size:expr, $to:ty, $self:expr) => { + $self.stack.values.calculate_trap::<$size>(|a, b| { let a: $to = a.into(); let b: $to = b.into(); @@ -120,12 +120,4 @@ macro_rules! checked_int_arithmetic { }; } -pub(super) use arithmetic; -pub(super) use arithmetic_single; pub(super) use break_to; -pub(super) use checked_conv_float; -pub(super) use checked_int_arithmetic; -pub(super) use comp; -pub(super) use comp_zero; -pub(super) use conv; -pub(super) use float_min_max; diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 90f4d8d..ecfe02b 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -2,8 +2,8 @@ use alloc::{format, rc::Rc, string::ToString}; use core::ops::ControlFlow; use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction}; -use super::stack::{BlockFrame, BlockType}; -use super::{InterpreterRuntime, Stack}; +use super::stack::{BlockFrame, BlockType, StackHeight}; +use super::{values::*, InterpreterRuntime, Stack}; use crate::runtime::CallFrame; use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap}; @@ -55,8 +55,17 @@ impl<'store, 'stack> Executor<'store, 'stack> { match self.cf.fetch_instr() { Nop => self.exec_noop(), Unreachable => self.exec_unreachable()?, - Drop(t) => self.exec_drop(t.size())?, - Select(_valtype) => self.exec_select()?, + + Drop32 => self.stack.values.drop::()?, + Drop64 => self.stack.values.drop::()?, + Drop128 => self.stack.values.drop::()?, + DropRef => self.stack.values.drop::()?, + + Select32 => self.stack.values.select::()?, + Select64 => self.stack.values.select::()?, + Select128 => self.stack.values.select::()?, + SelectRef => self.stack.values.select::()?, + Call(v) => self.exec_call_direct(*v)?, CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?, @@ -77,12 +86,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { GlobalGet(global_index) => self.exec_global_get(*global_index)?, GlobalSet(global_index) => self.exec_global_set(*global_index)?, - I32Const(val) => self.exec_const(*val), - I64Const(val) => self.exec_const(*val), - F32Const(val) => self.exec_const(*val), - F64Const(val) => self.exec_const(*val), - RefFunc(func_idx) => self.exec_const(*func_idx), - RefNull(_) => self.exec_const(-1i64), + I32Const(val) => self.stack.values.push_32(*val), + I64Const(val) => self.stack.values.push_64(*val), + F32Const(val) => self.stack.values.push_32(val.to_bits() as i32), + F64Const(val) => self.stack.values.push_64(val.to_bits() as i64), + RefFunc(func_idx) => self.stack.values.push_ref(Some(*func_idx)), // do we need to resolve the function index? + RefNull(_) => self.stack.values.push_ref(None), RefIsNull => self.exec_ref_is_null()?, MemorySize(addr) => self.exec_memory_size(*addr)?, @@ -96,15 +105,44 @@ impl<'store, 'stack> Executor<'store, 'stack> { ElemDrop(elem_index) => self.exec_elem_drop(*elem_index)?, TableCopy { from, to } => self.exec_table_copy(*from, *to)?, - I32Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I64Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - F32Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - F64Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I32Store8 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I32Store16 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I64Store8 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I64Store16 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, - I64Store32 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset)?, + I32Store { mem_addr, offset } => { + let v = self.stack.values.pop_32()?; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + I64Store { mem_addr, offset } => { + let v = self.stack.values.pop_64()?; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + F32Store { mem_addr, offset } => { + let v = f32::from_bits(self.stack.values.pop_32()? as u32); + self.exec_mem_store::(v, *mem_addr, *offset)? + } + F64Store { mem_addr, offset } => { + let v = f64::from_bits(self.stack.values.pop_64()? as u64); + self.exec_mem_store::(v, *mem_addr, *offset)? + } + + // TODO: this prob. needs specific conversion functions that truncate the underlying bits + I32Store8 { mem_addr, offset } => { + let v = self.stack.values.pop_32()? as i8; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + I32Store16 { mem_addr, offset } => { + let v = self.stack.values.pop_32()? as i16; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + I64Store8 { mem_addr, offset } => { + let v = self.stack.values.pop_64()? as i8; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + I64Store16 { mem_addr, offset } => { + let v = self.stack.values.pop_64()? as i16; + self.exec_mem_store::(v, *mem_addr, *offset)? + } + I64Store32 { mem_addr, offset } => { + let v = self.stack.values.pop_64()? as i32; + self.exec_mem_store::(v, *mem_addr, *offset)? + } I32Load { mem_addr, offset } => self.exec_mem_load::(|v| v, *mem_addr, *offset)?, I64Load { mem_addr, offset } => self.exec_mem_load::(|v| v, *mem_addr, *offset)?, @@ -121,7 +159,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64Load32S { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, I64Load32U { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, - // I64Eqz => comp_zero!(==, i64, self), + // I64Eqz => comp_zero!(==, 8, i64, self), // I32Eqz => comp_zero!(==, i32, self), // I32Eq => comp!(==, i32, self), @@ -260,15 +298,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} // unsigned versions of these are a bit broken atm - I32TruncF32S => checked_conv_float!(f32, i32, self), - I32TruncF64S => checked_conv_float!(f64, i32, self), - I32TruncF32U => checked_conv_float!(f32, u32, i32, self), - I32TruncF64U => checked_conv_float!(f64, u32, i32, self), - I64TruncF32S => checked_conv_float!(f32, i64, self), - I64TruncF64S => checked_conv_float!(f64, i64, self), - I64TruncF32U => checked_conv_float!(f32, u64, i64, self), - I64TruncF64U => checked_conv_float!(f64, u64, i64, self), - + // I32TruncF32S => checked_conv_float!(4, f32, i32, self), + // I32TruncF64S => checked_conv_float!(8, f64, i32, self), + // I32TruncF32U => checked_conv_float!(4, f32, u32, i32, self), + // I32TruncF64U => checked_conv_float!(8, f64, u32, i32, self), + // I64TruncF32S => checked_conv_float!(4, f32, i64, self), + // I64TruncF64S => checked_conv_float!(8, f64, i64, self), + // I64TruncF32U => checked_conv_float!(4, f32, u64, i64, self), + // I64TruncF64U => checked_conv_float!(8, f64, u64, i64, self), TableGet(table_idx) => self.exec_table_get(*table_idx)?, TableSet(table_idx) => self.exec_table_set(*table_idx)?, TableSize(table_idx) => self.exec_table_size(*table_idx)?, @@ -298,6 +335,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32StoreLocal { local_a, local_b, offset, mem_addr } => { self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)? } + instr => todo!("instruction not implemented: {:?}", instr), }; self.cf.instr_ptr += 1; @@ -310,22 +348,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { Err(Error::Trap(Trap::Unreachable)) } - fn exec_drop(&mut self, size: usize) -> Result<()> { - self.stack.values.drop(size) - } - fn exec_select(&mut self) -> Result<()> { - let cond: i32 = self.stack.values.pop()?.into(); - let val2 = self.stack.values.pop()?; - - // if cond != 0, we already have the right value on the stack - if cond == 0 { - *self.stack.values.last_mut()? = val2; - } - Ok(()) - } fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> Result<()> { - let params = self.stack.values.pop_locals(&wasm_func.ty.params); - let new_call_frame = CallFrame::new_raw(wasm_func, owner, ¶ms, self.stack.blocks.len() as u32); + let params = self.stack.values.pop_many_raw(&wasm_func.ty.params)?; + let new_call_frame = CallFrame::new_raw(wasm_func, owner, params.into_iter(), self.stack.blocks.len() as u32); self.cf.instr_ptr += 1; // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); @@ -338,9 +363,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { crate::Function::Wasm(wasm_func) => wasm_func, crate::Function::Host(host_func) => { let func = &host_func.clone(); - let params = self.stack.values.pop_params(&host_func.ty.params)?; + let params = self.stack.values.pop_many(&host_func.ty.params)?; let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; - self.stack.values.extend_from_typed(&res); + self.stack.values.extend_from_wasmvalues(&res); return Ok(()); } }; @@ -350,7 +375,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { // verify that the table is of the right type, this should be validated by the parser already let func_ref = { let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?; - let table_idx: u32 = self.stack.values.pop()?.into(); + let table_idx: u32 = self.stack.values.pop_32()? as u32; let table = table.borrow(); assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); table @@ -373,9 +398,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { } let host_func = host_func.clone(); - let params = self.stack.values.pop_params(&host_func.ty.params)?; + let params = self.stack.values.pop_many(&host_func.ty.params)?; let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; - self.stack.values.extend_from_typed(&res); + self.stack.values.extend_from_wasmvalues(&res); return Ok(()); } }; @@ -390,7 +415,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> { // truthy value is on the top of the stack, so enter the then block - if i32::from(self.stack.values.pop()?) != 0 { + if self.stack.values.pop_32()? != 0 { self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, args); return Ok(()); } @@ -412,57 +437,23 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) { - #[cfg(not(feature = "simd"))] - { - let (params, results) = match args { - BlockArgs::Empty => (0, 0), - BlockArgs::Type(_) => (0, 1), - BlockArgs::FuncType(t) => { - let ty = self.module.func_ty(t); - (ty.params.len() as u8, ty.results.len() as u8) - } - }; - - self.stack.blocks.push(BlockFrame { - instr_ptr, - end_instr_offset, - stack_ptr: self.stack.values.len() as u32 - params as u32, - results, - params, - ty, - }); + let (params, results) = match args { + BlockArgs::Empty => (StackHeight::default(), StackHeight::default()), + BlockArgs::Type(t) => (StackHeight::default(), t.into()), + BlockArgs::FuncType(t) => { + let ty = self.module.func_ty(t); + ((&*ty.params).into(), (&*ty.results).into()) + } }; - #[cfg(feature = "simd")] - { - let (params, results, simd_params, simd_results) = match args { - BlockArgs::Empty => (0, 0, 0, 0), - BlockArgs::Type(t) => match t { - ValType::V128 => (0, 0, 0, 1), - _ => (0, 1, 0, 0), - }, - BlockArgs::FuncType(t) => { - let ty = self.module.func_ty(t); - let simd_params = ty.params.iter().filter(|t| t.is_simd()).count() as u8; - let simd_results = ty.results.iter().filter(|t| t.is_simd()).count() as u8; - let params = ty.params.len() as u8 - simd_params; - let results = ty.results.len() as u8 - simd_results; - (params, results, simd_params, simd_results) - } - }; - - self.stack.blocks.push(BlockFrame { - instr_ptr, - end_instr_offset, - stack_ptr: self.stack.values.len() as u32 - params as u32, - simd_stack_ptr: self.stack.values.simd_len() as u16 - simd_params as u16, - results, - simd_params, - simd_results, - params, - ty, - }); - }; + self.stack.blocks.push(BlockFrame { + instr_ptr, + end_instr_offset, + stack_ptr: self.stack.values.height(), + results, + params, + ty, + }); } fn exec_br(&mut self, to: u32) -> Result> { break_to!(to, self); @@ -470,8 +461,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(ControlFlow::Continue(())) } fn exec_br_if(&mut self, to: u32) -> Result> { - let val: i32 = self.stack.values.pop()?.into(); - if val != 0 { + if self.stack.values.pop_32()? != 0 { break_to!(to, self); } self.cf.incr_instr_ptr(); @@ -484,7 +474,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, self.cf.instructions().len()))); } - let idx: i32 = self.stack.values.pop()?.into(); + let idx = self.stack.values.pop_32()?; match self.cf.instructions()[start..end].get(idx as usize) { None => break_to!(default, self), Some(Instruction::BrLabel(to)) => break_to!(*to, self), @@ -510,9 +500,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_end_block(&mut self) -> Result<()> { let block = self.stack.blocks.pop()?; - #[cfg(feature = "simd")] - self.stack.values.truncate_keep_simd(block.simd_stack_ptr, block.simd_results as u32); - self.stack.values.truncate_keep(block.stack_ptr, block.results as u32); + self.stack.values.truncate_keep(&block.stack_ptr, &block.results); Ok(()) } @@ -520,46 +508,47 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push(self.cf.get_local(local_index)); } fn exec_local_set(&mut self, local_index: u32) -> Result<()> { - self.stack.values.pop().map(|val| self.cf.set_local(local_index, val)) + todo!("needs to be updated"); + // self.stack.values.pop().map(|val| self.cf.set_local(local_index, val)) } fn exec_local_tee(&mut self, local_index: u32) -> Result<()> { - self.stack.values.last().map(|val| self.cf.set_local(local_index, *val)) + todo!("needs to be updated"); + // self.stack.values.last().map(|val| self.cf.set_local(local_index, *val)) } fn exec_global_get(&mut self, global_index: u32) -> Result<()> { self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?); Ok(()) } fn exec_global_set(&mut self, global_index: u32) -> Result<()> { - self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop()?) - } - - fn exec_const(&mut self, val: impl Into) { - self.stack.values.push(val.into()); + todo!("needs to be updated"); + // self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop_raw()?) } fn exec_ref_is_null(&mut self) -> Result<()> { - self.stack.values.replace_top::<8>(|val| ((i32::from(val) == -1) as i32).into()) + let is_null = self.stack.values.pop_ref()?.is_none() as i32; + self.stack.values.push_32(is_null); + Ok(()) } fn exec_memory_size(&mut self, addr: u32) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?; - self.stack.values.push((mem.borrow().page_count() as i32).into()); + self.stack.values.push_32(mem.borrow().page_count() as i32); Ok(()) } fn exec_memory_grow(&mut self, addr: u32) -> Result<()> { let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?.borrow_mut(); let prev_size = mem.page_count() as i32; - let pages_delta = self.stack.values.last_mut()?; - *pages_delta = match mem.grow(i32::from(*pages_delta)) { - Some(_) => prev_size.into(), - None => (-1).into(), - }; + let pages_delta = self.stack.values.pop_32()?; + self.stack.values.push_32(match mem.grow(pages_delta) { + Some(_) => prev_size, + None => -1, + }); Ok(()) } fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> { - let size: i32 = self.stack.values.pop()?.into(); - let src: i32 = self.stack.values.pop()?.into(); - let dst: i32 = self.stack.values.pop()?.into(); + let size = self.stack.values.pop_32()?; + let src = self.stack.values.pop_32()?; + let dst = self.stack.values.pop_32()?; if from == to { let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from)?)?.borrow_mut(); @@ -574,18 +563,18 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn exec_memory_fill(&mut self, addr: u32) -> Result<()> { - let size: i32 = self.stack.values.pop()?.into(); - let val: i32 = self.stack.values.pop()?.into(); - let dst: i32 = self.stack.values.pop()?.into(); + let size = self.stack.values.pop_32()?; + let val = self.stack.values.pop_32()?; + let dst = self.stack.values.pop_32()?; let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?; mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; Ok(()) } fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> { - let size: i32 = self.stack.values.pop()?.into(); // n - let offset: i32 = self.stack.values.pop()?.into(); // s - let dst: i32 = self.stack.values.pop()?.into(); // d + let size = self.stack.values.pop_32()?; // n + let offset = self.stack.values.pop_32()?; // s + let dst = self.stack.values.pop_32()?; // d let data = self.store.get_data(self.module.resolve_data_addr(data_index)?)?; let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index)?)?; @@ -615,9 +604,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)?).map(|e| e.drop()) } fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> { - let size: i32 = self.stack.values.pop()?.into(); - let src: i32 = self.stack.values.pop()?.into(); - let dst: i32 = self.stack.values.pop()?.into(); + let size: i32 = self.stack.values.pop_32()?; + let src: i32 = self.stack.values.pop_32()?; + let dst: i32 = self.stack.values.pop_32()?; if from == to { let mut table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow_mut(); @@ -632,14 +621,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } - fn exec_mem_load, const LOAD_SIZE: usize, TARGET: Into>( + fn exec_mem_load, const LOAD_SIZE: usize, TARGET: Into>( &mut self, cast: fn(LOAD) -> TARGET, mem_addr: tinywasm_types::MemAddr, offset: u64, ) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; - let val: u64 = self.stack.values.pop()?.into(); + let val: u64 = self.stack.values.pop_64()? as u64; let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else { cold(); return Err(Error::Trap(crate::Trap::MemoryOutOfBounds { @@ -653,32 +642,31 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push(cast(val).into()); Ok(()) } - fn exec_mem_store + MemStorable, const N: usize>( + fn exec_mem_store, const N: usize>( &mut self, + val: T, mem_addr: tinywasm_types::MemAddr, offset: u64, ) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; - let val: T = self.stack.values.pop()?.into(); let val = val.to_mem_bytes(); - let addr: u64 = self.stack.values.pop()?.into(); - mem.borrow_mut().store((offset + addr) as usize, val.len(), &val)?; + let addr: i64 = self.stack.values.pop_64()?; + mem.borrow_mut().store((offset + addr as u64) as usize, val.len(), &val)?; Ok(()) } fn exec_table_get(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let idx: u32 = self.stack.values.pop()?.into(); - let v = table.borrow().get_wasm_val(idx)?; + let idx: i32 = self.stack.values.pop_32()?; + let v = table.borrow().get_wasm_val(idx as u32)?; self.stack.values.push(v.into()); Ok(()) } fn exec_table_set(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let val = self.stack.values.pop()?.as_reference(); - let idx = self.stack.values.pop()?.into(); + let val = self.stack.values.pop_ref()?; + let idx = self.stack.values.pop_32()? as u32; table.borrow_mut().set(idx, val.into())?; - Ok(()) } fn exec_table_size(&mut self, table_index: u32) -> Result<()> { @@ -692,9 +680,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index)?)?; let elem_len = elem.items.as_ref().map(|items| items.len()).unwrap_or(0); - let size: i32 = self.stack.values.pop()?.into(); // n - let offset: i32 = self.stack.values.pop()?.into(); // s - let dst: i32 = self.stack.values.pop()?.into(); // d + let size: i32 = self.stack.values.pop_32()?; // n + let offset: i32 = self.stack.values.pop_32()?; // s + let dst: i32 = self.stack.values.pop_32()?; // d if unlikely(((size + offset) as usize > elem_len) || ((dst + size) > table_len)) { return Err(Trap::TableOutOfBounds { offset: offset as usize, len: size as usize, max: elem_len }.into()); @@ -719,8 +707,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; let sz = table.borrow().size(); - let n: i32 = self.stack.values.pop()?.into(); - let val = self.stack.values.pop()?.as_reference(); + let n = self.stack.values.pop_32()?; + let val = self.stack.values.pop_ref()?; match table.borrow_mut().grow(n, val.into()) { Ok(_) => self.stack.values.push(sz.into()), @@ -732,9 +720,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_table_fill(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let n: i32 = self.stack.values.pop()?.into(); - let val = self.stack.values.pop()?.as_reference(); - let i: i32 = self.stack.values.pop()?.into(); + let n = self.stack.values.pop_32()?; + let val = self.stack.values.pop_ref()?; + let i = self.stack.values.pop_32()?; if unlikely(i + n > table.borrow().size()) { return Err(Error::Trap(Trap::TableOutOfBounds { @@ -756,45 +744,47 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_i32_const_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?; let val = const_i32.to_mem_bytes(); - let addr: u64 = self.cf.get_local(local).into(); + let addr = self.cf.get_local(local).unwrap_64(); mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; Ok(()) } fn exec_i32_store_local(&mut self, local_a: u32, local_b: u32, offset: u32, mem_addr: u8) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?; - let addr: u64 = self.cf.get_local(local_a).into(); - let val: i32 = self.cf.get_local(local_b).into(); + let addr: u64 = self.cf.get_local(local_a).unwrap_64(); + let val: i32 = self.cf.get_local(local_b).unwrap_32() as i32; let val = val.to_mem_bytes(); mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; Ok(()) } fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) { - let local: i32 = self.cf.get_local(local).into(); + let local: i32 = self.cf.get_local(local).unwrap_32() as i32; self.stack.values.push((local + val).into()); } fn exec_i64_xor_const_rotl(&mut self, rotate_by: i64) -> Result<()> { - let val: i64 = self.stack.values.pop()?.into(); - let res = self.stack.values.last_mut()?; - let mask: i64 = (*res).into(); - *res = (val ^ mask).rotate_left(rotate_by as u32).into(); + let val = self.stack.values.pop_64()?; + let mask = self.stack.values.pop_64()?; + self.stack.values.push_64((val ^ mask).rotate_left(rotate_by as u32)); Ok(()) } fn exec_local_get2(&mut self, a: u32, b: u32) { - self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b)]); + todo!("needs to be updated"); + // self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b)]); } fn exec_local_get3(&mut self, a: u32, b: u32, c: u32) { - self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b), self.cf.get_local(c)]); + todo!("needs to be updated"); + // self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b), self.cf.get_local(c)]); } fn exec_local_get_set(&mut self, a: u32, b: u32) { self.cf.set_local(b, self.cf.get_local(a)) } fn exec_local_tee_get(&mut self, a: u32, b: u32) -> Result<()> { - let last = self.stack.values.last()?; - self.cf.set_local(a, *last); - self.stack.values.push(match a == b { - true => *last, - false => self.cf.get_local(b), - }); - Ok(()) + todo!("needs to be updated"); + // let last = self.stack.values.last()?; + // self.cf.set_local(a, *last); + // self.stack.values.push(match a == b { + // true => *last, + // false => self.cf.get_local(b), + // }); + // Ok(()) } } diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs index 7027eac..fca58cc 100644 --- a/crates/tinywasm/src/runtime/mod.rs +++ b/crates/tinywasm/src/runtime/mod.rs @@ -1,7 +1,11 @@ mod interpreter; -mod stack; +pub(crate) mod stack; -pub(crate) use stack::{CallFrame, RawWasmValue, Stack}; +#[doc(hidden)] +pub use stack::values; +pub use stack::values::*; + +pub(crate) use stack::{CallFrame, Stack}; /// The main TinyWasm runtime. /// diff --git a/crates/tinywasm/src/runtime/raw.rs.old b/crates/tinywasm/src/runtime/raw.rs.old deleted file mode 100644 index a186fd7..0000000 --- a/crates/tinywasm/src/runtime/raw.rs.old +++ /dev/null @@ -1,123 +0,0 @@ -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(Clone, Copy, Default, PartialEq, Eq)] -pub struct RawWasmValue(pub [u8; 8]); - -impl Debug for RawWasmValue { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "RawWasmValue({})", 0) - } -} - -impl RawWasmValue { - #[inline] - /// Attach a type to the raw value (does not support simd values) - pub fn attach_type(self, ty: ValType) -> WasmValue { - match ty { - ValType::I32 => WasmValue::I32(self.into()), - ValType::I64 => WasmValue::I64(self.into()), - ValType::F32 => WasmValue::F32(self.into()), - ValType::F64 => WasmValue::F64(self.into()), - ValType::V128 => panic!("RawWasmValue cannot be converted to V128"), - ValType::RefExtern => { - self.as_reference().map(WasmValue::RefExtern).unwrap_or(WasmValue::RefNull(ValType::RefExtern)) - } - ValType::RefFunc => { - self.as_reference().map(WasmValue::RefFunc).unwrap_or(WasmValue::RefNull(ValType::RefFunc)) - } - } - } - - #[inline] - pub(crate) fn as_reference(&self) -> Option { - match i64::from(*self) { - v if v < 0 => None, - addr => Some(addr as u32), - } - } -} - -impl From for RawWasmValue { - #[inline] - fn from(v: WasmValue) -> Self { - match v { - WasmValue::I32(i) => Self::from(i), - WasmValue::I64(i) => Self::from(i), - WasmValue::F32(i) => Self::from(i), - WasmValue::F64(i) => Self::from(i), - WasmValue::V128(_) => panic!("RawWasmValue cannot be converted to V128"), - WasmValue::RefExtern(v) => Self::from(v as i64), - WasmValue::RefFunc(v) => Self::from(v as i64), - WasmValue::RefNull(_) => Self::from(-1i64), - } - } -} - -macro_rules! impl_from_raw_wasm_value { - ($type:ty, $to_raw:expr, $from_raw:expr) => { - // Implement From<$type> for RawWasmValue - impl From<$type> for RawWasmValue { - #[inline] - fn from(value: $type) -> Self { - #[allow(clippy::redundant_closure_call)] - Self(u64::to_ne_bytes($to_raw(value))) - } - } - - // Implement From for $type - impl From for $type { - #[inline] - fn from(value: RawWasmValue) -> Self { - #[allow(clippy::redundant_closure_call)] - $from_raw(value.0) - } - } - }; -} - -// This all looks like a lot of extra steps, but the compiler will optimize it all away. -impl_from_raw_wasm_value!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].try_into().unwrap())); -impl_from_raw_wasm_value!(u16, |x| x as u64, |x: [u8; 8]| u16::from_ne_bytes(x[0..2].try_into().unwrap())); -impl_from_raw_wasm_value!(i32, |x| x as u64, |x: [u8; 8]| i32::from_ne_bytes(x[0..4].try_into().unwrap())); -impl_from_raw_wasm_value!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0..4].try_into().unwrap())); -impl_from_raw_wasm_value!(i64, |x| x as u64, |x: [u8; 8]| i64::from_ne_bytes(x[0..8].try_into().unwrap())); -impl_from_raw_wasm_value!(u64, |x| x, |x: [u8; 8]| u64::from_ne_bytes(x[0..8].try_into().unwrap())); -impl_from_raw_wasm_value!(i8, |x| x as u64, |x: [u8; 8]| i8::from_ne_bytes(x[0..1].try_into().unwrap())); -impl_from_raw_wasm_value!(u8, |x| x as u64, |x: [u8; 8]| u8::from_ne_bytes(x[0..1].try_into().unwrap())); - -impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x: [u8; 8]| f32::from_ne_bytes( - x[0..4].try_into().unwrap() -)); -impl_from_raw_wasm_value!(f64, f64::to_bits, |x: [u8; 8]| f64::from_bits(u64::from_ne_bytes( - x[0..8].try_into().unwrap() -))); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_raw_wasm_value() { - macro_rules! test_macro { - ($( $ty:ty => $val:expr ),*) => { - $( - let raw: RawWasmValue = $val.into(); - let val: $ty = raw.into(); - assert_eq!(val, $val); - )* - }; - } - - test_macro! { - i32 => 0, i64 => 0, u8 => 0, u16 => 0, u32 => 0, u64 => 0, i8 => 0, i16 => 0, f32 => 0.0, f64 => 0.0, - i32 => i32::MIN, i64 => i64::MIN, u8 => u8::MIN, u16 => u16::MIN, u32 => u32::MIN, u64 => u64::MIN, i8 => i8::MIN, i16 => i16::MIN, f32 => f32::MIN, f64 => f64::MIN, - i32 => i32::MAX, i64 => i64::MAX, u8 => u8::MAX, u16 => u16::MAX, u32 => u32::MAX, u64 => u64::MAX, i8 => i8::MAX, i16 => i16::MAX, f32 => f32::MAX, f64 => f64::MAX - } - } -} diff --git a/crates/tinywasm/src/runtime/raw_simd.rs.old b/crates/tinywasm/src/runtime/raw_simd.rs.old deleted file mode 100644 index ba7dd62..0000000 --- a/crates/tinywasm/src/runtime/raw_simd.rs.old +++ /dev/null @@ -1,27 +0,0 @@ -use core::{fmt::Debug, simd::Simd}; - -/// A large raw wasm value, used for 128-bit values. -/// -/// This is the internal representation of vector values. -/// -/// See [`WasmValue`] for the public representation. -#[derive(Clone, Copy, Default, PartialEq, Eq)] -pub struct RawSimdWasmValue(Simd); // wasm has up to 16 8 bit lanes - -impl Debug for RawSimdWasmValue { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "LargeRawWasmValue({})", 0) - } -} - -impl From for RawSimdWasmValue { - fn from(value: u128) -> Self { - Self(value.to_le_bytes().into()) - } -} - -impl From for u128 { - fn from(value: RawSimdWasmValue) -> Self { - u128::from_le_bytes(value.0.into()) - } -} diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index c01c9fb..059c091 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -1,6 +1,8 @@ use crate::{cold, unlikely, Error, Result}; use alloc::vec::Vec; +use super::value_stack::{StackHeight, StackLocation}; + #[derive(Debug)] pub(crate) struct BlockStack(Vec); @@ -57,16 +59,9 @@ pub(crate) struct BlockFrame { pub(crate) instr_ptr: usize, // position of the instruction pointer when the block was entered pub(crate) end_instr_offset: u32, // position of the end instruction of the block - pub(crate) stack_ptr: u32, // position of the stack pointer when the block was entered - pub(crate) results: u8, - pub(crate) params: u8, - - #[cfg(feature = "simd")] - pub(crate) simd_stack_ptr: u16, // position of the large stack pointer when the block was entered - #[cfg(feature = "simd")] - pub(crate) simd_results: u8, - #[cfg(feature = "simd")] - pub(crate) simd_params: u8, + pub(crate) stack_ptr: StackLocation, // stack pointer when the block was entered + pub(crate) results: StackHeight, + pub(crate) params: StackHeight, pub(crate) ty: BlockType, } diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 30bbfac..41fd9b2 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,4 +1,4 @@ -use super::value_stack::{wasmvalue_to_localvalue, RawWasmValue}; +use super::values::TinyWasmValue; use super::BlockType; use crate::unlikely; use crate::{Result, Trap}; @@ -41,7 +41,7 @@ pub(crate) struct CallFrame { pub(crate) block_ptr: u32, pub(crate) func_instance: Rc, pub(crate) module_addr: ModuleInstanceAddr, - pub(crate) locals: Box<[[u8; 16]]>, + pub(crate) locals: Box<[TinyWasmValue]>, } impl CallFrame { @@ -96,7 +96,7 @@ impl CallFrame { self.instr_ptr = break_to.instr_ptr; // We also want to push the params to the stack - values.break_to_params(break_to); + values.truncate_keep(&break_to.stack_ptr, &break_to.params); // check if we're breaking to the loop if break_to_relative != 0 { @@ -109,7 +109,7 @@ impl CallFrame { BlockType::Block | BlockType::If | BlockType::Else => { // this is a block, so we want to jump to the next instruction after the block ends // We also want to push the block's results to the stack - values.break_to_results(break_to); + values.truncate_keep(&break_to.stack_ptr, &break_to.results); // (the inst_ptr will be incremented by 1 before the next instruction is executed) self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize; @@ -129,15 +129,14 @@ impl CallFrame { params: &[WasmValue], block_ptr: u32, ) -> Self { - let locals = params.iter().map(|v| wasmvalue_to_localvalue(*v)).collect::>(); - Self::new_raw(wasm_func_inst, owner, &locals, block_ptr) + Self::new_raw(wasm_func_inst, owner, params.iter().map(|v| v.into()), block_ptr) } #[inline(always)] pub(crate) fn new_raw( wasm_func_inst: Rc, owner: ModuleInstanceAddr, - params: &[[u8; 16]], + params: impl ExactSizeIterator, block_ptr: u32, ) -> Self { let locals = { @@ -153,21 +152,13 @@ impl CallFrame { } #[inline(always)] - pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: RawWasmValue) { - match N { - 4 | 8 | 16 => { - self.locals[local_index as usize].copy_from_slice(&value.0); - } - _ => unreachable!("Invalid RawWasmValue size"), - } + pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: TinyWasmValue) { + self.locals[local_index as usize] = value; } #[inline(always)] - pub(crate) fn get_local(&self, local_index: LocalAddr) -> RawWasmValue { - match N { - 4 | 8 | 16 => RawWasmValue::from(&self.locals[local_index as usize][..N]), - _ => unreachable!("Invalid RawWasmValue size"), - } + pub(crate) fn get_local(&self, local_index: LocalAddr) -> TinyWasmValue { + self.locals[local_index as usize] } #[inline(always)] diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/runtime/stack/mod.rs index f2e506d..bc43621 100644 --- a/crates/tinywasm/src/runtime/stack/mod.rs +++ b/crates/tinywasm/src/runtime/stack/mod.rs @@ -1,10 +1,11 @@ mod block_stack; mod call_stack; mod value_stack; +pub mod values; pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; pub(crate) use call_stack::{CallFrame, CallStack}; -pub(crate) use value_stack::{RawWasmValue, ValueStack}; +pub(crate) use value_stack::{StackHeight, ValueStack}; /// A WebAssembly Stack #[derive(Debug)] diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index dfaa451..d24f8e0 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -1,209 +1,211 @@ use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; +use super::values::*; use crate::{Error, Result}; +pub(crate) const STACK_32_SIZE: usize = 1024 * 128; +pub(crate) const STACK_64_SIZE: usize = 1024 * 128; +pub(crate) const STACK_128_SIZE: usize = 1024 * 128; +pub(crate) const STACK_REF_SIZE: usize = 1024; -pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub(crate) struct RawWasmValue(pub(crate) [u8; N]); - -impl From<&[u8]> for RawWasmValue { - fn from(bytes: &[u8]) -> Self { - assert!(bytes.len() != N, "Invalid byte length"); - let mut value = [0; N]; - value.copy_from_slice(bytes); - Self(value) - } +#[derive(Debug)] +pub(crate) struct ValueStack { + pub(crate) stack_32: Vec, + pub(crate) stack_64: Vec, + pub(crate) stack_128: Vec, + pub(crate) stack_ref: Vec, } -pub(crate) fn wasmvalue_to_bytes(value: WasmValue, mut cb: impl FnMut(&[u8])) { - match value { - WasmValue::I32(v) => cb(&v.to_le_bytes()), - WasmValue::I64(v) => cb(&v.to_le_bytes()), - WasmValue::F32(v) => cb(&v.to_le_bytes()), - WasmValue::F64(v) => cb(&v.to_le_bytes()), - WasmValue::V128(v) => cb(&v.to_le_bytes()), - WasmValue::RefExtern(v) => cb(&(v as i64).to_le_bytes()), - WasmValue::RefFunc(v) => cb(&(v as i64).to_le_bytes()), - WasmValue::RefNull(_) => cb(&(-1i64).to_le_bytes()), - } +#[derive(Debug, Clone, Copy)] +pub(crate) struct StackLocation { + pub(crate) s32: u32, + pub(crate) s64: u32, + pub(crate) s128: u32, + pub(crate) sref: u32, } -pub(crate) fn wasmvalue_to_localvalue(value: WasmValue) -> [u8; 16] { - let mut res = [0; 16]; - match value { - WasmValue::I32(v) => res.copy_from_slice(&v.to_le_bytes()), - WasmValue::I64(v) => res.copy_from_slice(&v.to_le_bytes()), - WasmValue::F32(v) => res.copy_from_slice(&v.to_le_bytes()), - WasmValue::F64(v) => res.copy_from_slice(&v.to_le_bytes()), - WasmValue::V128(v) => res.copy_from_slice(&v.to_le_bytes()), - WasmValue::RefExtern(v) => res.copy_from_slice(&(v as i64).to_le_bytes()), - WasmValue::RefFunc(v) => res.copy_from_slice(&(v as i64).to_le_bytes()), - WasmValue::RefNull(_) => res.copy_from_slice(&(-1i64).to_le_bytes()), - } - res +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct StackHeight { + pub(crate) s32: u32, + pub(crate) s64: u32, + pub(crate) s128: u32, + pub(crate) sref: u32, } -pub(crate) fn bytes_to_localvalues(bytes: &[u8], tys: &[ValType]) -> Vec<[u8; 16]> { - let mut values = Vec::with_capacity(tys.len()); - let mut offset = 0; - for ty in tys { - match ty.size() { - 4 | 8 | 16 => { - let mut value = [0; 16]; - value[..ty.size()].copy_from_slice(&bytes[offset..offset + ty.size()]); - values.push(value); - } - _ => unreachable!(), +impl From for StackHeight { + fn from(value: ValType) -> Self { + match value { + ValType::I32 | ValType::F32 => Self { s32: 1, ..Default::default() }, + ValType::I64 | ValType::F64 => Self { s64: 1, ..Default::default() }, + ValType::V128 => Self { s128: 1, ..Default::default() }, + ValType::RefExtern | ValType::RefFunc => Self { sref: 1, ..Default::default() }, } - offset += 16; } - values } -pub(crate) fn bytes_to_wasmvalues(bytes: &[u8], tys: &[ValType]) -> Vec { - let mut values = Vec::with_capacity(tys.len()); - let mut offset = 0; - for ty in tys { - let (value, new_offset) = match ty { - ValType::I32 => (WasmValue::I32(i32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())), 4), - ValType::I64 => (WasmValue::I64(i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap())), 8), - ValType::F32 => (WasmValue::F32(f32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())), 4), - ValType::F64 => (WasmValue::F64(f64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap())), 8), - ValType::V128 => (WasmValue::V128(u128::from_le_bytes(bytes[offset..offset + 16].try_into().unwrap())), 16), - ValType::RefExtern => { - let v = i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap()); - (WasmValue::RefExtern(v as u32), 8) +impl From<&[ValType]> for StackHeight { + fn from(value: &[ValType]) -> Self { + let mut s32 = 0; + let mut s64 = 0; + let mut s128 = 0; + let mut sref = 0; + for val_type in value.iter() { + match val_type { + ValType::I32 | ValType::F32 => s32 += 1, + ValType::I64 | ValType::F64 => s64 += 1, + ValType::V128 => s128 += 1, + ValType::RefExtern | ValType::RefFunc => sref += 1, } - ValType::RefFunc => { - let v = i64::from_le_bytes(bytes[offset..offset + 8].try_into().unwrap()); - (WasmValue::RefFunc(v as u32), 8) - } - }; - values.push(value); - offset += new_offset; + } + Self { s32, s64, s128, sref } } - values -} - -#[derive(Debug)] -pub(crate) struct ValueStack { - pub(crate) stack: Vec, } impl ValueStack { pub(crate) fn new() -> Self { - Self { stack: Vec::with_capacity(VALUE_STACK_SIZE) } + Self { + stack_32: Vec::with_capacity(STACK_32_SIZE), + stack_64: Vec::with_capacity(STACK_64_SIZE), + stack_128: Vec::with_capacity(STACK_128_SIZE), + stack_ref: Vec::with_capacity(STACK_REF_SIZE), + } } - pub(crate) fn height(&self) -> usize { - self.stack.len() + pub(crate) fn height(&self) -> StackLocation { + StackLocation { + s32: self.stack_32.len() as u32, + s64: self.stack_64.len() as u32, + s128: self.stack_128.len() as u32, + sref: self.stack_ref.len() as u32, + } } - pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { - let value = func(self.pop::()?); - self.push(value); - Ok(()) + pub(crate) fn pop_32(&mut self) -> Result { + self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32) } - - pub(crate) fn replace_top_trap( - &mut self, - func: fn(RawWasmValue) -> Result>, - ) -> Result<()> { - let value = func(self.pop::()?)?; - self.push(value); - Ok(()) + pub(crate) fn pop_64(&mut self) -> Result { + self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64) } - - pub(crate) fn calculate( - &mut self, - func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue, - ) -> Result<()> { - let v2 = self.pop::()?; - let v1 = self.pop::()?; - self.push(func(v1, v2)); - Ok(()) + pub(crate) fn pop_128(&mut self) -> Result { + self.stack_128.pop().ok_or(Error::ValueStackUnderflow) } - - pub(crate) fn calculate_trap( - &mut self, - func: fn(RawWasmValue, RawWasmValue) -> Result>, - ) -> Result<()> { - let v2 = self.pop::()?; - let v1 = self.pop::()?; - self.push(func(v1, v2)?); - Ok(()) + pub(crate) fn pop_ref(&mut self) -> Result> { + self.stack_ref.pop().ok_or(Error::ValueStackUnderflow) + } + pub(crate) fn push_32(&mut self, value: i32) { + self.stack_32.push(value as u32); + } + pub(crate) fn push_64(&mut self, value: i64) { + self.stack_64.push(value as u64); + } + pub(crate) fn push_128(&mut self, value: u128) { + self.stack_128.push(value); + } + pub(crate) fn push_ref(&mut self, value: Option) { + self.stack_ref.push(value); } - pub(crate) fn drop(&mut self, len: usize) -> Result<()> { - if len > self.stack.len() { - return Err(Error::ValueStackUnderflow).into(); + pub(crate) fn drop(&mut self) -> Result<()> { + match T { + 0 => self.stack_32.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), + 1 => self.stack_64.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), + 2 => self.stack_128.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), + 3 => self.stack_ref.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), + _ => unreachable!("Invalid type"), } - self.stack.truncate(self.stack.len() - len); + } + pub(crate) fn select(&mut self) -> Result<()> { + macro_rules! select { + ($($i:literal => $pop:ident, $push:ident),*) => { + match T { + $($i => { + let cond = self.pop_32()?; + let val2 = self.$pop()?; + if cond == 0 { + self.drop::<$i>()?; + self.$push(val2); + } + })* + _ => unreachable!("Invalid type") + } + }; + } + select!(0 => pop_32, push_32, 1 => pop_64, push_64, 2 => pop_128, push_128, 3 => pop_ref, push_ref); Ok(()) } - pub(crate) fn truncate(&mut self, len: usize) { - self.stack.truncate(len); + pub(crate) fn pop(&mut self, val_type: ValType) -> Result { + match val_type { + ValType::I32 => self.pop_32().map(WasmValue::I32), + ValType::I64 => self.pop_64().map(WasmValue::I64), + ValType::V128 => self.pop_128().map(WasmValue::V128), + ValType::F32 => self.pop_32().map(|v| WasmValue::F32(f32::from_bits(v as u32))), + ValType::F64 => self.pop_64().map(|v| WasmValue::F64(f64::from_bits(v as u64))), + ValType::RefExtern => self.pop_ref().map(|v| match v { + Some(v) => WasmValue::RefExtern(v), + None => WasmValue::RefNull(ValType::RefExtern), + }), + ValType::RefFunc => self.pop_ref().map(|v| match v { + Some(v) => WasmValue::RefFunc(v), + None => WasmValue::RefNull(ValType::RefFunc), + }), + } } - /// Truncate the stack to `len`, but still keep `keep` elements at the end. - pub(crate) fn truncate_keep(&mut self, len: usize, keep: usize) { - let total_to_keep = len + keep; - let len = self.height(); - assert!(len >= total_to_keep, "RawWasmValueotal to keep should be less than or equal to self.top"); - - if len <= total_to_keep { - return; // No need to truncate if the current size is already less than or equal to total_to_keep + pub(crate) fn pop_raw(&mut self, val_type: ValType) -> Result { + match val_type { + ValType::I32 => self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value32), + ValType::I64 => self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value64), + ValType::V128 => self.stack_128.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value128), + ValType::RefExtern => self.stack_ref.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::ValueRef), + ValType::RefFunc => self.stack_ref.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::ValueRef), + ValType::F32 => self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value32), + ValType::F64 => self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value64), } - - let items_to_remove = len - total_to_keep; - let remove_start_index = (len - items_to_remove - keep) as usize; - let remove_end_index = (len - keep) as usize; - self.stack.drain(remove_start_index..remove_end_index); } - pub(crate) fn last(&self) -> Result> { - let len = self.stack.len(); - if len < N { - return Err(Error::ValueStackUnderflow); + pub(crate) fn pop_many(&mut self, val_types: &[ValType]) -> Result> { + let mut values = Vec::with_capacity(val_types.len()); + for val_type in val_types.iter().rev() { + values.push(self.pop(*val_type)?); } - Ok(RawWasmValue::from(&self.stack[len - N..])) + Ok(values) } - pub(crate) fn pop(&mut self) -> Result> { - let len = self.stack.len(); - if len < N { - return Err(Error::ValueStackUnderflow); + pub(crate) fn pop_many_raw(&mut self, val_types: &[ValType]) -> Result> { + let mut values = Vec::with_capacity(val_types.len()); + for val_type in val_types.iter().rev() { + values.push(self.pop_raw(*val_type)?); } - - let mut bytes = [0; N]; - bytes.copy_from_slice(&self.stack[len - N..]); - self.stack.truncate(len - N); - Ok(RawWasmValue(bytes)) + Ok(values) } - pub(crate) fn push(&mut self, value: RawWasmValue) { - self.stack.extend_from_slice(&value.0); + pub(crate) fn truncate(&mut self, height: &StackLocation) { + self.stack_32.truncate(height.s32 as usize); + self.stack_64.truncate(height.s64 as usize); + self.stack_128.truncate(height.s128 as usize); + self.stack_ref.truncate(height.sref as usize); } - pub(crate) fn pop_n_typed(&mut self, tys: &[ValType]) -> Vec { - let len: usize = tys.iter().map(|ty| ty.size()).sum(); - let values = bytes_to_wasmvalues(&self.stack[self.stack.len() - len..], tys); - self.stack.truncate(self.stack.len() - len); - values + pub(crate) fn truncate_keep(&mut self, height: &StackLocation, keep: &StackHeight) { + self.stack_32.drain(height.s32 as usize..(self.stack_128.len() - keep.s32 as usize)); + self.stack_64.drain(height.s64 as usize..(self.stack_64.len() - keep.s64 as usize)); + self.stack_128.drain(height.s128 as usize..(self.stack_128.len() - keep.s128 as usize)); + self.stack_ref.drain(height.sref as usize..(self.stack_ref.len() - keep.sref as usize)); } - pub(crate) fn pop_locals(&mut self, locals: &[ValType]) -> Vec<[u8; 16]> { - let len: usize = locals.iter().map(|ty| ty.size()).sum(); - let values = bytes_to_localvalues(&self.stack[self.stack.len() - len..], locals); - self.stack.truncate(self.stack.len() - len); - values + pub(crate) fn push(&mut self, value: TinyWasmValue) { + match value { + TinyWasmValue::Value32(v) => self.stack_32.push(v), + TinyWasmValue::Value64(v) => self.stack_64.push(v), + TinyWasmValue::Value128(v) => self.stack_128.push(v), + TinyWasmValue::ValueRef(v) => self.stack_ref.push(v), + } } - pub(crate) fn push_typed(&mut self, values: &[WasmValue]) { - values.iter().for_each(|v| wasmvalue_to_bytes(*v, |bytes| self.stack.extend_from_slice(bytes))); + pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) { + for value in values.iter() { + self.push(value.into()) + } } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs.old b/crates/tinywasm/src/runtime/stack/value_stack.rs.old deleted file mode 100644 index 10fe264..0000000 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs.old +++ /dev/null @@ -1,266 +0,0 @@ -use crate::{boxvec::BoxVec, cold, runtime::RawWasmValue, unlikely, Error, Result}; -use alloc::vec::Vec; -use tinywasm_types::{ValType, WasmValue}; - -use super::BlockFrame; - -pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128; - -#[cfg(feature = "simd")] -use crate::runtime::raw_simd::RawSimdWasmValue; - -#[derive(Debug)] -pub(crate) struct ValueStack { - pub(crate) stack: BoxVec, - - #[cfg(feature = "simd")] - simd_stack: BoxVec, -} - -impl Default for ValueStack { - fn default() -> Self { - Self { - stack: BoxVec::with_capacity(VALUE_STACK_SIZE), - - #[cfg(feature = "simd")] - simd_stack: BoxVec::with_capacity(SIMD_VALUE_STACK_SIZE), - } - } -} - -impl ValueStack { - #[inline] - pub(crate) fn extend_from_typed(&mut self, values: &[WasmValue]) { - #[cfg(not(feature = "simd"))] - self.stack.extend(values.iter().map(|v| RawWasmValue::from(*v))); - - #[cfg(feature = "simd")] - { - values.iter().for_each(|v| match v { - WasmValue::V128(v) => self.simd_stack.push(RawSimdWasmValue::from(*v)), - v => self.stack.push(RawWasmValue::from(*v)), - }); - } - } - - #[inline(always)] - pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { - let v = self.last_mut()?; - *v = func(*v); - Ok(()) - } - - #[inline(always)] - pub(crate) fn replace_top_trap(&mut self, func: fn(RawWasmValue) -> Result) -> Result<()> { - let v = self.last_mut()?; - *v = func(*v)?; - Ok(()) - } - - #[inline(always)] - pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> { - let v2 = self.pop()?; - let v1 = self.last_mut()?; - *v1 = func(*v1, v2); - Ok(()) - } - - #[inline(always)] - pub(crate) fn calculate_trap( - &mut self, - func: fn(RawWasmValue, RawWasmValue) -> Result, - ) -> Result<()> { - let v2 = self.pop()?; - let v1 = self.last_mut()?; - *v1 = func(*v1, v2)?; - Ok(()) - } - - #[inline(always)] - pub(crate) fn len(&self) -> usize { - self.stack.len() - } - - #[cfg(feature = "simd")] - #[inline(always)] - pub(crate) fn simd_len(&self) -> usize { - self.simd_stack.len() - } - - #[inline] - pub(crate) fn truncate_keep(&mut self, n: u32, end_keep: u32) { - truncate_keep(&mut self.stack, n, end_keep); - } - - #[cfg(feature = "simd")] - #[inline] - pub(crate) fn truncate_keep_simd(&mut self, n: u16, end_keep: u32) { - truncate_keep(&mut self.simd_stack, n as u32, end_keep); - } - - #[inline(always)] - pub(crate) fn push(&mut self, value: RawWasmValue) { - self.stack.push(value); - } - - #[inline(always)] - pub(crate) fn extend_from_slice(&mut self, values: &[RawWasmValue]) { - self.stack.extend_from_slice(values); - } - - #[inline] - pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { - match self.stack.last_mut() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } - } - } - - #[inline] - pub(crate) fn last(&self) -> Result<&RawWasmValue> { - match self.stack.last() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } - } - } - - #[inline(always)] - pub(crate) fn pop(&mut self) -> Result { - match self.stack.pop() { - Some(v) => Ok(v), - None => { - cold(); // cold in here instead of the stack makes a huge performance difference - Err(Error::ValueStackUnderflow) - } - } - } - - #[inline] - pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result> { - #[cfg(not(feature = "simd"))] - return Ok(self.pop_n(types.len())?.iter().zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect()); - - #[cfg(feature = "simd")] - { - let mut values = Vec::with_capacity(types.len()); - for ty in types { - match ty { - ValType::V128 => values.push(WasmValue::V128(self.simd_stack.pop().unwrap().into())), - ty => values.push(self.pop()?.attach_type(*ty)), - } - } - Ok(values) - } - } - - #[inline] - pub(crate) fn break_to_results(&mut self, bf: &BlockFrame) { - let end = self.stack.len() - bf.results as usize; - self.stack.drain(bf.stack_ptr as usize..end); - - #[cfg(feature = "simd")] - let end = self.simd_stack.len() - bf.simd_results as usize; - #[cfg(feature = "simd")] - self.simd_stack.drain(bf.simd_stack_ptr as usize..end); - } - - #[inline] - pub(crate) fn break_to_params(&mut self, bf: &BlockFrame) { - let end = self.stack.len() - bf.params as usize; - self.stack.drain(bf.stack_ptr as usize..end); - - #[cfg(feature = "simd")] - let end = self.simd_stack.len() - bf.simd_params as usize; - #[cfg(feature = "simd")] - self.simd_stack.drain(bf.simd_stack_ptr as usize..end); - } - - #[inline] - pub(crate) fn last_n(&self, n: usize) -> Result<&[RawWasmValue]> { - let len = self.stack.len(); - if unlikely(len < n) { - return Err(Error::ValueStackUnderflow); - } - Ok(&self.stack[len - n..len]) - } - - #[inline] - pub(crate) fn pop_n(&mut self, n: usize) -> Result<&[RawWasmValue]> { - match self.stack.pop_n(n) { - Some(v) => Ok(v), - None => { - cold(); - Err(Error::ValueStackUnderflow) - } - } - } -} - -#[inline(always)] -fn truncate_keep(data: &mut BoxVec, n: u32, end_keep: u32) { - let total_to_keep = n + end_keep; - let len = data.len() as u32; - assert!(len >= total_to_keep, "RawWasmValueotal to keep should be less than or equal to self.top"); - - if len <= total_to_keep { - return; // No need to truncate if the current size is already less than or equal to total_to_keep - } - - let items_to_remove = len - total_to_keep; - let remove_start_index = (len - items_to_remove - end_keep) as usize; - let remove_end_index = (len - end_keep) as usize; - data.drain(remove_start_index..remove_end_index); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_value_stack() { - let mut stack = ValueStack::default(); - stack.push(1.into()); - stack.push(2.into()); - stack.push(3.into()); - assert_eq!(stack.len(), 3); - assert_eq!(i32::from(stack.pop().unwrap()), 3); - assert_eq!(stack.len(), 2); - assert_eq!(i32::from(stack.pop().unwrap()), 2); - assert_eq!(stack.len(), 1); - assert_eq!(i32::from(stack.pop().unwrap()), 1); - assert_eq!(stack.len(), 0); - } - - #[test] - fn test_truncate_keep() { - macro_rules! test_macro { - ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { - $( - let mut stack = ValueStack::default(); - stack.push(1.into()); - stack.push(2.into()); - stack.push(3.into()); - stack.push(4.into()); - stack.push(5.into()); - stack.truncate_keep($n, $end_keep); - assert_eq!(stack.len(), $expected); - )* - }; - } - - test_macro! { - 0, 0, 0, - 1, 0, 1, - 0, 1, 1, - 1, 1, 2, - 2, 1, 3, - 2, 2, 4 - } - } -} diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs new file mode 100644 index 0000000..f027a91 --- /dev/null +++ b/crates/tinywasm/src/runtime/stack/values.rs @@ -0,0 +1,128 @@ +#![allow(missing_docs)] +use tinywasm_types::{ValType, WasmValue}; + +pub type Value32 = u32; +pub type Value64 = u64; +pub type Value128 = u128; +pub type ValueRef = Option; + +pub const VALUE32: u8 = 0; +pub const VALUE64: u8 = 1; +pub const VALUE128: u8 = 2; +pub const VALUEREF: u8 = 3; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum TinyWasmValue { + Value32(Value32), + Value64(Value64), + Value128(Value128), + ValueRef(ValueRef), +} + +impl TinyWasmValue { + pub fn unwrap_32(&self) -> Value32 { + match self { + TinyWasmValue::Value32(v) => *v, + _ => unreachable!("Expected Value32"), + } + } + + pub fn unwrap_64(&self) -> Value64 { + match self { + TinyWasmValue::Value64(v) => *v, + _ => unreachable!("Expected Value64"), + } + } + + pub fn unwrap_128(&self) -> Value128 { + match self { + TinyWasmValue::Value128(v) => *v, + _ => unreachable!("Expected Value128"), + } + } + + pub fn unwrap_ref(&self) -> ValueRef { + match self { + TinyWasmValue::ValueRef(v) => *v, + _ => unreachable!("Expected ValueRef"), + } + } + + pub fn attach_type(&self, ty: ValType) -> WasmValue { + match ty { + ValType::I32 => WasmValue::I32(self.unwrap_32() as i32), + ValType::I64 => WasmValue::I64(self.unwrap_64() as i64), + ValType::F32 => WasmValue::F32(f32::from_bits(self.unwrap_32())), + ValType::F64 => WasmValue::F64(f64::from_bits(self.unwrap_64())), + ValType::V128 => WasmValue::V128(self.unwrap_128()), + ValType::RefExtern => match self.unwrap_ref() { + Some(v) => WasmValue::RefExtern(v), + None => WasmValue::RefNull(ValType::RefExtern), + }, + ValType::RefFunc => match self.unwrap_ref() { + Some(v) => WasmValue::RefFunc(v), + None => WasmValue::RefNull(ValType::RefFunc), + }, + } + } +} + +impl Default for TinyWasmValue { + fn default() -> Self { + TinyWasmValue::Value32(0) + } +} + +impl From for TinyWasmValue { + fn from(value: WasmValue) -> Self { + match value { + WasmValue::I32(v) => TinyWasmValue::Value32(v as u32), + WasmValue::I64(v) => TinyWasmValue::Value64(v as u64), + WasmValue::V128(v) => TinyWasmValue::Value128(v), + WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()), + WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()), + WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(Some(v)), + WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(Some(v)), + WasmValue::RefNull(_) => TinyWasmValue::ValueRef(None), + } + } +} + +impl From<&WasmValue> for TinyWasmValue { + fn from(value: &WasmValue) -> Self { + match value { + WasmValue::I32(v) => TinyWasmValue::Value32(*v as u32), + WasmValue::I64(v) => TinyWasmValue::Value64(*v as u64), + WasmValue::V128(v) => TinyWasmValue::Value128(*v), + WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()), + WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()), + WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(Some(*v)), + WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(Some(*v)), + WasmValue::RefNull(_) => TinyWasmValue::ValueRef(None), + } + } +} + +impl From for TinyWasmValue { + fn from(value: f32) -> Self { + TinyWasmValue::Value32(value.to_bits()) + } +} + +impl From for TinyWasmValue { + fn from(value: f64) -> Self { + TinyWasmValue::Value64(value.to_bits()) + } +} + +impl From for TinyWasmValue { + fn from(value: i32) -> Self { + TinyWasmValue::Value32(value as u32) + } +} + +impl From for TinyWasmValue { + fn from(value: i64) -> Self { + TinyWasmValue::Value64(value as u64) + } +} diff --git a/crates/tinywasm/src/store/global.rs b/crates/tinywasm/src/store/global.rs index 6cc778c..a18e43d 100644 --- a/crates/tinywasm/src/store/global.rs +++ b/crates/tinywasm/src/store/global.rs @@ -3,20 +3,20 @@ use core::cell::Cell; use alloc::{format, string::ToString}; use tinywasm_types::*; -use crate::{runtime::RawWasmValue, unlikely, Error, Result}; +use crate::{runtime::TinyWasmValue, unlikely, Error, Result}; /// A WebAssembly Global Instance /// /// See #[derive(Debug)] pub(crate) struct GlobalInstance { - pub(crate) value: Cell, + pub(crate) value: Cell, pub(crate) ty: GlobalType, pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances } impl GlobalInstance { - pub(crate) fn new(ty: GlobalType, value: RawWasmValue, owner: ModuleInstanceAddr) -> Self { + pub(crate) fn new(ty: GlobalType, value: TinyWasmValue, owner: ModuleInstanceAddr) -> Self { Self { ty, value: value.into(), _owner: owner } } @@ -50,7 +50,7 @@ mod tests { #[test] fn test_global_instance_get_set() { let global_type = GlobalType { ty: ValType::I32, mutable: true }; - let initial_value = RawWasmValue::from(10i32); + let initial_value = TinyWasmValue::from(10i32); let owner = 0; let mut global_instance = GlobalInstance::new(global_type, initial_value, owner); diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 03ed0e5..5538cd6 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -3,7 +3,7 @@ use core::cell::RefCell; use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; -use crate::runtime::{self, InterpreterRuntime, RawWasmValue}; +use crate::runtime::{self, InterpreterRuntime, TinyWasmValue}; use crate::{Error, Function, ModuleInstance, Result, Trap}; mod data; @@ -160,8 +160,8 @@ impl Store { } /// Get the global at the actual index in the store - #[inline(always)] - pub(crate) fn get_global_val(&self, addr: MemAddr) -> Result { + #[doc(hidden)] + pub fn get_global_val(&self, addr: MemAddr) -> Result { self.data .globals .get(addr as usize) @@ -170,8 +170,8 @@ impl Store { } /// Set the global at the actual index in the store - #[inline(always)] - pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: RawWasmValue) -> Result<()> { + #[doc(hidden)] + pub fn set_global_val(&mut self, addr: MemAddr, value: TinyWasmValue) -> Result<()> { let global = self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global")); global.map(|global| global.value.set(value)) } @@ -251,7 +251,7 @@ impl Store { let addr = globals.get(*addr as usize).copied().ok_or_else(|| { Error::Other(format!("global {} not found. This should have been caught by the validator", addr)) })?; - let val: i64 = self.data.globals[addr as usize].value.get().into(); + let val = self.data.globals[addr as usize].value.get().unwrap_64() as i64; // check if the global is actually a null reference match val < 0 { @@ -368,7 +368,7 @@ impl Store { Ok((data_addrs.into_boxed_slice(), None)) } - pub(crate) fn add_global(&mut self, ty: GlobalType, value: RawWasmValue, idx: ModuleInstanceAddr) -> Result { + pub(crate) fn add_global(&mut self, ty: GlobalType, value: TinyWasmValue, idx: ModuleInstanceAddr) -> Result { self.data.globals.push(GlobalInstance::new(ty, value, idx)); Ok(self.data.globals.len() as Addr - 1) } @@ -396,7 +396,7 @@ impl Store { use tinywasm_types::ConstInstruction::*; let val = match const_instr { I32Const(i) => *i, - GlobalGet(addr) => i32::from(self.data.globals[*addr as usize].value.get()), + GlobalGet(addr) => self.data.globals[*addr as usize].value.get().unwrap_32() as i32, _ => return Err(Error::Other("expected i32".to_string())), }; Ok(val) @@ -408,13 +408,13 @@ impl Store { const_instr: &tinywasm_types::ConstInstruction, module_global_addrs: &[Addr], module_func_addrs: &[FuncAddr], - ) -> Result { + ) -> Result { use tinywasm_types::ConstInstruction::*; let val = match const_instr { - F32Const(f) => RawWasmValue::from(*f), - F64Const(f) => RawWasmValue::from(*f), - I32Const(i) => RawWasmValue::from(*i), - I64Const(i) => RawWasmValue::from(*i), + F32Const(f) => (*f).into(), + F64Const(f) => (*f).into(), + I32Const(i) => (*i).into(), + I64Const(i) => (*i).into(), GlobalGet(addr) => { let addr = module_global_addrs.get(*addr as usize).ok_or_else(|| { Error::Other(format!("global {} not found. This should have been caught by the validator", addr)) @@ -424,10 +424,10 @@ impl Store { self.data.globals.get(*addr as usize).expect("global not found. This should be unreachable"); global.value.get() } - RefNull(t) => RawWasmValue::from(t.default_value()), - RefFunc(idx) => RawWasmValue::from(*module_func_addrs.get(*idx as usize).ok_or_else(|| { + RefNull(t) => t.default_value().into(), + RefFunc(idx) => TinyWasmValue::ValueRef(Some(*module_func_addrs.get(*idx as usize).ok_or_else(|| { Error::Other(format!("function {} not found. This should have been caught by the validator", idx)) - })?), + })?)), }; Ok(val) } diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index a038c4b..efbdfb5 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -121,8 +121,15 @@ pub enum Instruction { // > Parametric Instructions // See - Drop(ValType), - Select(Option), + Drop32, + Drop64, + Drop128, + DropRef, + + Select32, + Select64, + Select128, + SelectRef, // > Variable Instructions // See diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index eeea469..6c422d0 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -147,18 +147,6 @@ impl ValType { matches!(self, ValType::V128) } - pub const fn size(&self) -> usize { - match self { - ValType::I32 => 4, - ValType::I64 => 8, - ValType::F32 => 4, - ValType::F64 => 8, - ValType::V128 => 16, - ValType::RefFunc => 8, - ValType::RefExtern => 8, - } - } - pub(crate) fn to_byte(self) -> u8 { match self { ValType::I32 => 0x7F, From 182d7594365c60b8f7ff81ab2aa820892d3f1496 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 27 Jun 2024 01:38:23 +0200 Subject: [PATCH 03/10] wip: refactor value stack api Signed-off-by: Henry Gressmann --- .../tinywasm/src/runtime/interpreter/mod.rs | 461 ++++++++++-------- .../tinywasm/src/runtime/stack/block_stack.rs | 2 +- crates/tinywasm/src/runtime/stack/mod.rs | 2 +- .../tinywasm/src/runtime/stack/value_stack.rs | 281 ++++++----- crates/tinywasm/src/runtime/stack/values.rs | 45 ++ crates/tinywasm/tests/generated/2.0.csv | 2 +- crates/tinywasm/tests/generated/mvp.csv | 2 +- 7 files changed, 463 insertions(+), 332 deletions(-) diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index ecfe02b..07513df 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -1,8 +1,9 @@ use alloc::{format, rc::Rc, string::ToString}; use core::ops::ControlFlow; use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction}; +use traits::{TinywasmFloatExt, WasmIntOps}; -use super::stack::{BlockFrame, BlockType, StackHeight}; +use super::stack::{values::StackHeight, BlockFrame, BlockType}; use super::{values::*, InterpreterRuntime, Stack}; use crate::runtime::CallFrame; use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap}; @@ -56,15 +57,15 @@ impl<'store, 'stack> Executor<'store, 'stack> { Nop => self.exec_noop(), Unreachable => self.exec_unreachable()?, - Drop32 => self.stack.values.drop::()?, - Drop64 => self.stack.values.drop::()?, - Drop128 => self.stack.values.drop::()?, - DropRef => self.stack.values.drop::()?, + Drop32 => self.stack.values.drop::()?, + Drop64 => self.stack.values.drop::()?, + Drop128 => self.stack.values.drop::()?, + DropRef => self.stack.values.drop::()?, - Select32 => self.stack.values.select::()?, - Select64 => self.stack.values.select::()?, - Select128 => self.stack.values.select::()?, - SelectRef => self.stack.values.select::()?, + Select32 => self.stack.values.select::()?, + Select64 => self.stack.values.select::()?, + Select128 => self.stack.values.select::()?, + SelectRef => self.stack.values.select::()?, Call(v) => self.exec_call_direct(*v)?, CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?, @@ -86,12 +87,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { GlobalGet(global_index) => self.exec_global_get(*global_index)?, GlobalSet(global_index) => self.exec_global_set(*global_index)?, - I32Const(val) => self.stack.values.push_32(*val), - I64Const(val) => self.stack.values.push_64(*val), - F32Const(val) => self.stack.values.push_32(val.to_bits() as i32), - F64Const(val) => self.stack.values.push_64(val.to_bits() as i64), - RefFunc(func_idx) => self.stack.values.push_ref(Some(*func_idx)), // do we need to resolve the function index? - RefNull(_) => self.stack.values.push_ref(None), + I32Const(val) => self.stack.values.push(*val), + I64Const(val) => self.stack.values.push(*val), + F32Const(val) => self.stack.values.push::(val.to_bits() as i32), + F64Const(val) => self.stack.values.push(val.to_bits() as i64), + RefFunc(func_idx) => self.stack.values.push(Some(*func_idx)), // do we need to resolve the function index? + RefNull(_) => self.stack.values.push(None), RefIsNull => self.exec_ref_is_null()?, MemorySize(addr) => self.exec_memory_size(*addr)?, @@ -106,41 +107,41 @@ impl<'store, 'stack> Executor<'store, 'stack> { TableCopy { from, to } => self.exec_table_copy(*from, *to)?, I32Store { mem_addr, offset } => { - let v = self.stack.values.pop_32()?; + let v = self.stack.values.pop::()?; self.exec_mem_store::(v, *mem_addr, *offset)? } I64Store { mem_addr, offset } => { - let v = self.stack.values.pop_64()?; + let v = self.stack.values.pop::()?; self.exec_mem_store::(v, *mem_addr, *offset)? } F32Store { mem_addr, offset } => { - let v = f32::from_bits(self.stack.values.pop_32()? as u32); + let v = self.stack.values.pop::()?; self.exec_mem_store::(v, *mem_addr, *offset)? } F64Store { mem_addr, offset } => { - let v = f64::from_bits(self.stack.values.pop_64()? as u64); + let v = self.stack.values.pop::()?; self.exec_mem_store::(v, *mem_addr, *offset)? } // TODO: this prob. needs specific conversion functions that truncate the underlying bits I32Store8 { mem_addr, offset } => { - let v = self.stack.values.pop_32()? as i8; + let v = self.stack.values.pop::()? as i8; self.exec_mem_store::(v, *mem_addr, *offset)? } I32Store16 { mem_addr, offset } => { - let v = self.stack.values.pop_32()? as i16; + let v = self.stack.values.pop::()? as i16; self.exec_mem_store::(v, *mem_addr, *offset)? } I64Store8 { mem_addr, offset } => { - let v = self.stack.values.pop_64()? as i8; + let v = self.stack.values.pop::()? as i8; self.exec_mem_store::(v, *mem_addr, *offset)? } I64Store16 { mem_addr, offset } => { - let v = self.stack.values.pop_64()? as i16; + let v = self.stack.values.pop::()? as i16; self.exec_mem_store::(v, *mem_addr, *offset)? } I64Store32 { mem_addr, offset } => { - let v = self.stack.values.pop_64()? as i32; + let v = self.stack.values.pop::()? as i32; self.exec_mem_store::(v, *mem_addr, *offset)? } @@ -159,145 +160,185 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64Load32S { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, I64Load32U { mem_addr, offset } => self.exec_mem_load::(|v| v as i64, *mem_addr, *offset)?, - // I64Eqz => comp_zero!(==, 8, i64, self), - // I32Eqz => comp_zero!(==, i32, self), - - // I32Eq => comp!(==, i32, self), - // I64Eq => comp!(==, i64, self), - // F32Eq => comp!(==, f32, self), - // F64Eq => comp!(==, f64, self), - - // I32Ne => comp!(!=, i32, self), - // I64Ne => comp!(!=, i64, self), - // F32Ne => comp!(!=, f32, self), - // F64Ne => comp!(!=, f64, self), - - // I32LtS => comp!(<, i32, self), - // I64LtS => comp!(<, i64, self), - // I32LtU => comp!(<, u32, self), - // I64LtU => comp!(<, u64, self), - // F32Lt => comp!(<, f32, self), - // F64Lt => comp!(<, f64, self), - - // I32LeS => comp!(<=, i32, self), - // I64LeS => comp!(<=, i64, self), - // I32LeU => comp!(<=, u32, self), - // I64LeU => comp!(<=, u64, self), - // F32Le => comp!(<=, f32, self), - // F64Le => comp!(<=, f64, self), - - // I32GeS => comp!(>=, i32, self), - // I64GeS => comp!(>=, i64, self), - // I32GeU => comp!(>=, u32, self), - // I64GeU => comp!(>=, u64, self), - // F32Ge => comp!(>=, f32, self), - // F64Ge => comp!(>=, f64, self), - - // I32GtS => comp!(>, i32, self), - // I64GtS => comp!(>, i64, self), - // I32GtU => comp!(>, u32, self), - // I64GtU => comp!(>, u64, self), - // F32Gt => comp!(>, f32, self), - // F64Gt => comp!(>, f64, self), - - // I64Add => arithmetic!(wrapping_add, i64, self), - // I32Add => arithmetic!(wrapping_add, i32, self), - // F32Add => arithmetic!(+, f32, self), - // F64Add => arithmetic!(+, f64, self), - - // I32Sub => arithmetic!(wrapping_sub, i32, self), - // I64Sub => arithmetic!(wrapping_sub, i64, self), - // F32Sub => arithmetic!(-, f32, self), - // F64Sub => arithmetic!(-, f64, self), - - // F32Div => arithmetic!(/, f32, self), - // F64Div => arithmetic!(/, f64, self), - - // I32Mul => arithmetic!(wrapping_mul, i32, self), - // I64Mul => arithmetic!(wrapping_mul, i64, self), - // F32Mul => arithmetic!(*, f32, self), - // F64Mul => arithmetic!(*, f64, self), + I64Eqz => self.stack.values.replace_top::(|v| Ok((v == 0) as i32))?, + I32Eqz => self.stack.values.replace_top::(|v| Ok((v == 0) as i32))?, + I32Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, + I64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, + F32Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, + F64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, + + I32Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, + I64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i64))?, + F32Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, + F64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, + + I32LtS => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + I64LtS => self.stack.values.calculate::(|a, b| Ok((a < b) as i64))?, + I32LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + I64LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i64))?, + F32Lt => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + F64Lt => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + + I32LeS => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + I64LeS => self.stack.values.calculate::(|a, b| Ok((a <= b) as i64))?, + I32LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + I64LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i64))?, + F32Le => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + F64Le => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + + I32GeS => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + I64GeS => self.stack.values.calculate::(|a, b| Ok((a >= b) as i64))?, + I32GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + I64GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i64))?, + F32Ge => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + F64Ge => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + + I32GtS => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + I64GtS => self.stack.values.calculate::(|a, b| Ok((a > b) as i64))?, + I32GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + I64GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i64))?, + F32Gt => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + F64Gt => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + + I32Add => self.stack.values.calculate::(|a, b| Ok(a.wrapping_add(b)))?, + I64Add => self.stack.values.calculate::(|a, b| Ok(a.wrapping_add(b)))?, + F32Add => self.stack.values.calculate::(|a, b| Ok(a + b))?, + F64Add => self.stack.values.calculate::(|a, b| Ok(a + b))?, + + I32Sub => self.stack.values.calculate::(|a, b| Ok(a.wrapping_sub(b)))?, + I64Sub => self.stack.values.calculate::(|a, b| Ok(a.wrapping_sub(b)))?, + F32Sub => self.stack.values.calculate::(|a, b| Ok(a - b))?, + F64Sub => self.stack.values.calculate::(|a, b| Ok(a - b))?, + + F32Div => self.stack.values.calculate::(|a, b| Ok(a / b))?, + F64Div => self.stack.values.calculate::(|a, b| Ok(a / b))?, + + I32Mul => self.stack.values.calculate::(|a, b| Ok(a.wrapping_mul(b)))?, + I64Mul => self.stack.values.calculate::(|a, b| Ok(a.wrapping_mul(b)))?, + F32Mul => self.stack.values.calculate::(|a, b| Ok(a * b))?, + F64Mul => self.stack.values.calculate::(|a, b| Ok(a * b))?, // // these can trap - // I32DivS => checked_int_arithmetic!(checked_div, i32, self), - // I64DivS => checked_int_arithmetic!(checked_div, i64, self), - // I32DivU => checked_int_arithmetic!(checked_div, u32, self), - // I64DivU => checked_int_arithmetic!(checked_div, u64, self), - - // I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, self), - // I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, self), - // I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, self), - // I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, self), - - // I32And => arithmetic!(bitand, i32, self), - // I64And => arithmetic!(bitand, i64, self), - // I32Or => arithmetic!(bitor, i32, self), - // I64Or => arithmetic!(bitor, i64, self), - // I32Xor => arithmetic!(bitxor, i32, self), - // I64Xor => arithmetic!(bitxor, i64, self), - // I32Shl => arithmetic!(wasm_shl, i32, self), - // I64Shl => arithmetic!(wasm_shl, i64, self), - // I32ShrS => arithmetic!(wasm_shr, i32, self), - // I64ShrS => arithmetic!(wasm_shr, i64, self), - // I32ShrU => arithmetic!(wasm_shr, u32, self), - // I64ShrU => arithmetic!(wasm_shr, u64, self), - // I32Rotl => arithmetic!(wasm_rotl, i32, self), - // I64Rotl => arithmetic!(wasm_rotl, i64, self), - // I32Rotr => arithmetic!(wasm_rotr, i32, self), - // I64Rotr => arithmetic!(wasm_rotr, i64, self), - - // I32Clz => arithmetic_single!(leading_zeros, i32, self), - // I64Clz => arithmetic_single!(leading_zeros, i64, self), - // I32Ctz => arithmetic_single!(trailing_zeros, i32, self), - // I64Ctz => arithmetic_single!(trailing_zeros, i64, self), - // I32Popcnt => arithmetic_single!(count_ones, i32, self), - // I64Popcnt => arithmetic_single!(count_ones, i64, self), - - // F32ConvertI32S => conv!(i32, f32, self), - // F32ConvertI64S => conv!(i64, f32, self), - // F64ConvertI32S => conv!(i32, f64, self), - // F64ConvertI64S => conv!(i64, f64, self), - // F32ConvertI32U => conv!(u32, f32, self), - // F32ConvertI64U => conv!(u64, f32, self), - // F64ConvertI32U => conv!(u32, f64, self), - // F64ConvertI64U => conv!(u64, f64, self), - // I32Extend8S => conv!(i8, i32, self), - // I32Extend16S => conv!(i16, i32, self), - // I64Extend8S => conv!(i8, i64, self), - // I64Extend16S => conv!(i16, i64, self), - // I64Extend32S => conv!(i32, i64, self), - // I64ExtendI32U => conv!(u32, i64, self), - // I64ExtendI32S => conv!(i32, i64, self), - // I32WrapI64 => conv!(i64, i32, self), - - // F32DemoteF64 => conv!(f64, f32, self), - // F64PromoteF32 => conv!(f32, f64, self), - - // F32Abs => arithmetic_single!(abs, f32, self), - // F64Abs => arithmetic_single!(abs, f64, self), - // F32Neg => arithmetic_single!(neg, f32, self), - // F64Neg => arithmetic_single!(neg, f64, self), - // F32Ceil => arithmetic_single!(ceil, f32, self), - // F64Ceil => arithmetic_single!(ceil, f64, self), - // F32Floor => arithmetic_single!(floor, f32, self), - // F64Floor => arithmetic_single!(floor, f64, self), - // F32Trunc => arithmetic_single!(trunc, f32, self), - // F64Trunc => arithmetic_single!(trunc, f64, self), - // F32Nearest => arithmetic_single!(tw_nearest, f32, self), - // F64Nearest => arithmetic_single!(tw_nearest, f64, self), - // F32Sqrt => arithmetic_single!(sqrt, f32, self), - // F64Sqrt => arithmetic_single!(sqrt, f64, self), - // F32Min => arithmetic!(tw_minimum, f32, self), - // F64Min => arithmetic!(tw_minimum, f64, self), - // F32Max => arithmetic!(tw_maximum, f32, self), - // F64Max => arithmetic!(tw_maximum, f64, self), - // F32Copysign => arithmetic!(copysign, f32, self), - // F64Copysign => arithmetic!(copysign, f64, self), + I32DivS => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_div(b)) + })?, + I64DivS => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_div(b)) + })?, + I32DivU => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_div(b)) + })?, + I64DivU => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_div(b)) + })?, + + I32RemS => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_rem(b)) + })?, + I64RemS => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_rem(b)) + })?, + I32RemU => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_rem(b)) + })?, + I64RemU => self.stack.values.calculate::(|a, b| { + if unlikely(b == 0) { + return Err(Error::Trap(Trap::DivisionByZero)); + } + Ok(a.wrapping_rem(b)) + })?, + + I32And => self.stack.values.calculate::(|a, b| Ok(a & b))?, + I64And => self.stack.values.calculate::(|a, b| Ok(a & b))?, + I32Or => self.stack.values.calculate::(|a, b| Ok(a | b))?, + I64Or => self.stack.values.calculate::(|a, b| Ok(a | b))?, + I32Xor => self.stack.values.calculate::(|a, b| Ok(a ^ b))?, + I64Xor => self.stack.values.calculate::(|a, b| Ok(a ^ b))?, + I32Shl => self.stack.values.calculate::(|a, b| Ok(a.wasm_shl(b)))?, + I64Shl => self.stack.values.calculate::(|a, b| Ok(a.wasm_shl(b)))?, + I32ShrS => self.stack.values.calculate::(|a, b| Ok(a.wasm_shr(b)))?, + I64ShrS => self.stack.values.calculate::(|a, b| Ok(a.wasm_shr(b)))?, + I32ShrU => self.stack.values.calculate::(|a, b| Ok(a.wasm_shr(b)))?, + I64ShrU => self.stack.values.calculate::(|a, b| Ok(a.wasm_shr(b)))?, + I32Rotl => self.stack.values.calculate::(|a, b| Ok(a.wasm_rotl(b)))?, + I64Rotl => self.stack.values.calculate::(|a, b| Ok(a.wasm_rotl(b)))?, + I32Rotr => self.stack.values.calculate::(|a, b| Ok(a.wasm_rotr(b)))?, + I64Rotr => self.stack.values.calculate::(|a, b| Ok(a.wasm_rotr(b)))?, + + I32Clz => self.stack.values.replace_top::(|v| Ok(v.leading_zeros() as i32))?, + I64Clz => self.stack.values.replace_top::(|v| Ok(v.leading_zeros() as i64))?, + I32Ctz => self.stack.values.replace_top::(|v| Ok(v.trailing_zeros() as i32))?, + I64Ctz => self.stack.values.replace_top::(|v| Ok(v.trailing_zeros() as i64))?, + I32Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones() as i32))?, + I64Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones() as i64))?, + + F32ConvertI32S => self.stack.values.replace_top::(|v| Ok(v as f32))?, + F32ConvertI64S => self.stack.values.replace_top::(|v| Ok(v as f32))?, + F64ConvertI32S => self.stack.values.replace_top::(|v| Ok(v as f64))?, + F64ConvertI64S => self.stack.values.replace_top::(|v| Ok(v as f64))?, + F32ConvertI32U => self.stack.values.replace_top::(|v| Ok(v as f32))?, + F32ConvertI64U => self.stack.values.replace_top::(|v| Ok(v as f32))?, + F64ConvertI32U => self.stack.values.replace_top::(|v| Ok(v as f64))?, + F64ConvertI64U => self.stack.values.replace_top::(|v| Ok(v as f64))?, + + I32Extend8S => self.stack.values.replace_top::(|v| Ok((v as i8) as i32))?, + I32Extend16S => self.stack.values.replace_top::(|v| Ok((v as i16) as i32))?, + I64Extend8S => self.stack.values.replace_top::(|v| Ok((v as i8) as i64))?, + I64Extend16S => self.stack.values.replace_top::(|v| Ok((v as i16) as i64))?, + I64Extend32S => self.stack.values.replace_top::(|v| Ok((v as i32) as i64))?, + I64ExtendI32U => self.stack.values.replace_top::(|v| Ok(v as i64))?, + I64ExtendI32S => self.stack.values.replace_top::(|v| Ok(v as i64))?, + I32WrapI64 => self.stack.values.replace_top::(|v| Ok(v as i32))?, + + F32DemoteF64 => self.stack.values.replace_top::(|v| Ok(v as f32))?, + F64PromoteF32 => self.stack.values.replace_top::(|v| Ok(v as f64))?, + + F32Abs => self.stack.values.replace_top::(|v| Ok(v.abs()))?, + F64Abs => self.stack.values.replace_top::(|v| Ok(v.abs()))?, + F32Neg => self.stack.values.replace_top::(|v| Ok(-v))?, + F64Neg => self.stack.values.replace_top::(|v| Ok(-v))?, + F32Ceil => self.stack.values.replace_top::(|v| Ok(v.ceil()))?, + F64Ceil => self.stack.values.replace_top::(|v| Ok(v.ceil()))?, + F32Floor => self.stack.values.replace_top::(|v| Ok(v.floor()))?, + F64Floor => self.stack.values.replace_top::(|v| Ok(v.floor()))?, + F32Trunc => self.stack.values.replace_top::(|v| Ok(v.trunc()))?, + F64Trunc => self.stack.values.replace_top::(|v| Ok(v.trunc()))?, + F32Nearest => self.stack.values.replace_top::(|v| Ok(v.tw_nearest()))?, + F64Nearest => self.stack.values.replace_top::(|v| Ok(v.tw_nearest()))?, + F32Sqrt => self.stack.values.replace_top::(|v| Ok(v.sqrt()))?, + F64Sqrt => self.stack.values.replace_top::(|v| Ok(v.sqrt()))?, + F32Min => self.stack.values.calculate::(|a, b| Ok(a.tw_minimum(b)))?, + F64Min => self.stack.values.calculate::(|a, b| Ok(a.tw_minimum(b)))?, + F32Max => self.stack.values.calculate::(|a, b| Ok(a.tw_maximum(b)))?, + F64Max => self.stack.values.calculate::(|a, b| Ok(a.tw_maximum(b)))?, + F32Copysign => self.stack.values.calculate::(|a, b| Ok(a.copysign(b)))?, + F64Copysign => self.stack.values.calculate::(|a, b| Ok(a.copysign(b)))?, // no-op instructions since types are erased at runtime I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} - // unsigned versions of these are a bit broken atm + // WIP // I32TruncF32S => checked_conv_float!(4, f32, i32, self), // I32TruncF64S => checked_conv_float!(8, f64, i32, self), // I32TruncF32U => checked_conv_float!(4, f32, u32, i32, self), @@ -313,14 +354,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { TableGrow(table_idx) => self.exec_table_grow(*table_idx)?, TableFill(table_idx) => self.exec_table_fill(*table_idx)?, - // I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, self), - // I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, self), - // I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, self), - // I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, self), - // I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, self), - // I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, self), - // I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, self), - // I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, self), + I32TruncSatF32S => self.stack.values.replace_top::(|v| Ok(v.trunc() as i32))?, + I32TruncSatF32U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u32))?, + I32TruncSatF64S => self.stack.values.replace_top::(|v| Ok(v.trunc() as i32))?, + I32TruncSatF64U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u32))?, + I64TruncSatF32S => self.stack.values.replace_top::(|v| Ok(v.trunc() as i64))?, + I64TruncSatF32U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u64))?, + I64TruncSatF64S => self.stack.values.replace_top::(|v| Ok(v.trunc() as i64))?, + I64TruncSatF64U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u64))?, // custom instructions LocalGet2(a, b) => self.exec_local_get2(*a, *b), @@ -375,7 +416,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { // verify that the table is of the right type, this should be validated by the parser already let func_ref = { let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?; - let table_idx: u32 = self.stack.values.pop_32()? as u32; + let table_idx: u32 = self.stack.values.pop::()? as u32; let table = table.borrow(); assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); table @@ -415,7 +456,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> { // truthy value is on the top of the stack, so enter the then block - if self.stack.values.pop_32()? != 0 { + if self.stack.values.pop::()? != 0 { self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, args); return Ok(()); } @@ -461,7 +502,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(ControlFlow::Continue(())) } fn exec_br_if(&mut self, to: u32) -> Result> { - if self.stack.values.pop_32()? != 0 { + if self.stack.values.pop::()? != 0 { break_to!(to, self); } self.cf.incr_instr_ptr(); @@ -474,7 +515,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, self.cf.instructions().len()))); } - let idx = self.stack.values.pop_32()?; + let idx = self.stack.values.pop::()?; match self.cf.instructions()[start..end].get(idx as usize) { None => break_to!(default, self), Some(Instruction::BrLabel(to)) => break_to!(*to, self), @@ -505,7 +546,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_local_get(&mut self, local_index: u32) { - self.stack.values.push(self.cf.get_local(local_index)); + self.stack.values.push_dyn(self.cf.get_local(local_index)); } fn exec_local_set(&mut self, local_index: u32) -> Result<()> { todo!("needs to be updated"); @@ -516,7 +557,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { // self.stack.values.last().map(|val| self.cf.set_local(local_index, *val)) } fn exec_global_get(&mut self, global_index: u32) -> Result<()> { - self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?); + self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?); Ok(()) } fn exec_global_set(&mut self, global_index: u32) -> Result<()> { @@ -524,21 +565,21 @@ impl<'store, 'stack> Executor<'store, 'stack> { // self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop_raw()?) } fn exec_ref_is_null(&mut self) -> Result<()> { - let is_null = self.stack.values.pop_ref()?.is_none() as i32; - self.stack.values.push_32(is_null); + let is_null = self.stack.values.pop::()?.is_none() as i32; + self.stack.values.push::(is_null); Ok(()) } fn exec_memory_size(&mut self, addr: u32) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?; - self.stack.values.push_32(mem.borrow().page_count() as i32); + self.stack.values.push::(mem.borrow().page_count() as i32); Ok(()) } fn exec_memory_grow(&mut self, addr: u32) -> Result<()> { let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?.borrow_mut(); let prev_size = mem.page_count() as i32; - let pages_delta = self.stack.values.pop_32()?; - self.stack.values.push_32(match mem.grow(pages_delta) { + let pages_delta = self.stack.values.pop::()?; + self.stack.values.push::(match mem.grow(pages_delta) { Some(_) => prev_size, None => -1, }); @@ -546,9 +587,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> { - let size = self.stack.values.pop_32()?; - let src = self.stack.values.pop_32()?; - let dst = self.stack.values.pop_32()?; + let size = self.stack.values.pop::()?; + let src = self.stack.values.pop::()?; + let dst = self.stack.values.pop::()?; if from == to { let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from)?)?.borrow_mut(); @@ -563,18 +604,18 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn exec_memory_fill(&mut self, addr: u32) -> Result<()> { - let size = self.stack.values.pop_32()?; - let val = self.stack.values.pop_32()?; - let dst = self.stack.values.pop_32()?; + let size = self.stack.values.pop::()?; + let val = self.stack.values.pop::()?; + let dst = self.stack.values.pop::()?; let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?; mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; Ok(()) } fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> { - let size = self.stack.values.pop_32()?; // n - let offset = self.stack.values.pop_32()?; // s - let dst = self.stack.values.pop_32()?; // d + let size = self.stack.values.pop::()?; // n + let offset = self.stack.values.pop::()?; // s + let dst = self.stack.values.pop::()?; // d let data = self.store.get_data(self.module.resolve_data_addr(data_index)?)?; let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index)?)?; @@ -604,9 +645,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)?).map(|e| e.drop()) } fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> { - let size: i32 = self.stack.values.pop_32()?; - let src: i32 = self.stack.values.pop_32()?; - let dst: i32 = self.stack.values.pop_32()?; + let size: i32 = self.stack.values.pop::()?; + let src: i32 = self.stack.values.pop::()?; + let dst: i32 = self.stack.values.pop::()?; if from == to { let mut table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow_mut(); @@ -628,7 +669,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { offset: u64, ) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; - let val: u64 = self.stack.values.pop_64()? as u64; + let val: u64 = self.stack.values.pop::()? as u64; let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else { cold(); return Err(Error::Trap(crate::Trap::MemoryOutOfBounds { @@ -639,7 +680,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { }; let val = mem.borrow().load_as::(addr)?; - self.stack.values.push(cast(val).into()); + self.stack.values.push_dyn(cast(val).into()); Ok(()) } fn exec_mem_store, const N: usize>( @@ -650,28 +691,28 @@ impl<'store, 'stack> Executor<'store, 'stack> { ) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; let val = val.to_mem_bytes(); - let addr: i64 = self.stack.values.pop_64()?; + let addr: i64 = self.stack.values.pop::()?; mem.borrow_mut().store((offset + addr as u64) as usize, val.len(), &val)?; Ok(()) } fn exec_table_get(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let idx: i32 = self.stack.values.pop_32()?; + let idx: i32 = self.stack.values.pop::()?; let v = table.borrow().get_wasm_val(idx as u32)?; - self.stack.values.push(v.into()); + self.stack.values.push_dyn(v.into()); Ok(()) } fn exec_table_set(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let val = self.stack.values.pop_ref()?; - let idx = self.stack.values.pop_32()? as u32; + let val = self.stack.values.pop::()?; + let idx = self.stack.values.pop::()? as u32; table.borrow_mut().set(idx, val.into())?; Ok(()) } fn exec_table_size(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - self.stack.values.push(table.borrow().size().into()); + self.stack.values.push_dyn(table.borrow().size().into()); Ok(()) } fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> { @@ -680,9 +721,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index)?)?; let elem_len = elem.items.as_ref().map(|items| items.len()).unwrap_or(0); - let size: i32 = self.stack.values.pop_32()?; // n - let offset: i32 = self.stack.values.pop_32()?; // s - let dst: i32 = self.stack.values.pop_32()?; // d + let size: i32 = self.stack.values.pop::()?; // n + let offset: i32 = self.stack.values.pop::()?; // s + let dst: i32 = self.stack.values.pop::()?; // d if unlikely(((size + offset) as usize > elem_len) || ((dst + size) > table_len)) { return Err(Trap::TableOutOfBounds { offset: offset as usize, len: size as usize, max: elem_len }.into()); @@ -707,12 +748,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; let sz = table.borrow().size(); - let n = self.stack.values.pop_32()?; - let val = self.stack.values.pop_ref()?; + let n = self.stack.values.pop::()?; + let val = self.stack.values.pop::()?; match table.borrow_mut().grow(n, val.into()) { - Ok(_) => self.stack.values.push(sz.into()), - Err(_) => self.stack.values.push((-1_i32).into()), + Ok(_) => self.stack.values.push_dyn(sz.into()), + Err(_) => self.stack.values.push_dyn((-1_i32).into()), } Ok(()) @@ -720,9 +761,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_table_fill(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?; - let n = self.stack.values.pop_32()?; - let val = self.stack.values.pop_ref()?; - let i = self.stack.values.pop_32()?; + let n = self.stack.values.pop::()?; + let val = self.stack.values.pop::()?; + let i = self.stack.values.pop::()?; if unlikely(i + n > table.borrow().size()) { return Err(Error::Trap(Trap::TableOutOfBounds { @@ -758,12 +799,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) { let local: i32 = self.cf.get_local(local).unwrap_32() as i32; - self.stack.values.push((local + val).into()); + self.stack.values.push_dyn((local + val).into()); } fn exec_i64_xor_const_rotl(&mut self, rotate_by: i64) -> Result<()> { - let val = self.stack.values.pop_64()?; - let mask = self.stack.values.pop_64()?; - self.stack.values.push_64((val ^ mask).rotate_left(rotate_by as u32)); + let val = self.stack.values.pop::()?; + let mask = self.stack.values.pop::()?; + self.stack.values.push((val ^ mask).rotate_left(rotate_by as u32)); Ok(()) } fn exec_local_get2(&mut self, a: u32, b: u32) { diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index 059c091..cef536a 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -1,7 +1,7 @@ use crate::{cold, unlikely, Error, Result}; use alloc::vec::Vec; -use super::value_stack::{StackHeight, StackLocation}; +use super::values::{StackHeight, StackLocation}; #[derive(Debug)] pub(crate) struct BlockStack(Vec); diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/runtime/stack/mod.rs index bc43621..3902bd2 100644 --- a/crates/tinywasm/src/runtime/stack/mod.rs +++ b/crates/tinywasm/src/runtime/stack/mod.rs @@ -5,7 +5,7 @@ pub mod values; pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; pub(crate) use call_stack::{CallFrame, CallStack}; -pub(crate) use value_stack::{StackHeight, ValueStack}; +pub(crate) use value_stack::ValueStack; /// A WebAssembly Stack #[derive(Debug)] diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index d24f8e0..abff03a 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -16,51 +16,6 @@ pub(crate) struct ValueStack { pub(crate) stack_ref: Vec, } -#[derive(Debug, Clone, Copy)] -pub(crate) struct StackLocation { - pub(crate) s32: u32, - pub(crate) s64: u32, - pub(crate) s128: u32, - pub(crate) sref: u32, -} - -#[derive(Debug, Clone, Copy, Default)] -pub(crate) struct StackHeight { - pub(crate) s32: u32, - pub(crate) s64: u32, - pub(crate) s128: u32, - pub(crate) sref: u32, -} - -impl From for StackHeight { - fn from(value: ValType) -> Self { - match value { - ValType::I32 | ValType::F32 => Self { s32: 1, ..Default::default() }, - ValType::I64 | ValType::F64 => Self { s64: 1, ..Default::default() }, - ValType::V128 => Self { s128: 1, ..Default::default() }, - ValType::RefExtern | ValType::RefFunc => Self { sref: 1, ..Default::default() }, - } - } -} - -impl From<&[ValType]> for StackHeight { - fn from(value: &[ValType]) -> Self { - let mut s32 = 0; - let mut s64 = 0; - let mut s128 = 0; - let mut sref = 0; - for val_type in value.iter() { - match val_type { - ValType::I32 | ValType::F32 => s32 += 1, - ValType::I64 | ValType::F64 => s64 += 1, - ValType::V128 => s128 += 1, - ValType::RefExtern | ValType::RefFunc => sref += 1, - } - } - Self { s32, s64, s128, sref } - } -} - impl ValueStack { pub(crate) fn new() -> Self { Self { @@ -80,94 +35,57 @@ impl ValueStack { } } - pub(crate) fn pop_32(&mut self) -> Result { - self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32) - } - pub(crate) fn pop_64(&mut self) -> Result { - self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64) - } - pub(crate) fn pop_128(&mut self) -> Result { - self.stack_128.pop().ok_or(Error::ValueStackUnderflow) + pub(crate) fn pop(&mut self) -> Result { + T::pop(self) } - pub(crate) fn pop_ref(&mut self) -> Result> { - self.stack_ref.pop().ok_or(Error::ValueStackUnderflow) - } - pub(crate) fn push_32(&mut self, value: i32) { - self.stack_32.push(value as u32); - } - pub(crate) fn push_64(&mut self, value: i64) { - self.stack_64.push(value as u64); - } - pub(crate) fn push_128(&mut self, value: u128) { - self.stack_128.push(value); + + pub(crate) fn push(&mut self, value: T) { + T::push(self, value) } - pub(crate) fn push_ref(&mut self, value: Option) { - self.stack_ref.push(value); + + pub(crate) fn drop(&mut self) -> Result<()> { + T::pop(self).map(|_| ()) } - pub(crate) fn drop(&mut self) -> Result<()> { - match T { - 0 => self.stack_32.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), - 1 => self.stack_64.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), - 2 => self.stack_128.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), - 3 => self.stack_ref.pop().map(|_| ()).ok_or(Error::ValueStackUnderflow), - _ => unreachable!("Invalid type"), + pub(crate) fn select(&mut self) -> Result<()> { + let cond: i32 = self.pop()?; + let val2: T = self.pop()?; + if cond == 0 { + self.drop::()?; + self.push(val2); } + Ok(()) } - pub(crate) fn select(&mut self) -> Result<()> { - macro_rules! select { - ($($i:literal => $pop:ident, $push:ident),*) => { - match T { - $($i => { - let cond = self.pop_32()?; - let val2 = self.$pop()?; - if cond == 0 { - self.drop::<$i>()?; - self.$push(val2); - } - })* - _ => unreachable!("Invalid type") - } - }; - } - select!(0 => pop_32, push_32, 1 => pop_64, push_64, 2 => pop_128, push_128, 3 => pop_ref, push_ref); + + pub(crate) fn calculate(&mut self, func: fn(T, T) -> Result) -> Result<()> { + let v2 = T::pop(self)?; + let v1 = T::pop(self)?; + U::push(self, func(v1, v2)?); Ok(()) } - pub(crate) fn pop(&mut self, val_type: ValType) -> Result { - match val_type { - ValType::I32 => self.pop_32().map(WasmValue::I32), - ValType::I64 => self.pop_64().map(WasmValue::I64), - ValType::V128 => self.pop_128().map(WasmValue::V128), - ValType::F32 => self.pop_32().map(|v| WasmValue::F32(f32::from_bits(v as u32))), - ValType::F64 => self.pop_64().map(|v| WasmValue::F64(f64::from_bits(v as u64))), - ValType::RefExtern => self.pop_ref().map(|v| match v { - Some(v) => WasmValue::RefExtern(v), - None => WasmValue::RefNull(ValType::RefExtern), - }), - ValType::RefFunc => self.pop_ref().map(|v| match v { - Some(v) => WasmValue::RefFunc(v), - None => WasmValue::RefNull(ValType::RefFunc), - }), - } + pub(crate) fn replace_top(&mut self, func: fn(T) -> Result) -> Result<()> { + let v1 = T::pop(self)?; + U::push(self, func(v1)?); + Ok(()) } - pub(crate) fn pop_raw(&mut self, val_type: ValType) -> Result { + pub(crate) fn pop_dyn(&mut self, val_type: ValType) -> Result { match val_type { - ValType::I32 => self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value32), - ValType::I64 => self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value64), - ValType::V128 => self.stack_128.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value128), - ValType::RefExtern => self.stack_ref.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::ValueRef), - ValType::RefFunc => self.stack_ref.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::ValueRef), - ValType::F32 => self.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value32), - ValType::F64 => self.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(TinyWasmValue::Value64), + ValType::I32 => self.pop().map(TinyWasmValue::Value32), + ValType::I64 => self.pop().map(TinyWasmValue::Value64), + ValType::V128 => self.pop().map(TinyWasmValue::Value128), + ValType::RefExtern => self.pop().map(TinyWasmValue::ValueRef), + ValType::RefFunc => self.pop().map(TinyWasmValue::ValueRef), + ValType::F32 => self.pop().map(TinyWasmValue::Value32), + ValType::F64 => self.pop().map(TinyWasmValue::Value64), } } pub(crate) fn pop_many(&mut self, val_types: &[ValType]) -> Result> { let mut values = Vec::with_capacity(val_types.len()); for val_type in val_types.iter().rev() { - values.push(self.pop(*val_type)?); + values.push(self.pop_wasmvalue(*val_type)?); } Ok(values) } @@ -175,7 +93,7 @@ impl ValueStack { pub(crate) fn pop_many_raw(&mut self, val_types: &[ValType]) -> Result> { let mut values = Vec::with_capacity(val_types.len()); for val_type in val_types.iter().rev() { - values.push(self.pop_raw(*val_type)?); + values.push(self.pop_dyn(*val_type)?); } Ok(values) } @@ -194,7 +112,7 @@ impl ValueStack { self.stack_ref.drain(height.sref as usize..(self.stack_ref.len() - keep.sref as usize)); } - pub(crate) fn push(&mut self, value: TinyWasmValue) { + pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) { match value { TinyWasmValue::Value32(v) => self.stack_32.push(v), TinyWasmValue::Value64(v) => self.stack_64.push(v), @@ -203,9 +121,136 @@ impl ValueStack { } } + pub(crate) fn pop_wasmvalue(&mut self, val_type: ValType) -> Result { + match val_type { + ValType::I32 => self.pop().map(WasmValue::I32), + ValType::I64 => self.pop().map(WasmValue::I64), + ValType::V128 => self.pop().map(WasmValue::V128), + ValType::F32 => self.pop().map(WasmValue::F32), + ValType::F64 => self.pop().map(WasmValue::F64), + ValType::RefExtern => self.pop().map(|v| match v { + Some(v) => WasmValue::RefExtern(v), + None => WasmValue::RefNull(ValType::RefExtern), + }), + ValType::RefFunc => self.pop().map(|v| match v { + Some(v) => WasmValue::RefFunc(v), + None => WasmValue::RefNull(ValType::RefFunc), + }), + } + } + pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) { for value in values.iter() { - self.push(value.into()) + self.push_dyn(value.into()) } } } + +mod sealed { + #[allow(unreachable_pub)] + pub trait Sealed {} +} + +impl sealed::Sealed for i32 {} +impl sealed::Sealed for f32 {} +impl sealed::Sealed for i64 {} +impl sealed::Sealed for u64 {} +impl sealed::Sealed for f64 {} +impl sealed::Sealed for u32 {} +impl sealed::Sealed for Value128 {} +impl sealed::Sealed for ValueRef {} + +pub(crate) trait StackValue: sealed::Sealed { + fn push(stack: &mut ValueStack, value: Self); + fn pop(stack: &mut ValueStack) -> Result + where + Self: Sized; +} + +impl StackValue for i32 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value as u32); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32) + } +} + +impl StackValue for f32 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value.to_bits()); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(f32::from_bits) + } +} + +impl StackValue for i64 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value as u64); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64) + } +} + +impl StackValue for u64 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow) + } +} + +impl StackValue for f64 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value.to_bits()); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(f64::from_bits) + } +} + +impl StackValue for u32 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow) + } +} + +impl StackValue for Value128 { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_128.push(value); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_128.pop().ok_or(Error::ValueStackUnderflow) + } +} + +impl StackValue for ValueRef { + #[inline] + fn push(stack: &mut ValueStack, value: Self) { + stack.stack_ref.push(value); + } + #[inline] + fn pop(stack: &mut ValueStack) -> Result { + stack.stack_ref.pop().ok_or(Error::ValueStackUnderflow) + } +} diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs index f027a91..3e32c53 100644 --- a/crates/tinywasm/src/runtime/stack/values.rs +++ b/crates/tinywasm/src/runtime/stack/values.rs @@ -11,6 +11,51 @@ pub const VALUE64: u8 = 1; pub const VALUE128: u8 = 2; pub const VALUEREF: u8 = 3; +#[derive(Debug, Clone, Copy)] +pub(crate) struct StackLocation { + pub(crate) s32: u32, + pub(crate) s64: u32, + pub(crate) s128: u32, + pub(crate) sref: u32, +} + +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct StackHeight { + pub(crate) s32: u32, + pub(crate) s64: u32, + pub(crate) s128: u32, + pub(crate) sref: u32, +} + +impl From for StackHeight { + fn from(value: ValType) -> Self { + match value { + ValType::I32 | ValType::F32 => Self { s32: 1, ..Default::default() }, + ValType::I64 | ValType::F64 => Self { s64: 1, ..Default::default() }, + ValType::V128 => Self { s128: 1, ..Default::default() }, + ValType::RefExtern | ValType::RefFunc => Self { sref: 1, ..Default::default() }, + } + } +} + +impl From<&[ValType]> for StackHeight { + fn from(value: &[ValType]) -> Self { + let mut s32 = 0; + let mut s64 = 0; + let mut s128 = 0; + let mut sref = 0; + for val_type in value.iter() { + match val_type { + ValType::I32 | ValType::F32 => s32 += 1, + ValType::I64 | ValType::F64 => s64 += 1, + ValType::V128 => s128 += 1, + ValType::RefExtern | ValType::RefFunc => sref += 1, + } + } + Self { s32, s64, s128, sref } + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub enum TinyWasmValue { Value32(Value32), diff --git a/crates/tinywasm/tests/generated/2.0.csv b/crates/tinywasm/tests/generated/2.0.csv index 3ad4978..dc16bfd 100644 --- a/crates/tinywasm/tests/generated/2.0.csv +++ b/crates/tinywasm/tests/generated/2.0.csv @@ -3,4 +3,4 @@ 0.4.1,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,27871,48,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":112,"failed":5},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1728,"failed":0},{"name":"table_fill.wast","passed":45,"failed":0},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":50,"failed":0},{"name":"table_init.wast","passed":737,"failed":43},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,7429,20498,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":100,"failed":62},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"bulk.wast","passed":34,"failed":83},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":34,"failed":136},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":80,"failed":539},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":14,"failed":2500},{"name":"f32_bitwise.wast","passed":4,"failed":360},{"name":"f32_cmp.wast","passed":7,"failed":2400},{"name":"f64.wast","passed":14,"failed":2500},{"name":"f64_bitwise.wast","passed":4,"failed":360},{"name":"f64_cmp.wast","passed":7,"failed":2400},{"name":"fac.wast","passed":1,"failed":7},{"name":"float_exprs.wast","passed":96,"failed":804},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":1,"failed":440},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":80,"failed":92},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":86,"failed":374},{"name":"i64.wast","passed":32,"failed":384},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":19,"failed":89},{"name":"int_literals.wast","passed":49,"failed":2},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":34,"failed":19},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_copy.wast","passed":119,"failed":4331},{"name":"memory_fill.wast","passed":83,"failed":17},{"name":"memory_grow.wast","passed":37,"failed":59},{"name":"memory_init.wast","passed":114,"failed":126},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref_func.wast","passed":6,"failed":11},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":3,"failed":25},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1717,"failed":11},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":31,"failed":19},{"name":"table_init.wast","passed":737,"failed":43},{"name":"table_set.wast","passed":12,"failed":14},{"name":"table_size.wast","passed":2,"failed":37},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 41b2d92..e6752db 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,20279,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,5664,14623,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":100,"failed":62},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":34,"failed":136},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":435,"failed":184},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":114,"failed":2400},{"name":"f32_bitwise.wast","passed":40,"failed":324},{"name":"f32_cmp.wast","passed":7,"failed":2400},{"name":"f64.wast","passed":114,"failed":2400},{"name":"f64_bitwise.wast","passed":40,"failed":324},{"name":"f64_cmp.wast","passed":7,"failed":2400},{"name":"fac.wast","passed":1,"failed":7},{"name":"float_exprs.wast","passed":343,"failed":557},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":106,"failed":335},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":80,"failed":92},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":127,"failed":333},{"name":"i64.wast","passed":83,"failed":333},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":96,"failed":12},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":34,"failed":19},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":37,"failed":59},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":3,"failed":25},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] From 089e9b0cc537ae90097fc10bf0bd73620b85dce3 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 27 Jun 2024 15:11:34 +0200 Subject: [PATCH 04/10] wip: per value local registers Signed-off-by: Henry Gressmann --- crates/parser/src/conversion.rs | 42 +++- crates/parser/src/module.rs | 4 +- crates/parser/src/visit.rs | 119 ++++----- .../src/runtime/interpreter/macros.rs | 123 ---------- .../tinywasm/src/runtime/interpreter/mod.rs | 194 ++++++--------- .../interpreter/{traits.rs => num_helpers.rs} | 44 ++++ .../tinywasm/src/runtime/stack/call_stack.rs | 63 +++-- .../tinywasm/src/runtime/stack/value_stack.rs | 143 ++--------- crates/tinywasm/src/runtime/stack/values.rs | 228 ++++++++++++++++++ crates/tinywasm/tests/generated/mvp.csv | 2 +- crates/types/src/instructions.rs | 48 ++-- crates/types/src/lib.rs | 11 +- 12 files changed, 536 insertions(+), 485 deletions(-) delete mode 100644 crates/tinywasm/src/runtime/interpreter/macros.rs rename crates/tinywasm/src/runtime/interpreter/{traits.rs => num_helpers.rs} (66%) diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 2f6fa37..f18b570 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -174,21 +174,39 @@ pub(crate) fn convert_module_code( let count = locals_reader.get_count(); let pos = locals_reader.original_position(); - let locals = { - let mut locals = Vec::new(); - locals.reserve_exact(count as usize); - for (i, local) in locals_reader.into_iter().enumerate() { - let local = local?; - validator.define_locals(pos + i, local.0, local.1)?; - for _ in 0..local.0 { - locals.push(convert_valtype(&local.1)); + // maps a local's address to the index in the type's locals array + let mut local_addr_map = Vec::with_capacity(count as usize); + let mut local_counts = LocalCounts::default(); + + for (i, local) in locals_reader.into_iter().enumerate() { + let local = local?; + validator.define_locals(pos + i, local.0, local.1)?; + } + + for i in 0..validator.len_locals() { + match validator.get_local_type(i) { + Some(wasmparser::ValType::I32) | Some(wasmparser::ValType::F32) => { + local_addr_map.push(local_counts.local_32); + local_counts.local_32 += 1; + } + Some(wasmparser::ValType::I64) | Some(wasmparser::ValType::F64) => { + local_addr_map.push(local_counts.local_64); + local_counts.local_64 += 1; } + Some(wasmparser::ValType::V128) => { + local_addr_map.push(local_counts.local_128); + local_counts.local_128 += 1; + } + Some(wasmparser::ValType::Ref(_)) => { + local_addr_map.push(local_counts.local_ref); + local_counts.local_ref += 1; + } + None => return Err(crate::ParseError::UnsupportedOperator("Unknown local type".to_string())), } - locals.into_boxed_slice() - }; + } - let (body, allocations) = process_operators_and_validate(validator, func)?; - Ok(((body, locals), allocations)) + let (body, allocations) = process_operators_and_validate(validator, func, local_addr_map)?; + Ok(((body, local_counts), allocations)) } pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result { diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 7cf5da7..3ee619f 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -3,12 +3,12 @@ use crate::{conversion, ParseError, Result}; use alloc::string::ToString; use alloc::{boxed::Box, format, vec::Vec}; use tinywasm_types::{ - Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValType, + Data, Element, Export, FuncType, Global, Import, Instruction, LocalCounts, MemoryType, TableType, TinyWasmModule, WasmFunction, }; use wasmparser::{FuncValidatorAllocations, Payload, Validator}; -pub(crate) type Code = (Box<[Instruction]>, Box<[ValType]>); +pub(crate) type Code = (Box<[Instruction]>, LocalCounts); #[derive(Default)] pub(crate) struct ModuleReader { diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 679143c..19925db 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -25,10 +25,11 @@ impl<'a, R: WasmModuleResources> VisitOperator<'a> for ValidateThenVisit<'_, R> pub(crate) fn process_operators_and_validate( validator: FuncValidator, body: FunctionBody<'_>, + local_addr_map: Vec, ) -> Result<(Box<[Instruction]>, FuncValidatorAllocations)> { let mut reader = body.get_operators_reader()?; let remaining = reader.get_binary_reader().bytes_remaining(); - let mut builder = FunctionBuilder::new(remaining, validator); + let mut builder = FunctionBuilder::new(remaining, validator, local_addr_map); while !reader.eof() { reader.visit_operator(&mut ValidateThenVisit(reader.original_position(), &mut builder))??; @@ -78,6 +79,7 @@ pub(crate) struct FunctionBuilder { validator: FuncValidator, instructions: Vec, label_ptrs: Vec, + local_addr_map: Vec, errors: Vec, } @@ -95,9 +97,10 @@ impl FunctionBuilder { } impl FunctionBuilder { - pub(crate) fn new(instr_capacity: usize, validator: FuncValidator) -> Self { + pub(crate) fn new(instr_capacity: usize, validator: FuncValidator, local_addr_map: Vec) -> Self { Self { validator, + local_addr_map, instructions: Vec::with_capacity(instr_capacity), label_ptrs: Vec::with_capacity(256), errors: Vec::new(), @@ -338,91 +341,63 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { let arg = MemoryArg { offset: memarg.offset, mem_addr: memarg.memory }; let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; - - if self.instructions.len() < 3 || arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF { - return self.instructions.push(i32store); - } - - match self.instructions[self.instructions.len() - 2..] { - [_, Instruction::LocalGet2(a, b)] => { - self.instructions.pop(); - self.instructions.push(Instruction::I32StoreLocal { - local_a: a, - local_b: b, - offset: arg.offset as u32, - mem_addr: arg.mem_addr as u8, - }) - } - [Instruction::LocalGet(a), Instruction::I32Const(b)] => { - self.instructions.pop(); - self.instructions.pop(); - self.instructions.push(Instruction::I32ConstStoreLocal { - local: a, - const_i32: b, - offset: arg.offset as u32, - mem_addr: arg.mem_addr as u8, - }) - } - _ => self.instructions.push(i32store), - } + self.instructions.push(i32store) } fn visit_local_get(&mut self, idx: u32) -> Self::Output { - let Some(instruction) = self.instructions.last_mut() else { - return self.instructions.push(Instruction::LocalGet(idx)); - }; - - match instruction { - Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx), - Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx), - Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx), - _ => self.instructions.push(Instruction::LocalGet(idx)), - }; + let idx = self.local_addr_map[idx as usize]; + match self.validator.get_operand_type(0) { + Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + tinywasm_types::ValType::I32 => Instruction::LocalGet32(idx), + tinywasm_types::ValType::F32 => Instruction::LocalGet32(idx), + tinywasm_types::ValType::I64 => Instruction::LocalGet64(idx), + tinywasm_types::ValType::F64 => Instruction::LocalGet64(idx), + tinywasm_types::ValType::V128 => Instruction::LocalGet128(idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalGetRef(idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalGetRef(idx), + }), + _ => unreachable!("this should have been caught by the validator"), + } } fn visit_local_set(&mut self, idx: u32) -> Self::Output { - let Some(instruction) = self.instructions.last_mut() else { - return self.instructions.push(Instruction::LocalSet(idx)); - }; - match instruction { - Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx), - _ => self.instructions.push(Instruction::LocalSet(idx)), - }; + let idx = self.local_addr_map[idx as usize]; + match self.validator.get_operand_type(0) { + Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + tinywasm_types::ValType::I32 => Instruction::LocalSet32(idx), + tinywasm_types::ValType::F32 => Instruction::LocalSet32(idx), + tinywasm_types::ValType::I64 => Instruction::LocalSet64(idx), + tinywasm_types::ValType::F64 => Instruction::LocalSet64(idx), + tinywasm_types::ValType::V128 => Instruction::LocalSet128(idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalSetRef(idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalSetRef(idx), + }), + _ => unreachable!("this should have been caught by the validator"), + } } fn visit_local_tee(&mut self, idx: u32) -> Self::Output { - self.instructions.push(Instruction::LocalTee(idx)) + let idx = self.local_addr_map[idx as usize]; + match self.validator.get_operand_type(0) { + Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + tinywasm_types::ValType::I32 => Instruction::LocalTee32(idx), + tinywasm_types::ValType::F32 => Instruction::LocalTee32(idx), + tinywasm_types::ValType::I64 => Instruction::LocalTee64(idx), + tinywasm_types::ValType::F64 => Instruction::LocalTee64(idx), + tinywasm_types::ValType::V128 => Instruction::LocalTee128(idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalTeeRef(idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalTeeRef(idx), + }), + _ => unreachable!("this should have been caught by the validator"), + } } fn visit_i64_rotl(&mut self) -> Self::Output { - let Some([Instruction::I64Xor, Instruction::I64Const(a)]) = self.instructions.last_chunk::<2>() else { - return self.instructions.push(Instruction::I64Rotl); - }; - let a = *a; - self.instructions.pop(); - self.instructions.pop(); - self.instructions.push(Instruction::I64XorConstRotl(a)) + self.instructions.push(Instruction::I64Rotl) } fn visit_i32_add(&mut self) -> Self::Output { - let Some(last) = self.instructions.last_chunk::<2>() else { - return self.instructions.push(Instruction::I32Add); - }; - - match *last { - [Instruction::LocalGet(a), Instruction::I32Const(b)] => { - self.instructions.pop(); - self.instructions.pop(); - self.instructions.push(Instruction::I32LocalGetConstAdd(a, b)) - } - [Instruction::LocalGet2(a, b), Instruction::I32Const(c)] => { - self.instructions.pop(); - self.instructions.pop(); - self.instructions.push(Instruction::LocalGet(a)); - self.instructions.push(Instruction::I32LocalGetConstAdd(b, c)) - } - _ => self.instructions.push(Instruction::I32Add), - } + self.instructions.push(Instruction::I32Add) } fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output { diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs deleted file mode 100644 index 5e725fb..0000000 --- a/crates/tinywasm/src/runtime/interpreter/macros.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Break to a block at the given index (relative to the current frame) -// If there is no block at the given index, return or call the parent function -// -// This is a bit hard to see from the spec, but it's vaild to use breaks to return -// from a function, so we need to check if the label stack is empty -macro_rules! break_to { - ($break_to_relative:expr, $self:expr) => { - if $self.cf.break_to($break_to_relative, &mut $self.stack.values, &mut $self.stack.blocks).is_none() { - return $self.exec_return(); - } - }; -} - -/// Doing the actual conversion from float to int is a bit tricky, because -/// we need to check for overflow. This macro generates the min/max values -/// for a specific conversion, which are then used in the actual conversion. -/// Rust sadly doesn't have wrapping casts for floats yet, maybe never. -/// Alternatively, https://crates.io/crates/az could be used for this but -/// it's not worth the dependency. -#[rustfmt::skip] -macro_rules! float_min_max { - (f32, i32) => {(-2147483904.0_f32, 2147483648.0_f32)}; - (f64, i32) => {(-2147483649.0_f64, 2147483648.0_f64)}; - (f32, u32) => {(-1.0_f32, 4294967296.0_f32)}; // 2^32 - (f64, u32) => {(-1.0_f64, 4294967296.0_f64)}; // 2^32 - (f32, i64) => {(-9223373136366403584.0_f32, 9223372036854775808.0_f32)}; // 2^63 + 2^40 | 2^63 - (f64, i64) => {(-9223372036854777856.0_f64, 9223372036854775808.0_f64)}; // 2^63 + 2^40 | 2^63 - (f32, u64) => {(-1.0_f32, 18446744073709551616.0_f32)}; // 2^64 - (f64, u64) => {(-1.0_f64, 18446744073709551616.0_f64)}; // 2^64 - // other conversions are not allowed - ($from:ty, $to:ty) => {compile_error!("invalid float conversion")}; -} - -/// Convert a value on the stack -macro_rules! conv { - ($from:ty, $to:ty, $self:expr) => { - $self.stack.values.replace_top(|v| (<$from>::from(v) as $to).into())? - }; -} - -/// Convert a value on the stack with error checking -macro_rules! checked_conv_float { - // Direct conversion with error checking (two types) - ($size:expr, $from:tt, $to:tt, $self:expr) => { - checked_conv_float!($size, $from, $to, $to, $self) - }; - // Conversion with an intermediate unsigned type and error checking (three types) - ($size:expr, $from:tt, $intermediate:tt, $to:tt, $self:expr) => { - $self.stack.values.replace_top_trap::<$size>(|v| { - let (min, max) = float_min_max!($from, $intermediate); - let a: $from = v.into(); - if unlikely(a.is_nan()) { - return Err(Error::Trap(crate::Trap::InvalidConversionToInt)); - } - if unlikely(a <= min || a >= max) { - return Err(Error::Trap(crate::Trap::IntegerOverflow)); - } - Ok((a as $intermediate as $to).into()) - })? - }; -} - -/// Compare two values on the stack -macro_rules! comp { - ($op:tt, $size:expr, $to:ty, $self:ident) => { - $self.stack.values.calculate::<$size>(|a, b| { - ((<$to>::from(a) $op <$to>::from(b)) as i32).into() - })? - }; -} - -/// Compare a value on the stack to zero -macro_rules! comp_zero { - ($op:tt, $size:expr, $ty:ty, $self:expr) => { - $self.stack.values.replace_top::<$size>(|v| ((<$ty>::from(v) $op 0) as i32).into())? - }; -} - -/// Apply an arithmetic method to two values on the stack -macro_rules! arithmetic { - ($op:ident, $size:expr, $to:ty, $self:expr) => { - $self.stack.values.calculate::<$size>(|a, b| { - (<$to>::from(a).$op(<$to>::from(b)) as $to).into() - })? - }; - - // also allow operators such as +, - - ($op:tt, $size:expr, $ty:ty, $self:expr) => { - $self.stack.values.calculate::<$size>(|a, b| { - ((<$ty>::from(a) $op <$ty>::from(b)) as $ty).into() - })? - }; -} - -/// Apply an arithmetic method to a single value on the stack -macro_rules! arithmetic_single { - ($op:ident, $size:expr, $ty:ty, $self:expr) => { - arithmetic_single!($op, $size, $ty, $ty, $self) - }; - - ($op:ident, $size:expr, $from:ty, $to:ty, $self:expr) => { - $self.stack.values.replace_top::<$size>(|v| (<$from>::from(v).$op() as $to).into())? - }; -} - -/// Apply an arithmetic operation to two values on the stack with error checking -macro_rules! checked_int_arithmetic { - ($op:ident, $size:expr, $to:ty, $self:expr) => { - $self.stack.values.calculate_trap::<$size>(|a, b| { - let a: $to = a.into(); - let b: $to = b.into(); - - if unlikely(b == 0) { - return Err(Error::Trap(crate::Trap::DivisionByZero)); - } - - let result = a.$op(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))?; - Ok((result).into()) - })? - }; -} - -pub(super) use break_to; diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 07513df..2df3b4e 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -1,16 +1,4 @@ -use alloc::{format, rc::Rc, string::ToString}; -use core::ops::ControlFlow; -use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction}; -use traits::{TinywasmFloatExt, WasmIntOps}; - -use super::stack::{values::StackHeight, BlockFrame, BlockType}; -use super::{values::*, InterpreterRuntime, Stack}; -use crate::runtime::CallFrame; -use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap}; - -mod macros; -mod traits; -use macros::*; +mod num_helpers; #[cfg(not(feature = "std"))] mod no_std_floats; @@ -19,6 +7,16 @@ mod no_std_floats; #[allow(unused_imports)] use no_std_floats::NoStdFloatExt; +use alloc::{format, rc::Rc, string::ToString}; +use core::ops::ControlFlow; +use num_helpers::*; +use tinywasm_types::*; + +use super::stack::{values::StackHeight, BlockFrame, BlockType}; +use super::{values::*, InterpreterRuntime, Stack}; +use crate::runtime::CallFrame; +use crate::*; + impl InterpreterRuntime { pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> { Executor::new(store, stack)?.run_to_completion() @@ -81,9 +79,29 @@ impl<'store, 'stack> Executor<'store, 'stack> { Return => return self.exec_return(), EndBlockFrame => self.exec_end_block()?, - LocalGet(local_index) => self.exec_local_get(*local_index), - LocalSet(local_index) => self.exec_local_set(*local_index)?, - LocalTee(local_index) => self.exec_local_tee(*local_index)?, + LocalGet32(local_index) => { + self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? + } + LocalGet64(local_index) => { + self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? + } + LocalGet128(local_index) => { + self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? + } + LocalGetRef(local_index) => { + self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? + } + + LocalSet32(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + LocalSet64(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + LocalSet128(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + LocalSetRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + + LocalTee32(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::()?)?, + LocalTee64(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::()?)?, + LocalTee128(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::()?)?, + LocalTeeRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::()?)?, + GlobalGet(global_index) => self.exec_global_get(*global_index)?, GlobalSet(global_index) => self.exec_global_set(*global_index)?, @@ -218,55 +236,55 @@ impl<'store, 'stack> Executor<'store, 'stack> { F32Mul => self.stack.values.calculate::(|a, b| Ok(a * b))?, F64Mul => self.stack.values.calculate::(|a, b| Ok(a * b))?, - // // these can trap + // these can trap I32DivS => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_div(b)) + a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I64DivS => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_div(b)) + a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I32DivU => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_div(b)) + a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I64DivU => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_div(b)) + a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I32RemS => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_rem(b)) + a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I64RemS => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_rem(b)) + a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I32RemU => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_rem(b)) + a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I64RemU => self.stack.values.calculate::(|a, b| { if unlikely(b == 0) { return Err(Error::Trap(Trap::DivisionByZero)); } - Ok(a.wrapping_rem(b)) + a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow)) })?, I32And => self.stack.values.calculate::(|a, b| Ok(a & b))?, @@ -338,15 +356,15 @@ impl<'store, 'stack> Executor<'store, 'stack> { // no-op instructions since types are erased at runtime I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} - // WIP - // I32TruncF32S => checked_conv_float!(4, f32, i32, self), - // I32TruncF64S => checked_conv_float!(8, f64, i32, self), - // I32TruncF32U => checked_conv_float!(4, f32, u32, i32, self), - // I32TruncF64U => checked_conv_float!(8, f64, u32, i32, self), - // I64TruncF32S => checked_conv_float!(4, f32, i64, self), - // I64TruncF64S => checked_conv_float!(8, f64, i64, self), - // I64TruncF32U => checked_conv_float!(4, f32, u64, i64, self), - // I64TruncF64U => checked_conv_float!(8, f64, u64, i64, self), + I32TruncF32S => checked_conv_float!(f32, i32, self), + I32TruncF64S => checked_conv_float!(f64, i32, self), + I32TruncF32U => checked_conv_float!(f32, u32, i32, self), + I32TruncF64U => checked_conv_float!(f64, u32, i32, self), + I64TruncF32S => checked_conv_float!(f32, i64, self), + I64TruncF64S => checked_conv_float!(f64, i64, self), + I64TruncF32U => checked_conv_float!(f32, u64, i64, self), + I64TruncF64U => checked_conv_float!(f64, u64, i64, self), + TableGet(table_idx) => self.exec_table_get(*table_idx)?, TableSet(table_idx) => self.exec_table_set(*table_idx)?, TableSize(table_idx) => self.exec_table_size(*table_idx)?, @@ -362,21 +380,19 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64TruncSatF32U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u64))?, I64TruncSatF64S => self.stack.values.replace_top::(|v| Ok(v.trunc() as i64))?, I64TruncSatF64U => self.stack.values.replace_top::(|v| Ok(v.trunc() as u64))?, - // custom instructions - LocalGet2(a, b) => self.exec_local_get2(*a, *b), - LocalGet3(a, b, c) => self.exec_local_get3(*a, *b, *c), - LocalTeeGet(a, b) => self.exec_local_tee_get(*a, *b)?, - LocalGetSet(a, b) => self.exec_local_get_set(*a, *b), - I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by)?, - I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val), - I32ConstStoreLocal { local, const_i32, offset, mem_addr } => { - self.exec_i32_const_store_local(*local, *const_i32, *offset, *mem_addr)? - } - I32StoreLocal { local_a, local_b, offset, mem_addr } => { - self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)? - } - instr => todo!("instruction not implemented: {:?}", instr), + // LocalGet2(a, b) => self.exec_local_get2(*a, *b), + // LocalGet3(a, b, c) => self.exec_local_get3(*a, *b, *c), + // LocalTeeGet(a, b) => self.exec_local_tee_get(*a, *b)?, + // LocalGetSet(a, b) => self.exec_local_get_set(*a, *b), + // I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by)?, + // I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val), + // I32ConstStoreLocal { local, const_i32, offset, mem_addr } => { + // self.exec_i32_const_store_local(*local, *const_i32, *offset, *mem_addr)? + // } + // I32StoreLocal { local_a, local_b, offset, mem_addr } => { + // self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)? + // } }; self.cf.instr_ptr += 1; @@ -497,13 +513,18 @@ impl<'store, 'stack> Executor<'store, 'stack> { }); } fn exec_br(&mut self, to: u32) -> Result> { - break_to!(to, self); + if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { + return self.exec_return(); + } + self.cf.incr_instr_ptr(); Ok(ControlFlow::Continue(())) } fn exec_br_if(&mut self, to: u32) -> Result> { - if self.stack.values.pop::()? != 0 { - break_to!(to, self); + if self.stack.values.pop::()? != 0 + && self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() + { + return self.exec_return(); } self.cf.incr_instr_ptr(); Ok(ControlFlow::Continue(())) @@ -516,10 +537,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { } let idx = self.stack.values.pop::()?; - match self.cf.instructions()[start..end].get(idx as usize) { - None => break_to!(default, self), - Some(Instruction::BrLabel(to)) => break_to!(*to, self), + let to = match self.cf.instructions()[start..end].get(idx as usize) { + None => default, + Some(Instruction::BrLabel(to)) => *to, _ => return Err(Error::Other("br_table with invalid label".to_string())), + }; + + if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { + return self.exec_return(); } self.cf.incr_instr_ptr(); @@ -545,22 +570,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } - fn exec_local_get(&mut self, local_index: u32) { - self.stack.values.push_dyn(self.cf.get_local(local_index)); - } - fn exec_local_set(&mut self, local_index: u32) -> Result<()> { - todo!("needs to be updated"); - // self.stack.values.pop().map(|val| self.cf.set_local(local_index, val)) - } - fn exec_local_tee(&mut self, local_index: u32) -> Result<()> { - todo!("needs to be updated"); - // self.stack.values.last().map(|val| self.cf.set_local(local_index, *val)) - } fn exec_global_get(&mut self, global_index: u32) -> Result<()> { self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?); Ok(()) } - fn exec_global_set(&mut self, global_index: u32) -> Result<()> { + fn exec_global_set(&mut self, _global_index: u32) -> Result<()> { todo!("needs to be updated"); // self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop_raw()?) } @@ -780,52 +794,4 @@ impl<'store, 'stack> Executor<'store, 'stack> { table.borrow_mut().fill(self.module.func_addrs(), i as usize, n as usize, val.into())?; Ok(()) } - - // custom instructions - fn exec_i32_const_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> { - let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?; - let val = const_i32.to_mem_bytes(); - let addr = self.cf.get_local(local).unwrap_64(); - mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; - Ok(()) - } - fn exec_i32_store_local(&mut self, local_a: u32, local_b: u32, offset: u32, mem_addr: u8) -> Result<()> { - let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?; - let addr: u64 = self.cf.get_local(local_a).unwrap_64(); - let val: i32 = self.cf.get_local(local_b).unwrap_32() as i32; - let val = val.to_mem_bytes(); - mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; - Ok(()) - } - fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) { - let local: i32 = self.cf.get_local(local).unwrap_32() as i32; - self.stack.values.push_dyn((local + val).into()); - } - fn exec_i64_xor_const_rotl(&mut self, rotate_by: i64) -> Result<()> { - let val = self.stack.values.pop::()?; - let mask = self.stack.values.pop::()?; - self.stack.values.push((val ^ mask).rotate_left(rotate_by as u32)); - Ok(()) - } - fn exec_local_get2(&mut self, a: u32, b: u32) { - todo!("needs to be updated"); - // self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b)]); - } - fn exec_local_get3(&mut self, a: u32, b: u32, c: u32) { - todo!("needs to be updated"); - // self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b), self.cf.get_local(c)]); - } - fn exec_local_get_set(&mut self, a: u32, b: u32) { - self.cf.set_local(b, self.cf.get_local(a)) - } - fn exec_local_tee_get(&mut self, a: u32, b: u32) -> Result<()> { - todo!("needs to be updated"); - // let last = self.stack.values.last()?; - // self.cf.set_local(a, *last); - // self.stack.values.push(match a == b { - // true => *last, - // false => self.cf.get_local(b), - // }); - // Ok(()) - } } diff --git a/crates/tinywasm/src/runtime/interpreter/traits.rs b/crates/tinywasm/src/runtime/interpreter/num_helpers.rs similarity index 66% rename from crates/tinywasm/src/runtime/interpreter/traits.rs rename to crates/tinywasm/src/runtime/interpreter/num_helpers.rs index 7aeb3b7..d0402bc 100644 --- a/crates/tinywasm/src/runtime/interpreter/traits.rs +++ b/crates/tinywasm/src/runtime/interpreter/num_helpers.rs @@ -5,6 +5,50 @@ where fn checked_wrapping_rem(self, rhs: Self) -> Option; } +/// Doing the actual conversion from float to int is a bit tricky, because +/// we need to check for overflow. This macro generates the min/max values +/// for a specific conversion, which are then used in the actual conversion. +/// Rust sadly doesn't have wrapping casts for floats yet, maybe never. +/// Alternatively, https://crates.io/crates/az could be used for this but +/// it's not worth the dependency. +#[rustfmt::skip] +macro_rules! float_min_max { + (f32, i32) => {(-2147483904.0_f32, 2147483648.0_f32)}; + (f64, i32) => {(-2147483649.0_f64, 2147483648.0_f64)}; + (f32, u32) => {(-1.0_f32, 4294967296.0_f32)}; // 2^32 + (f64, u32) => {(-1.0_f64, 4294967296.0_f64)}; // 2^32 + (f32, i64) => {(-9223373136366403584.0_f32, 9223372036854775808.0_f32)}; // 2^63 + 2^40 | 2^63 + (f64, i64) => {(-9223372036854777856.0_f64, 9223372036854775808.0_f64)}; // 2^63 + 2^40 | 2^63 + (f32, u64) => {(-1.0_f32, 18446744073709551616.0_f32)}; // 2^64 + (f64, u64) => {(-1.0_f64, 18446744073709551616.0_f64)}; // 2^64 + // other conversions are not allowed + ($from:ty, $to:ty) => {compile_error!("invalid float conversion")}; +} + +/// Convert a value on the stack with error checking +macro_rules! checked_conv_float { + // Direct conversion with error checking (two types) + ($from:tt, $to:tt, $self:expr) => { + checked_conv_float!($from, $to, $to, $self) + }; + // Conversion with an intermediate unsigned type and error checking (three types) + ($from:tt, $intermediate:tt, $to:tt, $self:expr) => { + $self.stack.values.replace_top::<$from, $to>(|v| { + let (min, max) = float_min_max!($from, $intermediate); + if unlikely(v.is_nan()) { + return Err(Error::Trap(crate::Trap::InvalidConversionToInt)); + } + if unlikely(v <= min || v >= max) { + return Err(Error::Trap(crate::Trap::IntegerOverflow)); + } + Ok((v as $intermediate as $to).into()) + })? + }; +} + +pub(crate) use checked_conv_float; +pub(crate) use float_min_max; + pub(crate) trait TinywasmFloatExt { fn tw_minimum(self, other: Self) -> Self; fn tw_maximum(self, other: Self) -> Self; diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 41fd9b2..8e9dbe7 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,4 +1,4 @@ -use super::values::TinyWasmValue; +use super::values::{InternalValue, TinyWasmValue, Value128, Value32, Value64, ValueRef}; use super::BlockType; use crate::unlikely; use crate::{Result, Trap}; @@ -41,7 +41,25 @@ pub(crate) struct CallFrame { pub(crate) block_ptr: u32, pub(crate) func_instance: Rc, pub(crate) module_addr: ModuleInstanceAddr, - pub(crate) locals: Box<[TinyWasmValue]>, + pub(crate) locals: Locals, +} + +#[derive(Debug)] +pub(crate) struct Locals { + pub(crate) locals_32: Box<[Value32]>, + pub(crate) locals_64: Box<[Value64]>, + pub(crate) locals_128: Box<[Value128]>, + pub(crate) locals_ref: Box<[ValueRef]>, +} + +impl Locals { + pub(crate) fn get(&self, local_index: LocalAddr) -> Result { + T::local_get(self, local_index) + } + + pub(crate) fn set(&mut self, local_index: LocalAddr, value: T) -> Result<()> { + T::local_set(self, local_index, value) + } } impl CallFrame { @@ -140,25 +158,34 @@ impl CallFrame { block_ptr: u32, ) -> Self { let locals = { - let total_size = wasm_func_inst.locals.len() + params.len(); - let mut locals = Vec::new(); - locals.reserve_exact(total_size); - locals.extend(params); - locals.resize_with(total_size, Default::default); - locals.into_boxed_slice() - }; + let mut locals_32 = Vec::new(); + let mut locals_64 = Vec::new(); + let mut locals_128 = Vec::new(); + let mut locals_ref = Vec::new(); + + for p in params { + match p { + TinyWasmValue::Value32(v) => locals_32.push(v), + TinyWasmValue::Value64(v) => locals_64.push(v), + TinyWasmValue::Value128(v) => locals_128.push(v), + TinyWasmValue::ValueRef(v) => locals_ref.push(v), + } + } - Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals } - } + locals_32.resize_with(wasm_func_inst.locals.local_32 as usize, Default::default); + locals_64.resize_with(wasm_func_inst.locals.local_64 as usize, Default::default); + locals_128.resize_with(wasm_func_inst.locals.local_128 as usize, Default::default); + locals_ref.resize_with(wasm_func_inst.locals.local_ref as usize, Default::default); - #[inline(always)] - pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: TinyWasmValue) { - self.locals[local_index as usize] = value; - } + Locals { + locals_32: locals_32.into_boxed_slice(), + locals_64: locals_64.into_boxed_slice(), + locals_128: locals_128.into_boxed_slice(), + locals_ref: locals_ref.into_boxed_slice(), + } + }; - #[inline(always)] - pub(crate) fn get_local(&self, local_index: LocalAddr) -> TinyWasmValue { - self.locals[local_index as usize] + Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals } } #[inline(always)] diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index abff03a..6925872 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; use super::values::*; -use crate::{Error, Result}; +use crate::Result; pub(crate) const STACK_32_SIZE: usize = 1024 * 128; pub(crate) const STACK_64_SIZE: usize = 1024 * 128; pub(crate) const STACK_128_SIZE: usize = 1024 * 128; @@ -35,19 +35,23 @@ impl ValueStack { } } - pub(crate) fn pop(&mut self) -> Result { - T::pop(self) + pub(crate) fn peek(&self) -> Result { + T::stack_peek(self) } - pub(crate) fn push(&mut self, value: T) { - T::push(self, value) + pub(crate) fn pop(&mut self) -> Result { + T::stack_pop(self) } - pub(crate) fn drop(&mut self) -> Result<()> { - T::pop(self).map(|_| ()) + pub(crate) fn push(&mut self, value: T) { + T::stack_push(self, value) } - pub(crate) fn select(&mut self) -> Result<()> { + pub(crate) fn drop(&mut self) -> Result<()> { + T::stack_pop(self).map(|_| ()) + } + + pub(crate) fn select(&mut self) -> Result<()> { let cond: i32 = self.pop()?; let val2: T = self.pop()?; if cond == 0 { @@ -57,16 +61,16 @@ impl ValueStack { Ok(()) } - pub(crate) fn calculate(&mut self, func: fn(T, T) -> Result) -> Result<()> { - let v2 = T::pop(self)?; - let v1 = T::pop(self)?; - U::push(self, func(v1, v2)?); + pub(crate) fn calculate(&mut self, func: fn(T, T) -> Result) -> Result<()> { + let v2 = T::stack_pop(self)?; + let v1 = T::stack_pop(self)?; + U::stack_push(self, func(v1, v2)?); Ok(()) } - pub(crate) fn replace_top(&mut self, func: fn(T) -> Result) -> Result<()> { - let v1 = T::pop(self)?; - U::push(self, func(v1)?); + pub(crate) fn replace_top(&mut self, func: fn(T) -> Result) -> Result<()> { + let v1 = T::stack_pop(self)?; + U::stack_push(self, func(v1)?); Ok(()) } @@ -145,112 +149,3 @@ impl ValueStack { } } } - -mod sealed { - #[allow(unreachable_pub)] - pub trait Sealed {} -} - -impl sealed::Sealed for i32 {} -impl sealed::Sealed for f32 {} -impl sealed::Sealed for i64 {} -impl sealed::Sealed for u64 {} -impl sealed::Sealed for f64 {} -impl sealed::Sealed for u32 {} -impl sealed::Sealed for Value128 {} -impl sealed::Sealed for ValueRef {} - -pub(crate) trait StackValue: sealed::Sealed { - fn push(stack: &mut ValueStack, value: Self); - fn pop(stack: &mut ValueStack) -> Result - where - Self: Sized; -} - -impl StackValue for i32 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_32.push(value as u32); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32) - } -} - -impl StackValue for f32 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_32.push(value.to_bits()); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(f32::from_bits) - } -} - -impl StackValue for i64 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_64.push(value as u64); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64) - } -} - -impl StackValue for u64 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_64.push(value); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_64.pop().ok_or(Error::ValueStackUnderflow) - } -} - -impl StackValue for f64 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_64.push(value.to_bits()); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(f64::from_bits) - } -} - -impl StackValue for u32 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_32.push(value); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_32.pop().ok_or(Error::ValueStackUnderflow) - } -} - -impl StackValue for Value128 { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_128.push(value); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_128.pop().ok_or(Error::ValueStackUnderflow) - } -} - -impl StackValue for ValueRef { - #[inline] - fn push(stack: &mut ValueStack, value: Self) { - stack.stack_ref.push(value); - } - #[inline] - fn pop(stack: &mut ValueStack) -> Result { - stack.stack_ref.pop().ok_or(Error::ValueStackUnderflow) - } -} diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs index 3e32c53..ab58d6e 100644 --- a/crates/tinywasm/src/runtime/stack/values.rs +++ b/crates/tinywasm/src/runtime/stack/values.rs @@ -1,6 +1,10 @@ #![allow(missing_docs)] use tinywasm_types::{ValType, WasmValue}; +use crate::{Error, Result}; + +use super::{call_stack::Locals, ValueStack}; + pub type Value32 = u32; pub type Value64 = u64; pub type Value128 = u128; @@ -171,3 +175,227 @@ impl From for TinyWasmValue { TinyWasmValue::Value64(value as u64) } } + +mod sealed { + #[allow(unreachable_pub)] + pub trait Sealed {} +} + +impl sealed::Sealed for i32 {} +impl sealed::Sealed for f32 {} +impl sealed::Sealed for i64 {} +impl sealed::Sealed for u64 {} +impl sealed::Sealed for f64 {} +impl sealed::Sealed for u32 {} +impl sealed::Sealed for Value128 {} +impl sealed::Sealed for ValueRef {} + +// TODO: this can be made a bit more maintainable by using a macro + +pub(crate) trait InternalValue: sealed::Sealed { + fn stack_push(stack: &mut ValueStack, value: Self); + fn stack_pop(stack: &mut ValueStack) -> Result + where + Self: Sized; + fn stack_peek(stack: &ValueStack) -> Result + where + Self: Sized; + + fn local_get(locals: &Locals, index: u32) -> Result + where + Self: Sized; + + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()>; +} + +impl InternalValue for i32 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value as u32); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_32.last().ok_or(Error::ValueStackUnderflow).map(|v| *v as i32) + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_32[index as usize] as i32) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_32[index as usize] = value as u32; + Ok(()) + } +} + +impl InternalValue for f32 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value.to_bits()); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(f32::from_bits) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_32.last().ok_or(Error::ValueStackUnderflow).map(|v| f32::from_bits(*v)) + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(f32::from_bits(locals.locals_32[index as usize])) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_32[index as usize] = value.to_bits(); + Ok(()) + } +} + +impl InternalValue for i64 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value as u64); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_64.last().ok_or(Error::ValueStackUnderflow).map(|v| *v as i64) + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_64[index as usize] as i64) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_64[index as usize] = value as u64; + Ok(()) + } +} + +impl InternalValue for u64 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_64.last().ok_or(Error::ValueStackUnderflow).copied() + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_64[index as usize]) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_64[index as usize] = value; + Ok(()) + } +} + +impl InternalValue for f64 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_64.push(value.to_bits()); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(f64::from_bits) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_64.last().ok_or(Error::ValueStackUnderflow).map(|v| f64::from_bits(*v)) + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(f64::from_bits(locals.locals_64[index as usize])) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_64[index as usize] = value.to_bits(); + Ok(()) + } +} + +impl InternalValue for u32 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_32.push(value); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_32.pop().ok_or(Error::ValueStackUnderflow) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_32.last().ok_or(Error::ValueStackUnderflow).copied() + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_32[index as usize]) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_32[index as usize] = value; + Ok(()) + } +} + +impl InternalValue for Value128 { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_128.push(value); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_128.pop().ok_or(Error::ValueStackUnderflow) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_128.last().ok_or(Error::ValueStackUnderflow).copied() + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_128[index as usize]) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_128[index as usize] = value; + Ok(()) + } +} + +impl InternalValue for ValueRef { + #[inline] + fn stack_push(stack: &mut ValueStack, value: Self) { + stack.stack_ref.push(value); + } + #[inline] + fn stack_pop(stack: &mut ValueStack) -> Result { + stack.stack_ref.pop().ok_or(Error::ValueStackUnderflow) + } + #[inline] + fn stack_peek(stack: &ValueStack) -> Result { + stack.stack_ref.last().ok_or(Error::ValueStackUnderflow).copied() + } + #[inline] + fn local_get(locals: &Locals, index: u32) -> Result { + Ok(locals.locals_ref[index as usize]) + } + #[inline] + fn local_set(locals: &mut Locals, index: u32, value: Self) -> Result<()> { + locals.locals_ref[index as usize] = value; + Ok(()) + } +} diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index e6752db..ce94f3c 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,5664,14623,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":100,"failed":62},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":34,"failed":136},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":435,"failed":184},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":114,"failed":2400},{"name":"f32_bitwise.wast","passed":40,"failed":324},{"name":"f32_cmp.wast","passed":7,"failed":2400},{"name":"f64.wast","passed":114,"failed":2400},{"name":"f64_bitwise.wast","passed":40,"failed":324},{"name":"f64_cmp.wast","passed":7,"failed":2400},{"name":"fac.wast","passed":1,"failed":7},{"name":"float_exprs.wast","passed":343,"failed":557},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":106,"failed":335},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":80,"failed":92},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":127,"failed":333},{"name":"i64.wast","passed":83,"failed":333},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":96,"failed":12},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":34,"failed":19},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":37,"failed":59},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":3,"failed":25},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,17411,2876,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":99,"failed":63},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":42,"failed":128},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":0,"failed":8},{"name":"float_exprs.wast","passed":812,"failed":88},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":77,"failed":95},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":33,"failed":20},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":31,"failed":65},{"name":"memory_redundancy.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":0,"failed":11},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":1,"failed":27},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index efbdfb5..c93936b 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -87,21 +87,20 @@ pub enum ConstInstruction { #[rustfmt::skip] pub enum Instruction { // > Custom Instructions - BrLabel(LabelAddr), - // LocalGet + I32Const + I32Add - I32LocalGetConstAdd(LocalAddr, i32), - // LocalGet + I32Const + I32Store - I32ConstStoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 }, - // LocalGet + LocalGet + I32Store - I32StoreLocal { local_a: LocalAddr, local_b: LocalAddr, offset: u32, mem_addr: u8 }, - // I64Xor + I64Const + I64RotL - // Commonly used by a few crypto libraries - I64XorConstRotl(i64), - // LocalTee + LocalGet - LocalTeeGet(LocalAddr, LocalAddr), - LocalGet2(LocalAddr, LocalAddr), - LocalGet3(LocalAddr, LocalAddr, LocalAddr), - LocalGetSet(LocalAddr, LocalAddr), + // // LocalGet + I32Const + I32Add + // I32LocalGetConstAdd(LocalAddr, i32), + // // LocalGet + I32Const + I32Store + // I32ConstStoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 }, + // // LocalGet + LocalGet + I32Store + // I32StoreLocal { local_a: LocalAddr, local_b: LocalAddr, offset: u32, mem_addr: u8 }, + // // I64Xor + I64Const + I64RotL + // // Commonly used by a few crypto libraries + // I64XorConstRotl(i64), + // // LocalTee + LocalGet + // LocalTeeGet(LocalAddr, LocalAddr), + // LocalGet2(LocalAddr, LocalAddr), + // LocalGet3(LocalAddr, LocalAddr, LocalAddr), + // LocalGetSet(LocalAddr, LocalAddr), // > Control Instructions // See @@ -115,6 +114,7 @@ pub enum Instruction { Br(LabelAddr), BrIf(LabelAddr), BrTable(BrTableDefault, BrTableLen), // has to be followed by multiple BrLabel instructions + BrLabel(LabelAddr), Return, Call(FuncAddr), CallIndirect(TypeAddr, TableAddr), @@ -133,9 +133,21 @@ pub enum Instruction { // > Variable Instructions // See - LocalGet(LocalAddr), - LocalSet(LocalAddr), - LocalTee(LocalAddr), + LocalGet32(LocalAddr), + LocalGet64(LocalAddr), + LocalGet128(LocalAddr), + LocalGetRef(LocalAddr), + + LocalSet32(LocalAddr), + LocalSet64(LocalAddr), + LocalSet128(LocalAddr), + LocalSetRef(LocalAddr), + + LocalTee32(LocalAddr), + LocalTee64(LocalAddr), + LocalTee128(LocalAddr), + LocalTeeRef(LocalAddr), + GlobalGet(GlobalAddr), GlobalSet(GlobalAddr), diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index d447efb..785b13b 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -172,11 +172,20 @@ pub struct FuncType { pub results: Box<[ValType]>, } +#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))] +pub struct LocalCounts { + pub local_32: u32, + pub local_64: u32, + pub local_128: u32, + pub local_ref: u32, +} + #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))] pub struct WasmFunction { pub instructions: Box<[Instruction]>, - pub locals: Box<[ValType]>, + pub locals: LocalCounts, pub ty: FuncType, } From eb1727afa92320da463224f816f692ecb1da1ad4 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 27 Jun 2024 19:22:24 +0200 Subject: [PATCH 05/10] wip: fix a bunch of newly introduced bugs Signed-off-by: Henry Gressmann --- crates/parser/src/visit.rs | 36 +++++++++++++------ .../tinywasm/src/runtime/interpreter/mod.rs | 31 +++++++++------- crates/tinywasm/src/runtime/stack/values.rs | 29 ++++++++++++--- crates/tinywasm/tests/generated/mvp.csv | 2 +- crates/types/src/instructions.rs | 5 ++- 5 files changed, 72 insertions(+), 31 deletions(-) diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 19925db..795d359 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -10,8 +10,8 @@ struct ValidateThenVisit<'a, R: WasmModuleResources>(usize, &'a mut FunctionBuil macro_rules! validate_then_visit { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {$( fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { - self.1.validator_visitor(self.0).$visit($($($arg.clone()),*)?)?; - self.1.$visit($($($arg),*)?); + self.1.$visit($($($arg.clone()),*)?); + self.1.validator_visitor(self.0).$visit($($($arg),*)?)?; Ok(()) } )*}; @@ -138,7 +138,6 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild visit_br, Instruction::Br, u32, visit_br_if, Instruction::BrIf, u32, visit_global_get, Instruction::GlobalGet, u32, - visit_global_set, Instruction::GlobalSet, u32, visit_i32_const, Instruction::I32Const, i32, visit_i64_const, Instruction::I64Const, i64, visit_call, Instruction::Call, u32, @@ -318,6 +317,21 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U } + fn visit_global_set(&mut self, global_index: u32) -> Self::Output { + match self.validator.get_operand_type(0) { + Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + tinywasm_types::ValType::I32 => Instruction::GlobalSet32(global_index), + tinywasm_types::ValType::F32 => Instruction::GlobalSet32(global_index), + tinywasm_types::ValType::I64 => Instruction::GlobalSet64(global_index), + tinywasm_types::ValType::F64 => Instruction::GlobalSet64(global_index), + tinywasm_types::ValType::V128 => Instruction::GlobalSet128(global_index), + tinywasm_types::ValType::RefExtern => Instruction::GlobalSetRef(global_index), + tinywasm_types::ValType::RefFunc => Instruction::GlobalSetRef(global_index), + }), + _ => self.visit_unreachable(), + } + } + fn visit_drop(&mut self) -> Self::Output { match self.validator.get_operand_type(0) { Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { @@ -329,13 +343,13 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild tinywasm_types::ValType::RefExtern => Instruction::DropRef, tinywasm_types::ValType::RefFunc => Instruction::DropRef, }), - _ => unreachable!("this should have been caught by the validator"), + _ => self.visit_unreachable(), } } fn visit_select(&mut self) -> Self::Output { match self.validator.get_operand_type(0) { Some(Some(t)) => self.visit_typed_select(t), - _ => unreachable!("Unknow type for select"), + _ => self.visit_unreachable(), } } fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { @@ -346,8 +360,8 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild fn visit_local_get(&mut self, idx: u32) -> Self::Output { let idx = self.local_addr_map[idx as usize]; - match self.validator.get_operand_type(0) { - Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { + match self.validator.get_local_type(idx) { + Some(t) => self.instructions.push(match convert_valtype(&t) { tinywasm_types::ValType::I32 => Instruction::LocalGet32(idx), tinywasm_types::ValType::F32 => Instruction::LocalGet32(idx), tinywasm_types::ValType::I64 => Instruction::LocalGet64(idx), @@ -356,7 +370,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild tinywasm_types::ValType::RefExtern => Instruction::LocalGetRef(idx), tinywasm_types::ValType::RefFunc => Instruction::LocalGetRef(idx), }), - _ => unreachable!("this should have been caught by the validator"), + _ => self.visit_unreachable(), } } @@ -372,7 +386,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild tinywasm_types::ValType::RefExtern => Instruction::LocalSetRef(idx), tinywasm_types::ValType::RefFunc => Instruction::LocalSetRef(idx), }), - _ => unreachable!("this should have been caught by the validator"), + _ => self.visit_unreachable(), } } @@ -388,7 +402,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild tinywasm_types::ValType::RefExtern => Instruction::LocalTeeRef(idx), tinywasm_types::ValType::RefFunc => Instruction::LocalTeeRef(idx), }), - _ => unreachable!("this should have been caught by the validator"), + _ => self.visit_unreachable(), } } @@ -479,7 +493,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild .targets() .map(|t| t.map(Instruction::BrLabel)) .collect::, wasmparser::BinaryReaderError>>() - .expect("BrTable targets are invalid, this should have been caught by the validator"); + .expect("visit_br_table: BrTable targets are invalid, this should have been caught by the validator"); self.instructions.extend(([Instruction::BrTable(def, instrs.len() as u32)].into_iter()).chain(instrs)); } diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 2df3b4e..5c463d7 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -65,8 +65,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { Select128 => self.stack.values.select::()?, SelectRef => self.stack.values.select::()?, - Call(v) => self.exec_call_direct(*v)?, - CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?, + Call(v) => return self.exec_call_direct(*v), + CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table), If(args, el, end) => self.exec_if((*args).into(), *el, *end)?, Else(end_offset) => self.exec_else(*end_offset)?, @@ -103,7 +103,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { LocalTeeRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::()?)?, GlobalGet(global_index) => self.exec_global_get(*global_index)?, - GlobalSet(global_index) => self.exec_global_set(*global_index)?, + GlobalSet32(global_index) => self.exec_global_set::(*global_index)?, + GlobalSet64(global_index) => self.exec_global_set::(*global_index)?, + GlobalSet128(global_index) => self.exec_global_set::(*global_index)?, + GlobalSetRef(global_index) => self.exec_global_set::(*global_index)?, I32Const(val) => self.stack.values.push(*val), I64Const(val) => self.stack.values.push(*val), @@ -405,16 +408,15 @@ impl<'store, 'stack> Executor<'store, 'stack> { Err(Error::Trap(Trap::Unreachable)) } - fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> Result<()> { + fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> Result> { let params = self.stack.values.pop_many_raw(&wasm_func.ty.params)?; let new_call_frame = CallFrame::new_raw(wasm_func, owner, params.into_iter(), self.stack.blocks.len() as u32); self.cf.instr_ptr += 1; // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); - self.cf.instr_ptr -= 1; - Ok(()) + return Ok(ControlFlow::Continue(())); } - fn exec_call_direct(&mut self, v: u32) -> Result<()> { + fn exec_call_direct(&mut self, v: u32) -> Result> { let func_inst = self.store.get_func(self.module.resolve_func_addr(v)?)?; let wasm_func = match &func_inst.func { crate::Function::Wasm(wasm_func) => wasm_func, @@ -423,12 +425,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_many(&host_func.ty.params)?; let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); - return Ok(()); + return Ok(ControlFlow::Continue(())); } }; self.exec_call(wasm_func.clone(), func_inst.owner) } - fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<()> { + fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result> { // verify that the table is of the right type, this should be validated by the parser already let func_ref = { let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?; @@ -458,7 +460,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_many(&host_func.ty.params)?; let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); - return Ok(()); + self.cf.instr_ptr += 1; + return Ok(ControlFlow::Continue(())); } }; @@ -574,9 +577,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?); Ok(()) } - fn exec_global_set(&mut self, _global_index: u32) -> Result<()> { - todo!("needs to be updated"); - // self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop_raw()?) + fn exec_global_set(&mut self, global_index: u32) -> Result<()> + where + TinyWasmValue: From, + { + self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop::()?.into()) } fn exec_ref_is_null(&mut self) -> Result<()> { let is_null = self.stack.values.pop::()?.is_none() as i32; diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs index ab58d6e..4abce92 100644 --- a/crates/tinywasm/src/runtime/stack/values.rs +++ b/crates/tinywasm/src/runtime/stack/values.rs @@ -10,11 +10,6 @@ pub type Value64 = u64; pub type Value128 = u128; pub type ValueRef = Option; -pub const VALUE32: u8 = 0; -pub const VALUE64: u8 = 1; -pub const VALUE128: u8 = 2; -pub const VALUEREF: u8 = 3; - #[derive(Debug, Clone, Copy)] pub(crate) struct StackLocation { pub(crate) s32: u32, @@ -170,12 +165,36 @@ impl From for TinyWasmValue { } } +impl From for TinyWasmValue { + fn from(value: u32) -> Self { + TinyWasmValue::Value32(value) + } +} + impl From for TinyWasmValue { fn from(value: i64) -> Self { TinyWasmValue::Value64(value as u64) } } +impl From for TinyWasmValue { + fn from(value: u64) -> Self { + TinyWasmValue::Value64(value) + } +} + +impl From for TinyWasmValue { + fn from(value: Value128) -> Self { + TinyWasmValue::Value128(value) + } +} + +impl From for TinyWasmValue { + fn from(value: ValueRef) -> Self { + TinyWasmValue::ValueRef(value) + } +} + mod sealed { #[allow(unreachable_pub)] pub trait Sealed {} diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index ce94f3c..34bee64 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,17411,2876,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":99,"failed":63},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":42,"failed":128},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":0,"failed":8},{"name":"float_exprs.wast","passed":812,"failed":88},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":77,"failed":95},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":33,"failed":20},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":31,"failed":65},{"name":"memory_redundancy.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":0,"failed":11},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":1,"failed":27},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,18293,1986,[{"name":"address.wast","passed":5,"failed":255},{"name":"align.wast","passed":114,"failed":48},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":174,"failed":49},{"name":"br.wast","passed":39,"failed":58},{"name":"br_if.wast","passed":64,"failed":54},{"name":"br_table.wast","passed":72,"failed":102},{"name":"call.wast","passed":47,"failed":44},{"name":"call_indirect.wast","passed":103,"failed":67},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":6,"failed":2},{"name":"float_exprs.wast","passed":776,"failed":124},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":144,"failed":28},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":94,"failed":16},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":125,"failed":116},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":9,"failed":20},{"name":"left-to-right.wast","passed":1,"failed":95},{"name":"linking.wast","passed":120,"failed":12},{"name":"load.wast","passed":60,"failed":37},{"name":"local_get.wast","passed":27,"failed":9},{"name":"local_set.wast","passed":52,"failed":1},{"name":"local_tee.wast","passed":76,"failed":21},{"name":"loop.wast","passed":68,"failed":52},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":61,"failed":35},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":52,"failed":36},{"name":"return.wast","passed":82,"failed":2},{"name":"select.wast","passed":82,"failed":66},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":6,"failed":14},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":19,"failed":9},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":22,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":60,"failed":4},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":29,"failed":21},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index c93936b..d19326d 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -149,7 +149,10 @@ pub enum Instruction { LocalTeeRef(LocalAddr), GlobalGet(GlobalAddr), - GlobalSet(GlobalAddr), + GlobalSet32(GlobalAddr), + GlobalSet64(GlobalAddr), + GlobalSet128(GlobalAddr), + GlobalSetRef(GlobalAddr), // > Memory Instructions I32Load { offset: u64, mem_addr: MemAddr }, From 08410e957f28a779dd76a6669a0e062930587406 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 27 Jun 2024 20:00:54 +0200 Subject: [PATCH 06/10] wip: fix more bugs Signed-off-by: Henry Gressmann --- crates/parser/src/visit.rs | 16 +++--- .../tinywasm/src/runtime/interpreter/mod.rs | 39 ++++++++++--- .../tinywasm/src/runtime/stack/call_stack.rs | 2 + .../tinywasm/src/runtime/stack/value_stack.rs | 57 +++++++++++++++---- crates/tinywasm/tests/generated/mvp.csv | 2 +- 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 795d359..1402a1c 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -359,16 +359,16 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_local_get(&mut self, idx: u32) -> Self::Output { - let idx = self.local_addr_map[idx as usize]; + let resolved_idx = self.local_addr_map[idx as usize]; match self.validator.get_local_type(idx) { Some(t) => self.instructions.push(match convert_valtype(&t) { - tinywasm_types::ValType::I32 => Instruction::LocalGet32(idx), - tinywasm_types::ValType::F32 => Instruction::LocalGet32(idx), - tinywasm_types::ValType::I64 => Instruction::LocalGet64(idx), - tinywasm_types::ValType::F64 => Instruction::LocalGet64(idx), - tinywasm_types::ValType::V128 => Instruction::LocalGet128(idx), - tinywasm_types::ValType::RefExtern => Instruction::LocalGetRef(idx), - tinywasm_types::ValType::RefFunc => Instruction::LocalGetRef(idx), + tinywasm_types::ValType::I32 => Instruction::LocalGet32(resolved_idx), + tinywasm_types::ValType::F32 => Instruction::LocalGet32(resolved_idx), + tinywasm_types::ValType::I64 => Instruction::LocalGet64(resolved_idx), + tinywasm_types::ValType::F64 => Instruction::LocalGet64(resolved_idx), + tinywasm_types::ValType::V128 => Instruction::LocalGet128(resolved_idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalGetRef(resolved_idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalGetRef(resolved_idx), }), _ => self.visit_unreachable(), } diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 5c463d7..dd942ed 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -80,9 +80,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { EndBlockFrame => self.exec_end_block()?, LocalGet32(local_index) => { + crate::log::info!("LocalGet32"); self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } LocalGet64(local_index) => { + crate::log::info!("LocalGet64"); self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } LocalGet128(local_index) => { @@ -92,8 +94,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } - LocalSet32(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, - LocalSet64(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + LocalSet32(local_index) => { + crate::log::info!("LocalSet32"); + self.cf.locals.set(*local_index, self.stack.values.pop::()?)? + } + LocalSet64(local_index) => { + crate::log::info!("LocalSet64"); + self.cf.locals.set(*local_index, self.stack.values.pop::()?)? + } LocalSet128(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, LocalSetRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, @@ -136,11 +144,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.exec_mem_store::(v, *mem_addr, *offset)? } F32Store { mem_addr, offset } => { + crate::log::info!("F32Store"); let v = self.stack.values.pop::()?; + crate::log::info!("F32Storeend"); self.exec_mem_store::(v, *mem_addr, *offset)? } F64Store { mem_addr, offset } => { + crate::log::info!("f64_1"); + crate::log::info!("{:?}", self.stack.values.height()); let v = self.stack.values.pop::()?; + crate::log::info!("f64_2"); self.exec_mem_store::(v, *mem_addr, *offset)? } @@ -414,7 +427,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.cf.instr_ptr += 1; // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); - return Ok(ControlFlow::Continue(())); + Ok(ControlFlow::Continue(())) } fn exec_call_direct(&mut self, v: u32) -> Result> { let func_inst = self.store.get_func(self.module.resolve_func_addr(v)?)?; @@ -497,6 +510,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) { + crate::log::info!("enter_block"); + let (params, results) = match args { BlockArgs::Empty => (StackHeight::default(), StackHeight::default()), BlockArgs::Type(t) => (StackHeight::default(), t.into()), @@ -505,6 +520,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { ((&*ty.params).into(), (&*ty.results).into()) } }; + crate::log::info!("enter_block2"); self.stack.blocks.push(BlockFrame { instr_ptr, @@ -514,6 +530,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { params, ty, }); + + crate::log::info!("enter_block3"); } fn exec_br(&mut self, to: u32) -> Result> { if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { @@ -554,6 +572,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(ControlFlow::Continue(())) } fn exec_return(&mut self) -> Result> { + crate::log::info!("exec_return"); let old = self.cf.block_ptr(); match self.stack.call_stack.pop() { None => return Ok(ControlFlow::Break(())), @@ -569,6 +588,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_end_block(&mut self) -> Result<()> { let block = self.stack.blocks.pop()?; + crate::log::info!("exec_end_block: {:?}", block); self.stack.values.truncate_keep(&block.stack_ptr, &block.results); Ok(()) } @@ -681,14 +701,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } - fn exec_mem_load, const LOAD_SIZE: usize, TARGET: Into>( + fn exec_mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( &mut self, cast: fn(LOAD) -> TARGET, mem_addr: tinywasm_types::MemAddr, offset: u64, ) -> Result<()> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; - let val: u64 = self.stack.values.pop::()? as u64; + let val = self.stack.values.pop::()? as u64; let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else { cold(); return Err(Error::Trap(crate::Trap::MemoryOutOfBounds { @@ -697,9 +717,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { max: mem.borrow().max_pages(), })); }; - let val = mem.borrow().load_as::(addr)?; - self.stack.values.push_dyn(cast(val).into()); + self.stack.values.push(cast(val)); Ok(()) } fn exec_mem_store, const N: usize>( @@ -708,10 +727,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { mem_addr: tinywasm_types::MemAddr, offset: u64, ) -> Result<()> { + crate::log::info!("exec_mem_store"); let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; let val = val.to_mem_bytes(); - let addr: i64 = self.stack.values.pop::()?; - mem.borrow_mut().store((offset + addr as u64) as usize, val.len(), &val)?; + let addr = self.stack.values.pop::()? as u64; + mem.borrow_mut().store((offset + addr) as usize, val.len(), &val)?; + crate::log::info!("exec_mem_store_end"); Ok(()) } diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 8e9dbe7..a1b16f2 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -185,6 +185,8 @@ impl CallFrame { } }; + crate::log::info!("Locals: {:?}", locals); + Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 6925872..529bb6f 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -102,18 +102,11 @@ impl ValueStack { Ok(values) } - pub(crate) fn truncate(&mut self, height: &StackLocation) { - self.stack_32.truncate(height.s32 as usize); - self.stack_64.truncate(height.s64 as usize); - self.stack_128.truncate(height.s128 as usize); - self.stack_ref.truncate(height.sref as usize); - } - pub(crate) fn truncate_keep(&mut self, height: &StackLocation, keep: &StackHeight) { - self.stack_32.drain(height.s32 as usize..(self.stack_128.len() - keep.s32 as usize)); - self.stack_64.drain(height.s64 as usize..(self.stack_64.len() - keep.s64 as usize)); - self.stack_128.drain(height.s128 as usize..(self.stack_128.len() - keep.s128 as usize)); - self.stack_ref.drain(height.sref as usize..(self.stack_ref.len() - keep.sref as usize)); + truncate_keep(&mut self.stack_32, height.s32, keep.s32); + truncate_keep(&mut self.stack_64, height.s64, keep.s64); + truncate_keep(&mut self.stack_128, height.s128, keep.s128); + truncate_keep(&mut self.stack_ref, height.sref, keep.sref); } pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) { @@ -149,3 +142,45 @@ impl ValueStack { } } } + +fn truncate_keep(data: &mut Vec, n: u32, end_keep: u32) { + let total_to_keep = n + end_keep; + let len = data.len() as u32; + assert!(len >= total_to_keep, "total to keep should be less than or equal to self.top"); + + if len <= total_to_keep { + return; // No need to truncate if the current size is already less than or equal to total_to_keep + } + + let items_to_remove = len - total_to_keep; + let remove_start_index = (len - items_to_remove - end_keep) as usize; + let remove_end_index = (len - end_keep) as usize; + data.drain(remove_start_index..remove_end_index); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_truncate_keep() { + macro_rules! test_macro { + ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { + $( + let mut stack = alloc::vec![1,2,3,4,5]; + truncate_keep(&mut stack, $n, $end_keep); + assert_eq!(stack.len(), $expected); + )* + }; + } + + test_macro! { + 0, 0, 0, + 1, 0, 1, + 0, 1, 1, + 1, 1, 2, + 2, 1, 3, + 2, 2, 4 + } + } +} diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 34bee64..7276106 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,18293,1986,[{"name":"address.wast","passed":5,"failed":255},{"name":"align.wast","passed":114,"failed":48},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":174,"failed":49},{"name":"br.wast","passed":39,"failed":58},{"name":"br_if.wast","passed":64,"failed":54},{"name":"br_table.wast","passed":72,"failed":102},{"name":"call.wast","passed":47,"failed":44},{"name":"call_indirect.wast","passed":103,"failed":67},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":6,"failed":2},{"name":"float_exprs.wast","passed":776,"failed":124},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":144,"failed":28},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":94,"failed":16},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":125,"failed":116},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":9,"failed":20},{"name":"left-to-right.wast","passed":1,"failed":95},{"name":"linking.wast","passed":120,"failed":12},{"name":"load.wast","passed":60,"failed":37},{"name":"local_get.wast","passed":27,"failed":9},{"name":"local_set.wast","passed":52,"failed":1},{"name":"local_tee.wast","passed":76,"failed":21},{"name":"loop.wast","passed":68,"failed":52},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_grow.wast","passed":61,"failed":35},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":52,"failed":36},{"name":"return.wast","passed":82,"failed":2},{"name":"select.wast","passed":82,"failed":66},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":6,"failed":14},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":19,"failed":9},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":22,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":60,"failed":4},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":29,"failed":21},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,19876,403,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":212,"failed":11},{"name":"br.wast","passed":95,"failed":2},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":72,"failed":19},{"name":"call_indirect.wast","passed":153,"failed":17},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":29,"failed":40},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":6,"failed":2},{"name":"float_exprs.wast","passed":866,"failed":34},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":152,"failed":20},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":108,"failed":2},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":205,"failed":36},{"name":"imports.wast","passed":183,"failed":3},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":85,"failed":11},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":103,"failed":17},{"name":"memory.wast","passed":87,"failed":1},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":78,"failed":10},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":130,"failed":18},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":18,"failed":2},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] From 526f63c26c80a44520b7828d3575a62820b36c83 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 27 Jun 2024 22:13:23 +0200 Subject: [PATCH 07/10] wip: fix even more bugs Signed-off-by: Henry Gressmann --- crates/parser/src/visit.rs | 34 +++++------ .../tinywasm/src/runtime/interpreter/mod.rs | 57 +++++++------------ .../tinywasm/src/runtime/stack/call_stack.rs | 6 +- .../tinywasm/src/runtime/stack/value_stack.rs | 22 ++++--- crates/tinywasm/tests/generated/mvp.csv | 2 +- 5 files changed, 54 insertions(+), 67 deletions(-) diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 1402a1c..4e2fece 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -347,7 +347,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } } fn visit_select(&mut self) -> Self::Output { - match self.validator.get_operand_type(0) { + match self.validator.get_operand_type(1) { Some(Some(t)) => self.visit_typed_select(t), _ => self.visit_unreachable(), } @@ -375,32 +375,32 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_local_set(&mut self, idx: u32) -> Self::Output { - let idx = self.local_addr_map[idx as usize]; + let resolved_idx = self.local_addr_map[idx as usize]; match self.validator.get_operand_type(0) { Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { - tinywasm_types::ValType::I32 => Instruction::LocalSet32(idx), - tinywasm_types::ValType::F32 => Instruction::LocalSet32(idx), - tinywasm_types::ValType::I64 => Instruction::LocalSet64(idx), - tinywasm_types::ValType::F64 => Instruction::LocalSet64(idx), - tinywasm_types::ValType::V128 => Instruction::LocalSet128(idx), - tinywasm_types::ValType::RefExtern => Instruction::LocalSetRef(idx), - tinywasm_types::ValType::RefFunc => Instruction::LocalSetRef(idx), + tinywasm_types::ValType::I32 => Instruction::LocalSet32(resolved_idx), + tinywasm_types::ValType::F32 => Instruction::LocalSet32(resolved_idx), + tinywasm_types::ValType::I64 => Instruction::LocalSet64(resolved_idx), + tinywasm_types::ValType::F64 => Instruction::LocalSet64(resolved_idx), + tinywasm_types::ValType::V128 => Instruction::LocalSet128(resolved_idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalSetRef(resolved_idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalSetRef(resolved_idx), }), _ => self.visit_unreachable(), } } fn visit_local_tee(&mut self, idx: u32) -> Self::Output { - let idx = self.local_addr_map[idx as usize]; + let resolved_idx = self.local_addr_map[idx as usize]; match self.validator.get_operand_type(0) { Some(Some(t)) => self.instructions.push(match convert_valtype(&t) { - tinywasm_types::ValType::I32 => Instruction::LocalTee32(idx), - tinywasm_types::ValType::F32 => Instruction::LocalTee32(idx), - tinywasm_types::ValType::I64 => Instruction::LocalTee64(idx), - tinywasm_types::ValType::F64 => Instruction::LocalTee64(idx), - tinywasm_types::ValType::V128 => Instruction::LocalTee128(idx), - tinywasm_types::ValType::RefExtern => Instruction::LocalTeeRef(idx), - tinywasm_types::ValType::RefFunc => Instruction::LocalTeeRef(idx), + tinywasm_types::ValType::I32 => Instruction::LocalTee32(resolved_idx), + tinywasm_types::ValType::F32 => Instruction::LocalTee32(resolved_idx), + tinywasm_types::ValType::I64 => Instruction::LocalTee64(resolved_idx), + tinywasm_types::ValType::F64 => Instruction::LocalTee64(resolved_idx), + tinywasm_types::ValType::V128 => Instruction::LocalTee128(resolved_idx), + tinywasm_types::ValType::RefExtern => Instruction::LocalTeeRef(resolved_idx), + tinywasm_types::ValType::RefFunc => Instruction::LocalTeeRef(resolved_idx), }), _ => self.visit_unreachable(), } diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index dd942ed..3e48570 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -80,11 +80,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { EndBlockFrame => self.exec_end_block()?, LocalGet32(local_index) => { - crate::log::info!("LocalGet32"); self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } LocalGet64(local_index) => { - crate::log::info!("LocalGet64"); self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } LocalGet128(local_index) => { @@ -94,14 +92,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.cf.locals.get::(*local_index).map(|v| self.stack.values.push(v))? } - LocalSet32(local_index) => { - crate::log::info!("LocalSet32"); - self.cf.locals.set(*local_index, self.stack.values.pop::()?)? - } - LocalSet64(local_index) => { - crate::log::info!("LocalSet64"); - self.cf.locals.set(*local_index, self.stack.values.pop::()?)? - } + LocalSet32(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, + LocalSet64(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, LocalSet128(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, LocalSetRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::()?)?, @@ -144,16 +136,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.exec_mem_store::(v, *mem_addr, *offset)? } F32Store { mem_addr, offset } => { - crate::log::info!("F32Store"); let v = self.stack.values.pop::()?; - crate::log::info!("F32Storeend"); self.exec_mem_store::(v, *mem_addr, *offset)? } F64Store { mem_addr, offset } => { - crate::log::info!("f64_1"); - crate::log::info!("{:?}", self.stack.values.height()); let v = self.stack.values.pop::()?; - crate::log::info!("f64_2"); self.exec_mem_store::(v, *mem_addr, *offset)? } @@ -202,35 +189,35 @@ impl<'store, 'stack> Executor<'store, 'stack> { F64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, I32Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, - I64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i64))?, + I64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, F32Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, F64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, I32LtS => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, - I64LtS => self.stack.values.calculate::(|a, b| Ok((a < b) as i64))?, - I32LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, - I64LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i64))?, + I64LtS => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + I32LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, + I64LtU => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, F32Lt => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, F64Lt => self.stack.values.calculate::(|a, b| Ok((a < b) as i32))?, I32LeS => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, - I64LeS => self.stack.values.calculate::(|a, b| Ok((a <= b) as i64))?, - I32LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, - I64LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i64))?, + I64LeS => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + I32LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, + I64LeU => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, F32Le => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, F64Le => self.stack.values.calculate::(|a, b| Ok((a <= b) as i32))?, I32GeS => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, - I64GeS => self.stack.values.calculate::(|a, b| Ok((a >= b) as i64))?, - I32GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, - I64GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i64))?, + I64GeS => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + I32GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, + I64GeU => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, F32Ge => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, F64Ge => self.stack.values.calculate::(|a, b| Ok((a >= b) as i32))?, I32GtS => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, - I64GtS => self.stack.values.calculate::(|a, b| Ok((a > b) as i64))?, - I32GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, - I64GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i64))?, + I64GtS => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + I32GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, + I64GtU => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, F32Gt => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, F64Gt => self.stack.values.calculate::(|a, b| Ok((a > b) as i32))?, @@ -423,7 +410,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> Result> { let params = self.stack.values.pop_many_raw(&wasm_func.ty.params)?; - let new_call_frame = CallFrame::new_raw(wasm_func, owner, params.into_iter(), self.stack.blocks.len() as u32); + let new_call_frame = + CallFrame::new_raw(wasm_func, owner, params.into_iter().rev(), self.stack.blocks.len() as u32); self.cf.instr_ptr += 1; // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); @@ -438,9 +426,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_many(&host_func.ty.params)?; let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); + self.cf.instr_ptr += 1; return Ok(ControlFlow::Continue(())); } }; + self.exec_call(wasm_func.clone(), func_inst.owner) } fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result> { @@ -510,8 +500,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) { - crate::log::info!("enter_block"); - let (params, results) = match args { BlockArgs::Empty => (StackHeight::default(), StackHeight::default()), BlockArgs::Type(t) => (StackHeight::default(), t.into()), @@ -520,7 +508,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { ((&*ty.params).into(), (&*ty.results).into()) } }; - crate::log::info!("enter_block2"); self.stack.blocks.push(BlockFrame { instr_ptr, @@ -530,8 +517,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { params, ty, }); - - crate::log::info!("enter_block3"); } fn exec_br(&mut self, to: u32) -> Result> { if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { @@ -572,7 +557,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(ControlFlow::Continue(())) } fn exec_return(&mut self) -> Result> { - crate::log::info!("exec_return"); let old = self.cf.block_ptr(); match self.stack.call_stack.pop() { None => return Ok(ControlFlow::Break(())), @@ -588,7 +572,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_end_block(&mut self) -> Result<()> { let block = self.stack.blocks.pop()?; - crate::log::info!("exec_end_block: {:?}", block); self.stack.values.truncate_keep(&block.stack_ptr, &block.results); Ok(()) } @@ -727,12 +710,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { mem_addr: tinywasm_types::MemAddr, offset: u64, ) -> Result<()> { - crate::log::info!("exec_mem_store"); let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?; let val = val.to_mem_bytes(); let addr = self.stack.values.pop::()? as u64; mem.borrow_mut().store((offset + addr) as usize, val.len(), &val)?; - crate::log::info!("exec_mem_store_end"); Ok(()) } diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index a1b16f2..d2017ad 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -114,7 +114,7 @@ impl CallFrame { self.instr_ptr = break_to.instr_ptr; // We also want to push the params to the stack - values.truncate_keep(&break_to.stack_ptr, &break_to.params); + values.truncate_block(&break_to.stack_ptr, &break_to.params); // check if we're breaking to the loop if break_to_relative != 0 { @@ -127,7 +127,7 @@ impl CallFrame { BlockType::Block | BlockType::If | BlockType::Else => { // this is a block, so we want to jump to the next instruction after the block ends // We also want to push the block's results to the stack - values.truncate_keep(&break_to.stack_ptr, &break_to.results); + values.truncate_block(&break_to.stack_ptr, &break_to.results); // (the inst_ptr will be incremented by 1 before the next instruction is executed) self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize; @@ -185,8 +185,6 @@ impl CallFrame { } }; - crate::log::info!("Locals: {:?}", locals); - Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 529bb6f..1218ab0 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -88,7 +88,7 @@ impl ValueStack { pub(crate) fn pop_many(&mut self, val_types: &[ValType]) -> Result> { let mut values = Vec::with_capacity(val_types.len()); - for val_type in val_types.iter().rev() { + for val_type in val_types.iter() { values.push(self.pop_wasmvalue(*val_type)?); } Ok(values) @@ -96,17 +96,25 @@ impl ValueStack { pub(crate) fn pop_many_raw(&mut self, val_types: &[ValType]) -> Result> { let mut values = Vec::with_capacity(val_types.len()); - for val_type in val_types.iter().rev() { + for val_type in val_types.iter() { values.push(self.pop_dyn(*val_type)?); } Ok(values) } - pub(crate) fn truncate_keep(&mut self, height: &StackLocation, keep: &StackHeight) { - truncate_keep(&mut self.stack_32, height.s32, keep.s32); - truncate_keep(&mut self.stack_64, height.s64, keep.s64); - truncate_keep(&mut self.stack_128, height.s128, keep.s128); - truncate_keep(&mut self.stack_ref, height.sref, keep.sref); + #[inline] + pub(crate) fn truncate_block(&mut self, to: &StackLocation, keep: &StackHeight) { + self.stack_32.drain(to.s32 as usize..(self.stack_32.len() as usize - keep.s32 as usize)); + self.stack_64.drain(to.s64 as usize..(self.stack_64.len() as usize - keep.s64 as usize)); + self.stack_128.drain(to.s128 as usize..(self.stack_128.len() as usize - keep.s128 as usize)); + self.stack_ref.drain(to.sref as usize..(self.stack_ref.len() as usize - keep.sref as usize)); + } + + pub(crate) fn truncate_keep(&mut self, to: &StackLocation, keep: &StackHeight) { + truncate_keep(&mut self.stack_32, to.s32, keep.s32); + truncate_keep(&mut self.stack_64, to.s64, keep.s64); + truncate_keep(&mut self.stack_128, to.s128, keep.s128); + truncate_keep(&mut self.stack_ref, to.sref, keep.sref); } pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) { diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 7276106..926d4ee 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,19876,403,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":212,"failed":11},{"name":"br.wast","passed":95,"failed":2},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":72,"failed":19},{"name":"call_indirect.wast","passed":153,"failed":17},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":29,"failed":40},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":6,"failed":2},{"name":"float_exprs.wast","passed":866,"failed":34},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":152,"failed":20},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":108,"failed":2},{"name":"i32.wast","passed":440,"failed":20},{"name":"i64.wast","passed":290,"failed":126},{"name":"if.wast","passed":205,"failed":36},{"name":"imports.wast","passed":183,"failed":3},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":106,"failed":2},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":85,"failed":11},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":103,"failed":17},{"name":"memory.wast","passed":87,"failed":1},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":78,"failed":10},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":130,"failed":18},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":18,"failed":2},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,20222,57,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":215,"failed":8},{"name":"br.wast","passed":96,"failed":1},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":89,"failed":2},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":899,"failed":1},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":164,"failed":8},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":221,"failed":20},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":112,"failed":8},{"name":"memory.wast","passed":87,"failed":1},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] From fc4dbb81841ba80502a1efb00a08917cce4fab0b Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 28 Jun 2024 00:53:49 +0200 Subject: [PATCH 08/10] chore: fix remaining 1.0 issues Signed-off-by: Henry Gressmann --- crates/tinywasm/src/func.rs | 3 +- .../tinywasm/src/runtime/interpreter/mod.rs | 16 ++++++++-- .../tinywasm/src/runtime/stack/call_stack.rs | 6 ++-- .../tinywasm/src/runtime/stack/value_stack.rs | 32 +++++++------------ crates/tinywasm/src/store/mod.rs | 8 +---- crates/tinywasm/tests/generated/2.0.csv | 2 +- crates/tinywasm/tests/generated/mvp.csv | 2 +- 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 7c30e4a..e41addd 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -76,7 +76,8 @@ impl FuncHandle { // assert!(stack.values.len() >= result_m); // 2. Pop m values from the stack - let res = stack.values.pop_many(&func_ty.results)?; + let res = stack.values.pop_results(&func_ty.results)?; + crate::log::info!("Function returned: {:?}", res); // The values are returned as the results of the invocation. Ok(res) diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 3e48570..c6a6c19 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -51,6 +51,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[inline(always)] fn exec_next(&mut self) -> Result> { use tinywasm_types::Instruction::*; + crate::log::info!("inst: {:?}", self.cf.fetch_instr()); match self.cf.fetch_instr() { Nop => self.exec_noop(), Unreachable => self.exec_unreachable()?, @@ -186,7 +187,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, I64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, F32Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, - F64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, + F64Eq => self.stack.values.calculate::(|a, b| Ok((a == b) as i32))?, I32Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, I64Ne => self.stack.values.calculate::(|a, b| Ok((a != b) as i32))?, @@ -423,7 +424,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { crate::Function::Wasm(wasm_func) => wasm_func, crate::Function::Host(host_func) => { let func = &host_func.clone(); - let params = self.stack.values.pop_many(&host_func.ty.params)?; + let params = self.stack.values.pop_params(&host_func.ty.params)?; let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); self.cf.instr_ptr += 1; @@ -460,7 +461,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { } let host_func = host_func.clone(); - let params = self.stack.values.pop_many(&host_func.ty.params)?; + let params = self.stack.values.pop_params(&host_func.ty.params)?; let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); self.cf.instr_ptr += 1; @@ -509,6 +510,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { } }; + crate::log::info!("entering block {:?} with params {:?} and results {:?}", ty, params, results); + crate::log::info!("current stackptr: {:?}", self.stack.values.height()); + self.stack.blocks.push(BlockFrame { instr_ptr, end_instr_offset, @@ -519,9 +523,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { }); } fn exec_br(&mut self, to: u32) -> Result> { + crate::log::info!("breaking to block {:?}", to); if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { return self.exec_return(); } + crate::log::info!("breaking to block end"); self.cf.incr_instr_ptr(); Ok(ControlFlow::Continue(())) @@ -572,6 +578,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_end_block(&mut self) -> Result<()> { let block = self.stack.blocks.pop()?; + + crate::log::info!("ending block {:?} with results {:?}", block.stack_ptr, block.results); + crate::log::info!("current stackptr: {:?}", self.stack.values.height()); + self.stack.values.truncate_keep(&block.stack_ptr, &block.results); Ok(()) } diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index d2017ad..5608b9c 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -104,7 +104,9 @@ impl CallFrame { values: &mut super::ValueStack, blocks: &mut super::BlockStack, ) -> Option<()> { + crate::log::info!("1"); let break_to = blocks.get_relative_to(break_to_relative, self.block_ptr)?; + crate::log::info!("2"); // instr_ptr points to the label instruction, but the next step // will increment it by 1 since we're changing the "current" instr_ptr @@ -114,7 +116,7 @@ impl CallFrame { self.instr_ptr = break_to.instr_ptr; // We also want to push the params to the stack - values.truncate_block(&break_to.stack_ptr, &break_to.params); + values.truncate_keep(&break_to.stack_ptr, &break_to.params); // check if we're breaking to the loop if break_to_relative != 0 { @@ -127,7 +129,7 @@ impl CallFrame { BlockType::Block | BlockType::If | BlockType::Else => { // this is a block, so we want to jump to the next instruction after the block ends // We also want to push the block's results to the stack - values.truncate_block(&break_to.stack_ptr, &break_to.results); + values.truncate_keep(&break_to.stack_ptr, &break_to.results); // (the inst_ptr will be incremented by 1 before the next instruction is executed) self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize; diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 1218ab0..40376f1 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -86,12 +86,15 @@ impl ValueStack { } } - pub(crate) fn pop_many(&mut self, val_types: &[ValType]) -> Result> { - let mut values = Vec::with_capacity(val_types.len()); - for val_type in val_types.iter() { - values.push(self.pop_wasmvalue(*val_type)?); - } - Ok(values) + pub(crate) fn pop_params(&mut self, val_types: &[ValType]) -> Result> { + val_types.iter().map(|val_type| self.pop_wasmvalue(*val_type)).collect::>>() + } + + pub(crate) fn pop_results(&mut self, val_types: &[ValType]) -> Result> { + val_types.iter().rev().map(|val_type| self.pop_wasmvalue(*val_type)).collect::>>().map(|mut v| { + v.reverse(); + v + }) } pub(crate) fn pop_many_raw(&mut self, val_types: &[ValType]) -> Result> { @@ -102,14 +105,6 @@ impl ValueStack { Ok(values) } - #[inline] - pub(crate) fn truncate_block(&mut self, to: &StackLocation, keep: &StackHeight) { - self.stack_32.drain(to.s32 as usize..(self.stack_32.len() as usize - keep.s32 as usize)); - self.stack_64.drain(to.s64 as usize..(self.stack_64.len() as usize - keep.s64 as usize)); - self.stack_128.drain(to.s128 as usize..(self.stack_128.len() as usize - keep.s128 as usize)); - self.stack_ref.drain(to.sref as usize..(self.stack_ref.len() as usize - keep.sref as usize)); - } - pub(crate) fn truncate_keep(&mut self, to: &StackLocation, keep: &StackHeight) { truncate_keep(&mut self.stack_32, to.s32, keep.s32); truncate_keep(&mut self.stack_64, to.s64, keep.s64); @@ -154,16 +149,13 @@ impl ValueStack { fn truncate_keep(data: &mut Vec, n: u32, end_keep: u32) { let total_to_keep = n + end_keep; let len = data.len() as u32; - assert!(len >= total_to_keep, "total to keep should be less than or equal to self.top"); + crate::log::error!("truncate_keep: len: {}, total_to_keep: {}, end_keep: {}", len, total_to_keep, end_keep); - if len <= total_to_keep { + if len <= n { return; // No need to truncate if the current size is already less than or equal to total_to_keep } - let items_to_remove = len - total_to_keep; - let remove_start_index = (len - items_to_remove - end_keep) as usize; - let remove_end_index = (len - end_keep) as usize; - data.drain(remove_start_index..remove_end_index); + data.drain((n as usize)..(len - end_keep) as usize); } #[cfg(test)] diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 5538cd6..9ebd82e 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -251,13 +251,7 @@ impl Store { let addr = globals.get(*addr as usize).copied().ok_or_else(|| { Error::Other(format!("global {} not found. This should have been caught by the validator", addr)) })?; - let val = self.data.globals[addr as usize].value.get().unwrap_64() as i64; - - // check if the global is actually a null reference - match val < 0 { - true => None, - false => Some(val as u32), - } + self.data.globals[addr as usize].value.get().unwrap_ref() } _ => return Err(Error::UnsupportedFeature(format!("const expression other than ref: {:?}", item))), }; diff --git a/crates/tinywasm/tests/generated/2.0.csv b/crates/tinywasm/tests/generated/2.0.csv index dc16bfd..353c879 100644 --- a/crates/tinywasm/tests/generated/2.0.csv +++ b/crates/tinywasm/tests/generated/2.0.csv @@ -3,4 +3,4 @@ 0.4.1,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,7429,20498,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":100,"failed":62},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"bulk.wast","passed":34,"failed":83},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":34,"failed":136},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":676,"failed":102},{"name":"conversions.wast","passed":80,"failed":539},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":91,"failed":7},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":14,"failed":2500},{"name":"f32_bitwise.wast","passed":4,"failed":360},{"name":"f32_cmp.wast","passed":7,"failed":2400},{"name":"f64.wast","passed":14,"failed":2500},{"name":"f64_bitwise.wast","passed":4,"failed":360},{"name":"f64_cmp.wast","passed":7,"failed":2400},{"name":"fac.wast","passed":1,"failed":7},{"name":"float_exprs.wast","passed":96,"failed":804},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":1,"failed":440},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":80,"failed":92},{"name":"func_ptrs.wast","passed":35,"failed":1},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":86,"failed":374},{"name":"i64.wast","passed":32,"failed":384},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":175,"failed":11},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":19,"failed":89},{"name":"int_literals.wast","passed":49,"failed":2},{"name":"labels.wast","passed":3,"failed":26},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":115,"failed":17},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":16,"failed":20},{"name":"local_set.wast","passed":34,"failed":19},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":38,"failed":50},{"name":"memory_copy.wast","passed":119,"failed":4331},{"name":"memory_fill.wast","passed":83,"failed":17},{"name":"memory_grow.wast","passed":37,"failed":59},{"name":"memory_init.wast","passed":114,"failed":126},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":2,"failed":40},{"name":"memory_trap.wast","passed":3,"failed":179},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":4,"failed":84},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref_func.wast","passed":6,"failed":11},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":0,"failed":7},{"name":"start.wast","passed":8,"failed":12},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":3,"failed":25},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1717,"failed":11},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":31,"failed":19},{"name":"table_init.wast","passed":737,"failed":43},{"name":"table_set.wast","passed":12,"failed":14},{"name":"table_size.wast","passed":2,"failed":37},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":0,"failed":36},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":0,"failed":7},{"name":"unwind.wast","passed":0,"failed":50},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,27856,63,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":112,"failed":5},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref_func.wast","passed":6,"failed":11},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1728,"failed":0},{"name":"table_fill.wast","passed":45,"failed":0},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":46,"failed":4},{"name":"table_init.wast","passed":737,"failed":43},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 926d4ee..41b2d92 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -8,4 +8,4 @@ 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.7.0,20222,57,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":215,"failed":8},{"name":"br.wast","passed":96,"failed":1},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":89,"failed":2},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":96,"failed":2},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":899,"failed":1},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":164,"failed":8},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":221,"failed":20},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":112,"failed":8},{"name":"memory.wast","passed":87,"failed":1},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.7.0,20279,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":104,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] From 08114361127efd5c842f7cc0235446a2bf5d718b Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 28 Jun 2024 01:02:25 +0200 Subject: [PATCH 09/10] chore: update deps, cleanup Signed-off-by: Henry Gressmann --- Cargo.lock | 28 +++++++++---------- crates/cli/Cargo.toml | 2 +- crates/parser/Cargo.toml | 2 +- crates/parser/src/lib.rs | 1 + crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/func.rs | 1 - .../tinywasm/src/runtime/interpreter/mod.rs | 20 +++---------- .../tinywasm/src/runtime/stack/call_stack.rs | 2 -- crates/tinywasm/src/runtime/stack/values.rs | 4 +-- 9 files changed, 24 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d432d76..7a7412a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,9 +295,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cfg-if" @@ -768,9 +768,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "enum-iterator" @@ -1999,7 +1999,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast 211.0.1", + "wast 212.0.0", ] [[package]] @@ -2011,7 +2011,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 211.0.1", + "wast 212.0.0", ] [[package]] @@ -2020,7 +2020,7 @@ version = "0.7.0" dependencies = [ "log", "tinywasm-types", - "wasmparser 0.211.1", + "wasmparser 0.212.0", ] [[package]] @@ -2304,9 +2304,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.211.1" +version = "0.212.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e7d931a1120ef357f32b74547646b6fa68ea25e377772b72874b131a9ed70d4" +checksum = "501940df4418b8929eb6d52f1aade1fdd15a5b86c92453cb696e3c906bd3fc33" dependencies = [ "leb128", ] @@ -2550,9 +2550,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.211.1" +version = "0.212.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3189cc8a91f547390e2f043ca3b3e3fe0892f7d581767fd4e4b7f3dc3fe8e561" +checksum = "8d28bc49ba1e5c5b61ffa7a2eace10820443c4b7d1c0b144109261d14570fdf8" dependencies = [ "ahash 0.8.11", "bitflags 2.6.0", @@ -2584,15 +2584,15 @@ dependencies = [ [[package]] name = "wast" -version = "211.0.1" +version = "212.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b25506dd82d00da6b14a87436b3d52b1d264083fa79cdb72a0d1b04a8595ccaa" +checksum = "4606a05fb0aae5d11dd7d8280a640d88a63ee019360ba9be552da3d294b8d1f5" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.211.1", + "wasm-encoder 0.212.0", ] [[package]] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 60207a6..bccf998 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -20,7 +20,7 @@ argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" pretty_env_logger="0.5" -wast={version="211.0", optional=true} +wast={version="212.0", optional=true} [features] default=["wat"] diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 5b28112..89d2b71 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace=true rust-version.workspace=true [dependencies] -wasmparser={version="0.211", default-features=false, features=["validate"]} +wasmparser={version="0.212", default-features=false, features=["validate"]} log={version="0.4", optional=true} tinywasm-types={version="0.7.0", path="../types", default-features=false} diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 51743c7..0e8f976 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -62,6 +62,7 @@ impl Parser { component_model: false, component_model_nested_names: false, component_model_values: false, + component_model_more_flags: false, exceptions: false, extended_const: false, gc: false, diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index d3f81c7..d82d850 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -31,7 +31,7 @@ libm={version="0.2", default-features=false} [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} -wast={version="211.0"} +wast={version="212.0"} owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index e41addd..650f9df 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -77,7 +77,6 @@ impl FuncHandle { // 2. Pop m values from the stack let res = stack.values.pop_results(&func_ty.results)?; - crate::log::info!("Function returned: {:?}", res); // The values are returned as the results of the invocation. Ok(res) diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index c6a6c19..8028e87 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -51,7 +51,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[inline(always)] fn exec_next(&mut self) -> Result> { use tinywasm_types::Instruction::*; - crate::log::info!("inst: {:?}", self.cf.fetch_instr()); match self.cf.fetch_instr() { Nop => self.exec_noop(), Unreachable => self.exec_unreachable()?, @@ -144,8 +143,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { let v = self.stack.values.pop::()?; self.exec_mem_store::(v, *mem_addr, *offset)? } - - // TODO: this prob. needs specific conversion functions that truncate the underlying bits I32Store8 { mem_addr, offset } => { let v = self.stack.values.pop::()? as i8; self.exec_mem_store::(v, *mem_addr, *offset)? @@ -399,7 +396,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { // } }; - self.cf.instr_ptr += 1; + self.cf.incr_instr_ptr(); Ok(ControlFlow::Continue(())) } @@ -413,7 +410,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_many_raw(&wasm_func.ty.params)?; let new_call_frame = CallFrame::new_raw(wasm_func, owner, params.into_iter().rev(), self.stack.blocks.len() as u32); - self.cf.instr_ptr += 1; // skip the call instruction + self.cf.incr_instr_ptr(); // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; self.module.swap_with(self.cf.module_addr(), self.store); Ok(ControlFlow::Continue(())) @@ -427,7 +424,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_params(&host_func.ty.params)?; let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); - self.cf.instr_ptr += 1; + self.cf.incr_instr_ptr(); return Ok(ControlFlow::Continue(())); } }; @@ -464,7 +461,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let params = self.stack.values.pop_params(&host_func.ty.params)?; let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; self.stack.values.extend_from_wasmvalues(&res); - self.cf.instr_ptr += 1; + self.cf.incr_instr_ptr(); return Ok(ControlFlow::Continue(())); } }; @@ -510,9 +507,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { } }; - crate::log::info!("entering block {:?} with params {:?} and results {:?}", ty, params, results); - crate::log::info!("current stackptr: {:?}", self.stack.values.height()); - self.stack.blocks.push(BlockFrame { instr_ptr, end_instr_offset, @@ -523,11 +517,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { }); } fn exec_br(&mut self, to: u32) -> Result> { - crate::log::info!("breaking to block {:?}", to); if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() { return self.exec_return(); } - crate::log::info!("breaking to block end"); self.cf.incr_instr_ptr(); Ok(ControlFlow::Continue(())) @@ -578,10 +570,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { } fn exec_end_block(&mut self) -> Result<()> { let block = self.stack.blocks.pop()?; - - crate::log::info!("ending block {:?} with results {:?}", block.stack_ptr, block.results); - crate::log::info!("current stackptr: {:?}", self.stack.values.height()); - self.stack.values.truncate_keep(&block.stack_ptr, &block.results); Ok(()) } diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 5608b9c..8e9dbe7 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -104,9 +104,7 @@ impl CallFrame { values: &mut super::ValueStack, blocks: &mut super::BlockStack, ) -> Option<()> { - crate::log::info!("1"); let break_to = blocks.get_relative_to(break_to_relative, self.block_ptr)?; - crate::log::info!("2"); // instr_ptr points to the label instruction, but the next step // will increment it by 1 since we're changing the "current" instr_ptr diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs index 4abce92..606e13a 100644 --- a/crates/tinywasm/src/runtime/stack/values.rs +++ b/crates/tinywasm/src/runtime/stack/values.rs @@ -195,6 +195,8 @@ impl From for TinyWasmValue { } } +// TODO: this can be made a bit more maintainable by using a macro + mod sealed { #[allow(unreachable_pub)] pub trait Sealed {} @@ -209,8 +211,6 @@ impl sealed::Sealed for u32 {} impl sealed::Sealed for Value128 {} impl sealed::Sealed for ValueRef {} -// TODO: this can be made a bit more maintainable by using a macro - pub(crate) trait InternalValue: sealed::Sealed { fn stack_push(stack: &mut ValueStack, value: Self); fn stack_pop(stack: &mut ValueStack) -> Result From 2eec08ba5b69593290e5536b0e732b044e4b8c0c Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 28 Jun 2024 01:07:48 +0200 Subject: [PATCH 10/10] docs: update changelog Signed-off-by: Henry Gressmann --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6539a1..da8359c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [UNRELEASED] + +### Changed + +- Improved support for WebAssembly 2.0 features +- Simplify and optimize the interpreter loop +- Use a seperate stack and locals for 32, 64 and 128 bit values and references (#21) +- Updated to latest wasmparser version + ## [0.7.0] - 2024-05-15 **All Commits**: https://github.com/explodingcamera/tinywasm/compare/v0.6.0...v0.7.0