diff --git a/Userland/Libraries/LibWasm/Opcode.h b/Userland/Libraries/LibWasm/Opcode.h index 8381f11b040..b540d575467 100644 --- a/Userland/Libraries/LibWasm/Opcode.h +++ b/Userland/Libraries/LibWasm/Opcode.h @@ -20,6 +20,8 @@ namespace Instructions { M(block, 0x02) \ M(loop, 0x03) \ M(if_, 0x04) \ + M(structured_else, 0x05) \ + M(structured_end, 0x0b) \ M(br, 0x0c) \ M(br_if, 0x0d) \ M(br_table, 0x0e) \ @@ -217,8 +219,6 @@ namespace Instructions { M(table_grow, 0xfc0000000000000full) \ M(table_size, 0xfc00000000000010ull) \ M(table_fill, 0xfc00000000000011ull) \ - M(structured_else, 0xff00000000000000ull) \ - M(structured_end, 0xff00000000000001ull) \ M(v128_load, 0xfd00000000000000ull) \ M(v128_load8x8_s, 0xfd00000000000001ull) \ M(v128_load8x8_u, 0xfd00000000000002ull) \ diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 96ee30717c7..3a4b18f5367 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -35,6 +35,7 @@ static auto parse_vector(Stream& stream) size_t count = count_or_error.release_value(); Vector entries; + entries.ensure_capacity(count); for (size_t i = 0; i < count; ++i) { auto result = T::parse(stream); if (result.is_error()) @@ -49,6 +50,7 @@ static auto parse_vector(Stream& stream) size_t count = count_or_error.release_value(); Vector entries; + entries.ensure_capacity(count); for (size_t i = 0; i < count; ++i) { if constexpr (IsSame) { auto value_or_error = stream.read_value>(); @@ -85,40 +87,6 @@ static ParseResult parse_name(Stream& stream) return string; } -template -struct ParseUntilAnyOfResult { - u8 terminator { 0 }; - Vector values; -}; -template -static ParseResult> parse_until_any_of(Stream& stream, Args&... args) -requires(requires(Stream& stream, Args... args) { T::parse(stream, args...); }) -{ - ScopeLogger logger; - ReconsumableStream new_stream { stream }; - - ParseUntilAnyOfResult result; - for (;;) { - auto byte_or_error = new_stream.read_value(); - if (byte_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedValueOrTerminator); - - auto byte = byte_or_error.release_value(); - - constexpr auto equals = [](auto&& a, auto&& b) { return a == b; }; - - if ((... || equals(byte, terminators))) { - result.terminator = byte; - return result; - } - - new_stream.unread({ &byte, 1 }); - auto parse_result = TRY(T::parse(new_stream, args...)); - - result.values.extend(parse_result); - } -} - ParseResult ValueType::parse(Stream& stream) { ScopeLogger logger("ValueType"sv); @@ -272,127 +240,413 @@ ParseResult BlockType::parse(Stream& stream) return BlockType { TypeIndex(index_value) }; } -ParseResult> Instruction::parse(Stream& stream, InstructionPointer& ip) +ParseResult Instruction::parse(Stream& stream) { - struct NestedInstructionState { - Vector prior_instructions; - OpCode opcode; - BlockType block_type; - InstructionPointer end_ip; - Optional else_ip; - }; - Vector nested_instructions; - Vector resulting_instructions; + ScopeLogger logger("Instruction"sv); + auto byte_or_error = stream.read_value(); + if (byte_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedKindTag); - do { - ScopeLogger logger("Instruction"sv); - auto byte_or_error = stream.read_value(); - if (byte_or_error.is_error()) + auto byte = byte_or_error.release_value(); + + OpCode opcode { byte }; + + switch (opcode.value()) { + case Instructions::block.value(): + case Instructions::loop.value(): + case Instructions::if_.value(): { + auto block_type = TRY(BlockType::parse(stream)); + return Instruction { + opcode, StructuredInstructionArgs { block_type, {}, {} } + }; + } + case Instructions::br.value(): + case Instructions::br_if.value(): { + // branches with a single label immediate + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, index }; + } + case Instructions::br_table.value(): { + // br_table label* label + auto labels = TRY(parse_vector>(stream)); + auto default_label = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, TableBranchArgs { labels, default_label } }; + } + case Instructions::call.value(): { + // call function + auto function_index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, function_index }; + } + case Instructions::call_indirect.value(): { + // call_indirect type table + auto type_index = TRY(GenericIndexParser::parse(stream)); + auto table_index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, IndirectCallArgs { type_index, table_index } }; + } + case Instructions::i32_load.value(): + case Instructions::i64_load.value(): + case Instructions::f32_load.value(): + case Instructions::f64_load.value(): + case Instructions::i32_load8_s.value(): + case Instructions::i32_load8_u.value(): + case Instructions::i32_load16_s.value(): + case Instructions::i32_load16_u.value(): + case Instructions::i64_load8_s.value(): + case Instructions::i64_load8_u.value(): + case Instructions::i64_load16_s.value(): + case Instructions::i64_load16_u.value(): + case Instructions::i64_load32_s.value(): + case Instructions::i64_load32_u.value(): + case Instructions::i32_store.value(): + case Instructions::i64_store.value(): + case Instructions::f32_store.value(): + case Instructions::f64_store.value(): + case Instructions::i32_store8.value(): + case Instructions::i32_store16.value(): + case Instructions::i64_store8.value(): + case Instructions::i64_store16.value(): + case Instructions::i64_store32.value(): { + // 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 & 0x40) != 0) { + align &= ~0x40; + 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(); + + return Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset), MemoryIndex(memory_index) } }; + } + case Instructions::local_get.value(): + case Instructions::local_set.value(): + case Instructions::local_tee.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, index }; + } + case Instructions::global_get.value(): + case Instructions::global_set.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, index }; + } + case Instructions::memory_size.value(): + case Instructions::memory_grow.value(): { + // 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 byte = byte_or_error.release_value(); + auto memory_index = memory_index_or_error.release_value(); - if (!nested_instructions.is_empty()) { - auto& nested_structure = nested_instructions.last(); - if (byte == 0x0b) { - // block/loop/if end - nested_structure.end_ip = ip + (nested_structure.else_ip.has_value() ? 1 : 0); - ++ip; + return Instruction { opcode, MemoryIndexArgument { MemoryIndex(memory_index) } }; + } + case Instructions::i32_const.value(): { + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedSignedImmediate); + i32 value = value_or_error.release_value(); - // Transform op(..., instr*) -> op(...) instr* op(end(ip)) - auto instructions = move(nested_structure.prior_instructions); - instructions.ensure_capacity(instructions.size() + 2 + resulting_instructions.size()); - instructions.append(Instruction { nested_structure.opcode, StructuredInstructionArgs { nested_structure.block_type, nested_structure.end_ip, nested_structure.else_ip } }); - instructions.extend(move(resulting_instructions)); - instructions.append(Instruction { Instructions::structured_end }); - resulting_instructions = move(instructions); - nested_instructions.take_last(); - continue; + return Instruction { opcode, value }; + } + case Instructions::i64_const.value(): { + // op literal + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedSignedImmediate); + i64 value = value_or_error.release_value(); + + return Instruction { opcode, value }; + } + case Instructions::f32_const.value(): { + // op literal + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); + auto value = value_or_error.release_value(); + + auto floating = bit_cast(static_cast(value)); + return Instruction { opcode, floating }; + } + case Instructions::f64_const.value(): { + // op literal + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); + auto value = value_or_error.release_value(); + + auto floating = bit_cast(static_cast(value)); + return Instruction { opcode, floating }; + } + case Instructions::table_get.value(): + case Instructions::table_set.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, index }; + } + case Instructions::select_typed.value(): { + auto types = TRY(parse_vector(stream)); + return Instruction { opcode, types }; + } + case Instructions::ref_null.value(): { + auto type = TRY(ValueType::parse(stream)); + if (!type.is_reference()) + return ParseError::InvalidType; + + return Instruction { opcode, type }; + } + case Instructions::ref_func.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { opcode, index }; + } + case Instructions::structured_end.value(): + case Instructions::structured_else.value(): + case Instructions::ref_is_null.value(): + case Instructions::unreachable.value(): + case Instructions::nop.value(): + case Instructions::return_.value(): + case Instructions::drop.value(): + case Instructions::select.value(): + case Instructions::i32_eqz.value(): + case Instructions::i32_eq.value(): + case Instructions::i32_ne.value(): + case Instructions::i32_lts.value(): + case Instructions::i32_ltu.value(): + case Instructions::i32_gts.value(): + case Instructions::i32_gtu.value(): + case Instructions::i32_les.value(): + case Instructions::i32_leu.value(): + case Instructions::i32_ges.value(): + case Instructions::i32_geu.value(): + case Instructions::i64_eqz.value(): + case Instructions::i64_eq.value(): + case Instructions::i64_ne.value(): + case Instructions::i64_lts.value(): + case Instructions::i64_ltu.value(): + case Instructions::i64_gts.value(): + case Instructions::i64_gtu.value(): + case Instructions::i64_les.value(): + case Instructions::i64_leu.value(): + case Instructions::i64_ges.value(): + case Instructions::i64_geu.value(): + case Instructions::f32_eq.value(): + case Instructions::f32_ne.value(): + case Instructions::f32_lt.value(): + case Instructions::f32_gt.value(): + case Instructions::f32_le.value(): + case Instructions::f32_ge.value(): + case Instructions::f64_eq.value(): + case Instructions::f64_ne.value(): + case Instructions::f64_lt.value(): + case Instructions::f64_gt.value(): + case Instructions::f64_le.value(): + case Instructions::f64_ge.value(): + case Instructions::i32_clz.value(): + case Instructions::i32_ctz.value(): + case Instructions::i32_popcnt.value(): + case Instructions::i32_add.value(): + case Instructions::i32_sub.value(): + case Instructions::i32_mul.value(): + case Instructions::i32_divs.value(): + case Instructions::i32_divu.value(): + case Instructions::i32_rems.value(): + case Instructions::i32_remu.value(): + case Instructions::i32_and.value(): + case Instructions::i32_or.value(): + case Instructions::i32_xor.value(): + case Instructions::i32_shl.value(): + case Instructions::i32_shrs.value(): + case Instructions::i32_shru.value(): + case Instructions::i32_rotl.value(): + case Instructions::i32_rotr.value(): + case Instructions::i64_clz.value(): + case Instructions::i64_ctz.value(): + case Instructions::i64_popcnt.value(): + case Instructions::i64_add.value(): + case Instructions::i64_sub.value(): + case Instructions::i64_mul.value(): + case Instructions::i64_divs.value(): + case Instructions::i64_divu.value(): + case Instructions::i64_rems.value(): + case Instructions::i64_remu.value(): + case Instructions::i64_and.value(): + case Instructions::i64_or.value(): + case Instructions::i64_xor.value(): + case Instructions::i64_shl.value(): + case Instructions::i64_shrs.value(): + case Instructions::i64_shru.value(): + case Instructions::i64_rotl.value(): + case Instructions::i64_rotr.value(): + case Instructions::f32_abs.value(): + case Instructions::f32_neg.value(): + case Instructions::f32_ceil.value(): + case Instructions::f32_floor.value(): + case Instructions::f32_trunc.value(): + case Instructions::f32_nearest.value(): + case Instructions::f32_sqrt.value(): + case Instructions::f32_add.value(): + case Instructions::f32_sub.value(): + case Instructions::f32_mul.value(): + case Instructions::f32_div.value(): + case Instructions::f32_min.value(): + case Instructions::f32_max.value(): + case Instructions::f32_copysign.value(): + case Instructions::f64_abs.value(): + case Instructions::f64_neg.value(): + case Instructions::f64_ceil.value(): + case Instructions::f64_floor.value(): + case Instructions::f64_trunc.value(): + case Instructions::f64_nearest.value(): + case Instructions::f64_sqrt.value(): + case Instructions::f64_add.value(): + case Instructions::f64_sub.value(): + case Instructions::f64_mul.value(): + case Instructions::f64_div.value(): + case Instructions::f64_min.value(): + case Instructions::f64_max.value(): + case Instructions::f64_copysign.value(): + case Instructions::i32_wrap_i64.value(): + case Instructions::i32_trunc_sf32.value(): + case Instructions::i32_trunc_uf32.value(): + case Instructions::i32_trunc_sf64.value(): + case Instructions::i32_trunc_uf64.value(): + case Instructions::i64_extend_si32.value(): + case Instructions::i64_extend_ui32.value(): + case Instructions::i64_trunc_sf32.value(): + case Instructions::i64_trunc_uf32.value(): + case Instructions::i64_trunc_sf64.value(): + case Instructions::i64_trunc_uf64.value(): + case Instructions::f32_convert_si32.value(): + case Instructions::f32_convert_ui32.value(): + case Instructions::f32_convert_si64.value(): + case Instructions::f32_convert_ui64.value(): + case Instructions::f32_demote_f64.value(): + case Instructions::f64_convert_si32.value(): + case Instructions::f64_convert_ui32.value(): + case Instructions::f64_convert_si64.value(): + case Instructions::f64_convert_ui64.value(): + case Instructions::f64_promote_f32.value(): + case Instructions::i32_reinterpret_f32.value(): + case Instructions::i64_reinterpret_f64.value(): + case Instructions::f32_reinterpret_i32.value(): + case Instructions::f64_reinterpret_i64.value(): + case Instructions::i32_extend8_s.value(): + case Instructions::i32_extend16_s.value(): + case Instructions::i64_extend8_s.value(): + case Instructions::i64_extend16_s.value(): + case Instructions::i64_extend32_s.value(): + return Instruction { opcode }; + case 0xfc: + case 0xfd: { + // These are multibyte instructions. + auto selector_or_error = stream.read_value>(); + if (selector_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + u32 selector = selector_or_error.release_value(); + OpCode full_opcode = static_cast(opcode.value()) << 56 | selector; + + switch (full_opcode.value()) { + case Instructions::i32_trunc_sat_f32_s.value(): + case Instructions::i32_trunc_sat_f32_u.value(): + case Instructions::i32_trunc_sat_f64_s.value(): + case Instructions::i32_trunc_sat_f64_u.value(): + case Instructions::i64_trunc_sat_f32_s.value(): + case Instructions::i64_trunc_sat_f32_u.value(): + case Instructions::i64_trunc_sat_f64_s.value(): + case Instructions::i64_trunc_sat_f64_u.value(): + return Instruction { full_opcode }; + case Instructions::memory_init.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + + // 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 memory_index = memory_index_or_error.release_value(); + + return Instruction { full_opcode, MemoryInitArgs { index, MemoryIndex(memory_index) } }; + } + case Instructions::data_drop.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { full_opcode, index }; + } + 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 memory_index_or_error = stream.read_value(); + if (memory_index_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + + indices[i] = memory_index_or_error.release_value(); } + return Instruction { full_opcode, MemoryCopyArgs { indices[1], indices[0] } }; + } + case Instructions::memory_fill.value(): { + // 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); - if (byte == 0x05) { - // if...else - - // Transform op(..., instr*, instr*) -> op(...) instr* op(else(ip) instr* op(end(ip)) - resulting_instructions.append(Instruction { Instructions::structured_else }); - ++ip; - nested_structure.else_ip = ip.value(); - continue; - } + auto memory_index = memory_index_or_error.release_value(); + return Instruction { full_opcode, MemoryIndexArgument { MemoryIndex { memory_index } } }; } - - OpCode opcode { byte }; - ++ip; - - switch (opcode.value()) { - case Instructions::block.value(): - case Instructions::loop.value(): - case Instructions::if_.value(): { - auto block_type = TRY(BlockType::parse(stream)); - nested_instructions.append({ move(resulting_instructions), opcode, block_type, {}, {} }); - resulting_instructions = {}; - break; - } - case Instructions::br.value(): - case Instructions::br_if.value(): { - // branches with a single label immediate - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, index }); - break; - } - case Instructions::br_table.value(): { - // br_table label* label - auto labels = TRY(parse_vector>(stream)); - auto default_label = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, TableBranchArgs { labels, default_label } }); - break; - } - case Instructions::call.value(): { - // call function - auto function_index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, function_index }); - break; - } - case Instructions::call_indirect.value(): { - // call_indirect type table - auto type_index = TRY(GenericIndexParser::parse(stream)); + case Instructions::table_init.value(): { + auto element_index = TRY(GenericIndexParser::parse(stream)); auto table_index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, IndirectCallArgs { type_index, table_index } }); - break; + return Instruction { full_opcode, TableElementArgs { element_index, table_index } }; } - case Instructions::i32_load.value(): - case Instructions::i64_load.value(): - case Instructions::f32_load.value(): - case Instructions::f64_load.value(): - case Instructions::i32_load8_s.value(): - case Instructions::i32_load8_u.value(): - case Instructions::i32_load16_s.value(): - case Instructions::i32_load16_u.value(): - case Instructions::i64_load8_s.value(): - case Instructions::i64_load8_u.value(): - case Instructions::i64_load16_s.value(): - case Instructions::i64_load16_u.value(): - case Instructions::i64_load32_s.value(): - case Instructions::i64_load32_u.value(): - case Instructions::i32_store.value(): - case Instructions::i64_store.value(): - case Instructions::f32_store.value(): - case Instructions::f64_store.value(): - case Instructions::i32_store8.value(): - case Instructions::i32_store16.value(): - case Instructions::i64_store8.value(): - case Instructions::i64_store16.value(): - case Instructions::i64_store32.value(): { - // op (align [multi-memory: memindex] offset) + case Instructions::elem_drop.value(): { + auto element_index = TRY(GenericIndexParser::parse(stream)); + return Instruction { full_opcode, element_index }; + } + case Instructions::table_copy.value(): { + auto lhs = TRY(GenericIndexParser::parse(stream)); + auto rhs = TRY(GenericIndexParser::parse(stream)); + return Instruction { full_opcode, TableTableArgs { lhs, rhs } }; + } + case Instructions::table_grow.value(): + case Instructions::table_size.value(): + case Instructions::table_fill.value(): { + auto index = TRY(GenericIndexParser::parse(stream)); + return Instruction { full_opcode, index }; + } + case Instructions::v128_load.value(): + case Instructions::v128_load8x8_s.value(): + case Instructions::v128_load8x8_u.value(): + case Instructions::v128_load16x4_s.value(): + case Instructions::v128_load16x4_u.value(): + case Instructions::v128_load32x2_s.value(): + case Instructions::v128_load32x2_u.value(): + case Instructions::v128_load8_splat.value(): + case Instructions::v128_load16_splat.value(): + case Instructions::v128_load32_splat.value(): + case Instructions::v128_load64_splat.value(): + case Instructions::v128_load32_zero.value(): + case Instructions::v128_load64_zero.value(): + case Instructions::v128_store.value(): { + // 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); + 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 & 0x40) != 0) { - align &= ~0x40; + 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); @@ -401,651 +655,292 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP auto offset_or_error = stream.read_value>(); if (offset_or_error.is_error()) - return with_eof_check(stream, ParseError::InvalidInput); + return with_eof_check(stream, ParseError::ExpectedIndex); size_t offset = offset_or_error.release_value(); - resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset), MemoryIndex(memory_index) } }); - break; + return Instruction { full_opcode, MemoryArgument { static_cast(align), static_cast(offset), MemoryIndex(memory_index) } }; } - case Instructions::local_get.value(): - case Instructions::local_set.value(): - case Instructions::local_tee.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, index }); - break; - } - case Instructions::global_get.value(): - case Instructions::global_set.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, index }); - break; - } - case Instructions::memory_size.value(): - case Instructions::memory_grow.value(): { - // op [multi-memory: memindex]|0x00 + case Instructions::v128_load8_lane.value(): + case Instructions::v128_load16_lane.value(): + case Instructions::v128_load32_lane.value(): + case Instructions::v128_load64_lane.value(): + case Instructions::v128_store8_lane.value(): + case Instructions::v128_store16_lane.value(): + case Instructions::v128_store32_lane.value(): + case Instructions::v128_store64_lane.value(): { + // 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(); - auto memory_index_or_error = stream.read_value(); - if (memory_index_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedKindTag); + // 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 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 { opcode, MemoryIndexArgument { MemoryIndex(memory_index) } }); - break; - } - case Instructions::i32_const.value(): { - auto value_or_error = stream.read_value>(); - if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedSignedImmediate); - i32 value = value_or_error.release_value(); - - resulting_instructions.append(Instruction { opcode, value }); - break; - } - case Instructions::i64_const.value(): { - // op literal - auto value_or_error = stream.read_value>(); - if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedSignedImmediate); - i64 value = value_or_error.release_value(); - - resulting_instructions.append(Instruction { opcode, value }); - break; - } - case Instructions::f32_const.value(): { - // op literal - auto value_or_error = stream.read_value>(); - if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); - auto value = value_or_error.release_value(); - - auto floating = bit_cast(static_cast(value)); - resulting_instructions.append(Instruction { opcode, floating }); - break; - } - case Instructions::f64_const.value(): { - // op literal - auto value_or_error = stream.read_value>(); - if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); - auto value = value_or_error.release_value(); - - auto floating = bit_cast(static_cast(value)); - resulting_instructions.append(Instruction { opcode, floating }); - break; - } - case Instructions::table_get.value(): - case Instructions::table_set.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, index }); - break; - } - case Instructions::select_typed.value(): { - auto types = TRY(parse_vector(stream)); - resulting_instructions.append(Instruction { opcode, types }); - break; - } - case Instructions::ref_null.value(): { - auto type = TRY(ValueType::parse(stream)); - if (!type.is_reference()) - return ParseError::InvalidType; - - resulting_instructions.append(Instruction { opcode, type }); - break; - } - case Instructions::ref_func.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { opcode, index }); - break; - } - case Instructions::ref_is_null.value(): - case Instructions::unreachable.value(): - case Instructions::nop.value(): - case Instructions::return_.value(): - case Instructions::drop.value(): - case Instructions::select.value(): - case Instructions::i32_eqz.value(): - case Instructions::i32_eq.value(): - case Instructions::i32_ne.value(): - case Instructions::i32_lts.value(): - case Instructions::i32_ltu.value(): - case Instructions::i32_gts.value(): - case Instructions::i32_gtu.value(): - case Instructions::i32_les.value(): - case Instructions::i32_leu.value(): - case Instructions::i32_ges.value(): - case Instructions::i32_geu.value(): - case Instructions::i64_eqz.value(): - case Instructions::i64_eq.value(): - case Instructions::i64_ne.value(): - case Instructions::i64_lts.value(): - case Instructions::i64_ltu.value(): - case Instructions::i64_gts.value(): - case Instructions::i64_gtu.value(): - case Instructions::i64_les.value(): - case Instructions::i64_leu.value(): - case Instructions::i64_ges.value(): - case Instructions::i64_geu.value(): - case Instructions::f32_eq.value(): - case Instructions::f32_ne.value(): - case Instructions::f32_lt.value(): - case Instructions::f32_gt.value(): - case Instructions::f32_le.value(): - case Instructions::f32_ge.value(): - case Instructions::f64_eq.value(): - case Instructions::f64_ne.value(): - case Instructions::f64_lt.value(): - case Instructions::f64_gt.value(): - case Instructions::f64_le.value(): - case Instructions::f64_ge.value(): - case Instructions::i32_clz.value(): - case Instructions::i32_ctz.value(): - case Instructions::i32_popcnt.value(): - case Instructions::i32_add.value(): - case Instructions::i32_sub.value(): - case Instructions::i32_mul.value(): - case Instructions::i32_divs.value(): - case Instructions::i32_divu.value(): - case Instructions::i32_rems.value(): - case Instructions::i32_remu.value(): - case Instructions::i32_and.value(): - case Instructions::i32_or.value(): - case Instructions::i32_xor.value(): - case Instructions::i32_shl.value(): - case Instructions::i32_shrs.value(): - case Instructions::i32_shru.value(): - case Instructions::i32_rotl.value(): - case Instructions::i32_rotr.value(): - case Instructions::i64_clz.value(): - case Instructions::i64_ctz.value(): - case Instructions::i64_popcnt.value(): - case Instructions::i64_add.value(): - case Instructions::i64_sub.value(): - case Instructions::i64_mul.value(): - case Instructions::i64_divs.value(): - case Instructions::i64_divu.value(): - case Instructions::i64_rems.value(): - case Instructions::i64_remu.value(): - case Instructions::i64_and.value(): - case Instructions::i64_or.value(): - case Instructions::i64_xor.value(): - case Instructions::i64_shl.value(): - case Instructions::i64_shrs.value(): - case Instructions::i64_shru.value(): - case Instructions::i64_rotl.value(): - case Instructions::i64_rotr.value(): - case Instructions::f32_abs.value(): - case Instructions::f32_neg.value(): - case Instructions::f32_ceil.value(): - case Instructions::f32_floor.value(): - case Instructions::f32_trunc.value(): - case Instructions::f32_nearest.value(): - case Instructions::f32_sqrt.value(): - case Instructions::f32_add.value(): - case Instructions::f32_sub.value(): - case Instructions::f32_mul.value(): - case Instructions::f32_div.value(): - case Instructions::f32_min.value(): - case Instructions::f32_max.value(): - case Instructions::f32_copysign.value(): - case Instructions::f64_abs.value(): - case Instructions::f64_neg.value(): - case Instructions::f64_ceil.value(): - case Instructions::f64_floor.value(): - case Instructions::f64_trunc.value(): - case Instructions::f64_nearest.value(): - case Instructions::f64_sqrt.value(): - case Instructions::f64_add.value(): - case Instructions::f64_sub.value(): - case Instructions::f64_mul.value(): - case Instructions::f64_div.value(): - case Instructions::f64_min.value(): - case Instructions::f64_max.value(): - case Instructions::f64_copysign.value(): - case Instructions::i32_wrap_i64.value(): - case Instructions::i32_trunc_sf32.value(): - case Instructions::i32_trunc_uf32.value(): - case Instructions::i32_trunc_sf64.value(): - case Instructions::i32_trunc_uf64.value(): - case Instructions::i64_extend_si32.value(): - case Instructions::i64_extend_ui32.value(): - case Instructions::i64_trunc_sf32.value(): - case Instructions::i64_trunc_uf32.value(): - case Instructions::i64_trunc_sf64.value(): - case Instructions::i64_trunc_uf64.value(): - case Instructions::f32_convert_si32.value(): - case Instructions::f32_convert_ui32.value(): - case Instructions::f32_convert_si64.value(): - case Instructions::f32_convert_ui64.value(): - case Instructions::f32_demote_f64.value(): - case Instructions::f64_convert_si32.value(): - case Instructions::f64_convert_ui32.value(): - case Instructions::f64_convert_si64.value(): - case Instructions::f64_convert_ui64.value(): - case Instructions::f64_promote_f32.value(): - case Instructions::i32_reinterpret_f32.value(): - case Instructions::i64_reinterpret_f64.value(): - case Instructions::f32_reinterpret_i32.value(): - case Instructions::f64_reinterpret_i64.value(): - case Instructions::i32_extend8_s.value(): - case Instructions::i32_extend16_s.value(): - case Instructions::i64_extend8_s.value(): - case Instructions::i64_extend16_s.value(): - case Instructions::i64_extend32_s.value(): - resulting_instructions.append(Instruction { opcode }); - break; - case 0xfc: - case 0xfd: { - // These are multibyte instructions. - auto selector_or_error = stream.read_value>(); - if (selector_or_error.is_error()) + auto index_or_error = stream.read_value(); + if (index_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); - u32 selector = selector_or_error.release_value(); - OpCode full_opcode = static_cast(opcode.value()) << 56 | selector; + auto index = index_or_error.release_value(); - switch (full_opcode.value()) { - case Instructions::i32_trunc_sat_f32_s.value(): - case Instructions::i32_trunc_sat_f32_u.value(): - case Instructions::i32_trunc_sat_f64_s.value(): - case Instructions::i32_trunc_sat_f64_u.value(): - case Instructions::i64_trunc_sat_f32_s.value(): - case Instructions::i64_trunc_sat_f32_u.value(): - case Instructions::i64_trunc_sat_f64_s.value(): - case Instructions::i64_trunc_sat_f64_u.value(): - resulting_instructions.append(Instruction { full_opcode }); - break; - case Instructions::memory_init.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - - // 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 memory_index = memory_index_or_error.release_value(); - - resulting_instructions.append(Instruction { full_opcode, MemoryInitArgs { index, MemoryIndex(memory_index) } }); - break; - } - case Instructions::data_drop.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { full_opcode, index }); - 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 memory_index_or_error = stream.read_value(); - if (memory_index_or_error.is_error()) - return with_eof_check(stream, ParseError::InvalidInput); - - indices[i] = memory_index_or_error.release_value(); - } - resulting_instructions.append(Instruction { full_opcode, MemoryCopyArgs { indices[1], indices[0] } }); - break; - } - case Instructions::memory_fill.value(): { - // 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 memory_index = memory_index_or_error.release_value(); - resulting_instructions.append(Instruction { full_opcode, MemoryIndexArgument { MemoryIndex { memory_index } } }); - break; - } - case Instructions::table_init.value(): { - auto element_index = TRY(GenericIndexParser::parse(stream)); - auto table_index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { full_opcode, TableElementArgs { element_index, table_index } }); - break; - } - case Instructions::elem_drop.value(): { - auto element_index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { full_opcode, element_index }); - break; - } - case Instructions::table_copy.value(): { - auto lhs = TRY(GenericIndexParser::parse(stream)); - auto rhs = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { full_opcode, TableTableArgs { lhs, rhs } }); - break; - } - case Instructions::table_grow.value(): - case Instructions::table_size.value(): - case Instructions::table_fill.value(): { - auto index = TRY(GenericIndexParser::parse(stream)); - resulting_instructions.append(Instruction { full_opcode, index }); - break; - } - case Instructions::v128_load.value(): - case Instructions::v128_load8x8_s.value(): - case Instructions::v128_load8x8_u.value(): - case Instructions::v128_load16x4_s.value(): - case Instructions::v128_load16x4_u.value(): - case Instructions::v128_load32x2_s.value(): - case Instructions::v128_load32x2_u.value(): - case Instructions::v128_load8_splat.value(): - case Instructions::v128_load16_splat.value(): - case Instructions::v128_load32_splat.value(): - case Instructions::v128_load64_splat.value(): - case Instructions::v128_load32_zero.value(): - case Instructions::v128_load64_zero.value(): - case Instructions::v128_store.value(): { - // 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), MemoryIndex(memory_index) } }); - break; - } - case Instructions::v128_load8_lane.value(): - case Instructions::v128_load16_lane.value(): - case Instructions::v128_load32_lane.value(): - case Instructions::v128_load64_lane.value(): - case Instructions::v128_store8_lane.value(): - case Instructions::v128_store16_lane.value(): - case Instructions::v128_store32_lane.value(): - case Instructions::v128_store64_lane.value(): { - // 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); - size_t offset = offset_or_error.release_value(); - - auto index_or_error = stream.read_value(); - if (index_or_error.is_error()) - 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), MemoryIndex(memory_index) }, index } }); - break; - } - case Instructions::v128_const.value(): { - // op (literal:16) - auto value_or_error = stream.read_value>(); + return Instruction { full_opcode, MemoryAndLaneArgument { { static_cast(align), static_cast(offset), MemoryIndex(memory_index) }, index } }; + } + case Instructions::v128_const.value(): { + // op (literal:16) + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidImmediate); + return Instruction { full_opcode, value_or_error.release_value() }; + } + case Instructions::i8x16_shuffle.value(): { + // op 16x(lane) + u8 lanes[16]; + for (size_t i = 0; i < 16; ++i) { + auto value_or_error = stream.read_value(); if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::InvalidImmediate); - resulting_instructions.append(Instruction { full_opcode, value_or_error.release_value() }); - break; - } - case Instructions::i8x16_shuffle.value(): { - // op 16x(lane) - u8 lanes[16]; - for (size_t i = 0; i < 16; ++i) { - auto value_or_error = stream.read_value(); - if (value_or_error.is_error()) - return with_eof_check(stream, ParseError::InvalidInput); - lanes[i] = value_or_error.release_value(); - } - resulting_instructions.append(Instruction { full_opcode, ShuffleArgument(lanes) }); - break; - } - case Instructions::i8x16_extract_lane_s.value(): - case Instructions::i8x16_extract_lane_u.value(): - case Instructions::i8x16_replace_lane.value(): - case Instructions::i16x8_extract_lane_s.value(): - case Instructions::i16x8_extract_lane_u.value(): - case Instructions::i16x8_replace_lane.value(): - case Instructions::i32x4_extract_lane.value(): - case Instructions::i32x4_replace_lane.value(): - case Instructions::i64x2_extract_lane.value(): - case Instructions::i64x2_replace_lane.value(): - case Instructions::f32x4_extract_lane.value(): - case Instructions::f32x4_replace_lane.value(): - case Instructions::f64x2_extract_lane.value(): - case Instructions::f64x2_replace_lane.value(): { - // op (lane) - auto lane_or_error = stream.read_value(); - if (lane_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); - auto lane = lane_or_error.release_value(); - resulting_instructions.append(Instruction { full_opcode, LaneIndex { lane } }); - break; - } - case Instructions::i8x16_swizzle.value(): - case Instructions::i8x16_splat.value(): - case Instructions::i16x8_splat.value(): - case Instructions::i32x4_splat.value(): - case Instructions::i64x2_splat.value(): - case Instructions::f32x4_splat.value(): - case Instructions::f64x2_splat.value(): - case Instructions::i8x16_eq.value(): - case Instructions::i8x16_ne.value(): - case Instructions::i8x16_lt_s.value(): - case Instructions::i8x16_lt_u.value(): - case Instructions::i8x16_gt_s.value(): - case Instructions::i8x16_gt_u.value(): - case Instructions::i8x16_le_s.value(): - case Instructions::i8x16_le_u.value(): - case Instructions::i8x16_ge_s.value(): - case Instructions::i8x16_ge_u.value(): - case Instructions::i16x8_eq.value(): - case Instructions::i16x8_ne.value(): - case Instructions::i16x8_lt_s.value(): - case Instructions::i16x8_lt_u.value(): - case Instructions::i16x8_gt_s.value(): - case Instructions::i16x8_gt_u.value(): - case Instructions::i16x8_le_s.value(): - case Instructions::i16x8_le_u.value(): - case Instructions::i16x8_ge_s.value(): - case Instructions::i16x8_ge_u.value(): - case Instructions::i32x4_eq.value(): - case Instructions::i32x4_ne.value(): - case Instructions::i32x4_lt_s.value(): - case Instructions::i32x4_lt_u.value(): - case Instructions::i32x4_gt_s.value(): - case Instructions::i32x4_gt_u.value(): - case Instructions::i32x4_le_s.value(): - case Instructions::i32x4_le_u.value(): - case Instructions::i32x4_ge_s.value(): - case Instructions::i32x4_ge_u.value(): - case Instructions::f32x4_eq.value(): - case Instructions::f32x4_ne.value(): - case Instructions::f32x4_lt.value(): - case Instructions::f32x4_gt.value(): - case Instructions::f32x4_le.value(): - case Instructions::f32x4_ge.value(): - case Instructions::f64x2_eq.value(): - case Instructions::f64x2_ne.value(): - case Instructions::f64x2_lt.value(): - case Instructions::f64x2_gt.value(): - case Instructions::f64x2_le.value(): - case Instructions::f64x2_ge.value(): - case Instructions::v128_not.value(): - case Instructions::v128_and.value(): - case Instructions::v128_andnot.value(): - case Instructions::v128_or.value(): - case Instructions::v128_xor.value(): - case Instructions::v128_bitselect.value(): - case Instructions::v128_any_true.value(): - case Instructions::f32x4_demote_f64x2_zero.value(): - case Instructions::f64x2_promote_low_f32x4.value(): - case Instructions::i8x16_abs.value(): - case Instructions::i8x16_neg.value(): - case Instructions::i8x16_popcnt.value(): - case Instructions::i8x16_all_true.value(): - case Instructions::i8x16_bitmask.value(): - case Instructions::i8x16_narrow_i16x8_s.value(): - case Instructions::i8x16_narrow_i16x8_u.value(): - case Instructions::f32x4_ceil.value(): - case Instructions::f32x4_floor.value(): - case Instructions::f32x4_trunc.value(): - case Instructions::f32x4_nearest.value(): - case Instructions::i8x16_shl.value(): - case Instructions::i8x16_shr_s.value(): - case Instructions::i8x16_shr_u.value(): - case Instructions::i8x16_add.value(): - case Instructions::i8x16_add_sat_s.value(): - case Instructions::i8x16_add_sat_u.value(): - case Instructions::i8x16_sub.value(): - case Instructions::i8x16_sub_sat_s.value(): - case Instructions::i8x16_sub_sat_u.value(): - case Instructions::f64x2_ceil.value(): - case Instructions::f64x2_floor.value(): - case Instructions::i8x16_min_s.value(): - case Instructions::i8x16_min_u.value(): - case Instructions::i8x16_max_s.value(): - case Instructions::i8x16_max_u.value(): - case Instructions::f64x2_trunc.value(): - case Instructions::i8x16_avgr_u.value(): - case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): - case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): - case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): - case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): - case Instructions::i16x8_abs.value(): - case Instructions::i16x8_neg.value(): - case Instructions::i16x8_q15mulr_sat_s.value(): - case Instructions::i16x8_all_true.value(): - case Instructions::i16x8_bitmask.value(): - case Instructions::i16x8_narrow_i32x4_s.value(): - case Instructions::i16x8_narrow_i32x4_u.value(): - case Instructions::i16x8_extend_low_i8x16_s.value(): - case Instructions::i16x8_extend_high_i8x16_s.value(): - case Instructions::i16x8_extend_low_i8x16_u.value(): - case Instructions::i16x8_extend_high_i8x16_u.value(): - case Instructions::i16x8_shl.value(): - case Instructions::i16x8_shr_s.value(): - case Instructions::i16x8_shr_u.value(): - case Instructions::i16x8_add.value(): - case Instructions::i16x8_add_sat_s.value(): - case Instructions::i16x8_add_sat_u.value(): - case Instructions::i16x8_sub.value(): - case Instructions::i16x8_sub_sat_s.value(): - case Instructions::i16x8_sub_sat_u.value(): - case Instructions::f64x2_nearest.value(): - case Instructions::i16x8_mul.value(): - case Instructions::i16x8_min_s.value(): - case Instructions::i16x8_min_u.value(): - case Instructions::i16x8_max_s.value(): - case Instructions::i16x8_max_u.value(): - case Instructions::i16x8_avgr_u.value(): - case Instructions::i16x8_extmul_low_i8x16_s.value(): - case Instructions::i16x8_extmul_high_i8x16_s.value(): - case Instructions::i16x8_extmul_low_i8x16_u.value(): - case Instructions::i16x8_extmul_high_i8x16_u.value(): - case Instructions::i32x4_abs.value(): - case Instructions::i32x4_neg.value(): - case Instructions::i32x4_all_true.value(): - case Instructions::i32x4_bitmask.value(): - case Instructions::i32x4_extend_low_i16x8_s.value(): - case Instructions::i32x4_extend_high_i16x8_s.value(): - case Instructions::i32x4_extend_low_i16x8_u.value(): - case Instructions::i32x4_extend_high_i16x8_u.value(): - case Instructions::i32x4_shl.value(): - case Instructions::i32x4_shr_s.value(): - case Instructions::i32x4_shr_u.value(): - case Instructions::i32x4_add.value(): - case Instructions::i32x4_sub.value(): - case Instructions::i32x4_mul.value(): - case Instructions::i32x4_min_s.value(): - case Instructions::i32x4_min_u.value(): - case Instructions::i32x4_max_s.value(): - case Instructions::i32x4_max_u.value(): - case Instructions::i32x4_dot_i16x8_s.value(): - case Instructions::i32x4_extmul_low_i16x8_s.value(): - case Instructions::i32x4_extmul_high_i16x8_s.value(): - case Instructions::i32x4_extmul_low_i16x8_u.value(): - case Instructions::i32x4_extmul_high_i16x8_u.value(): - case Instructions::i64x2_abs.value(): - case Instructions::i64x2_neg.value(): - case Instructions::i64x2_all_true.value(): - case Instructions::i64x2_bitmask.value(): - case Instructions::i64x2_extend_low_i32x4_s.value(): - case Instructions::i64x2_extend_high_i32x4_s.value(): - case Instructions::i64x2_extend_low_i32x4_u.value(): - case Instructions::i64x2_extend_high_i32x4_u.value(): - case Instructions::i64x2_shl.value(): - case Instructions::i64x2_shr_s.value(): - case Instructions::i64x2_shr_u.value(): - case Instructions::i64x2_add.value(): - case Instructions::i64x2_sub.value(): - case Instructions::i64x2_mul.value(): - case Instructions::i64x2_eq.value(): - case Instructions::i64x2_ne.value(): - case Instructions::i64x2_lt_s.value(): - case Instructions::i64x2_gt_s.value(): - case Instructions::i64x2_le_s.value(): - case Instructions::i64x2_ge_s.value(): - case Instructions::i64x2_extmul_low_i32x4_s.value(): - case Instructions::i64x2_extmul_high_i32x4_s.value(): - case Instructions::i64x2_extmul_low_i32x4_u.value(): - case Instructions::i64x2_extmul_high_i32x4_u.value(): - case Instructions::f32x4_abs.value(): - case Instructions::f32x4_neg.value(): - case Instructions::f32x4_sqrt.value(): - case Instructions::f32x4_add.value(): - case Instructions::f32x4_sub.value(): - case Instructions::f32x4_mul.value(): - case Instructions::f32x4_div.value(): - case Instructions::f32x4_min.value(): - case Instructions::f32x4_max.value(): - case Instructions::f32x4_pmin.value(): - case Instructions::f32x4_pmax.value(): - case Instructions::f64x2_abs.value(): - case Instructions::f64x2_neg.value(): - case Instructions::f64x2_sqrt.value(): - case Instructions::f64x2_add.value(): - case Instructions::f64x2_sub.value(): - case Instructions::f64x2_mul.value(): - case Instructions::f64x2_div.value(): - case Instructions::f64x2_min.value(): - case Instructions::f64x2_max.value(): - case Instructions::f64x2_pmin.value(): - case Instructions::f64x2_pmax.value(): - case Instructions::i32x4_trunc_sat_f32x4_s.value(): - case Instructions::i32x4_trunc_sat_f32x4_u.value(): - case Instructions::f32x4_convert_i32x4_s.value(): - case Instructions::f32x4_convert_i32x4_u.value(): - case Instructions::i32x4_trunc_sat_f64x2_s_zero.value(): - case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): - case Instructions::f64x2_convert_low_i32x4_s.value(): - case Instructions::f64x2_convert_low_i32x4_u.value(): - // op - resulting_instructions.append(Instruction { full_opcode }); - break; - default: - return ParseError::UnknownInstruction; + lanes[i] = value_or_error.release_value(); } + return Instruction { full_opcode, ShuffleArgument(lanes) }; } + case Instructions::i8x16_extract_lane_s.value(): + case Instructions::i8x16_extract_lane_u.value(): + case Instructions::i8x16_replace_lane.value(): + case Instructions::i16x8_extract_lane_s.value(): + case Instructions::i16x8_extract_lane_u.value(): + case Instructions::i16x8_replace_lane.value(): + case Instructions::i32x4_extract_lane.value(): + case Instructions::i32x4_replace_lane.value(): + case Instructions::i64x2_extract_lane.value(): + case Instructions::i64x2_replace_lane.value(): + case Instructions::f32x4_extract_lane.value(): + case Instructions::f32x4_replace_lane.value(): + case Instructions::f64x2_extract_lane.value(): + case Instructions::f64x2_replace_lane.value(): { + // op (lane) + auto lane_or_error = stream.read_value(); + if (lane_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + auto lane = lane_or_error.release_value(); + return Instruction { full_opcode, LaneIndex { lane } }; } - } while (!nested_instructions.is_empty()); - - return resulting_instructions; + case Instructions::i8x16_swizzle.value(): + case Instructions::i8x16_splat.value(): + case Instructions::i16x8_splat.value(): + case Instructions::i32x4_splat.value(): + case Instructions::i64x2_splat.value(): + case Instructions::f32x4_splat.value(): + case Instructions::f64x2_splat.value(): + case Instructions::i8x16_eq.value(): + case Instructions::i8x16_ne.value(): + case Instructions::i8x16_lt_s.value(): + case Instructions::i8x16_lt_u.value(): + case Instructions::i8x16_gt_s.value(): + case Instructions::i8x16_gt_u.value(): + case Instructions::i8x16_le_s.value(): + case Instructions::i8x16_le_u.value(): + case Instructions::i8x16_ge_s.value(): + case Instructions::i8x16_ge_u.value(): + case Instructions::i16x8_eq.value(): + case Instructions::i16x8_ne.value(): + case Instructions::i16x8_lt_s.value(): + case Instructions::i16x8_lt_u.value(): + case Instructions::i16x8_gt_s.value(): + case Instructions::i16x8_gt_u.value(): + case Instructions::i16x8_le_s.value(): + case Instructions::i16x8_le_u.value(): + case Instructions::i16x8_ge_s.value(): + case Instructions::i16x8_ge_u.value(): + case Instructions::i32x4_eq.value(): + case Instructions::i32x4_ne.value(): + case Instructions::i32x4_lt_s.value(): + case Instructions::i32x4_lt_u.value(): + case Instructions::i32x4_gt_s.value(): + case Instructions::i32x4_gt_u.value(): + case Instructions::i32x4_le_s.value(): + case Instructions::i32x4_le_u.value(): + case Instructions::i32x4_ge_s.value(): + case Instructions::i32x4_ge_u.value(): + case Instructions::f32x4_eq.value(): + case Instructions::f32x4_ne.value(): + case Instructions::f32x4_lt.value(): + case Instructions::f32x4_gt.value(): + case Instructions::f32x4_le.value(): + case Instructions::f32x4_ge.value(): + case Instructions::f64x2_eq.value(): + case Instructions::f64x2_ne.value(): + case Instructions::f64x2_lt.value(): + case Instructions::f64x2_gt.value(): + case Instructions::f64x2_le.value(): + case Instructions::f64x2_ge.value(): + case Instructions::v128_not.value(): + case Instructions::v128_and.value(): + case Instructions::v128_andnot.value(): + case Instructions::v128_or.value(): + case Instructions::v128_xor.value(): + case Instructions::v128_bitselect.value(): + case Instructions::v128_any_true.value(): + case Instructions::f32x4_demote_f64x2_zero.value(): + case Instructions::f64x2_promote_low_f32x4.value(): + case Instructions::i8x16_abs.value(): + case Instructions::i8x16_neg.value(): + case Instructions::i8x16_popcnt.value(): + case Instructions::i8x16_all_true.value(): + case Instructions::i8x16_bitmask.value(): + case Instructions::i8x16_narrow_i16x8_s.value(): + case Instructions::i8x16_narrow_i16x8_u.value(): + case Instructions::f32x4_ceil.value(): + case Instructions::f32x4_floor.value(): + case Instructions::f32x4_trunc.value(): + case Instructions::f32x4_nearest.value(): + case Instructions::i8x16_shl.value(): + case Instructions::i8x16_shr_s.value(): + case Instructions::i8x16_shr_u.value(): + case Instructions::i8x16_add.value(): + case Instructions::i8x16_add_sat_s.value(): + case Instructions::i8x16_add_sat_u.value(): + case Instructions::i8x16_sub.value(): + case Instructions::i8x16_sub_sat_s.value(): + case Instructions::i8x16_sub_sat_u.value(): + case Instructions::f64x2_ceil.value(): + case Instructions::f64x2_floor.value(): + case Instructions::i8x16_min_s.value(): + case Instructions::i8x16_min_u.value(): + case Instructions::i8x16_max_s.value(): + case Instructions::i8x16_max_u.value(): + case Instructions::f64x2_trunc.value(): + case Instructions::i8x16_avgr_u.value(): + case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): + case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): + case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): + case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): + case Instructions::i16x8_abs.value(): + case Instructions::i16x8_neg.value(): + case Instructions::i16x8_q15mulr_sat_s.value(): + case Instructions::i16x8_all_true.value(): + case Instructions::i16x8_bitmask.value(): + case Instructions::i16x8_narrow_i32x4_s.value(): + case Instructions::i16x8_narrow_i32x4_u.value(): + case Instructions::i16x8_extend_low_i8x16_s.value(): + case Instructions::i16x8_extend_high_i8x16_s.value(): + case Instructions::i16x8_extend_low_i8x16_u.value(): + case Instructions::i16x8_extend_high_i8x16_u.value(): + case Instructions::i16x8_shl.value(): + case Instructions::i16x8_shr_s.value(): + case Instructions::i16x8_shr_u.value(): + case Instructions::i16x8_add.value(): + case Instructions::i16x8_add_sat_s.value(): + case Instructions::i16x8_add_sat_u.value(): + case Instructions::i16x8_sub.value(): + case Instructions::i16x8_sub_sat_s.value(): + case Instructions::i16x8_sub_sat_u.value(): + case Instructions::f64x2_nearest.value(): + case Instructions::i16x8_mul.value(): + case Instructions::i16x8_min_s.value(): + case Instructions::i16x8_min_u.value(): + case Instructions::i16x8_max_s.value(): + case Instructions::i16x8_max_u.value(): + case Instructions::i16x8_avgr_u.value(): + case Instructions::i16x8_extmul_low_i8x16_s.value(): + case Instructions::i16x8_extmul_high_i8x16_s.value(): + case Instructions::i16x8_extmul_low_i8x16_u.value(): + case Instructions::i16x8_extmul_high_i8x16_u.value(): + case Instructions::i32x4_abs.value(): + case Instructions::i32x4_neg.value(): + case Instructions::i32x4_all_true.value(): + case Instructions::i32x4_bitmask.value(): + case Instructions::i32x4_extend_low_i16x8_s.value(): + case Instructions::i32x4_extend_high_i16x8_s.value(): + case Instructions::i32x4_extend_low_i16x8_u.value(): + case Instructions::i32x4_extend_high_i16x8_u.value(): + case Instructions::i32x4_shl.value(): + case Instructions::i32x4_shr_s.value(): + case Instructions::i32x4_shr_u.value(): + case Instructions::i32x4_add.value(): + case Instructions::i32x4_sub.value(): + case Instructions::i32x4_mul.value(): + case Instructions::i32x4_min_s.value(): + case Instructions::i32x4_min_u.value(): + case Instructions::i32x4_max_s.value(): + case Instructions::i32x4_max_u.value(): + case Instructions::i32x4_dot_i16x8_s.value(): + case Instructions::i32x4_extmul_low_i16x8_s.value(): + case Instructions::i32x4_extmul_high_i16x8_s.value(): + case Instructions::i32x4_extmul_low_i16x8_u.value(): + case Instructions::i32x4_extmul_high_i16x8_u.value(): + case Instructions::i64x2_abs.value(): + case Instructions::i64x2_neg.value(): + case Instructions::i64x2_all_true.value(): + case Instructions::i64x2_bitmask.value(): + case Instructions::i64x2_extend_low_i32x4_s.value(): + case Instructions::i64x2_extend_high_i32x4_s.value(): + case Instructions::i64x2_extend_low_i32x4_u.value(): + case Instructions::i64x2_extend_high_i32x4_u.value(): + case Instructions::i64x2_shl.value(): + case Instructions::i64x2_shr_s.value(): + case Instructions::i64x2_shr_u.value(): + case Instructions::i64x2_add.value(): + case Instructions::i64x2_sub.value(): + case Instructions::i64x2_mul.value(): + case Instructions::i64x2_eq.value(): + case Instructions::i64x2_ne.value(): + case Instructions::i64x2_lt_s.value(): + case Instructions::i64x2_gt_s.value(): + case Instructions::i64x2_le_s.value(): + case Instructions::i64x2_ge_s.value(): + case Instructions::i64x2_extmul_low_i32x4_s.value(): + case Instructions::i64x2_extmul_high_i32x4_s.value(): + case Instructions::i64x2_extmul_low_i32x4_u.value(): + case Instructions::i64x2_extmul_high_i32x4_u.value(): + case Instructions::f32x4_abs.value(): + case Instructions::f32x4_neg.value(): + case Instructions::f32x4_sqrt.value(): + case Instructions::f32x4_add.value(): + case Instructions::f32x4_sub.value(): + case Instructions::f32x4_mul.value(): + case Instructions::f32x4_div.value(): + case Instructions::f32x4_min.value(): + case Instructions::f32x4_max.value(): + case Instructions::f32x4_pmin.value(): + case Instructions::f32x4_pmax.value(): + case Instructions::f64x2_abs.value(): + case Instructions::f64x2_neg.value(): + case Instructions::f64x2_sqrt.value(): + case Instructions::f64x2_add.value(): + case Instructions::f64x2_sub.value(): + case Instructions::f64x2_mul.value(): + case Instructions::f64x2_div.value(): + case Instructions::f64x2_min.value(): + case Instructions::f64x2_max.value(): + case Instructions::f64x2_pmin.value(): + case Instructions::f64x2_pmax.value(): + case Instructions::i32x4_trunc_sat_f32x4_s.value(): + case Instructions::i32x4_trunc_sat_f32x4_u.value(): + case Instructions::f32x4_convert_i32x4_s.value(): + case Instructions::f32x4_convert_i32x4_u.value(): + case Instructions::i32x4_trunc_sat_f64x2_s_zero.value(): + case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): + case Instructions::f64x2_convert_low_i32x4_s.value(): + case Instructions::f64x2_convert_low_i32x4_u.value(): + // op + return Instruction { full_opcode }; + default: + return ParseError::UnknownInstruction; + } + } + } + return ParseError::UnknownInstruction; } ParseResult CustomSection::parse(Stream& stream) @@ -1157,12 +1052,41 @@ ParseResult MemorySection::parse(Stream& stream) ParseResult Expression::parse(Stream& stream) { ScopeLogger logger("Expression"sv); - InstructionPointer ip { 0 }; - auto instructions = parse_until_any_of(stream, ip); - if (instructions.is_error()) - return instructions.error(); - return Expression { move(instructions.value().values) }; + InstructionPointer ip { 0 }; + Vector stack; + Vector instructions; + while (true) { + auto instruction = TRY(Instruction::parse(stream)); + switch (instruction.opcode().value()) { + case Instructions::block.value(): + case Instructions::loop.value(): + case Instructions::if_.value(): + stack.append(ip); + break; + case Instructions::structured_end.value(): { + if (stack.is_empty()) + return Expression { move(instructions) }; + auto entry = stack.take_last(); + auto& args = instructions[entry.value()].arguments().get(); + // Patch the end_ip of the last structured instruction + args.end_ip = ip + (args.else_ip.has_value() ? 1 : 0); + break; + } + case Instructions::structured_else.value(): { + if (stack.is_empty()) + return ParseError::UnknownInstruction; + auto entry = stack.last(); + auto& args = instructions[entry.value()].arguments().get(); + args.else_ip = ip + 1; + break; + } + } + instructions.append(move(instruction)); + ++ip; + } + + return Expression { move(instructions) }; } ParseResult GlobalSection::Global::parse(Stream& stream) diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index a7540cf4547..1e5ec6e6d41 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -460,10 +460,11 @@ public: { } - static ParseResult> parse(Stream& stream, InstructionPointer& ip); + static ParseResult parse(Stream& stream); auto& opcode() const { return m_opcode; } auto& arguments() const { return m_arguments; } + auto& arguments() { return m_arguments; } private: OpCode m_opcode { 0 };