summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/visit.rs136
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs2
-rw-r--r--crates/types/src/instructions.rs8
-rw-r--r--crates/types/src/lib.rs2
4 files changed, 135 insertions, 13 deletions
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 7da2d99..f263dcc 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -388,7 +388,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
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_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),
+ 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),
// 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),
@@ -446,6 +446,30 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
fn visit_drop(&mut self) -> Self::Output {
+ match self.instructions.last().copied() {
+ Some(Instruction::LocalTee32(local)) => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalSet32(local));
+ return;
+ }
+ Some(Instruction::LocalTee64(local)) => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalSet64(local));
+ return;
+ }
+ Some(Instruction::LocalTee128(local)) => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalSet128(local));
+ return;
+ }
+ Some(Instruction::LocalTeeRef(local)) => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalSetRef(local));
+ return;
+ }
+ _ => {}
+ }
+
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::Drop32,
@@ -491,6 +515,18 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
return;
}
+ if len >= 2 {
+ let lhs = self.instructions[len - 2];
+ let rhs = self.instructions[len - 1];
+ if let (Instruction::I32Const(c), Instruction::LocalGet32(local)) = (lhs, rhs) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalGet32(local));
+ self.instructions.push(Instruction::I32AddConst(c));
+ return;
+ }
+ }
+
self.instructions.push(Instruction::I32Add);
}
@@ -513,6 +549,18 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
return;
}
+ if len >= 2 {
+ let lhs = self.instructions[len - 2];
+ let rhs = self.instructions[len - 1];
+ if let (Instruction::I64Const(c), Instruction::LocalGet64(local)) = (lhs, rhs) {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalGet64(local));
+ self.instructions.push(Instruction::I64AddConst(c));
+ return;
+ }
+ }
+
self.instructions.push(Instruction::I64Add);
}
@@ -541,14 +589,44 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
};
match self.validator.get_local_type(idx) {
- Some(t) => self.instructions.push(match t {
- wasmparser::ValType::I32 => Instruction::LocalGet32(resolved_idx),
- wasmparser::ValType::F32 => Instruction::LocalGet32(resolved_idx),
- wasmparser::ValType::I64 => Instruction::LocalGet64(resolved_idx),
- wasmparser::ValType::F64 => Instruction::LocalGet64(resolved_idx),
- wasmparser::ValType::V128 => Instruction::LocalGet128(resolved_idx),
- wasmparser::ValType::Ref(_) => Instruction::LocalGetRef(resolved_idx),
- }),
+ Some(t) => match t {
+ wasmparser::ValType::I32 | wasmparser::ValType::F32 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalSet32(local)) if *local == resolved_idx)
+ {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalTee32(resolved_idx));
+ return;
+ }
+ self.instructions.push(Instruction::LocalGet32(resolved_idx));
+ }
+ wasmparser::ValType::I64 | wasmparser::ValType::F64 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalSet64(local)) if *local == resolved_idx)
+ {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalTee64(resolved_idx));
+ return;
+ }
+ self.instructions.push(Instruction::LocalGet64(resolved_idx));
+ }
+ wasmparser::ValType::V128 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalSet128(local)) if *local == resolved_idx)
+ {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalTee128(resolved_idx));
+ return;
+ }
+ self.instructions.push(Instruction::LocalGet128(resolved_idx));
+ }
+ wasmparser::ValType::Ref(_) => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalSetRef(local)) if *local == resolved_idx)
+ {
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalTeeRef(resolved_idx));
+ return;
+ }
+ self.instructions.push(Instruction::LocalGetRef(resolved_idx));
+ }
+ },
_ => {
self.visit_unreachable();
}
@@ -572,6 +650,12 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
{
let from = *from;
self.instructions.pop();
+
+ if from == resolved_idx {
+ // local.set x (local.get x) is a no-op; drop it.
+ return;
+ }
+
// validation will ensure that the last instruction is the correct local.get
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
@@ -612,6 +696,35 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
return;
};
+ if let Some(Some(t)) = self.validator.get_operand_type(0) {
+ match t {
+ wasmparser::ValType::I32 | wasmparser::ValType::F32 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalGet32(local)) if *local == resolved_idx)
+ {
+ return;
+ }
+ }
+ wasmparser::ValType::I64 | wasmparser::ValType::F64 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalGet64(local)) if *local == resolved_idx)
+ {
+ return;
+ }
+ }
+ wasmparser::ValType::V128 => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalGet128(local)) if *local == resolved_idx)
+ {
+ return;
+ }
+ }
+ wasmparser::ValType::Ref(_) => {
+ if matches!(self.instructions.last(), Some(Instruction::LocalGetRef(local)) if *local == resolved_idx)
+ {
+ 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)) => {
@@ -836,6 +949,11 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::Ref(_) => Instruction::SelectRef,
});
}
+
+ fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {}
+ fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {}
+ fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {}
+ fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {}
}
macro_rules! impl_visit_simd_operator {
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index bd2e31e..54ab12a 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -100,7 +100,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
#[rustfmt::skip]
match next {
- Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
+ Nop => {}
Unreachable => return Err(Trap::Unreachable.into()),
Drop32 => self.store.stack.values.drop::<Value32>(),
Drop64 => self.store.stack.values.drop::<Value64>(),
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 5e88cfa..bccbdd1 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -139,14 +139,17 @@ pub enum Instruction {
// See <https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions>
I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU,
I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU,
+
// Comparisons
F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge,
F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge,
I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU,
I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU,
+
// Bitwise
I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr,
I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr,
+
// Floating Point
F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign,
F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign,
@@ -154,8 +157,9 @@ pub enum Instruction {
I64Extend8S, I64Extend16S, I64Extend32S, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U,
F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64,
F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32,
- // Reinterpretations (noops at runtime)
- I32ReinterpretF32, I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64,
+
+ // Reinterpretations are parser no-ops and intentionally omitted.
+
// Saturating Float-to-Int Conversions
I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U,
I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U,
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 2a167a4..2f6107a 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -50,7 +50,7 @@ pub mod archive;
#[cfg(not(feature = "archive"))]
pub mod archive {
- #[cfg_attr(feature = "debug", derive(Debug))]
+ #[derive(Debug)]
pub enum TwasmError {}
impl core::fmt::Display for TwasmError {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {