From 1faa6a53ac3bed4fae2e24513240582f33757eb7 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 30 Nov 2023 15:40:22 +0100 Subject: feat: make module immutable Signed-off-by: Henry Gressmann --- crates/cli/bin.rs | 4 +- crates/tinywasm/src/engine/executer.rs | 1 - crates/tinywasm/src/engine/mod.rs | 20 ---------- crates/tinywasm/src/engine/stack/call.rs | 9 ----- crates/tinywasm/src/engine/stack/mod.rs | 39 -------------------- crates/tinywasm/src/engine/types.rs | 61 ------------------------------- crates/tinywasm/src/lib.rs | 2 +- crates/tinywasm/src/module/mod.rs | 50 ++++++++++++++++--------- crates/tinywasm/src/module/reader.rs | 20 ++-------- crates/tinywasm/src/runtime/executer.rs | 1 + crates/tinywasm/src/runtime/mod.rs | 14 +++++++ crates/tinywasm/src/runtime/stack/call.rs | 9 +++++ crates/tinywasm/src/runtime/stack/mod.rs | 39 ++++++++++++++++++++ crates/tinywasm/src/runtime/types.rs | 59 ++++++++++++++++++++++++++++++ crates/tinywasm/src/store.rs | 37 +++++-------------- 15 files changed, 170 insertions(+), 195 deletions(-) delete mode 100644 crates/tinywasm/src/engine/executer.rs delete mode 100644 crates/tinywasm/src/engine/mod.rs delete mode 100644 crates/tinywasm/src/engine/stack/call.rs delete mode 100644 crates/tinywasm/src/engine/stack/mod.rs delete mode 100644 crates/tinywasm/src/engine/types.rs create mode 100644 crates/tinywasm/src/runtime/executer.rs create mode 100644 crates/tinywasm/src/runtime/mod.rs create mode 100644 crates/tinywasm/src/runtime/stack/call.rs create mode 100644 crates/tinywasm/src/runtime/stack/mod.rs create mode 100644 crates/tinywasm/src/runtime/types.rs (limited to 'crates') diff --git a/crates/cli/bin.rs b/crates/cli/bin.rs index 18b61cc..7cc0703 100644 --- a/crates/cli/bin.rs +++ b/crates/cli/bin.rs @@ -68,9 +68,9 @@ fn main() -> Result<()> { } fn run(wasm: &[u8]) -> Result<()> { + let module = tinywasm::Module::try_new(wasm)?; let mut store = tinywasm::Store::default(); - let mut module = tinywasm::Module::try_new(&mut store, wasm)?; - let instance = tinywasm::ModuleInstance::new(&mut module)?; + let _instance = tinywasm::ModuleInstance::new(&mut store, &module)?; Ok(()) } diff --git a/crates/tinywasm/src/engine/executer.rs b/crates/tinywasm/src/engine/executer.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/tinywasm/src/engine/executer.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/tinywasm/src/engine/mod.rs b/crates/tinywasm/src/engine/mod.rs deleted file mode 100644 index a134659..0000000 --- a/crates/tinywasm/src/engine/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -mod executer; -mod stack; -mod types; - -pub use executer::*; -pub use stack::*; -pub use types::*; - -#[derive(Debug)] -pub struct Engine { - pub stack: Stack, -} - -impl Default for Engine { - fn default() -> Self { - Self { - stack: Stack::default(), - } - } -} diff --git a/crates/tinywasm/src/engine/stack/call.rs b/crates/tinywasm/src/engine/stack/call.rs deleted file mode 100644 index 0d0ffae..0000000 --- a/crates/tinywasm/src/engine/stack/call.rs +++ /dev/null @@ -1,9 +0,0 @@ -use alloc::vec::Vec; - -#[derive(Debug)] -pub struct CallFrame { - pub instr_ptr: usize, - pub func_ptr: usize, - - pub local_addrs: Vec, -} diff --git a/crates/tinywasm/src/engine/stack/mod.rs b/crates/tinywasm/src/engine/stack/mod.rs deleted file mode 100644 index f7ffdf3..0000000 --- a/crates/tinywasm/src/engine/stack/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::WasmValue; -use alloc::vec::Vec; - -mod call; -pub use call::CallFrame; - -// minimum stack size -pub const STACK_SIZE: usize = 1024; -// minimum call stack size -pub const CALL_STACK_SIZE: usize = 1024; - -/// A WebAssembly Stack -#[derive(Debug)] -pub struct Stack { - /// Locals - // TODO: maybe store the locals on the stack instead? - pub locals: Vec, - - /// The value stack - // TODO: Split into Vec and Vec for better memory usage? - pub value_stack: Vec, // keeping this typed for now to make it easier to debug - pub value_stack_top: usize, - - /// The call stack - pub call_stack: Vec, - pub call_stack_top: usize, -} - -impl Default for Stack { - fn default() -> Self { - Self { - locals: Vec::new(), - value_stack: Vec::with_capacity(STACK_SIZE), - value_stack_top: 0, - call_stack: Vec::with_capacity(CALL_STACK_SIZE), - call_stack_top: 0, - } - } -} diff --git a/crates/tinywasm/src/engine/types.rs b/crates/tinywasm/src/engine/types.rs deleted file mode 100644 index ab81b9d..0000000 --- a/crates/tinywasm/src/engine/types.rs +++ /dev/null @@ -1,61 +0,0 @@ -use alloc::{string::String, vec::Vec}; -use wasmparser::{FuncType, OperatorsIterator, ValType}; - -use crate::module::ModuleInstance; - -/// A WebAssembly Label -pub struct Label(Addr); - -/// A WebAssembly Address. -/// These are indexes into the respective stores. -/// See https://webassembly.github.io/spec/core/exec/runtime.html#addresses -pub type Addr = u32; -pub type FuncAddr = Addr; -pub type TableAddr = Addr; -pub type MemAddr = Addr; -pub type GlobalAddr = Addr; -pub type ElmAddr = Addr; -pub type DataAddr = Addr; -pub type ExternAddr = Addr; - -/// A WebAssembly Function Instance. -/// See https://webassembly.github.io/spec/core/exec/runtime.html#function-instances -#[derive(Debug)] -pub enum FuncInst { - Host(HostFunc), - Module(ModuleFunc), -} -#[derive(Debug)] -pub struct HostFunc { - pub ty: FuncType, - pub hostcode: fn() -> (), -} -#[derive(Debug)] -pub struct ModuleFunc { - pub ty: FuncType, - pub module: Addr, - pub code: FuncAddr, -} -pub struct Func<'a> { - pub ty: FuncType, - pub locals: Vec, - pub body: Vec>, -} - -/// A WebAssembly Export Instance. -/// https://webassembly.github.io/spec/core/exec/runtime.html#export-instances -#[derive(Debug)] -pub struct ExportInst { - pub name: String, - pub value: ExternVal, -} - -/// A WebAssembly External Value. -/// https://webassembly.github.io/spec/core/exec/runtime.html#external-values -#[derive(Debug)] -pub enum ExternVal { - Func(FuncAddr), - Table(TableAddr), - Mem(MemAddr), - Global(GlobalAddr), -} diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index f4bdd65..c362526 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -18,8 +18,8 @@ pub use module::ModuleInstance; pub mod types; pub use types::*; -pub mod engine; pub mod naive; +pub mod runtime; #[cfg(test)] mod tests { diff --git a/crates/tinywasm/src/module/mod.rs b/crates/tinywasm/src/module/mod.rs index 51731e9..a3a8e44 100644 --- a/crates/tinywasm/src/module/mod.rs +++ b/crates/tinywasm/src/module/mod.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use wasmparser::{Export, FuncType, Validator}; -use crate::{engine::FuncAddr, Error, Result, Store}; +use crate::{runtime::FuncAddr, Error, Result, Store}; use self::reader::ModuleReader; @@ -9,34 +9,38 @@ pub mod reader; #[derive(Debug)] pub struct Module<'a> { - store: &'a mut Store<'a>, reader: ModuleReader<'a>, } /// A WebAssembly Module Instance. +/// Addrs are indices into the store's data structures. /// See https://webassembly.github.io/spec/core/exec/runtime.html#module-instances #[derive(Debug)] pub struct ModuleInstance<'m, 'data> { - pub module: &'m Module<'data>, + pub(crate) module: &'m Module<'data>, - pub types: Vec, - pub func_addrs: Vec, + pub(crate) types: Vec, + pub(crate) func_addrs: Vec, // pub table_addrs: Vec, // pub mem_addrs: Vec, // pub global_addrs: Vec, // pub elem_addrs: Vec, // pub data_addrs: Vec, - pub exports: Vec>, + pub(crate) exports: Vec>, } -impl<'m, 'data> ModuleInstance<'m, 'data> { - pub fn new(module: &'m mut Module<'data>) -> Result { +impl<'m, 'data> ModuleInstance<'m, 'data> +where + 'm: 'data, +{ + pub fn new(store: &'data mut Store<'data>, module: &'m Module<'data>) -> Result { let types = module .reader .type_section - .take() + .as_ref() .map(|s| { - s.into_iter() + s.clone() + .into_iter() .map(|ty| { let wasmparser::Type::Func(func) = ty?; Ok(func) @@ -49,22 +53,32 @@ impl<'m, 'data> ModuleInstance<'m, 'data> { let func_addrs = module .reader .function_section - .take() - .map(|s| s.into_iter().map(|f| Ok(f?)).collect::>>()) + .as_ref() + .map(|s| { + s.clone() + .into_iter() + .map(|f| Ok(f?)) + .collect::>>() + }) .transpose()? .unwrap_or_default(); let exports = module .reader .export_section - .take() - .map(|s| s.into_iter().map(|e| Ok(e?)).collect::>>()) + .as_ref() + .map(|s| { + s.clone() + .into_iter() + .map(|e| Ok(e?)) + .collect::>>() + }) .transpose()? .unwrap_or_default(); + store.initialize(&module.reader)?; Ok(Self { module, - types, func_addrs, // table_addrs, @@ -78,17 +92,17 @@ impl<'m, 'data> ModuleInstance<'m, 'data> { } impl<'a> Module<'a> { - pub fn try_new(store: &'a mut Store<'a>, wasm: &'a [u8]) -> Result> { + pub fn try_new(wasm: &'a [u8]) -> Result> { let mut validator = Validator::new(); let mut reader = ModuleReader::new(); - for payload in wasmparser::Parser::new(0).parse_all(&wasm) { + for payload in wasmparser::Parser::new(0).parse_all(wasm) { reader.process_payload(payload?, &mut validator)?; } if !reader.end_reached { return Error::other("End not reached"); } - Ok(Self { store, reader }) + Ok(Self { reader }) } } diff --git a/crates/tinywasm/src/module/reader.rs b/crates/tinywasm/src/module/reader.rs index 50d1012..13a42a1 100644 --- a/crates/tinywasm/src/module/reader.rs +++ b/crates/tinywasm/src/module/reader.rs @@ -151,25 +151,11 @@ impl<'a> ModuleReader<'a> { Ok(()) } - - // fn exports(&mut self) -> Result> { - // let mut exports = Vec::new(); - - // if let Some(export_section) = self.export_section { - // for export in export_section.into_iter() { - // let export = export?; - // let name = export.name; - // let kind = export.kind; - // let index = export.index; - // exports.push(Export { name, kind, index }); - // } - // } - - // Ok(exports) - // } } -#[derive(Debug)] +/// A WebAssembly code section +/// Can be cloned to read functions multiple times +#[derive(Debug, Clone)] pub struct CodeSection<'a> { pub(crate) functions: Vec>, } diff --git a/crates/tinywasm/src/runtime/executer.rs b/crates/tinywasm/src/runtime/executer.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/crates/tinywasm/src/runtime/executer.rs @@ -0,0 +1 @@ + diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs new file mode 100644 index 0000000..fe2c6e4 --- /dev/null +++ b/crates/tinywasm/src/runtime/mod.rs @@ -0,0 +1,14 @@ +mod executer; +mod stack; +mod types; + +pub use executer::*; +pub use stack::*; +pub use types::*; + +/// A WebAssembly Runtime. +/// See https://webassembly.github.io/spec/core/exec/runtime.html +#[derive(Debug, Default)] +pub struct Runtime { + pub stack: Stack, +} diff --git a/crates/tinywasm/src/runtime/stack/call.rs b/crates/tinywasm/src/runtime/stack/call.rs new file mode 100644 index 0000000..0d0ffae --- /dev/null +++ b/crates/tinywasm/src/runtime/stack/call.rs @@ -0,0 +1,9 @@ +use alloc::vec::Vec; + +#[derive(Debug)] +pub struct CallFrame { + pub instr_ptr: usize, + pub func_ptr: usize, + + pub local_addrs: Vec, +} diff --git a/crates/tinywasm/src/runtime/stack/mod.rs b/crates/tinywasm/src/runtime/stack/mod.rs new file mode 100644 index 0000000..f7ffdf3 --- /dev/null +++ b/crates/tinywasm/src/runtime/stack/mod.rs @@ -0,0 +1,39 @@ +use crate::WasmValue; +use alloc::vec::Vec; + +mod call; +pub use call::CallFrame; + +// minimum stack size +pub const STACK_SIZE: usize = 1024; +// minimum call stack size +pub const CALL_STACK_SIZE: usize = 1024; + +/// A WebAssembly Stack +#[derive(Debug)] +pub struct Stack { + /// Locals + // TODO: maybe store the locals on the stack instead? + pub locals: Vec, + + /// The value stack + // TODO: Split into Vec and Vec for better memory usage? + pub value_stack: Vec, // keeping this typed for now to make it easier to debug + pub value_stack_top: usize, + + /// The call stack + pub call_stack: Vec, + pub call_stack_top: usize, +} + +impl Default for Stack { + fn default() -> Self { + Self { + locals: Vec::new(), + value_stack: Vec::with_capacity(STACK_SIZE), + value_stack_top: 0, + call_stack: Vec::with_capacity(CALL_STACK_SIZE), + call_stack_top: 0, + } + } +} diff --git a/crates/tinywasm/src/runtime/types.rs b/crates/tinywasm/src/runtime/types.rs new file mode 100644 index 0000000..511eac1 --- /dev/null +++ b/crates/tinywasm/src/runtime/types.rs @@ -0,0 +1,59 @@ +use alloc::{string::String, vec::Vec}; +use wasmparser::{FuncType, OperatorsIterator, ValType}; + +/// A WebAssembly Label +pub struct Label(Addr); + +/// A WebAssembly Address. +/// These are indexes into the respective stores. +/// See https://webassembly.github.io/spec/core/exec/runtime.html#addresses +pub type Addr = u32; +pub type FuncAddr = Addr; +pub type TableAddr = Addr; +pub type MemAddr = Addr; +pub type GlobalAddr = Addr; +pub type ElmAddr = Addr; +pub type DataAddr = Addr; +pub type ExternAddr = Addr; + +/// A WebAssembly Function Instance. +/// See https://webassembly.github.io/spec/core/exec/runtime.html#function-instances +#[derive(Debug)] +pub enum FuncInst { + Host(HostFunc), + Module(ModuleFunc), +} +#[derive(Debug)] +pub struct HostFunc { + pub ty: FuncType, + pub hostcode: fn() -> (), +} +#[derive(Debug)] +pub struct ModuleFunc { + pub ty: FuncType, + pub module: Addr, + pub code: FuncAddr, +} +pub struct Func<'a> { + pub ty: FuncType, + pub locals: Vec, + pub body: Vec>, +} + +/// A WebAssembly Export Instance. +/// https://webassembly.github.io/spec/core/exec/runtime.html#export-instances +#[derive(Debug)] +pub struct ExportInst { + pub name: String, + pub value: ExternVal, +} + +/// A WebAssembly External Value. +/// https://webassembly.github.io/spec/core/exec/runtime.html#external-values +#[derive(Debug)] +pub enum ExternVal { + Func(FuncAddr), + Table(TableAddr), + Mem(MemAddr), + Global(GlobalAddr), +} diff --git a/crates/tinywasm/src/store.rs b/crates/tinywasm/src/store.rs index 3c70c2f..617e9d9 100644 --- a/crates/tinywasm/src/store.rs +++ b/crates/tinywasm/src/store.rs @@ -1,38 +1,30 @@ use alloc::vec::Vec; use wasmparser::FunctionBody; -use crate::{engine::Engine, module::reader::ModuleReader, Result}; +use crate::{module::reader::ModuleReader, runtime::Runtime, Result}; /// global state that can be manipulated by WebAssembly programs /// https://webassembly.github.io/spec/core/exec/runtime.html#store -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Store<'data> { - pub data: StoreData<'data>, - pub engine: Engine, + pub(crate) data: StoreData<'data>, + pub(crate) engine: Runtime, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct StoreData<'data> { pub funcs: Vec>, // pub tables: Vec, // pub mems: Vec, // pub globals: Vec, -} - -impl<'data> Default for StoreData<'data> { - fn default() -> Self { - Self { - funcs: Vec::new(), - // tables: Vec::new(), - // mems: Vec::new(), - // globals: Vec::new(), - } - } + // pub elems: Vec, + // pub datas: Vec, } impl<'data> Store<'data> { - pub(crate) fn initialize(&'data mut self, reader: &'data mut ModuleReader) -> Result<()> { - let code = reader.code_section.take().ok_or_else(|| { + /// Initialize the store with global state from the given module + pub(crate) fn initialize(&'data mut self, reader: &ModuleReader<'data>) -> Result<()> { + let code = reader.code_section.clone().ok_or_else(|| { crate::Error::Other("Module must have a code section to initialize the store".into()) })?; @@ -40,12 +32,3 @@ impl<'data> Store<'data> { Ok(()) } } - -impl Default for Store<'_> { - fn default() -> Self { - Self { - data: StoreData::default(), - engine: Engine::default(), - } - } -} -- cgit v1.3.1