summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-02-27 00:17:09 +0100
committerHenry Gressmann <mail@henrygressmann.de>2024-02-27 00:17:09 +0100
commit5e573f0765570e0aaf6c9415b652b25d5bddebd9 (patch)
tree5027b5c53413db89d40e6e87d30e09d07d5c2cc4
parent0fa1bca956229fa49509524aa7edd087439ea39a (diff)
no more simd
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--crates/benchmarks/benches/fibonacci.rs6
-rw-r--r--crates/parser/src/visit.rs69
-rw-r--r--crates/tinywasm/src/runtime/interpreter/macros.rs2
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs129
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs12
-rw-r--r--crates/tinywasm/src/runtime/stack/value_stack.rs10
-rw-r--r--crates/tinywasm/src/runtime/value.rs42
-rw-r--r--crates/types/src/instructions.rs26
-rw-r--r--crates/types/src/value.rs15
-rw-r--r--examples/rust/analyze.py36
10 files changed, 250 insertions, 97 deletions
diff --git a/crates/benchmarks/benches/fibonacci.rs b/crates/benchmarks/benches/fibonacci.rs
index 38bbde9..8a4dab2 100644
--- a/crates/benchmarks/benches/fibonacci.rs
+++ b/crates/benchmarks/benches/fibonacci.rs
@@ -17,10 +17,10 @@ fn run_wasmi(wasm: &[u8], iterations: i32, name: &str) {
fn run_wasmer(wasm: &[u8], iterations: i32, name: &str) {
use wasmer::*;
- let engine: Engine = wasmer::Singlepass::default().into();
- let mut store = Store::default();
+ let compiler = wasmer::Singlepass::default();
+ let mut store = Store::new(compiler);
let import_object = imports! {};
- let module = wasmer::Module::from_binary(&engine, wasm).expect("wasmer::Module::from_binary");
+ let module = wasmer::Module::from_binary(&store, wasm).expect("wasmer::Module::from_binary");
let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
let fib = instance.exports.get_typed_function::<i32, i32>(&store, name).expect("get_function");
fib.call(&mut store, iterations).expect("call");
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 15024f1..9038567 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -142,9 +142,6 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
define_primitive_operands! {
visit_br, Instruction::Br, u32,
visit_br_if, Instruction::BrIf, u32,
- visit_local_get, Instruction::LocalGet, u32,
- visit_local_set, Instruction::LocalSet, u32,
- visit_local_tee, Instruction::LocalTee, u32,
visit_global_get, Instruction::GlobalGet, u32,
visit_global_set, Instruction::GlobalSet, u32,
visit_i32_const, Instruction::I32Const, i32,
@@ -220,7 +217,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i32_clz, Instruction::I32Clz,
visit_i32_ctz, Instruction::I32Ctz,
visit_i32_popcnt, Instruction::I32Popcnt,
- visit_i32_add, Instruction::I32Add,
+ // visit_i32_add, Instruction::I32Add, custom implementation
visit_i32_sub, Instruction::I32Sub,
visit_i32_mul, Instruction::I32Mul,
visit_i32_div_s, Instruction::I32DivS,
@@ -251,7 +248,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i64_shl, Instruction::I64Shl,
visit_i64_shr_s, Instruction::I64ShrS,
visit_i64_shr_u, Instruction::I64ShrU,
- visit_i64_rotl, Instruction::I64Rotl,
+ // visit_i64_rotl, Instruction::I64Rotl, custom implementation
visit_i64_rotr, Instruction::I64Rotr,
visit_f32_abs, Instruction::F32Abs,
visit_f32_neg, Instruction::F32Neg,
@@ -325,6 +322,68 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U
}
+ fn visit_local_get(&mut self, idx: u32) -> Self::Output {
+ if let Some(instruction) = self.instructions.last_mut() {
+ match instruction {
+ // Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx),
+ // Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx),
+ // Instruction::LocalGet3(a, b, c) => *instruction = Instruction::LocalGet4(*a, *b, *c, idx),
+ // Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx),
+ _ => return self.visit(Instruction::LocalGet(idx)),
+ };
+ Ok(())
+ } else {
+ self.visit(Instruction::LocalGet(idx))
+ }
+ }
+
+ fn visit_local_set(&mut self, idx: u32) -> Self::Output {
+ // LocalGetSet
+ if let Some(instruction) = self.instructions.last_mut() {
+ match instruction {
+ // Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx),
+ _ => return self.visit(Instruction::LocalSet(idx)),
+ };
+ Ok(())
+ } else {
+ self.visit(Instruction::LocalSet(idx))
+ }
+ }
+
+ fn visit_local_tee(&mut self, idx: u32) -> Self::Output {
+ self.visit(Instruction::LocalTee(idx))
+ }
+
+ fn visit_i64_rotl(&mut self) -> Self::Output {
+ if self.instructions.len() < 2 {
+ return self.visit(Instruction::I64Rotl);
+ }
+
+ match self.instructions[self.instructions.len() - 2..] {
+ // [Instruction::I64Xor, Instruction::I64Const(a)] => {
+ // self.instructions.pop();
+ // self.instructions.pop();
+ // self.visit(Instruction::I64XorConstRotl(a))
+ // }
+ _ => self.visit(Instruction::I64Rotl),
+ }
+ }
+
+ fn visit_i32_add(&mut self) -> Self::Output {
+ if self.instructions.len() < 2 {
+ return self.visit(Instruction::I32Add);
+ }
+
+ match self.instructions[self.instructions.len() - 2..] {
+ // [Instruction::LocalGet(a), Instruction::I32Const(b)] => {
+ // self.instructions.pop();
+ // self.instructions.pop();
+ // self.visit(Instruction::I32LocalGetConstAdd(a, b))
+ // }
+ _ => self.visit(Instruction::I32Add),
+ }
+ }
+
fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output {
self.label_ptrs.push(self.instructions.len());
self.visit(Instruction::Block(convert_blocktype(blockty), 0))
diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs
index 18330a4..1da8758 100644
--- a/crates/tinywasm/src/runtime/interpreter/macros.rs
+++ b/crates/tinywasm/src/runtime/interpreter/macros.rs
@@ -11,7 +11,7 @@
// from a function, so we need to check if the label stack is empty
macro_rules! break_to {
($cf:ident, $stack:ident, $break_to_relative:ident) => {{
- if $cf.break_to(*$break_to_relative, &mut $stack.values, &mut $stack.blocks).is_none() {
+ if $cf.break_to($break_to_relative, &mut $stack.values, &mut $stack.blocks).is_none() {
if $stack.call_stack.is_empty() {
return Ok(ExecResult::Return);
} else {
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index b06152d..57e5f34 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -89,7 +89,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
// unreasonable complexity
// See https://pliniker.github.io/post/dispatchers/
use tinywasm_types::Instruction::*;
- match &instrs[cf.instr_ptr] {
+ match cf.current_instruction() {
Nop => { /* do nothing */ }
Unreachable => {
cold();
@@ -113,7 +113,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
Call(v) => {
// prepare the call frame
- let func_idx = module.resolve_func_addr(*v);
+ let func_idx = module.resolve_func_addr(v);
let func_inst = store.get_func(func_idx as usize)?.clone();
let wasm_func = match &func_inst.func {
@@ -140,7 +140,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
CallIndirect(type_addr, table_addr) => {
- let table = store.get_table(module.resolve_table_addr(*table_addr) as usize)?;
+ let table = store.get_table(module.resolve_table_addr(table_addr) as usize)?;
let table_idx = stack.values.pop_t::<u32>()?;
// verify that the table is of the right type, this should be validated by the parser already
@@ -155,7 +155,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
};
let func_inst = store.get_func(func_ref as usize)?.clone();
- let call_ty = module.func_ty(*type_addr);
+ let call_ty = module.func_ty(type_addr);
let wasm_func = match func_inst.func {
crate::Function::Wasm(ref f) => f.clone(),
@@ -202,10 +202,10 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
cf.enter_block(
BlockFrame::new(
cf.instr_ptr,
- cf.instr_ptr + *end_offset,
+ cf.instr_ptr + end_offset,
stack.values.len(),
BlockType::If,
- args,
+ &args,
module,
),
&mut stack.values,
@@ -217,17 +217,17 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
// falsy value is on the top of the stack
if let Some(else_offset) = else_offset {
let label = BlockFrame::new(
- cf.instr_ptr + *else_offset,
- cf.instr_ptr + *end_offset,
+ cf.instr_ptr + else_offset,
+ cf.instr_ptr + end_offset,
stack.values.len(),
BlockType::Else,
- args,
+ &args,
module,
);
- cf.instr_ptr += *else_offset;
+ cf.instr_ptr += else_offset;
cf.enter_block(label, &mut stack.values, &mut stack.blocks);
} else {
- cf.instr_ptr += *end_offset;
+ cf.instr_ptr += end_offset;
}
}
@@ -235,10 +235,10 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
cf.enter_block(
BlockFrame::new(
cf.instr_ptr,
- cf.instr_ptr + *end_offset,
+ cf.instr_ptr + end_offset,
stack.values.len(),
BlockType::Loop,
- args,
+ &args,
module,
),
&mut stack.values,
@@ -250,10 +250,10 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
cf.enter_block(
BlockFrame::new(
cf.instr_ptr,
- cf.instr_ptr + *end_offset,
+ cf.instr_ptr + end_offset,
stack.values.len(), // - params,
BlockType::Block,
- args,
+ &args,
module,
),
&mut stack.values,
@@ -262,7 +262,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
BrTable(default, len) => {
- let instr = instrs[cf.instr_ptr + 1..cf.instr_ptr + 1 + *len]
+ let instr = cf.instructions()[cf.instr_ptr + 1..cf.instr_ptr + 1 + len]
.iter()
.map(|i| match i {
BrLabel(l) => Ok(*l),
@@ -273,7 +273,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
})
.collect::<Result<Vec<_>>>()?;
- if unlikely(instr.len() != *len) {
+ if unlikely(instr.len() != len) {
panic!(
"Expected {} BrLabel instructions, got {}, this should have been validated by the parser",
len,
@@ -282,7 +282,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
let idx = stack.values.pop_t::<i32>()? as usize;
- let to = instr.get(idx).unwrap_or(default);
+ let to = *instr.get(idx).unwrap_or(&default);
break_to!(cf, stack, to);
}
@@ -319,7 +319,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let res_count = block.results;
stack.values.truncate_keep(block.stack_ptr, res_count);
- cf.instr_ptr += *end_offset;
+ cf.instr_ptr += end_offset;
}
EndBlockFrame => {
@@ -332,55 +332,53 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
stack.values.truncate_keep(block.stack_ptr, block.results);
}
- LocalGet(local_index) => stack.values.push(cf.get_local(*local_index as usize)),
- LocalSet(local_index) => cf.set_local(*local_index as usize, stack.values.pop()?),
+ LocalGet(local_index) => stack.values.push(cf.get_local(local_index as usize)),
+ LocalSet(local_index) => cf.set_local(local_index as usize, stack.values.pop()?),
LocalTee(local_index) => {
- let last_val = match stack.values.last() {
- Ok(val) => val,
- Err(_) => {
- log::error!("index: {}", local_index);
- log::error!("stack: {:?}", stack.values);
-
- panic!();
- }
- };
- cf.set_local(*local_index as usize, *last_val)
+ cf.set_local(
+ local_index as usize,
+ stack
+ .values
+ .last()
+ .expect("localtee: stack is empty. this should have been validated by the parser")
+ .clone(),
+ );
}
GlobalGet(global_index) => {
- let idx = module.resolve_global_addr(*global_index);
+ let idx = module.resolve_global_addr(global_index);
let global = store.get_global_val(idx as usize)?;
stack.values.push(global);
}
GlobalSet(global_index) => {
- let idx = module.resolve_global_addr(*global_index);
+ let idx = module.resolve_global_addr(global_index);
store.set_global_val(idx as usize, stack.values.pop()?)?;
}
- I32Const(val) => stack.values.push((*val).into()),
- I64Const(val) => stack.values.push((*val).into()),
- F32Const(val) => stack.values.push((*val).into()),
- F64Const(val) => stack.values.push((*val).into()),
+ I32Const(val) => stack.values.push((val).into()),
+ I64Const(val) => stack.values.push((val).into()),
+ F32Const(val) => stack.values.push((val).into()),
+ F64Const(val) => stack.values.push((val).into()),
MemorySize(addr, byte) => {
- if *byte != 0 {
+ if byte != 0 {
cold();
return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string()));
}
- let mem_idx = module.resolve_mem_addr(*addr);
+ let mem_idx = module.resolve_mem_addr(addr);
let mem = store.get_mem(mem_idx as usize)?;
stack.values.push((mem.borrow().page_count() as i32).into());
}
MemoryGrow(addr, byte) => {
- if *byte != 0 {
+ if byte != 0 {
cold();
return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string()));
}
- let mem_idx = module.resolve_mem_addr(*addr);
+ let mem_idx = module.resolve_mem_addr(addr);
let mem = store.get_mem(mem_idx as usize)?;
let (res, prev_size) = {
@@ -401,7 +399,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let src = stack.values.pop_t::<i32>()?;
let dst = stack.values.pop_t::<i32>()?;
- let mem = store.get_mem(module.resolve_mem_addr(*from) as usize)?;
+ let mem = store.get_mem(module.resolve_mem_addr(from) as usize)?;
let mut mem = mem.borrow_mut();
if from == to {
@@ -409,7 +407,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
mem.copy_within(dst as usize, src as usize, size as usize)?;
} else {
// copy between two memories
- let mem2 = store.get_mem(module.resolve_mem_addr(*to) as usize)?;
+ let mem2 = store.get_mem(module.resolve_mem_addr(to) as usize)?;
let mut mem2 = mem2.borrow_mut();
mem2.copy_from_slice(dst as usize, mem.load(src as usize, 0, size as usize)?)?;
}
@@ -420,7 +418,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let val = stack.values.pop_t::<i32>()?;
let dst = stack.values.pop_t::<i32>()?;
- let mem = store.get_mem(module.resolve_mem_addr(*addr) as usize)?;
+ let mem = store.get_mem(module.resolve_mem_addr(addr) as usize)?;
let mut mem = mem.borrow_mut();
mem.fill(dst as usize, size as usize, val as u8)?;
}
@@ -430,13 +428,13 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let offset = stack.values.pop_t::<i32>()? as usize;
let dst = stack.values.pop_t::<i32>()? as usize;
- let data_idx = module.resolve_data_addr(*data_index);
+ let data_idx = module.resolve_data_addr(data_index);
let Some(ref data) = store.get_data(data_idx as usize)?.data else {
cold();
return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into());
};
- let mem_idx = module.resolve_mem_addr(*mem_index);
+ let mem_idx = module.resolve_mem_addr(mem_index);
let mem = store.get_mem(mem_idx as usize)?;
let data_len = data.len();
@@ -453,7 +451,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
DataDrop(data_index) => {
- let data_idx = module.resolve_data_addr(*data_index);
+ let data_idx = module.resolve_data_addr(data_index);
let data = store.get_data_mut(data_idx as usize)?;
data.drop();
}
@@ -632,7 +630,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
I64TruncF64U => checked_conv_float!(f64, u64, i64, stack),
TableGet(table_index) => {
- let table_idx = module.resolve_table_addr(*table_index);
+ let table_idx = module.resolve_table_addr(table_index);
let table = store.get_table(table_idx as usize)?;
let idx = stack.values.pop_t::<i32>()? as usize;
let v = table.borrow().get_wasm_val(idx)?;
@@ -640,7 +638,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
TableSet(table_index) => {
- let table_idx = module.resolve_table_addr(*table_index);
+ let table_idx = module.resolve_table_addr(table_index);
let table = store.get_table(table_idx as usize)?;
let val = stack.values.pop_t::<u32>()?;
let idx = stack.values.pop_t::<u32>()? as usize;
@@ -648,16 +646,16 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
TableSize(table_index) => {
- let table_idx = module.resolve_table_addr(*table_index);
+ let table_idx = module.resolve_table_addr(table_index);
let table = store.get_table(table_idx as usize)?;
stack.values.push(table.borrow().size().into());
}
TableInit(table_index, elem_index) => {
- let table_idx = module.resolve_table_addr(*table_index);
+ let table_idx = module.resolve_table_addr(table_index);
let table = store.get_table(table_idx as usize)?;
- let elem_idx = module.resolve_elem_addr(*elem_index);
+ let elem_idx = module.resolve_elem_addr(elem_index);
let elem = store.get_elem(elem_idx as usize)?;
if let ElementKind::Passive = elem.kind {
@@ -680,6 +678,33 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, stack),
I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, stack),
+ // custom instructions
+ LocalGet2(a, b) => {
+ stack.values.push(cf.get_local(a as usize));
+ stack.values.push(cf.get_local(b as usize));
+ }
+ LocalGet3(a, b, c) => {
+ stack.values.push(cf.get_local(a as usize));
+ stack.values.push(cf.get_local(b as usize));
+ stack.values.push(cf.get_local(c as usize));
+ }
+ LocalGet4(a, b, c, d) => {
+ stack.values.push(cf.get_local(a as usize));
+ stack.values.push(cf.get_local(b as usize));
+ stack.values.push(cf.get_local(c as usize));
+ stack.values.push(cf.get_local(d as usize));
+ }
+ LocalTeeGet(a, b) => {
+ let last =
+ *stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser");
+ cf.set_local(a as usize, last);
+ stack.values.push(cf.get_local(b as usize));
+ }
+
+ // LocalTeeGet
+ // LocalGetSet
+ // I64XorConstRotl
+ // I32LocalGetConstAdd
i => {
cold();
log::error!("unimplemented instruction: {:?}", i);
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs
index 1c441a8..dd80bb7 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/call_stack.rs
@@ -1,5 +1,5 @@
use alloc::{boxed::Box, rc::Rc, vec::Vec};
-use tinywasm_types::{ModuleInstanceAddr, WasmFunction};
+use tinywasm_types::{Instruction, ModuleInstanceAddr, WasmFunction};
use crate::runtime::{BlockType, RawWasmValue};
use crate::unlikely;
@@ -142,4 +142,14 @@ impl CallFrame {
pub(crate) fn get_local(&self, local_index: usize) -> RawWasmValue {
self.locals[local_index]
}
+
+ #[inline]
+ pub(crate) fn instructions(&self) -> &[Instruction] {
+ &self.func_instance.0.instructions
+ }
+
+ #[inline(always)]
+ pub(crate) fn current_instruction(&self) -> Instruction {
+ self.func_instance.0.instructions[self.instr_ptr]
+ }
}
diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs
index 9649177..be5b53b 100644
--- a/crates/tinywasm/src/runtime/stack/value_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/value_stack.rs
@@ -58,14 +58,8 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn last(&self) -> Result<&RawWasmValue> {
- match self.stack.last() {
- Some(v) => Ok(v),
- None => {
- cold();
- Err(Error::ValueStackUnderflow)
- }
- }
+ pub(crate) fn last(&self) -> Option<&RawWasmValue> {
+ self.stack.last()
}
#[inline]
diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs
index 4e1b746..56fdf60 100644
--- a/crates/tinywasm/src/runtime/value.rs
+++ b/crates/tinywasm/src/runtime/value.rs
@@ -8,7 +8,8 @@ use tinywasm_types::{ValType, WasmValue};
/// See [`WasmValue`] for the public representation.
#[derive(Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
-pub struct RawWasmValue([u8; 16]);
+// pub struct RawWasmValue([u8; 16]);
+pub struct RawWasmValue([u8; 8]);
impl Debug for RawWasmValue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
@@ -18,7 +19,7 @@ impl Debug for RawWasmValue {
impl RawWasmValue {
#[inline(always)]
- pub fn raw_value(&self) -> [u8; 16] {
+ pub fn raw_value(&self) -> [u8; 8] {
self.0
}
@@ -29,7 +30,7 @@ impl RawWasmValue {
ValType::I64 => WasmValue::I64(self.into()),
ValType::F32 => WasmValue::F32(f32::from_bits(self.into())),
ValType::F64 => WasmValue::F64(f64::from_bits(self.into())),
- ValType::V128 => WasmValue::V128(self.into()),
+ // ValType::V128 => WasmValue::V128(self.into()),
ValType::RefExtern => {
let val: i64 = self.into();
if val < 0 {
@@ -58,7 +59,7 @@ impl From<WasmValue> for RawWasmValue {
WasmValue::I64(i) => Self::from(i),
WasmValue::F32(i) => Self::from(i),
WasmValue::F64(i) => Self::from(i),
- WasmValue::V128(i) => Self::from(i),
+ // WasmValue::V128(i) => Self::from(i),
WasmValue::RefExtern(v) => Self::from(v as i64),
WasmValue::RefFunc(v) => Self::from(v as i64),
WasmValue::RefNull(_) => Self::from(-1i64),
@@ -72,8 +73,8 @@ macro_rules! impl_from_raw_wasm_value {
impl From<$type> for RawWasmValue {
#[inline]
fn from(value: $type) -> Self {
- #[allow(clippy::redundant_closure_call)] // the comiler will figure it out :)
- Self(u128::to_ne_bytes($to_raw(value)))
+ #[allow(clippy::redundant_closure_call)]
+ Self(u64::to_ne_bytes($to_raw(value)))
}
}
@@ -81,29 +82,32 @@ macro_rules! impl_from_raw_wasm_value {
impl From<RawWasmValue> for $type {
#[inline]
fn from(value: RawWasmValue) -> Self {
- #[allow(clippy::redundant_closure_call)] // the comiler will figure it out :)
+ #[allow(clippy::redundant_closure_call)]
$from_raw(value.0)
}
}
};
}
+type RawValue = u64;
+type RawValueRep = [u8; 8];
+
// This all looks like a lot of extra steps, but the compiler will optimize it all away.
-// The u128 just makes it a bit easier to write.
-impl_from_raw_wasm_value!(i32, |x| x as u128, |x: [u8; 16]| i32::from_ne_bytes(x[0..4].try_into().unwrap()));
-impl_from_raw_wasm_value!(i64, |x| x as u128, |x: [u8; 16]| i64::from_ne_bytes(x[0..8].try_into().unwrap()));
-impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u128, |x: [u8; 16]| f32::from_bits(u32::from_ne_bytes(
+// The `u128` is used to make the conversion easier to write.
+impl_from_raw_wasm_value!(i32, |x| x as RawValue, |x: RawValueRep| i32::from_ne_bytes(x[0..4].try_into().unwrap()));
+impl_from_raw_wasm_value!(i64, |x| x as RawValue, |x: RawValueRep| i64::from_ne_bytes(x[0..8].try_into().unwrap()));
+impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as RawValue, |x: RawValueRep| f32::from_bits(u32::from_ne_bytes(
x[0..4].try_into().unwrap()
)));
-impl_from_raw_wasm_value!(f64, |x| f64::to_bits(x) as u128, |x: [u8; 16]| f64::from_bits(u64::from_ne_bytes(
+impl_from_raw_wasm_value!(f64, |x| f64::to_bits(x) as RawValue, |x: RawValueRep| f64::from_bits(u64::from_ne_bytes(
x[0..8].try_into().unwrap()
)));
-impl_from_raw_wasm_value!(u8, |x| x as u128, |x: [u8; 16]| u8::from_ne_bytes(x[0..1].try_into().unwrap()));
-impl_from_raw_wasm_value!(u16, |x| x as u128, |x: [u8; 16]| u16::from_ne_bytes(x[0..2].try_into().unwrap()));
-impl_from_raw_wasm_value!(u32, |x| x as u128, |x: [u8; 16]| u32::from_ne_bytes(x[0..4].try_into().unwrap()));
-impl_from_raw_wasm_value!(u64, |x| x as u128, |x: [u8; 16]| u64::from_ne_bytes(x[0..8].try_into().unwrap()));
-impl_from_raw_wasm_value!(u128, |x| x, |x: [u8; 16]| u128::from_ne_bytes(x.try_into().unwrap()));
+impl_from_raw_wasm_value!(u8, |x| x as RawValue, |x: RawValueRep| u8::from_ne_bytes(x[0..1].try_into().unwrap()));
+impl_from_raw_wasm_value!(u16, |x| x as RawValue, |x: RawValueRep| u16::from_ne_bytes(x[0..2].try_into().unwrap()));
+impl_from_raw_wasm_value!(u32, |x| x as RawValue, |x: RawValueRep| u32::from_ne_bytes(x[0..4].try_into().unwrap()));
+impl_from_raw_wasm_value!(u64, |x| x as RawValue, |x: RawValueRep| u64::from_ne_bytes(x[0..8].try_into().unwrap()));
+// impl_from_raw_wasm_value!(u128, |x| x, |x: RawValueRep| RawValue::from_ne_bytes(x));
-impl_from_raw_wasm_value!(i8, |x| x as u128, |x: [u8; 16]| i8::from_ne_bytes(x[0..1].try_into().unwrap()));
-impl_from_raw_wasm_value!(i16, |x| x as u128, |x: [u8; 16]| i16::from_ne_bytes(x[0..2].try_into().unwrap()));
+impl_from_raw_wasm_value!(i8, |x| x as RawValue, |x: RawValueRep| i8::from_ne_bytes(x[0..1].try_into().unwrap()));
+impl_from_raw_wasm_value!(i16, |x| x as RawValue, |x: RawValueRep| i16::from_ne_bytes(x[0..2].try_into().unwrap()));
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index fc12b54..dd941b3 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -54,6 +54,32 @@ pub enum Instruction {
// Custom Instructions
BrLabel(LabelAddr),
+ //== Not implemented yet, to be determined
+
+ // LocalGet + I32Const + I32Add
+ // One of the most common patterns in the Rust compiler output
+ I32LocalGetConstAdd(LocalAddr, i32),
+
+ // LocalGet + I32Const + I32Store
+ // Also common, helps us skip the stack entirely
+ I32LocalGetConstStore(LocalAddr, i32, MemoryArg), // I32Store + LocalGet + I32Const
+
+ // I64Xor + I64Const + I64RotL
+ // Commonly used by a few crypto libraries
+ I64XorConstRotl(i64),
+
+ // LocalTee + LocalGet
+ LocalTeeGet(LocalAddr, LocalAddr),
+ LocalGet2(LocalAddr, LocalAddr),
+ LocalGet3(LocalAddr, LocalAddr, LocalAddr),
+ LocalGet4(LocalAddr, LocalAddr, LocalAddr, LocalAddr),
+ LocalGetSet(LocalAddr, LocalAddr),
+
+ I32AddConst(i32),
+ I32SubConst(i32),
+ I64AddConst(i64),
+ I64SubConst(i64),
+
// Control Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
Unreachable,
diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs
index 3c02e55..8fd72fb 100644
--- a/crates/types/src/value.rs
+++ b/crates/types/src/value.rs
@@ -16,9 +16,8 @@ pub enum WasmValue {
F32(f32),
/// A 64-bit float.
F64(f64),
- /// A half of a 128-bit vector. Allways used in pairs.
- V128(u128),
-
+ // /// A 128-bit vector
+ // V128(u128),
RefExtern(ExternAddr),
RefFunc(FuncAddr),
RefNull(ValType),
@@ -49,7 +48,7 @@ impl WasmValue {
ValType::I64 => Self::I64(0),
ValType::F32 => Self::F32(0.0),
ValType::F64 => Self::F64(0.0),
- ValType::V128 => Self::V128(0),
+ // ValType::V128 => Self::V128(0),
ValType::RefFunc => Self::RefNull(ValType::RefFunc),
ValType::RefExtern => Self::RefNull(ValType::RefExtern),
}
@@ -92,7 +91,7 @@ impl Debug for WasmValue {
WasmValue::I64(i) => write!(f, "i64({})", i),
WasmValue::F32(i) => write!(f, "f32({})", i),
WasmValue::F64(i) => write!(f, "f64({})", i),
- WasmValue::V128(i) => write!(f, "v128.half({:?})", i),
+ // WasmValue::V128(i) => write!(f, "v128.half({:?})", i),
WasmValue::RefExtern(addr) => write!(f, "ref.extern({:?})", addr),
WasmValue::RefFunc(addr) => write!(f, "ref.func({:?})", addr),
WasmValue::RefNull(ty) => write!(f, "ref.null({:?})", ty),
@@ -109,7 +108,7 @@ impl WasmValue {
Self::I64(_) => ValType::I64,
Self::F32(_) => ValType::F32,
Self::F64(_) => ValType::F64,
- Self::V128(_) => ValType::V128,
+ // Self::V128(_) => ValType::V128,
Self::RefExtern(_) => ValType::RefExtern,
Self::RefFunc(_) => ValType::RefFunc,
Self::RefNull(ty) => *ty,
@@ -129,8 +128,8 @@ pub enum ValType {
F32,
/// A 64-bit float.
F64,
- /// A half of a 128-bit vector. Allways used in pairs.
- V128,
+ /// A 128-bit vector
+ // V128,
/// A reference to a function.
RefFunc,
/// A reference to an external value.
diff --git a/examples/rust/analyze.py b/examples/rust/analyze.py
new file mode 100644
index 0000000..a450a1a
--- /dev/null
+++ b/examples/rust/analyze.py
@@ -0,0 +1,36 @@
+import re
+import sys
+from collections import Counter
+
+seq_len = 5
+
+# Check if a file path was provided
+if len(sys.argv) < 2:
+ print("Usage: python script.py path/to/yourfile.wat")
+ sys.exit(1)
+
+# The first command line argument is the file path
+file_path = sys.argv[1]
+
+# Regex to match WASM operators, adjust as necessary
+operator_pattern = re.compile(r'\b[a-z0-9_]+\.[a-z0-9_]+\b')
+
+# Read the file
+with open(file_path, 'r') as file:
+ content = file.read()
+
+# Find all operators
+operators = operator_pattern.findall(content)
+
+# Generate sequences of three consecutive operators
+sequences = [' '.join(operators[i:i+seq_len]) for i in range(len(operators) - 2)]
+
+# Count occurrences of each sequence
+sequence_counts = Counter(sequences)
+
+# Sort sequences by their count, this time in ascending order for reverse display
+sorted_sequences = sorted(sequence_counts.items(), key=lambda x: x[1])
+
+# Print the sequences, now from least common to most common
+for sequence, count in sorted_sequences:
+ print(f"{sequence}: {count}")