diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 5993aed655..dc0409c004 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -111,29 +111,6 @@ void BytecodeInterpreter::load_and_push(Configuration& configuration, Instructio configuration.stack().peek() = Value(static_cast(read_value(slice))); } -void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data) -{ - auto& address = configuration.frame().module().memories().first(); - auto memory = configuration.store().get(address); - TRAP_IF_NOT(memory); - auto& arg = instruction.arguments().get(); - TRAP_IF_NOT(!configuration.stack().is_empty()); - auto entry = configuration.stack().pop(); - TRAP_IF_NOT(entry.has()); - auto base = entry.get().to(); - TRAP_IF_NOT(base.has_value()); - u64 instance_address = static_cast(bit_cast(base.value())) + arg.offset; - Checked addition { instance_address }; - addition += data.size(); - if (addition.has_overflow() || addition.value() > memory->size()) { - m_trap = Trap { "Memory access out of bounds" }; - dbgln("LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size()); - return; - } - dbgln_if(WASM_TRACE_DEBUG, "tempoaray({}b) -> store({})", data.size(), instance_address); - data.copy_to(memory->data().bytes().slice(instance_address, data.size())); -} - void BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address) { TRAP_IF_NOT(m_stack_info.size_free() >= Constants::minimum_stack_space_to_keep_free); @@ -224,16 +201,73 @@ void BytecodeInterpreter::unary_operation(Configuration& configuration) configuration.stack().peek() = Value(result); } -#define POP_AND_STORE(pop_type, store_type) \ - do { \ - TRAP_IF_NOT(!configuration.stack().is_empty()); \ - auto entry = configuration.stack().pop(); \ - TRAP_IF_NOT(entry.has()); \ - auto value = ConvertToRaw {}(*entry.get().to()); \ - dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(store_type)); \ - store_to_memory(configuration, instruction, { &value, sizeof(store_type) }); \ - return; \ - } while (false) +template +struct ConvertToRaw { + T operator()(T value) + { + return LittleEndian(value); + } +}; + +template<> +struct ConvertToRaw { + u32 operator()(float value) + { + LittleEndian res; + ReadonlyBytes bytes { &value, sizeof(float) }; + InputMemoryStream stream { bytes }; + stream >> res; + VERIFY(!stream.has_any_error()); + return static_cast(res); + } +}; + +template<> +struct ConvertToRaw { + u64 operator()(double value) + { + LittleEndian res; + ReadonlyBytes bytes { &value, sizeof(double) }; + InputMemoryStream stream { bytes }; + stream >> res; + VERIFY(!stream.has_any_error()); + return static_cast(res); + } +}; + +template +void BytecodeInterpreter::pop_and_store(Configuration& configuration, Instruction const& instruction) +{ + TRAP_IF_NOT(!configuration.stack().is_empty()); + auto entry = configuration.stack().pop(); + TRAP_IF_NOT(entry.has()); + auto value = ConvertToRaw {}(*entry.get().to()); + dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(StoreT)); + store_to_memory(configuration, instruction, { &value, sizeof(StoreT) }); +} + +void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data) +{ + auto& address = configuration.frame().module().memories().first(); + auto memory = configuration.store().get(address); + TRAP_IF_NOT(memory); + auto& arg = instruction.arguments().get(); + TRAP_IF_NOT(!configuration.stack().is_empty()); + auto entry = configuration.stack().pop(); + TRAP_IF_NOT(entry.has()); + auto base = entry.get().to(); + TRAP_IF_NOT(base.has_value()); + u64 instance_address = static_cast(bit_cast(base.value())) + arg.offset; + Checked addition { instance_address }; + addition += data.size(); + if (addition.has_overflow() || addition.value() > memory->size()) { + m_trap = Trap { "Memory access out of bounds" }; + dbgln("LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size()); + return; + } + dbgln_if(WASM_TRACE_DEBUG, "tempoaray({}b) -> store({})", data.size(), instance_address); + data.copy_to(memory->data().bytes().slice(instance_address, data.size())); +} template T BytecodeInterpreter::read_value(ReadonlyBytes data) @@ -270,40 +304,6 @@ double BytecodeInterpreter::read_value(ReadonlyBytes data) return bit_cast(static_cast(raw_value)); } -template -struct ConvertToRaw { - T operator()(T value) - { - return LittleEndian(value); - } -}; - -template<> -struct ConvertToRaw { - u32 operator()(float value) - { - LittleEndian res; - ReadonlyBytes bytes { &value, sizeof(float) }; - InputMemoryStream stream { bytes }; - stream >> res; - VERIFY(!stream.has_any_error()); - return static_cast(res); - } -}; - -template<> -struct ConvertToRaw { - u64 operator()(double value) - { - LittleEndian res; - ReadonlyBytes bytes { &value, sizeof(double) }; - InputMemoryStream stream { bytes }; - stream >> res; - VERIFY(!stream.has_any_error()); - return static_cast(res); - } -}; - template MakeSigned BytecodeInterpreter::checked_signed_truncate(V value) { @@ -550,23 +550,23 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi case Instructions::i64_load32_u.value(): return load_and_push(configuration, instruction); case Instructions::i32_store.value(): - POP_AND_STORE(i32, i32); + return pop_and_store(configuration, instruction); case Instructions::i64_store.value(): - POP_AND_STORE(i64, i64); + return pop_and_store(configuration, instruction); case Instructions::f32_store.value(): - POP_AND_STORE(float, float); + return pop_and_store(configuration, instruction); case Instructions::f64_store.value(): - POP_AND_STORE(double, double); + return pop_and_store(configuration, instruction); case Instructions::i32_store8.value(): - POP_AND_STORE(i32, i8); + return pop_and_store(configuration, instruction); case Instructions::i32_store16.value(): - POP_AND_STORE(i32, i16); + return pop_and_store(configuration, instruction); case Instructions::i64_store8.value(): - POP_AND_STORE(i64, i8); + return pop_and_store(configuration, instruction); case Instructions::i64_store16.value(): - POP_AND_STORE(i64, i16); + return pop_and_store(configuration, instruction); case Instructions::i64_store32.value(): - POP_AND_STORE(i64, i32); + return pop_and_store(configuration, instruction); case Instructions::local_tee.value(): { TRAP_IF_NOT(!configuration.stack().is_empty()); auto& entry = configuration.stack().peek(); diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h index 9a9912daed..8528578275 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h @@ -37,6 +37,8 @@ protected: void branch_to_label(Configuration&, LabelIndex); template void load_and_push(Configuration&, Instruction const&); + template + void pop_and_store(Configuration&, Instruction const&); void store_to_memory(Configuration&, Instruction const&, ReadonlyBytes data); void call_address(Configuration&, FunctionAddress);