summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/visit.rs64
-rw-r--r--crates/tinywasm/Cargo.toml2
-rw-r--r--crates/tinywasm/src/boxvec.rs12
-rw-r--r--crates/tinywasm/src/instance.rs33
-rw-r--r--crates/tinywasm/src/runtime/interpreter/macros.rs41
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs148
-rw-r--r--crates/tinywasm/src/runtime/raw.rs19
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs39
-rw-r--r--crates/tinywasm/src/runtime/stack/value_stack.rs37
-rw-r--r--crates/tinywasm/src/store/memory.rs45
-rw-r--r--crates/tinywasm/src/store/mod.rs20
-rw-r--r--crates/types/src/instructions.rs12
12 files changed, 254 insertions, 218 deletions
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index bddd01d..c9176a4 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -126,9 +126,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_global_set, Instruction::GlobalSet, u32,
visit_i32_const, Instruction::I32Const, i32,
visit_i64_const, Instruction::I64Const, i64,
- visit_call, Instruction::Call, u32,
- visit_local_set, Instruction::LocalSet, u32,
- visit_local_tee, Instruction::LocalTee, u32
+ visit_call, Instruction::Call, u32
}
define_primitive_operands! {
@@ -319,10 +317,19 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
match self.instructions[self.instructions.len() - 2..] {
+ [_, Instruction::LocalGet2(a, b)] => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32StoreLocal {
+ local_a: a,
+ local_b: b,
+ offset: arg.offset as u32,
+ mem_addr: arg.mem_addr as u8,
+ })
+ }
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
self.instructions.pop();
self.instructions.pop();
- self.instructions.push(Instruction::I32StoreLocal {
+ self.instructions.push(Instruction::I32ConstStoreLocal {
local: a,
const_i32: b,
offset: arg.offset as u32,
@@ -334,10 +341,10 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
- if self.instructions.is_empty() {
+ let Some(instruction) = self.instructions.last_mut() else {
return self.instructions.push(Instruction::LocalGet(idx));
- }
- let instruction = self.instructions.last_mut().unwrap();
+ };
+
match instruction {
Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx),
Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx),
@@ -346,32 +353,47 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
};
}
+ fn visit_local_set(&mut self, idx: u32) -> Self::Output {
+ let Some(instruction) = self.instructions.last_mut() else {
+ return self.instructions.push(Instruction::LocalSet(idx));
+ };
+ match instruction {
+ Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx),
+ _ => self.instructions.push(Instruction::LocalSet(idx)),
+ };
+ }
+
+ fn visit_local_tee(&mut self, idx: u32) -> Self::Output {
+ self.instructions.push(Instruction::LocalTee(idx))
+ }
+
fn visit_i64_rotl(&mut self) -> Self::Output {
- if self.instructions.len() < 2 {
+ let Some([Instruction::I64Xor, Instruction::I64Const(a)]) = self.instructions.last_chunk::<2>() else {
return self.instructions.push(Instruction::I64Rotl);
- }
-
- match self.instructions[self.instructions.len() - 2..] {
- [Instruction::I64Xor, Instruction::I64Const(a)] => {
- self.instructions.pop();
- self.instructions.pop();
- self.instructions.push(Instruction::I64XorConstRotl(a))
- }
- _ => self.instructions.push(Instruction::I64Rotl),
- }
+ };
+ let a = *a;
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64XorConstRotl(a))
}
fn visit_i32_add(&mut self) -> Self::Output {
- if self.instructions.len() < 2 {
+ let Some(last) = self.instructions.last_chunk::<2>() else {
return self.instructions.push(Instruction::I32Add);
- }
+ };
- match self.instructions[self.instructions.len() - 2..] {
+ match *last {
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
self.instructions.pop();
self.instructions.pop();
self.instructions.push(Instruction::I32LocalGetConstAdd(a, b))
}
+ [Instruction::LocalGet2(a, b), Instruction::I32Const(c)] => {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalGet(a));
+ self.instructions.push(Instruction::I32LocalGetConstAdd(b, c))
+ }
_ => self.instructions.push(Instruction::I32Add),
}
}
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index 78c1b42..0d2c00e 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -28,7 +28,7 @@ serde={version="1.0", features=["derive"]}
pretty_env_logger="0.5"
[features]
-default=["std", "parser", "logging", "archive", "simd", "nightly"]
+default=["std", "parser", "logging", "archive"]
logging=["_log", "tinywasm-parser?/logging", "tinywasm-types/logging"]
std=["tinywasm-parser?/std", "tinywasm-types/std"]
parser=["tinywasm-parser"]
diff --git a/crates/tinywasm/src/boxvec.rs b/crates/tinywasm/src/boxvec.rs
index 17d3740..9c6732d 100644
--- a/crates/tinywasm/src/boxvec.rs
+++ b/crates/tinywasm/src/boxvec.rs
@@ -83,6 +83,18 @@ impl<T: Copy + Default> BoxVec<T> {
}
#[inline(always)]
+ pub(crate) fn extend(&mut self, iter: impl Iterator<Item = T>) {
+ let (lower, _) = iter.size_hint();
+ let upper = lower;
+ let new_end = self.end + upper;
+ assert!(new_end <= self.data.len(), "stack overflow");
+ for (i, value) in iter.enumerate() {
+ self.data[self.end + i] = value;
+ }
+ self.end = new_end;
+ }
+
+ #[inline(always)]
pub(crate) fn drain(&mut self, range: impl RangeBounds<usize>) -> Cow<'_, [T]> {
let start = match range.start_bound() {
core::ops::Bound::Included(&start) => start,
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index abc2819..d9e038a 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -133,40 +133,45 @@ impl ModuleInstance {
&self.0.func_addrs
}
+ #[cold]
+ fn not_found_error(name: &str) -> Error {
+ Error::Other(format!("address for {} not found", name))
+ }
+
// resolve a function address to the global store address
#[inline(always)]
- pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> FuncAddr {
- self.0.func_addrs[addr as usize]
+ pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> Result<FuncAddr> {
+ self.0.func_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("function")).copied()
}
// resolve a table address to the global store address
#[inline(always)]
- pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr {
- self.0.table_addrs[addr as usize]
+ pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> Result<TableAddr> {
+ self.0.table_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("table")).copied()
}
// resolve a memory address to the global store address
#[inline(always)]
- pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr {
- self.0.mem_addrs[addr as usize]
+ pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> Result<MemAddr> {
+ self.0.mem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("mem")).copied()
}
// resolve a data address to the global store address
#[inline(always)]
- pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> MemAddr {
- self.0.data_addrs[addr as usize]
+ pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> Result<DataAddr> {
+ self.0.data_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("data")).copied()
}
// resolve a memory address to the global store address
#[inline(always)]
- pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> ElemAddr {
- self.0.elem_addrs[addr as usize]
+ pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> Result<ElemAddr> {
+ self.0.elem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("elem")).copied()
}
// resolve a global address to the global store address
#[inline(always)]
- pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr {
- self.0.global_addrs[addr as usize]
+ pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> Result<GlobalAddr> {
+ self.0.global_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("global")).copied()
}
/// Get an exported function by name
@@ -218,13 +223,13 @@ impl ModuleInstance {
/// Get a memory by address
pub fn memory<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRef<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr))?;
+ let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
Ok(MemoryRef { instance: mem.borrow() })
}
/// Get a memory by address (mutable)
pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRefMut<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr))?;
+ let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
Ok(MemoryRefMut { instance: mem.borrow_mut() })
}
diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs
index aca2252..b2042c2 100644
--- a/crates/tinywasm/src/runtime/interpreter/macros.rs
+++ b/crates/tinywasm/src/runtime/interpreter/macros.rs
@@ -1,20 +1,14 @@
-//! More generic macros for various instructions
-//!
-//! These macros are used to generate the actual instruction implementations.
-//! In some basic tests this generated better assembly than using generic functions, even when inlined.
-//! (Something to revisit in the future)
-
// Break to a block at the given index (relative to the current frame)
// If there is no block at the given index, return or call the parent function
//
// This is a bit hard to see from the spec, but it's vaild to use breaks to return
// from a function, so we need to check if the label stack is empty
macro_rules! break_to {
- ($break_to_relative:expr, $self:expr) => {{
+ ($break_to_relative:expr, $self:expr) => {
if $self.cf.break_to($break_to_relative, &mut $self.stack.values, &mut $self.stack.blocks).is_none() {
return $self.exec_return();
}
- }};
+ };
}
/// Doing the actual conversion from float to int is a bit tricky, because
@@ -51,20 +45,19 @@ macro_rules! checked_conv_float {
checked_conv_float!($from, $to, $to, $self)
};
// Conversion with an intermediate unsigned type and error checking (three types)
- ($from:tt, $intermediate:tt, $to:tt, $self:expr) => {{
- let (min, max) = float_min_max!($from, $intermediate);
- let a: $from = $self.stack.values.pop()?.into();
-
- if unlikely(a.is_nan()) {
- return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
- }
-
- if unlikely(a <= min || a >= max) {
- return Err(Error::Trap(crate::Trap::IntegerOverflow));
- }
-
- $self.stack.values.push((a as $intermediate as $to).into());
- }};
+ ($from:tt, $intermediate:tt, $to:tt, $self:expr) => {
+ $self.stack.values.replace_top_trap(|v| {
+ let (min, max) = float_min_max!($from, $intermediate);
+ let a: $from = v.into();
+ if unlikely(a.is_nan()) {
+ return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
+ }
+ if unlikely(a <= min || a >= max) {
+ return Err(Error::Trap(crate::Trap::IntegerOverflow));
+ }
+ Ok((a as $intermediate as $to).into())
+ })?
+ };
}
/// Compare two values on the stack
@@ -79,9 +72,7 @@ macro_rules! comp {
/// Compare a value on the stack to zero
macro_rules! comp_zero {
($op:tt, $ty:ty, $self:expr) => {
- $self.stack.values.replace_top(|v| {
- ((<$ty>::from(v) $op 0) as i32).into()
- })?
+ $self.stack.values.replace_top(|v| ((<$ty>::from(v) $op 0) as i32).into())?
};
}
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index 6163f1b..8902aad 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -2,11 +2,10 @@ use alloc::{format, rc::Rc, string::ToString};
use core::ops::{BitAnd, BitOr, BitXor, ControlFlow, Neg};
use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction};
-use super::raw::ToMemBytes;
use super::stack::{BlockFrame, BlockType};
use super::{InterpreterRuntime, RawWasmValue, Stack};
use crate::runtime::CallFrame;
-use crate::{cold, unlikely, Error, FuncContext, MemLoadable, ModuleInstance, Result, Store, Trap};
+use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap};
mod macros;
mod traits;
@@ -36,10 +35,11 @@ struct Executor<'store, 'stack> {
impl<'store, 'stack> Executor<'store, 'stack> {
pub(crate) fn new(store: &'store mut Store, stack: &'stack mut Stack) -> Result<Self> {
let current_frame = stack.call_stack.pop().ok_or_else(|| Error::CallStackUnderflow)?;
- let current_module = store.get_module_instance_raw(current_frame.module_addr);
+ let current_module = store.get_module_instance_raw(current_frame.module_addr());
Ok(Self { cf: current_frame, module: current_module, stack, store })
}
+ #[inline]
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
loop {
match self.exec_next()? {
@@ -58,16 +58,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Drop => self.exec_drop()?,
Select(_valtype) => self.exec_select()?,
- Call(v) => return self.exec_call_direct(*v),
- CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table),
+ Call(v) => self.exec_call_direct(*v)?,
+ CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?,
- If(args, el, end) => return self.exec_if((*args).into(), *el, *end),
+ If(args, el, end) => self.exec_if((*args).into(), *el, *end)?,
Else(end_offset) => self.exec_else(*end_offset)?,
- Loop(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Loop, *args),
- Block(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Block, *args),
+ Loop(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, *args),
+ Block(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, *args),
Br(v) => return self.exec_br(*v),
BrIf(v) => return self.exec_br_if(*v),
BrTable(default, len) => return self.exec_brtable(*default, *len),
+ BrLabel(_) => {}
Return => return self.exec_return(),
EndBlockFrame => self.exec_end_block()?,
@@ -292,13 +293,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
LocalGetSet(a, b) => self.exec_local_get_set(*a, *b),
I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by)?,
I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val),
- I32StoreLocal { local, const_i32, offset, mem_addr } => {
- self.exec_i32_store_local(*local, *const_i32, *offset, *mem_addr)?
+ I32ConstStoreLocal { local, const_i32, offset, mem_addr } => {
+ self.exec_i32_const_store_local(*local, *const_i32, *offset, *mem_addr)?
}
-
- i => {
- cold();
- return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i)));
+ I32StoreLocal { local_a, local_b, offset, mem_addr } => {
+ self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)?
}
};
@@ -326,16 +325,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
Ok(())
}
- fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<ControlFlow<()>> {
+ fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<()> {
let params = self.stack.values.pop_n(wasm_func.ty.params.len())?;
let new_call_frame = CallFrame::new(wasm_func, owner, params, self.stack.blocks.len() as u32);
self.cf.instr_ptr += 1; // skip the call instruction
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
- self.module.swap_with(self.cf.module_addr, self.store);
- Ok(ControlFlow::Continue(()))
+ self.module.swap_with(self.cf.module_addr(), self.store);
+ self.cf.instr_ptr -= 1;
+ Ok(())
}
- fn exec_call_direct(&mut self, v: u32) -> Result<ControlFlow<()>> {
- let func_inst = self.store.get_func(self.module.resolve_func_addr(v))?;
+ fn exec_call_direct(&mut self, v: u32) -> Result<()> {
+ let func_inst = self.store.get_func(self.module.resolve_func_addr(v)?)?;
let wasm_func = match &func_inst.func {
crate::Function::Wasm(wasm_func) => wasm_func,
crate::Function::Host(host_func) => {
@@ -343,16 +343,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let params = self.stack.values.pop_params(&host_func.ty.params)?;
let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
self.stack.values.extend_from_typed(&res);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ return Ok(());
}
};
self.exec_call(wasm_func.clone(), func_inst.owner)
}
- fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ControlFlow<()>> {
+ fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<()> {
// verify that the table is of the right type, this should be validated by the parser already
let func_ref = {
- let table = self.store.get_table(self.module.resolve_table_addr(table_addr))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?;
let table_idx: u32 = self.stack.values.pop()?.into();
let table = table.borrow();
assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref");
@@ -379,8 +378,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let params = self.stack.values.pop_params(&host_func.ty.params)?;
let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
self.stack.values.extend_from_typed(&res);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ return Ok(());
}
};
@@ -392,29 +390,27 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Err(Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into())
}
- fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<ControlFlow<()>> {
+ fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> {
// truthy value is on the top of the stack, so enter the then block
if i32::from(self.stack.values.pop()?) != 0 {
- self.enter_block(self.cf.instr_ptr, end_offset, BlockType::If, args);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, args);
+ return Ok(());
}
// falsy value is on the top of the stack
if else_offset == 0 {
- self.cf.instr_ptr += end_offset as usize + 1;
- return Ok(ControlFlow::Continue(()));
+ *self.cf.instr_ptr_mut() += end_offset as usize;
+ return Ok(());
}
- let old = self.cf.instr_ptr;
- self.cf.instr_ptr += else_offset as usize;
+ let old = self.cf.instr_ptr();
+ *self.cf.instr_ptr_mut() += else_offset as usize;
self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, args);
- self.cf.instr_ptr += 1;
- Ok(ControlFlow::Continue(()))
+ Ok(())
}
fn exec_else(&mut self, end_offset: u32) -> Result<()> {
self.exec_end_block()?;
- self.cf.instr_ptr += end_offset as usize;
+ *self.cf.instr_ptr_mut() += end_offset as usize;
Ok(())
}
fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) {
@@ -472,7 +468,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_br(&mut self, to: u32) -> Result<ControlFlow<()>> {
break_to!(to, self);
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_br_if(&mut self, to: u32) -> Result<ControlFlow<()>> {
@@ -480,11 +476,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
if val != 0 {
break_to!(to, self);
}
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_brtable(&mut self, default: u32, len: u32) -> Result<ControlFlow<()>> {
- let start = self.cf.instr_ptr + 1;
+ let start = self.cf.instr_ptr() + 1;
let end = start + len as usize;
if end > self.cf.instructions().len() {
return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, self.cf.instructions().len())));
@@ -497,21 +493,21 @@ impl<'store, 'stack> Executor<'store, 'stack> {
_ => return Err(Error::Other("br_table with invalid label".to_string())),
}
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_return(&mut self) -> Result<ControlFlow<()>> {
- let old = self.cf.block_ptr;
+ let old = self.cf.block_ptr();
match self.stack.call_stack.pop() {
None => return Ok(ControlFlow::Break(())),
Some(cf) => self.cf = cf,
}
- if old > self.cf.block_ptr {
+ if old > self.cf.block_ptr() {
self.stack.blocks.truncate(old);
}
- self.module.swap_with(self.cf.module_addr, self.store);
+ self.module.swap_with(self.cf.module_addr(), self.store);
Ok(ControlFlow::Continue(()))
}
fn exec_end_block(&mut self) -> Result<()> {
@@ -532,11 +528,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
self.stack.values.last().map(|val| self.cf.set_local(local_index, *val))
}
fn exec_global_get(&mut self, global_index: u32) -> Result<()> {
- self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index))?);
+ self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?);
Ok(())
}
fn exec_global_set(&mut self, global_index: u32) -> Result<()> {
- self.store.set_global_val(self.module.resolve_global_addr(global_index), self.stack.values.pop()?)
+ self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop()?)
}
fn exec_const(&mut self, val: impl Into<RawWasmValue>) {
@@ -551,7 +547,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string()));
}
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?;
self.stack.values.push((mem.borrow().page_count() as i32).into());
Ok(())
}
@@ -560,7 +556,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string()));
}
- let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?.borrow_mut();
+ let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?.borrow_mut();
let prev_size = mem.page_count() as i32;
let pages_delta = self.stack.values.last_mut()?;
*pages_delta = match mem.grow(i32::from(*pages_delta)) {
@@ -577,13 +573,13 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let dst: i32 = self.stack.values.pop()?.into();
if from == to {
- let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow_mut();
+ let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from)?)?.borrow_mut();
// copy within the same memory
mem_from.copy_within(dst as usize, src as usize, size as usize)?;
} else {
// copy between two memories
- let mem_from = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow();
- let mut mem_to = self.store.get_mem(self.module.resolve_mem_addr(to))?.borrow_mut();
+ let mem_from = self.store.get_mem(self.module.resolve_mem_addr(from)?)?.borrow();
+ let mut mem_to = self.store.get_mem(self.module.resolve_mem_addr(to)?)?.borrow_mut();
mem_to.copy_from_slice(dst as usize, mem_from.load(src as usize, size as usize)?)?;
}
Ok(())
@@ -593,7 +589,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let val: i32 = self.stack.values.pop()?.into();
let dst: i32 = self.stack.values.pop()?.into();
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?;
mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?;
Ok(())
}
@@ -602,8 +598,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let offset: i32 = self.stack.values.pop()?.into(); // s
let dst: i32 = self.stack.values.pop()?.into(); // d
- let data = self.store.get_data(self.module.resolve_data_addr(data_index))?;
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index))?;
+ let data = self.store.get_data(self.module.resolve_data_addr(data_index)?)?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index)?)?;
let data_len = data.data.as_ref().map(|d| d.len()).unwrap_or(0);
@@ -624,10 +620,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_data_drop(&mut self, data_index: u32) -> Result<()> {
- self.store.get_data_mut(self.module.resolve_data_addr(data_index)).map(|d| d.drop())
+ self.store.get_data_mut(self.module.resolve_data_addr(data_index)?).map(|d| d.drop())
}
fn exec_elem_drop(&mut self, elem_index: u32) -> Result<()> {
- self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).map(|e| e.drop())
+ self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)?).map(|e| e.drop())
}
fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> {
let size: i32 = self.stack.values.pop()?.into();
@@ -635,13 +631,13 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let dst: i32 = self.stack.values.pop()?.into();
if from == to {
- let mut table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow_mut();
+ let mut table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow_mut();
// copy within the same memory
table_from.copy_within(dst as usize, src as usize, size as usize)?;
} else {
// copy between two memories
- let table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow();
- let mut table_to = self.store.get_table(self.module.resolve_table_addr(to))?.borrow_mut();
+ let table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow();
+ let mut table_to = self.store.get_table(self.module.resolve_table_addr(to)?)?.borrow_mut();
table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)?;
}
Ok(())
@@ -653,9 +649,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
mem_addr: tinywasm_types::MemAddr,
offset: u64,
) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?;
let val: u64 = self.stack.values.pop()?.into();
let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else {
+ cold();
return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
offset: offset as usize,
len: LOAD_SIZE,
@@ -667,12 +664,12 @@ impl<'store, 'stack> Executor<'store, 'stack> {
self.stack.values.push(cast(val).into());
Ok(())
}
- fn exec_mem_store<T: From<RawWasmValue> + ToMemBytes<N>, const N: usize>(
+ fn exec_mem_store<T: From<RawWasmValue> + MemStorable<N>, const N: usize>(
&mut self,
mem_addr: tinywasm_types::MemAddr,
offset: u64,
) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?;
let val: T = self.stack.values.pop()?.into();
let val = val.to_mem_bytes();
let addr: u64 = self.stack.values.pop()?.into();
@@ -681,14 +678,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_table_get(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let idx: u32 = self.stack.values.pop()?.into();
let v = table.borrow().get_wasm_val(idx)?;
self.stack.values.push(v.into());
Ok(())
}
fn exec_table_set(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let val = self.stack.values.pop()?.as_reference();
let idx = self.stack.values.pop()?.into();
table.borrow_mut().set(idx, val.into())?;
@@ -696,14 +693,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_table_size(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
self.stack.values.push(table.borrow().size().into());
Ok(())
}
fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let table_len = table.borrow().size();
- let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index))?;
+ let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index)?)?;
let elem_len = elem.items.as_ref().map(|items| items.len()).unwrap_or(0);
let size: i32 = self.stack.values.pop()?.into(); // n
@@ -732,7 +729,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
// todo: this is just a placeholder, need to check the spec
fn exec_table_grow(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let sz = table.borrow().size();
let n: i32 = self.stack.values.pop()?.into();
@@ -746,7 +743,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_table_fill(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let n: i32 = self.stack.values.pop()?.into();
let val = self.stack.values.pop()?.as_reference();
@@ -769,14 +766,21 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
// custom instructions
-
- fn exec_i32_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32))?;
- let val = const_i32.to_le_bytes();
+ fn exec_i32_const_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?;
+ let val = const_i32.to_mem_bytes();
let addr: u64 = self.cf.get_local(local).into();
mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
Ok(())
}
+ fn exec_i32_store_local(&mut self, local_a: u32, local_b: u32, offset: u32, mem_addr: u8) -> Result<()> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?;
+ let addr: u64 = self.cf.get_local(local_a).into();
+ let val: i32 = self.cf.get_local(local_b).into();
+ let val = val.to_mem_bytes();
+ mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
+ Ok(())
+ }
fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) {
let local: i32 = self.cf.get_local(local).into();
self.stack.values.push((local + val).into());
diff --git a/crates/tinywasm/src/runtime/raw.rs b/crates/tinywasm/src/runtime/raw.rs
index 877dcb1..a186fd7 100644
--- a/crates/tinywasm/src/runtime/raw.rs
+++ b/crates/tinywasm/src/runtime/raw.rs
@@ -15,25 +15,6 @@ impl Debug for RawWasmValue {
}
}
-pub(crate) trait ToMemBytes<const N: usize> {
- fn to_mem_bytes(self) -> [u8; N];
-}
-
-macro_rules! impl_to_mem_bytes {
- ($( $ty:ty, $n:expr ),*) => {
- $(
- impl ToMemBytes<$n> for $ty {
- #[inline]
- fn to_mem_bytes(self) -> [u8; $n] {
- self.to_ne_bytes()
- }
- }
- )*
- };
-}
-
-impl_to_mem_bytes! {u8, 1, u16, 2, u32, 4, u64, 8, i8, 1, i16, 2, i32, 4, i64, 8, f32, 4, f64, 8}
-
impl RawWasmValue {
#[inline]
/// Attach a type to the raw value (does not support simd values)
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs
index 14077a8..30957be 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/call_stack.rs
@@ -3,10 +3,11 @@ use crate::runtime::RawWasmValue;
use crate::unlikely;
use crate::{Result, Trap};
-use alloc::{boxed::Box, rc::Rc, vec::Vec};
+use alloc::boxed::Box;
+use alloc::{rc::Rc, vec, vec::Vec};
use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction};
-const CALL_STACK_SIZE: usize = 1024;
+pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
#[derive(Debug)]
pub(crate) struct CallStack {
@@ -16,10 +17,7 @@ pub(crate) struct CallStack {
impl CallStack {
#[inline]
pub(crate) fn new(initial_frame: CallFrame) -> Self {
- let mut stack = Vec::new();
- stack.reserve_exact(CALL_STACK_SIZE);
- stack.push(initial_frame);
- Self { stack }
+ Self { stack: vec![initial_frame] }
}
#[inline(always)]
@@ -29,7 +27,7 @@ impl CallStack {
#[inline(always)]
pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
- if unlikely((self.stack.len() + 1) >= CALL_STACK_SIZE) {
+ if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) {
return Err(Trap::CallStackOverflow.into());
}
self.stack.push(call_frame);
@@ -48,6 +46,31 @@ pub(crate) struct CallFrame {
impl CallFrame {
#[inline(always)]
+ pub(crate) fn instr_ptr(&self) -> usize {
+ self.instr_ptr
+ }
+
+ #[inline(always)]
+ pub(crate) fn instr_ptr_mut(&mut self) -> &mut usize {
+ &mut self.instr_ptr
+ }
+
+ #[inline(always)]
+ pub(crate) fn incr_instr_ptr(&mut self) {
+ self.instr_ptr += 1;
+ }
+
+ #[inline(always)]
+ pub(crate) fn module_addr(&self) -> ModuleInstanceAddr {
+ self.module_addr
+ }
+
+ #[inline(always)]
+ 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,
@@ -115,7 +138,7 @@ impl CallFrame {
locals.into_boxed_slice()
};
- Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, locals, block_ptr }
+ Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
}
#[inline(always)]
diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs
index db05364..159e366 100644
--- a/crates/tinywasm/src/runtime/stack/value_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/value_stack.rs
@@ -4,14 +4,10 @@ use tinywasm_types::{ValType, WasmValue};
use super::BlockFrame;
-pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024 * 128;
-// pub(crate) const MAX_VALUE_STACK_SIZE: usize = u32::MAX / 32 as usize;
+pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128;
#[cfg(feature = "simd")]
-pub(crate) const MIN_SIMD_VALUE_STACK_SIZE: usize = 1024 * 32;
-
-// #[cfg(feature = "simd")]
-// pub(crate) const MAX_SIMD_VALUE_STACK_SIZE: usize = u16::MAX as usize;
+pub(crate) const SIMD_VALUE_STACK_SIZE: usize = 1024 * 32;
#[cfg(feature = "simd")]
use crate::runtime::raw_simd::RawSimdWasmValue;
@@ -27,10 +23,10 @@ pub(crate) struct ValueStack {
impl Default for ValueStack {
fn default() -> Self {
Self {
- stack: BoxVec::with_capacity(MIN_VALUE_STACK_SIZE),
+ stack: BoxVec::with_capacity(VALUE_STACK_SIZE),
#[cfg(feature = "simd")]
- simd_stack: BoxVec::with_capacity(MIN_SIMD_VALUE_STACK_SIZE),
+ simd_stack: BoxVec::with_capacity(SIMD_VALUE_STACK_SIZE),
}
}
}
@@ -58,20 +54,17 @@ impl ValueStack {
}
#[inline(always)]
- pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> {
- if self.stack.end < 2 {
- cold(); // cold in here instead of the stack makes a huge performance difference
- return Err(Error::ValueStackUnderflow);
- }
-
- assert!(
- self.stack.end >= 2 && self.stack.end <= self.stack.data.len(),
- "invalid stack state (should be impossible)"
- );
- self.stack.data[self.stack.end - 2] =
- func(self.stack.data[self.stack.end - 2], self.stack.data[self.stack.end - 1]);
+ pub(crate) fn replace_top_trap(&mut self, func: fn(RawWasmValue) -> Result<RawWasmValue>) -> Result<()> {
+ let v = self.last_mut()?;
+ *v = func(*v)?;
+ Ok(())
+ }
- self.stack.end -= 1;
+ #[inline(always)]
+ pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> {
+ let v2 = self.pop()?;
+ let v1 = self.last_mut()?;
+ *v1 = func(*v1, v2);
Ok(())
}
@@ -154,7 +147,7 @@ impl ValueStack {
#[inline]
pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result<Vec<WasmValue>> {
#[cfg(not(feature = "simd"))]
- return Ok(self.pop_n_rev(types.len())?.zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect());
+ return Ok(self.pop_n(types.len())?.iter().zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect());
#[cfg(feature = "simd")]
{
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index e480577..9d6cdaf 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -81,12 +81,11 @@ impl MemoryInstance {
if end > self.data.len() {
return Err(self.trap_oob(addr, SIZE));
}
- let val = T::from_le_bytes(match self.data[addr..end].try_into() {
+
+ Ok(T::from_le_bytes(match self.data[addr..end].try_into() {
Ok(bytes) => bytes,
Err(_) => unreachable!("checked bounds above"),
- });
-
- Ok(val)
+ }))
}
#[inline]
@@ -99,8 +98,7 @@ impl MemoryInstance {
if end > self.data.len() {
return Err(self.trap_oob(addr, len));
}
-
- self.data[addr..end].fill(val);
+ self.data[addr..end].fill_with(|| val);
Ok(())
}
@@ -132,15 +130,13 @@ impl MemoryInstance {
Ok(())
}
+ #[inline]
pub(crate) fn grow(&mut self, pages_delta: i32) -> Option<i32> {
let current_pages = self.page_count();
let new_pages = current_pages as i64 + pages_delta as i64;
+ debug_assert!(new_pages <= i32::MAX as i64, "page count should never be greater than i32::MAX");
- if new_pages < 0 || new_pages > MAX_PAGES as i64 {
- return None;
- }
-
- if new_pages as usize > self.max_pages() {
+ if new_pages < 0 || new_pages > MAX_PAGES as i64 || new_pages as usize > self.max_pages() {
return None;
}
@@ -150,20 +146,26 @@ impl MemoryInstance {
}
// Zero initialize the new pages
- self.data.resize(new_size, 0);
+ self.data.reserve_exact(new_size);
+ self.data.resize_with(new_size, Default::default);
self.page_count = new_pages as usize;
- debug_assert!(current_pages <= i32::MAX as usize, "page count should never be greater than i32::MAX");
Some(current_pages as i32)
}
}
+/// A trait for types that can be stored in memory
+pub(crate) trait MemStorable<const N: usize> {
+ /// Store a value in memory
+ fn to_mem_bytes(self) -> [u8; N];
+}
+
/// A trait for types that can be loaded from memory
-pub(crate) trait MemLoadable<const T: usize>: Sized + Copy {
+pub(crate) trait MemLoadable<const N: usize>: Sized + Copy {
/// Load a value from memory
- fn from_le_bytes(bytes: [u8; T]) -> Self;
+ fn from_le_bytes(bytes: [u8; N]) -> Self;
}
-macro_rules! impl_mem_loadable_for_primitive {
+macro_rules! impl_mem_traits {
($($type:ty, $size:expr),*) => {
$(
impl MemLoadable<$size> for $type {
@@ -172,13 +174,18 @@ macro_rules! impl_mem_loadable_for_primitive {
<$type>::from_le_bytes(bytes)
}
}
+
+ impl MemStorable<$size> for $type {
+ #[inline(always)]
+ fn to_mem_bytes(self) -> [u8; $size] {
+ self.to_ne_bytes()
+ }
+ }
)*
}
}
-impl_mem_loadable_for_primitive!(
- u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16
-);
+impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16);
#[cfg(test)]
mod memory_instance_tests {
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 6617988..f72dcab 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -112,55 +112,55 @@ impl Store {
}
/// Get the function at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_func(&self, addr: FuncAddr) -> Result<&FunctionInstance> {
self.data.funcs.get(addr as usize).ok_or_else(|| Self::not_found_error("function"))
}
/// Get the memory at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&RefCell<MemoryInstance>> {
self.data.memories.get(addr as usize).ok_or_else(|| Self::not_found_error("memory"))
}
/// Get the table at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&RefCell<TableInstance>> {
self.data.tables.get(addr as usize).ok_or_else(|| Self::not_found_error("table"))
}
/// Get the data at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_data(&self, addr: DataAddr) -> Result<&DataInstance> {
self.data.datas.get(addr as usize).ok_or_else(|| Self::not_found_error("data"))
}
/// Get the data at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_data_mut(&mut self, addr: DataAddr) -> Result<&mut DataInstance> {
self.data.datas.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("data"))
}
/// Get the element at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_elem(&self, addr: ElemAddr) -> Result<&ElementInstance> {
self.data.elements.get(addr as usize).ok_or_else(|| Self::not_found_error("element"))
}
/// Get the element at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> Result<&mut ElementInstance> {
self.data.elements.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("element"))
}
/// Get the global at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&GlobalInstance> {
self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global"))
}
/// Get the global at the actual index in the store
- #[inline]
+ #[inline(always)]
pub fn get_global_val(&self, addr: MemAddr) -> Result<RawWasmValue> {
self.data
.globals
@@ -170,7 +170,7 @@ impl Store {
}
/// Set the global at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: RawWasmValue) -> Result<()> {
let global = self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global"));
global.map(|global| global.value.set(value))
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index bb1f96c..f9f861e 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -85,18 +85,16 @@ pub enum ConstInstruction {
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
// should be kept as small as possible (16 bytes max)
#[rustfmt::skip]
-#[non_exhaustive]
pub enum Instruction {
// > Custom Instructions
BrLabel(LabelAddr),
// LocalGet + I32Const + I32Add
- // One of the most common patterns in the Rust compiler output
I32LocalGetConstAdd(LocalAddr, i32),
- // LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const
- // Also common, helps us skip the stack entirely.
- // Has to be followed by an I32Const instruction
- I32StoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 },
- // I64Xor + I64Const + I64RotL
+ // LocalGet + I32Const + I32Store
+ I32ConstStoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 },
+ // LocalGet + LocalGet + I32Store
+ I32StoreLocal { local_a: LocalAddr, local_b: LocalAddr, offset: u32, mem_addr: u8 },
+ // I64Xor + I64Const + I64RotL
// Commonly used by a few crypto libraries
I64XorConstRotl(i64),
// LocalTee + LocalGet