mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
LibWasm: Un-nest the structured instructions
This commit is contained in:
parent
06a1c27e4d
commit
7a12f23c28
Notes:
sideshowbarker
2024-07-18 18:13:18 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/7a12f23c285 Pull-request: https://github.com/SerenityOS/serenity/pull/7021
3 changed files with 69 additions and 58 deletions
|
@ -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,
|
||||
|
|
|
@ -81,8 +81,8 @@ struct ParseUntilAnyOfResult {
|
|||
u8 terminator { 0 };
|
||||
Vector<T> values;
|
||||
};
|
||||
template<typename T, typename... Args>
|
||||
static ParseResult<ParseUntilAnyOfResult<T>> parse_until_any_of(InputStream& stream, Args... terminators) requires(requires(InputStream& stream) { T::parse(stream); })
|
||||
template<typename T, u8... terminators, typename... Args>
|
||||
static ParseResult<ParseUntilAnyOfResult<T>> parse_until_any_of(InputStream& stream, Args... args) requires(requires(InputStream& stream, Args... args) { T::parse(stream, args...); })
|
||||
{
|
||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger;
|
||||
ReconsumableStream new_stream { stream };
|
||||
|
@ -105,7 +105,7 @@ static ParseResult<ParseUntilAnyOfResult<T>> 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> 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> Instruction::parse(InputStream& stream)
|
||||
ParseResult<Vector<Instruction>> Instruction::parse(InputStream& stream, InstructionPointer& ip)
|
||||
{
|
||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Instruction");
|
||||
u8 byte;
|
||||
|
@ -279,6 +281,7 @@ ParseResult<Instruction> 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> Instruction::parse(InputStream& stream)
|
|||
auto block_type = BlockType::parse(stream);
|
||||
if (block_type.is_error())
|
||||
return block_type.error();
|
||||
NonnullOwnPtrVector<Instruction> left_instructions, right_instructions;
|
||||
Vector<Instruction> instructions;
|
||||
InstructionPointer end_ip, else_ip;
|
||||
|
||||
{
|
||||
auto result = parse_until_any_of<Instruction>(stream, 0x0b, 0x05);
|
||||
auto result = parse_until_any_of<Instruction, 0x0b, 0x05>(stream, ip);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
|
||||
if (result.value().terminator == 0x0b) {
|
||||
// block/loop/if without else
|
||||
NonnullOwnPtrVector<Instruction> instructions;
|
||||
for (auto& entry : result.value().values)
|
||||
instructions.append(make<Instruction>(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<Instruction>(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<Instruction>(stream, 0x0b);
|
||||
auto result = parse_until_any_of<Instruction, 0x0b>(stream, ip);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
|
||||
for (auto& entry : result.value().values)
|
||||
right_instructions.append(make<Instruction>(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> 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> 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> 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> 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> Instruction::parse(InputStream& stream)
|
|||
if (!LEB128::read_unsigned(stream, offset))
|
||||
return with_eof_check(stream, ParseError::InvalidInput);
|
||||
|
||||
return Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } };
|
||||
return Vector { Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } } };
|
||||
}
|
||||
case Instructions::local_get.value():
|
||||
case Instructions::local_set.value():
|
||||
|
@ -398,7 +408,7 @@ ParseResult<Instruction> 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> 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> 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> 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> Instruction::parse(InputStream& stream)
|
|||
return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
|
||||
|
||||
auto floating = bit_cast<float>(static_cast<u32>(value));
|
||||
return Instruction { opcode, floating };
|
||||
return Vector { Instruction { opcode, floating } };
|
||||
}
|
||||
case Instructions::f64_const.value(): {
|
||||
// op literal
|
||||
|
@ -454,7 +466,7 @@ ParseResult<Instruction> Instruction::parse(InputStream& stream)
|
|||
return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
|
||||
|
||||
auto floating = bit_cast<double>(static_cast<u64>(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> 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<ValueType>(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> 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<FunctionIndex>::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> 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> 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<DataIndex>::parse(stream);
|
||||
if (index.is_error())
|
||||
|
@ -642,13 +654,13 @@ ParseResult<Instruction> 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<DataIndex>::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> 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> 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<ElementIndex>::parse(stream);
|
||||
|
@ -677,13 +689,13 @@ ParseResult<Instruction> Instruction::parse(InputStream& stream)
|
|||
auto table_index = GenericIndexParser<TableIndex>::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<ElementIndex>::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<TableIndex>::parse(stream);
|
||||
|
@ -692,7 +704,7 @@ ParseResult<Instruction> Instruction::parse(InputStream& stream)
|
|||
auto rhs = GenericIndexParser<TableIndex>::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> Instruction::parse(InputStream& stream)
|
|||
auto index = GenericIndexParser<TableIndex>::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> MemorySection::parse(InputStream& stream)
|
|||
ParseResult<Expression> Expression::parse(InputStream& stream)
|
||||
{
|
||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Expression");
|
||||
auto instructions = parse_until_any_of<Instruction>(stream, 0x0b);
|
||||
InstructionPointer ip { 0 };
|
||||
auto instructions = parse_until_any_of<Instruction, 0x0b>(stream, ip);
|
||||
if (instructions.is_error())
|
||||
return instructions.error();
|
||||
|
||||
|
|
|
@ -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<Instruction> instructions;
|
||||
};
|
||||
|
||||
struct BlockAndTwoInstructionSets {
|
||||
BlockType block_type;
|
||||
NonnullOwnPtrVector<Instruction> left_instructions;
|
||||
NonnullOwnPtrVector<Instruction> right_instructions;
|
||||
InstructionPointer end_ip;
|
||||
Optional<InstructionPointer> else_ip;
|
||||
};
|
||||
|
||||
struct TableBranchArgs {
|
||||
|
@ -422,14 +418,13 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
static ParseResult<Instruction> parse(InputStream& stream);
|
||||
static ParseResult<Vector<Instruction>> 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,
|
||||
|
|
Loading…
Reference in a new issue