summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-06-28 23:19:05 +0200
committerHenry Gressmann <mail@henrygressmann.de>2024-06-28 23:19:05 +0200
commit7e8770cc4e418ef1a8cdfd9b1f59ee14b07cc6c9 (patch)
tree7865a95f3a5b6d32b5b26aa42ec3ed730def3d95 /crates
parentabec4b6cec6ced6c0500348ac5990486a4fe8287 (diff)
chore: restructure runtime
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/conversion.rs8
-rw-r--r--crates/parser/src/visit.rs74
-rw-r--r--crates/tinywasm/Cargo.toml10
-rw-r--r--crates/tinywasm/src/func.rs4
-rw-r--r--crates/tinywasm/src/imports.rs6
-rw-r--r--crates/tinywasm/src/instance.rs38
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs (renamed from crates/tinywasm/src/runtime/interpreter/mod.rs)83
-rw-r--r--crates/tinywasm/src/interpreter/mod.rs (renamed from crates/tinywasm/src/runtime/mod.rs)11
-rw-r--r--crates/tinywasm/src/interpreter/no_std_floats.rs (renamed from crates/tinywasm/src/runtime/interpreter/no_std_floats.rs)0
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs (renamed from crates/tinywasm/src/runtime/interpreter/num_helpers.rs)2
-rw-r--r--crates/tinywasm/src/interpreter/stack/block_stack.rs (renamed from crates/tinywasm/src/runtime/stack/block_stack.rs)0
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs (renamed from crates/tinywasm/src/runtime/stack/call_stack.rs)0
-rw-r--r--crates/tinywasm/src/interpreter/stack/mod.rs (renamed from crates/tinywasm/src/runtime/stack/mod.rs)0
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs (renamed from crates/tinywasm/src/runtime/stack/value_stack.rs)56
-rw-r--r--crates/tinywasm/src/interpreter/stack/values.rs200
-rw-r--r--crates/tinywasm/src/lib.rs4
-rw-r--r--crates/tinywasm/src/module.rs11
-rw-r--r--crates/tinywasm/src/reference.rs49
-rw-r--r--crates/tinywasm/src/runtime/stack/values.rs420
-rw-r--r--crates/tinywasm/src/store/element.rs2
-rw-r--r--crates/tinywasm/src/store/function.rs4
-rw-r--r--crates/tinywasm/src/store/global.rs56
-rw-r--r--crates/tinywasm/src/store/mod.rs6
-rw-r--r--crates/types/src/archive.rs6
-rw-r--r--crates/types/src/instructions.rs101
-rw-r--r--crates/types/src/lib.rs4
-rw-r--r--crates/types/src/value.rs32
27 files changed, 395 insertions, 792 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
index 1d550f3..214487f 100644
--- a/crates/parser/src/conversion.rs
+++ b/crates/parser/src/conversion.rs
@@ -225,14 +225,6 @@ pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result<FuncType>
Ok(FuncType { params, results })
}
-pub(crate) fn convert_blocktype(blocktype: wasmparser::BlockType) -> BlockArgs {
- match blocktype {
- wasmparser::BlockType::Empty => BlockArgs::Empty,
- wasmparser::BlockType::Type(ty) => BlockArgs::Type(convert_valtype(&ty)),
- wasmparser::BlockType::FuncType(ty) => BlockArgs::FuncType(ty),
- }
-}
-
pub(crate) fn convert_reftype(reftype: &wasmparser::RefType) -> ValType {
match reftype {
_ if reftype.is_func_ref() => ValType::RefFunc,
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 1db00ad..e9844aa 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -1,6 +1,6 @@
-use crate::{conversion::convert_blocktype, Result};
+use crate::Result;
-use crate::conversion::convert_heaptype;
+use crate::conversion::{convert_heaptype, convert_valtype};
use alloc::string::ToString;
use alloc::{boxed::Box, vec::Vec};
use tinywasm_types::{Instruction, MemoryArg};
@@ -357,7 +357,13 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
- let resolved_idx = self.local_addr_map[idx as usize];
+ let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else {
+ self.errors.push(crate::ParseError::UnsupportedOperator(
+ "Local index is too large, tinywasm does not support local indexes that large".to_string(),
+ ));
+ return;
+ };
+
match self.validator.get_local_type(idx) {
Some(t) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::LocalGet32(resolved_idx),
@@ -372,7 +378,13 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
fn visit_local_set(&mut self, idx: u32) -> Self::Output {
- let resolved_idx = self.local_addr_map[idx as usize];
+ let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else {
+ self.errors.push(crate::ParseError::UnsupportedOperator(
+ "Local index is too large, tinywasm does not support local indexes that large".to_string(),
+ ));
+ return;
+ };
+
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::LocalSet32(resolved_idx),
@@ -387,7 +399,13 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
fn visit_local_tee(&mut self, idx: u32) -> Self::Output {
- let resolved_idx = self.local_addr_map[idx as usize];
+ let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else {
+ self.errors.push(crate::ParseError::UnsupportedOperator(
+ "Local index is too large, tinywasm does not support local indexes that large".to_string(),
+ ));
+ return;
+ };
+
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::LocalTee32(resolved_idx),
@@ -411,17 +429,29 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output {
self.label_ptrs.push(self.instructions.len());
- self.instructions.push(Instruction::Block(convert_blocktype(blockty), 0))
+ self.instructions.push(match blockty {
+ wasmparser::BlockType::Empty => Instruction::Block(0),
+ wasmparser::BlockType::FuncType(idx) => Instruction::BlockWithFuncType(idx, 0),
+ wasmparser::BlockType::Type(ty) => Instruction::BlockWithType(convert_valtype(&ty), 0),
+ })
}
fn visit_loop(&mut self, ty: wasmparser::BlockType) -> Self::Output {
self.label_ptrs.push(self.instructions.len());
- self.instructions.push(Instruction::Loop(convert_blocktype(ty), 0))
+ self.instructions.push(match ty {
+ wasmparser::BlockType::Empty => Instruction::Loop(0),
+ wasmparser::BlockType::FuncType(idx) => Instruction::LoopWithFuncType(idx, 0),
+ wasmparser::BlockType::Type(ty) => Instruction::LoopWithType(convert_valtype(&ty), 0),
+ })
}
fn visit_if(&mut self, ty: wasmparser::BlockType) -> Self::Output {
self.label_ptrs.push(self.instructions.len());
- self.instructions.push(Instruction::If(convert_blocktype(ty).into(), 0, 0))
+ self.instructions.push(match ty {
+ wasmparser::BlockType::Empty => Instruction::If(0, 0),
+ wasmparser::BlockType::FuncType(idx) => Instruction::IfWithFuncType(idx, 0, 0),
+ wasmparser::BlockType::Type(ty) => Instruction::IfWithType(convert_valtype(&ty), 0, 0),
+ })
}
fn visit_else(&mut self) -> Self::Output {
@@ -451,12 +481,18 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
};
let if_instruction = &mut self.instructions[if_label_pointer];
- let Instruction::If(_, else_offset, end_offset) = if_instruction else {
- self.errors.push(crate::ParseError::UnsupportedOperator(
- "Expected to end an if block, but the last label was not an if".to_string(),
- ));
- return;
+ let (else_offset, end_offset) = match if_instruction {
+ Instruction::If(else_offset, end_offset)
+ | Instruction::IfWithFuncType(_, else_offset, end_offset)
+ | Instruction::IfWithType(_, else_offset, end_offset) => (else_offset, end_offset),
+ _ => {
+ self.errors.push(crate::ParseError::UnsupportedOperator(
+ "Expected to end an if block, but the last label was not an if".to_string(),
+ ));
+
+ return;
+ }
};
*else_offset = (label_pointer - if_label_pointer)
@@ -467,9 +503,15 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
.try_into()
.expect("else_instr_end_offset is too large, tinywasm does not support blocks that large");
}
- Some(Instruction::Block(_, end_offset))
- | Some(Instruction::Loop(_, end_offset))
- | Some(Instruction::If(_, _, end_offset)) => {
+ Some(Instruction::Block(end_offset))
+ | Some(Instruction::BlockWithType(_, end_offset))
+ | Some(Instruction::BlockWithFuncType(_, end_offset))
+ | Some(Instruction::Loop(end_offset))
+ | Some(Instruction::LoopWithFuncType(_, end_offset))
+ | Some(Instruction::LoopWithType(_, end_offset))
+ | Some(Instruction::If(_, end_offset))
+ | Some(Instruction::IfWithFuncType(_, _, end_offset))
+ | Some(Instruction::IfWithType(_, _, end_offset)) => {
*end_offset = (current_instr_ptr - label_pointer)
.try_into()
.expect("else_instr_end_offset is too large, tinywasm does not support blocks that large");
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index d82d850..4e15123 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -19,16 +19,6 @@ 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="212.0"}
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 650f9df..3b97d93 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -1,4 +1,4 @@
-use crate::runtime::{CallFrame, Stack};
+use crate::interpreter::{CallFrame, Stack};
use crate::{log, unlikely, Function};
use crate::{Error, FuncContext, Result, Store};
use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec};
@@ -59,7 +59,7 @@ impl FuncHandle {
};
// 6. Let f be the dummy frame
- let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, 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)
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index f24ed73..8c208f0 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -348,7 +348,7 @@ impl Imports {
) -> Result<ResolvedImports> {
let mut imports = ResolvedImports::new();
- for import in module.data.imports.iter() {
+ for import in module.0.imports.iter() {
let val = self.take(store, import).ok_or_else(|| LinkingError::unknown_import(import))?;
match val {
@@ -368,7 +368,7 @@ impl Imports {
}
(Extern::Function(extern_func), ImportKind::Function(ty)) => {
let import_func_type = module
- .data
+ .0
.func_types
.get(*ty as usize)
.ok_or_else(|| LinkingError::incompatible_import_type(import))?;
@@ -409,7 +409,7 @@ impl Imports {
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
let func = store.get_func(func_addr)?;
let import_func_type = module
- .data
+ .0
.func_types
.get(*ty as usize)
.ok_or_else(|| LinkingError::incompatible_import_type(import))?;
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 4ad3d09..7250cf0 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -64,45 +64,39 @@ impl ModuleInstance {
let idx = store.next_module_instance_idx();
let mut addrs = imports.unwrap_or_default().link(store, &module, idx)?;
- let data = module.data;
- addrs.funcs.extend(store.init_funcs(data.funcs.into(), idx)?);
- addrs.tables.extend(store.init_tables(data.table_types.into(), idx)?);
- addrs.memories.extend(store.init_memories(data.memory_types.into(), idx)?);
+ addrs.funcs.extend(store.init_funcs(module.0.funcs.into(), idx)?);
+ addrs.tables.extend(store.init_tables(module.0.table_types.into(), idx)?);
+ addrs.memories.extend(store.init_memories(module.0.memory_types.into(), idx)?);
- let global_addrs = store.init_globals(addrs.globals, data.globals.into(), &addrs.funcs, idx)?;
+ let global_addrs = store.init_globals(addrs.globals, module.0.globals.into(), &addrs.funcs, idx)?;
let (elem_addrs, elem_trapped) =
- store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &data.elements, idx)?;
- let (data_addrs, data_trapped) = store.init_datas(&addrs.memories, data.data.into(), idx)?;
+ store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.0.elements, idx)?;
+ let (data_addrs, data_trapped) = store.init_datas(&addrs.memories, module.0.data.into(), idx)?;
let instance = ModuleInstanceInner {
failed_to_instantiate: elem_trapped.is_some() || data_trapped.is_some(),
store_id: store.id(),
idx,
- types: data.func_types,
+ types: module.0.func_types,
func_addrs: addrs.funcs.into_boxed_slice(),
table_addrs: addrs.tables.into_boxed_slice(),
mem_addrs: addrs.memories.into_boxed_slice(),
global_addrs: global_addrs.into_boxed_slice(),
elem_addrs,
data_addrs,
- func_start: data.start_func,
- imports: data.imports,
- exports: data.exports,
+ func_start: module.0.start_func,
+ imports: module.0.imports,
+ exports: module.0.exports,
};
let instance = ModuleInstance::new(instance);
store.add_instance(instance.clone());
- if let Some(trap) = elem_trapped {
- return Err(trap.into());
- };
-
- if let Some(trap) = data_trapped {
- return Err(trap.into());
- };
-
- Ok(instance)
+ match (elem_trapped, data_trapped) {
+ (Some(trap), _) | (_, Some(trap)) => Err(trap.into()),
+ _ => Ok(instance),
+ }
}
/// Get a export by name
@@ -224,13 +218,13 @@ impl ModuleInstance {
/// Get a memory by address
pub fn memory<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRef<'a>> {
let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
- Ok(MemoryRef { instance: mem.borrow() })
+ Ok(MemoryRef(mem.borrow()))
}
/// Get a memory by address (mutable)
pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRefMut<'a>> {
let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
- Ok(MemoryRefMut { instance: mem.borrow_mut() })
+ Ok(MemoryRefMut(mem.borrow_mut()))
}
/// Get the start function of the module
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/interpreter/executor.rs
index 8028e87..386099d 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -1,34 +1,25 @@
-mod num_helpers;
-
#[cfg(not(feature = "std"))]
mod no_std_floats;
+use interpreter::CallFrame;
#[cfg(not(feature = "std"))]
#[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 super::num_helpers::*;
+use super::stack::{values::StackHeight, BlockFrame, BlockType, Stack};
+use super::values::*;
use crate::*;
-impl InterpreterRuntime {
- pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> {
- Executor::new(store, stack)?.run_to_completion()
- }
-}
-
-struct Executor<'store, 'stack> {
- store: &'store mut Store,
- stack: &'stack mut Stack,
-
+pub(super) struct Executor<'store, 'stack> {
cf: CallFrame,
module: ModuleInstance,
+ store: &'store mut Store,
+ stack: &'stack mut Stack,
}
impl<'store, 'stack> Executor<'store, 'stack> {
@@ -68,10 +59,28 @@ impl<'store, 'stack> Executor<'store, 'stack> {
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)?,
+ If(end, el) => self.exec_if(*end, *el, (Default::default(), Default::default()))?,
+ IfWithType(ty, end, el) => self.exec_if(*end, *el, (Default::default(), (*ty).into()))?,
+ IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty))?,
Else(end_offset) => self.exec_else(*end_offset)?,
- Loop(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, *args),
- Block(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, *args),
+ Loop(end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, (Default::default(), Default::default()))
+ }
+ LoopWithType(ty, end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, (Default::default(), (*ty).into()))
+ }
+ LoopWithFuncType(ty, end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, self.resolve_functype(*ty))
+ }
+ Block(end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, (Default::default(), Default::default()))
+ }
+ BlockWithType(ty, end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, (Default::default(), (*ty).into()))
+ }
+ BlockWithFuncType(ty, end) => {
+ self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, self.resolve_functype(*ty))
+ }
Br(v) => return self.exec_br(*v),
BrIf(v) => return self.exec_br_if(*v),
BrTable(default, len) => return self.exec_brtable(*default, *len),
@@ -429,7 +438,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
};
- self.exec_call(wasm_func.clone(), func_inst.owner)
+ self.exec_call(wasm_func.clone(), func_inst._owner)
}
fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ControlFlow<()>> {
// verify that the table is of the right type, this should be validated by the parser already
@@ -467,17 +476,22 @@ impl<'store, 'stack> Executor<'store, 'stack> {
};
if wasm_func.ty == *call_ty {
- return self.exec_call(wasm_func.clone(), func_inst.owner);
+ return self.exec_call(wasm_func.clone(), func_inst._owner);
}
cold();
Err(Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into())
}
- fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> {
+ fn exec_if(
+ &mut self,
+ else_offset: u32,
+ end_offset: u32,
+ (params, results): (StackHeight, StackHeight),
+ ) -> Result<()> {
// truthy value is on the top of the stack, so enter the then block
if self.stack.values.pop::<i32>()? != 0 {
- self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, args);
+ self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, (params, results));
return Ok(());
}
@@ -489,7 +503,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let old = self.cf.instr_ptr();
*self.cf.instr_ptr_mut() += else_offset as usize;
- self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, args);
+ self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, (params, results));
Ok(())
}
fn exec_else(&mut self, end_offset: u32) -> Result<()> {
@@ -497,16 +511,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
*self.cf.instr_ptr_mut() += end_offset as usize;
Ok(())
}
- fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) {
- 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())
- }
- };
-
+ fn resolve_functype(&self, idx: u32) -> (StackHeight, StackHeight) {
+ let ty = self.module.func_ty(idx);
+ ((&*ty.params).into(), (&*ty.results).into())
+ }
+ fn enter_block(
+ &mut self,
+ instr_ptr: usize,
+ end_instr_offset: u32,
+ ty: BlockType,
+ (params, results): (StackHeight, StackHeight),
+ ) {
self.stack.blocks.push(BlockFrame {
instr_ptr,
end_instr_offset,
diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/interpreter/mod.rs
index fca58cc..f9096f8 100644
--- a/crates/tinywasm/src/runtime/mod.rs
+++ b/crates/tinywasm/src/interpreter/mod.rs
@@ -1,4 +1,5 @@
-mod interpreter;
+mod executor;
+mod num_helpers;
pub(crate) mod stack;
#[doc(hidden)]
@@ -7,8 +8,16 @@ pub use stack::values::*;
pub(crate) use stack::{CallFrame, Stack};
+use crate::{Result, Store};
+
/// The main TinyWasm runtime.
///
/// This is the default runtime used by TinyWasm.
#[derive(Debug, Default)]
pub struct InterpreterRuntime {}
+
+impl InterpreterRuntime {
+ pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> {
+ executor::Executor::new(store, stack)?.run_to_completion()
+ }
+}
diff --git a/crates/tinywasm/src/runtime/interpreter/no_std_floats.rs b/crates/tinywasm/src/interpreter/no_std_floats.rs
index 5b9471e..5b9471e 100644
--- a/crates/tinywasm/src/runtime/interpreter/no_std_floats.rs
+++ b/crates/tinywasm/src/interpreter/no_std_floats.rs
diff --git a/crates/tinywasm/src/runtime/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index d0402bc..88a5e9e 100644
--- a/crates/tinywasm/src/runtime/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -11,7 +11,7 @@ where
/// 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]
+#[rustfmt::skip]
macro_rules! float_min_max {
(f32, i32) => {(-2147483904.0_f32, 2147483648.0_f32)};
(f64, i32) => {(-2147483649.0_f64, 2147483648.0_f64)};
diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/interpreter/stack/block_stack.rs
index cef536a..cef536a 100644
--- a/crates/tinywasm/src/runtime/stack/block_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/block_stack.rs
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index 8e9dbe7..8e9dbe7 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/interpreter/stack/mod.rs
index 3902bd2..3902bd2 100644
--- a/crates/tinywasm/src/runtime/stack/mod.rs
+++ b/crates/tinywasm/src/interpreter/stack/mod.rs
diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 40376f1..fc23b48 100644
--- a/crates/tinywasm/src/runtime/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -106,10 +106,19 @@ impl ValueStack {
}
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);
+ #[inline(always)]
+ fn truncate_keep<T: Copy + Default>(data: &mut Vec<T>, n: u32, end_keep: u32) {
+ let len = data.len() as u32;
+ if len <= n {
+ return; // No need to truncate if the current size is already less than or equal to total_to_keep
+ }
+ data.drain((n as usize)..(len - end_keep) as usize);
+ }
+
+ truncate_keep(&mut self.stack_32, to.s32, keep.s32 as u32);
+ truncate_keep(&mut self.stack_64, to.s64, keep.s64 as u32);
+ truncate_keep(&mut self.stack_128, to.s128, keep.s128 as u32);
+ truncate_keep(&mut self.stack_ref, to.sref, keep.sref as u32);
}
pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) {
@@ -145,42 +154,3 @@ impl ValueStack {
}
}
}
-
-fn truncate_keep<T: Copy + Default>(data: &mut Vec<T>, n: u32, end_keep: u32) {
- let total_to_keep = n + end_keep;
- let len = data.len() as u32;
- crate::log::error!("truncate_keep: len: {}, total_to_keep: {}, end_keep: {}", len, total_to_keep, end_keep);
-
- if len <= n {
- return; // No need to truncate if the current size is already less than or equal to total_to_keep
- }
-
- data.drain((n as usize)..(len - end_keep) as usize);
-}
-
-#[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/src/interpreter/stack/values.rs b/crates/tinywasm/src/interpreter/stack/values.rs
new file mode 100644
index 0000000..6e8274f
--- /dev/null
+++ b/crates/tinywasm/src/interpreter/stack/values.rs
@@ -0,0 +1,200 @@
+#![allow(missing_docs)]
+use super::{call_stack::Locals, ValueStack};
+use crate::{Error, Result};
+use tinywasm_types::{LocalAddr, ValType, WasmValue};
+
+pub(crate) type Value32 = u32;
+pub(crate) type Value64 = u64;
+pub(crate) type Value128 = u128;
+pub(crate) type ValueRef = Option<u32>;
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+/// A untyped WebAssembly value
+pub enum TinyWasmValue {
+ Value32(Value32),
+ Value64(Value64),
+ Value128(Value128),
+ ValueRef(ValueRef),
+}
+
+#[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: u16,
+ pub(crate) s64: u16,
+ pub(crate) s128: u16,
+ pub(crate) sref: u16,
+}
+
+impl From<ValType> 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 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 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<WasmValue> for TinyWasmValue {
+ fn from(value: WasmValue) -> Self {
+ TinyWasmValue::from(&value)
+ }
+}
+
+mod sealed {
+ #[allow(unreachable_pub)]
+ pub trait Sealed {}
+}
+
+pub(crate) trait InternalValue: sealed::Sealed {
+ fn stack_push(stack: &mut ValueStack, value: Self);
+ fn stack_pop(stack: &mut ValueStack) -> Result<Self>
+ where
+ Self: Sized;
+ fn stack_peek(stack: &ValueStack) -> Result<Self>
+ where
+ Self: Sized;
+ fn local_get(locals: &Locals, index: LocalAddr) -> Result<Self>
+ where
+ Self: Sized;
+ fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) -> Result<()>;
+}
+
+macro_rules! impl_internalvalue {
+ ($( $variant:ident, $stack:ident, $locals:ident, $internal:ty, $outer:ty, $to_internal:expr, $to_outer:expr )*) => {
+ $(
+ impl sealed::Sealed for $outer {}
+
+ impl From<$outer> for TinyWasmValue {
+ fn from(value: $outer) -> Self {
+ TinyWasmValue::$variant($to_internal(value))
+ }
+ }
+
+ impl InternalValue for $outer {
+ #[inline]
+ fn stack_push(stack: &mut ValueStack, value: Self) {
+ stack.$stack.push($to_internal(value));
+ }
+ #[inline]
+ fn stack_pop(stack: &mut ValueStack) -> Result<Self> {
+ stack.$stack.pop().ok_or(Error::ValueStackUnderflow).map($to_outer)
+ }
+ #[inline]
+ fn stack_peek(stack: &ValueStack) -> Result<Self> {
+ stack.$stack.last().copied().ok_or(Error::ValueStackUnderflow).map($to_outer)
+ }
+ #[inline]
+ fn local_get(locals: &Locals, index: LocalAddr) -> Result<Self> {
+ Ok($to_outer(locals.$locals[index as usize]))
+ }
+ #[inline]
+ fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) -> Result<()> {
+ locals.$locals[index as usize] = $to_internal(value);
+ Ok(())
+ }
+ }
+ )*
+ };
+}
+
+impl_internalvalue! {
+ Value32, stack_32, locals_32, u32, u32, |v| v, |v| v
+ Value64, stack_64, locals_64, u64, u64, |v| v, |v| v
+ Value32, stack_32, locals_32, u32, i32, |v| v as u32, |v: u32| v as i32
+ Value64, stack_64, locals_64, u64, i64, |v| v as u64, |v| v as i64
+ Value32, stack_32, locals_32, u32, f32, f32::to_bits, f32::from_bits
+ Value64, stack_64, locals_64, u64, f64, f64::to_bits, f64::from_bits
+ Value128, stack_128, locals_128, Value128, Value128, |v| v, |v| v
+ ValueRef, stack_ref, locals_ref, ValueRef, ValueRef, |v| v, |v| v
+}
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index 9c48ee0..c1c2549 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -108,8 +108,8 @@ mod reference;
mod store;
/// Runtime for executing WebAssembly modules.
-pub mod runtime;
-pub use runtime::InterpreterRuntime;
+pub mod interpreter;
+pub use interpreter::InterpreterRuntime;
#[cfg(feature = "parser")]
/// Re-export of [`tinywasm_parser`]. Requires `parser` feature.
diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs
index 5b5f0c6..f6e8e04 100644
--- a/crates/tinywasm/src/module.rs
+++ b/crates/tinywasm/src/module.rs
@@ -1,24 +1,21 @@
use crate::{Imports, ModuleInstance, Result, Store};
use tinywasm_types::TinyWasmModule;
-#[derive(Debug)]
/// A WebAssembly Module
///
/// See <https://webassembly.github.io/spec/core/syntax/modules.html#syntax-module>
-#[derive(Clone)]
-pub struct Module {
- pub(crate) data: TinyWasmModule,
-}
+#[derive(Debug, Clone)]
+pub struct Module(pub(crate) TinyWasmModule);
impl From<&TinyWasmModule> for Module {
fn from(data: &TinyWasmModule) -> Self {
- Self { data: data.clone() }
+ Self(data.clone())
}
}
impl From<TinyWasmModule> for Module {
fn from(data: TinyWasmModule) -> Self {
- Self { data }
+ Self(data)
}
}
diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs
index f3acc49..870de48 100644
--- a/crates/tinywasm/src/reference.rs
+++ b/crates/tinywasm/src/reference.rs
@@ -1,45 +1,40 @@
-use core::cell::{Ref, RefCell, RefMut};
+use core::cell::{Ref, RefMut};
use core::ffi::CStr;
use alloc::ffi::CString;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
-use crate::{GlobalInstance, MemoryInstance, Result};
-use tinywasm_types::WasmValue;
+use crate::{MemoryInstance, Result};
// This module essentially contains the public APIs to interact with the data stored in the store
/// A reference to a memory instance
#[derive(Debug)]
-pub struct MemoryRef<'a> {
- pub(crate) instance: Ref<'a, MemoryInstance>,
-}
+pub struct MemoryRef<'a>(pub(crate) Ref<'a, MemoryInstance>);
/// A borrowed reference to a memory instance
#[derive(Debug)]
-pub struct MemoryRefMut<'a> {
- pub(crate) instance: RefMut<'a, MemoryInstance>,
-}
+pub struct MemoryRefMut<'a>(pub(crate) RefMut<'a, MemoryInstance>);
impl<'a> MemoryRefLoad for MemoryRef<'a> {
/// Load a slice of memory
fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
- self.instance.load(offset, len)
+ self.0.load(offset, len)
}
}
impl<'a> MemoryRefLoad for MemoryRefMut<'a> {
/// Load a slice of memory
fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
- self.instance.load(offset, len)
+ self.0.load(offset, len)
}
}
impl MemoryRef<'_> {
/// Load a slice of memory
pub fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
- self.instance.load(offset, len)
+ self.0.load(offset, len)
}
/// Load a slice of memory as a vector
@@ -51,7 +46,7 @@ impl MemoryRef<'_> {
impl MemoryRefMut<'_> {
/// Load a slice of memory
pub fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
- self.instance.load(offset, len)
+ self.0.load(offset, len)
}
/// Load a slice of memory as a vector
@@ -61,27 +56,27 @@ impl MemoryRefMut<'_> {
/// Grow the memory by the given number of pages
pub fn grow(&mut self, delta_pages: i32) -> Option<i32> {
- self.instance.grow(delta_pages)
+ self.0.grow(delta_pages)
}
/// Get the current size of the memory in pages
pub fn page_count(&mut self) -> usize {
- self.instance.page_count()
+ self.0.page_count()
}
/// Copy a slice of memory to another place in memory
pub fn copy_within(&mut self, src: usize, dst: usize, len: usize) -> Result<()> {
- self.instance.copy_within(src, dst, len)
+ self.0.copy_within(src, dst, len)
}
/// Fill a slice of memory with a value
pub fn fill(&mut self, offset: usize, len: usize, val: u8) -> Result<()> {
- self.instance.fill(offset, len, val)
+ self.0.fill(offset, len, val)
}
/// Store a slice of memory
pub fn store(&mut self, offset: usize, len: usize, data: &[u8]) -> Result<()> {
- self.instance.store(offset, len, data)
+ self.0.store(offset, len, data)
}
}
@@ -139,21 +134,3 @@ pub trait MemoryStringExt: MemoryRefLoad {
impl MemoryStringExt for MemoryRef<'_> {}
impl MemoryStringExt for MemoryRefMut<'_> {}
-
-/// A reference to a global instance
-#[derive(Debug)]
-pub struct GlobalRef {
- pub(crate) instance: RefCell<GlobalInstance>,
-}
-
-impl GlobalRef {
- /// Get the value of the global
- pub fn get(&self) -> WasmValue {
- self.instance.borrow().get()
- }
-
- /// Set the value of the global
- pub fn set(&self, val: WasmValue) -> Result<()> {
- self.instance.borrow_mut().set(val)
- }
-}
diff --git a/crates/tinywasm/src/runtime/stack/values.rs b/crates/tinywasm/src/runtime/stack/values.rs
deleted file mode 100644
index 606e13a..0000000
--- a/crates/tinywasm/src/runtime/stack/values.rs
+++ /dev/null
@@ -1,420 +0,0 @@
-#![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;
-pub type ValueRef = Option<u32>;
-
-#[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<ValType> 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),
- 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<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<&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<f32> for TinyWasmValue {
- fn from(value: f32) -> Self {
- TinyWasmValue::Value32(value.to_bits())
- }
-}
-
-impl From<f64> for TinyWasmValue {
- fn from(value: f64) -> Self {
- TinyWasmValue::Value64(value.to_bits())
- }
-}
-
-impl From<i32> for TinyWasmValue {
- fn from(value: i32) -> Self {
- TinyWasmValue::Value32(value as u32)
- }
-}
-
-impl From<u32> for TinyWasmValue {
- fn from(value: u32) -> Self {
- TinyWasmValue::Value32(value)
- }
-}
-
-impl From<i64> for TinyWasmValue {
- fn from(value: i64) -> Self {
- TinyWasmValue::Value64(value as u64)
- }
-}
-
-impl From<u64> for TinyWasmValue {
- fn from(value: u64) -> Self {
- TinyWasmValue::Value64(value)
- }
-}
-
-impl From<Value128> for TinyWasmValue {
- fn from(value: Value128) -> Self {
- TinyWasmValue::Value128(value)
- }
-}
-
-impl From<ValueRef> for TinyWasmValue {
- fn from(value: ValueRef) -> Self {
- TinyWasmValue::ValueRef(value)
- }
-}
-
-// TODO: this can be made a bit more maintainable by using a macro
-
-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 InternalValue: sealed::Sealed {
- fn stack_push(stack: &mut ValueStack, value: Self);
- fn stack_pop(stack: &mut ValueStack) -> Result<Self>
- where
- Self: Sized;
- fn stack_peek(stack: &ValueStack) -> Result<Self>
- where
- Self: Sized;
-
- fn local_get(locals: &Locals, index: u32) -> Result<Self>
- 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<Self> {
- stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i32)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_32.last().ok_or(Error::ValueStackUnderflow).map(|v| *v as i32)
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_32.pop().ok_or(Error::ValueStackUnderflow).map(f32::from_bits)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_32.last().ok_or(Error::ValueStackUnderflow).map(|v| f32::from_bits(*v))
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(|v| v as i64)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_64.last().ok_or(Error::ValueStackUnderflow).map(|v| *v as i64)
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_64.pop().ok_or(Error::ValueStackUnderflow)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_64.last().ok_or(Error::ValueStackUnderflow).copied()
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_64.pop().ok_or(Error::ValueStackUnderflow).map(f64::from_bits)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_64.last().ok_or(Error::ValueStackUnderflow).map(|v| f64::from_bits(*v))
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_32.pop().ok_or(Error::ValueStackUnderflow)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_32.last().ok_or(Error::ValueStackUnderflow).copied()
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_128.pop().ok_or(Error::ValueStackUnderflow)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_128.last().ok_or(Error::ValueStackUnderflow).copied()
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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<Self> {
- stack.stack_ref.pop().ok_or(Error::ValueStackUnderflow)
- }
- #[inline]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- stack.stack_ref.last().ok_or(Error::ValueStackUnderflow).copied()
- }
- #[inline]
- fn local_get(locals: &Locals, index: u32) -> Result<Self> {
- 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/src/store/element.rs b/crates/tinywasm/src/store/element.rs
index 6da73c7..40301a5 100644
--- a/crates/tinywasm/src/store/element.rs
+++ b/crates/tinywasm/src/store/element.rs
@@ -9,7 +9,7 @@ use tinywasm_types::*;
pub(crate) struct ElementInstance {
pub(crate) kind: ElementKind,
pub(crate) items: Option<Vec<TableElement>>, // none is the element was dropped
- _owner: ModuleInstanceAddr, // index into store.module_instances
+ pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
}
impl ElementInstance {
diff --git a/crates/tinywasm/src/store/function.rs b/crates/tinywasm/src/store/function.rs
index ef370c2..f3f1df0 100644
--- a/crates/tinywasm/src/store/function.rs
+++ b/crates/tinywasm/src/store/function.rs
@@ -8,11 +8,11 @@ use tinywasm_types::*;
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
pub(crate) struct FunctionInstance {
pub(crate) func: Function,
- pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances, none for host functions
+ pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances, none for host functions
}
impl FunctionInstance {
pub(crate) fn new_wasm(func: WasmFunction, owner: ModuleInstanceAddr) -> Self {
- Self { func: Function::Wasm(Rc::new(func)), owner }
+ Self { func: Function::Wasm(Rc::new(func)), _owner: owner }
}
}
diff --git a/crates/tinywasm/src/store/global.rs b/crates/tinywasm/src/store/global.rs
index a18e43d..b7a47d6 100644
--- a/crates/tinywasm/src/store/global.rs
+++ b/crates/tinywasm/src/store/global.rs
@@ -1,10 +1,7 @@
+use crate::interpreter::TinyWasmValue;
use core::cell::Cell;
-
-use alloc::{format, string::ToString};
use tinywasm_types::*;
-use crate::{runtime::TinyWasmValue, unlikely, Error, Result};
-
/// A WebAssembly Global Instance
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
@@ -19,55 +16,4 @@ impl GlobalInstance {
pub(crate) fn new(ty: GlobalType, value: TinyWasmValue, owner: ModuleInstanceAddr) -> Self {
Self { ty, value: value.into(), _owner: owner }
}
-
- #[inline]
- pub(crate) fn get(&self) -> WasmValue {
- self.value.get().attach_type(self.ty.ty)
- }
-
- pub(crate) fn set(&mut self, val: WasmValue) -> Result<()> {
- if unlikely(val.val_type() != self.ty.ty) {
- return Err(Error::Other(format!(
- "global type mismatch: expected {:?}, got {:?}",
- self.ty.ty,
- val.val_type()
- )));
- }
-
- if unlikely(!self.ty.mutable) {
- return Err(Error::Other("global is immutable".to_string()));
- }
-
- self.value.set(val.into());
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_global_instance_get_set() {
- let global_type = GlobalType { ty: ValType::I32, mutable: true };
- let initial_value = TinyWasmValue::from(10i32);
- let owner = 0;
-
- let mut global_instance = GlobalInstance::new(global_type, initial_value, owner);
-
- // Test `get`
- assert_eq!(global_instance.get(), WasmValue::I32(10), "global value should be 10");
-
- // Test `set` with correct type
- assert!(global_instance.set(WasmValue::I32(20)).is_ok(), "set should succeed");
- assert_eq!(global_instance.get(), WasmValue::I32(20), "global value should be 20");
-
- // Test `set` with incorrect type
- assert!(matches!(global_instance.set(WasmValue::F32(1.0)), Err(Error::Other(_))), "set should fail");
-
- // Test `set` on immutable global
- let immutable_global_type = GlobalType { ty: ValType::I32, mutable: false };
- let mut immutable_global_instance = GlobalInstance::new(immutable_global_type, initial_value, owner);
- assert!(matches!(immutable_global_instance.set(WasmValue::I32(30)), Err(Error::Other(_))));
- }
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 9ebd82e..b427497 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, TinyWasmValue};
+use crate::interpreter::{self, InterpreterRuntime, TinyWasmValue};
use crate::{Error, Function, ModuleInstance, Result, Trap};
mod data;
@@ -57,7 +57,7 @@ impl Store {
}
/// Create a new store with the given runtime
- pub(crate) fn runtime(&self) -> runtime::InterpreterRuntime {
+ pub(crate) fn runtime(&self) -> interpreter::InterpreterRuntime {
match self.runtime {
Runtime::Default => InterpreterRuntime::default(),
}
@@ -381,7 +381,7 @@ impl Store {
}
pub(crate) fn add_func(&mut self, func: Function, idx: ModuleInstanceAddr) -> Result<FuncAddr> {
- self.data.funcs.push(FunctionInstance { func, owner: idx });
+ self.data.funcs.push(FunctionInstance { func, _owner: idx });
Ok(self.data.funcs.len() as FuncAddr - 1)
}
diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs
index 52146e7..0a57f4c 100644
--- a/crates/types/src/archive.rs
+++ b/crates/types/src/archive.rs
@@ -57,11 +57,7 @@ impl TinyWasmModule {
/// Creates a TinyWasmModule from a slice of bytes.
pub fn from_twasm(wasm: &[u8]) -> Result<TinyWasmModule, TwasmError> {
let len = validate_magic(wasm)?;
- let root = check_archived_root::<Self>(&wasm[len..]).map_err(|_e| {
- crate::log::error!("Invalid archive: {}", _e);
- TwasmError::InvalidArchive
- })?;
-
+ let root = check_archived_root::<Self>(&wasm[len..]).map_err(|_e| TwasmError::InvalidArchive)?;
Ok(root.deserialize(&mut rkyv::Infallible).unwrap())
}
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index d19326d..dd201ad 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -1,50 +1,6 @@
use super::{FuncAddr, GlobalAddr, LabelAddr, LocalAddr, TableAddr, TypeAddr, ValType};
use crate::{DataAddr, ElemAddr, MemAddr};
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
-pub enum BlockArgs {
- Empty,
- Type(ValType),
- FuncType(u32),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
-/// A packed representation of BlockArgs
-/// This is needed to keep the size of the Instruction enum small.
-/// Sadly, using #[repr(u8)] on BlockArgs itself is not possible because of the FuncType variant.
-pub struct BlockArgsPacked([u8; 5]); // Modifying this directly can cause runtime errors, but no UB
-
-impl From<BlockArgs> for BlockArgsPacked {
- fn from(args: BlockArgs) -> Self {
- let mut packed = [0; 5];
- match args {
- BlockArgs::Empty => packed[0] = 0,
- BlockArgs::Type(t) => {
- packed[0] = 1;
- packed[1] = t.to_byte();
- }
- BlockArgs::FuncType(t) => {
- packed[0] = 2;
- packed[1..].copy_from_slice(&t.to_le_bytes());
- }
- }
- Self(packed)
- }
-}
-
-impl From<BlockArgsPacked> for BlockArgs {
- fn from(packed: BlockArgsPacked) -> Self {
- match packed.0[0] {
- 0 => BlockArgs::Empty,
- 1 => BlockArgs::Type(ValType::from_byte(packed.0[1]).unwrap()),
- 2 => BlockArgs::FuncType(u32::from_le_bytes(packed.0[1..].try_into().unwrap())),
- _ => unreachable!(),
- }
- }
-}
-
/// Represents a memory immediate in a WebAssembly memory instruction.
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
@@ -106,9 +62,19 @@ pub enum Instruction {
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
Unreachable,
Nop,
- Block(BlockArgs, EndOffset),
- Loop(BlockArgs, EndOffset),
- If(BlockArgsPacked, ElseOffset, EndOffset), // If else offset is 0 if there is no else block
+
+ Block(EndOffset),
+ BlockWithType(ValType, EndOffset),
+ BlockWithFuncType(TypeAddr, EndOffset),
+
+ Loop(EndOffset),
+ LoopWithType(ValType, EndOffset),
+ LoopWithFuncType(TypeAddr, EndOffset),
+
+ If(ElseOffset, EndOffset),
+ IfWithType(ValType, ElseOffset, EndOffset),
+ IfWithFuncType(TypeAddr, ElseOffset, EndOffset),
+
Else(EndOffset),
EndBlockFrame,
Br(LabelAddr),
@@ -233,44 +199,3 @@ pub enum Instruction {
DataDrop(DataAddr),
ElemDrop(ElemAddr),
}
-
-#[cfg(test)]
-mod test_blockargs_packed {
- use super::*;
-
- #[test]
- fn test_empty() {
- let packed: BlockArgsPacked = BlockArgs::Empty.into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::Empty);
- }
-
- #[test]
- fn test_val_type_i32() {
- let packed: BlockArgsPacked = BlockArgs::Type(ValType::I32).into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I32));
- }
-
- #[test]
- fn test_val_type_i64() {
- let packed: BlockArgsPacked = BlockArgs::Type(ValType::I64).into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I64));
- }
-
- #[test]
- fn test_val_type_f32() {
- let packed: BlockArgsPacked = BlockArgs::Type(ValType::F32).into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F32));
- }
-
- #[test]
- fn test_val_type_f64() {
- let packed: BlockArgsPacked = BlockArgs::Type(ValType::F64).into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F64));
- }
-
- #[test]
- fn test_func_type() {
- let packed: BlockArgsPacked = BlockArgs::FuncType(0x12345678).into();
- assert_eq!(BlockArgs::from(packed), BlockArgs::FuncType(0x12345678));
- }
-}
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 785b13b..cdee7e6 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -14,7 +14,7 @@ use core::{fmt::Debug, ops::Range};
// log for logging (optional).
#[cfg(feature = "logging")]
-#[allow(clippy::single_component_path_imports)]
+#[allow(clippy::single_component_path_imports, unused)]
use log;
#[cfg(not(feature = "logging"))]
@@ -125,7 +125,7 @@ pub type ExternAddr = Addr;
// additional internal addresses
pub type TypeAddr = Addr;
-pub type LocalAddr = Addr;
+pub type LocalAddr = u16; // there can't be more than 50.000 locals in a function
pub type LabelAddr = Addr;
pub type ModuleInstanceAddr = Addr;
diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs
index 6c422d0..c418338 100644
--- a/crates/types/src/value.rs
+++ b/crates/types/src/value.rs
@@ -146,31 +146,6 @@ impl ValType {
pub fn is_simd(&self) -> bool {
matches!(self, ValType::V128)
}
-
- pub(crate) fn to_byte(self) -> u8 {
- match self {
- ValType::I32 => 0x7F,
- ValType::I64 => 0x7E,
- ValType::F32 => 0x7D,
- ValType::F64 => 0x7C,
- ValType::V128 => 0x7B,
- ValType::RefFunc => 0x70,
- ValType::RefExtern => 0x6F,
- }
- }
-
- pub(crate) fn from_byte(byte: u8) -> Option<Self> {
- match byte {
- 0x7F => Some(ValType::I32),
- 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,
- }
- }
}
macro_rules! impl_conversion_for_wasmvalue {
@@ -202,9 +177,4 @@ macro_rules! impl_conversion_for_wasmvalue {
}
}
-impl_conversion_for_wasmvalue! {
- i32 => I32,
- i64 => I64,
- f32 => F32,
- f64 => F64
-}
+impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, u128 => V128 }