srctree

Robin Linden parent 690f83e9 7ce7b0f8
wasm: Implement parsing the global section

inlinesplit
wasm/byte_code_parser.cpp added: 158, removed: 5, total 153
@@ -99,6 +99,42 @@ std::optional<Limits> parse(std::istream &is) {
return Limits{.min = *min, .max = *max};
}
 
template<>
std::optional<GlobalType> parse(std::istream &is) {
auto valtype = parse<ValueType>(is);
if (!valtype) {
return std::nullopt;
}
 
std::uint8_t mut{};
if (!is.read(reinterpret_cast<char *>(&mut), sizeof(mut)) || mut > 1) {
return std::nullopt;
}
 
return GlobalType{
.type = *std::move(valtype),
.mutability = mut == 0 ? GlobalType::Mutability::Const : GlobalType::Mutability::Var,
};
}
 
template<>
std::optional<GlobalSection::Global> parse(std::istream &is) {
auto type = parse<GlobalType>(is);
if (!type) {
return std::nullopt;
}
 
auto init = instructions::parse(is);
if (!init) {
return std::nullopt;
}
 
return GlobalSection::Global{
.type = *std::move(type),
.init = *std::move(init),
};
}
 
// https://webassembly.github.io/spec/core/binary/types.html#function-types
template<>
std::optional<FunctionType> parse(std::istream &is) {
@@ -279,6 +315,14 @@ std::optional<MemorySection> parse_memory_section(std::istream &is) {
return std::nullopt;
}
 
std::optional<GlobalSection> parse_global_section(std::istream &is) {
if (auto maybe_globals = parse_vector<GlobalSection::Global>(is)) {
return GlobalSection{*std::move(maybe_globals)};
}
 
return std::nullopt;
}
 
std::optional<ExportSection> parse_export_section(std::istream &is) {
if (auto maybe_exports = parse_vector<Export>(is)) {
return ExportSection{.exports = std::move(maybe_exports).value()};
@@ -388,6 +432,12 @@ tl::expected<Module, ModuleParseError> ByteCodeParser::parse_module(std::istream
return tl::unexpected{ModuleParseError::InvalidMemorySection};
}
break;
case SectionId::Global:
module.global_section = parse_global_section(is);
if (!module.global_section) {
return tl::unexpected{ModuleParseError::InvalidGlobalSection};
}
break;
case SectionId::Export:
module.export_section = parse_export_section(is);
if (!module.export_section) {
 
wasm/byte_code_parser.h added: 158, removed: 5, total 153
@@ -22,6 +22,7 @@ enum class ModuleParseError {
InvalidFunctionSection,
InvalidTableSection,
InvalidMemorySection,
InvalidGlobalSection,
InvalidExportSection,
InvalidStartSection,
InvalidCodeSection,
 
wasm/byte_code_parser_test.cpp added: 158, removed: 5, total 153
@@ -282,6 +282,80 @@ void memory_section_tests() {
});
}
 
void global_section_tests() {
etest::test("global section, missing data", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, empty", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {0})).value();
expect_eq(module.global_section, wasm::GlobalSection{});
});
 
etest::test("global section, missing global after count", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, missing globaltype valuetype", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, missing globaltype mutability", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1, 0x7f}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, invalid globaltype mutability", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1, 0x7f, 2}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, missing init", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1, 0x7f, 0}));
expect_eq(module, tl::unexpected{wasm::ModuleParseError::InvalidGlobalSection});
});
 
etest::test("global section, const i32 42", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1, 0x7f, 0, 0x41, 42, 0x0b}))
.value();
expect_eq(module.global_section,
wasm::GlobalSection{.globals{{
.type{wasm::ValueType{wasm::ValueType::Int32}, wasm::GlobalType::Mutability::Const},
.init{wasm::instructions::I32Const{42}},
}}});
});
 
etest::test("global section, var i32 42", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Global, {1, 0x7f, 1, 0x41, 42, 0x0b}))
.value();
expect_eq(module.global_section,
wasm::GlobalSection{.globals{{
.type{wasm::ValueType{wasm::ValueType::Int32}, wasm::GlobalType::Mutability::Var},
.init{wasm::instructions::I32Const{42}},
}}});
});
 
etest::test("global section, multiple globals", [] {
auto module = ByteCodeParser::parse_module(
make_module_bytes(SectionId::Global, {2, 0x7f, 1, 0x41, 42, 0x0b, 0x7f, 0, 0x41, 42, 0x0b}))
.value();
expect_eq(module.global_section,
wasm::GlobalSection{.globals{
{
.type{wasm::ValueType{wasm::ValueType::Int32}, wasm::GlobalType::Mutability::Var},
.init{wasm::instructions::I32Const{42}},
},
{
.type{wasm::ValueType{wasm::ValueType::Int32}, wasm::GlobalType::Mutability::Const},
.init{wasm::instructions::I32Const{42}},
},
}});
});
}
 
void type_section_tests() {
etest::test("type section, missing type data", [] {
auto module = ByteCodeParser::parse_module(make_module_bytes(SectionId::Type, {}));
@@ -485,6 +559,7 @@ int main() {
function_section_tests();
table_section_tests();
memory_section_tests();
global_section_tests();
export_section_tests();
start_section_tests();
code_section_tests();
 
wasm/wasm.h added: 158, removed: 5, total 153
@@ -43,6 +43,33 @@ struct MemorySection {
[[nodiscard]] bool operator==(MemorySection const &) const = default;
};
 
// https://webassembly.github.io/spec/core/binary/types.html#binary-globaltype
struct GlobalType {
enum class Mutability {
Const,
Var,
};
 
ValueType type{};
Mutability mutability{};
 
[[nodiscard]] bool operator==(GlobalType const &) const = default;
};
 
// https://webassembly.github.io/spec/core/binary/modules.html#binary-globalsec
struct GlobalSection {
struct Global {
GlobalType type{};
std::vector<instructions::Instruction> init{};
 
[[nodiscard]] bool operator==(Global const &) const = default;
};
 
std::vector<Global> globals{};
 
[[nodiscard]] bool operator==(GlobalSection const &) const = default;
};
 
// https://webassembly.github.io/spec/core/binary/modules.html#binary-export
struct Export {
enum class Type { Function = 0, Table = 1, Memory = 2, Global = 3 };
@@ -95,7 +122,7 @@ struct Module {
std::optional<FunctionSection> function_section{};
std::optional<TableSection> table_section{};
std::optional<MemorySection> memory_section{};
// TODO(robinlinden): global_section
std::optional<GlobalSection> global_section{};
std::optional<ExportSection> export_section{};
std::optional<StartSection> start_section{};
// TODO(robinlinden): element_section