summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2023-12-09 22:04:50 +0100
committerHenry Gressmann <mail@henrygressmann.de>2023-12-09 22:04:50 +0100
commit085c117cc0de0bb9ae90d4cbe65090ed53189b70 (patch)
tree76b868276a1a62bba3ed476d35775714d8b05d1d
parentd860a706d9f38a52cb9bd50b2a436f7c3daaf024 (diff)
chore: refactor executer
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--crates/tinywasm/Cargo.toml1
-rw-r--r--crates/tinywasm/src/lib.rs6
-rw-r--r--crates/tinywasm/src/runtime/executer/mod.rs156
-rw-r--r--crates/tinywasm/src/runtime/executor/macros.rs (renamed from crates/tinywasm/src/runtime/executer/macros.rs)0
-rw-r--r--crates/tinywasm/src/runtime/executor/mod.rs186
-rw-r--r--crates/tinywasm/src/runtime/mod.rs2
-rw-r--r--crates/tinywasm/src/store.rs10
7 files changed, 198 insertions, 163 deletions
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index bf19f89..28ec5f5 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -22,3 +22,4 @@ default=["std", "parser", "logging"]
logging=["log", "tinywasm-types/logging", "tinywasm-parser?/logging"]
std=["tinywasm-parser?/std", "tinywasm-types/std"]
parser=["tinywasm-parser"]
+nightly=[]
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index 616d2ab..aa01ef9 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -1,6 +1,5 @@
#![no_std]
#![forbid(unsafe_code)]
-#![cfg_attr(not(feature = "std"), feature(error_in_core))]
#![doc(test(
no_crate_inject,
attr(
@@ -9,9 +8,14 @@
)
))]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
+#![cfg_attr(feature = "nightly", feature(error_in_core))]
//! ## A tiny WebAssembly Runtime written in Rust
+// compiler error when using no_std without nightly
+#[cfg(all(not(feature = "std"), not(nightly)))]
+const _: () = { compile_error!("`nightly` feature is required for `no_std`") };
+
mod std;
extern crate alloc;
diff --git a/crates/tinywasm/src/runtime/executer/mod.rs b/crates/tinywasm/src/runtime/executer/mod.rs
deleted file mode 100644
index 2428b61..0000000
--- a/crates/tinywasm/src/runtime/executer/mod.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use super::{DefaultRuntime, Stack};
-use crate::{
- log::debug,
- runtime::{BlockFrame, BlockFrameType, RawWasmValue},
- CallFrame, Error, ModuleInstance, Result, Store,
-};
-use alloc::vec::Vec;
-use tinywasm_types::BlockArgs;
-
-mod macros;
-use macros::*;
-
-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();
-
- 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) => {
- cf.blocks.push(BlockFrame {
- instr_ptr: cf.instr_ptr,
- stack_ptr: stack.values.len(),
- args: *args,
- ty: BlockFrameType::Loop,
- });
- stack.values.block_args(*args)?;
- }
- BrTable(_default, len) => {
- let instr = instrs[cf.instr_ptr + 1..cf.instr_ptr + 1 + *len]
- .iter()
- .map(|i| match i {
- BrLabel(l) => Ok(*l),
- _ => panic!("Expected BrLabel, this should have been validated by the parser"),
- })
- .collect::<Result<Vec<_>>>()?;
-
- if instr.len() != *len {
- panic!("Expected {} BrLabel instructions, got {}", len, instr.len());
- }
-
- todo!()
- }
- Br(v) => cf.break_to(*v, &mut stack.values)?,
- BrIf(v) => {
- let val: i32 = stack.values.pop().ok_or(Error::StackUnderflow)?.into();
- if val > 0 {
- cf.break_to(*v, &mut stack.values)?
- };
- }
- End => {
- let blocks = &mut cf.blocks;
- let Some(block) = blocks.pop() else {
- 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);
-
- match block.ty {
- BlockFrameType::Loop => {
- debug!("end(loop): break loop");
- let res: &[RawWasmValue] = match block.args {
- BlockArgs::Empty => &[],
- BlockArgs::Type(_t) => todo!(),
- BlockArgs::FuncType(_t) => todo!(),
- };
-
- // remove the loop values from the stack
- stack.values.trim(block.stack_ptr);
-
- // push the loop result values to the stack
- stack.values.extend(res.iter().copied());
- }
- _ => {
- panic!("Attempted to end a block that is not the top block");
- }
- }
- }
- LocalGet(local_index) => {
- debug!("local.get: {:?}", local_index);
- let val = cf.get_local(*local_index as usize);
- debug!("local: {:#?}", val);
- stack.values.push(val);
- }
- LocalSet(local_index) => {
- debug!("local.set: {:?}", local_index);
- let val = stack.values.pop().ok_or(Error::StackUnderflow)?;
- cf.set_local(*local_index as usize, val);
- }
- LocalTee(local_index) => {
- debug!("local.tee: {:?}", local_index);
- let val = stack.values.pop().ok_or(Error::StackUnderflow)?;
- cf.set_local(*local_index as usize, val);
- stack.values.push(val);
- }
- I32Const(val) => stack.values.push((*val).into()),
- I64Const(val) => stack.values.push((*val).into()),
- I64Add => add_instr!(i64, stack),
- I32Add => add_instr!(i32, stack),
- F32Add => add_instr!(f32, stack),
- F64Add => add_instr!(f64, stack),
-
- I32Sub => sub_instr!(i32, stack),
- I64Sub => sub_instr!(i64, stack),
- F32Sub => sub_instr!(f32, stack),
- F64Sub => sub_instr!(f64, stack),
-
- I32LtS => lts_instr!(i32, stack),
- I64LtS => lts_instr!(i64, stack),
- F32Lt => lts_instr!(f32, stack),
- F64Lt => lts_instr!(f64, stack),
-
- I32DivS => div_instr!(i32, stack),
- I64DivS => div_instr!(i64, stack),
- F32Div => div_instr!(f32, stack),
- F64Div => div_instr!(f64, stack),
-
- i => todo!("{:?}", i),
- }
-
- cf.instr_ptr += 1;
- }
-
- debug!("end of exec");
- debug!("stack: {:?}", stack.values);
- debug!("insts: {:?}", instrs);
- debug!("instr_ptr: {}", cf.instr_ptr);
- Err(Error::FuncDidNotReturn)
- }
-}
diff --git a/crates/tinywasm/src/runtime/executer/macros.rs b/crates/tinywasm/src/runtime/executor/macros.rs
index 154d7f7..154d7f7 100644
--- a/crates/tinywasm/src/runtime/executer/macros.rs
+++ b/crates/tinywasm/src/runtime/executor/macros.rs
diff --git a/crates/tinywasm/src/runtime/executor/mod.rs b/crates/tinywasm/src/runtime/executor/mod.rs
new file mode 100644
index 0000000..1fbcf3f
--- /dev/null
+++ b/crates/tinywasm/src/runtime/executor/mod.rs
@@ -0,0 +1,186 @@
+use super::{DefaultRuntime, Stack};
+use crate::{
+ log::debug,
+ runtime::{BlockFrame, BlockFrameType, RawWasmValue},
+ CallFrame, Error, ModuleInstance, Result, Store,
+};
+use alloc::vec::Vec;
+use tinywasm_types::{BlockArgs, Instruction};
+
+mod macros;
+use macros::*;
+
+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)?.clone();
+ let instrs = func.instructions();
+
+ while let Some(instr) = instrs.get(cf.instr_ptr) {
+ match exec_one(&mut cf, instr, instrs, stack, store, &module)? {
+ // return from the function
+ ExecResult::Return => return Ok(()),
+
+ // continue to the next instruction and don't increment the instruction pointer
+ ExecResult::Continue => continue,
+
+ // continue to the next instruction and increment the instruction pointer
+ ExecResult::Ok => {
+ cf.instr_ptr += 1;
+ }
+ }
+ }
+
+ debug!("end of exec");
+ debug!("stack: {:?}", stack.values);
+ debug!("insts: {:?}", instrs);
+ debug!("instr_ptr: {}", cf.instr_ptr);
+ Err(Error::FuncDidNotReturn)
+ }
+}
+
+enum ExecResult {
+ Ok,
+ Continue,
+ Return,
+}
+
+#[inline]
+fn exec_one(
+ cf: &mut CallFrame,
+ instr: &Instruction,
+ instrs: &[Instruction],
+ stack: &mut Stack,
+ store: &mut Store,
+ module: &ModuleInstance,
+) -> Result<ExecResult> {
+ 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) => {
+ cf.blocks.push(BlockFrame {
+ instr_ptr: cf.instr_ptr,
+ stack_ptr: stack.values.len(),
+ args: *args,
+ ty: BlockFrameType::Loop,
+ });
+ stack.values.block_args(*args)?;
+ }
+ BrTable(_default, len) => {
+ let instr = instrs[cf.instr_ptr + 1..cf.instr_ptr + 1 + *len]
+ .iter()
+ .map(|i| match i {
+ BrLabel(l) => Ok(*l),
+ _ => panic!("Expected BrLabel, this should have been validated by the parser"),
+ })
+ .collect::<Result<Vec<_>>>()?;
+
+ if instr.len() != *len {
+ panic!("Expected {} BrLabel instructions, got {}", len, instr.len());
+ }
+
+ todo!()
+ }
+ Br(v) => cf.break_to(*v, &mut stack.values)?,
+ BrIf(v) => {
+ let val: i32 = stack.values.pop().ok_or(Error::StackUnderflow)?.into();
+ if val > 0 {
+ cf.break_to(*v, &mut stack.values)?
+ };
+ }
+ End => {
+ let blocks = &mut cf.blocks;
+ let Some(block) = blocks.pop() else {
+ if stack.call_stack.is_empty() {
+ debug!("end: no block to end and no parent call frame, returning");
+ return Ok(ExecResult::Return);
+ } else {
+ debug!("end: no block to end, returning to parent call frame");
+ *cf = stack.call_stack.pop()?;
+ cf.instr_ptr = cf.instr_ptr.saturating_sub(1);
+ return Ok(ExecResult::Continue);
+ }
+ };
+ debug!("end, blocks: {:?}", blocks);
+ debug!(" instr_ptr: {}", cf.instr_ptr);
+
+ match block.ty {
+ BlockFrameType::Loop => {
+ debug!("end(loop): break loop");
+ let res: &[RawWasmValue] = match block.args {
+ BlockArgs::Empty => &[],
+ BlockArgs::Type(_t) => todo!(),
+ BlockArgs::FuncType(_t) => todo!(),
+ };
+
+ // remove the loop values from the stack
+ stack.values.trim(block.stack_ptr);
+
+ // push the loop result values to the stack
+ stack.values.extend(res.iter().copied());
+ }
+ _ => {
+ panic!("Attempted to end a block that is not the top block");
+ }
+ }
+ }
+ LocalGet(local_index) => {
+ debug!("local.get: {:?}", local_index);
+ let val = cf.get_local(*local_index as usize);
+ debug!("local: {:#?}", val);
+ stack.values.push(val);
+ }
+ LocalSet(local_index) => {
+ debug!("local.set: {:?}", local_index);
+ let val = stack.values.pop().ok_or(Error::StackUnderflow)?;
+ cf.set_local(*local_index as usize, val);
+ }
+ LocalTee(local_index) => {
+ debug!("local.tee: {:?}", local_index);
+ let val = stack.values.pop().ok_or(Error::StackUnderflow)?;
+ cf.set_local(*local_index as usize, val);
+ stack.values.push(val);
+ }
+ I32Const(val) => stack.values.push((*val).into()),
+ I64Const(val) => stack.values.push((*val).into()),
+ I64Add => add_instr!(i64, stack),
+ I32Add => add_instr!(i32, stack),
+ F32Add => add_instr!(f32, stack),
+ F64Add => add_instr!(f64, stack),
+
+ I32Sub => sub_instr!(i32, stack),
+ I64Sub => sub_instr!(i64, stack),
+ F32Sub => sub_instr!(f32, stack),
+ F64Sub => sub_instr!(f64, stack),
+
+ I32LtS => lts_instr!(i32, stack),
+ I64LtS => lts_instr!(i64, stack),
+ F32Lt => lts_instr!(f32, stack),
+ F64Lt => lts_instr!(f64, stack),
+
+ I32DivS => div_instr!(i32, stack),
+ I64DivS => div_instr!(i64, stack),
+ F32Div => div_instr!(f32, stack),
+ F64Div => div_instr!(f64, stack),
+
+ i => todo!("{:?}", i),
+ };
+
+ Ok(ExecResult::Ok)
+}
diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs
index e79a3a3..07cff38 100644
--- a/crates/tinywasm/src/runtime/mod.rs
+++ b/crates/tinywasm/src/runtime/mod.rs
@@ -1,4 +1,4 @@
-mod executer;
+mod executor;
mod stack;
mod value;
diff --git a/crates/tinywasm/src/store.rs b/crates/tinywasm/src/store.rs
index 2e7ebdd..3214540 100644
--- a/crates/tinywasm/src/store.rs
+++ b/crates/tinywasm/src/store.rs
@@ -1,6 +1,6 @@
use core::sync::atomic::{AtomicUsize, Ordering};
-use alloc::{format, vec::Vec};
+use alloc::{format, rc::Rc, vec::Vec};
use tinywasm_types::{FuncAddr, Function, Instruction, ModuleInstanceAddr, TypeAddr, ValType};
use crate::{
@@ -99,7 +99,7 @@ impl FunctionInstance {
#[derive(Debug, Default)]
/// Global state that can be manipulated by WebAssembly programs
pub struct StoreData {
- pub(crate) funcs: Vec<FunctionInstance>,
+ pub(crate) funcs: Vec<Rc<FunctionInstance>>,
// pub tables: Vec<TableAddr>,
// pub mems: Vec<MemAddr>,
// pub globals: Vec<GlobalAddr>,
@@ -127,16 +127,16 @@ impl Store {
pub(crate) fn add_funcs(&mut self, funcs: Vec<Function>, idx: ModuleInstanceAddr) -> Vec<FuncAddr> {
let mut func_addrs = Vec::with_capacity(funcs.len());
for func in funcs.into_iter() {
- self.data.funcs.push(FunctionInstance {
+ self.data.funcs.push(Rc::new(FunctionInstance {
func,
_module_instance: idx,
- });
+ }));
func_addrs.push(idx as FuncAddr);
}
func_addrs
}
- pub(crate) fn get_func(&self, addr: usize) -> Result<&FunctionInstance> {
+ pub(crate) fn get_func(&self, addr: usize) -> Result<&Rc<FunctionInstance>> {
self.data
.funcs
.get(addr)