From 4c3071c7c209c2e53c73862be72c9b493f263e78 Mon Sep 17 00:00:00 2001 From: Diego <96022404+dzfrias@users.noreply.github.com> Date: Sat, 15 Jun 2024 11:13:15 -0700 Subject: [PATCH] LibWasm: Implement rest of table instructions --- .../AbstractMachine/AbstractMachine.cpp | 2 + .../AbstractMachine/BytecodeInterpreter.cpp | 76 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 68cad9c1449..7376d729dbd 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -340,6 +340,8 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vectorreferences().begin(); it < elem_instance->references().end(); ++i, ++it) { table_instance->elements()[i + d.value()] = *it; } + // Drop element + *m_store.get(main_module_instance.elements()[current_index]) = ElementInstance(elem_instance->type(), {}); } return IterationDecision::Continue; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 0e15bebc1c1..1dd6d506d8d 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -871,6 +872,78 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi *configuration.store().get(address) = ElementInstance(elem->type(), {}); return; } + case Instructions::table_init.value(): { + auto& args = instruction.arguments().get(); + auto table_address = configuration.frame().module().tables()[args.table_index.value()]; + auto table = configuration.store().get(table_address); + auto element_address = configuration.frame().module().elements()[args.element_index.value()]; + auto element = configuration.store().get(element_address); + auto count = *configuration.stack().pop().get().to(); + auto source_offset = *configuration.stack().pop().get().to(); + auto destination_offset = *configuration.stack().pop().get().to(); + + Checked checked_source_offset = source_offset; + Checked checked_destination_offset = destination_offset; + checked_source_offset += count; + checked_destination_offset += count; + TRAP_IF_NOT(!checked_source_offset.has_overflow() && checked_source_offset <= (u32)element->references().size()); + TRAP_IF_NOT(!checked_destination_offset.has_overflow() && checked_destination_offset <= (u32)table->elements().size()); + + for (u32 i = 0; i < count; ++i) + table->elements()[destination_offset + i] = element->references()[source_offset + i]; + return; + } + case Instructions::table_copy.value(): { + auto& args = instruction.arguments().get(); + auto source_address = configuration.frame().module().tables()[args.rhs.value()]; + auto destination_address = configuration.frame().module().tables()[args.lhs.value()]; + auto source_instance = configuration.store().get(source_address); + auto destination_instance = configuration.store().get(destination_address); + + auto count = configuration.stack().pop().get().to().value(); + auto source_offset = configuration.stack().pop().get().to().value(); + auto destination_offset = configuration.stack().pop().get().to().value(); + + Checked source_position = source_offset; + source_position.saturating_add(count); + Checked destination_position = destination_offset; + destination_position.saturating_add(count); + TRAP_IF_NOT(source_position <= source_instance->elements().size()); + TRAP_IF_NOT(destination_position <= destination_instance->elements().size()); + + if (count == 0) + return; + + if (destination_offset <= source_offset) { + for (u32 i = 0; i < count; ++i) { + auto value = source_instance->elements()[source_offset + i]; + destination_instance->elements()[destination_offset + i] = value; + } + } else { + for (u32 i = count - 1; i != NumericLimits::max(); --i) { + auto value = source_instance->elements()[source_offset + i]; + destination_instance->elements()[destination_offset + i] = value; + } + } + + return; + } + case Instructions::table_fill.value(): { + auto table_index = instruction.arguments().get(); + auto address = configuration.frame().module().tables()[table_index.value()]; + auto table = configuration.store().get(address); + auto count = *configuration.stack().pop().get().to(); + auto value = *configuration.stack().pop().get().to(); + auto start = *configuration.stack().pop().get().to(); + + Checked checked_offset = start; + checked_offset += count; + TRAP_IF_NOT(!checked_offset.has_overflow() && checked_offset <= (u32)table->elements().size()); + + for (u32 i = 0; i < count; ++i) + table->elements()[start + i] = value; + return; + } case Instructions::table_set.value(): { auto ref = *configuration.stack().pop().get().to(); auto index = (size_t)(*configuration.stack().pop().get().to()); @@ -1582,9 +1655,6 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): case Instructions::f64x2_convert_low_i32x4_s.value(): case Instructions::f64x2_convert_low_i32x4_u.value(): - case Instructions::table_init.value(): - case Instructions::table_copy.value(): - case Instructions::table_fill.value(): default: dbgln_if(WASM_TRACE_DEBUG, "Instruction '{}' not implemented", instruction_name(instruction.opcode())); m_trap = Trap { ByteString::formatted("Unimplemented instruction {}", instruction_name(instruction.opcode())) };