summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--crates/parser/src/visit.rs131
-rw-r--r--crates/tinywasm/benches/argon2id.rs8
-rw-r--r--crates/tinywasm/benches/tinywasm.rs8
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs102
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs38
-rw-r--r--crates/tinywasm/src/interpreter/values.rs37
-rw-r--r--crates/types/src/instructions.rs7
8 files changed, 211 insertions, 122 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c47dea..7452dbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,7 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Extern tables now correctly update their type after growing
- Increased MSRV to 1.80.0
- Simplify and optimize the interpreter loop
-- Use a seperate stack and locals for 32, 64 and 128 bit values and references (#21)
+- Use a separate stack and locals for 32, 64 and 128 bit values and references (#21)
- Updated to latest `wasmparser` version
- Removed benchmarks comparing TinyWasm to other WebAssembly runtimes to reduce build dependencies
- Memory and Data Instances are no longer reference counted
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index d02eb11..b71185e 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -325,11 +325,7 @@ impl<R: WasmModuleResources> FunctionBuilder<R> {
};
match frame.kind {
- FrameKind::Loop => {
- if let Instruction::Jump(target) = &mut self.instructions[jump_ip] {
- *target = self.ctx_stack[ctx_idx].start_ip as u32;
- }
- }
+ FrameKind::Loop => self.patch_jump(jump_ip, self.ctx_stack[ctx_idx].start_ip),
_ => self.ctx_stack[ctx_idx].branch_jumps.push(jump_ip),
}
}
@@ -385,12 +381,12 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
define_mem_operands! {
- visit_i32_load(I32Load), visit_i64_load(I64Load), visit_f32_load(F32Load), visit_f64_load(F64Load), visit_i32_load8_s(I32Load8S), visit_i32_load8_u(I32Load8U), visit_i32_load16_s(I32Load16S), visit_i32_load16_u(I32Load16U), visit_i64_load8_s(I64Load8S), visit_i64_load8_u(I64Load8U), visit_i64_load16_s(I64Load16S), visit_i64_load16_u(I64Load16U), visit_i64_load32_s(I64Load32S), visit_i64_load32_u(I64Load32U), visit_i32_store( I32Store), visit_i64_store(I64Store), visit_f32_store(F32Store), visit_f64_store(F64Store), visit_i32_store8(I32Store8), visit_i32_store16(I32Store16), visit_i64_store8(I64Store8), visit_i64_store16(I64Store16), visit_i64_store32(I64Store32)
+ visit_i32_load(I32Load), visit_i64_load(I64Load), visit_f32_load(F32Load), visit_f64_load(F64Load), visit_i32_load8_s(I32Load8S), visit_i32_load8_u(I32Load8U), visit_i32_load16_s(I32Load16S), visit_i32_load16_u(I32Load16U), visit_i64_load8_s(I64Load8S), visit_i64_load8_u(I64Load8U), visit_i64_load16_s(I64Load16S), visit_i64_load16_u(I64Load16U), visit_i64_load32_s(I64Load32S), visit_i64_load32_u(I64Load32U), visit_i64_store(I64Store), visit_f32_store(F32Store), visit_f64_store(F64Store), visit_i32_store8(I32Store8), visit_i32_store16(I32Store16), visit_i64_store8(I64Store8), visit_i64_store16(I64Store16), visit_i64_store32(I64Store32)
}
define_operands! {
// basic instructions
- visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_call(Call, u32), visit_return_call(ReturnCall, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), visit_nop(Nop), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), visit_i32_popcnt(I32Popcnt), visit_i32_add(I32Add), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), visit_i64_add(I64Add), visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), visit_i64_rotl(I64Rotl), visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), visit_i32_reinterpret_f32(I32ReinterpretF32), visit_i64_reinterpret_f64(I64ReinterpretF64), visit_f32_reinterpret_i32(F32ReinterpretI32), visit_f64_reinterpret_i64(F64ReinterpretI64),
+ visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_call(Call, u32), visit_return_call(ReturnCall, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), visit_nop(Nop), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), visit_i32_popcnt(I32Popcnt), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), visit_i32_reinterpret_f32(I32ReinterpretF32), visit_i64_reinterpret_f64(I64ReinterpretF64), visit_f32_reinterpret_i32(F32ReinterpretI32), visit_f64_reinterpret_i64(F64ReinterpretI64),
// sign_extension
visit_i32_extend8_s(I32Extend8S), visit_i32_extend16_s(I32Extend16S), visit_i64_extend8_s(I64Extend8S), visit_i64_extend16_s(I64Extend16S), visit_i64_extend32_s(I64Extend32S),
@@ -423,6 +419,23 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
}
+ fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output {
+ let memarg = MemoryArg::new(memarg.offset, memarg.memory);
+ let len = self.instructions.len();
+ if len >= 2 {
+ let addr = self.instructions[len - 2];
+ let value = self.instructions[len - 1];
+ if let (Instruction::LocalGet32(addr_local), Instruction::LocalGet32(value_local)) = (addr, value) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32StoreLocalLocal(memarg, addr_local, value_local));
+ return;
+ }
+ }
+
+ self.instructions.push(Instruction::I32Store(memarg));
+ }
+
fn visit_drop(&mut self) -> Self::Output {
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
@@ -447,21 +460,67 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
fn visit_return(&mut self) -> Self::Output {
- if let Some(instr) = self.instructions.last_mut() {
- match instr {
- Instruction::Call(addr) => {
- *instr = Instruction::ReturnCall(*addr);
- return;
- }
- Instruction::CallIndirect(ty, table) => {
- *instr = Instruction::ReturnCallIndirect(*ty, *table);
- return;
- }
- _ => {}
+ self.instructions.push(Instruction::Return);
+ }
+
+ fn visit_i32_add(&mut self) -> Self::Output {
+ let len = self.instructions.len();
+ if len >= 2 {
+ let lhs = self.instructions[len - 2];
+ let rhs = self.instructions[len - 1];
+ if let (Instruction::LocalGet32(a), Instruction::LocalGet32(b)) = (lhs, rhs) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32AddLocals(a, b));
+ return;
}
}
- self.instructions.push(Instruction::Return);
+ if let Some(Instruction::I32Const(c)) = self.instructions.last().copied() {
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32AddConst(c));
+ return;
+ }
+
+ self.instructions.push(Instruction::I32Add);
+ }
+
+ fn visit_i64_add(&mut self) -> Self::Output {
+ let len = self.instructions.len();
+ if len >= 2 {
+ let lhs = self.instructions[len - 2];
+ let rhs = self.instructions[len - 1];
+ if let (Instruction::LocalGet64(a), Instruction::LocalGet64(b)) = (lhs, rhs) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64AddLocals(a, b));
+ return;
+ }
+ }
+
+ if let Some(Instruction::I64Const(c)) = self.instructions.last().copied() {
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64AddConst(c));
+ return;
+ }
+
+ self.instructions.push(Instruction::I64Add);
+ }
+
+ fn visit_i64_rotl(&mut self) -> Self::Output {
+ let len = self.instructions.len();
+ if len >= 2 {
+ let lhs = self.instructions[len - 2];
+ let rhs = self.instructions[len - 1];
+ if let (Instruction::I64Xor, Instruction::I64Const(c)) = (lhs, rhs) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64XorRotlConst(c));
+ return;
+ }
+ }
+
+ self.instructions.push(Instruction::I64Rotl);
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
@@ -544,6 +603,34 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
return;
};
+ if let Some(Instruction::I64XorRotlConst(c)) = self.instructions.last().copied() {
+ match self.validator.get_operand_type(0) {
+ Some(Some(wasmparser::ValType::I64)) | Some(Some(wasmparser::ValType::F64)) => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64XorRotlConstTee(c, resolved_idx));
+ return;
+ }
+ _ => {}
+ }
+ }
+
+ let len = self.instructions.len();
+ if len >= 2 {
+ let addr = self.instructions[len - 2];
+ let load = self.instructions[len - 1];
+ if let (Instruction::LocalGet32(addr_local), Instruction::I32Load(memarg)) = (addr, load) {
+ match self.validator.get_operand_type(0) {
+ Some(Some(wasmparser::ValType::I32)) | Some(Some(wasmparser::ValType::F32)) => {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32LoadLocalTee(memarg, addr_local, resolved_idx));
+ return;
+ }
+ _ => {}
+ }
+ }
+ }
+
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::LocalTee32(resolved_idx),
@@ -595,6 +682,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
ctx.has_else = true;
ctx.branch_jumps.push(jump_ip);
self.patch_jump_if_zero(cond_jump_ip, self.instructions.len());
+ if !matches!(self.instructions.last(), Some(Instruction::Nop)) {
+ self.instructions.push(Instruction::Nop);
+ }
};
};
}
@@ -602,6 +692,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
fn visit_end(&mut self) -> Self::Output {
if let Some(ctx) = self.ctx_stack.pop() {
self.patch_end_jumps(ctx, self.instructions.len());
+ if !matches!(self.instructions.last(), Some(Instruction::Nop)) {
+ self.instructions.push(Instruction::Nop);
+ }
} else {
self.instructions.push(Instruction::Return);
}
diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs
index aa8b38b..ca08378 100644
--- a/crates/tinywasm/benches/argon2id.rs
+++ b/crates/tinywasm/benches/argon2id.rs
@@ -31,11 +31,11 @@ fn argon2id_run(module: TinyWasmModule) -> Result<()> {
fn criterion_benchmark(c: &mut Criterion) {
let module = argon2id_parse().expect("argon2id_parse");
- let twasm = argon2id_to_twasm(&module).expect("argon2id_to_twasm");
+ let _twasm = argon2id_to_twasm(&module).expect("argon2id_to_twasm");
- c.bench_function("argon2id_parse", |b| b.iter(argon2id_parse));
- c.bench_function("argon2id_to_twasm", |b| b.iter(|| argon2id_to_twasm(&module)));
- c.bench_function("argon2id_from_twasm", |b| b.iter(|| argon2id_from_twasm(&twasm)));
+ // c.bench_function("argon2id_parse", |b| b.iter(argon2id_parse));
+ // c.bench_function("argon2id_to_twasm", |b| b.iter(|| argon2id_to_twasm(&module)));
+ // c.bench_function("argon2id_from_twasm", |b| b.iter(|| argon2id_from_twasm(&twasm)));
c.bench_function("argon2id", |b| b.iter(|| argon2id_run(module.clone())));
}
diff --git a/crates/tinywasm/benches/tinywasm.rs b/crates/tinywasm/benches/tinywasm.rs
index 4848a4a..a949b52 100644
--- a/crates/tinywasm/benches/tinywasm.rs
+++ b/crates/tinywasm/benches/tinywasm.rs
@@ -33,11 +33,11 @@ fn tinywasm_run(module: TinyWasmModule) -> Result<()> {
fn criterion_benchmark(c: &mut Criterion) {
let module = tinywasm_parse().expect("tinywasm_parse");
- let twasm = tinywasm_to_twasm(&module).expect("tinywasm_to_twasm");
+ let _twasm = tinywasm_to_twasm(&module).expect("tinywasm_to_twasm");
- c.bench_function("tinywasm_parse", |b| b.iter(tinywasm_parse));
- c.bench_function("tinywasm_to_twasm", |b| b.iter(|| tinywasm_to_twasm(&module)));
- c.bench_function("tinywasm_from_twasm", |b| b.iter(|| tinywasm_from_twasm(&twasm)));
+ // c.bench_function("tinywasm_parse", |b| b.iter(tinywasm_parse));
+ // c.bench_function("tinywasm_to_twasm", |b| b.iter(|| tinywasm_to_twasm(&module)));
+ // c.bench_function("tinywasm_from_twasm", |b| b.iter(|| tinywasm_from_twasm(&twasm)));
c.bench_function("tinywasm", |b| b.iter(|| tinywasm_run(module.clone())));
}
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 02e91c5..1da799e 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -72,6 +72,10 @@ impl<'store> Executor<'store> {
(binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
self.store.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
};
+ (local_set_pop $ty:ty, $local_index:expr) => {{
+ let val = self.store.stack.values.pop::<$ty>();
+ self.store.stack.values.local_set(&self.cf, *$local_index, val);
+ }};
}
let next = match self.func.instructions.0.get(self.cf.instr_ptr) {
@@ -166,58 +170,58 @@ impl<'store> Executor<'store> {
return ControlFlow::Continue(());
}
Return => return self.exec_return(),
- LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get_32(&self.cf, *local_index)).to_cf()?,
- LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get_64(&self.cf, *local_index)).to_cf()?,
- LocalGet128(local_index) => self.store.stack.values.push(self.store.stack.values.local_get_128(&self.cf, *local_index)).to_cf()?,
- LocalGetRef(local_index) => self.store.stack.values.push(self.store.stack.values.local_get_ref(&self.cf, *local_index)).to_cf()?,
- LocalSet32(local_index) => {
- let val = self.store.stack.values.pop::<Value32>();
- self.store.stack.values.local_set_32(&self.cf, *local_index, val);
- }
- LocalSet64(local_index) => {
- let val = self.store.stack.values.pop::<Value64>();
- self.store.stack.values.local_set_64(&self.cf, *local_index, val);
- }
- LocalSet128(local_index) => {
- let val = self.store.stack.values.pop::<Value128>();
- self.store.stack.values.local_set_128(&self.cf, *local_index, val);
- }
- LocalSetRef(local_index) => {
- let val = self.store.stack.values.pop::<ValueRef>();
- self.store.stack.values.local_set_ref(&self.cf, *local_index, val);
- }
- LocalCopy32(from, to) => {
- let val = self.store.stack.values.local_get_32(&self.cf, *from);
- self.store.stack.values.local_set_32(&self.cf, *to, val);
- }
- LocalCopy64(from, to) => {
- let val = self.store.stack.values.local_get_64(&self.cf, *from);
- self.store.stack.values.local_set_64(&self.cf, *to, val);
- }
- LocalCopy128(from, to) => {
- let val = self.store.stack.values.local_get_128(&self.cf, *from);
- self.store.stack.values.local_set_128(&self.cf, *to, val);
- }
- LocalCopyRef(from, to) => {
- let val = self.store.stack.values.local_get_ref(&self.cf, *from);
- self.store.stack.values.local_set_ref(&self.cf, *to, val);
- }
- LocalTee32(local_index) => {
- let val = self.store.stack.values.peek::<Value32>();
- self.store.stack.values.local_set_32(&self.cf, *local_index, val);
- }
- LocalTee64(local_index) => {
- let val = self.store.stack.values.peek::<Value64>();
- self.store.stack.values.local_set_64(&self.cf, *local_index, val);
+ LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value32>(&self.cf, *local_index)).to_cf()?,
+ LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value64>(&self.cf, *local_index)).to_cf()?,
+ LocalGet128(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value128>(&self.cf, *local_index)).to_cf()?,
+ LocalGetRef(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<ValueRef>(&self.cf, *local_index)).to_cf()?,
+ LocalSet32(local_index) => stack_op!(local_set_pop Value32, local_index),
+ LocalSet64(local_index) => stack_op!(local_set_pop Value64, local_index),
+ LocalSet128(local_index) => stack_op!(local_set_pop Value128, local_index),
+ LocalSetRef(local_index) => stack_op!(local_set_pop ValueRef, local_index),
+ LocalCopy32(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value32>(&self.cf, *from)),
+ LocalCopy64(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value64>(&self.cf, *from)),
+ LocalCopy128(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value128>(&self.cf, *from)),
+ LocalCopyRef(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<ValueRef>(&self.cf, *from)),
+ I32AddLocals(a, b) => self.store.stack.values.push(
+ self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)),
+ ).to_cf()?,
+ I64AddLocals(a, b) => self.store.stack.values.push(
+ self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)),
+ ).to_cf()?,
+ I32AddConst(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)),
+ I64AddConst(c) => stack_op!(unary i64, |v| v.wrapping_add(*c)),
+ I32StoreLocalLocal(m, addr_local, value_local) => {
+ let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(m.mem_addr()));
+ let addr = u64::from(self.store.stack.values.local_get::<u32>(&self.cf, *addr_local));
+ let value = self.store.stack.values.local_get::<u32>(&self.cf, *value_local).to_mem_bytes();
+ if let Err(e) = mem.store((m.offset() + addr) as usize, value.len(), &value) {
+ return ControlFlow::Break(Some(e));
+ }
}
- LocalTee128(local_index) => {
- let val = self.store.stack.values.peek::<Value128>();
- self.store.stack.values.local_set_128(&self.cf, *local_index, val);
+ I32LoadLocalTee(m, addr_local, dst_local) => {
+ let mem = self.store.state.get_mem(self.module.resolve_mem_addr(m.mem_addr()));
+ let addr = u64::from(self.store.stack.values.local_get::<u32>(&self.cf, *addr_local));
+ let Some(Ok(addr)) = m.offset().checked_add(addr).map(|a| a.try_into()) else {
+ return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
+ offset: addr as usize,
+ len: 4,
+ max: 0,
+ })));
+ };
+ let value = mem.load_as::<4, i32>(addr).to_cf()?;
+ self.store.stack.values.local_set(&self.cf, *dst_local, value);
+ self.store.stack.values.push(value).to_cf()?;
}
- LocalTeeRef(local_index) => {
- let val = self.store.stack.values.peek::<ValueRef>();
- self.store.stack.values.local_set_ref(&self.cf, *local_index, val);
+ I64XorRotlConst(c) => stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32)),
+ I64XorRotlConstTee(c, local_index) => {
+ self.store.stack.values.binary_same::<i64>(|lhs, rhs| Ok((lhs ^ rhs).rotate_left(*c as u32))).to_cf()?;
+ let val = self.store.stack.values.peek::<i64>();
+ self.store.stack.values.local_set(&self.cf, *local_index, val);
}
+ LocalTee32(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value32>()),
+ LocalTee64(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value64>()),
+ LocalTee128(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value128>()),
+ LocalTeeRef(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<ValueRef>()),
GlobalGet(global_index) => self.exec_global_get(*global_index).to_cf()?,
GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index),
GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index),
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 76c4b28..b461f7a 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -268,43 +268,13 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn local_get_32(&self, frame: &CallFrame, index: LocalAddr) -> Value32 {
- self.stack_32.get(frame.locals_base.s32 + index as usize)
+ pub(crate) fn local_get<T: InternalValue>(&self, frame: &CallFrame, index: LocalAddr) -> T {
+ T::local_get(self, frame, index)
}
#[inline]
- pub(crate) fn local_get_64(&self, frame: &CallFrame, index: LocalAddr) -> Value64 {
- self.stack_64.get(frame.locals_base.s64 + index as usize)
- }
-
- #[inline]
- pub(crate) fn local_get_128(&self, frame: &CallFrame, index: LocalAddr) -> Value128 {
- self.stack_128.get(frame.locals_base.s128 + index as usize)
- }
-
- #[inline]
- pub(crate) fn local_get_ref(&self, frame: &CallFrame, index: LocalAddr) -> ValueRef {
- self.stack_ref.get(frame.locals_base.sref + index as usize)
- }
-
- #[inline]
- pub(crate) fn local_set_32(&mut self, frame: &CallFrame, index: LocalAddr, value: Value32) {
- self.stack_32.set(frame.locals_base.s32 + index as usize, value);
- }
-
- #[inline]
- pub(crate) fn local_set_64(&mut self, frame: &CallFrame, index: LocalAddr, value: Value64) {
- self.stack_64.set(frame.locals_base.s64 + index as usize, value);
- }
-
- #[inline]
- pub(crate) fn local_set_128(&mut self, frame: &CallFrame, index: LocalAddr, value: Value128) {
- self.stack_128.set(frame.locals_base.s128 + index as usize, value);
- }
-
- #[inline]
- pub(crate) fn local_set_ref(&mut self, frame: &CallFrame, index: LocalAddr, value: ValueRef) {
- self.stack_ref.set(frame.locals_base.sref + index as usize, value);
+ pub(crate) fn local_set<T: InternalValue>(&mut self, frame: &CallFrame, index: LocalAddr, value: T) {
+ T::local_set(self, frame, index, value);
}
pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) -> Result<()> {
diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs
index b1530e7..9b6e2c1 100644
--- a/crates/tinywasm/src/interpreter/values.rs
+++ b/crates/tinywasm/src/interpreter/values.rs
@@ -1,6 +1,7 @@
use crate::{Result, interpreter::value128::Value128};
-use super::stack::ValueStack;
+use super::stack::{CallFrame, ValueStack};
+use tinywasm_types::LocalAddr;
use tinywasm_types::{ExternRef, FuncRef, ValType, WasmValue};
pub(crate) type Value32 = u32;
@@ -105,6 +106,12 @@ mod sealed {
pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> {
fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()>;
+ fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self
+ where
+ Self: Sized;
+ fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self)
+ where
+ Self: Sized;
fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()>
where
Self: Sized;
@@ -124,7 +131,7 @@ pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> {
}
macro_rules! impl_internalvalue {
- ($( $variant:ident, $stack:ident, $internal:ty, $outer:ty, $to_internal:expr, $to_outer:expr )*) => {
+ ($( $variant:ident, $stack:ident, $stack_base:ident, $outer:ty, $to_internal:expr, $to_outer:expr )*) => {
$(
impl sealed::Sealed for $outer {}
@@ -141,6 +148,16 @@ macro_rules! impl_internalvalue {
}
#[inline]
+ fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self {
+ $to_outer(stack.$stack.get(frame.locals_base.$stack_base + index as usize))
+ }
+
+ #[inline]
+ fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self) {
+ stack.$stack.set(frame.locals_base.$stack_base + index as usize, $to_internal(value));
+ }
+
+ #[inline]
fn stack_pop(stack: &mut ValueStack) -> Self {
$to_outer(stack.$stack.pop())
}
@@ -179,12 +196,12 @@ macro_rules! impl_internalvalue {
}
impl_internalvalue! {
- Value32, stack_32, u32, u32, |v| v, |v| v
- Value64, stack_64, u64, u64, |v| v, |v| v
- Value32, stack_32, u32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes())
- Value64, stack_64, u64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes())
- Value32, stack_32, u32, f32, f32::to_bits, f32::from_bits
- Value64, stack_64, u64, f64, f64::to_bits, f64::from_bits
- ValueRef, stack_ref, ValueRef, ValueRef, |v| v, |v| v
- Value128, stack_128, Value128, Value128, |v| v, |v| v
+ Value32, stack_32, s32, u32, |v| v, |v| v
+ Value64, stack_64, s64, u64, |v| v, |v| v
+ Value32, stack_32, s32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes())
+ Value64, stack_64, s64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes())
+ Value32, stack_32, s32, f32, f32::to_bits, f32::from_bits
+ Value64, stack_64, s64, f64, f64::to_bits, f64::from_bits
+ ValueRef, stack_ref, sref, ValueRef, |v| v, |v| v
+ Value128, stack_128, s128, Value128, |v| v, |v| v
}
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 71b518f..7f0cef5 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -51,7 +51,12 @@ pub enum ConstInstruction {
#[rustfmt::skip]
pub enum Instruction {
LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), LocalCopyRef(LocalAddr, LocalAddr),
-
+ I32AddLocals(LocalAddr, LocalAddr), I64AddLocals(LocalAddr, LocalAddr),
+ I32AddConst(i32), I64AddConst(i64),
+ I32StoreLocalLocal(MemoryArg, LocalAddr, LocalAddr),
+ I32LoadLocalTee(MemoryArg, LocalAddr, LocalAddr),
+ I64XorRotlConst(i64),
+ I64XorRotlConstTee(i64, LocalAddr),
// > Control Instructions (jump-oriented, lowered from structured control during parsing)
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
Unreachable,