summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Libraries/LibWasm/Parser/Parser.cpp860
1 files changed, 448 insertions, 412 deletions
diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp
index f35b26b6ea..8317ef0b7c 100644
--- a/Userland/Libraries/LibWasm/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp
@@ -277,458 +277,494 @@ ParseResult<BlockType> BlockType::parse(InputStream& stream)
ParseResult<Vector<Instruction>> Instruction::parse(InputStream& stream, InstructionPointer& ip)
{
- ScopeLogger<WASM_BINPARSER_DEBUG> logger("Instruction"sv);
- u8 byte;
- stream >> byte;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::ExpectedKindTag);
- OpCode opcode { byte };
- ++ip;
-
- switch (opcode.value()) {
- case Instructions::block.value():
- case Instructions::loop.value():
- case Instructions::if_.value(): {
- auto block_type = BlockType::parse(stream);
- if (block_type.is_error())
- return block_type.error();
- Vector<Instruction> instructions;
- InstructionPointer end_ip, else_ip;
-
- {
- auto result = parse_until_any_of<Instruction, 0x0b, 0x05>(stream, ip);
- if (result.is_error())
- return result.error();
+ struct NestedInstructionState {
+ Vector<Instruction> prior_instructions;
+ OpCode opcode;
+ BlockType block_type;
+ InstructionPointer end_ip;
+ Optional<InstructionPointer> else_ip;
+ };
+ Vector<NestedInstructionState, 4> nested_instructions;
+ Vector<Instruction> resulting_instructions;
- if (result.value().terminator == 0x0b) {
- // block/loop/if without else
- result.value().values.append(Instruction { Instructions::structured_end });
+ do {
+ ScopeLogger<WASM_BINPARSER_DEBUG> logger("Instruction"sv);
+ u8 byte;
+ stream >> byte;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::ExpectedKindTag);
- // Transform op(..., instr*) -> op(...) instr* op(end(ip))
- result.value().values.prepend(Instruction { opcode, StructuredInstructionArgs { BlockType { block_type.release_value() }, ip.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 result.release_value().values;
+
+ // 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;
}
- // Transform op(..., instr*, instr*) -> op(...) instr* op(else(ip) instr* op(end(ip))
- VERIFY(result.value().terminator == 0x05);
- instructions.extend(result.release_value().values);
- instructions.append(Instruction { Instructions::structured_else });
- ++ip;
- else_ip = ip.value();
- }
- // if with else
- {
- auto result = parse_until_any_of<Instruction, 0x0b>(stream, ip);
- if (result.is_error())
- return result.error();
- instructions.extend(result.release_value().values);
- instructions.append(Instruction { Instructions::structured_end });
- ++ip;
- end_ip = ip.value();
+ 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;
+ }
}
- instructions.prepend(Instruction { opcode, StructuredInstructionArgs { BlockType { block_type.release_value() }, end_ip, else_ip } });
- return instructions;
- }
- case Instructions::br.value():
- case Instructions::br_if.value(): {
- // branches with a single label immediate
- auto index = GenericIndexParser<LabelIndex>::parse(stream);
- if (index.is_error())
- return index.error();
+ OpCode opcode { byte };
+ ++ip;
- return Vector { Instruction { opcode, index.release_value() } };
- }
- case Instructions::br_table.value(): {
- // br_table label* label
- auto labels = parse_vector<GenericIndexParser<LabelIndex>>(stream);
- if (labels.is_error())
- return labels.error();
+ switch (opcode.value()) {
+ case Instructions::block.value():
+ case Instructions::loop.value():
+ case Instructions::if_.value(): {
+ auto block_type = BlockType::parse(stream);
+ if (block_type.is_error())
+ return block_type.error();
- auto default_label = GenericIndexParser<LabelIndex>::parse(stream);
- if (default_label.is_error())
- return default_label.error();
+ nested_instructions.append({ move(resulting_instructions), opcode, block_type.release_value(), {}, {} });
+ resulting_instructions = {};
+ break;
+ }
+ case Instructions::br.value():
+ case Instructions::br_if.value(): {
+ // branches with a single label immediate
+ auto index = GenericIndexParser<LabelIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
- return Vector { Instruction { opcode, TableBranchArgs { labels.release_value(), default_label.release_value() } } };
- }
- case Instructions::call.value(): {
- // call function
- auto function_index = GenericIndexParser<FunctionIndex>::parse(stream);
- if (function_index.is_error())
- return function_index.error();
+ resulting_instructions.append(Instruction { opcode, index.release_value() });
+ break;
+ }
+ case Instructions::br_table.value(): {
+ // br_table label* label
+ auto labels = parse_vector<GenericIndexParser<LabelIndex>>(stream);
+ if (labels.is_error())
+ return labels.error();
- return Vector { Instruction { opcode, function_index.release_value() } };
- }
- case Instructions::call_indirect.value(): {
- // call_indirect type table
- auto type_index = GenericIndexParser<TypeIndex>::parse(stream);
- if (type_index.is_error())
- return type_index.error();
+ auto default_label = GenericIndexParser<LabelIndex>::parse(stream);
+ if (default_label.is_error())
+ return default_label.error();
- auto table_index = GenericIndexParser<TableIndex>::parse(stream);
- if (table_index.is_error())
- return table_index.error();
+ resulting_instructions.append(Instruction { opcode, TableBranchArgs { labels.release_value(), default_label.release_value() } });
+ break;
+ }
+ case Instructions::call.value(): {
+ // call function
+ auto function_index = GenericIndexParser<FunctionIndex>::parse(stream);
+ if (function_index.is_error())
+ return function_index.error();
- return Vector { Instruction { opcode, IndirectCallArgs { type_index.release_value(), table_index.release_value() } } };
- }
- 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 offset)
- size_t align, offset;
- if (!LEB128::read_unsigned(stream, align))
- return with_eof_check(stream, ParseError::InvalidInput);
- if (!LEB128::read_unsigned(stream, offset))
- return with_eof_check(stream, ParseError::InvalidInput);
-
- return Vector { Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } } };
- }
- case Instructions::local_get.value():
- case Instructions::local_set.value():
- case Instructions::local_tee.value(): {
- auto index = GenericIndexParser<LocalIndex>::parse(stream);
- if (index.is_error())
- return index.error();
+ resulting_instructions.append(Instruction { opcode, function_index.release_value() });
+ break;
+ }
+ case Instructions::call_indirect.value(): {
+ // call_indirect type table
+ auto type_index = GenericIndexParser<TypeIndex>::parse(stream);
+ if (type_index.is_error())
+ return type_index.error();
- return Vector { Instruction { opcode, index.release_value() } };
- }
- case Instructions::global_get.value():
- case Instructions::global_set.value(): {
- auto index = GenericIndexParser<GlobalIndex>::parse(stream);
- if (index.is_error())
- return index.error();
+ auto table_index = GenericIndexParser<TableIndex>::parse(stream);
+ if (table_index.is_error())
+ return table_index.error();
- return Vector { Instruction { opcode, index.release_value() } };
- }
- case Instructions::memory_size.value():
- case Instructions::memory_grow.value(): {
- // op 0x0
- // The zero is currently unused.
- u8 unused;
- stream >> unused;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::ExpectedKindTag);
- if (unused != 0x00) {
- dbgln("Invalid tag in memory_grow {}", unused);
- return with_eof_check(stream, ParseError::InvalidTag);
+ resulting_instructions.append(Instruction { opcode, IndirectCallArgs { type_index.release_value(), table_index.release_value() } });
+ break;
}
+ 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 offset)
+ size_t align;
+ if (!LEB128::read_unsigned(stream, align))
+ return with_eof_check(stream, ParseError::InvalidInput);
- return Vector { Instruction { opcode } };
- }
- case Instructions::i32_const.value(): {
- i32 value;
- if (!LEB128::read_signed(stream, value))
- return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
+ size_t offset;
+ if (!LEB128::read_unsigned(stream, offset))
+ return with_eof_check(stream, ParseError::InvalidInput);
- return Vector { Instruction { opcode, value } };
- }
- case Instructions::i64_const.value(): {
- // op literal
- i64 value;
- if (!LEB128::read_signed(stream, value))
- return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
+ resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } });
+ break;
+ }
+ case Instructions::local_get.value():
+ case Instructions::local_set.value():
+ case Instructions::local_tee.value(): {
+ auto index = GenericIndexParser<LocalIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
- return Vector { Instruction { opcode, value } };
- }
- case Instructions::f32_const.value(): {
- // op literal
- LittleEndian<u32> value;
- stream >> value;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
+ resulting_instructions.append(Instruction { opcode, index.release_value() });
+ break;
+ }
+ case Instructions::global_get.value():
+ case Instructions::global_set.value(): {
+ auto index = GenericIndexParser<GlobalIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
- auto floating = bit_cast<float>(static_cast<u32>(value));
- return Vector { Instruction { opcode, floating } };
- }
- case Instructions::f64_const.value(): {
- // op literal
- LittleEndian<u64> value;
- stream >> value;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
+ resulting_instructions.append(Instruction { opcode, index.release_value() });
+ break;
+ }
+ case Instructions::memory_size.value():
+ case Instructions::memory_grow.value(): {
+ // op 0x0
+ // The zero is currently unused.
+ u8 unused;
+ stream >> unused;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::ExpectedKindTag);
+ if (unused != 0x00) {
+ dbgln("Invalid tag in memory_grow {}", unused);
+ return with_eof_check(stream, ParseError::InvalidTag);
+ }
- auto floating = bit_cast<double>(static_cast<u64>(value));
- return Vector { Instruction { opcode, floating } };
- }
- case Instructions::table_get.value():
- case Instructions::table_set.value(): {
- auto index = GenericIndexParser<TableIndex>::parse(stream);
- if (index.is_error())
- return index.error();
+ resulting_instructions.append(Instruction { opcode });
+ break;
+ }
+ case Instructions::i32_const.value(): {
+ i32 value;
+ if (!LEB128::read_signed(stream, value))
+ return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
- return Vector { Instruction { opcode, index.release_value() } };
- }
- case Instructions::select_typed.value(): {
- auto types = parse_vector<ValueType>(stream);
- if (types.is_error())
- return types.error();
+ resulting_instructions.append(Instruction { opcode, value });
+ break;
+ }
+ case Instructions::i64_const.value(): {
+ // op literal
+ i64 value;
+ if (!LEB128::read_signed(stream, value))
+ return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
- return Vector { Instruction { opcode, types.release_value() } };
- }
- case Instructions::ref_null.value(): {
- auto type = ValueType::parse(stream);
- if (type.is_error())
- return type.error();
- if (!type.value().is_reference())
- return ParseError::InvalidType;
-
- return Vector { Instruction { opcode, type.release_value() } };
- }
- case Instructions::ref_func.value(): {
- auto index = GenericIndexParser<FunctionIndex>::parse(stream);
- if (index.is_error())
- return index.error();
+ resulting_instructions.append(Instruction { opcode, value });
+ break;
+ }
+ case Instructions::f32_const.value(): {
+ // op literal
+ LittleEndian<u32> value;
+ stream >> value;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
- return Vector { Instruction { opcode, index.release_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 Vector { Instruction { opcode } };
- case 0xfc: {
- // These are multibyte instructions.
- u32 selector;
- if (!LEB128::read_unsigned(stream, selector))
- return with_eof_check(stream, ParseError::InvalidInput);
- switch (selector) {
- case Instructions::i32_trunc_sat_f32_s_second:
- case Instructions::i32_trunc_sat_f32_u_second:
- case Instructions::i32_trunc_sat_f64_s_second:
- case Instructions::i32_trunc_sat_f64_u_second:
- case Instructions::i64_trunc_sat_f32_s_second:
- case Instructions::i64_trunc_sat_f32_u_second:
- case Instructions::i64_trunc_sat_f64_s_second:
- case Instructions::i64_trunc_sat_f64_u_second:
- return Vector { Instruction { OpCode { 0xfc00 | selector } } };
- case Instructions::memory_init_second: {
- auto index = GenericIndexParser<DataIndex>::parse(stream);
+ auto floating = bit_cast<float>(static_cast<u32>(value));
+ resulting_instructions.append(Instruction { opcode, floating });
+ break;
+ }
+ case Instructions::f64_const.value(): {
+ // op literal
+ LittleEndian<u64> value;
+ stream >> value;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
+
+ auto floating = bit_cast<double>(static_cast<u64>(value));
+ resulting_instructions.append(Instruction { opcode, floating });
+ break;
+ }
+ case Instructions::table_get.value():
+ case Instructions::table_set.value(): {
+ auto index = GenericIndexParser<TableIndex>::parse(stream);
if (index.is_error())
return index.error();
- u8 unused;
- stream >> unused;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::InvalidInput);
- if (unused != 0x00)
- return ParseError::InvalidImmediate;
- return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } };
+
+ resulting_instructions.append(Instruction { opcode, index.release_value() });
+ break;
+ }
+ case Instructions::select_typed.value(): {
+ auto types = parse_vector<ValueType>(stream);
+ if (types.is_error())
+ return types.error();
+
+ resulting_instructions.append(Instruction { opcode, types.release_value() });
+ break;
}
- case Instructions::data_drop_second: {
- auto index = GenericIndexParser<DataIndex>::parse(stream);
+ case Instructions::ref_null.value(): {
+ auto type = ValueType::parse(stream);
+ if (type.is_error())
+ return type.error();
+ if (!type.value().is_reference())
+ return ParseError::InvalidType;
+
+ resulting_instructions.append(Instruction { opcode, type.release_value() });
+ break;
+ }
+ case Instructions::ref_func.value(): {
+ auto index = GenericIndexParser<FunctionIndex>::parse(stream);
if (index.is_error())
return index.error();
- return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } };
+
+ resulting_instructions.append(Instruction { opcode, index.release_value() });
+ break;
}
- case Instructions::memory_copy_second: {
- for (size_t i = 0; i < 2; ++i) {
+ 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: {
+ // These are multibyte instructions.
+ u32 selector;
+ if (!LEB128::read_unsigned(stream, selector))
+ return with_eof_check(stream, ParseError::InvalidInput);
+ switch (selector) {
+ case Instructions::i32_trunc_sat_f32_s_second:
+ case Instructions::i32_trunc_sat_f32_u_second:
+ case Instructions::i32_trunc_sat_f64_s_second:
+ case Instructions::i32_trunc_sat_f64_u_second:
+ case Instructions::i64_trunc_sat_f32_s_second:
+ case Instructions::i64_trunc_sat_f32_u_second:
+ case Instructions::i64_trunc_sat_f64_s_second:
+ case Instructions::i64_trunc_sat_f64_u_second:
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } });
+ break;
+ case Instructions::memory_init_second: {
+ auto index = GenericIndexParser<DataIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
u8 unused;
stream >> unused;
if (stream.has_any_error())
return with_eof_check(stream, ParseError::InvalidInput);
if (unused != 0x00)
return ParseError::InvalidImmediate;
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() });
+ break;
+ }
+ case Instructions::data_drop_second: {
+ auto index = GenericIndexParser<DataIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() });
+ break;
+ }
+ case Instructions::memory_copy_second: {
+ for (size_t i = 0; i < 2; ++i) {
+ u8 unused;
+ stream >> unused;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::InvalidInput);
+ if (unused != 0x00)
+ return ParseError::InvalidImmediate;
+ }
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } });
+ break;
+ }
+ case Instructions::memory_fill_second: {
+ u8 unused;
+ stream >> unused;
+ if (stream.has_any_error())
+ return with_eof_check(stream, ParseError::InvalidInput);
+ if (unused != 0x00)
+ return ParseError::InvalidImmediate;
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } });
+ break;
+ }
+ case Instructions::table_init_second: {
+ auto element_index = GenericIndexParser<ElementIndex>::parse(stream);
+ if (element_index.is_error())
+ return element_index.error();
+ auto table_index = GenericIndexParser<TableIndex>::parse(stream);
+ if (table_index.is_error())
+ return table_index.error();
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, TableElementArgs { element_index.release_value(), table_index.release_value() } });
+ break;
+ }
+ case Instructions::elem_drop_second: {
+ auto element_index = GenericIndexParser<ElementIndex>::parse(stream);
+ if (element_index.is_error())
+ return element_index.error();
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, element_index.release_value() });
+ break;
+ }
+ case Instructions::table_copy_second: {
+ auto lhs = GenericIndexParser<TableIndex>::parse(stream);
+ if (lhs.is_error())
+ return lhs.error();
+ auto rhs = GenericIndexParser<TableIndex>::parse(stream);
+ if (rhs.is_error())
+ return rhs.error();
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, TableTableArgs { lhs.release_value(), rhs.release_value() } });
+ break;
+ }
+ case Instructions::table_grow_second:
+ case Instructions::table_size_second:
+ case Instructions::table_fill_second: {
+ auto index = GenericIndexParser<TableIndex>::parse(stream);
+ if (index.is_error())
+ return index.error();
+ resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() });
+ break;
+ }
+ default:
+ return ParseError::UnknownInstruction;
}
- return Vector { Instruction { OpCode { 0xfc00 | selector } } };
- }
- case Instructions::memory_fill_second: {
- u8 unused;
- stream >> unused;
- if (stream.has_any_error())
- return with_eof_check(stream, ParseError::InvalidInput);
- if (unused != 0x00)
- return ParseError::InvalidImmediate;
- return Vector { Instruction { OpCode { 0xfc00 | selector } } };
- }
- case Instructions::table_init_second: {
- auto element_index = GenericIndexParser<ElementIndex>::parse(stream);
- if (element_index.is_error())
- return element_index.error();
- auto table_index = GenericIndexParser<TableIndex>::parse(stream);
- if (table_index.is_error())
- return table_index.error();
- return Vector { Instruction { OpCode { 0xfc00 | selector }, TableElementArgs { element_index.release_value(), table_index.release_value() } } };
- }
- case Instructions::elem_drop_second: {
- auto element_index = GenericIndexParser<ElementIndex>::parse(stream);
- if (element_index.is_error())
- return element_index.error();
- return Vector { Instruction { OpCode { 0xfc00 | selector }, element_index.release_value() } };
- }
- case Instructions::table_copy_second: {
- auto lhs = GenericIndexParser<TableIndex>::parse(stream);
- if (lhs.is_error())
- return lhs.error();
- auto rhs = GenericIndexParser<TableIndex>::parse(stream);
- if (rhs.is_error())
- return rhs.error();
- return Vector { Instruction { OpCode { 0xfc00 | selector }, TableTableArgs { lhs.release_value(), rhs.release_value() } } };
- }
- case Instructions::table_grow_second:
- case Instructions::table_size_second:
- case Instructions::table_fill_second: {
- auto index = GenericIndexParser<TableIndex>::parse(stream);
- if (index.is_error())
- return index.error();
- return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } };
}
- default:
- return ParseError::UnknownInstruction;
}
- }
- }
+ } while (!nested_instructions.is_empty());
- return ParseError::UnknownInstruction;
+ return resulting_instructions;
}
ParseResult<CustomSection> CustomSection::parse(InputStream& stream)