From 7a12f23c285645ddb0d5e02d250ae93915c15802 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Sat, 1 May 2021 19:56:45 +0430 Subject: [PATCH] LibWasm: Un-nest the structured instructions --- Userland/Libraries/LibWasm/Opcode.h | 4 +- Userland/Libraries/LibWasm/Parser/Parser.cpp | 105 +++++++++++-------- Userland/Libraries/LibWasm/Types.h | 18 ++-- 3 files changed, 69 insertions(+), 58 deletions(-) diff --git a/Userland/Libraries/LibWasm/Opcode.h b/Userland/Libraries/LibWasm/Opcode.h index 1e03ec1e38..97d6ae6184 100644 --- a/Userland/Libraries/LibWasm/Opcode.h +++ b/Userland/Libraries/LibWasm/Opcode.h @@ -209,7 +209,9 @@ static constexpr OpCode i32_trunc_sat_f32_s = 0xfc00, table_copy = 0xfc0e, table_grow = 0xfc0f, table_size = 0xfc10, - table_fill = 0xfc11; + table_fill = 0xfc11, + structured_else = 0xff00, + structured_end = 0xff01; static constexpr u32 i32_trunc_sat_f32_s_second = 0, i32_trunc_sat_f32_u_second = 1, diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 50c844de15..e7532181ba 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -81,8 +81,8 @@ struct ParseUntilAnyOfResult { u8 terminator { 0 }; Vector values; }; -template -static ParseResult> parse_until_any_of(InputStream& stream, Args... terminators) requires(requires(InputStream& stream) { T::parse(stream); }) +template +static ParseResult> parse_until_any_of(InputStream& stream, Args... args) requires(requires(InputStream& stream, Args... args) { T::parse(stream, args...); }) { ScopeLogger logger; ReconsumableStream new_stream { stream }; @@ -105,7 +105,7 @@ static ParseResult> parse_until_any_of(InputStream& str } new_stream.unread({ &byte, 1 }); - auto parse_result = T::parse(new_stream); + auto parse_result = T::parse(new_stream, args...); if (parse_result.is_error()) return parse_result.error(); @@ -265,13 +265,15 @@ ParseResult BlockType::parse(InputStream& stream) if (!LEB128::read_signed(new_stream, index_value)) return with_eof_check(stream, ParseError::ExpectedIndex); - if (index_value < 0) + if (index_value < 0) { + dbgln("Invalid type index {}", index_value); return with_eof_check(stream, ParseError::InvalidIndex); + } return BlockType { TypeIndex(index_value) }; } -ParseResult Instruction::parse(InputStream& stream) +ParseResult> Instruction::parse(InputStream& stream, InstructionPointer& ip) { ScopeLogger logger("Instruction"); u8 byte; @@ -279,6 +281,7 @@ ParseResult Instruction::parse(InputStream& stream) if (stream.has_any_error()) return with_eof_check(stream, ParseError::ExpectedKindTag); OpCode opcode { byte }; + ++ip; switch (opcode.value()) { case Instructions::block.value(): @@ -287,36 +290,43 @@ ParseResult Instruction::parse(InputStream& stream) auto block_type = BlockType::parse(stream); if (block_type.is_error()) return block_type.error(); - NonnullOwnPtrVector left_instructions, right_instructions; + Vector instructions; + InstructionPointer end_ip, else_ip; + { - auto result = parse_until_any_of(stream, 0x0b, 0x05); + auto result = parse_until_any_of(stream, ip); if (result.is_error()) return result.error(); if (result.value().terminator == 0x0b) { // block/loop/if without else - NonnullOwnPtrVector instructions; - for (auto& entry : result.value().values) - instructions.append(make(move(entry))); + result.value().values.append(Instruction { Instructions::structured_end }); - return Instruction { opcode, BlockAndInstructionSet { block_type.release_value(), move(instructions) } }; + // Transform op(..., instr*) -> op(...) instr* op(end(ip)) + result.value().values.prepend(Instruction { opcode, StructuredInstructionArgs { BlockType { block_type.release_value() }, ip, {} } }); + return result.release_value().values; } + // Transform op(..., instr*, instr*) -> op(...) instr* op(else(ip) instr* op(end(ip)) VERIFY(result.value().terminator == 0x05); - for (auto& entry : result.value().values) - left_instructions.append(make(move(entry))); + instructions.append(result.release_value().values); + instructions.append(Instruction { Instructions::structured_else }); + ++ip; + else_ip = ip; } // if with else { - auto result = parse_until_any_of(stream, 0x0b); + auto result = parse_until_any_of(stream, ip); if (result.is_error()) return result.error(); - - for (auto& entry : result.value().values) - right_instructions.append(make(move(entry))); + instructions.append(result.release_value().values); + instructions.append(Instruction { Instructions::structured_end }); + ++ip; + end_ip = ip; } - return Instruction { opcode, BlockAndTwoInstructionSets { block_type.release_value(), move(left_instructions), move(right_instructions) } }; + 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(): { @@ -325,7 +335,7 @@ ParseResult Instruction::parse(InputStream& stream) if (index.is_error()) return index.error(); - return Instruction { opcode, index.release_value() }; + return Vector { Instruction { opcode, index.release_value() } }; } case Instructions::br_table.value(): { // br_table label* label @@ -337,7 +347,7 @@ ParseResult Instruction::parse(InputStream& stream) if (default_label.is_error()) return default_label.error(); - return Instruction { opcode, TableBranchArgs { labels.release_value(), default_label.release_value() } }; + return Vector { Instruction { opcode, TableBranchArgs { labels.release_value(), default_label.release_value() } } }; } case Instructions::call.value(): { // call function @@ -345,7 +355,7 @@ ParseResult Instruction::parse(InputStream& stream) if (function_index.is_error()) return function_index.error(); - return Instruction { opcode, function_index.release_value() }; + return Vector { Instruction { opcode, function_index.release_value() } }; } case Instructions::call_indirect.value(): { // call_indirect type table @@ -357,7 +367,7 @@ ParseResult Instruction::parse(InputStream& stream) if (table_index.is_error()) return table_index.error(); - return Instruction { opcode, IndirectCallArgs { type_index.release_value(), table_index.release_value() } }; + return Vector { Instruction { opcode, IndirectCallArgs { type_index.release_value(), table_index.release_value() } } }; } case Instructions::i32_load.value(): case Instructions::i64_load.value(): @@ -389,7 +399,7 @@ ParseResult Instruction::parse(InputStream& stream) if (!LEB128::read_unsigned(stream, offset)) return with_eof_check(stream, ParseError::InvalidInput); - return Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset) } }; + return Vector { Instruction { opcode, MemoryArgument { static_cast(align), static_cast(offset) } } }; } case Instructions::local_get.value(): case Instructions::local_set.value(): @@ -398,7 +408,7 @@ ParseResult Instruction::parse(InputStream& stream) if (index.is_error()) return index.error(); - return Instruction { opcode, index.release_value() }; + return Vector { Instruction { opcode, index.release_value() } }; } case Instructions::global_get.value(): case Instructions::global_set.value(): { @@ -406,7 +416,7 @@ ParseResult Instruction::parse(InputStream& stream) if (index.is_error()) return index.error(); - return Instruction { opcode, index.release_value() }; + return Vector { Instruction { opcode, index.release_value() } }; } case Instructions::memory_size.value(): case Instructions::memory_grow.value(): { @@ -416,17 +426,19 @@ ParseResult Instruction::parse(InputStream& stream) stream >> unused; if (stream.has_any_error()) return with_eof_check(stream, ParseError::ExpectedKindTag); - if (unused != 0x00) + if (unused != 0x00) { + dbgln("Invalid tag in memory_grow {}", unused); return with_eof_check(stream, ParseError::InvalidTag); + } - return Instruction { opcode }; + return Vector { Instruction { opcode } }; } case Instructions::i32_const.value(): { i32 value; if (!LEB128::read_signed(stream, value)) return with_eof_check(stream, ParseError::ExpectedSignedImmediate); - return Instruction { opcode, value }; + return Vector { Instruction { opcode, value } }; } case Instructions::i64_const.value(): { // op literal @@ -434,7 +446,7 @@ ParseResult Instruction::parse(InputStream& stream) if (!LEB128::read_signed(stream, value)) return with_eof_check(stream, ParseError::ExpectedSignedImmediate); - return Instruction { opcode, value }; + return Vector { Instruction { opcode, value } }; } case Instructions::f32_const.value(): { // op literal @@ -444,7 +456,7 @@ ParseResult Instruction::parse(InputStream& stream) return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); auto floating = bit_cast(static_cast(value)); - return Instruction { opcode, floating }; + return Vector { Instruction { opcode, floating } }; } case Instructions::f64_const.value(): { // op literal @@ -454,7 +466,7 @@ ParseResult Instruction::parse(InputStream& stream) return with_eof_check(stream, ParseError::ExpectedFloatingImmediate); auto floating = bit_cast(static_cast(value)); - return Instruction { opcode, floating }; + return Vector { Instruction { opcode, floating } }; } case Instructions::table_get.value(): case Instructions::table_set.value(): { @@ -462,14 +474,14 @@ ParseResult Instruction::parse(InputStream& stream) if (index.is_error()) return index.error(); - return Instruction { opcode, index.release_value() }; + return Vector { Instruction { opcode, index.release_value() } }; } case Instructions::select_typed.value(): { auto types = parse_vector(stream); if (types.is_error()) return types.error(); - return Instruction { opcode, types.release_value() }; + return Vector { Instruction { opcode, types.release_value() } }; } case Instructions::ref_null.value(): { auto type = ValueType::parse(stream); @@ -478,14 +490,14 @@ ParseResult Instruction::parse(InputStream& stream) if (!type.value().is_reference()) return ParseError::InvalidType; - return Instruction { opcode, type.release_value() }; + return Vector { Instruction { opcode, type.release_value() } }; } case Instructions::ref_func.value(): { auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - return Instruction { opcode, index.release_value() }; + return Vector { Instruction { opcode, index.release_value() } }; } case Instructions::ref_is_null.value(): case Instructions::unreachable.value(): @@ -616,7 +628,7 @@ ParseResult Instruction::parse(InputStream& stream) case Instructions::i64_reinterpret_f64.value(): case Instructions::f32_reinterpret_i32.value(): case Instructions::f64_reinterpret_i64.value(): - return Instruction { opcode }; + return Vector { Instruction { opcode } }; case 0xfc: { // These are multibyte instructions. u32 selector; @@ -631,7 +643,7 @@ ParseResult Instruction::parse(InputStream& stream) 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 Instruction { OpCode { 0xfc00 | selector } }; + return Vector { Instruction { OpCode { 0xfc00 | selector } } }; case Instructions::memory_init_second: { auto index = GenericIndexParser::parse(stream); if (index.is_error()) @@ -642,13 +654,13 @@ ParseResult Instruction::parse(InputStream& stream) return with_eof_check(stream, ParseError::InvalidInput); if (unused != 0x00) return ParseError::InvalidImmediate; - return Instruction { OpCode { 0xfc00 | selector }, index.release_value() }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } }; } case Instructions::data_drop_second: { auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - return Instruction { OpCode { 0xfc00 | selector }, index.release_value() }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } }; } case Instructions::memory_copy_second: { for (size_t i = 0; i < 2; ++i) { @@ -659,7 +671,7 @@ ParseResult Instruction::parse(InputStream& stream) if (unused != 0x00) return ParseError::InvalidImmediate; } - return Instruction { OpCode { 0xfc00 | selector } }; + return Vector { Instruction { OpCode { 0xfc00 | selector } } }; } case Instructions::memory_fill_second: { u8 unused; @@ -668,7 +680,7 @@ ParseResult Instruction::parse(InputStream& stream) return with_eof_check(stream, ParseError::InvalidInput); if (unused != 0x00) return ParseError::InvalidImmediate; - return Instruction { OpCode { 0xfc00 | selector } }; + return Vector { Instruction { OpCode { 0xfc00 | selector } } }; } case Instructions::table_init_second: { auto element_index = GenericIndexParser::parse(stream); @@ -677,13 +689,13 @@ ParseResult Instruction::parse(InputStream& stream) auto table_index = GenericIndexParser::parse(stream); if (table_index.is_error()) return table_index.error(); - return Instruction { OpCode { 0xfc00 | selector }, TableElementArgs { element_index.release_value(), table_index.release_value() } }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, TableElementArgs { element_index.release_value(), table_index.release_value() } } }; } case Instructions::elem_drop_second: { auto element_index = GenericIndexParser::parse(stream); if (element_index.is_error()) return element_index.error(); - return Instruction { OpCode { 0xfc00 | selector }, element_index.release_value() }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, element_index.release_value() } }; } case Instructions::table_copy_second: { auto lhs = GenericIndexParser::parse(stream); @@ -692,7 +704,7 @@ ParseResult Instruction::parse(InputStream& stream) auto rhs = GenericIndexParser::parse(stream); if (rhs.is_error()) return rhs.error(); - return Instruction { OpCode { 0xfc00 | selector }, TableTableArgs { lhs.release_value(), rhs.release_value() } }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, TableTableArgs { lhs.release_value(), rhs.release_value() } } }; } case Instructions::table_grow_second: case Instructions::table_size_second: @@ -700,7 +712,7 @@ ParseResult Instruction::parse(InputStream& stream) auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - return Instruction { OpCode { 0xfc00 | selector }, index.release_value() }; + return Vector { Instruction { OpCode { 0xfc00 | selector }, index.release_value() } }; } default: return ParseError::UnknownInstruction; @@ -834,7 +846,8 @@ ParseResult MemorySection::parse(InputStream& stream) ParseResult Expression::parse(InputStream& stream) { ScopeLogger logger("Expression"); - auto instructions = parse_until_any_of(stream, 0x0b); + InstructionPointer ip { 0 }; + auto instructions = parse_until_any_of(stream, ip); if (instructions.is_error()) return instructions.error(); diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index 20871c1a43..f55ab9330b 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -54,6 +54,7 @@ TYPEDEF_DISTINCT_ORDERED_ID(size_t, LocalIndex); TYPEDEF_DISTINCT_ORDERED_ID(size_t, GlobalIndex); TYPEDEF_DISTINCT_ORDERED_ID(size_t, LabelIndex); TYPEDEF_DISTINCT_ORDERED_ID(size_t, DataIndex); +TYPEDEF_DISTINCT_NUMERIC_GENERAL(u64, true, true, false, true, false, true, InstructionPointer); ParseError with_eof_check(const InputStream& stream, ParseError error_if_not_eof); @@ -389,15 +390,10 @@ public: TableIndex rhs; }; - struct BlockAndInstructionSet { + struct StructuredInstructionArgs { BlockType block_type; - NonnullOwnPtrVector instructions; - }; - - struct BlockAndTwoInstructionSets { - BlockType block_type; - NonnullOwnPtrVector left_instructions; - NonnullOwnPtrVector right_instructions; + InstructionPointer end_ip; + Optional else_ip; }; struct TableBranchArgs { @@ -422,14 +418,13 @@ public: { } - static ParseResult parse(InputStream& stream); + static ParseResult> parse(InputStream& stream, InstructionPointer& ip); private: OpCode m_opcode { 0 }; // clang-format off Variant< - BlockAndInstructionSet, - BlockAndTwoInstructionSets, + BlockType, DataIndex, ElementIndex, FunctionIndex, @@ -438,6 +433,7 @@ private: LabelIndex, LocalIndex, MemoryArgument, + StructuredInstructionArgs, TableBranchArgs, TableElementArgs, TableIndex,