From 1cca6de38052fd7fcbf39a5ba195eafb9a51c637 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 24 May 2024 15:44:20 +0200 Subject: chore: cleanup simd stack code Signed-off-by: Henry Gressmann --- crates/parser/Cargo.toml | 1 - crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/func.rs | 2 +- crates/tinywasm/src/lib.rs | 2 +- crates/tinywasm/src/runtime/interpreter/mod.rs | 4 +- crates/tinywasm/src/runtime/mod.rs | 14 ++- crates/tinywasm/src/runtime/raw.rs | 122 ++++++++++++++++++ crates/tinywasm/src/runtime/raw_simd.rs | 13 ++ crates/tinywasm/src/runtime/stack.rs | 32 ----- crates/tinywasm/src/runtime/stack/block_stack.rs | 6 +- crates/tinywasm/src/runtime/stack/call_stack.rs | 6 +- .../src/runtime/stack/large_value_stack.rs | 12 -- crates/tinywasm/src/runtime/stack/mod.rs | 24 ++++ crates/tinywasm/src/runtime/stack/value_stack.rs | 83 ++++++++----- crates/tinywasm/src/runtime/value.rs | 138 --------------------- crates/tinywasm/src/store/global.rs | 5 +- crates/tinywasm/tests/testsuite/run.rs | 2 +- crates/types/src/value.rs | 13 +- 18 files changed, 240 insertions(+), 241 deletions(-) create mode 100644 crates/tinywasm/src/runtime/raw.rs create mode 100644 crates/tinywasm/src/runtime/raw_simd.rs delete mode 100644 crates/tinywasm/src/runtime/stack.rs delete mode 100644 crates/tinywasm/src/runtime/stack/large_value_stack.rs create mode 100644 crates/tinywasm/src/runtime/stack/mod.rs delete mode 100644 crates/tinywasm/src/runtime/value.rs diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 6d48a24..03d7c9b 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -16,4 +16,3 @@ tinywasm-types={version="0.7.0", path="../types", default-features=false} default=["std", "logging"] logging=["log"] std=["tinywasm-types/std", "wasmparser/std"] -nightly=[] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index fb4a182..0dfde7b 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -33,7 +33,7 @@ logging=["_log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] parser=["tinywasm-parser"] archive=["tinywasm-types/archive"] -nightly=[] +simd=[] [[test]] name="test-mvp" diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 0f19651..e43b680 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,4 +1,4 @@ -use crate::runtime::{CallFrame, Stack, WasmValueRepr}; +use crate::runtime::{CallFrame, Stack}; use crate::{log, runtime::RawWasmValue, unlikely, Function}; use crate::{Error, FuncContext, Result, Store}; use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec}; diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 2e9fece..24cf56a 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -5,7 +5,7 @@ ))] #![allow(unexpected_cfgs, clippy::reserve_after_initialization)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] -#![cfg_attr(nightly, feature(error_in_core))] +#![cfg_attr(nightly, feature(error_in_core, portable_simd))] #![forbid(unsafe_code)] //! A tiny WebAssembly Runtime written in Rust diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index f9dc95c..c4fff7d 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -3,8 +3,9 @@ use alloc::string::ToString; use core::ops::{BitAnd, BitOr, BitXor, Neg}; use tinywasm_types::{BlockArgs, ElementKind, Instruction, ValType}; +use super::stack::{BlockFrame, BlockType}; use super::{InterpreterRuntime, RawWasmValue, Stack}; -use crate::runtime::{BlockFrame, BlockType, CallFrame}; +use crate::runtime::CallFrame; use crate::{cold, unlikely}; use crate::{Error, FuncContext, ModuleInstance, Result, Store, Trap}; @@ -724,7 +725,6 @@ impl<'store, 'stack> Executor<'store, 'stack> { instr_ptr, end_instr_offset, stack_ptr: self.stack.values.len() as u32 - params as u32, - large_stack_ptr: 0, results, params, ty, diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs index 72fa6d4..705b085 100644 --- a/crates/tinywasm/src/runtime/mod.rs +++ b/crates/tinywasm/src/runtime/mod.rs @@ -1,10 +1,16 @@ mod interpreter; mod stack; -mod value; + +mod raw; + +#[cfg(all(nightly, feature = "simd"))] +mod raw_simd; use crate::Result; -pub use stack::*; -pub use value::{LargeRawWasmValue, RawWasmValue, WasmValueRepr}; + +pub use raw::RawWasmValue; +pub(crate) use stack::CallFrame; +pub(crate) use stack::Stack; #[allow(rustdoc::private_intra_doc_links)] /// A WebAssembly runtime. @@ -12,7 +18,7 @@ pub use value::{LargeRawWasmValue, RawWasmValue, WasmValueRepr}; /// See pub trait Runtime { /// Execute all call-frames on the stack until the stack is empty. - fn exec(&self, store: &mut crate::Store, stack: &mut crate::runtime::Stack) -> Result<()>; + fn exec(&self, store: &mut crate::Store, stack: &mut Stack) -> Result<()>; } /// The main TinyWasm runtime. diff --git a/crates/tinywasm/src/runtime/raw.rs b/crates/tinywasm/src/runtime/raw.rs new file mode 100644 index 0000000..2f1dd68 --- /dev/null +++ b/crates/tinywasm/src/runtime/raw.rs @@ -0,0 +1,122 @@ +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([u8; 8]); + +impl Debug for RawWasmValue { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "RawWasmValue({})", 0) + } +} + +impl RawWasmValue { + #[inline(always)] + /// Get the raw value + pub fn raw_value(&self) -> [u8; 8] { + self.0 + } + + #[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(f32::from_bits(self.into())), + ValType::F64 => WasmValue::F64(f64::from_bits(self.into())), + ValType::V128 => panic!("RawWasmValue cannot be converted to V128"), + ValType::RefExtern => match i64::from(self) { + v if v < 0 => WasmValue::RefNull(ValType::RefExtern), + addr => WasmValue::RefExtern(addr as u32), + }, + ValType::RefFunc => match i64::from(self) { + v if v < 0 => WasmValue::RefNull(ValType::RefFunc), + addr => WasmValue::RefFunc(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!(i32, |x| x as u64, |x: [u8; 8]| i32::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!(u8, |x| x as u64, |x: [u8; 8]| u8::from_ne_bytes(x[0..1].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!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0..4].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!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].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 b/crates/tinywasm/src/runtime/raw_simd.rs new file mode 100644 index 0000000..46cb0c5 --- /dev/null +++ b/crates/tinywasm/src/runtime/raw_simd.rs @@ -0,0 +1,13 @@ +/// 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([u8; 16]); + +impl Debug for RawSimdWasmValue { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "LargeRawWasmValue({})", 0) + } +} diff --git a/crates/tinywasm/src/runtime/stack.rs b/crates/tinywasm/src/runtime/stack.rs deleted file mode 100644 index ebcc41f..0000000 --- a/crates/tinywasm/src/runtime/stack.rs +++ /dev/null @@ -1,32 +0,0 @@ -mod block_stack; -mod call_stack; -mod large_value_stack; -mod value_stack; - -pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; -pub(crate) use call_stack::{CallFrame, CallStack}; -pub(crate) use large_value_stack::LargeValueStack; -pub(crate) use value_stack::ValueStack; - -use super::RawWasmValue; - -/// A WebAssembly Stack -#[derive(Debug)] -pub struct Stack { - pub(crate) values: ValueStack, - pub(crate) large_values: LargeValueStack, - - pub(crate) blocks: BlockStack, - pub(crate) call_stack: CallStack, -} - -impl Stack { - pub(crate) fn new(call_frame: CallFrame) -> Self { - Self { - values: ValueStack::default(), - blocks: BlockStack::new(), - call_stack: CallStack::new(call_frame), - large_values: LargeValueStack::default(), - } - } -} diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index 425f584..6c3a844 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -55,8 +55,10 @@ 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) large_stack_ptr: u32, // position of the large stack pointer when the block was entered + pub(crate) stack_ptr: u32, // position of the stack pointer when the block was entered + + #[cfg(all(nightly, feature = "simd"))] + pub(crate) simd_stack_ptr: u32, // position of the large stack pointer when the block was entered pub(crate) results: u8, pub(crate) params: u8, diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 430e1c4..316e3ed 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,9 +1,11 @@ -use crate::runtime::{BlockType, RawWasmValue}; +use crate::runtime::RawWasmValue; use crate::{cold, unlikely}; use crate::{Error, Result, Trap}; use alloc::{boxed::Box, rc::Rc, vec::Vec}; use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction}; +use super::BlockType; + const CALL_STACK_SIZE: usize = 1024; #[derive(Debug)] @@ -72,7 +74,7 @@ impl CallFrame { pub(crate) fn break_to( &mut self, break_to_relative: u32, - values: &mut super::ValueStack, + values: &mut super::ValueStack, blocks: &mut super::BlockStack, ) -> Option<()> { let break_to = blocks.get_relative_to(break_to_relative, self.block_ptr)?; diff --git a/crates/tinywasm/src/runtime/stack/large_value_stack.rs b/crates/tinywasm/src/runtime/stack/large_value_stack.rs deleted file mode 100644 index 97b7ce5..0000000 --- a/crates/tinywasm/src/runtime/stack/large_value_stack.rs +++ /dev/null @@ -1,12 +0,0 @@ -use alloc::vec::Vec; - -use crate::runtime::LargeRawWasmValue; - -#[derive(Debug)] -pub(crate) struct LargeValueStack(Vec); - -impl Default for LargeValueStack { - fn default() -> Self { - Self(Vec::new()) - } -} diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/runtime/stack/mod.rs new file mode 100644 index 0000000..3ef5348 --- /dev/null +++ b/crates/tinywasm/src/runtime/stack/mod.rs @@ -0,0 +1,24 @@ +mod block_stack; +mod call_stack; +mod value_stack; + +#[cfg(nightly)] +mod simd_value_stack; + +pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; +pub(crate) use call_stack::{CallFrame, CallStack}; +pub(crate) use value_stack::ValueStack; + +/// A WebAssembly Stack +#[derive(Debug)] +pub struct Stack { + pub(crate) values: ValueStack, + pub(crate) blocks: BlockStack, + pub(crate) call_stack: CallStack, +} + +impl Stack { + pub(crate) fn new(call_frame: CallFrame) -> Self { + Self { values: ValueStack::default(), blocks: BlockStack::new(), 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 993715c..811cdd0 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -1,33 +1,46 @@ -use crate::{cold, runtime::WasmValueRepr, unlikely, Error, Result}; +use crate::{cold, runtime::RawWasmValue, unlikely, Error, Result}; use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024 * 128; +#[cfg(all(nightly, feature = "simd"))] +pub(crate) const MIN_SIMD_VALUE_STACK_SIZE: usize = 1024 * 32; + #[derive(Debug)] -pub(crate) struct ValueStack(Vec); +pub(crate) struct ValueStack { + stack: Vec, + + #[cfg(all(nightly, feature = "simd"))] + simd_stack: Vec, +} -impl Default for ValueStack { +impl Default for ValueStack { fn default() -> Self { - Self(Vec::with_capacity(MIN_VALUE_STACK_SIZE)) + Self { + stack: Vec::with_capacity(MIN_VALUE_STACK_SIZE), + + #[cfg(all(nightly, feature = "simd"))] + simd_stack: Vec::with_capacity(MIN_SIMD_VALUE_STACK_SIZE), + } } } -impl + Copy + WasmValueRepr> ValueStack { +impl ValueStack { #[inline] pub(crate) fn extend_from_typed(&mut self, values: &[WasmValue]) { - self.0.extend(values.iter().map(|v| T::from(*v))); + self.stack.extend(values.iter().map(|v| RawWasmValue::from(*v))); } #[inline(always)] - pub(crate) fn replace_top(&mut self, func: fn(T) -> T) -> Result<()> { + 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 calculate(&mut self, func: fn(T, T) -> T) -> Result<()> { + 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); @@ -35,7 +48,10 @@ impl + Copy + WasmValueRepr> ValueStack { } #[inline(always)] - pub(crate) fn calculate_trap(&mut self, func: fn(T, T) -> Result) -> Result<()> { + 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)?; @@ -44,14 +60,14 @@ impl + Copy + WasmValueRepr> ValueStack { #[inline(always)] pub(crate) fn len(&self) -> usize { - self.0.len() + self.stack.len() } #[inline] pub(crate) fn truncate_keep(&mut self, n: u32, end_keep: u32) { let total_to_keep = n + end_keep; - let len = self.0.len() as u32; - assert!(len >= total_to_keep, "Total to keep should be less than or equal to self.top"); + let len = self.stack.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 @@ -60,22 +76,22 @@ impl + Copy + WasmValueRepr> ValueStack { 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; - self.0.drain(remove_start_index..remove_end_index); + self.stack.drain(remove_start_index..remove_end_index); } #[inline(always)] - pub(crate) fn push(&mut self, value: T) { - self.0.push(value); + pub(crate) fn push(&mut self, value: RawWasmValue) { + self.stack.push(value); } #[inline(always)] - pub(crate) fn extend_from_slice(&mut self, values: &[T]) { - self.0.extend_from_slice(values); + 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 T> { - match self.0.last_mut() { + pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { + match self.stack.last_mut() { Some(v) => Ok(v), None => { cold(); @@ -85,8 +101,8 @@ impl + Copy + WasmValueRepr> ValueStack { } #[inline] - pub(crate) fn last(&self) -> Result<&T> { - match self.0.last() { + pub(crate) fn last(&self) -> Result<&RawWasmValue> { + match self.stack.last() { Some(v) => Ok(v), None => { cold(); @@ -96,8 +112,8 @@ impl + Copy + WasmValueRepr> ValueStack { } #[inline(always)] - pub(crate) fn pop(&mut self) -> Result { - match self.0.pop() { + pub(crate) fn pop(&mut self) -> Result { + match self.stack.pop() { Some(v) => Ok(v), None => { cold(); @@ -114,36 +130,35 @@ impl + Copy + WasmValueRepr> ValueStack { #[inline] pub(crate) fn break_to(&mut self, new_stack_size: u32, result_count: u8) { let start = new_stack_size as usize; - let end = self.0.len() - result_count as usize; - self.0.drain(start..end); + let end = self.stack.len() - result_count as usize; + self.stack.drain(start..end); } #[inline] - pub(crate) fn last_n(&self, n: usize) -> Result<&[T]> { - let len = self.0.len(); + 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.0[len - n..len]) + Ok(&self.stack[len - n..len]) } #[inline] - pub(crate) fn pop_n_rev(&mut self, n: usize) -> Result> { - if unlikely(self.0.len() < n) { + pub(crate) fn pop_n_rev(&mut self, n: usize) -> Result> { + if unlikely(self.stack.len() < n) { return Err(Error::ValueStackUnderflow); } - Ok(self.0.drain((self.0.len() - n)..)) + Ok(self.stack.drain((self.stack.len() - n)..)) } } #[cfg(test)] mod tests { use super::*; - use crate::runtime::RawWasmValue; #[test] fn test_value_stack() { - let mut stack: ValueStack = ValueStack::default(); + let mut stack = ValueStack::default(); stack.push(1.into()); stack.push(2.into()); stack.push(3.into()); @@ -161,7 +176,7 @@ mod tests { macro_rules! test_macro { ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { $( - let mut stack: ValueStack = ValueStack::default(); + let mut stack = ValueStack::default(); stack.push(1.into()); stack.push(2.into()); stack.push(3.into()); diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs deleted file mode 100644 index 832371e..0000000 --- a/crates/tinywasm/src/runtime/value.rs +++ /dev/null @@ -1,138 +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([u8; 8]); - -/// 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 LargeRawWasmValue([u8; 16]); - -impl Debug for RawWasmValue { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "RawWasmValue({})", 0) - } -} - -impl Debug for LargeRawWasmValue { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "LargeRawWasmValue({})", 0) - } -} - -pub trait WasmValueRepr { - fn attach_type(self, ty: ValType) -> WasmValue; -} - -impl WasmValueRepr for RawWasmValue { - #[inline] - 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(f32::from_bits(self.into())), - ValType::F64 => WasmValue::F64(f64::from_bits(self.into())), - ValType::RefExtern => match i64::from(self) { - v if v < 0 => WasmValue::RefNull(ValType::RefExtern), - addr => WasmValue::RefExtern(addr as u32), - }, - ValType::RefFunc => match i64::from(self) { - v if v < 0 => WasmValue::RefNull(ValType::RefFunc), - addr => WasmValue::RefFunc(addr as u32), - }, - } - } -} - -impl RawWasmValue { - #[inline(always)] - pub fn raw_value(&self) -> [u8; 8] { - self.0 - } -} - -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::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!(i32, |x| x as u64, |x: [u8; 8]| i32::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!(u8, |x| x as u64, |x: [u8; 8]| u8::from_ne_bytes(x[0..1].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!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0..4].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!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].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/store/global.rs b/crates/tinywasm/src/store/global.rs index e4a1817..6cc778c 100644 --- a/crates/tinywasm/src/store/global.rs +++ b/crates/tinywasm/src/store/global.rs @@ -3,10 +3,7 @@ use core::cell::Cell; use alloc::{format, string::ToString}; use tinywasm_types::*; -use crate::{ - runtime::{RawWasmValue, WasmValueRepr}, - unlikely, Error, Result, -}; +use crate::{runtime::RawWasmValue, unlikely, Error, Result}; /// A WebAssembly Global Instance /// diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index beb20a8..1de633f 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -6,7 +6,7 @@ use super::TestSuite; use _log as log; use eyre::{eyre, Result}; use log::{debug, error, info}; -use tinywasm::{runtime::WasmValueRepr, Extern, Imports, ModuleInstance}; +use tinywasm::{Extern, Imports, ModuleInstance}; use tinywasm_types::{ExternVal, MemoryType, ModuleInstanceAddr, TableType, ValType, WasmValue}; use wast::{lexer::Lexer, parser::ParseBuffer, Wast}; diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 28ca6e2..0f127a8 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -17,7 +17,7 @@ pub enum WasmValue { /// A 64-bit float. F64(f64), // /// A 128-bit vector - // V128(u128), + V128(u128), RefExtern(ExternAddr), RefFunc(FuncAddr), RefNull(ValType), @@ -31,7 +31,6 @@ impl WasmValue { Self::I64(i) => ConstInstruction::I64Const(*i), Self::F32(i) => ConstInstruction::F32Const(*i), Self::F64(i) => ConstInstruction::F64Const(*i), - Self::RefFunc(i) => ConstInstruction::RefFunc(*i), Self::RefNull(ty) => ConstInstruction::RefNull(*ty), @@ -48,7 +47,7 @@ impl WasmValue { ValType::I64 => Self::I64(0), ValType::F32 => Self::F32(0.0), ValType::F64 => Self::F64(0.0), - // ValType::V128 => Self::V128(0), + ValType::V128 => Self::V128(0), ValType::RefFunc => Self::RefNull(ValType::RefFunc), ValType::RefExtern => Self::RefNull(ValType::RefExtern), } @@ -91,7 +90,7 @@ impl Debug for WasmValue { WasmValue::I64(i) => write!(f, "i64({})", i), WasmValue::F32(i) => write!(f, "f32({})", i), WasmValue::F64(i) => write!(f, "f64({})", i), - // WasmValue::V128(i) => write!(f, "v128.half({:?})", i), + WasmValue::V128(i) => write!(f, "v128({:?})", i), WasmValue::RefExtern(addr) => write!(f, "ref.extern({:?})", addr), WasmValue::RefFunc(addr) => write!(f, "ref.func({:?})", addr), WasmValue::RefNull(ty) => write!(f, "ref.null({:?})", ty), @@ -108,7 +107,7 @@ impl WasmValue { Self::I64(_) => ValType::I64, Self::F32(_) => ValType::F32, Self::F64(_) => ValType::F64, - // Self::V128(_) => ValType::V128, + Self::V128(_) => ValType::V128, Self::RefExtern(_) => ValType::RefExtern, Self::RefFunc(_) => ValType::RefFunc, Self::RefNull(ty) => *ty, @@ -129,7 +128,7 @@ pub enum ValType { /// A 64-bit float. F64, /// A 128-bit vector - // V128, + V128, /// A reference to a function. RefFunc, /// A reference to an external value. @@ -148,6 +147,7 @@ impl ValType { ValType::I64 => 0x7E, ValType::F32 => 0x7D, ValType::F64 => 0x7C, + ValType::V128 => 0x7B, ValType::RefFunc => 0x70, ValType::RefExtern => 0x6F, } @@ -159,6 +159,7 @@ impl ValType { 0x7E => Some(ValType::I64), 0x7D => Some(ValType::F32), 0x7C => Some(ValType::F64), + 0x7B => Some(ValType::V128), 0x70 => Some(ValType::RefFunc), 0x6F => Some(ValType::RefExtern), _ => None, -- cgit v1.3.1