diff options
| author | Henry Gressmann <mail@henrygressmann.de> | 2024-05-30 01:16:56 +0200 |
|---|---|---|
| committer | Henry Gressmann <mail@henrygressmann.de> | 2024-05-30 01:16:56 +0200 |
| commit | 7c3fd68f703d944b05dcea08f3a46c59b41503f4 (patch) | |
| tree | 4588645c28ea9775ae39f4875b019f72269dbb6f /crates | |
| parent | ffb1e095fc1d6a2d54cc7637797c625dee6ebe6a (diff) | |
chore: cleanup
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/parser/src/visit.rs | 64 | ||||
| -rw-r--r-- | crates/tinywasm/Cargo.toml | 2 | ||||
| -rw-r--r-- | crates/tinywasm/src/boxvec.rs | 12 | ||||
| -rw-r--r-- | crates/tinywasm/src/instance.rs | 33 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/interpreter/macros.rs | 41 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/interpreter/mod.rs | 148 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/raw.rs | 19 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/stack/call_stack.rs | 39 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/stack/value_stack.rs | 37 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/memory.rs | 45 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/mod.rs | 20 | ||||
| -rw-r--r-- | crates/types/src/instructions.rs | 12 |
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() }, ¶ms)?; 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() }, ¶ms)?; 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 |
