summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rw-r--r--crates/tinywasm/src/func.rs16
-rw-r--r--crates/tinywasm/src/instance.rs8
-rw-r--r--crates/tinywasm/src/runtime/executer/mod.rs41
-rw-r--r--crates/tinywasm/src/runtime/mod.rs5
-rw-r--r--crates/tinywasm/src/runtime/stack/blocks.rs4
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs26
-rw-r--r--crates/tinywasm/src/store.rs28
8 files changed, 103 insertions, 37 deletions
diff --git a/Cargo.lock b/Cargo.lock
index aabea9b..b1289e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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,
}
}
}