Skip to content

Commit

Permalink
feat: improve lable/block handling, add support for more arithmetic o…
Browse files Browse the repository at this point in the history
…pcodes

Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
  • Loading branch information
explodingcamera committed Dec 7, 2023
1 parent 0cf77f7 commit b0292c7
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 173 deletions.
2 changes: 1 addition & 1 deletion crates/parser/src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub fn process_operators<'a>(
let targets = targets
.targets()
.collect::<Result<Vec<u32>, wasmparser::BinaryReaderError>>()?;
instructions.push(Instruction::BrTable(def, targets.len() as u32));
instructions.push(Instruction::BrTable(def, targets.len()));
instructions.extend(targets.into_iter().map(Instruction::BrLabel));
continue;
}
Expand Down
9 changes: 9 additions & 0 deletions crates/tinywasm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ use core::fmt::Display;
#[cfg(feature = "parser")]
use tinywasm_parser::ParseError;

#[derive(Debug)]
pub enum Trap {
Unreachable,
}

#[derive(Debug)]
pub enum Error {
#[cfg(feature = "parser")]
Expand All @@ -15,6 +20,8 @@ pub enum Error {
UnsupportedFeature(String),
Other(String),

Trap(Trap),

FuncDidNotReturn,
StackUnderflow,
BlockStackUnderflow,
Expand All @@ -31,6 +38,8 @@ impl Display for Error {
#[cfg(feature = "std")]
Self::Io(err) => write!(f, "I/O error: {}", err),

Self::Trap(trap) => write!(f, "trap: {:?}", trap),

Self::Other(message) => write!(f, "unknown error: {}", message),
Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {}", feature),
Self::FuncDidNotReturn => write!(f, "function did not return"),
Expand Down
155 changes: 0 additions & 155 deletions crates/tinywasm/src/runtime/executer.rs

This file was deleted.

44 changes: 44 additions & 0 deletions crates/tinywasm/src/runtime/executer/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// Add two values from the stack
macro_rules! add_instr {
($ty:ty, $stack:ident) => {{
let [a, b] = $stack.values.pop_n_const::<2>()?;
let a: $ty = a.into();
let b: $ty = b.into();
$stack.values.push((a + b).into());
}};
}

/// Subtract the top two values on the stack
macro_rules! sub_instr {
($ty:ty, $stack:ident) => {{
let [a, b] = $stack.values.pop_n_const::<2>()?;
let a: $ty = a.into();
let b: $ty = b.into();
$stack.values.push((a - b).into());
}};
}

/// Divide the top two values on the stack
macro_rules! div_instr {
($ty:ty, $stack:ident) => {{
let [a, b] = $stack.values.pop_n_const::<2>()?;
let a: $ty = a.into();
let b: $ty = b.into();
$stack.values.push((a / b).into());
}};
}

/// Less than signed instruction
macro_rules! lts_instr {
($ty:ty, $stack:ident) => {{
let [a, b] = $stack.values.pop_n_const::<2>()?;
let a: $ty = a.into();
let b: $ty = b.into();
$stack.values.push(((a < b) as i32).into());
}};
}

pub(super) use add_instr;
pub(super) use div_instr;
pub(super) use lts_instr;
pub(super) use sub_instr;
130 changes: 130 additions & 0 deletions crates/tinywasm/src/runtime/executer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use super::{Runtime, Stack};
use crate::{
log::debug,
runtime::{BlockFrame, BlockFrameType, RawWasmValue},
Error, Result,
};
use alloc::vec::Vec;
use tinywasm_types::{BlockArgs, Instruction};

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()?;

// 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 {
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 {
debug!("end: no block to end, returning");
return Ok(());
};
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);
}
I32Const(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)
}
}
5 changes: 4 additions & 1 deletion crates/tinywasm/src/runtime/stack.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
mod blocks;
mod call_stack;
mod value_stack;

use self::{call_stack::CallStack, value_stack::ValueStack};
pub use call_stack::CallFrame;
pub(crate) use blocks::{BlockFrame, BlockFrameType};
pub(crate) use call_stack::CallFrame;

/// A WebAssembly Stack
#[derive(Debug, Default)]
Expand Down
Loading

0 comments on commit b0292c7

Please sign in to comment.