diff options
| -rw-r--r-- | Cargo.lock | 12 | ||||
| -rw-r--r-- | crates/tinywasm/src/func.rs | 16 | ||||
| -rw-r--r-- | crates/tinywasm/src/instance.rs | 8 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/executer/mod.rs | 41 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/mod.rs | 5 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/stack/blocks.rs | 4 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/stack/call_stack.rs | 26 | ||||
| -rw-r--r-- | crates/tinywasm/src/store.rs | 28 |
8 files changed, 103 insertions, 37 deletions
@@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "8bbb8258be8305fb0237d7b295f47bb24ff1b136a535f473baf40e70468515aa" dependencies = [ "indenter", "once_cell", @@ -301,9 +301,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "owo-colors" @@ -439,9 +439,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "bfeae074e687625746172d639330f1de242a178bf3189b51e35a7a21573513ac" dependencies = [ "bitflags", "errno", diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 3428256..6a189da 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -10,13 +10,14 @@ use crate::{ #[derive(Debug)] /// A function handle pub struct FuncHandle { - pub(crate) _module: ModuleInstance, + pub(crate) module: ModuleInstance, pub(crate) addr: FuncAddr, pub(crate) ty: FuncType, /// The name of the function, if it has one pub name: Option<String>, } + impl FuncHandle { /// Call a function /// @@ -26,11 +27,7 @@ impl FuncHandle { // 1. Assert: funcs[func_addr] exists // 2. let func_inst be the functiuon instance funcs[func_addr] - let func_inst = store - .data - .funcs - .get(self.addr as usize) - .ok_or(Error::Other(format!("function {} not found", self.addr)))?; + let func_inst = store.get_func(self.addr as usize)?; // 3. Let func_ty be the function type let func_ty = &self.ty; @@ -64,8 +61,8 @@ impl FuncHandle { // 8. Push the values to the stack (Not needed since the call frame owns the values) // 9. Invoke the function instance - let instrs = func_inst.instructions(); - store.runtime.exec(&mut stack, instrs)?; + let runtime = store.runtime(); + runtime.exec(store, &mut stack, self.module.clone())?; // Once the function returns: let result_m = func_ty.results.len(); @@ -125,6 +122,7 @@ macro_rules! impl_into_wasm_value_tuple { } } +impl_into_wasm_value_tuple!(); impl_into_wasm_value_tuple!(T1); impl_into_wasm_value_tuple!(T1, T2); impl_into_wasm_value_tuple!(T1, T2, T3); @@ -141,6 +139,7 @@ macro_rules! impl_from_wasm_value_tuple { $($T: TryFrom<WasmValue, Error = ()>),* { fn from_wasm_value_tuple(values: Vec<WasmValue>) -> Result<Self> { + #[allow(unused_variables, unused_mut)] let mut iter = values.into_iter(); Ok(( $( @@ -156,6 +155,7 @@ macro_rules! impl_from_wasm_value_tuple { } } +impl_from_wasm_value_tuple!(); impl_from_wasm_value_tuple!(T1); impl_from_wasm_value_tuple!(T1, T2); impl_from_wasm_value_tuple!(T1, T2, T3); diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 6b1374e..5e87e74 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -54,6 +54,10 @@ impl ModuleInstance { })) } + pub(crate) fn func_ty(&self, addr: FuncAddr) -> &FuncType { + &self.0.types[addr as usize] + } + /// Get an exported function by name pub fn get_func(&self, store: &Store, name: &str) -> Result<FuncHandle> { if self.0.store_id != store.id() { @@ -67,7 +71,7 @@ impl ModuleInstance { Ok(FuncHandle { addr: export.index, - _module: self.clone(), + module: self.clone(), name: Some(name.to_string()), ty, }) @@ -115,7 +119,7 @@ impl ModuleInstance { let ty = self.0.types[func.ty_addr() as usize].clone(); Ok(Some(FuncHandle { - _module: self.clone(), + module: self.clone(), addr: func_addr, ty, name: None, diff --git a/crates/tinywasm/src/runtime/executer/mod.rs b/crates/tinywasm/src/runtime/executer/mod.rs index c09a22e..2428b61 100644 --- a/crates/tinywasm/src/runtime/executer/mod.rs +++ b/crates/tinywasm/src/runtime/executer/mod.rs @@ -1,24 +1,39 @@ -use super::{Runtime, Stack}; +use super::{DefaultRuntime, Stack}; use crate::{ log::debug, runtime::{BlockFrame, BlockFrameType, RawWasmValue}, - Error, Result, + CallFrame, Error, ModuleInstance, Result, Store, }; use alloc::vec::Vec; -use tinywasm_types::{BlockArgs, Instruction}; +use tinywasm_types::BlockArgs; mod macros; use macros::*; -impl<const CHECK_TYPES: bool> Runtime<CHECK_TYPES> { - pub(crate) fn exec(&self, stack: &mut Stack, instrs: &[Instruction]) -> Result<()> { - let cf = stack.call_stack.top_mut()?; +impl DefaultRuntime { + pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack, module: ModuleInstance) -> Result<()> { + let mut cf = stack.call_stack.pop()?; + let func = store.get_func(cf.func_ptr)?; + let instrs = func.instructions(); - // TODO: maybe we don't need to check if the instr_ptr is valid since - // it should be validated by the parser while let Some(instr) = instrs.get(cf.instr_ptr) { use tinywasm_types::Instruction::*; match instr { + Call(v) => { + // prepare the call frame + let func = store.get_func(*v as usize)?; + let func_ty = module.func_ty(*v); + debug!("call: {:?}", func_ty); + let call_frame = CallFrame::new(*v as usize, &[], func.locals().to_vec()); + + // push the call frame + stack.call_stack.push(cf.clone()); + stack.call_stack.push(call_frame); + debug!("call: {:?}", func); + + // call the function + cf = stack.call_stack.pop()?; + } Nop => {} // do nothing Unreachable => return Err(Error::Trap(crate::Trap::Unreachable)), Loop(args) => { @@ -55,8 +70,14 @@ impl<const CHECK_TYPES: bool> Runtime<CHECK_TYPES> { End => { let blocks = &mut cf.blocks; let Some(block) = blocks.pop() else { - debug!("end: no block to end, returning"); - return Ok(()); + if stack.call_stack.is_empty() { + debug!("end: no block to end and no parent call frame, returning"); + return Ok(()); + } else { + debug!("end: no block to end, returning to parent call frame"); + cf = stack.call_stack.pop()?; + continue; + } }; debug!("end, blocks: {:?}", blocks); debug!(" instr_ptr: {}", cf.instr_ptr); diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs index 0f22a52..e79a3a3 100644 --- a/crates/tinywasm/src/runtime/mod.rs +++ b/crates/tinywasm/src/runtime/mod.rs @@ -12,6 +12,7 @@ pub(crate) use value::RawWasmValue; /// that the module is valid. /// /// See <https://webassembly.github.io/spec/core/exec/runtime.html> -// Execution is implemented in the `executer` module +/// +/// Execution is implemented in the [`crate::runtime::executer`] module #[derive(Debug, Default)] -pub struct Runtime<const CHECK_TYPES: bool> {} +pub struct DefaultRuntime {} diff --git a/crates/tinywasm/src/runtime/stack/blocks.rs b/crates/tinywasm/src/runtime/stack/blocks.rs index f1a02f7..d2bb6d6 100644 --- a/crates/tinywasm/src/runtime/stack/blocks.rs +++ b/crates/tinywasm/src/runtime/stack/blocks.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use log::info; use tinywasm_types::BlockArgs; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub(crate) struct Blocks(Vec<BlockFrame>); impl Blocks { @@ -31,7 +31,7 @@ impl Blocks { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct BlockFrame { // where to resume execution when the block is broken pub(crate) instr_ptr: usize, diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index f1055ae..6e96e6c 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -6,6 +6,7 @@ use super::{blocks::Blocks, BlockFrameType}; // minimum call stack size const CALL_STACK_SIZE: usize = 1024; +const CALL_STACK_MAX_SIZE: usize = 1024 * 1024; #[derive(Debug)] pub(crate) struct CallStack { @@ -23,6 +24,20 @@ impl Default for CallStack { } impl CallStack { + pub(crate) fn is_empty(&self) -> bool { + self.top == 0 + } + + pub(crate) fn pop(&mut self) -> Result<CallFrame> { + assert!(self.top <= self.stack.len()); + if self.top == 0 { + return Err(Error::CallStackEmpty); + } + + self.top -= 1; + Ok(self.stack.pop().unwrap()) + } + #[inline] pub(crate) fn _top(&self) -> Result<&CallFrame> { assert!(self.top <= self.stack.len()); @@ -33,7 +48,7 @@ impl CallStack { } #[inline] - pub(crate) fn top_mut(&mut self) -> Result<&mut CallFrame> { + pub(crate) fn _top_mut(&mut self) -> Result<&mut CallFrame> { assert!(self.top <= self.stack.len()); if self.top == 0 { return Err(Error::CallStackEmpty); @@ -43,15 +58,18 @@ impl CallStack { #[inline] pub(crate) fn push(&mut self, call_frame: CallFrame) { + assert!(self.top <= self.stack.len()); + assert!(self.stack.len() <= CALL_STACK_MAX_SIZE); + self.top += 1; self.stack.push(call_frame); } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct CallFrame { pub(crate) instr_ptr: usize, - pub(crate) _func_ptr: usize, + pub(crate) func_ptr: usize, pub(crate) blocks: Blocks, pub(crate) locals: Box<[RawWasmValue]>, @@ -90,7 +108,7 @@ impl CallFrame { Self { instr_ptr: 0, - _func_ptr: func_ptr, + func_ptr, local_count: locals.len(), locals: locals.into_boxed_slice(), blocks: Blocks::default(), diff --git a/crates/tinywasm/src/store.rs b/crates/tinywasm/src/store.rs index 10aa56a..2e7ebdd 100644 --- a/crates/tinywasm/src/store.rs +++ b/crates/tinywasm/src/store.rs @@ -3,7 +3,10 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use alloc::{format, vec::Vec}; use tinywasm_types::{FuncAddr, Function, Instruction, ModuleInstanceAddr, TypeAddr, ValType}; -use crate::{runtime::Runtime, Error, ModuleInstance, Result}; +use crate::{ + runtime::{self, DefaultRuntime}, + Error, ModuleInstance, Result, +}; // global store id counter static STORE_ID: AtomicUsize = AtomicUsize::new(0); @@ -24,7 +27,26 @@ pub struct Store { module_instance_count: usize, pub(crate) data: StoreData, - pub(crate) runtime: Runtime<true>, + pub(crate) runtime: Runtime, +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum Runtime { + Default, +} + +impl Store { + /// Create a new store + pub fn new() -> Self { + Self::default() + } + + /// Create a new store with the given runtime + pub(crate) fn runtime(&self) -> runtime::DefaultRuntime { + match self.runtime { + Runtime::Default => DefaultRuntime::default(), + } + } } impl PartialEq for Store { @@ -42,7 +64,7 @@ impl Default for Store { module_instances: Vec::new(), module_instance_count: 0, data: StoreData::default(), - runtime: Runtime::default(), + runtime: Runtime::Default, } } } |
