diff --git a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp index 085735de75..8513c8ff83 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/BytecodeInterpreter.cpp @@ -88,13 +88,13 @@ void BytecodeInterpreter::branch_to_label(Configuration& configuration, LabelInd template void BytecodeInterpreter::load_and_push(Configuration& configuration, Instruction const& instruction) { - auto& address = configuration.frame().module().memories().first(); + auto& arg = instruction.arguments().get(); + auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); if (!memory) { m_trap = Trap { "Nonexistent memory" }; return; } - auto& arg = instruction.arguments().get(); auto& entry = configuration.stack().peek(); auto base = entry.get().to(); if (!base.has_value()) { @@ -123,13 +123,13 @@ ALWAYS_INLINE static TDst convert_vector(TSrc v) template typename SetSign> void BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instruction const& instruction) { - auto& address = configuration.frame().module().memories().first(); + auto& arg = instruction.arguments().get(); + auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); if (!memory) { m_trap = Trap { "Nonexistent memory" }; return; } - auto& arg = instruction.arguments().get(); auto& entry = configuration.stack().peek(); auto base = entry.get().to(); if (!base.has_value()) { @@ -161,13 +161,13 @@ void BytecodeInterpreter::load_and_push_mxn(Configuration& configuration, Instru template void BytecodeInterpreter::load_and_push_m_splat(Configuration& configuration, Instruction const& instruction) { - auto& address = configuration.frame().module().memories().first(); + auto& arg = instruction.arguments().get(); + auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; auto memory = configuration.store().get(address); if (!memory) { m_trap = Trap { "Nonexistent memory" }; return; } - auto& arg = instruction.arguments().get(); auto& entry = configuration.stack().peek(); auto base = entry.get().to(); if (!base.has_value()) { @@ -384,9 +384,9 @@ void BytecodeInterpreter::pop_and_store(Configuration& configuration, Instructio void BytecodeInterpreter::store_to_memory(Configuration& configuration, Instruction const& instruction, ReadonlyBytes data, i32 base) { - auto& address = configuration.frame().module().memories().first(); - auto memory = configuration.store().get(address); auto& arg = instruction.arguments().get(); + auto& address = configuration.frame().module().memories()[arg.memory_index.value()]; + auto memory = configuration.store().get(address); u64 instance_address = static_cast(bit_cast(base)) + arg.offset; Checked addition { instance_address }; addition += data.size(); @@ -745,7 +745,8 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return; } case Instructions::memory_size.value(): { - auto address = configuration.frame().module().memories()[0]; + 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); @@ -753,7 +754,8 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi return; } case Instructions::memory_grow.value(): { - auto address = configuration.frame().module().memories()[0]; + 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.stack().peek(); @@ -767,7 +769,8 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi } // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-fill case Instructions::memory_fill.value(): { - auto address = configuration.frame().module().memories()[0]; + auto& args = instruction.arguments().get(); + auto address = configuration.frame().module().memories()[args.memory_index.value()]; auto instance = configuration.store().get(address); auto count = configuration.stack().pop().get().to().value(); auto value = configuration.stack().pop().get().to().value(); @@ -790,31 +793,35 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi } // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-copy case Instructions::memory_copy.value(): { - auto address = configuration.frame().module().memories()[0]; - auto instance = configuration.store().get(address); + 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); + auto count = configuration.stack().pop().get().to().value(); auto source_offset = configuration.stack().pop().get().to().value(); auto destination_offset = configuration.stack().pop().get().to().value(); - TRAP_IF_NOT(static_cast(source_offset + count) <= instance->data().size()); - TRAP_IF_NOT(static_cast(destination_offset + count) <= instance->data().size()); + TRAP_IF_NOT(static_cast(source_offset + count) <= source_instance->data().size()); + TRAP_IF_NOT(static_cast(destination_offset + count) <= destination_instance->data().size()); if (count == 0) return; Instruction synthetic_store_instruction { Instructions::i32_store8, - Instruction::MemoryArgument { 0, 0 } + Instruction::MemoryArgument { 0, 0, args.dst_index } }; if (destination_offset <= source_offset) { for (auto i = 0; i < count; ++i) { - auto value = instance->data()[source_offset + i]; + auto value = source_instance->data()[source_offset + i]; store_to_memory(configuration, synthetic_store_instruction, { &value, sizeof(value) }, destination_offset + i); } } else { for (auto i = count - 1; i >= 0; --i) { - auto value = instance->data()[source_offset + i]; + auto value = source_instance->data()[source_offset + i]; store_to_memory(configuration, synthetic_store_instruction, { &value, sizeof(value) }, destination_offset + i); } } @@ -823,8 +830,8 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi } // https://webassembly.github.io/spec/core/bikeshed/#exec-memory-init case Instructions::memory_init.value(): { - auto data_index = instruction.arguments().get(); - auto& data_address = configuration.frame().module().datas()[data_index.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 count = *configuration.stack().pop().get().to(); auto source_offset = *configuration.stack().pop().get().to(); @@ -836,7 +843,7 @@ void BytecodeInterpreter::interpret(Configuration& configuration, InstructionPoi Instruction synthetic_store_instruction { Instructions::i32_store8, - Instruction::MemoryArgument { 0, 0 } + Instruction::MemoryArgument { 0, 0, args.memory_index } }; for (size_t i = 0; i < (size_t)count; ++i) { diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp index 0365b090ed..a82d04f517 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -148,11 +148,6 @@ ErrorOr Validator::validate(Module& module) } } - if (m_context.memories.size() > 1) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return Errors::out_of_bounds("memory section count"sv, m_context.memories.size(), 1, 1); - } - module.set_validation_status(Module::ValidationStatus::Valid, {}); return {}; } @@ -1577,9 +1572,10 @@ VALIDATE_INSTRUCTION(elem_drop) // https://webassembly.github.io/spec/core/bikeshed/#memory-instructions%E2%91%A2 VALIDATE_INSTRUCTION(i32_load) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(i32)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(i32)); @@ -1590,9 +1586,10 @@ VALIDATE_INSTRUCTION(i32_load) VALIDATE_INSTRUCTION(i64_load) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(i64)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(i64)); @@ -1603,9 +1600,10 @@ VALIDATE_INSTRUCTION(i64_load) VALIDATE_INSTRUCTION(f32_load) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(float)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(float)); @@ -1616,9 +1614,10 @@ VALIDATE_INSTRUCTION(f32_load) VALIDATE_INSTRUCTION(f64_load) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(double)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(double)); @@ -1629,9 +1628,10 @@ VALIDATE_INSTRUCTION(f64_load) VALIDATE_INSTRUCTION(i32_load16_s) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1642,9 +1642,10 @@ VALIDATE_INSTRUCTION(i32_load16_s) VALIDATE_INSTRUCTION(i32_load16_u) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1655,9 +1656,10 @@ VALIDATE_INSTRUCTION(i32_load16_u) VALIDATE_INSTRUCTION(i32_load8_s) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1668,9 +1670,10 @@ VALIDATE_INSTRUCTION(i32_load8_s) VALIDATE_INSTRUCTION(i32_load8_u) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1681,9 +1684,10 @@ VALIDATE_INSTRUCTION(i32_load8_u) VALIDATE_INSTRUCTION(i64_load32_s) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 32 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 32 / 8); @@ -1694,9 +1698,10 @@ VALIDATE_INSTRUCTION(i64_load32_s) VALIDATE_INSTRUCTION(i64_load32_u) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 32 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 32 / 8); @@ -1707,9 +1712,10 @@ VALIDATE_INSTRUCTION(i64_load32_u) VALIDATE_INSTRUCTION(i64_load16_s) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1720,9 +1726,10 @@ VALIDATE_INSTRUCTION(i64_load16_s) VALIDATE_INSTRUCTION(i64_load16_u) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1733,9 +1740,10 @@ VALIDATE_INSTRUCTION(i64_load16_u) VALIDATE_INSTRUCTION(i64_load8_s) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1746,9 +1754,10 @@ VALIDATE_INSTRUCTION(i64_load8_s) VALIDATE_INSTRUCTION(i64_load8_u) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1759,9 +1768,10 @@ VALIDATE_INSTRUCTION(i64_load8_u) VALIDATE_INSTRUCTION(i32_store) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(i32)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(i32)); @@ -1772,9 +1782,10 @@ VALIDATE_INSTRUCTION(i32_store) VALIDATE_INSTRUCTION(i64_store) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(i64)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(i64)); @@ -1785,9 +1796,10 @@ VALIDATE_INSTRUCTION(i64_store) VALIDATE_INSTRUCTION(f32_store) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(float)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(float)); @@ -1798,9 +1810,10 @@ VALIDATE_INSTRUCTION(f32_store) VALIDATE_INSTRUCTION(f64_store) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(double)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(double)); @@ -1811,9 +1824,10 @@ VALIDATE_INSTRUCTION(f64_store) VALIDATE_INSTRUCTION(i32_store16) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1824,9 +1838,10 @@ VALIDATE_INSTRUCTION(i32_store16) VALIDATE_INSTRUCTION(i32_store8) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1837,9 +1852,10 @@ VALIDATE_INSTRUCTION(i32_store8) VALIDATE_INSTRUCTION(i64_store32) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 32 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 32 / 8); @@ -1850,9 +1866,10 @@ VALIDATE_INSTRUCTION(i64_store32) VALIDATE_INSTRUCTION(i64_store16) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 16 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 16 / 8); @@ -1863,9 +1880,10 @@ VALIDATE_INSTRUCTION(i64_store16) VALIDATE_INSTRUCTION(i64_store8) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > 8 / 8) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, 8 / 8); @@ -1876,7 +1894,7 @@ VALIDATE_INSTRUCTION(i64_store8) VALIDATE_INSTRUCTION(memory_size) { - TRY(validate(MemoryIndex { 0 })); + TRY(validate(instruction.arguments().get().memory_index)); stack.append(ValueType(ValueType::I32)); return {}; @@ -1884,7 +1902,8 @@ VALIDATE_INSTRUCTION(memory_size) VALIDATE_INSTRUCTION(memory_grow) { - TRY(validate(MemoryIndex { 0 })); + TRY(validate(instruction.arguments().get().memory_index)); + TRY((stack.take())); stack.append(ValueType(ValueType::I32)); @@ -1893,7 +1912,7 @@ VALIDATE_INSTRUCTION(memory_grow) VALIDATE_INSTRUCTION(memory_fill) { - TRY(validate(MemoryIndex { 0 })); + TRY(validate(instruction.arguments().get().memory_index)); TRY((stack.take())); @@ -1902,7 +1921,9 @@ VALIDATE_INSTRUCTION(memory_fill) VALIDATE_INSTRUCTION(memory_copy) { - TRY(validate(MemoryIndex { 0 })); + auto& args = instruction.arguments().get(); + TRY(validate(args.src_index)); + TRY(validate(args.dst_index)); TRY((stack.take())); @@ -1911,10 +1932,11 @@ VALIDATE_INSTRUCTION(memory_copy) VALIDATE_INSTRUCTION(memory_init) { - TRY(validate(MemoryIndex { 0 })); - auto index = instruction.arguments().get(); - TRY(validate(index)); + auto& args = instruction.arguments().get(); + + TRY(validate(args.memory_index)); + TRY(validate(args.data_index)); TRY((stack.take())); @@ -2183,9 +2205,10 @@ VALIDATE_INSTRUCTION(call_indirect) VALIDATE_INSTRUCTION(v128_load) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(u128)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(u128)); @@ -2201,7 +2224,7 @@ VALIDATE_INSTRUCTION(v128_load8x8_s) constexpr auto M = 8; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2216,7 +2239,7 @@ VALIDATE_INSTRUCTION(v128_load8x8_u) constexpr auto M = 8; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2231,7 +2254,7 @@ VALIDATE_INSTRUCTION(v128_load16x4_s) constexpr auto M = 4; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2246,7 +2269,7 @@ VALIDATE_INSTRUCTION(v128_load16x4_u) constexpr auto M = 4; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2261,7 +2284,7 @@ VALIDATE_INSTRUCTION(v128_load32x2_s) constexpr auto M = 2; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2276,7 +2299,7 @@ VALIDATE_INSTRUCTION(v128_load32x2_u) constexpr auto M = 2; constexpr auto max_alignment = N * M / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2290,7 +2313,7 @@ VALIDATE_INSTRUCTION(v128_load8_splat) constexpr auto N = 8; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2304,7 +2327,7 @@ VALIDATE_INSTRUCTION(v128_load16_splat) constexpr auto N = 16; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2318,7 +2341,7 @@ VALIDATE_INSTRUCTION(v128_load32_splat) constexpr auto N = 32; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2332,7 +2355,7 @@ VALIDATE_INSTRUCTION(v128_load64_splat) constexpr auto N = 64; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -2342,9 +2365,10 @@ VALIDATE_INSTRUCTION(v128_load64_splat) VALIDATE_INSTRUCTION(v128_store) { - TRY(validate(MemoryIndex { 0 })); - auto& arg = instruction.arguments().get(); + + TRY(validate(arg.memory_index)); + if ((1ull << arg.align) > sizeof(u128)) return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(u128)); @@ -2865,7 +2889,7 @@ VALIDATE_INSTRUCTION(v128_load8_lane) if (arg.lane > max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2883,7 +2907,7 @@ VALIDATE_INSTRUCTION(v128_load16_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2901,7 +2925,7 @@ VALIDATE_INSTRUCTION(v128_load32_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2919,7 +2943,7 @@ VALIDATE_INSTRUCTION(v128_load64_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if (arg.memory.align > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2937,7 +2961,7 @@ VALIDATE_INSTRUCTION(v128_store8_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2955,7 +2979,7 @@ VALIDATE_INSTRUCTION(v128_store16_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2973,7 +2997,7 @@ VALIDATE_INSTRUCTION(v128_store32_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -2991,7 +3015,7 @@ VALIDATE_INSTRUCTION(v128_store64_lane) if (arg.lane >= max_lane) return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory.memory_index)); if ((1 << arg.memory.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); @@ -3005,7 +3029,7 @@ VALIDATE_INSTRUCTION(v128_load32_zero) constexpr auto N = 32; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); @@ -3019,7 +3043,7 @@ VALIDATE_INSTRUCTION(v128_load64_zero) constexpr auto N = 64; constexpr auto max_alignment = N / 8; - TRY(validate(MemoryIndex { 0 })); + TRY(validate(arg.memory_index)); if ((1 << arg.align) > max_alignment) return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 17efb8eadd..0465cc29f5 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -418,18 +418,28 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP case Instructions::i64_store8.value(): case Instructions::i64_store16.value(): case Instructions::i64_store32.value(): { - // op (align offset) + // op (align [multi-memory: memindex] offset) auto align_or_error = stream.read_value>(); if (align_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); size_t align = align_or_error.release_value(); + // Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment. + size_t memory_index = 0; + if ((align & 0x20) != 0) { + align &= ~0x20; + auto memory_index_or_error = stream.read_value>(); + if (memory_index_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + memory_index = memory_index_or_error.release_value(); + } + auto offset_or_error = stream.read_value>(); if (offset_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); size_t offset = offset_or_error.release_value(); - resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset) } }); + resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset), MemoryIndex(memory_index) } }); break; } case Instructions::local_get.value(): @@ -453,19 +463,15 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP } case Instructions::memory_size.value(): case Instructions::memory_grow.value(): { - // op 0x0 - // The zero is currently unused. - auto unused_or_error = stream.read_value(); - if (unused_or_error.is_error()) + // op [multi-memory: memindex]|0x00 + + auto memory_index_or_error = stream.read_value(); + if (memory_index_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedKindTag); - auto unused = unused_or_error.release_value(); - if (unused != 0x00) { - dbgln("Invalid tag in memory_grow {}", unused); - return with_eof_check(stream, ParseError::InvalidTag); - } + auto memory_index = memory_index_or_error.release_value(); - resulting_instructions.append(Instruction { opcode }); + resulting_instructions.append(Instruction { opcode, MemoryIndexArgument { MemoryIndex(memory_index) } }); break; } case Instructions::i32_const.value(): { @@ -704,14 +710,15 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - auto unused_or_error = stream.read_value(); - if (unused_or_error.is_error()) + + // Proposal "multi-memory", literal 0x00 is replaced with a memory index. + auto memory_index_or_error = stream.read_value(); + if (memory_index_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); - auto unused = unused_or_error.release_value(); - if (unused != 0x00) - return ParseError::InvalidImmediate; - resulting_instructions.append(Instruction { full_opcode, index.release_value() }); + auto memory_index = memory_index_or_error.release_value(); + + resulting_instructions.append(Instruction { full_opcode, MemoryInitArgs { index.release_value(), MemoryIndex(memory_index) } }); break; } case Instructions::data_drop.value(): { @@ -722,27 +729,27 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP break; } case Instructions::memory_copy.value(): { + // Proposal "multi-memory", literal 0x00 is replaced with two memory indices, destination and source, respectively. + MemoryIndex indices[] = { 0, 0 }; + for (size_t i = 0; i < 2; ++i) { - auto unused_or_error = stream.read_value(); - if (unused_or_error.is_error()) + auto memory_index_or_error = stream.read_value(); + if (memory_index_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); - auto unused = unused_or_error.release_value(); - if (unused != 0x00) - return ParseError::InvalidImmediate; + indices[i] = memory_index_or_error.release_value(); } - resulting_instructions.append(Instruction { full_opcode }); + resulting_instructions.append(Instruction { full_opcode, MemoryCopyArgs { indices[1], indices[0] } }); break; } case Instructions::memory_fill.value(): { - auto unused_or_error = stream.read_value(); - if (unused_or_error.is_error()) + // Proposal "multi-memory", literal 0x00 is replaced with a memory index. + auto memory_index_or_error = stream.read_value(); + if (memory_index_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); - auto unused = unused_or_error.release_value(); - if (unused != 0x00) - return ParseError::InvalidImmediate; - resulting_instructions.append(Instruction { full_opcode }); + auto memory_index = memory_index_or_error.release_value(); + resulting_instructions.append(Instruction { full_opcode, MemoryIndexArgument { MemoryIndex { memory_index } } }); break; } case Instructions::table_init.value(): { @@ -793,17 +800,28 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP case Instructions::v128_load32_splat.value(): case Instructions::v128_load64_splat.value(): case Instructions::v128_store.value(): { - // op (align offset) + // op (align [multi-memory memindex] offset) auto align_or_error = stream.read_value>(); if (align_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedIndex); size_t align = align_or_error.release_value(); + + // Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment. + size_t memory_index = 0; + if ((align & 0x20) != 0) { + align &= ~0x20; + auto memory_index_or_error = stream.read_value>(); + if (memory_index_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + memory_index = memory_index_or_error.release_value(); + } + auto offset_or_error = stream.read_value>(); if (offset_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedIndex); size_t offset = offset_or_error.release_value(); - resulting_instructions.append(Instruction { full_opcode, MemoryArgument { static_cast(align), static_cast(offset) } }); + resulting_instructions.append(Instruction { full_opcode, MemoryArgument { static_cast(align), static_cast(offset), MemoryIndex(memory_index) } }); break; } case Instructions::v128_load8_lane.value(): @@ -814,11 +832,22 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP case Instructions::v128_store16_lane.value(): case Instructions::v128_store32_lane.value(): case Instructions::v128_store64_lane.value(): { - // op (align offset) (index) + // op (align [multi-memory: memindex] offset) (index) auto align_or_error = stream.read_value>(); if (align_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedIndex); size_t align = align_or_error.release_value(); + + // Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment. + size_t memory_index = 0; + if ((align & 0x20) != 0) { + align &= ~0x20; + auto memory_index_or_error = stream.read_value>(); + if (memory_index_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + memory_index = memory_index_or_error.release_value(); + } + auto offset_or_error = stream.read_value>(); if (offset_or_error.is_error()) return with_eof_check(stream, ParseError::ExpectedIndex); @@ -829,7 +858,7 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP return with_eof_check(stream, ParseError::InvalidInput); auto index = index_or_error.release_value(); - resulting_instructions.append(Instruction { full_opcode, MemoryAndLaneArgument { { static_cast(align), static_cast(offset) }, index } }); + resulting_instructions.append(Instruction { full_opcode, MemoryAndLaneArgument { { static_cast(align), static_cast(offset), MemoryIndex(memory_index) }, index } }); break; } case Instructions::v128_const.value(): { diff --git a/Userland/Libraries/LibWasm/Printer/Printer.cpp b/Userland/Libraries/LibWasm/Printer/Printer.cpp index 167aea0377..23858e46c1 100644 --- a/Userland/Libraries/LibWasm/Printer/Printer.cpp +++ b/Userland/Libraries/LibWasm/Printer/Printer.cpp @@ -432,8 +432,11 @@ void Printer::print(Wasm::Instruction const& instruction) [&](LocalIndex const& index) { print("(local index {})", index.value()); }, [&](TableIndex const& index) { print("(table index {})", index.value()); }, [&](Instruction::IndirectCallArgs const& args) { print("(indirect (type index {}) (table index {}))", args.type.value(), args.table.value()); }, - [&](Instruction::MemoryArgument const& args) { print("(memory (align {}) (offset {}))", args.align, args.offset); }, - [&](Instruction::MemoryAndLaneArgument const& args) { print("(memory (align {}) (offset {})) (lane {})", args.memory.align, args.memory.offset, args.lane); }, + [&](Instruction::MemoryArgument const& args) { print("(memory index {} (align {}) (offset {}))", args.memory_index.value(), args.align, args.offset); }, + [&](Instruction::MemoryAndLaneArgument const& args) { print("(memory index {} (align {}) (offset {})) (lane {})", args.memory.memory_index.value(), args.memory.align, args.memory.offset, args.lane); }, + [&](Instruction::MemoryInitArgs const& args) { print("(memory index {}) (data index {})", args.memory_index.value(), args.data_index.value()); }, + [&](Instruction::MemoryCopyArgs const& args) { print("(from (memory index {}) to (memory index {}))", args.src_index.value(), args.dst_index.value()); }, + [&](Instruction::MemoryIndexArgument const& args) { print("(memory index {})", args.memory_index.value()); }, [&](Instruction::LaneIndex const& args) { print("(lane {})", args.lane); }, [&](Instruction::ShuffleArgument const& args) { print("{{ {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} }}", diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index a2769c5979..fb4f301582 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -410,6 +410,7 @@ public: struct MemoryArgument { u32 align; u32 offset; + MemoryIndex memory_index { 0 }; }; struct MemoryAndLaneArgument { @@ -421,6 +422,21 @@ public: u8 lane; }; + // Proposal "multi-memory" + struct MemoryCopyArgs { + MemoryIndex src_index; + MemoryIndex dst_index; + }; + + struct MemoryInitArgs { + DataIndex data_index; + MemoryIndex memory_index; + }; + + struct MemoryIndexArgument { + MemoryIndex memory_index; + }; + struct ShuffleArgument { explicit ShuffleArgument(u8 (&lanes)[16]) : lanes { @@ -460,6 +476,9 @@ private: LocalIndex, MemoryArgument, MemoryAndLaneArgument, + MemoryCopyArgs, + MemoryIndexArgument, + MemoryInitArgs, StructuredInstructionArgs, ShuffleArgument, TableBranchArgs,