summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-03-25 23:41:50 +0100
committerHenry <mail@henrygressmann.de>2026-03-25 23:41:50 +0100
commit430ea402911855e8b8579f0e97b10699f22f758d (patch)
tree681f2ec35c497b0d9d686c8438f5c240ddeb535b /crates
parent9d19098154714d5196a803e7f098105690decbbd (diff)
chore: atomic module data
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/module.rs32
-rw-r--r--crates/parser/src/visit.rs6
-rw-r--r--crates/tinywasm/src/func.rs4
-rw-r--r--crates/tinywasm/src/imports.rs2
-rw-r--r--crates/tinywasm/src/instance.rs25
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs92
-rw-r--r--crates/tinywasm/src/interpreter/mod.rs6
-rw-r--r--crates/tinywasm/src/interpreter/stack/block_stack.rs6
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs62
-rw-r--r--crates/tinywasm/src/interpreter/stack/mod.rs5
-rw-r--r--crates/tinywasm/src/lib.rs2
-rw-r--r--crates/tinywasm/src/module.rs6
-rw-r--r--crates/tinywasm/src/store/mod.rs24
-rw-r--r--crates/types/src/instructions.rs4
-rw-r--r--crates/types/src/lib.rs71
15 files changed, 188 insertions, 159 deletions
diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs
index 4754d31..d498143 100644
--- a/crates/parser/src/module.rs
+++ b/crates/parser/src/module.rs
@@ -1,14 +1,15 @@
use crate::log::debug;
use crate::{ParseError, Result, conversion};
use alloc::string::ToString;
-use alloc::{boxed::Box, format, vec::Vec};
+use alloc::sync::Arc;
+use alloc::{format, vec::Vec};
use tinywasm_types::{
- Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValueCounts,
- ValueCountsSmall, WasmFunction, WasmFunctionData,
+ ArcSlice, Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule,
+ ValueCounts, ValueCountsSmall, WasmFunction, WasmFunctionData,
};
use wasmparser::{FuncValidatorAllocations, Payload, Validator};
-pub(crate) type Code = (Box<[Instruction]>, WasmFunctionData, ValueCounts);
+pub(crate) type Code = (Arc<[Instruction]>, WasmFunctionData, ValueCounts);
#[derive(Default)]
pub(crate) struct ModuleReader {
@@ -195,25 +196,24 @@ impl ModuleReader {
.map(|((instructions, data, locals), ty_idx)| {
let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
let params = ValueCountsSmall::from(&ty.params);
- WasmFunction { instructions, data, locals, params, ty }
+ WasmFunction { instructions: ArcSlice(instructions), data, locals, params, ty }
})
- .collect::<Vec<_>>()
- .into_boxed_slice();
+ .collect::<Vec<_>>();
let globals = self.globals;
let table_types = self.table_types;
Ok(TinyWasmModule {
- funcs,
- func_types: self.func_types.into_boxed_slice(),
- globals: globals.into_boxed_slice(),
- table_types: table_types.into_boxed_slice(),
- imports: self.imports.into_boxed_slice(),
+ funcs: funcs.into(),
+ func_types: self.func_types.into(),
+ globals: globals.into(),
+ table_types: table_types.into(),
+ imports: self.imports.into(),
start_func: self.start_func,
- data: self.data.into_boxed_slice(),
- exports: self.exports.into_boxed_slice(),
- elements: self.elements.into_boxed_slice(),
- memory_types: self.memory_types.into_boxed_slice(),
+ data: self.data.into(),
+ exports: self.exports.into(),
+ elements: self.elements.into(),
+ memory_types: self.memory_types.into(),
})
}
}
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 9b9ab75..8212763 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -2,7 +2,7 @@ use crate::Result;
use crate::conversion::{convert_heaptype, convert_valtype};
use alloc::string::ToString;
-use alloc::{boxed::Box, vec::Vec};
+use alloc::vec::Vec;
use tinywasm_types::{Instruction, MemoryArg, WasmFunctionData};
use wasmparser::{
FuncValidator, FuncValidatorAllocations, FunctionBody, VisitOperator, VisitSimdOperator, WasmModuleResources,
@@ -37,7 +37,7 @@ pub(crate) fn process_operators_and_validate<R: WasmModuleResources>(
validator: FuncValidator<R>,
body: FunctionBody<'_>,
local_addr_map: Vec<u32>,
-) -> Result<(Box<[Instruction]>, WasmFunctionData, FuncValidatorAllocations)> {
+) -> Result<(alloc::sync::Arc<[Instruction]>, WasmFunctionData, FuncValidatorAllocations)> {
let mut reader = body.get_operators_reader()?;
let remaining = reader.get_binary_reader().bytes_remaining();
let mut builder = FunctionBuilder::new(remaining, validator, local_addr_map);
@@ -52,7 +52,7 @@ pub(crate) fn process_operators_and_validate<R: WasmModuleResources>(
}
Ok((
- builder.instructions.into_boxed_slice(),
+ alloc::sync::Arc::from(builder.instructions),
WasmFunctionData { v128_constants: builder.v128_constants.into_boxed_slice() },
builder.validator.into_allocations(),
))
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 5d5b56b..3a3985b 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -60,10 +60,10 @@ impl FuncHandle {
// 7. Push the frame f to the call stack
// & 8. Push the values to the stack (Not needed since the call frame owns the values)
- store.stack.initialize(callframe);
+ store.stack.clear();
// 9. Invoke the function instance
- InterpreterRuntime::exec(store)?;
+ InterpreterRuntime::exec(store, callframe)?;
// Once the function returns:
// 1. Assert: m values are on the top of the stack (Ensured by validation)
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index aa05ae9..dcd5e12 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -363,7 +363,7 @@ impl Imports {
) -> Result<ResolvedImports> {
let mut imports = ResolvedImports::new();
- for import in &module.0.imports {
+ for import in &*module.0.imports {
let val = self.take(store, import).ok_or_else(|| LinkingError::unknown_import(import))?;
match val {
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 02ef531..7eddb10 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -1,4 +1,5 @@
-use alloc::{boxed::Box, format, rc::Rc};
+use alloc::boxed::Box;
+use alloc::{format, rc::Rc};
use tinywasm_types::*;
use crate::func::{FromWasmValueTuple, IntoWasmValueTuple};
@@ -20,7 +21,7 @@ pub(crate) struct ModuleInstanceInner {
pub(crate) store_id: usize,
pub(crate) idx: ModuleInstanceAddr,
- pub(crate) types: Box<[FuncType]>,
+ pub(crate) types: ArcSlice<FuncType>,
pub(crate) func_addrs: Box<[FuncAddr]>,
pub(crate) table_addrs: Box<[TableAddr]>,
@@ -30,8 +31,8 @@ pub(crate) struct ModuleInstanceInner {
pub(crate) data_addrs: Box<[DataAddr]>,
pub(crate) func_start: Option<FuncAddr>,
- pub(crate) imports: Box<[Import]>,
- pub(crate) exports: Box<[Export]>,
+ pub(crate) imports: ArcSlice<Import>,
+ pub(crate) exports: ArcSlice<Export>,
}
impl ModuleInstance {
@@ -65,20 +66,20 @@ impl ModuleInstance {
let idx = store.next_module_instance_idx();
let mut addrs = imports.unwrap_or_default().link(store, &module, idx)?;
- addrs.funcs.extend(store.init_funcs(module.0.funcs.into(), idx)?);
- addrs.tables.extend(store.init_tables(module.0.table_types.into(), idx)?);
- addrs.memories.extend(store.init_memories(module.0.memory_types.into(), idx)?);
+ addrs.funcs.extend(store.init_funcs(&module.0.funcs, idx)?);
+ addrs.tables.extend(store.init_tables(&module.0.table_types, idx)?);
+ addrs.memories.extend(store.init_memories(&module.0.memory_types, idx)?);
- let global_addrs = store.init_globals(addrs.globals, module.0.globals.into(), &addrs.funcs, idx)?;
+ let global_addrs = store.init_globals(addrs.globals, &module.0.globals, &addrs.funcs, idx)?;
let (elem_addrs, elem_trapped) =
store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.0.elements, idx)?;
- let (data_addrs, data_trapped) = store.init_data(&addrs.memories, module.0.data.into(), idx)?;
+ let (data_addrs, data_trapped) = store.init_data(&addrs.memories, &module.0.data, idx)?;
let instance = ModuleInstanceInner {
failed_to_instantiate: elem_trapped.is_some() || data_trapped.is_some(),
store_id: store.id(),
idx,
- types: module.0.func_types,
+ types: module.0.func_types.clone(),
func_addrs: addrs.funcs.into_boxed_slice(),
table_addrs: addrs.tables.into_boxed_slice(),
mem_addrs: addrs.memories.into_boxed_slice(),
@@ -86,8 +87,8 @@ impl ModuleInstance {
elem_addrs,
data_addrs,
func_start: module.0.start_func,
- imports: module.0.imports,
- exports: module.0.exports,
+ imports: module.0.imports.clone(),
+ exports: module.0.exports.clone(),
};
let instance = Self::new(instance);
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index dbeceb9..8d2e211 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -22,10 +22,9 @@ pub(crate) struct Executor<'store> {
}
impl<'store> Executor<'store> {
- pub(crate) fn new(store: &'store mut Store) -> Result<Self> {
- let current_frame = store.stack.call_stack.pop().expect("no call frame, this is a bug");
- let current_module = store.get_module_instance_raw(current_frame.module_addr());
- Ok(Self { cf: current_frame, module: current_module, store })
+ pub(crate) fn new(store: &'store mut Store, cf: CallFrame) -> Result<Self> {
+ let module = store.get_module_instance_raw(cf.module_addr());
+ Ok(Self { module, store, cf })
}
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
@@ -104,22 +103,22 @@ impl<'store> Executor<'store> {
BrTable(default, len) => return self.exec_brtable(*default, *len),
Return => return self.exec_return(),
EndBlockFrame => self.exec_end_block(),
- LocalGet32(local_index) => self.exec_local_get::<Value32>(*local_index),
- LocalGet64(local_index) => self.exec_local_get::<Value64>(*local_index),
- LocalGet128(local_index) => self.exec_local_get::<Value128>(*local_index),
- LocalGetRef(local_index) => self.exec_local_get::<ValueRef>(*local_index),
- LocalSet32(local_index) => self.exec_local_set::<Value32>(*local_index),
- LocalSet64(local_index) => self.exec_local_set::<Value64>(*local_index),
- LocalSet128(local_index) => self.exec_local_set::<Value128>(*local_index),
- LocalSetRef(local_index) => self.exec_local_set::<ValueRef>(*local_index),
- LocalCopy32(from, to) => self.exec_local_copy::<Value32>(*from, *to),
- LocalCopy64(from, to) => self.exec_local_copy::<Value64>(*from, *to),
- LocalCopy128(from, to) => self.exec_local_copy::<Value128>(*from, *to),
- LocalCopyRef(from, to) => self.exec_local_copy::<ValueRef>(*from, *to),
- LocalTee32(local_index) => self.exec_local_tee::<Value32>(*local_index),
- LocalTee64(local_index) => self.exec_local_tee::<Value64>(*local_index),
- LocalTee128(local_index) => self.exec_local_tee::<Value128>(*local_index),
- LocalTeeRef(local_index) => self.exec_local_tee::<ValueRef>(*local_index),
+ LocalGet32(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value32>(*local_index)),
+ LocalGet64(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value64>(*local_index)),
+ LocalGet128(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value128>(*local_index)),
+ LocalGetRef(local_index) => self.store.stack.values.push(self.cf.locals.get::<ValueRef>(*local_index)),
+ LocalSet32(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value32>()),
+ LocalSet64(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value64>()),
+ LocalSet128(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value128>()),
+ LocalSetRef(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<ValueRef>()),
+ LocalCopy32(from, to) => self.cf.locals.set(*to, self.cf.locals.get::<Value32>(*from)),
+ LocalCopy64(from, to) => self.cf.locals.set(*to, self.cf.locals.get::<Value64>(*from)),
+ LocalCopy128(from, to) => self.cf.locals.set(*to, self.cf.locals.get::<Value128>(*from)),
+ LocalCopyRef(from, to) => self.cf.locals.set(*to, self.cf.locals.get::<ValueRef>(*from)),
+ LocalTee32(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<Value32>()),
+ LocalTee64(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<Value64>()),
+ LocalTee128(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<Value128>()),
+ LocalTeeRef(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<ValueRef>()),
GlobalGet(global_index) => self.exec_global_get(*global_index),
GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index),
GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index),
@@ -567,11 +566,11 @@ impl<'store> Executor<'store> {
wasm_func: Rc<WasmFunction>,
owner: ModuleInstanceAddr,
) -> ControlFlow<Option<Error>> {
- let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
-
if IS_RETURN_CALL {
+ let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
self.cf.reuse_for(wasm_func, locals, self.store.stack.blocks.len() as u32, owner);
} else {
+ let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.store.stack.blocks.len() as u32);
self.cf.incr_instr_ptr(); // skip the call instruction
self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
@@ -580,7 +579,7 @@ impl<'store> Executor<'store> {
self.module.swap_with(self.cf.module_addr(), self.store);
ControlFlow::Continue(())
}
- fn exec_call_host(&mut self, host_func: &Rc<imports::HostFunction>) -> ControlFlow<Option<Error>> {
+ fn exec_call_host(&mut self, host_func: Rc<imports::HostFunction>) -> ControlFlow<Option<Error>> {
let params = self.store.stack.values.pop_types(&host_func.ty.params).collect::<Box<_>>();
let res = host_func.call(FuncContext { store: self.store, module_addr: self.module.id() }, &params).to_cf()?;
self.store.stack.values.extend_from_wasmvalues(&res);
@@ -589,9 +588,9 @@ impl<'store> Executor<'store> {
}
fn exec_call_direct<const IS_RETURN_CALL: bool>(&mut self, v: u32) -> ControlFlow<Option<Error>> {
let func_inst = self.store.state.get_func(self.module.resolve_func_addr(v));
- match func_inst.func.clone() {
- crate::Function::Wasm(wasm_func) => self.exec_call::<IS_RETURN_CALL>(wasm_func, func_inst.owner),
- crate::Function::Host(host_func) => self.exec_call_host(&host_func),
+ match &func_inst.func {
+ crate::Function::Wasm(wasm_func) => self.exec_call::<IS_RETURN_CALL>(wasm_func.clone(), func_inst.owner),
+ crate::Function::Host(host_func) => self.exec_call_host(host_func.clone()),
}
}
fn exec_call_indirect<const IS_RETURN_CALL: bool>(
@@ -612,26 +611,26 @@ impl<'store> Executor<'store> {
let func_inst = self.store.state.get_func(func_ref);
let call_ty = self.module.func_ty(type_addr);
- match func_inst.func.clone() {
+ match &func_inst.func {
crate::Function::Wasm(wasm_func) => {
- if unlikely(wasm_func.ty != *call_ty) {
+ if wasm_func.ty != *call_ty {
return ControlFlow::Break(Some(
Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }
.into(),
));
}
- self.exec_call::<IS_RETURN_CALL>(wasm_func, func_inst.owner)
+ self.exec_call::<IS_RETURN_CALL>(wasm_func.clone(), func_inst.owner)
}
crate::Function::Host(host_func) => {
- if unlikely(host_func.ty != *call_ty) {
+ if host_func.ty != *call_ty {
return ControlFlow::Break(Some(
Trap::IndirectCallTypeMismatch { actual: host_func.ty.clone(), expected: call_ty.clone() }
.into(),
));
}
- self.exec_call_host(&host_func)
+ self.exec_call_host(host_func.clone())
}
}
}
@@ -645,16 +644,16 @@ impl<'store> Executor<'store> {
// falsy value is on the top of the stack
if else_offset == 0 {
- self.cf.jump(end_offset as usize);
+ self.cf.jump(end_offset);
return;
}
- self.cf.jump(else_offset as usize);
+ self.cf.jump(else_offset);
self.enter_block(end_offset - else_offset, BlockType::Else, (params, results));
}
fn exec_else(&mut self, end_offset: u32) {
self.exec_end_block();
- self.cf.jump(end_offset as usize);
+ self.cf.jump(end_offset);
}
fn resolve_functype(&self, idx: u32) -> (StackHeight, StackHeight) {
let ty = self.module.func_ty(idx);
@@ -662,7 +661,7 @@ impl<'store> Executor<'store> {
}
fn enter_block(&mut self, end_instr_offset: u32, ty: BlockType, (params, results): (StackHeight, StackHeight)) {
self.store.stack.blocks.push(BlockFrame {
- instr_ptr: self.cf.instr_ptr(),
+ instr_ptr: self.cf.instr_ptr() as u32,
end_instr_offset,
stack_ptr: self.store.stack.values.height(),
results,
@@ -730,18 +729,6 @@ impl<'store> Executor<'store> {
let block = self.store.stack.blocks.pop();
self.store.stack.values.truncate_keep(block.stack_ptr, block.results);
}
- fn exec_local_get<T: InternalValue>(&mut self, local_index: u16) {
- let v = self.cf.locals.get::<T>(local_index);
- self.store.stack.values.push(v);
- }
- fn exec_local_set<T: InternalValue>(&mut self, local_index: u16) {
- let v = self.store.stack.values.pop::<T>();
- self.cf.locals.set(local_index, v);
- }
- fn exec_local_tee<T: InternalValue>(&mut self, local_index: u16) {
- let v = self.store.stack.values.peek::<T>();
- self.cf.locals.set(local_index, v);
- }
fn exec_global_get(&mut self, global_index: u32) {
self.store
@@ -830,7 +817,7 @@ impl<'store> Executor<'store> {
let data_len = data.data.as_ref().map_or(0, |d| d.len());
- if unlikely(((size + offset) as usize > data_len) || ((dst + size) as usize > mem.len())) {
+ if ((size + offset) as usize > data_len) || ((dst + size) as usize > mem.len()) {
return Err(Trap::MemoryOutOfBounds { offset: offset as usize, len: size as usize, max: data_len }.into());
}
@@ -999,7 +986,7 @@ impl<'store> Executor<'store> {
let elem_len = elem.items.as_ref().map_or(0, alloc::vec::Vec::len);
let table_len = table.size();
- if unlikely(size < 0 || ((size + offset) as usize > elem_len) || ((dst + size) > table_len)) {
+ if size < 0 || ((size + offset) as usize > elem_len) || ((dst + size) > table_len) {
return Err(Trap::TableOutOfBounds { offset: offset as usize, len: size as usize, max: elem_len }.into());
}
@@ -1038,7 +1025,7 @@ impl<'store> Executor<'store> {
let val = self.store.stack.values.pop::<ValueRef>();
let i = self.store.stack.values.pop::<i32>();
- if unlikely(i + n > table.size()) {
+ if i + n > table.size() {
return Err(Error::Trap(Trap::TableOutOfBounds {
offset: i as usize,
len: n as usize,
@@ -1052,9 +1039,4 @@ impl<'store> Executor<'store> {
table.fill(self.module.func_addrs(), i as usize, n as usize, val.into())
}
-
- fn exec_local_copy<T: InternalValue>(&mut self, from: u16, to: u16) {
- let v = self.cf.locals.get::<T>(from);
- self.cf.locals.set(to, v);
- }
}
diff --git a/crates/tinywasm/src/interpreter/mod.rs b/crates/tinywasm/src/interpreter/mod.rs
index 6f296ce..1a9a0cc 100644
--- a/crates/tinywasm/src/interpreter/mod.rs
+++ b/crates/tinywasm/src/interpreter/mod.rs
@@ -7,7 +7,7 @@ pub(crate) mod values;
#[cfg(not(feature = "std"))]
mod no_std_floats;
-use crate::{Result, Store};
+use crate::{Result, Store, interpreter::stack::CallFrame};
pub(crate) use value128::*;
pub(crate) use values::*;
@@ -18,7 +18,7 @@ pub(crate) use values::*;
pub(crate) struct InterpreterRuntime;
impl InterpreterRuntime {
- pub(crate) fn exec(store: &mut Store) -> Result<()> {
- executor::Executor::new(store)?.run_to_completion()
+ pub(crate) fn exec(store: &mut Store, cf: CallFrame) -> Result<()> {
+ executor::Executor::new(store, cf)?.run_to_completion()
}
}
diff --git a/crates/tinywasm/src/interpreter/stack/block_stack.rs b/crates/tinywasm/src/interpreter/stack/block_stack.rs
index b35ad94..e4d4c28 100644
--- a/crates/tinywasm/src/interpreter/stack/block_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/block_stack.rs
@@ -1,4 +1,4 @@
-use crate::{engine::Config, unlikely};
+use crate::engine::Config;
use alloc::vec::Vec;
use crate::interpreter::values::{StackHeight, StackLocation};
@@ -31,7 +31,7 @@ impl BlockStack {
let len = (self.0.len() as u32) - offset;
// the vast majority of wasm functions don't use break to return
- if unlikely(index >= len) {
+ if index >= len {
return None;
}
@@ -52,7 +52,7 @@ impl BlockStack {
#[derive(Debug)]
pub(crate) struct BlockFrame {
- pub(crate) instr_ptr: usize, // position of the instruction pointer when the block was entered
+ pub(crate) instr_ptr: u32, // position of the instruction pointer when the block was entered
pub(crate) end_instr_offset: u32, // position of the end instruction of the block
pub(crate) stack_ptr: StackLocation, // stack pointer when the block was entered
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index ba74d3a..4b0fad6 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -7,7 +7,7 @@ use crate::{Error, unlikely};
use alloc::boxed::Box;
use alloc::{rc::Rc, vec::Vec};
-use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue};
+use tinywasm_types::{ArcSlice, Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue};
pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
@@ -22,9 +22,8 @@ impl CallStack {
Self { stack: Vec::with_capacity(config.call_stack_init_size) }
}
- pub(crate) fn reset(&mut self, call_frame: CallFrame) {
+ pub(crate) fn clear(&mut self) {
self.stack.clear();
- self.stack.push(call_frame);
}
#[inline]
@@ -81,14 +80,14 @@ impl CallFrame {
&self.func_instance.data
}
- #[inline]
+ #[inline(always)]
pub(crate) fn incr_instr_ptr(&mut self) {
self.instr_ptr += 1;
}
#[inline]
- pub(crate) fn jump(&mut self, offset: usize) {
- self.instr_ptr += offset;
+ pub(crate) fn jump(&mut self, offset: u32) {
+ self.instr_ptr += offset as usize;
}
#[inline]
@@ -96,19 +95,20 @@ impl CallFrame {
self.module_addr
}
+ #[inline(always)]
+ pub(crate) fn fetch_instr(&self) -> &Instruction {
+ self
+ .func_instance
+ .instructions
+ .get(self.instr_ptr)
+ .unwrap_or_else(|| unreachable!("Instruction pointer out of bounds, this is a bug"))
+ }
+
#[inline]
pub(crate) fn block_ptr(&self) -> u32 {
self.block_ptr
}
- #[inline(always)]
- pub(crate) fn fetch_instr(&self) -> &Instruction {
- match self.func_instance.instructions.get(self.instr_ptr) {
- Some(instr) => instr,
- None => unreachable!("Instruction out of bounds, this is a bug"),
- }
- }
-
pub(crate) fn reuse_for(
&mut self,
func: Rc<WasmFunction>,
@@ -139,7 +139,7 @@ impl CallFrame {
match break_to.ty {
BlockType::Loop => {
// this is a loop, so we want to jump back to the start of the loop
- self.instr_ptr = break_to.instr_ptr;
+ self.instr_ptr = break_to.instr_ptr as usize;
// We also want to push the params to the stack
values.truncate_keep(break_to.stack_ptr, break_to.params);
@@ -158,7 +158,7 @@ impl CallFrame {
values.truncate_keep(break_to.stack_ptr, break_to.results);
// (the inst_ptr will be incremented by 1 before the next instruction is executed)
- self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize;
+ self.instr_ptr = (break_to.instr_ptr + break_to.end_instr_offset) as usize;
// we also want to trim the label stack, including the block
blocks.truncate(blocks.len() as u32 - (break_to_relative + 1));
@@ -170,16 +170,16 @@ impl CallFrame {
#[inline]
pub(crate) fn new(
- wasm_func_inst: Rc<WasmFunction>,
- owner: ModuleInstanceAddr,
+ func_instance: Rc<WasmFunction>,
+ module_addr: ModuleInstanceAddr,
params: &[WasmValue],
block_ptr: u32,
) -> Self {
let locals = {
- let mut locals_32 = Vec::with_capacity(wasm_func_inst.locals.c32 as usize);
- let mut locals_64 = Vec::with_capacity(wasm_func_inst.locals.c64 as usize);
- let mut locals_128 = Vec::with_capacity(wasm_func_inst.locals.c128 as usize);
- let mut locals_ref = Vec::with_capacity(wasm_func_inst.locals.cref as usize);
+ let mut locals_32 = Vec::with_capacity(func_instance.locals.c32 as usize);
+ let mut locals_64 = Vec::with_capacity(func_instance.locals.c64 as usize);
+ let mut locals_128 = Vec::with_capacity(func_instance.locals.c128 as usize);
+ let mut locals_ref = Vec::with_capacity(func_instance.locals.cref as usize);
for p in params {
match p.into() {
@@ -190,10 +190,10 @@ impl CallFrame {
}
}
- locals_32.resize_with(wasm_func_inst.locals.c32 as usize, Default::default);
- locals_64.resize_with(wasm_func_inst.locals.c64 as usize, Default::default);
- locals_128.resize_with(wasm_func_inst.locals.c128 as usize, Default::default);
- locals_ref.resize_with(wasm_func_inst.locals.cref as usize, Default::default);
+ locals_32.resize_with(func_instance.locals.c32 as usize, Default::default);
+ locals_64.resize_with(func_instance.locals.c64 as usize, Default::default);
+ locals_128.resize_with(func_instance.locals.c128 as usize, Default::default);
+ locals_ref.resize_with(func_instance.locals.cref as usize, Default::default);
Locals {
locals_32: locals_32.into_boxed_slice(),
@@ -203,21 +203,21 @@ impl CallFrame {
}
};
- Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
+ Self { instr_ptr: 0, func_instance, module_addr, block_ptr, locals }
}
#[inline]
pub(crate) fn new_raw(
- wasm_func_inst: Rc<WasmFunction>,
- owner: ModuleInstanceAddr,
+ func_instance: Rc<WasmFunction>,
+ module_addr: ModuleInstanceAddr,
locals: Locals,
block_ptr: u32,
) -> Self {
- Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
+ Self { instr_ptr: 0, func_instance, module_addr, block_ptr, locals }
}
#[inline]
- pub(crate) fn instructions(&self) -> &[Instruction] {
+ pub(crate) fn instructions(&self) -> &ArcSlice<Instruction> {
&self.func_instance.instructions
}
}
diff --git a/crates/tinywasm/src/interpreter/stack/mod.rs b/crates/tinywasm/src/interpreter/stack/mod.rs
index 0635bae..68b9164 100644
--- a/crates/tinywasm/src/interpreter/stack/mod.rs
+++ b/crates/tinywasm/src/interpreter/stack/mod.rs
@@ -21,10 +21,9 @@ impl Stack {
Self { values: ValueStack::new(config), blocks: BlockStack::new(config), call_stack: CallStack::new(config) }
}
- /// Initialize the stack with the given call frame (used for starting execution)
- pub(crate) fn initialize(&mut self, callframe: CallFrame) {
+ pub(crate) fn clear(&mut self) {
self.values.clear();
self.blocks.clear();
- self.call_stack.reset(callframe);
+ self.call_stack.clear();
}
}
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index 07748b9..31d52f7 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -4,7 +4,7 @@
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_assignments, unused_variables))
))]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
-#![forbid(unsafe_code)]
+#![deny(unsafe_code)]
//! A tiny WebAssembly Runtime written in Rust
//!
diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs
index 26cea9c..e0685eb 100644
--- a/crates/tinywasm/src/module.rs
+++ b/crates/tinywasm/src/module.rs
@@ -5,17 +5,17 @@ use tinywasm_types::TinyWasmModule;
///
/// See <https://webassembly.github.io/spec/core/syntax/modules.html#syntax-module>
#[derive(Debug, Clone)]
-pub struct Module(pub(crate) TinyWasmModule);
+pub struct Module(pub(crate) alloc::sync::Arc<TinyWasmModule>);
impl From<&TinyWasmModule> for Module {
fn from(data: &TinyWasmModule) -> Self {
- Self(data.clone())
+ Self(alloc::sync::Arc::new(data.clone()))
}
}
impl From<TinyWasmModule> for Module {
fn from(data: TinyWasmModule) -> Self {
- Self(data)
+ Self(alloc::sync::Arc::new(data))
}
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 70a2b01..757cbb2 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -220,33 +220,33 @@ impl Store {
// Linking related functions
impl Store {
/// Add functions to the store, returning their addresses in the store
- pub(crate) fn init_funcs(&mut self, funcs: Vec<WasmFunction>, idx: ModuleInstanceAddr) -> Result<Vec<FuncAddr>> {
+ pub(crate) fn init_funcs(&mut self, funcs: &[WasmFunction], idx: ModuleInstanceAddr) -> Result<Vec<FuncAddr>> {
let func_count = self.state.funcs.len();
let mut func_addrs = Vec::with_capacity(func_count);
- for (i, func) in funcs.into_iter().enumerate() {
- self.state.funcs.push(FunctionInstance::new_wasm(func, idx));
+ for (i, func) in funcs.iter().enumerate() {
+ self.state.funcs.push(FunctionInstance::new_wasm(func.clone(), idx));
func_addrs.push((i + func_count) as FuncAddr);
}
Ok(func_addrs)
}
/// Add tables to the store, returning their addresses in the store
- pub(crate) fn init_tables(&mut self, tables: Vec<TableType>, idx: ModuleInstanceAddr) -> Result<Vec<TableAddr>> {
+ pub(crate) fn init_tables(&mut self, tables: &[TableType], idx: ModuleInstanceAddr) -> Result<Vec<TableAddr>> {
let table_count = self.state.tables.len();
let mut table_addrs = Vec::with_capacity(table_count);
- for (i, table) in tables.into_iter().enumerate() {
- self.state.tables.push(TableInstance::new(table, idx));
+ for (i, table) in tables.iter().enumerate() {
+ self.state.tables.push(TableInstance::new(table.clone(), idx));
table_addrs.push((i + table_count) as TableAddr);
}
Ok(table_addrs)
}
/// Add memories to the store, returning their addresses in the store
- pub(crate) fn init_memories(&mut self, memories: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Result<Vec<MemAddr>> {
+ pub(crate) fn init_memories(&mut self, memories: &[MemoryType], idx: ModuleInstanceAddr) -> Result<Vec<MemAddr>> {
let mem_count = self.state.memories.len();
let mut mem_addrs = Vec::with_capacity(mem_count);
- for (i, mem) in memories.into_iter().enumerate() {
- self.state.memories.push(MemoryInstance::new(mem, idx));
+ for (i, mem) in memories.iter().enumerate() {
+ self.state.memories.push(MemoryInstance::new(*mem, idx));
mem_addrs.push((i + mem_count) as MemAddr);
}
Ok(mem_addrs)
@@ -256,7 +256,7 @@ impl Store {
pub(crate) fn init_globals(
&mut self,
mut imported_globals: Vec<GlobalAddr>,
- new_globals: Vec<Global>,
+ new_globals: &[Global],
func_addrs: &[FuncAddr],
idx: ModuleInstanceAddr,
) -> Result<Vec<Addr>> {
@@ -363,12 +363,12 @@ impl Store {
pub(crate) fn init_data(
&mut self,
mem_addrs: &[MemAddr],
- data: Vec<Data>,
+ data: &[Data],
idx: ModuleInstanceAddr,
) -> Result<(Box<[Addr]>, Option<Trap>)> {
let data_count = self.state.data.len();
let mut data_addrs = Vec::with_capacity(data_count);
- for (i, data) in data.into_iter().enumerate() {
+ for (i, data) in data.iter().enumerate() {
let data_val = match data.kind {
tinywasm_types::DataKind::Active { mem: mem_addr, offset } => {
let Some(mem_addr) = mem_addrs.get(mem_addr as usize) else {
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index aa57dfa..ee99601 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -68,7 +68,7 @@ pub enum Instruction {
Block(EndOffset),
BlockWithType(ValType, EndOffset),
BlockWithFuncType(TypeAddr, EndOffset),
-
+
Loop(EndOffset),
LoopWithType(ValType, EndOffset),
LoopWithFuncType(TypeAddr, EndOffset),
@@ -141,7 +141,7 @@ pub enum Instruction {
RefNull(ValType),
RefFunc(FuncAddr),
RefIsNull,
-
+
// > Numeric Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions>
I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU,
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index beaa828..395c056 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -9,8 +9,11 @@
//! Types used by [`tinywasm`](https://docs.rs/tinywasm) and [`tinywasm_parser`](https://docs.rs/tinywasm_parser).
extern crate alloc;
-use alloc::boxed::Box;
-use core::{fmt::Debug, ops::Range};
+use alloc::{boxed::Box, sync::Arc};
+use core::{
+ fmt::Debug,
+ ops::{Deref, Range},
+};
// Memory defaults
const MEM_PAGE_SIZE: u64 = 65536;
@@ -73,47 +76,47 @@ pub struct TinyWasmModule {
/// Optimized and validated WebAssembly functions
///
/// Contains data from to the `code`, `func`, and `type` sections of the original WebAssembly module.
- pub funcs: Box<[WasmFunction]>,
+ pub funcs: ArcSlice<WasmFunction>,
/// A vector of type definitions, indexed by `TypeAddr`
///
/// Corresponds to the `type` section of the original WebAssembly module.
- pub func_types: Box<[FuncType]>,
+ pub func_types: ArcSlice<FuncType>,
/// Exported items of the WebAssembly module.
///
/// Corresponds to the `export` section of the original WebAssembly module.
- pub exports: Box<[Export]>,
+ pub exports: ArcSlice<Export>,
/// Global components of the WebAssembly module.
///
/// Corresponds to the `global` section of the original WebAssembly module.
- pub globals: Box<[Global]>,
+ pub globals: ArcSlice<Global>,
/// Table components of the WebAssembly module used to initialize tables.
///
/// Corresponds to the `table` section of the original WebAssembly module.
- pub table_types: Box<[TableType]>,
+ pub table_types: ArcSlice<TableType>,
/// Memory components of the WebAssembly module used to initialize memories.
///
/// Corresponds to the `memory` section of the original WebAssembly module.
- pub memory_types: Box<[MemoryType]>,
+ pub memory_types: ArcSlice<MemoryType>,
/// Imports of the WebAssembly module.
///
/// Corresponds to the `import` section of the original WebAssembly module.
- pub imports: Box<[Import]>,
+ pub imports: ArcSlice<Import>,
/// Data segments of the WebAssembly module.
///
/// Corresponds to the `data` section of the original WebAssembly module.
- pub data: Box<[Data]>,
+ pub data: ArcSlice<Data>,
/// Element segments of the WebAssembly module.
///
/// Corresponds to the `elem` section of the original WebAssembly module.
- pub elements: Box<[Element]>,
+ pub elements: ArcSlice<Element>,
}
/// A WebAssembly External Kind.
@@ -249,13 +252,57 @@ impl<'a, T: IntoIterator<Item = &'a ValType>> From<T> for ValueCountsSmall {
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
pub struct WasmFunction {
- pub instructions: Box<[Instruction]>,
+ pub instructions: ArcSlice<Instruction>,
pub data: WasmFunctionData,
pub locals: ValueCounts,
pub params: ValueCountsSmall,
pub ty: FuncType,
}
+#[derive(Clone, PartialEq)]
+#[doc(hidden)]
+// wrapper around Arc<[T]> to support serde serialization and deserialization
+pub struct ArcSlice<T>(pub Arc<[T]>);
+
+impl<T> From<alloc::vec::Vec<T>> for ArcSlice<T> {
+ fn from(vec: alloc::vec::Vec<T>) -> Self {
+ Self(Arc::from(vec))
+ }
+}
+
+impl<T> Default for ArcSlice<T> {
+ fn default() -> Self {
+ Self(Arc::from([]))
+ }
+}
+
+impl<T> Deref for ArcSlice<T> {
+ type Target = [T];
+
+ fn deref(&self) -> &Self::Target {
+ self.0.as_ref()
+ }
+}
+
+impl<T: Debug> Debug for ArcSlice<T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ self.0.as_ref().fmt(f)
+ }
+}
+
+impl<T: serde::Serialize + Debug> serde::Serialize for ArcSlice<T> {
+ fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ self.0.as_ref().serialize(serializer)
+ }
+}
+
+impl<'de, T: serde::Deserialize<'de> + Debug> serde::Deserialize<'de> for ArcSlice<T> {
+ fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+ let vec: alloc::vec::Vec<T> = alloc::vec::Vec::deserialize(deserializer)?;
+ Ok(Self(Arc::from(vec)))
+ }
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
pub struct WasmFunctionData {