Skip to content

Commit

Permalink
feat: function calls
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Gressmann <[email protected]>
  • Loading branch information
explodingcamera committed Dec 9, 2023
1 parent 085c117 commit aa2cbdc
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
47 changes: 34 additions & 13 deletions crates/tinywasm/src/runtime/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,25 @@ use macros::*;

impl DefaultRuntime {
pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack, module: ModuleInstance) -> Result<()> {
// The current call frame, gets updated inside of exec_one
let mut cf = stack.call_stack.pop()?;
let func = store.get_func(cf.func_ptr)?.clone();
let instrs = func.instructions();

// The function to execute, gets updated from ExecResult::Call
let mut func = store.get_func(cf.func_ptr)?.clone();
let mut instrs = func.instructions();

while let Some(instr) = instrs.get(cf.instr_ptr) {
match exec_one(&mut cf, instr, instrs, stack, store, &module)? {
// Continue execution at the new top of the call stack
ExecResult::Call => {
func = store.get_func(cf.func_ptr)?.clone();
instrs = func.instructions();
continue;
}

// 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;
Expand All @@ -41,8 +48,8 @@ impl DefaultRuntime {

enum ExecResult {
Ok,
Continue,
Return,
Call,
}

#[inline]
Expand All @@ -56,23 +63,35 @@ fn exec_one(
) -> Result<ExecResult> {
use tinywasm_types::Instruction::*;
match instr {
Nop => {} // do nothing
Unreachable => return Err(Error::Trap(crate::Trap::Unreachable)),

Return => {
debug!("return");
}

Call(v) => {
debug!("start call");
// 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());

debug!("params: {:?}", func_ty.params);
debug!("stack: {:?}", stack.values);
let params = stack.values.pop_n(func_ty.params.len())?;
let call_frame = CallFrame::new_raw(*v as usize, &params, func.locals().to_vec());

// push the call frame
cf.instr_ptr += 1; // skip the call instruction
stack.call_stack.push(cf.clone());
stack.call_stack.push(call_frame);
debug!("call: {:?}", func);

// call the function
*cf = stack.call_stack.pop()?;
debug!("calling: {:?}", func);
return Ok(ExecResult::Call);
}
Nop => {} // do nothing
Unreachable => return Err(Error::Trap(crate::Trap::Unreachable)),

Loop(args) => {
cf.blocks.push(BlockFrame {
instr_ptr: cf.instr_ptr,
Expand All @@ -82,6 +101,7 @@ fn exec_one(
});
stack.values.block_args(*args)?;
}

BrTable(_default, len) => {
let instr = instrs[cf.instr_ptr + 1..cf.instr_ptr + 1 + *len]
.iter()
Expand All @@ -97,6 +117,7 @@ fn exec_one(

todo!()
}

Br(v) => cf.break_to(*v, &mut stack.values)?,
BrIf(v) => {
let val: i32 = stack.values.pop().ok_or(Error::StackUnderflow)?.into();
Expand All @@ -113,8 +134,7 @@ fn exec_one(
} 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);
return Ok(ExecResult::Call);
}
};
debug!("end, blocks: {:?}", blocks);
Expand All @@ -140,6 +160,7 @@ fn exec_one(
}
}
}

LocalGet(local_index) => {
debug!("local.get: {:?}", local_index);
let val = cf.get_local(*local_index as usize);
Expand Down
12 changes: 10 additions & 2 deletions crates/tinywasm/src/runtime/stack/call_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ impl CallFrame {
Ok(())
}

pub(crate) fn new(func_ptr: usize, params: &[WasmValue], local_types: Vec<ValType>) -> Self {
pub(crate) fn new_raw(func_ptr: usize, params: &[RawWasmValue], local_types: Vec<ValType>) -> Self {
let mut locals = Vec::with_capacity(local_types.len() + params.len());
locals.extend(params.iter().map(|v| RawWasmValue::from(*v)));
locals.extend(params.iter().cloned());
locals.extend(local_types.iter().map(|_| RawWasmValue::default()));

Self {
Expand All @@ -115,6 +115,14 @@ impl CallFrame {
}
}

pub(crate) fn new(func_ptr: usize, params: &[WasmValue], local_types: Vec<ValType>) -> Self {
CallFrame::new_raw(
func_ptr,
&params.iter().map(|v| RawWasmValue::from(*v)).collect::<Vec<_>>(),
local_types,
)
}

#[inline]
pub(crate) fn set_local(&mut self, local_index: usize, value: RawWasmValue) {
if local_index >= self.local_count {
Expand Down
16 changes: 16 additions & 0 deletions examples/wasm/call.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(module
(func $add_fn (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add
)

(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
call $add_fn
)

(export "add" (func $add))
)

0 comments on commit aa2cbdc

Please sign in to comment.