diff --git a/crates/ir/src/for_each_op.rs b/crates/ir/src/for_each_op.rs index d1e59c31bb..860f606b22 100644 --- a/crates/ir/src/for_each_op.rs +++ b/crates/ir/src/for_each_op.rs @@ -5623,7 +5623,7 @@ macro_rules! for_each_op { MemoryGrowBy { @result: Reg, /// The number of pages to add to the memory. - delta: Const16, + delta: u32, }, /// Wasm `memory.copy` instruction. diff --git a/crates/wasmi/src/engine/executor/instrs/memory.rs b/crates/wasmi/src/engine/executor/instrs/memory.rs index 89e35e4e91..7128128a48 100644 --- a/crates/wasmi/src/engine/executor/instrs/memory.rs +++ b/crates/wasmi/src/engine/executor/instrs/memory.rs @@ -76,9 +76,8 @@ impl<'engine> Executor<'engine> { &mut self, store: &mut Store, result: Reg, - delta: Const16, + delta: u32, ) -> Result<(), Error> { - let delta: u32 = delta.into(); let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref(); self.execute_memory_grow_impl(store, result, delta, &mut resource_limiter) } diff --git a/crates/wasmi/src/engine/translator/provider.rs b/crates/wasmi/src/engine/translator/provider.rs index 30730ef304..1fece98665 100644 --- a/crates/wasmi/src/engine/translator/provider.rs +++ b/crates/wasmi/src/engine/translator/provider.rs @@ -50,6 +50,14 @@ impl Provider { Self::Const(_) => None, } } + + /// Maps the constant value with `f` if `self` is [`Provider::Const`] and returns the result. + pub fn map_const(self, f: impl FnOnce(T) -> U) -> Provider { + match self { + Provider::Register(reg) => Provider::Register(reg), + Provider::Const(value) => Provider::Const(f(value)), + } + } } /// An untyped [`Provider`]. diff --git a/crates/wasmi/src/engine/translator/tests/op/memory/memory_grow.rs b/crates/wasmi/src/engine/translator/tests/op/memory/memory_grow.rs index 44ddd846d7..478f81a299 100644 --- a/crates/wasmi/src/engine/translator/tests/op/memory/memory_grow.rs +++ b/crates/wasmi/src/engine/translator/tests/op/memory/memory_grow.rs @@ -22,7 +22,7 @@ fn reg() { } fn test_imm16(delta: u32) { - assert!(1 <= delta && delta <= u32::from(u16::MAX)); + assert!(delta != 0); let wasm = &format!( r" (module @@ -35,7 +35,7 @@ fn test_imm16(delta: u32) { ); TranslationTest::from_wat(wasm) .expect_func_instrs([ - Instruction::memory_grow_by(Reg::from(0), u32imm16(delta)), + Instruction::memory_grow_by(Reg::from(0), delta), Instruction::memory_index(0), Instruction::return_reg(Reg::from(0)), ]) @@ -49,6 +49,9 @@ fn imm16() { test_imm16(42); test_imm16(u32::from(u16::MAX) - 1); test_imm16(u32::from(u16::MAX)); + test_imm16(u32::from(u16::MAX) + 1); + test_imm16(u32::MAX - 1); + test_imm16(u32::MAX); } #[test] @@ -69,34 +72,3 @@ fn imm_zero() { ]) .run(); } - -fn test_imm(delta: u32) { - let wasm = &format!( - r" - (module - (memory $m 10) - (func (result i32) - (i32.const {delta}) - (memory.grow $m) - ) - )", - ); - TranslationTest::from_wat(wasm) - .expect_func( - ExpectedFunc::new([ - Instruction::memory_grow(Reg::from(0), Reg::from(-1)), - Instruction::memory_index(0), - Instruction::return_reg(Reg::from(0)), - ]) - .consts([delta]), - ) - .run(); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn imm() { - test_imm(u32::from(u16::MAX) + 1); - test_imm(u32::MAX - 1); - test_imm(u32::MAX); -} diff --git a/crates/wasmi/src/engine/translator/visit.rs b/crates/wasmi/src/engine/translator/visit.rs index bd62e3359b..aad0240256 100644 --- a/crates/wasmi/src/engine/translator/visit.rs +++ b/crates/wasmi/src/engine/translator/visit.rs @@ -998,23 +998,19 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_memory_grow(&mut self, mem: u32, _mem_byte: u8) -> Self::Output { bail_unreachable!(self); - let delta = self.alloc.stack.pop(); - let delta = >>::new(delta, &mut self.alloc.stack)?; + let delta = self.alloc.stack.pop().map_const(u32::from); let memory = index::Memory::from(mem); let result = self.alloc.stack.push_dynamic()?; + if let Provider::Const(0) = delta { + // Case: growing by 0 pages. + // + // Since `memory.grow` returns the `memory.size` before the + // operation a `memory.grow` with `delta` of 0 can be translated + // as `memory.size` instruction instead. + self.push_fueled_instr(Instruction::memory_size(result, memory), FuelCosts::entity)?; + return Ok(()); + } let instr = match delta { - Provider::Const(delta) if u32::from(delta) == 0 => { - // Case: growing by 0 pages. - // - // Since `memory.grow` returns the `memory.size` before the - // operation a `memory.grow` with `delta` of 0 can be translated - // as `memory.size` instruction instead. - self.push_fueled_instr( - Instruction::memory_size(result, memory), - FuelCosts::entity, - )?; - return Ok(()); - } Provider::Const(delta) => Instruction::memory_grow_by(result, delta), Provider::Register(delta) => Instruction::memory_grow(result, delta), };