Skip to content

Commit

Permalink
rework pt 1
Browse files Browse the repository at this point in the history
  • Loading branch information
george-cosma committed Sep 18, 2024
1 parent f70a2e7 commit c8cdf29
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 33 deletions.
24 changes: 24 additions & 0 deletions src/execution/execution_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use crate::core::reader::types::FuncType;
use crate::core::reader::WasmReader;
use crate::execution::Store;

/// ExecutionInfo is a compilation of relevant information needed by the [interpreter loop](
/// crate::execution::interpreter_loop::run). The lifetime annotation `'r` represents that this structure needs to be
/// valid at least as long as the [RuntimeInstance](crate::execution::RuntimeInstance) that creates it.
pub struct ExecutionInfo<'r> {
pub wasm_bytecode: &'r [u8],
pub wasm_reader: WasmReader<'r>,
pub fn_types: &'r [FuncType],
pub store: &'r mut Store,
}

impl<'r> ExecutionInfo<'r> {
pub fn new(wasm_bytecode: &'r [u8], fn_types: &'r [FuncType], store: &'r mut Store) -> Self {
ExecutionInfo {
wasm_bytecode,
wasm_reader: WasmReader::new(wasm_bytecode),
fn_types,
store,
}
}
}
107 changes: 80 additions & 27 deletions src/execution/interpreter_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use crate::{
WasmReadable, WasmReader,
},
},
execution::execution_info::ExecutionInfo,
locals::Locals,
store::Store,
store::{FuncInst, Store},
value,
value_stack::Stack,
NumType, RuntimeError, ValType, Value,
Expand All @@ -33,21 +34,21 @@ use crate::execution::hooks::HookSet;

/// Interprets a functions. Parameters and return values are passed on the stack.
pub(super) fn run<H: HookSet>(
wasm_bytecode: &[u8],
types: &[FuncType],
store: &mut Store,
modules: &mut [ExecutionInfo],
current_module: &mut usize,
stack: &mut Stack,
mut hooks: H,
) -> Result<(), RuntimeError> {
let func_inst = store
let func_inst = modules[*current_module]
.store
.funcs
.get(stack.current_stackframe().func_idx)
.unwrap_validated()
.try_into_local()
.unwrap_validated();

// Start reading the function's instructions
let mut wasm = WasmReader::new(wasm_bytecode);
let mut wasm = &mut modules[*current_module].wasm_reader;

// unwrap is sound, because the validation assures that the function points to valid subslice of the WASM binary
wasm.move_start_to(func_inst.code_expr).unwrap();
Expand All @@ -56,7 +57,7 @@ pub(super) fn run<H: HookSet>(
loop {
// call the instruction hook
#[cfg(feature = "hooks")]
hooks.instruction_hook(wasm_bytecode, wasm.pc);
hooks.instruction_hook(modules[*current_module].wasm_bytecode, wasm.pc);

let first_instr_byte = wasm.read_u8().unwrap_validated();

Expand All @@ -79,8 +80,15 @@ pub(super) fn run<H: HookSet>(

let func_to_call_idx = stack.current_stackframe().func_idx;

let func_to_call_inst = store.funcs.get(func_to_call_idx).unwrap_validated();
let func_to_call_ty = types.get(func_to_call_inst.ty()).unwrap_validated();
let func_to_call_inst = modules[*current_module]
.store
.funcs
.get(func_to_call_idx)
.unwrap_validated();
let func_to_call_ty = modules[*current_module]
.fn_types
.get(func_to_call_inst.ty())
.unwrap_validated();

let ret_vals = stack
.pop_tail_iter(func_to_call_ty.returns.valtypes.len())
Expand All @@ -101,24 +109,32 @@ pub(super) fn run<H: HookSet>(
CALL => {
let func_to_call_idx = wasm.read_var_u32().unwrap_validated() as FuncIdx;

// TODO: if it is imported, defer to linking
let func_to_call_inst = store
let func_to_call_inst = modules[*current_module]
.store
.funcs
.get(func_to_call_idx)
.unwrap_validated()
.try_into_local()
.expect("TODO: call imported functions");
let func_to_call_ty = types.get(func_to_call_inst.ty).unwrap_validated();
.unwrap_validated();

let func_to_call_ty = modules[*current_module]
.fn_types
.get(func_to_call_inst.ty())
.unwrap_validated();
let params = stack.pop_tail_iter(func_to_call_ty.params.valtypes.len());
let remaining_locals = func_to_call_inst.locals.iter().cloned();

trace!("Instruction: call [{func_to_call_idx:?}]");
let locals = Locals::new(params, remaining_locals);
stack.push_stackframe(func_to_call_idx, func_to_call_ty, locals, wasm.pc);

wasm.move_start_to(func_to_call_inst.code_expr)
.unwrap_validated();
match func_to_call_inst {
FuncInst::Local(local_func_inst) => {
let remaining_locals = local_func_inst.locals.iter().cloned();
let locals = Locals::new(params, remaining_locals);

stack.push_stackframe(func_to_call_idx, func_to_call_ty, locals, wasm.pc);

wasm.move_start_to(local_func_inst.code_expr)
.unwrap_validated();
}
FuncInst::Imported(imported_func_inst) => todo!(),
}
}
LOCAL_GET => {
stack.get_local(wasm.read_var_u32().unwrap_validated() as LocalIdx);
Expand All @@ -127,21 +143,38 @@ pub(super) fn run<H: HookSet>(
LOCAL_TEE => stack.tee_local(wasm.read_var_u32().unwrap_validated() as LocalIdx),
GLOBAL_GET => {
let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
let global = store.globals.get(global_idx).unwrap_validated();
let global = modules[*current_module]
.store
.globals
.get(global_idx)
.unwrap_validated();

// TODO: imported global

stack.push_value(global.value);
}
GLOBAL_SET => {
let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
let global = store.globals.get_mut(global_idx).unwrap_validated();
let global = modules[*current_module]
.store
.globals
.get_mut(global_idx)
.unwrap_validated();

// TODO: imported global (?) ... can imported globals be set as mutable?

global.value = stack.pop_value(global.global.ty.ty)
}
I32_LOAD => {
let memarg = MemArg::read_unvalidated(&mut wasm);
let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let mem = store.mems.first().unwrap_validated(); // there is only one memory allowed as of now
// TODO: how does this interact with imports?
let mem = modules[*current_module]
.store
.mems
.first()
.unwrap_validated(); // there is only one memory allowed as of now

let data: u32 = {
// The spec states that this should be a 33 bit integer
Expand All @@ -167,7 +200,12 @@ pub(super) fn run<H: HookSet>(
let memarg = MemArg::read_unvalidated(&mut wasm);
let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let mem = store.mems.first().unwrap_validated(); // there is only one memory allowed as of now
// TODO: how does this interact with imports?
let mem = modules[*current_module]
.store
.mems
.first()
.unwrap_validated(); // there is only one memory allowed as of now

let data: f32 = {
// The spec states that this should be a 33 bit integer
Expand Down Expand Up @@ -195,7 +233,12 @@ pub(super) fn run<H: HookSet>(
let data_to_store: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let mem = store.mems.get_mut(0).unwrap_validated(); // there is only one memory allowed as of now
// TODO: How does this interact with imports?
let mem = modules[*current_module]
.store
.mems
.get_mut(0)
.unwrap_validated(); // there is only one memory allowed as of now

// The spec states that this should be a 33 bit integer
// See: https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions
Expand All @@ -216,7 +259,12 @@ pub(super) fn run<H: HookSet>(
let data_to_store: f32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let mem = store.mems.get_mut(0).unwrap_validated(); // there is only one memory allowed as of now
// TODO: how does this interact with imports?
let mem = modules[*current_module]
.store
.mems
.get_mut(0)
.unwrap_validated(); // there is only one memory allowed as of now

// The spec states that this should be a 33 bit integer
// See: https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions
Expand All @@ -237,7 +285,12 @@ pub(super) fn run<H: HookSet>(
let data_to_store: f64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();

let mem = store.mems.get_mut(0).unwrap_validated(); // there is only one memory allowed as of now
// TODO: how does this interact with imports?
let mem = modules[*current_module]
.store
.mems
.get_mut(0)
.unwrap_validated(); // there is only one memory allowed as of now

// The spec states that this should be a 33 bit integer
// See: https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions
Expand Down
16 changes: 10 additions & 6 deletions src/execution/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::vec::Vec;

use const_interpreter_loop::run_const;
use execution_info::ExecutionInfo;
use interpreter_loop::run;
use locals::Locals;
use store::{ImportedFuncInst, LocalFuncInst};
Expand All @@ -22,6 +23,7 @@ use crate::{RuntimeError, ValidationInfo};
// TODO
pub(crate) mod assert_validated;
mod const_interpreter_loop;
pub(crate) mod execution_info;
pub mod hooks;
mod interpreter_loop;
pub(crate) mod locals;
Expand Down Expand Up @@ -144,10 +146,11 @@ where
stack.push_stackframe(func_idx, func_ty, locals, usize::MAX);

// Run the interpreter
let execution_info = ExecutionInfo::new(self.wasm_bytecode, &self.types, &mut self.store);

run(
self.wasm_bytecode,
&self.types,
&mut self.store,
&mut [execution_info],
&mut 0, // todo!
&mut stack,
EmptyHookSet,
)?;
Expand Down Expand Up @@ -200,10 +203,11 @@ where
stack.push_stackframe(func_idx, func_ty, locals, 0);

// Run the interpreter
let execution_info = ExecutionInfo::new(self.wasm_bytecode, &self.types, &mut self.store);

run(
self.wasm_bytecode,
&self.types,
&mut self.store,
&mut [execution_info],
&mut 0, // todo!
&mut stack,
EmptyHookSet,
)?;
Expand Down

0 comments on commit c8cdf29

Please sign in to comment.