From 22448b0c35442a42458a2bdabd743d78e6a98a90 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Fri, 22 Aug 2025 17:11:25 +0200 Subject: [PATCH] LibWasm: Move the interpreter IP out of the configuration object This, along with moving the sources and destination out of the config object, makes it so we don't have to double-deref to get to them on each instruction, leading to a ~15% perf improvement on dispatch. --- .../AbstractMachine/AbstractMachine.cpp | 2 +- .../LibWasm/AbstractMachine/AbstractMachine.h | 2 + .../AbstractMachine/BytecodeInterpreter.cpp | 4267 ++++++++--------- .../AbstractMachine/BytecodeInterpreter.h | 36 +- .../LibWasm/AbstractMachine/Configuration.cpp | 3 +- .../LibWasm/AbstractMachine/Configuration.h | 20 +- .../LibWasm/AbstractMachine/Validator.cpp | 6 + Libraries/LibWasm/Opcode.h | 5 +- Libraries/LibWasm/Parser/Parser.cpp | 11 +- Libraries/LibWasm/Printer/Printer.cpp | 1 + Libraries/LibWasm/Types.h | 1 + 11 files changed, 2182 insertions(+), 2172 deletions(-) diff --git a/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 06b53b9e169..90d1c3f92e2 100644 --- a/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -270,7 +270,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector {}, entry, - entry.instructions().size(), + entry.instructions().size() - 1, }); auto result = config.execute(interpreter); if (result.is_trap()) diff --git a/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index c0e1e388946..24bc924a1a0 100644 --- a/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -572,6 +572,8 @@ public: DataInstance* get(DataAddress); ElementInstance* get(ElementAddress); + MemoryInstance* unsafe_get(MemoryAddress address) { return &m_memories.data()[address.value()]; } + private: Vector m_functions; Vector m_tables; diff --git a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 6a3cfe9de26..a1de59e51a8 100644 --- a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -79,15 +79,13 @@ template void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expression const& expression) { auto& instructions = expression.instructions(); - u64 max_ip_value = HasCompiledList ? expression.compiled_instructions.dispatches.size() : instructions.size(); - auto& current_ip_value = configuration.ip(); + u64 max_ip_value = (HasCompiledList ? expression.compiled_instructions.dispatches.size() : instructions.size()) - 1; + auto current_ip_value = configuration.ip(); u64 executed_instructions = 0; - configuration.sources[0] = Dispatch::RegisterOrStack::Stack; - configuration.sources[1] = Dispatch::RegisterOrStack::Stack; - configuration.sources[2] = Dispatch::RegisterOrStack::Stack; - configuration.destination = Dispatch::RegisterOrStack::Stack; constexpr static u32 default_sources_and_destination = (to_underlying(Dispatch::RegisterOrStack::Stack) | (to_underlying(Dispatch::RegisterOrStack::Stack) << 2) | (to_underlying(Dispatch::RegisterOrStack::Stack) << 4)); + SourcesAndDestination addresses { .sources_and_destination = default_sources_and_destination }; + enum class CouldHaveChangedIP { No, Yes @@ -95,7 +93,7 @@ void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expressio auto const cc = expression.compiled_instructions.dispatches.data(); - while (current_ip_value < max_ip_value) { + while (true) { if constexpr (HasDynamicInsnLimit) { if (executed_instructions++ >= Constants::max_allowed_executed_instructions_per_call) [[unlikely]] { m_trap = Trap::from_string("Exceeded maximum allowed number of instructions"); @@ -103,136 +101,96 @@ void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expressio } } // bounds checked by loop condition. - auto old_ip = current_ip_value; - { - configuration.sources_and_destination = HasCompiledList - ? cc[current_ip_value].sources_and_destination - : default_sources_and_destination; + addresses.sources_and_destination = HasCompiledList + ? cc[current_ip_value].sources_and_destination + : default_sources_and_destination; + auto const instruction = HasCompiledList + ? cc[current_ip_value].instruction + : &instructions.data()[current_ip_value]; + auto const opcode = (HasCompiledList + ? cc[current_ip_value].instruction_opcode + : instruction->opcode()) + .value(); - auto const instruction = HasCompiledList - ? cc[current_ip_value].instruction - : &instructions.data()[current_ip_value]; - - auto const opcode = instruction->opcode().value(); - -#define RUN_NEXT_INSTRUCTION(ip_changed) \ - { \ - if constexpr (ip_changed == CouldHaveChangedIP::No) { \ - ++current_ip_value; \ - } else { \ - if (current_ip_value == old_ip) \ - ++current_ip_value; \ - } \ - break; \ +#define RUN_NEXT_INSTRUCTION() \ + { \ + ++current_ip_value; \ + break; \ } - dbgln_if(WASM_TRACE_DEBUG, "Executing instruction {} at current_ip_value {}", instruction_name(instruction->opcode()), current_ip_value); - if ((opcode & Instructions::SyntheticInstructionBase.value()) != Instructions::SyntheticInstructionBase.value()) - __builtin_prefetch(&instruction->arguments(), /* read */ 0, /* low temporal locality */ 1); + dbgln_if(WASM_TRACE_DEBUG, "Executing instruction {} at current_ip_value {}", instruction_name(instruction->opcode()), current_ip_value); + if ((opcode & Instructions::SyntheticInstructionBase.value()) != Instructions::SyntheticInstructionBase.value()) + __builtin_prefetch(&instruction->arguments(), /* read */ 0, /* low temporal locality */ 1); - switch (opcode) { - case Instructions::local_get.value(): - configuration.push_to_destination(configuration.local(instruction->local_index())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_const.value(): - configuration.push_to_destination(Value(instruction->arguments().get())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_i32_add2local.value(): - configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), configuration.local(instruction->arguments().get()).to())))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_i32_addconstlocal.value(): - configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), instruction->arguments().get())))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_i32_andconstlocal.value(): - configuration.push_to_destination(Value(Operators::BitAnd {}(configuration.local(instruction->local_index()).to(), instruction->arguments().get()))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_i32_storelocal.value(): - if (store_value(configuration, *instruction, ConvertToRaw {}(configuration.local(instruction->local_index()).to()), 0)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_i64_storelocal.value(): - if (store_value(configuration, *instruction, ConvertToRaw {}(configuration.local(instruction->local_index()).to()), 0)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_local_seti32_const.value(): - configuration.local(instruction->local_index()) = Value(instruction->arguments().get()); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::synthetic_call_00.value(): - case Instructions::synthetic_call_01.value(): - case Instructions::synthetic_call_10.value(): - case Instructions::synthetic_call_11.value(): - case Instructions::synthetic_call_20.value(): - case Instructions::synthetic_call_21.value(): - case Instructions::synthetic_call_30.value(): - case Instructions::synthetic_call_31.value(): { - auto regs_copy = configuration.regs; - auto index = instruction->arguments().get(); - auto address = configuration.frame().module().functions()[index.value()]; - dbgln_if(WASM_TRACE_DEBUG, "[{}] call(#{} -> {})", current_ip_value, index.value(), address.value()); - if (call_address(configuration, address)) - return; - configuration.regs = regs_copy; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::unreachable.value(): - m_trap = Trap::from_string("Unreachable"); + switch (opcode) { + case Instructions::local_get.value(): + configuration.push_to_destination(configuration.local(instruction->local_index()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_const.value(): + configuration.push_to_destination(Value(instruction->arguments().unsafe_get()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_i32_add2local.value(): + configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), configuration.local(instruction->arguments().get()).to()))), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_i32_addconstlocal.value(): + configuration.push_to_destination(Value(static_cast(Operators::Add {}(configuration.local(instruction->local_index()).to(), instruction->arguments().unsafe_get()))), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_i32_andconstlocal.value(): + configuration.push_to_destination(Value(Operators::BitAnd {}(configuration.local(instruction->local_index()).to(), instruction->arguments().unsafe_get())), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_i32_storelocal.value(): + if (store_value(configuration, *instruction, ConvertToRaw {}(configuration.local(instruction->local_index()).to()), 0, addresses)) return; - case Instructions::nop.value(): - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::local_set.value(): { - // bounds checked by verifier. - configuration.local(instruction->local_index()) = configuration.take_source(0); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::i64_const.value(): - configuration.push_to_destination(Value(instruction->arguments().get())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_const.value(): - configuration.push_to_destination(Value(instruction->arguments().get())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_const.value(): - configuration.push_to_destination(Value(instruction->arguments().get())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::block.value(): { - size_t arity = 0; - size_t param_arity = 0; - auto& args = instruction->arguments().get(); - if (args.block_type.kind() != BlockType::Empty) [[unlikely]] { - switch (args.block_type.kind()) { - case BlockType::Type: - arity = 1; - break; - case BlockType::Index: { - auto& type = configuration.frame().module().types()[args.block_type.type_index().value()]; - arity = type.results().size(); - param_arity = type.parameters().size(); - break; - } - case BlockType::Empty: - VERIFY_NOT_REACHED(); - } - } - - configuration.label_stack().append(Label(arity, args.end_ip, configuration.value_stack().size() - param_arity)); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::loop.value(): { - auto& args = instruction->arguments().get(); - size_t arity = 0; - if (args.block_type.kind() == BlockType::Index) { - auto& type = configuration.frame().module().types()[args.block_type.type_index().value()]; - arity = type.parameters().size(); - } - configuration.label_stack().append(Label(arity, current_ip_value + 1, configuration.value_stack().size() - arity)); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::if_.value(): { - size_t arity = 0; - size_t param_arity = 0; - auto& args = instruction->arguments().get(); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_i64_storelocal.value(): + if (store_value(configuration, *instruction, ConvertToRaw {}(configuration.local(instruction->local_index()).to()), 0, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_local_seti32_const.value(): + configuration.local(instruction->local_index()) = Value(instruction->arguments().unsafe_get()); + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_call_00.value(): + case Instructions::synthetic_call_01.value(): + case Instructions::synthetic_call_10.value(): + case Instructions::synthetic_call_11.value(): + case Instructions::synthetic_call_20.value(): + case Instructions::synthetic_call_21.value(): + case Instructions::synthetic_call_30.value(): + case Instructions::synthetic_call_31.value(): { + auto regs_copy = configuration.regs; + auto index = instruction->arguments().get(); + auto address = configuration.frame().module().functions()[index.value()]; + dbgln_if(WASM_TRACE_DEBUG, "[{}] call(#{} -> {})", current_ip_value, index.value(), address.value()); + if (call_address(configuration, address)) + return; + configuration.regs = regs_copy; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::unreachable.value(): + m_trap = Trap::from_string("Unreachable"); + return; + case Instructions::nop.value(): + RUN_NEXT_INSTRUCTION(); + case Instructions::local_set.value(): { + // bounds checked by verifier. + configuration.local(instruction->local_index()) = configuration.take_source(0, addresses.sources); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::i64_const.value(): + configuration.push_to_destination(Value(instruction->arguments().unsafe_get()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_const.value(): + configuration.push_to_destination(Value(instruction->arguments().unsafe_get()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_const.value(): + configuration.push_to_destination(Value(instruction->arguments().unsafe_get()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::block.value(): { + size_t arity = 0; + size_t param_arity = 0; + auto& args = instruction->arguments().unsafe_get(); + if (args.block_type.kind() != BlockType::Empty) [[unlikely]] { switch (args.block_type.kind()) { - case BlockType::Empty: - break; case BlockType::Type: arity = 1; break; @@ -240,1996 +198,2031 @@ void BytecodeInterpreter::interpret_impl(Configuration& configuration, Expressio auto& type = configuration.frame().module().types()[args.block_type.type_index().value()]; arity = type.results().size(); param_arity = type.parameters().size(); + break; } + case BlockType::Empty: + VERIFY_NOT_REACHED(); } + } - auto value = configuration.take_source(0).to(); - auto end_label = Label(arity, args.end_ip.value(), configuration.value_stack().size() - param_arity); - if (value == 0) { - if (args.else_ip.has_value()) { - configuration.ip() = args.else_ip->value(); - configuration.label_stack().append(end_label); - } else { - configuration.ip() = args.end_ip.value() + 1; - } - } else { + configuration.label_stack().append(Label(arity, args.end_ip, configuration.value_stack().size() - param_arity)); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::loop.value(): { + auto& args = instruction->arguments().get(); + size_t arity = 0; + if (args.block_type.kind() == BlockType::Index) { + auto& type = configuration.frame().module().types()[args.block_type.type_index().value()]; + arity = type.parameters().size(); + } + configuration.label_stack().append(Label(arity, current_ip_value + 1, configuration.value_stack().size() - arity)); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::if_.value(): { + size_t arity = 0; + size_t param_arity = 0; + auto& args = instruction->arguments().unsafe_get(); + switch (args.block_type.kind()) { + case BlockType::Empty: + break; + case BlockType::Type: + arity = 1; + break; + case BlockType::Index: { + auto& type = configuration.frame().module().types()[args.block_type.type_index().value()]; + arity = type.results().size(); + param_arity = type.parameters().size(); + } + } + + auto value = configuration.take_source(0, addresses.sources).to(); + auto end_label = Label(arity, args.end_ip.value(), configuration.value_stack().size() - param_arity); + if (value == 0) { + if (args.else_ip.has_value()) { + current_ip_value = args.else_ip->value() - 1; configuration.label_stack().append(end_label); - } - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::structured_end.value(): - configuration.label_stack().take_last(); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::structured_else.value(): { - auto label = configuration.label_stack().take_last(); - // Jump to the end label - configuration.ip() = label.continuation().value(); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::return_.value(): { - configuration.label_stack().shrink(configuration.frame().label_index() + 1, true); - configuration.ip() = max_ip_value; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::br.value(): - branch_to_label(configuration, instruction->arguments().get()); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - case Instructions::br_if.value(): { - // bounds checked by verifier. - auto cond = configuration.take_source(0).to(); - if (cond == 0) - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - branch_to_label(configuration, instruction->arguments().get()); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::br_table.value(): { - auto& arguments = instruction->arguments().get(); - auto i = configuration.take_source(0).to(); - - if (i >= arguments.labels.size()) { - branch_to_label(configuration, arguments.default_); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - branch_to_label(configuration, arguments.labels[i]); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::call.value(): { - auto index = instruction->arguments().get(); - auto address = configuration.frame().module().functions()[index.value()]; - dbgln_if(WASM_TRACE_DEBUG, "call({})", address.value()); - if (call_address(configuration, address)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::call_indirect.value(): { - auto& args = instruction->arguments().get(); - auto table_address = configuration.frame().module().tables()[args.table.value()]; - auto table_instance = configuration.store().get(table_address); - // bounds checked by verifier. - auto index = configuration.take_source(0).to(); - TRAP_IN_LOOP_IF_NOT(index >= 0); - TRAP_IN_LOOP_IF_NOT(static_cast(index) < table_instance->elements().size()); - auto& element = table_instance->elements()[index]; - TRAP_IN_LOOP_IF_NOT(element.ref().has()); - auto address = element.ref().get().address; - auto const& type_actual = configuration.store().get(address)->visit([](auto& f) -> decltype(auto) { return f.type(); }); - auto const& type_expected = configuration.frame().module().types()[args.type.value()]; - TRAP_IN_LOOP_IF_NOT(type_actual.parameters().size() == type_expected.parameters().size()); - TRAP_IN_LOOP_IF_NOT(type_actual.results().size() == type_expected.results().size()); - TRAP_IN_LOOP_IF_NOT(type_actual.parameters() == type_expected.parameters()); - TRAP_IN_LOOP_IF_NOT(type_actual.results() == type_expected.results()); - - dbgln_if(WASM_TRACE_DEBUG, "call_indirect({} -> {})", index, address.value()); - if (call_address(configuration, address, CallAddressSource::IndirectCall)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::Yes); - } - case Instructions::i32_load.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_load.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_load.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_load8_s.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_load8_u.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_load16_s.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_load16_u.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load8_s.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load8_u.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load16_s.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load16_u.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load32_s.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_load32_u.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_store.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_store.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_store.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_store.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_store8.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_store16.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_store8.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_store16.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_store32.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::local_tee.value(): { - auto value = configuration.source_value(0); // bounds checked by verifier. - auto local_index = instruction->local_index(); - dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value()); - configuration.frame().locals()[local_index.value()] = value; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::global_get.value(): { - auto global_index = instruction->arguments().get(); - // This check here is for const expressions. In non-const expressions, - // a validation error would have been thrown. - TRAP_IN_LOOP_IF_NOT(global_index < configuration.frame().module().globals().size()); - auto address = configuration.frame().module().globals()[global_index.value()]; - dbgln_if(WASM_TRACE_DEBUG, "global({}) -> stack", address.value()); - auto global = configuration.store().get(address); - configuration.push_to_destination(global->value()); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::global_set.value(): { - auto global_index = instruction->arguments().get(); - auto address = configuration.frame().module().globals()[global_index.value()]; - // bounds checked by verifier. - auto value = configuration.take_source(0); - dbgln_if(WASM_TRACE_DEBUG, "stack -> global({})", address.value()); - auto global = configuration.store().get(address); - global->set_value(value); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::memory_size.value(): { - auto& args = instruction->arguments().get(); - auto address = configuration.frame().module().memories()[args.memory_index.value()]; - auto instance = configuration.store().get(address); - auto pages = instance->size() / Constants::page_size; - dbgln_if(WASM_TRACE_DEBUG, "memory.size -> stack({})", pages); - configuration.push_to_destination(Value(static_cast(pages))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::memory_grow.value(): { - auto& args = instruction->arguments().get(); - auto address = configuration.frame().module().memories()[args.memory_index.value()]; - auto instance = configuration.store().get(address); - i32 old_pages = instance->size() / Constants::page_size; - auto& entry = configuration.source_value(0); // bounds checked by verifier. - auto new_pages = entry.to(); - dbgln_if(WASM_TRACE_DEBUG, "memory.grow({}), previously {} pages...", new_pages, old_pages); - if (instance->grow(new_pages * Constants::page_size)) - entry = Value(old_pages); - else - entry = Value(-1); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-fill - case Instructions::memory_fill.value(): { - auto& args = instruction->arguments().get(); - auto address = configuration.frame().module().memories()[args.memory_index.value()]; - auto instance = configuration.store().get(address); - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - u8 value = static_cast(configuration.take_source(1).to()); - auto destination_offset = configuration.take_source(2).to(); - - TRAP_IN_LOOP_IF_NOT(static_cast(destination_offset + count) <= instance->data().size()); - - if (count == 0) - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - - for (u32 i = 0; i < count; ++i) { - if (store_to_memory(configuration, Instruction::MemoryArgument { 0, 0 }, { &value, sizeof(value) }, destination_offset + i)) - return; - } - - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-copy - case Instructions::memory_copy.value(): { - auto& args = instruction->arguments().get(); - auto source_address = configuration.frame().module().memories()[args.src_index.value()]; - auto destination_address = configuration.frame().module().memories()[args.dst_index.value()]; - auto source_instance = configuration.store().get(source_address); - auto destination_instance = configuration.store().get(destination_address); - - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - auto source_offset = configuration.take_source(1).to(); - auto destination_offset = configuration.take_source(2).to(); - - Checked source_position = source_offset; - source_position.saturating_add(count); - Checked destination_position = destination_offset; - destination_position.saturating_add(count); - TRAP_IN_LOOP_IF_NOT(source_position <= source_instance->data().size()); - TRAP_IN_LOOP_IF_NOT(destination_position <= destination_instance->data().size()); - - if (count == 0) - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - - Instruction::MemoryArgument memarg { 0, 0, args.dst_index }; - if (destination_offset <= source_offset) { - for (auto i = 0; i < count; ++i) { - auto value = source_instance->data()[source_offset + i]; - if (store_to_memory(configuration, memarg, { &value, sizeof(value) }, destination_offset + i)) - return; - } } else { - for (auto i = count - 1; i >= 0; --i) { - auto value = source_instance->data()[source_offset + i]; - if (store_to_memory(configuration, memarg, { &value, sizeof(value) }, destination_offset + i)) - return; - } + current_ip_value = args.end_ip.value(); } - - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); + } else { + configuration.label_stack().append(end_label); } - // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-init - case Instructions::memory_init.value(): { - auto& args = instruction->arguments().get(); - auto& data_address = configuration.frame().module().datas()[args.data_index.value()]; - auto& data = *configuration.store().get(data_address); - auto memory_address = configuration.frame().module().memories()[args.memory_index.value()]; - auto memory = configuration.store().get(memory_address); - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - auto source_offset = configuration.take_source(1).to(); - auto destination_offset = configuration.take_source(2).to(); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::structured_end.value(): + configuration.label_stack().take_last(); + RUN_NEXT_INSTRUCTION(); + case Instructions::structured_else.value(): { + auto label = configuration.label_stack().take_last(); + // Jump to the end label + current_ip_value = label.continuation().value() - 1; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::return_.value(): { + configuration.label_stack().shrink(configuration.frame().label_index() + 1, true); + current_ip_value = max_ip_value - 1; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::br.value(): + current_ip_value = branch_to_label(configuration, instruction->arguments().get()).value(); + RUN_NEXT_INSTRUCTION(); + case Instructions::br_if.value(): { + // bounds checked by verifier. + auto cond = configuration.take_source(0, addresses.sources).to(); + if (cond == 0) + RUN_NEXT_INSTRUCTION(); + current_ip_value = branch_to_label(configuration, instruction->arguments().get()).value(); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::br_table.value(): { + auto& arguments = instruction->arguments().get(); + auto i = configuration.take_source(0, addresses.sources).to(); - Checked source_position = source_offset; - source_position.saturating_add(count); - Checked destination_position = destination_offset; - destination_position.saturating_add(count); - TRAP_IN_LOOP_IF_NOT(source_position <= data.data().size()); - TRAP_IN_LOOP_IF_NOT(destination_position <= memory->data().size()); + if (i >= arguments.labels.size()) { + current_ip_value = branch_to_label(configuration, arguments.default_).value(); + RUN_NEXT_INSTRUCTION(); + } + current_ip_value = branch_to_label(configuration, arguments.labels[i]).value(); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::call.value(): { + auto index = instruction->arguments().get(); + auto address = configuration.frame().module().functions()[index.value()]; + dbgln_if(WASM_TRACE_DEBUG, "call({})", address.value()); + if (call_address(configuration, address)) + return; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::call_indirect.value(): { + auto& args = instruction->arguments().get(); + auto table_address = configuration.frame().module().tables()[args.table.value()]; + auto table_instance = configuration.store().get(table_address); + // bounds checked by verifier. + auto index = configuration.take_source(0, addresses.sources).to(); + TRAP_IN_LOOP_IF_NOT(index >= 0); + TRAP_IN_LOOP_IF_NOT(static_cast(index) < table_instance->elements().size()); + auto& element = table_instance->elements()[index]; + TRAP_IN_LOOP_IF_NOT(element.ref().has()); + auto address = element.ref().get().address; + auto const& type_actual = configuration.store().get(address)->visit([](auto& f) -> decltype(auto) { return f.type(); }); + auto const& type_expected = configuration.frame().module().types()[args.type.value()]; + TRAP_IN_LOOP_IF_NOT(type_actual.parameters().size() == type_expected.parameters().size()); + TRAP_IN_LOOP_IF_NOT(type_actual.results().size() == type_expected.results().size()); + TRAP_IN_LOOP_IF_NOT(type_actual.parameters() == type_expected.parameters()); + TRAP_IN_LOOP_IF_NOT(type_actual.results() == type_expected.results()); - if (count == 0) - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); + dbgln_if(WASM_TRACE_DEBUG, "call_indirect({} -> {})", index, address.value()); + if (call_address(configuration, address, CallAddressSource::IndirectCall)) + return; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::i32_load.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_load.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_load.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_load8_s.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_load8_u.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_load16_s.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_load16_u.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load8_s.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load8_u.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load16_s.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load16_u.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load32_s.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_load32_u.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_store.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_store.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_store.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_store.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_store8.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_store16.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_store8.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_store16.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_store32.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::local_tee.value(): { + auto value = configuration.source_value(0, addresses.sources); // bounds checked by verifier. + auto local_index = instruction->local_index(); + dbgln_if(WASM_TRACE_DEBUG, "stack:peek -> locals({})", local_index.value()); + configuration.frame().locals()[local_index.value()] = value; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::global_get.value(): { + auto global_index = instruction->arguments().get(); + // This check here is for const expressions. In non-const expressions, + // a validation error would have been thrown. + TRAP_IN_LOOP_IF_NOT(global_index < configuration.frame().module().globals().size()); + auto address = configuration.frame().module().globals()[global_index.value()]; + dbgln_if(WASM_TRACE_DEBUG, "global({}) -> stack", address.value()); + auto global = configuration.store().get(address); + configuration.push_to_destination(global->value(), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::global_set.value(): { + auto global_index = instruction->arguments().get(); + auto address = configuration.frame().module().globals()[global_index.value()]; + // bounds checked by verifier. + auto value = configuration.take_source(0, addresses.sources); + dbgln_if(WASM_TRACE_DEBUG, "stack -> global({})", address.value()); + auto global = configuration.store().get(address); + global->set_value(value); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::memory_size.value(): { + auto& args = instruction->arguments().get(); + auto address = configuration.frame().module().memories().data()[args.memory_index.value()]; + auto instance = configuration.store().get(address); + auto pages = instance->size() / Constants::page_size; + dbgln_if(WASM_TRACE_DEBUG, "memory.size -> stack({})", pages); + configuration.push_to_destination(Value(static_cast(pages)), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::memory_grow.value(): { + auto& args = instruction->arguments().get(); + auto address = configuration.frame().module().memories().data()[args.memory_index.value()]; + auto instance = configuration.store().get(address); + i32 old_pages = instance->size() / Constants::page_size; + auto& entry = configuration.source_value(0, addresses.sources); // bounds checked by verifier. + auto new_pages = entry.to(); + dbgln_if(WASM_TRACE_DEBUG, "memory.grow({}), previously {} pages...", new_pages, old_pages); + if (instance->grow(new_pages * Constants::page_size)) + entry = Value(old_pages); + else + entry = Value(-1); + RUN_NEXT_INSTRUCTION(); + } + // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-fill + case Instructions::memory_fill.value(): { + auto& args = instruction->arguments().get(); + auto address = configuration.frame().module().memories().data()[args.memory_index.value()]; + auto instance = configuration.store().get(address); + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + u8 value = static_cast(configuration.take_source(1, addresses.sources).to()); + auto destination_offset = configuration.take_source(2, addresses.sources).to(); - Instruction::MemoryArgument memarg { 0, 0, args.memory_index }; - for (size_t i = 0; i < (size_t)count; ++i) { - auto value = data.data()[source_offset + i]; + TRAP_IN_LOOP_IF_NOT(static_cast(destination_offset + count) <= instance->data().size()); + + if (count == 0) + RUN_NEXT_INSTRUCTION(); + + for (u32 i = 0; i < count; ++i) { + if (store_to_memory(configuration, Instruction::MemoryArgument { 0, 0 }, { &value, sizeof(value) }, destination_offset + i)) + return; + } + + RUN_NEXT_INSTRUCTION(); + } + // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-copy + case Instructions::memory_copy.value(): { + auto& args = instruction->arguments().get(); + auto source_address = configuration.frame().module().memories().data()[args.src_index.value()]; + auto destination_address = configuration.frame().module().memories().data()[args.dst_index.value()]; + auto source_instance = configuration.store().get(source_address); + auto destination_instance = configuration.store().get(destination_address); + + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + auto source_offset = configuration.take_source(1, addresses.sources).to(); + auto destination_offset = configuration.take_source(2, addresses.sources).to(); + + Checked source_position = source_offset; + source_position.saturating_add(count); + Checked destination_position = destination_offset; + destination_position.saturating_add(count); + TRAP_IN_LOOP_IF_NOT(source_position <= source_instance->data().size()); + TRAP_IN_LOOP_IF_NOT(destination_position <= destination_instance->data().size()); + + if (count == 0) + RUN_NEXT_INSTRUCTION(); + + Instruction::MemoryArgument memarg { 0, 0, args.dst_index }; + if (destination_offset <= source_offset) { + for (auto i = 0; i < count; ++i) { + auto value = source_instance->data()[source_offset + i]; if (store_to_memory(configuration, memarg, { &value, sizeof(value) }, destination_offset + i)) return; } - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - // https://webassembly.github.io/spec/core/bikeshed/#exec-data-drop - case Instructions::data_drop.value(): { - auto data_index = instruction->arguments().get(); - auto data_address = configuration.frame().module().datas()[data_index.value()]; - *configuration.store().get(data_address) = DataInstance({}); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::elem_drop.value(): { - auto elem_index = instruction->arguments().get(); - auto address = configuration.frame().module().elements()[elem_index.value()]; - auto elem = configuration.store().get(address); - *configuration.store().get(address) = ElementInstance(elem->type(), {}); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - 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); - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - auto source_offset = configuration.take_source(1).to(); - auto destination_offset = configuration.take_source(2).to(); - - Checked checked_source_offset = source_offset; - Checked checked_destination_offset = destination_offset; - checked_source_offset += count; - checked_destination_offset += count; - TRAP_IN_LOOP_IF_NOT(!checked_source_offset.has_overflow() && checked_source_offset <= (u32)element->references().size()); - TRAP_IN_LOOP_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]; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - 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); - - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - auto source_offset = configuration.take_source(1).to(); - auto destination_offset = configuration.take_source(2).to(); - - Checked source_position = source_offset; - source_position.saturating_add(count); - Checked destination_position = destination_offset; - destination_position.saturating_add(count); - TRAP_IN_LOOP_IF_NOT(source_position <= source_instance->elements().size()); - TRAP_IN_LOOP_IF_NOT(destination_position <= destination_instance->elements().size()); - - if (count == 0) - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - - 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; - } + } else { + for (auto i = count - 1; i >= 0; --i) { + auto value = source_instance->data()[source_offset + i]; + if (store_to_memory(configuration, memarg, { &value, sizeof(value) }, destination_offset + i)) + return; } + } - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - 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); - // bounds checked by verifier. - auto count = configuration.take_source(0).to(); - auto value = configuration.take_source(1); - auto start = configuration.take_source(2).to(); + RUN_NEXT_INSTRUCTION(); + } + // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-init + case Instructions::memory_init.value(): { + auto& args = instruction->arguments().get(); + auto& data_address = configuration.frame().module().datas()[args.data_index.value()]; + auto& data = *configuration.store().get(data_address); + auto memory_address = configuration.frame().module().memories().data()[args.memory_index.value()]; + auto memory = configuration.store().unsafe_get(memory_address); + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + auto source_offset = configuration.take_source(1, addresses.sources).to(); + auto destination_offset = configuration.take_source(2, addresses.sources).to(); - Checked checked_offset = start; - checked_offset += count; - TRAP_IN_LOOP_IF_NOT(!checked_offset.has_overflow() && checked_offset <= (u32)table->elements().size()); + Checked source_position = source_offset; + source_position.saturating_add(count); + Checked destination_position = destination_offset; + destination_position.saturating_add(count); + TRAP_IN_LOOP_IF_NOT(source_position <= data.data().size()); + TRAP_IN_LOOP_IF_NOT(destination_position <= memory->data().size()); - for (u32 i = 0; i < count; ++i) - table->elements()[start + i] = value.to(); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); + if (count == 0) + RUN_NEXT_INSTRUCTION(); + + Instruction::MemoryArgument memarg { 0, 0, args.memory_index }; + for (size_t i = 0; i < (size_t)count; ++i) { + auto value = data.data()[source_offset + i]; + if (store_to_memory(configuration, memarg, { &value, sizeof(value) }, destination_offset + i)) + return; } - case Instructions::table_set.value(): { - // bounds checked by verifier. - auto ref = configuration.take_source(0); - auto index = (size_t)(configuration.take_source(1).to()); - auto table_index = instruction->arguments().get(); - auto address = configuration.frame().module().tables()[table_index.value()]; - auto table = configuration.store().get(address); - TRAP_IN_LOOP_IF_NOT(index < table->elements().size()); - table->elements()[index] = ref.to(); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::table_get.value(): { - // bounds checked by verifier. - auto& index_value = configuration.source_value(0); - auto index = static_cast(index_value.to()); - auto table_index = instruction->arguments().get(); - auto address = configuration.frame().module().tables()[table_index.value()]; - auto table = configuration.store().get(address); - TRAP_IN_LOOP_IF_NOT(index < table->elements().size()); - index_value = Value(table->elements()[index]); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::table_grow.value(): { - // bounds checked by verifier. - auto size = configuration.take_source(0).to(); - auto fill_value = configuration.take_source(1); - auto table_index = instruction->arguments().get(); - auto address = configuration.frame().module().tables()[table_index.value()]; - auto table = configuration.store().get(address); - auto previous_size = table->elements().size(); - auto did_grow = table->grow(size, fill_value.to()); - if (!did_grow) { - configuration.push_to_destination(Value(-1)); - } else { - configuration.push_to_destination(Value(static_cast(previous_size))); + RUN_NEXT_INSTRUCTION(); + } + // https://webassembly.github.io/spec/core/bikeshed/#exec-data-drop + case Instructions::data_drop.value(): { + auto data_index = instruction->arguments().get(); + auto data_address = configuration.frame().module().datas()[data_index.value()]; + *configuration.store().get(data_address) = DataInstance({}); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::elem_drop.value(): { + auto elem_index = instruction->arguments().get(); + auto address = configuration.frame().module().elements()[elem_index.value()]; + auto elem = configuration.store().get(address); + *configuration.store().get(address) = ElementInstance(elem->type(), {}); + RUN_NEXT_INSTRUCTION(); + } + 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); + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + auto source_offset = configuration.take_source(1, addresses.sources).to(); + auto destination_offset = configuration.take_source(2, addresses.sources).to(); + + Checked checked_source_offset = source_offset; + Checked checked_destination_offset = destination_offset; + checked_source_offset += count; + checked_destination_offset += count; + TRAP_IN_LOOP_IF_NOT(!checked_source_offset.has_overflow() && checked_source_offset <= (u32)element->references().size()); + TRAP_IN_LOOP_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]; + RUN_NEXT_INSTRUCTION(); + } + 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); + + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + auto source_offset = configuration.take_source(1, addresses.sources).to(); + auto destination_offset = configuration.take_source(2, addresses.sources).to(); + + Checked source_position = source_offset; + source_position.saturating_add(count); + Checked destination_position = destination_offset; + destination_position.saturating_add(count); + TRAP_IN_LOOP_IF_NOT(source_position <= source_instance->elements().size()); + TRAP_IN_LOOP_IF_NOT(destination_position <= destination_instance->elements().size()); + + if (count == 0) + RUN_NEXT_INSTRUCTION(); + + 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; } - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); } - case Instructions::table_size.value(): { - auto table_index = instruction->arguments().get(); - auto address = configuration.frame().module().tables()[table_index.value()]; - auto table = configuration.store().get(address); - configuration.push_to_destination(Value(static_cast(table->elements().size()))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::ref_null.value(): { - auto type = instruction->arguments().get(); - configuration.push_to_destination(Value(Reference(Reference::Null { type }))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - }; - case Instructions::ref_func.value(): { - auto index = instruction->arguments().get().value(); - auto& functions = configuration.frame().module().functions(); - auto address = functions[index]; - configuration.push_to_destination(Value(Reference { Reference::Func { address, configuration.store().get_module_for(address) } })); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::ref_is_null.value(): { - // bounds checked by verifier. - auto ref = configuration.take_source(0); - configuration.push_to_destination(Value(static_cast(ref.to().ref().has() ? 1 : 0))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::drop.value(): - // bounds checked by verifier. - configuration.take_source(0); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::select.value(): - case Instructions::select_typed.value(): { - // Note: The type seems to only be used for validation. - auto value = configuration.take_source(0).to(); // bounds checked by verifier. - dbgln_if(WASM_TRACE_DEBUG, "select({})", value); - auto rhs = configuration.take_source(1); - auto& lhs = configuration.source_value(2); // bounds checked by verifier. - lhs = value != 0 ? lhs : rhs; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::i32_eqz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_eq.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_ne.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_lts.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_ltu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_gts.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_gtu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_les.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_leu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_ges.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_geu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_eqz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_eq.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_ne.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_lts.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_ltu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_gts.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_gtu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_les.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_leu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_ges.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_geu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_eq.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_ne.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_lt.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_gt.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_le.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_ge.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_eq.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_ne.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_lt.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_gt.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_le.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_ge.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_clz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_ctz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_popcnt.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_add.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_sub.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_mul.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_divs.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_divu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_rems.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_remu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_and.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_or.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_xor.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_shl.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_shrs.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_shru.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_rotl.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_rotr.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_clz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_ctz.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_popcnt.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_add.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_sub.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_mul.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_divs.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_divu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_rems.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_remu.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_and.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_or.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_xor.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_shl.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_shrs.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_shru.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_rotl.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_rotr.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_abs.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_neg.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_ceil.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_floor.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_trunc.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_nearest.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_sqrt.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_add.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_sub.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_mul.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_div.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_min.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_max.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_copysign.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_abs.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_neg.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_ceil.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_floor.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_trunc.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_nearest.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_sqrt.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_add.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_sub.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_mul.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_div.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_min.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_max.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_copysign.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_wrap_i64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sf32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_uf32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sf64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_uf64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sf32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_uf32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sf64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_uf64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_extend_si32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_extend_ui32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_convert_si32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_convert_ui32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_convert_si64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_convert_ui64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_demote_f64.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_convert_si32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_convert_ui32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_convert_si64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_convert_ui64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_promote_f32.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_reinterpret_f32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_reinterpret_f64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32_reinterpret_i32.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64_reinterpret_i64.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_extend8_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_extend16_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_extend8_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_extend16_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_extend32_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sat_f32_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sat_f32_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sat_f64_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32_trunc_sat_f64_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sat_f32_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sat_f32_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sat_f64_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64_trunc_sat_f64_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_const.value(): - configuration.push_to_destination(Value(instruction->arguments().get())); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load.value(): - if (load_and_push(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load8x8_s.value(): - if (load_and_push_mxn<8, 8, MakeSigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load8x8_u.value(): - if (load_and_push_mxn<8, 8, MakeUnsigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load16x4_s.value(): - if (load_and_push_mxn<16, 4, MakeSigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load16x4_u.value(): - if (load_and_push_mxn<16, 4, MakeUnsigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load32x2_s.value(): - if (load_and_push_mxn<32, 2, MakeSigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load32x2_u.value(): - if (load_and_push_mxn<32, 2, MakeUnsigned>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load8_splat.value(): - if (load_and_push_m_splat<8>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load16_splat.value(): - if (load_and_push_m_splat<16>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load32_splat.value(): - if (load_and_push_m_splat<32>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load64_splat.value(): - if (load_and_push_m_splat<64>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_splat.value(): - pop_and_push_m_splat<8, NativeIntegralType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_splat.value(): - pop_and_push_m_splat<16, NativeIntegralType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_splat.value(): - pop_and_push_m_splat<32, NativeIntegralType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_splat.value(): - pop_and_push_m_splat<64, NativeIntegralType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_splat.value(): - pop_and_push_m_splat<32, NativeFloatingType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_splat.value(): - pop_and_push_m_splat<64, NativeFloatingType>(configuration, *instruction); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_shuffle.value(): { - auto& arg = instruction->arguments().get(); - auto b = pop_vector(configuration, 0); - auto a = pop_vector(configuration, 1); - using VectorType = Native128ByteVectorOf; - VectorType result; - for (size_t i = 0; i < 16; ++i) - if (arg.lanes[i] < 16) - result[i] = a[arg.lanes[i]]; - else - result[i] = b[arg.lanes[i] - 16]; - configuration.push_to_destination(Value(bit_cast(result))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::v128_store.value(): - if (pop_and_store(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_shl.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_shr_u.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_shr_s.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_shl.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_shr_u.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_shr_s.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_shl.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_shr_u.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_shr_s.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_shl.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_shr_u.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_shr_s.value(): - if (binary_numeric_operation, i32>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_swizzle.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_extract_lane_s.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_extract_lane_u.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extract_lane_s.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extract_lane_u.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extract_lane.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extract_lane.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_extract_lane.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_extract_lane.value(): - if (unary_operation>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_replace_lane.value(): - if (binary_numeric_operation, i32>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_replace_lane.value(): - if (binary_numeric_operation, i32>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_replace_lane.value(): - if (binary_numeric_operation, i32>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_replace_lane.value(): - if (binary_numeric_operation, i64>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_replace_lane.value(): - if (binary_numeric_operation, float>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_replace_lane.value(): - if (binary_numeric_operation, double>(configuration, instruction->arguments().get().lane)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_lt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_lt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_gt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_gt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_le_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_le_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_ge_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_ge_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_all_true.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_popcnt.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_avgr_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_add_sat_s.value(): - if (binary_numeric_operation, MakeSigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_add_sat_u.value(): - if (binary_numeric_operation, MakeUnsigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_sub_sat_s.value(): - if (binary_numeric_operation, MakeSigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_sub_sat_u.value(): - if (binary_numeric_operation, MakeUnsigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_min_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_min_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_max_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_max_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_lt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_lt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_gt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_gt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_le_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_le_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_ge_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_ge_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_all_true.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_mul.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_avgr_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_add_sat_s.value(): - if (binary_numeric_operation, MakeSigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_add_sat_u.value(): - if (binary_numeric_operation, MakeUnsigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_sub_sat_s.value(): - if (binary_numeric_operation, MakeSigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_sub_sat_u.value(): - if (binary_numeric_operation, MakeUnsigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_min_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_min_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_max_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_max_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extend_low_i8x16_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extend_high_i8x16_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extend_low_i8x16_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extend_high_i8x16_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extmul_low_i8x16_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extmul_high_i8x16_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extmul_low_i8x16_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_extmul_high_i8x16_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_lt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_lt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_gt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_gt_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_le_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_le_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_ge_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_ge_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_all_true.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_mul.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_min_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_min_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_max_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_max_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extend_low_i16x8_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extend_high_i16x8_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extend_low_i16x8_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extend_high_i16x8_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extmul_low_i16x8_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extmul_high_i16x8_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extmul_low_i16x8_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_extmul_high_i16x8_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_lt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_gt_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_le_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_ge_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_all_true.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_mul.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extend_low_i32x4_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extend_high_i32x4_s.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extend_low_i32x4_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extend_high_i32x4_u.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extmul_low_i32x4_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extmul_high_i32x4_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extmul_low_i32x4_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_extmul_high_i32x4_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_lt.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_gt.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_le.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_ge.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_min.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_max.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_eq.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_ne.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_lt.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_gt.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_le.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_ge.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_min.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_max.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_div.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_mul.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_pmin.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_pmax.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_div.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_mul.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_sub.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_add.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_pmin.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_pmax.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_ceil.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_floor.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_trunc.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_nearest.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_sqrt.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_ceil.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_floor.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_trunc.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_nearest.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_sqrt.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_neg.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_abs.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_and.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_or.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_xor.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_not.value(): - if (unary_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_andnot.value(): - if (binary_numeric_operation(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_bitselect.value(): { - // bounds checked by verifier. - auto mask = configuration.take_source(0).to(); - auto false_vector = configuration.take_source(1).to(); - auto true_vector = configuration.take_source(2).to(); - u128 result = (true_vector & mask) | (false_vector & ~mask); - configuration.push_to_destination(Value(result)); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::v128_any_true.value(): { - auto vector = configuration.take_source(0).to(); // bounds checked by verifier. - configuration.push_to_destination(Value(static_cast(vector != 0))); - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - } - case Instructions::v128_load8_lane.value(): - if (load_and_push_lane_n<8>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load16_lane.value(): - if (load_and_push_lane_n<16>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load32_lane.value(): - if (load_and_push_lane_n<32>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load64_lane.value(): - if (load_and_push_lane_n<64>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load32_zero.value(): - if (load_and_push_zero_n<32>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_load64_zero.value(): - if (load_and_push_zero_n<64>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_store8_lane.value(): - if (pop_and_store_lane_n<8>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_store16_lane.value(): - if (pop_and_store_lane_n<16>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_store32_lane.value(): - if (pop_and_store_lane_n<32>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::v128_store64_lane.value(): - if (pop_and_store_lane_n<64>(configuration, *instruction)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_trunc_sat_f32x4_s.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_trunc_sat_f32x4_u.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_bitmask.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_bitmask.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_bitmask.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i64x2_bitmask.value(): - if (unary_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_dot_i16x8_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_narrow_i16x8_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i8x16_narrow_i16x8_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_narrow_i32x4_s.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_narrow_i32x4_u.value(): - if (binary_numeric_operation>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i16x8_q15mulr_sat_s.value(): - if (binary_numeric_operation, MakeSigned>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_convert_i32x4_s.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_convert_i32x4_u.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_convert_low_i32x4_s.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_convert_low_i32x4_u.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f32x4_demote_f64x2_zero.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::f64x2_promote_low_f32x4.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_trunc_sat_f64x2_s_zero.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): - if (unary_operation>>(configuration)) - return; - RUN_NEXT_INSTRUCTION(CouldHaveChangedIP::No); - default: - VERIFY_NOT_REACHED(); + + RUN_NEXT_INSTRUCTION(); + } + 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); + // bounds checked by verifier. + auto count = configuration.take_source(0, addresses.sources).to(); + auto value = configuration.take_source(1, addresses.sources); + auto start = configuration.take_source(2, addresses.sources).to(); + + Checked checked_offset = start; + checked_offset += count; + TRAP_IN_LOOP_IF_NOT(!checked_offset.has_overflow() && checked_offset <= (u32)table->elements().size()); + + for (u32 i = 0; i < count; ++i) + table->elements()[start + i] = value.to(); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::table_set.value(): { + // bounds checked by verifier. + auto ref = configuration.take_source(0, addresses.sources); + auto index = (size_t)(configuration.take_source(1, addresses.sources).to()); + auto table_index = instruction->arguments().get(); + auto address = configuration.frame().module().tables()[table_index.value()]; + auto table = configuration.store().get(address); + TRAP_IN_LOOP_IF_NOT(index < table->elements().size()); + table->elements()[index] = ref.to(); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::table_get.value(): { + // bounds checked by verifier. + auto& index_value = configuration.source_value(0, addresses.sources); + auto index = static_cast(index_value.to()); + auto table_index = instruction->arguments().get(); + auto address = configuration.frame().module().tables()[table_index.value()]; + auto table = configuration.store().get(address); + TRAP_IN_LOOP_IF_NOT(index < table->elements().size()); + index_value = Value(table->elements()[index]); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::table_grow.value(): { + // bounds checked by verifier. + auto size = configuration.take_source(0, addresses.sources).to(); + auto fill_value = configuration.take_source(1, addresses.sources); + auto table_index = instruction->arguments().get(); + auto address = configuration.frame().module().tables()[table_index.value()]; + auto table = configuration.store().get(address); + auto previous_size = table->elements().size(); + auto did_grow = table->grow(size, fill_value.to()); + if (!did_grow) { + configuration.push_to_destination(Value(-1), addresses.destination); + } else { + configuration.push_to_destination(Value(static_cast(previous_size)), addresses.destination); } + RUN_NEXT_INSTRUCTION(); + } + case Instructions::table_size.value(): { + auto table_index = instruction->arguments().get(); + auto address = configuration.frame().module().tables()[table_index.value()]; + auto table = configuration.store().get(address); + configuration.push_to_destination(Value(static_cast(table->elements().size())), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::ref_null.value(): { + auto type = instruction->arguments().get(); + configuration.push_to_destination(Value(Reference(Reference::Null { type })), addresses.destination); + RUN_NEXT_INSTRUCTION(); + }; + case Instructions::ref_func.value(): { + auto index = instruction->arguments().get().value(); + auto& functions = configuration.frame().module().functions(); + auto address = functions[index]; + configuration.push_to_destination(Value(Reference { Reference::Func { address, configuration.store().get_module_for(address) } }), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::ref_is_null.value(): { + // bounds checked by verifier. + auto ref = configuration.take_source(0, addresses.sources); + configuration.push_to_destination(Value(static_cast(ref.to().ref().has() ? 1 : 0)), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::drop.value(): + // bounds checked by verifier. + configuration.take_source(0, addresses.sources); + RUN_NEXT_INSTRUCTION(); + case Instructions::select.value(): + case Instructions::select_typed.value(): { + // Note: The type seems to only be used for validation. + auto value = configuration.take_source(0, addresses.sources).to(); // bounds checked by verifier. + dbgln_if(WASM_TRACE_DEBUG, "select({})", value); + auto rhs = configuration.take_source(1, addresses.sources); + auto& lhs = configuration.source_value(2, addresses.sources); // bounds checked by verifier. + lhs = value != 0 ? lhs : rhs; + RUN_NEXT_INSTRUCTION(); + } + case Instructions::i32_eqz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_eq.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_ne.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_lts.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_ltu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_gts.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_gtu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_les.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_leu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_ges.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_geu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_eqz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_eq.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_ne.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_lts.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_ltu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_gts.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_gtu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_les.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_leu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_ges.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_geu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_eq.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_ne.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_lt.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_gt.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_le.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_ge.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_eq.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_ne.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_lt.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_gt.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_le.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_ge.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_clz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_ctz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_popcnt.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_add.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_sub.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_mul.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_divs.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_divu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_rems.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_remu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_and.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_or.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_xor.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_shl.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_shrs.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_shru.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_rotl.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_rotr.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_clz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_ctz.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_popcnt.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_add.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_sub.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_mul.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_divs.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_divu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_rems.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_remu.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_and.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_or.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_xor.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_shl.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_shrs.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_shru.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_rotl.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_rotr.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_abs.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_neg.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_ceil.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_floor.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_trunc.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_nearest.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_sqrt.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_add.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_sub.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_mul.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_div.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_min.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_max.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_copysign.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_abs.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_neg.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_ceil.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_floor.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_trunc.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_nearest.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_sqrt.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_add.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_sub.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_mul.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_div.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_min.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_max.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_copysign.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_wrap_i64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sf32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_uf32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sf64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_uf64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sf32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_uf32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sf64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_uf64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_extend_si32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_extend_ui32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_convert_si32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_convert_ui32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_convert_si64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_convert_ui64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_demote_f64.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_convert_si32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_convert_ui32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_convert_si64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_convert_ui64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_promote_f32.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_reinterpret_f32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_reinterpret_f64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32_reinterpret_i32.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64_reinterpret_i64.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_extend8_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_extend16_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_extend8_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_extend16_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_extend32_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sat_f32_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sat_f32_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sat_f64_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32_trunc_sat_f64_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sat_f32_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sat_f32_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sat_f64_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64_trunc_sat_f64_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_const.value(): + configuration.push_to_destination(Value(instruction->arguments().get()), addresses.destination); + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load.value(): + if (load_and_push(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load8x8_s.value(): + if (load_and_push_mxn<8, 8, MakeSigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load8x8_u.value(): + if (load_and_push_mxn<8, 8, MakeUnsigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load16x4_s.value(): + if (load_and_push_mxn<16, 4, MakeSigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load16x4_u.value(): + if (load_and_push_mxn<16, 4, MakeUnsigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load32x2_s.value(): + if (load_and_push_mxn<32, 2, MakeSigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load32x2_u.value(): + if (load_and_push_mxn<32, 2, MakeUnsigned>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load8_splat.value(): + if (load_and_push_m_splat<8>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load16_splat.value(): + if (load_and_push_m_splat<16>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load32_splat.value(): + if (load_and_push_m_splat<32>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load64_splat.value(): + if (load_and_push_m_splat<64>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_splat.value(): + pop_and_push_m_splat<8, NativeIntegralType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_splat.value(): + pop_and_push_m_splat<16, NativeIntegralType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_splat.value(): + pop_and_push_m_splat<32, NativeIntegralType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_splat.value(): + pop_and_push_m_splat<64, NativeIntegralType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_splat.value(): + pop_and_push_m_splat<32, NativeFloatingType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_splat.value(): + pop_and_push_m_splat<64, NativeFloatingType>(configuration, *instruction, addresses); + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_shuffle.value(): { + auto& arg = instruction->arguments().get(); + auto b = pop_vector(configuration, 0, addresses); + auto a = pop_vector(configuration, 1, addresses); + using VectorType = Native128ByteVectorOf; + VectorType result; + for (size_t i = 0; i < 16; ++i) + if (arg.lanes[i] < 16) + result[i] = a[arg.lanes[i]]; + else + result[i] = b[arg.lanes[i] - 16]; + configuration.push_to_destination(Value(bit_cast(result)), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::v128_store.value(): + if (pop_and_store(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_shl.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_shr_u.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_shr_s.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_shl.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_shr_u.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_shr_s.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_shl.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_shr_u.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_shr_s.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_shl.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_shr_u.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_shr_s.value(): + if (binary_numeric_operation, i32>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_swizzle.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_extract_lane_s.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_extract_lane_u.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extract_lane_s.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extract_lane_u.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extract_lane.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extract_lane.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_extract_lane.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_extract_lane.value(): + if (unary_operation>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_replace_lane.value(): + if (binary_numeric_operation, i32>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_replace_lane.value(): + if (binary_numeric_operation, i32>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_replace_lane.value(): + if (binary_numeric_operation, i32>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_replace_lane.value(): + if (binary_numeric_operation, i64>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_replace_lane.value(): + if (binary_numeric_operation, float>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_replace_lane.value(): + if (binary_numeric_operation, double>(configuration, addresses, instruction->arguments().get().lane)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_lt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_lt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_gt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_gt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_le_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_le_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_ge_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_ge_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_all_true.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_popcnt.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_avgr_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_add_sat_s.value(): + if (binary_numeric_operation, MakeSigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_add_sat_u.value(): + if (binary_numeric_operation, MakeUnsigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_sub_sat_s.value(): + if (binary_numeric_operation, MakeSigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_sub_sat_u.value(): + if (binary_numeric_operation, MakeUnsigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_min_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_min_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_max_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_max_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_lt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_lt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_gt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_gt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_le_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_le_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_ge_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_ge_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_all_true.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_mul.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_avgr_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_add_sat_s.value(): + if (binary_numeric_operation, MakeSigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_add_sat_u.value(): + if (binary_numeric_operation, MakeUnsigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_sub_sat_s.value(): + if (binary_numeric_operation, MakeSigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_sub_sat_u.value(): + if (binary_numeric_operation, MakeUnsigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_min_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_min_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_max_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_max_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extend_low_i8x16_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extend_high_i8x16_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extend_low_i8x16_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extend_high_i8x16_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extmul_low_i8x16_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extmul_high_i8x16_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extmul_low_i8x16_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_extmul_high_i8x16_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_lt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_lt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_gt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_gt_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_le_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_le_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_ge_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_ge_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_all_true.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_mul.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_min_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_min_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_max_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_max_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extend_low_i16x8_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extend_high_i16x8_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extend_low_i16x8_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extend_high_i16x8_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extmul_low_i16x8_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extmul_high_i16x8_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extmul_low_i16x8_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_extmul_high_i16x8_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_lt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_gt_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_le_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_ge_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_all_true.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_mul.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extend_low_i32x4_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extend_high_i32x4_s.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extend_low_i32x4_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extend_high_i32x4_u.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extmul_low_i32x4_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extmul_high_i32x4_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extmul_low_i32x4_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_extmul_high_i32x4_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_lt.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_gt.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_le.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_ge.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_min.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_max.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_eq.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_ne.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_lt.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_gt.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_le.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_ge.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_min.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_max.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_div.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_mul.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_pmin.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_pmax.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_div.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_mul.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_sub.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_add.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_pmin.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_pmax.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_ceil.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_floor.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_trunc.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_nearest.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_sqrt.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_ceil.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_floor.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_trunc.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_nearest.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_sqrt.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_neg.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_abs.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_and.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_or.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_xor.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_not.value(): + if (unary_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_andnot.value(): + if (binary_numeric_operation(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_bitselect.value(): { + // bounds checked by verifier. + auto mask = configuration.take_source(0, addresses.sources).to(); + auto false_vector = configuration.take_source(1, addresses.sources).to(); + auto true_vector = configuration.take_source(2, addresses.sources).to(); + u128 result = (true_vector & mask) | (false_vector & ~mask); + configuration.push_to_destination(Value(result), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::v128_any_true.value(): { + auto vector = configuration.take_source(0, addresses.sources).to(); // bounds checked by verifier. + configuration.push_to_destination(Value(static_cast(vector != 0)), addresses.destination); + RUN_NEXT_INSTRUCTION(); + } + case Instructions::v128_load8_lane.value(): + if (load_and_push_lane_n<8>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load16_lane.value(): + if (load_and_push_lane_n<16>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load32_lane.value(): + if (load_and_push_lane_n<32>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load64_lane.value(): + if (load_and_push_lane_n<64>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load32_zero.value(): + if (load_and_push_zero_n<32>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_load64_zero.value(): + if (load_and_push_zero_n<64>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_store8_lane.value(): + if (pop_and_store_lane_n<8>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_store16_lane.value(): + if (pop_and_store_lane_n<16>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_store32_lane.value(): + if (pop_and_store_lane_n<32>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::v128_store64_lane.value(): + if (pop_and_store_lane_n<64>(configuration, *instruction, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_trunc_sat_f32x4_s.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_trunc_sat_f32x4_u.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_bitmask.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_bitmask.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_bitmask.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i64x2_bitmask.value(): + if (unary_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_dot_i16x8_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_narrow_i16x8_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i8x16_narrow_i16x8_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_narrow_i32x4_s.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_narrow_i32x4_u.value(): + if (binary_numeric_operation>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i16x8_q15mulr_sat_s.value(): + if (binary_numeric_operation, MakeSigned>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_convert_i32x4_s.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_convert_i32x4_u.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_convert_low_i32x4_s.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_convert_low_i32x4_u.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f32x4_demote_f64x2_zero.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::f64x2_promote_low_f32x4.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_trunc_sat_f64x2_s_zero.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): + if (unary_operation>>(configuration, addresses)) + return; + RUN_NEXT_INSTRUCTION(); + case Instructions::synthetic_end_expression.value(): + return; + default: + VERIFY_NOT_REACHED(); } } } -void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelIndex index) +InstructionPointer BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelIndex index) { dbgln_if(WASM_TRACE_DEBUG, "Branch to label with index {}...", index.value()); auto& label_stack = configuration.label_stack(); @@ -2238,16 +2231,16 @@ void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelInd dbgln_if(WASM_TRACE_DEBUG, "...which is actually IP {}, and has {} result(s)", label.continuation().value(), label.arity()); configuration.value_stack().remove(label.stack_height(), configuration.value_stack().size() - label.stack_height() - label.arity()); - configuration.ip() = label.continuation().value(); + return label.continuation().value() - 1; } template -bool BytecodeInterpreter::load_and_push(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::load_and_push(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto& arg = instruction.arguments().get(); auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); - auto& entry = configuration.source_value(0); // bounds checked by verifier. + auto& entry = configuration.source_value(0, addresses.sources); // bounds checked by verifier. auto base = entry.to(); u64 instance_address = static_cast(bit_cast(base)) + arg.offset; if (instance_address + sizeof(ReadType) > memory->size()) { @@ -2268,12 +2261,12 @@ ALWAYS_INLINE static TDst convert_vector(TSrc v) } template typename SetSign> -bool BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto& arg = instruction.arguments().get(); auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); - auto& entry = configuration.source_value(0); // bounds checked by verifier. + auto& entry = configuration.source_value(0, addresses.sources); // bounds checked by verifier. auto base = entry.to(); u64 instance_address = static_cast(bit_cast(base)) + arg.offset; if (instance_address + M * N / 8 > memory->size()) { @@ -2297,14 +2290,14 @@ bool BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instru } template -bool BytecodeInterpreter::load_and_push_lane_n(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::load_and_push_lane_n(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto memarg_and_lane = instruction.arguments().get(); auto& address = configuration.frame().module().memories()[memarg_and_lane.memory.memory_index.value()]; auto memory = configuration.store().get(address); // bounds checked by verifier. - auto vector = configuration.take_source(0).to(); - auto base = configuration.take_source(1).to(); + auto vector = configuration.take_source(0, addresses.sources).to(); + auto base = configuration.take_source(1, addresses.sources).to(); u64 instance_address = static_cast(bit_cast(base)) + memarg_and_lane.memory.offset; if (instance_address + N / 8 > memory->size()) { m_trap = Trap::from_string("Memory access out of bounds"); @@ -2313,18 +2306,18 @@ bool BytecodeInterpreter::load_and_push_lane_n(Configuration& configuration, Ins auto slice = memory->data().bytes().slice(instance_address, N / 8); auto dst = bit_cast(&vector) + memarg_and_lane.lane * N / 8; memcpy(dst, slice.data(), N / 8); - configuration.push_to_destination(Value(vector)); + configuration.push_to_destination(Value(vector), addresses.destination); return false; } template -bool BytecodeInterpreter::load_and_push_zero_n(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::load_and_push_zero_n(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto memarg_and_lane = instruction.arguments().get(); auto& address = configuration.frame().module().memories()[memarg_and_lane.memory_index.value()]; auto memory = configuration.store().get(address); // bounds checked by verifier. - auto base = configuration.take_source(0).to(); + auto base = configuration.take_source(0, addresses.sources).to(); u64 instance_address = static_cast(bit_cast(base)) + memarg_and_lane.offset; if (instance_address + N / 8 > memory->size()) { m_trap = Trap::from_string("Memory access out of bounds"); @@ -2333,17 +2326,17 @@ bool BytecodeInterpreter::load_and_push_zero_n(Configuration& configuration, Ins auto slice = memory->data().bytes().slice(instance_address, N / 8); u128 vector = 0; memcpy(&vector, slice.data(), N / 8); - configuration.push_to_destination(Value(vector)); + configuration.push_to_destination(Value(vector), addresses.destination); return false; } template -bool BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto& arg = instruction.arguments().get(); auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); - auto& entry = configuration.source_value(0); // bounds checked by verifier. + auto& entry = configuration.source_value(0, addresses.sources); // bounds checked by verifier. auto base = entry.to(); u64 instance_address = static_cast(bit_cast(base)) + arg.offset; if (instance_address + M / 8 > memory->size()) { @@ -2354,15 +2347,15 @@ bool BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, In dbgln_if(WASM_TRACE_DEBUG, "vec-splat({} : {}) -> stack", instance_address, M / 8); auto slice = memory->data().bytes().slice(instance_address, M / 8); auto value = read_value>(slice); - set_top_m_splat(configuration, value); + set_top_m_splat(configuration, value, addresses); return false; } template typename NativeType> -void BytecodeInterpreter::set_top_m_splat(Wasm::Configuration& configuration, NativeType value) +void BytecodeInterpreter::set_top_m_splat(Wasm::Configuration& configuration, NativeType value, SourcesAndDestination const& addresses) { auto push = [&](auto result) { - configuration.source_value(0) = Value(bit_cast(result)); + configuration.source_value(0, addresses.sources) = Value(bit_cast(result)); }; if constexpr (IsFloatingPoint>) { @@ -2387,21 +2380,21 @@ void BytecodeInterpreter::set_top_m_splat(Wasm::Configuration& configuration, Na } template typename NativeType> -void BytecodeInterpreter::pop_and_push_m_splat(Wasm::Configuration& configuration, Instruction const&) +void BytecodeInterpreter::pop_and_push_m_splat(Wasm::Configuration& configuration, Instruction const&, SourcesAndDestination const& addresses) { using PopT = Conditional, NativeType<64>>; using ReadT = NativeType; - auto entry = configuration.source_value(0); + auto entry = configuration.source_value(0, addresses.sources); auto value = static_cast(entry.to()); dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> splat({})", value, M); - set_top_m_splat(configuration, value); + set_top_m_splat(configuration, value, addresses); } template typename SetSign, typename VectorType> -VectorType BytecodeInterpreter::pop_vector(Configuration& configuration, size_t source) +VectorType BytecodeInterpreter::pop_vector(Configuration& configuration, size_t source, SourcesAndDestination const& addresses) { // bounds checked by verifier. - return bit_cast(configuration.take_source(source).to()); + return bit_cast(configuration.take_source(source, addresses.sources).to()); } bool BytecodeInterpreter::call_address(Configuration& configuration, FunctionAddress address, CallAddressSource source) @@ -2447,11 +2440,11 @@ bool BytecodeInterpreter::call_address(Configuration& configuration, FunctionAdd } template -bool BytecodeInterpreter::binary_numeric_operation(Configuration& configuration, Args&&... args) +bool BytecodeInterpreter::binary_numeric_operation(Configuration& configuration, SourcesAndDestination const& addresses, Args&&... args) { // bounds checked by Nor. - auto rhs = configuration.take_source(0).to(); - auto lhs = configuration.take_source(1).to(); // bounds checked by verifier. + auto rhs = configuration.take_source(0, addresses.sources).to(); + auto lhs = configuration.take_source(1, addresses.sources).to(); // bounds checked by verifier. PushType result; auto call_result = Operator { forward(args)... }(lhs, rhs); if constexpr (IsSpecializationOf) { @@ -2462,14 +2455,14 @@ bool BytecodeInterpreter::binary_numeric_operation(Configuration& configuration, result = call_result; } dbgln_if(WASM_TRACE_DEBUG, "{} {} {} = {}", lhs, Operator::name(), rhs, result); - configuration.push_to_destination(Value(result)); + configuration.push_to_destination(Value(result), addresses.destination); return false; } template -bool BytecodeInterpreter::unary_operation(Configuration& configuration, Args&&... args) +bool BytecodeInterpreter::unary_operation(Configuration& configuration, SourcesAndDestination const& addresses, Args&&... args) { - auto& entry = configuration.source_value(0); // bounds checked by veriNor. + auto& entry = configuration.source_value(0, addresses.sources); // bounds checked by verifier. auto value = entry.to(); auto call_result = Operator { forward(args)... }(value); PushType result; @@ -2486,48 +2479,48 @@ bool BytecodeInterpreter::unary_operation(Configuration& configuration, Args&&.. } template -bool BytecodeInterpreter::pop_and_store(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::pop_and_store(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { // bounds checked by verifier. - auto entry = configuration.take_source(0); + auto entry = configuration.take_source(0, addresses.sources); auto value = ConvertToRaw {}(entry.to()); - return store_value(configuration, instruction, value, 1); + return store_value(configuration, instruction, value, 1, addresses); } template -bool BytecodeInterpreter::store_value(Configuration& configuration, Instruction const& instruction, StoreT value, size_t address_source) +bool BytecodeInterpreter::store_value(Configuration& configuration, Instruction const& instruction, StoreT value, size_t address_source, SourcesAndDestination const& addresses) { - auto& memarg = instruction.arguments().get(); + auto& memarg = instruction.arguments().unsafe_get(); dbgln_if(WASM_TRACE_DEBUG, "stack({}) -> temporary({}b)", value, sizeof(StoreT)); - auto base = configuration.take_source(address_source).to(); + auto base = configuration.take_source(address_source, addresses.sources).to(); return store_to_memory(configuration, memarg, { &value, sizeof(StoreT) }, base); } template -bool BytecodeInterpreter::pop_and_store_lane_n(Configuration& configuration, Instruction const& instruction) +bool BytecodeInterpreter::pop_and_store_lane_n(Configuration& configuration, Instruction const& instruction, SourcesAndDestination const& addresses) { auto& memarg_and_lane = instruction.arguments().get(); // bounds checked by verifier. - auto vector = configuration.take_source(0).to(); + auto vector = configuration.take_source(0, addresses.sources).to(); auto src = bit_cast(&vector) + memarg_and_lane.lane * N / 8; - auto base = configuration.take_source(1).to(); + auto base = configuration.take_source(1, addresses.sources).to(); return store_to_memory(configuration, memarg_and_lane.memory, { src, N / 8 }, base); } bool BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction::MemoryArgument const& arg, ReadonlyBytes data, u32 base) { - auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; + auto& address = configuration.frame().module().memories().data()[arg.memory_index.value()]; auto memory = configuration.store().get(address); u64 instance_address = static_cast(base) + arg.offset; Checked addition { instance_address }; addition += data.size(); - if (addition.has_overflow() || addition.value() > memory->size()) { + if (addition.has_overflow() || addition.value() > memory->size()) [[unlikely]] { m_trap = Trap::from_string("Memory access out of bounds"); dbgln_if(WASM_TRACE_DEBUG, "LibWasm: Memory access out of bounds (expected 0 <= {} and {} <= {})", instance_address, instance_address + data.size(), memory->size()); return true; } dbgln_if(WASM_TRACE_DEBUG, "temporary({}b) -> store({})", data.size(), instance_address); - data.copy_to(memory->data().bytes().slice(instance_address, data.size())); + (void)data.copy_to(memory->data().bytes().slice(instance_address, data.size())); return false; } @@ -2574,6 +2567,7 @@ CompiledInstructions try_compile_instructions(Expression const& expression, Span static Instruction nop { Instructions::nop }; constexpr auto default_dispatch = [](Instruction const& instruction) { return Dispatch { + instruction.opcode(), &instruction, { .sources = { Dispatch::Stack, Dispatch::Stack, Dispatch::Stack }, .destination = Dispatch::Stack } }; @@ -2808,6 +2802,7 @@ CompiledInstructions try_compile_instructions(Expression const& expression, Span }; result.extra_instruction_storage.append(move(instruction)); result.dispatches[i].instruction = &result.extra_instruction_storage.unsafe_last(); + result.dispatches[i].instruction_opcode = result.dispatches[i].instruction->opcode(); } } for (auto index : nops_to_remove.in_reverse()) diff --git a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h index d29e6d33f35..72a23bc6e42 100644 --- a/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h +++ b/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.h @@ -13,6 +13,14 @@ namespace Wasm { +union SourcesAndDestination { + struct { + Dispatch::RegisterOrStack sources[3]; + Dispatch::RegisterOrStack destination; + }; + u32 sources_and_destination; +}; + struct WASM_API BytecodeInterpreter final : public Interpreter { explicit BytecodeInterpreter(StackInfo const& stack_info) : m_stack_info(stack_info) @@ -57,37 +65,37 @@ struct WASM_API BytecodeInterpreter final : public Interpreter { void interpret_impl(Configuration&, Expression const&); protected: - void branch_to_label(Configuration&, LabelIndex); + InstructionPointer branch_to_label(Configuration&, LabelIndex); template - bool load_and_push(Configuration&, Instruction const&); + bool load_and_push(Configuration&, Instruction const&, SourcesAndDestination const&); template - bool pop_and_store(Configuration&, Instruction const&); + bool pop_and_store(Configuration&, Instruction const&, SourcesAndDestination const&); template - bool store_value(Configuration&, Instruction const&, StoreT, size_t address_source); + bool store_value(Configuration&, Instruction const&, StoreT, size_t address_source, SourcesAndDestination const&); template - bool pop_and_store_lane_n(Configuration&, Instruction const&); + bool pop_and_store_lane_n(Configuration&, Instruction const&, SourcesAndDestination const&); template typename SetSign> - bool load_and_push_mxn(Configuration&, Instruction const&); + bool load_and_push_mxn(Configuration&, Instruction const&, SourcesAndDestination const&); template - bool load_and_push_lane_n(Configuration&, Instruction const&); + bool load_and_push_lane_n(Configuration&, Instruction const&, SourcesAndDestination const&); template - bool load_and_push_zero_n(Configuration&, Instruction const&); + bool load_and_push_zero_n(Configuration&, Instruction const&, SourcesAndDestination const&); template - bool load_and_push_m_splat(Configuration&, Instruction const&); + bool load_and_push_m_splat(Configuration&, Instruction const&, SourcesAndDestination const&); template typename NativeType> - void set_top_m_splat(Configuration&, NativeType); + void set_top_m_splat(Configuration&, NativeType, SourcesAndDestination const&); template typename NativeType> - void pop_and_push_m_splat(Configuration&, Instruction const&); + void pop_and_push_m_splat(Configuration&, Instruction const&, SourcesAndDestination const&); template typename SetSign, typename VectorType = Native128ByteVectorOf> - VectorType pop_vector(Configuration&, size_t source); + VectorType pop_vector(Configuration&, size_t source, SourcesAndDestination const&); bool store_to_memory(Configuration&, Instruction::MemoryArgument const&, ReadonlyBytes data, u32 base); bool call_address(Configuration&, FunctionAddress, CallAddressSource = CallAddressSource::DirectCall); template - bool binary_numeric_operation(Configuration&, Args&&...); + bool binary_numeric_operation(Configuration&, SourcesAndDestination const&, Args&&...); template - bool unary_operation(Configuration&, Args&&...); + bool unary_operation(Configuration&, SourcesAndDestination const&, Args&&...); template T read_value(ReadonlyBytes data); diff --git a/Libraries/LibWasm/AbstractMachine/Configuration.cpp b/Libraries/LibWasm/AbstractMachine/Configuration.cpp index a895a9d7942..e9d0ad12f0e 100644 --- a/Libraries/LibWasm/AbstractMachine/Configuration.cpp +++ b/Libraries/LibWasm/AbstractMachine/Configuration.cpp @@ -11,11 +11,10 @@ namespace Wasm { -void Configuration::unwind(Badge, CallFrameHandle const& frame_handle) +void Configuration::unwind(Badge, CallFrameHandle const&) { m_frame_stack.take_last(); m_depth--; - m_ip = frame_handle.ip.value(); m_locals_base = m_frame_stack.is_empty() ? nullptr : m_frame_stack.unchecked_last().locals().data(); } diff --git a/Libraries/LibWasm/AbstractMachine/Configuration.h b/Libraries/LibWasm/AbstractMachine/Configuration.h index e3aef3af23b..9c3ec8be4b7 100644 --- a/Libraries/LibWasm/AbstractMachine/Configuration.h +++ b/Libraries/LibWasm/AbstractMachine/Configuration.h @@ -21,7 +21,7 @@ public: void set_frame(Frame frame) { - Label label(frame.arity(), frame.expression().instructions().size(), m_value_stack.size()); + Label label(frame.arity(), frame.expression().instructions().size() - 1, m_value_stack.size()); frame.label_index() = m_label_stack.size(); if (auto hint = frame.expression().stack_usage_hint(); hint.has_value()) m_value_stack.ensure_capacity(*hint + m_value_stack.size()); @@ -50,8 +50,7 @@ public: struct CallFrameHandle { explicit CallFrameHandle(Configuration& configuration) - : ip(configuration.ip()) - , configuration(configuration) + : configuration(configuration) { configuration.depth()++; } @@ -61,7 +60,6 @@ public: configuration.unwind({}, *this); } - InstructionPointer ip { 0 }; Configuration& configuration; }; @@ -74,7 +72,7 @@ public: void dump_stack(); - ALWAYS_INLINE FLATTEN void push_to_destination(Value value) + ALWAYS_INLINE FLATTEN void push_to_destination(Value value, Dispatch::RegisterOrStack destination) { if (destination == Dispatch::RegisterOrStack::Stack) { value_stack().unchecked_append(value); @@ -83,7 +81,7 @@ public: regs.data()[to_underlying(destination)] = value; } - ALWAYS_INLINE FLATTEN Value& source_value(u8 index) + ALWAYS_INLINE FLATTEN Value& source_value(u8 index, Dispatch::RegisterOrStack const* sources) { // Note: The last source in a dispatch *must* be equal to the destination for this to be valid. auto const source = sources[index]; @@ -92,7 +90,7 @@ public: return regs.data()[to_underlying(source)]; } - ALWAYS_INLINE FLATTEN Value take_source(u8 index) + ALWAYS_INLINE FLATTEN Value take_source(u8 index, Dispatch::RegisterOrStack const* sources) { auto const source = sources[index]; if (source == Dispatch::RegisterOrStack::Stack) @@ -100,14 +98,6 @@ public: return regs.data()[to_underlying(source)]; } - union { - struct { - Dispatch::RegisterOrStack sources[3]; - Dispatch::RegisterOrStack destination; - }; - u32 sources_and_destination; - }; - Array regs = { Value(0), Value(0), diff --git a/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Libraries/LibWasm/AbstractMachine/Validator.cpp index 94a54ec45d0..16935674c39 100644 --- a/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -3700,6 +3700,12 @@ VALIDATE_INSTRUCTION(f64x2_convert_low_i32x4_u) return stack.take_and_put(ValueType::V128); } +VALIDATE_INSTRUCTION(synthetic_end_expression) +{ + is_constant = true; + return {}; // Always valid. +} + ErrorOr Validator::validate(Instruction const& instruction, Stack& stack, bool& is_constant) { switch (instruction.opcode().value()) { diff --git a/Libraries/LibWasm/Opcode.h b/Libraries/LibWasm/Opcode.h index e246dd93e85..9a6a47ffe3b 100644 --- a/Libraries/LibWasm/Opcode.h +++ b/Libraries/LibWasm/Opcode.h @@ -473,7 +473,8 @@ namespace Instructions { M(synthetic_call_20, 0xfe0000000000000aull, 2, 0) \ M(synthetic_call_21, 0xfe0000000000000bull, 2, 1) \ M(synthetic_call_30, 0xfe0000000000000cull, 3, 0) \ - M(synthetic_call_31, 0xfe0000000000000dull, 3, 1) + M(synthetic_call_31, 0xfe0000000000000dull, 3, 1) \ + M(synthetic_end_expression, 0xfe0000000000000eull, 0, 0) #define ENUMERATE_WASM_OPCODES(M) \ ENUMERATE_SINGLE_BYTE_WASM_OPCODES(M) \ @@ -484,7 +485,7 @@ ENUMERATE_WASM_OPCODES(M) #undef M static constexpr inline OpCode SyntheticInstructionBase = 0xfe00000000000000ull; -static constexpr inline size_t SyntheticInstructionCount = 14; +static constexpr inline size_t SyntheticInstructionCount = 15; } diff --git a/Libraries/LibWasm/Parser/Parser.cpp b/Libraries/LibWasm/Parser/Parser.cpp index 27fa47c7841..9e04fb41c2a 100644 --- a/Libraries/LibWasm/Parser/Parser.cpp +++ b/Libraries/LibWasm/Parser/Parser.cpp @@ -978,8 +978,10 @@ ParseResult Expression::parse(ConstrainedStream& stream, Optional(); // Patch the end_ip of the last structured instruction @@ -999,6 +1001,8 @@ ParseResult Expression::parse(ConstrainedStream& stream, Optional ElementSection::Element::parse(ConstrainedS if (!has_exprs) { auto indices = TRY(parse_vector>(stream)); for (auto& index : indices) { - Vector instructions { Instruction(Instructions::ref_func, index) }; + Vector instructions { + Instruction(Instructions::ref_func, index), + Instruction(Instructions::synthetic_end_expression), + }; items.empend(move(instructions)); } } else { diff --git a/Libraries/LibWasm/Printer/Printer.cpp b/Libraries/LibWasm/Printer/Printer.cpp index 0f326bd20aa..05f1884a20f 100644 --- a/Libraries/LibWasm/Printer/Printer.cpp +++ b/Libraries/LibWasm/Printer/Printer.cpp @@ -1160,5 +1160,6 @@ HashMap Wasm::Names::instruction_names { { Instructions::synthetic_call_21, "synthetic:call.21" }, { Instructions::synthetic_call_30, "synthetic:call.30" }, { Instructions::synthetic_call_31, "synthetic:call.31" }, + { Instructions::synthetic_end_expression, "synthetic:expression.end" }, }; HashMap Wasm::Names::instructions_by_name; diff --git a/Libraries/LibWasm/Types.h b/Libraries/LibWasm/Types.h index 6093fc12de3..ec3bdfd9361 100644 --- a/Libraries/LibWasm/Types.h +++ b/Libraries/LibWasm/Types.h @@ -535,6 +535,7 @@ struct Dispatch { Stack = CountRegisters, }; + OpCode instruction_opcode; Instruction const* instruction { nullptr }; union { struct {