mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibWasm: Introduce TRY_READ
for parser
Convenience macro akin to `TRY` for reading from a stream.
This commit is contained in:
parent
dc52998341
commit
9800ef6047
Notes:
github-actions[bot]
2024-07-28 11:03:38 +00:00
Author: https://github.com/dzfrias Commit: https://github.com/LadybirdBrowser/ladybird/commit/9800ef60473 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/875 Reviewed-by: https://github.com/alimpfard ✅
1 changed files with 71 additions and 191 deletions
|
@ -16,6 +16,18 @@
|
||||||
|
|
||||||
namespace Wasm {
|
namespace Wasm {
|
||||||
|
|
||||||
|
#define TRY_READ(stream, type, error) \
|
||||||
|
({ \
|
||||||
|
/* Ignore -Wshadow to allow nesting the macro. */ \
|
||||||
|
AK_IGNORE_DIAGNOSTIC("-Wshadow", \
|
||||||
|
auto&& _temporary_result = stream.read_value<type>()); \
|
||||||
|
static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_result.release_value())>, \
|
||||||
|
"Do not return a reference from a fallible expression"); \
|
||||||
|
if (_temporary_result.is_error()) [[unlikely]] \
|
||||||
|
return with_eof_check(stream, error); \
|
||||||
|
_temporary_result.release_value(); \
|
||||||
|
})
|
||||||
|
|
||||||
ParseError with_eof_check(Stream const& stream, ParseError error_if_not_eof)
|
ParseError with_eof_check(Stream const& stream, ParseError error_if_not_eof)
|
||||||
{
|
{
|
||||||
if (stream.is_eof())
|
if (stream.is_eof())
|
||||||
|
@ -90,11 +102,7 @@ static ParseResult<ByteString> parse_name(Stream& stream)
|
||||||
ParseResult<ValueType> ValueType::parse(Stream& stream)
|
ParseResult<ValueType> ValueType::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("ValueType"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("ValueType"sv);
|
||||||
auto tag_or_error = stream.read_value<u8>();
|
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Constants::i32_tag:
|
case Constants::i32_tag:
|
||||||
|
@ -112,7 +120,7 @@ ParseResult<ValueType> ValueType::parse(Stream& stream)
|
||||||
case Constants::extern_reference_tag:
|
case Constants::extern_reference_tag:
|
||||||
return ValueType(ExternReference);
|
return ValueType(ExternReference);
|
||||||
default:
|
default:
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return ParseError::InvalidTag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,11 +134,7 @@ ParseResult<ResultType> ResultType::parse(Stream& stream)
|
||||||
ParseResult<FunctionType> FunctionType::parse(Stream& stream)
|
ParseResult<FunctionType> FunctionType::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("FunctionType"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("FunctionType"sv);
|
||||||
auto tag_or_error = stream.read_value<u8>();
|
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
|
||||||
|
|
||||||
if (tag != Constants::function_signature_tag) {
|
if (tag != Constants::function_signature_tag) {
|
||||||
dbgln("Expected 0x60, but found {:#x}", tag);
|
dbgln("Expected 0x60, but found {:#x}", tag);
|
||||||
|
@ -146,11 +150,7 @@ ParseResult<FunctionType> FunctionType::parse(Stream& stream)
|
||||||
ParseResult<Limits> Limits::parse(Stream& stream)
|
ParseResult<Limits> Limits::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Limits"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Limits"sv);
|
||||||
auto flag_or_error = stream.read_value<u8>();
|
auto flag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (flag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto flag = flag_or_error.release_value();
|
|
||||||
|
|
||||||
if (flag > 1)
|
if (flag > 1)
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return with_eof_check(stream, ParseError::InvalidTag);
|
||||||
|
@ -183,7 +183,7 @@ ParseResult<TableType> TableType::parse(Stream& stream)
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("TableType"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("TableType"sv);
|
||||||
auto type_result = TRY(ValueType::parse(stream));
|
auto type_result = TRY(ValueType::parse(stream));
|
||||||
if (!type_result.is_reference())
|
if (!type_result.is_reference())
|
||||||
return with_eof_check(stream, ParseError::InvalidType);
|
return ParseError::InvalidType;
|
||||||
auto limits_result = TRY(Limits::parse(stream));
|
auto limits_result = TRY(Limits::parse(stream));
|
||||||
return TableType { type_result, limits_result };
|
return TableType { type_result, limits_result };
|
||||||
}
|
}
|
||||||
|
@ -192,12 +192,7 @@ ParseResult<GlobalType> GlobalType::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("GlobalType"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("GlobalType"sv);
|
||||||
auto type_result = TRY(ValueType::parse(stream));
|
auto type_result = TRY(ValueType::parse(stream));
|
||||||
|
auto mutable_ = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
auto mutable_or_error = stream.read_value<u8>();
|
|
||||||
if (mutable_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto mutable_ = mutable_or_error.release_value();
|
|
||||||
|
|
||||||
if (mutable_ > 1)
|
if (mutable_ > 1)
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return with_eof_check(stream, ParseError::InvalidTag);
|
||||||
|
@ -208,11 +203,8 @@ ParseResult<GlobalType> GlobalType::parse(Stream& stream)
|
||||||
ParseResult<BlockType> BlockType::parse(Stream& stream)
|
ParseResult<BlockType> BlockType::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("BlockType"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("BlockType"sv);
|
||||||
auto kind_or_error = stream.read_value<u8>();
|
auto kind = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (kind_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto kind = kind_or_error.release_value();
|
|
||||||
if (kind == Constants::empty_block_tag)
|
if (kind == Constants::empty_block_tag)
|
||||||
return BlockType {};
|
return BlockType {};
|
||||||
|
|
||||||
|
@ -227,10 +219,7 @@ ParseResult<BlockType> BlockType::parse(Stream& stream)
|
||||||
|
|
||||||
// FIXME: should be an i33. Right now, we're missing a potential last bit at
|
// FIXME: should be an i33. Right now, we're missing a potential last bit at
|
||||||
// the end. See https://webassembly.github.io/spec/core/binary/instructions.html#binary-blocktype
|
// the end. See https://webassembly.github.io/spec/core/binary/instructions.html#binary-blocktype
|
||||||
auto index_value_or_error = new_stream.read_value<LEB128<i32>>();
|
i32 index_value = TRY_READ(new_stream, LEB128<i32>, ParseError::ExpectedIndex);
|
||||||
if (index_value_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedIndex);
|
|
||||||
i32 index_value = index_value_or_error.release_value();
|
|
||||||
|
|
||||||
if (index_value < 0) {
|
if (index_value < 0) {
|
||||||
dbgln("Invalid type index {}", index_value);
|
dbgln("Invalid type index {}", index_value);
|
||||||
|
@ -243,11 +232,7 @@ ParseResult<BlockType> BlockType::parse(Stream& stream)
|
||||||
ParseResult<Instruction> Instruction::parse(Stream& stream)
|
ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Instruction"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Instruction"sv);
|
||||||
auto byte_or_error = stream.read_value<u8>();
|
auto byte = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (byte_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto byte = byte_or_error.release_value();
|
|
||||||
|
|
||||||
OpCode opcode { byte };
|
OpCode opcode { byte };
|
||||||
|
|
||||||
|
@ -307,27 +292,18 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case Instructions::i64_store16.value():
|
case Instructions::i64_store16.value():
|
||||||
case Instructions::i64_store32.value(): {
|
case Instructions::i64_store32.value(): {
|
||||||
// op (align [multi-memory: memindex] offset)
|
// op (align [multi-memory: memindex] offset)
|
||||||
auto align_or_error = stream.read_value<LEB128<u32>>();
|
u32 align = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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.
|
// Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment.
|
||||||
size_t memory_index = 0;
|
auto memory_index = 0;
|
||||||
if ((align & 0x40) != 0) {
|
if ((align & 0x40) != 0) {
|
||||||
align &= ~0x40;
|
align &= ~0x40;
|
||||||
auto memory_index_or_error = stream.read_value<LEB128<u32>>();
|
memory_index = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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<LEB128<u32>>();
|
auto offset = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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<u32>(align), static_cast<u32>(offset), MemoryIndex(memory_index) } };
|
return Instruction { opcode, MemoryArgument { align, offset, MemoryIndex(memory_index) } };
|
||||||
}
|
}
|
||||||
case Instructions::local_get.value():
|
case Instructions::local_get.value():
|
||||||
case Instructions::local_set.value():
|
case Instructions::local_set.value():
|
||||||
|
@ -343,48 +319,31 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case Instructions::memory_size.value():
|
case Instructions::memory_size.value():
|
||||||
case Instructions::memory_grow.value(): {
|
case Instructions::memory_grow.value(): {
|
||||||
// op [multi-memory: memindex]|0x00
|
// op [multi-memory: memindex]|0x00
|
||||||
|
auto memory_index = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
auto memory_index_or_error = stream.read_value<u8>();
|
|
||||||
if (memory_index_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto memory_index = memory_index_or_error.release_value();
|
|
||||||
|
|
||||||
return Instruction { opcode, MemoryIndexArgument { MemoryIndex(memory_index) } };
|
return Instruction { opcode, MemoryIndexArgument { MemoryIndex(memory_index) } };
|
||||||
}
|
}
|
||||||
case Instructions::i32_const.value(): {
|
case Instructions::i32_const.value(): {
|
||||||
auto value_or_error = stream.read_value<LEB128<i32>>();
|
auto value = TRY_READ(stream, LEB128<i32>, ParseError::ExpectedSignedImmediate);
|
||||||
if (value_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
|
|
||||||
i32 value = value_or_error.release_value();
|
|
||||||
|
|
||||||
return Instruction { opcode, value };
|
return Instruction { opcode, value };
|
||||||
}
|
}
|
||||||
case Instructions::i64_const.value(): {
|
case Instructions::i64_const.value(): {
|
||||||
// op literal
|
// op literal
|
||||||
auto value_or_error = stream.read_value<LEB128<i64>>();
|
auto value = TRY_READ(stream, LEB128<i64>, ParseError::ExpectedSignedImmediate);
|
||||||
if (value_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
|
|
||||||
i64 value = value_or_error.release_value();
|
|
||||||
|
|
||||||
return Instruction { opcode, value };
|
return Instruction { opcode, value };
|
||||||
}
|
}
|
||||||
case Instructions::f32_const.value(): {
|
case Instructions::f32_const.value(): {
|
||||||
// op literal
|
// op literal
|
||||||
auto value_or_error = stream.read_value<LittleEndian<u32>>();
|
auto value = TRY_READ(stream, LittleEndian<u32>, ParseError::ExpectedFloatingImmediate);
|
||||||
if (value_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
|
|
||||||
auto value = value_or_error.release_value();
|
|
||||||
|
|
||||||
auto floating = bit_cast<float>(static_cast<u32>(value));
|
auto floating = bit_cast<float>(static_cast<u32>(value));
|
||||||
return Instruction { opcode, floating };
|
return Instruction { opcode, floating };
|
||||||
}
|
}
|
||||||
case Instructions::f64_const.value(): {
|
case Instructions::f64_const.value(): {
|
||||||
// op literal
|
// op literal
|
||||||
auto value_or_error = stream.read_value<LittleEndian<u64>>();
|
auto value = TRY_READ(stream, LittleEndian<u64>, ParseError::ExpectedFloatingImmediate);
|
||||||
if (value_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedFloatingImmediate);
|
|
||||||
auto value = value_or_error.release_value();
|
|
||||||
|
|
||||||
auto floating = bit_cast<double>(static_cast<u64>(value));
|
auto floating = bit_cast<double>(static_cast<u64>(value));
|
||||||
return Instruction { opcode, floating };
|
return Instruction { opcode, floating };
|
||||||
|
@ -549,10 +508,7 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case 0xfc:
|
case 0xfc:
|
||||||
case 0xfd: {
|
case 0xfd: {
|
||||||
// These are multibyte instructions.
|
// These are multibyte instructions.
|
||||||
auto selector_or_error = stream.read_value<LEB128<u32>>();
|
auto selector = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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<u64>(opcode.value()) << 56 | selector;
|
OpCode full_opcode = static_cast<u64>(opcode.value()) << 56 | selector;
|
||||||
|
|
||||||
switch (full_opcode.value()) {
|
switch (full_opcode.value()) {
|
||||||
|
@ -569,11 +525,7 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
auto index = TRY(GenericIndexParser<DataIndex>::parse(stream));
|
auto index = TRY(GenericIndexParser<DataIndex>::parse(stream));
|
||||||
|
|
||||||
// Proposal "multi-memory", literal 0x00 is replaced with a memory index.
|
// Proposal "multi-memory", literal 0x00 is replaced with a memory index.
|
||||||
auto memory_index_or_error = stream.read_value<u8>();
|
auto memory_index = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
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) } };
|
return Instruction { full_opcode, MemoryInitArgs { index, MemoryIndex(memory_index) } };
|
||||||
}
|
}
|
||||||
|
@ -586,21 +538,14 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
MemoryIndex indices[] = { 0, 0 };
|
MemoryIndex indices[] = { 0, 0 };
|
||||||
|
|
||||||
for (size_t i = 0; i < 2; ++i) {
|
for (size_t i = 0; i < 2; ++i) {
|
||||||
auto memory_index_or_error = stream.read_value<u8>();
|
auto memory_index = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
if (memory_index_or_error.is_error())
|
indices[i] = memory_index;
|
||||||
return with_eof_check(stream, ParseError::InvalidInput);
|
|
||||||
|
|
||||||
indices[i] = memory_index_or_error.release_value();
|
|
||||||
}
|
}
|
||||||
return Instruction { full_opcode, MemoryCopyArgs { indices[1], indices[0] } };
|
return Instruction { full_opcode, MemoryCopyArgs { indices[1], indices[0] } };
|
||||||
}
|
}
|
||||||
case Instructions::memory_fill.value(): {
|
case Instructions::memory_fill.value(): {
|
||||||
// Proposal "multi-memory", literal 0x00 is replaced with a memory index.
|
// Proposal "multi-memory", literal 0x00 is replaced with a memory index.
|
||||||
auto memory_index_or_error = stream.read_value<u8>();
|
auto memory_index = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
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, MemoryIndexArgument { MemoryIndex { memory_index } } };
|
return Instruction { full_opcode, MemoryIndexArgument { MemoryIndex { memory_index } } };
|
||||||
}
|
}
|
||||||
case Instructions::table_init.value(): {
|
case Instructions::table_init.value(): {
|
||||||
|
@ -638,27 +583,18 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case Instructions::v128_load64_zero.value():
|
case Instructions::v128_load64_zero.value():
|
||||||
case Instructions::v128_store.value(): {
|
case Instructions::v128_store.value(): {
|
||||||
// op (align [multi-memory memindex] offset)
|
// op (align [multi-memory memindex] offset)
|
||||||
auto align_or_error = stream.read_value<LEB128<u32>>();
|
u32 align = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedIndex);
|
||||||
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.
|
// Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment.
|
||||||
size_t memory_index = 0;
|
auto memory_index = 0;
|
||||||
if ((align & 0x20) != 0) {
|
if ((align & 0x20) != 0) {
|
||||||
align &= ~0x20;
|
align &= ~0x20;
|
||||||
auto memory_index_or_error = stream.read_value<LEB128<u32>>();
|
memory_index = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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<LEB128<u32>>();
|
auto offset = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedIndex);
|
||||||
if (offset_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedIndex);
|
|
||||||
size_t offset = offset_or_error.release_value();
|
|
||||||
|
|
||||||
return Instruction { full_opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset), MemoryIndex(memory_index) } };
|
return Instruction { full_opcode, MemoryArgument { align, offset, MemoryIndex(memory_index) } };
|
||||||
}
|
}
|
||||||
case Instructions::v128_load8_lane.value():
|
case Instructions::v128_load8_lane.value():
|
||||||
case Instructions::v128_load16_lane.value():
|
case Instructions::v128_load16_lane.value():
|
||||||
|
@ -669,48 +605,31 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case Instructions::v128_store32_lane.value():
|
case Instructions::v128_store32_lane.value():
|
||||||
case Instructions::v128_store64_lane.value(): {
|
case Instructions::v128_store64_lane.value(): {
|
||||||
// op (align [multi-memory: memindex] offset) (index)
|
// op (align [multi-memory: memindex] offset) (index)
|
||||||
auto align_or_error = stream.read_value<LEB128<u32>>();
|
u32 align = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedIndex);
|
||||||
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.
|
// Proposal "multi-memory", if bit 6 of alignment is set, then a memory index follows the alignment.
|
||||||
size_t memory_index = 0;
|
auto memory_index = 0;
|
||||||
if ((align & 0x20) != 0) {
|
if ((align & 0x20) != 0) {
|
||||||
align &= ~0x20;
|
align &= ~0x20;
|
||||||
auto memory_index_or_error = stream.read_value<LEB128<u32>>();
|
memory_index = TRY_READ(stream, LEB128<u32>, ParseError::InvalidInput);
|
||||||
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<LEB128<u32>>();
|
auto offset = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedIndex);
|
||||||
if (offset_or_error.is_error())
|
auto index = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
return with_eof_check(stream, ParseError::ExpectedIndex);
|
|
||||||
size_t offset = offset_or_error.release_value();
|
|
||||||
|
|
||||||
auto index_or_error = stream.read_value<u8>();
|
return Instruction { full_opcode, MemoryAndLaneArgument { { align, offset, MemoryIndex(memory_index) }, index } };
|
||||||
if (index_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::InvalidInput);
|
|
||||||
auto index = index_or_error.release_value();
|
|
||||||
|
|
||||||
return Instruction { full_opcode, MemoryAndLaneArgument { { static_cast<u32>(align), static_cast<u32>(offset), MemoryIndex(memory_index) }, index } };
|
|
||||||
}
|
}
|
||||||
case Instructions::v128_const.value(): {
|
case Instructions::v128_const.value(): {
|
||||||
// op (literal:16)
|
// op (literal:16)
|
||||||
auto value_or_error = stream.read_value<LittleEndian<u128>>();
|
auto value = TRY_READ(stream, LittleEndian<u128>, ParseError::InvalidImmediate);
|
||||||
if (value_or_error.is_error())
|
return Instruction { full_opcode, value };
|
||||||
return with_eof_check(stream, ParseError::InvalidImmediate);
|
|
||||||
return Instruction { full_opcode, value_or_error.release_value() };
|
|
||||||
}
|
}
|
||||||
case Instructions::i8x16_shuffle.value(): {
|
case Instructions::i8x16_shuffle.value(): {
|
||||||
// op 16x(lane)
|
// op 16x(lane)
|
||||||
u8 lanes[16];
|
u8 lanes[16];
|
||||||
for (size_t i = 0; i < 16; ++i) {
|
for (size_t i = 0; i < 16; ++i) {
|
||||||
auto value_or_error = stream.read_value<u8>();
|
auto value = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
if (value_or_error.is_error())
|
lanes[i] = value;
|
||||||
return with_eof_check(stream, ParseError::InvalidInput);
|
|
||||||
lanes[i] = value_or_error.release_value();
|
|
||||||
}
|
}
|
||||||
return Instruction { full_opcode, ShuffleArgument(lanes) };
|
return Instruction { full_opcode, ShuffleArgument(lanes) };
|
||||||
}
|
}
|
||||||
|
@ -729,10 +648,7 @@ ParseResult<Instruction> Instruction::parse(Stream& stream)
|
||||||
case Instructions::f64x2_extract_lane.value():
|
case Instructions::f64x2_extract_lane.value():
|
||||||
case Instructions::f64x2_replace_lane.value(): {
|
case Instructions::f64x2_replace_lane.value(): {
|
||||||
// op (lane)
|
// op (lane)
|
||||||
auto lane_or_error = stream.read_value<u8>();
|
auto lane = TRY_READ(stream, u8, ParseError::InvalidInput);
|
||||||
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 } };
|
return Instruction { full_opcode, LaneIndex { lane } };
|
||||||
}
|
}
|
||||||
case Instructions::i8x16_swizzle.value():
|
case Instructions::i8x16_swizzle.value():
|
||||||
|
@ -961,7 +877,7 @@ ParseResult<CustomSection> CustomSection::parse(Stream& stream)
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
break;
|
break;
|
||||||
if (data_buffer.try_append(buf, size).is_error())
|
if (data_buffer.try_append(buf, size).is_error())
|
||||||
return with_eof_check(stream, ParseError::HugeAllocationRequested);
|
return ParseError::HugeAllocationRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CustomSection(name, move(data_buffer));
|
return CustomSection(name, move(data_buffer));
|
||||||
|
@ -979,11 +895,7 @@ ParseResult<ImportSection::Import> ImportSection::Import::parse(Stream& stream)
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Import"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Import"sv);
|
||||||
auto module = TRY(parse_name(stream));
|
auto module = TRY(parse_name(stream));
|
||||||
auto name = TRY(parse_name(stream));
|
auto name = TRY(parse_name(stream));
|
||||||
auto tag_or_error = stream.read_value<u8>();
|
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Constants::extern_function_tag: {
|
case Constants::extern_function_tag: {
|
||||||
|
@ -997,7 +909,7 @@ ParseResult<ImportSection::Import> ImportSection::Import::parse(Stream& stream)
|
||||||
case Constants::extern_global_tag:
|
case Constants::extern_global_tag:
|
||||||
return parse_with_type<GlobalType>(stream, module, name);
|
return parse_with_type<GlobalType>(stream, module, name);
|
||||||
default:
|
default:
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return ParseError::InvalidTag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,16 +1022,9 @@ ParseResult<ExportSection::Export> ExportSection::Export::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Export"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Export"sv);
|
||||||
auto name = TRY(parse_name(stream));
|
auto name = TRY(parse_name(stream));
|
||||||
auto tag_or_error = stream.read_value<u8>();
|
auto tag = TRY_READ(stream, u8, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
auto index = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedIndex);
|
||||||
|
|
||||||
auto index_or_error = stream.read_value<LEB128<u32>>();
|
|
||||||
if (index_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedIndex);
|
|
||||||
size_t index = index_or_error.release_value();
|
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Constants::extern_function_tag:
|
case Constants::extern_function_tag:
|
||||||
|
@ -1131,7 +1036,7 @@ ParseResult<ExportSection::Export> ExportSection::Export::parse(Stream& stream)
|
||||||
case Constants::extern_global_tag:
|
case Constants::extern_global_tag:
|
||||||
return Export { name, ExportDesc { GlobalIndex { index } } };
|
return Export { name, ExportDesc { GlobalIndex { index } } };
|
||||||
default:
|
default:
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return ParseError::InvalidTag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1159,11 +1064,7 @@ ParseResult<StartSection> StartSection::parse(Stream& stream)
|
||||||
ParseResult<ElementSection::Element> ElementSection::Element::parse(Stream& stream)
|
ParseResult<ElementSection::Element> ElementSection::Element::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Element"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Element"sv);
|
||||||
auto tag_or_error = stream.read_value<LEB128<u32>>();
|
auto tag = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
|
||||||
|
|
||||||
if (tag > 0x07)
|
if (tag > 0x07)
|
||||||
return ParseError::InvalidTag;
|
return ParseError::InvalidTag;
|
||||||
|
@ -1192,12 +1093,10 @@ ParseResult<ElementSection::Element> ElementSection::Element::parse(Stream& stre
|
||||||
if (has_exprs) {
|
if (has_exprs) {
|
||||||
type = TRY(ValueType::parse(stream));
|
type = TRY(ValueType::parse(stream));
|
||||||
} else {
|
} else {
|
||||||
auto extern_or_error = stream.read_value<u8>();
|
auto extern_ = TRY_READ(stream, u8, ParseError::InvalidType);
|
||||||
if (extern_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::InvalidType);
|
|
||||||
// Make sure that this is a function, as it's technically only the
|
// Make sure that this is a function, as it's technically only the
|
||||||
// allowed one.
|
// allowed one.
|
||||||
if (extern_or_error.release_value() != 0x00) {
|
if (extern_ != 0x00) {
|
||||||
return ParseError::InvalidType;
|
return ParseError::InvalidType;
|
||||||
}
|
}
|
||||||
type = ValueType(ValueType::FunctionReference);
|
type = ValueType(ValueType::FunctionReference);
|
||||||
|
@ -1228,17 +1127,14 @@ ParseResult<ElementSection> ElementSection::parse(Stream& stream)
|
||||||
ParseResult<Locals> Locals::parse(Stream& stream)
|
ParseResult<Locals> Locals::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Locals"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Locals"sv);
|
||||||
auto count_or_error = stream.read_value<LEB128<u32>>();
|
auto count = TRY_READ(stream, LEB128<u32>, ParseError::InvalidSize);
|
||||||
if (count_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::InvalidSize);
|
|
||||||
size_t count = count_or_error.release_value();
|
|
||||||
|
|
||||||
if (count > Constants::max_allowed_function_locals_per_type)
|
if (count > Constants::max_allowed_function_locals_per_type)
|
||||||
return with_eof_check(stream, ParseError::HugeAllocationRequested);
|
return ParseError::HugeAllocationRequested;
|
||||||
|
|
||||||
auto type = TRY(ValueType::parse(stream));
|
auto type = TRY(ValueType::parse(stream));
|
||||||
|
|
||||||
return Locals { static_cast<u32>(count), type };
|
return Locals { count, type };
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseResult<CodeSection::Func> CodeSection::Func::parse(Stream& stream, size_t size_hint)
|
ParseResult<CodeSection::Func> CodeSection::Func::parse(Stream& stream, size_t size_hint)
|
||||||
|
@ -1252,16 +1148,13 @@ ParseResult<CodeSection::Func> CodeSection::Func::parse(Stream& stream, size_t s
|
||||||
ParseResult<CodeSection::Code> CodeSection::Code::parse(Stream& stream)
|
ParseResult<CodeSection::Code> CodeSection::Code::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Code"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Code"sv);
|
||||||
auto size_or_error = stream.read_value<LEB128<u32>>();
|
auto size = TRY_READ(stream, LEB128<u32>, ParseError::InvalidSize);
|
||||||
if (size_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::InvalidSize);
|
|
||||||
size_t size = size_or_error.release_value();
|
|
||||||
|
|
||||||
// Emprically, if there are `size` bytes to be read, then there's around
|
// Emprically, if there are `size` bytes to be read, then there's around
|
||||||
// `size / 2` instructions, so we pass that as our size hint.
|
// `size / 2` instructions, so we pass that as our size hint.
|
||||||
auto func = TRY(Func::parse(stream, size / 2));
|
auto func = TRY(Func::parse(stream, size / 2));
|
||||||
|
|
||||||
return Code { static_cast<u32>(size), move(func) };
|
return Code { size, move(func) };
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseResult<CodeSection> CodeSection::parse(Stream& stream)
|
ParseResult<CodeSection> CodeSection::parse(Stream& stream)
|
||||||
|
@ -1274,14 +1167,10 @@ ParseResult<CodeSection> CodeSection::parse(Stream& stream)
|
||||||
ParseResult<DataSection::Data> DataSection::Data::parse(Stream& stream)
|
ParseResult<DataSection::Data> DataSection::Data::parse(Stream& stream)
|
||||||
{
|
{
|
||||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Data"sv);
|
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Data"sv);
|
||||||
auto tag_or_error = stream.read_value<LEB128<u32>>();
|
auto tag = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedKindTag);
|
||||||
if (tag_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedKindTag);
|
|
||||||
|
|
||||||
auto tag = tag_or_error.release_value();
|
|
||||||
|
|
||||||
if (tag > 0x02)
|
if (tag > 0x02)
|
||||||
return with_eof_check(stream, ParseError::InvalidTag);
|
return ParseError::InvalidTag;
|
||||||
|
|
||||||
if (tag == 0x00) {
|
if (tag == 0x00) {
|
||||||
auto expr = TRY(Expression::parse(stream));
|
auto expr = TRY(Expression::parse(stream));
|
||||||
|
@ -1340,17 +1229,8 @@ ParseResult<Module> Module::parse(Stream& stream)
|
||||||
|
|
||||||
Vector<AnySection> sections;
|
Vector<AnySection> sections;
|
||||||
while (!stream.is_eof()) {
|
while (!stream.is_eof()) {
|
||||||
auto section_id_or_error = stream.read_value<u8>();
|
auto section_id = TRY_READ(stream, u8, ParseError::ExpectedIndex);
|
||||||
if (section_id_or_error.is_error())
|
size_t section_size = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedSize);
|
||||||
return with_eof_check(stream, ParseError::ExpectedIndex);
|
|
||||||
|
|
||||||
auto section_id = section_id_or_error.release_value();
|
|
||||||
|
|
||||||
auto section_size_or_error = stream.read_value<LEB128<u32>>();
|
|
||||||
if (section_size_or_error.is_error())
|
|
||||||
return with_eof_check(stream, ParseError::ExpectedSize);
|
|
||||||
size_t section_size = section_size_or_error.release_value();
|
|
||||||
|
|
||||||
auto section_stream = ConstrainedStream { MaybeOwned<Stream>(stream), section_size };
|
auto section_stream = ConstrainedStream { MaybeOwned<Stream>(stream), section_size };
|
||||||
|
|
||||||
switch (section_id) {
|
switch (section_id) {
|
||||||
|
@ -1394,7 +1274,7 @@ ParseResult<Module> Module::parse(Stream& stream)
|
||||||
sections.append(TRY(DataCountSection::parse(section_stream)));
|
sections.append(TRY(DataCountSection::parse(section_stream)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return with_eof_check(stream, ParseError::InvalidIndex);
|
return ParseError::InvalidIndex;
|
||||||
}
|
}
|
||||||
if (section_stream.remaining() != 0)
|
if (section_stream.remaining() != 0)
|
||||||
return ParseError::SectionSizeMismatch;
|
return ParseError::SectionSizeMismatch;
|
||||||
|
|
Loading…
Reference in a new issue