From fcee718051b8f9fc9755314432c2aa9f18121c8c Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Mon, 5 Oct 2020 12:43:50 +0200 Subject: [PATCH] refactor: Allocate module dynamically --- lib/fizzy/execute.cpp | 20 +- lib/fizzy/execute.hpp | 2 +- lib/fizzy/instantiate.cpp | 78 ++-- lib/fizzy/instantiate.hpp | 16 +- lib/fizzy/parser.cpp | 95 ++--- lib/fizzy/parser.hpp | 3 +- test/spectests/spectests.cpp | 10 +- test/unittests/api_test.cpp | 14 +- test/unittests/end_to_end_test.cpp | 4 +- test/unittests/execute_call_test.cpp | 38 +- test/unittests/execute_control_test.cpp | 2 +- test/unittests/execute_numeric_test.cpp | 16 +- test/unittests/execute_test.cpp | 46 +-- test/unittests/instantiate_test.cpp | 70 ++-- test/unittests/module_test.cpp | 54 +-- test/unittests/parser_expr_test.cpp | 64 +-- test/unittests/parser_test.cpp | 472 +++++++++++------------ test/unittests/validation_stack_test.cpp | 22 +- test/utils/execute_helpers.hpp | 2 +- test/utils/fizzy_engine.cpp | 18 +- tools/wasi/wasi.cpp | 6 +- 21 files changed, 533 insertions(+), 519 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 84343e8a56..a8ceb1e164 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -467,14 +467,14 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, if (depth > CallStackLimit) return Trap; - const auto& func_type = instance.module.get_function_type(func_idx); + const auto& func_type = instance.module->get_function_type(func_idx); - assert(instance.module.imported_function_types.size() == instance.imported_functions.size()); + assert(instance.module->imported_function_types.size() == instance.imported_functions.size()); if (func_idx < instance.imported_functions.size()) return instance.imported_functions[func_idx].function( instance, {args, func_type.inputs.size()}, depth); - const auto& code = instance.module.get_code(func_idx); + const auto& code = instance.module->get_code(func_idx); auto* const memory = instance.memory.get(); OperandStack stack(args, func_type.inputs.size(), code.local_count, @@ -561,7 +561,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, case Instr::call: { const auto called_func_idx = read(immediates); - const auto& called_func_type = instance.module.get_function_type(called_func_idx); + const auto& called_func_type = instance.module->get_function_type(called_func_idx); if (!invoke_function(called_func_type, called_func_idx, instance, stack, depth)) goto trap; @@ -572,7 +572,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, assert(instance.table != nullptr); const auto expected_type_idx = read(immediates); - assert(expected_type_idx < instance.module.typesec.size()); + assert(expected_type_idx < instance.module->typesec.size()); const auto elem_idx = stack.pop().as(); if (elem_idx >= instance.table->size()) @@ -584,7 +584,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, // check actual type against expected type const auto& actual_type = called_func->type; - const auto& expected_type = instance.module.typesec[expected_type_idx]; + const auto& expected_type = instance.module->typesec[expected_type_idx]; if (expected_type != actual_type) goto trap; @@ -638,7 +638,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, else { const auto module_global_idx = idx - instance.imported_globals.size(); - assert(module_global_idx < instance.module.globalsec.size()); + assert(module_global_idx < instance.module->globalsec.size()); stack.push(instance.globals[module_global_idx]); } break; @@ -654,8 +654,8 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, else { const auto module_global_idx = idx - instance.imported_globals.size(); - assert(module_global_idx < instance.module.globalsec.size()); - assert(instance.module.globalsec[module_global_idx].type.is_mutable); + assert(module_global_idx < instance.module->globalsec.size()); + assert(instance.module->globalsec[module_global_idx].type.is_mutable); instance.globals[module_global_idx] = stack.pop(); } break; @@ -1518,7 +1518,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, end: assert(pc == &code.instructions[code.instructions.size()]); // End of code must be reached. - assert(stack.size() == instance.module.get_function_type(func_idx).outputs.size()); + assert(stack.size() == instance.module->get_function_type(func_idx).outputs.size()); return stack.size() != 0 ? ExecutionResult{stack.pop()} : Void; diff --git a/lib/fizzy/execute.hpp b/lib/fizzy/execute.hpp index 66c3d9a4b3..6c1f2c2190 100644 --- a/lib/fizzy/execute.hpp +++ b/lib/fizzy/execute.hpp @@ -43,7 +43,7 @@ ExecutionResult execute( inline ExecutionResult execute( Instance& instance, FuncIdx func_idx, std::initializer_list args) noexcept { - assert(args.size() == instance.module.get_function_type(func_idx).inputs.size()); + assert(args.size() == instance.module->get_function_type(func_idx).inputs.size()); return execute(instance, func_idx, args.begin()); } } // namespace fizzy diff --git a/lib/fizzy/instantiate.cpp b/lib/fizzy/instantiate.cpp index 2b2a32a4e1..b11d98b200 100644 --- a/lib/fizzy/instantiate.cpp +++ b/lib/fizzy/instantiate.cpp @@ -237,22 +237,22 @@ std::optional find_export(const Module& module, ExternalKind kind, std } // namespace -std::unique_ptr instantiate(Module module, +std::unique_ptr instantiate(std::unique_ptr&& module, std::vector imported_functions, std::vector imported_tables, std::vector imported_memories, std::vector imported_globals, uint32_t memory_pages_limit /*= DefaultMemoryPagesLimit*/) { - assert(module.funcsec.size() == module.codesec.size()); + assert(module->funcsec.size() == module->codesec.size()); - match_imported_functions(module.imported_function_types, imported_functions); - match_imported_tables(module.imported_table_types, imported_tables); - match_imported_memories(module.imported_memory_types, imported_memories); - match_imported_globals(module.imported_global_types, imported_globals); + match_imported_functions(module->imported_function_types, imported_functions); + match_imported_tables(module->imported_table_types, imported_tables); + match_imported_memories(module->imported_memory_types, imported_memories); + match_imported_globals(module->imported_global_types, imported_globals); // Init globals std::vector globals; - globals.reserve(module.globalsec.size()); - for (auto const& global : module.globalsec) + globals.reserve(module->globalsec.size()); + for (auto const& global : module->globalsec) { // Constraint to use global.get only with imported globals is checked at validation. assert(global.expression.kind != ConstantExpression::Kind::GlobalGet || @@ -262,10 +262,10 @@ std::unique_ptr instantiate(Module module, globals.emplace_back(value); } - auto [table, table_limits] = allocate_table(module.tablesec, imported_tables); + auto [table, table_limits] = allocate_table(module->tablesec, imported_tables); auto [memory, memory_limits] = - allocate_memory(module.memorysec, imported_memories, memory_pages_limit); + allocate_memory(module->memorysec, imported_memories, memory_pages_limit); // In case upper limit for local/imported memory is defined, // we adjust the hard memory limit, to ensure memory.grow will fail when exceeding it. // Note: allocate_memory ensures memory's max limit is always below memory_pages_limit. @@ -278,8 +278,8 @@ std::unique_ptr instantiate(Module module, // Before starting to fill memory and table, // check that data and element segments are within bounds. std::vector datasec_offsets; - datasec_offsets.reserve(module.datasec.size()); - for (const auto& data : module.datasec) + datasec_offsets.reserve(module->datasec.size()); + for (const auto& data : module->datasec) { // Offset is validated to be i32, but it's used in 64-bit calculation below. const uint64_t offset = @@ -291,10 +291,10 @@ std::unique_ptr instantiate(Module module, datasec_offsets.emplace_back(offset); } - assert(module.elementsec.empty() || table != nullptr); + assert(module->elementsec.empty() || table != nullptr); std::vector elementsec_offsets; - elementsec_offsets.reserve(module.elementsec.size()); - for (const auto& element : module.elementsec) + elementsec_offsets.reserve(module->elementsec.size()); + for (const auto& element : module->elementsec) { // Offset is validated to be i32, but it's used in 64-bit calculation below. const uint64_t offset = @@ -307,10 +307,10 @@ std::unique_ptr instantiate(Module module, } // Fill out memory based on data segments - for (size_t i = 0; i < module.datasec.size(); ++i) + for (size_t i = 0; i < module->datasec.size(); ++i) { // NOTE: these instructions can overlap - std::copy(module.datasec[i].init.begin(), module.datasec[i].init.end(), + std::copy(module->datasec[i].init.begin(), module->datasec[i].init.end(), memory->data() + datasec_offsets[i]); } @@ -321,41 +321,41 @@ std::unique_ptr instantiate(Module module, std::move(imported_functions), std::move(imported_globals)); // Fill the table based on elements segment - for (size_t i = 0; i < instance->module.elementsec.size(); ++i) + for (size_t i = 0; i < instance->module->elementsec.size(); ++i) { // Overwrite table[offset..] with element.init auto it_table = instance->table->begin() + elementsec_offsets[i]; - for (const auto idx : instance->module.elementsec[i].init) + for (const auto idx : instance->module->elementsec[i].init) { auto func = [idx, &instance_ref = *instance](fizzy::Instance&, span args, int depth) { return execute(instance_ref, idx, args.data(), depth); }; *it_table++ = - ExternalFunction{std::move(func), instance->module.get_function_type(idx)}; + ExternalFunction{std::move(func), instance->module->get_function_type(idx)}; } } // Run start function if present - if (instance->module.startfunc) + if (instance->module->startfunc) { - const auto funcidx = *instance->module.startfunc; - assert(funcidx < instance->imported_functions.size() + instance->module.funcsec.size()); + const auto funcidx = *instance->module->startfunc; + assert(funcidx < instance->imported_functions.size() + instance->module->funcsec.size()); if (execute(*instance, funcidx, {}).trapped) { // When element section modified imported table, and then start function trapped, // modifications to the table are not rolled back. // Instance in this case is not being returned to the user, so it needs to be kept alive // as long as functions using it are alive in the table. - if (!imported_tables.empty() && !instance->module.elementsec.empty()) + if (!imported_tables.empty() && !instance->module->elementsec.empty()) { // Instance may be used by several functions added to the table, // so we need a shared ownership here. std::shared_ptr shared_instance = std::move(instance); - for (size_t i = 0; i < shared_instance->module.elementsec.size(); ++i) + for (size_t i = 0; i < shared_instance->module->elementsec.size(); ++i) { auto it_table = shared_instance->table->begin() + elementsec_offsets[i]; - for ([[maybe_unused]] auto _ : shared_instance->module.elementsec[i].init) + for ([[maybe_unused]] auto _ : shared_instance->module->elementsec[i].init) { // Wrap the function with the lambda capturing shared instance auto& table_function = (*it_table)->function; @@ -373,6 +373,16 @@ std::unique_ptr instantiate(Module module, return instance; } +std::unique_ptr instantiate(const std::unique_ptr& module, + std::vector imported_functions, std::vector imported_tables, + std::vector imported_memories, std::vector imported_globals, + uint32_t memory_pages_limit) +{ + return instantiate(std::make_unique(*module), std::move(imported_functions), + std::move(imported_tables), std::move(imported_memories), std::move(imported_globals), + memory_pages_limit); +} + std::vector resolve_imported_functions( const Module& module, std::vector imported_functions) { @@ -427,7 +437,7 @@ std::optional find_exported_function(const Module& module, std::string_ std::optional find_exported_function(Instance& instance, std::string_view name) { - const auto opt_index = find_export(instance.module, ExternalKind::Function, name); + const auto opt_index = find_export(*instance.module, ExternalKind::Function, name); if (!opt_index.has_value()) return std::nullopt; @@ -436,12 +446,12 @@ std::optional find_exported_function(Instance& instance, std:: return execute(instance, idx, args.data(), depth); }; - return ExternalFunction{std::move(func), instance.module.get_function_type(idx)}; + return ExternalFunction{std::move(func), instance.module->get_function_type(idx)}; } std::optional find_exported_global(Instance& instance, std::string_view name) { - const auto opt_index = find_export(instance.module, ExternalKind::Global, name); + const auto opt_index = find_export(*instance.module, ExternalKind::Global, name); if (!opt_index.has_value()) return std::nullopt; @@ -457,16 +467,14 @@ std::optional find_exported_global(Instance& instance, std::stri // global owned by instance const auto module_global_idx = global_idx - instance.imported_globals.size(); return ExternalGlobal{&instance.globals[module_global_idx], - instance.module.globalsec[module_global_idx].type}; + instance.module->globalsec[module_global_idx].type}; } } std::optional find_exported_table(Instance& instance, std::string_view name) { - const auto& module = instance.module; - // Index returned from find_export is discarded, because there's no more than 1 table - if (!find_export(module, ExternalKind::Table, name)) + if (!find_export(*instance.module, ExternalKind::Table, name)) return std::nullopt; return ExternalTable{instance.table.get(), instance.table_limits}; @@ -474,10 +482,8 @@ std::optional find_exported_table(Instance& instance, std::string std::optional find_exported_memory(Instance& instance, std::string_view name) { - const auto& module = instance.module; - // Index returned from find_export is discarded, because there's no more than 1 memory - if (!find_export(module, ExternalKind::Memory, name)) + if (!find_export(*instance.module, ExternalKind::Memory, name)) return std::nullopt; return ExternalMemory{instance.memory.get(), instance.memory_limits}; diff --git a/lib/fizzy/instantiate.hpp b/lib/fizzy/instantiate.hpp index 224e5587e2..912e0a902e 100644 --- a/lib/fizzy/instantiate.hpp +++ b/lib/fizzy/instantiate.hpp @@ -54,7 +54,7 @@ using bytes_ptr = std::unique_ptr; // The module instance. struct Instance { - Module module; + std::unique_ptr module; // Memory is either allocated and owned by the instance or imported as already allocated bytes // and owned externally. // For these cases unique_ptr would either have a normal deleter or noop deleter respectively @@ -70,9 +70,9 @@ struct Instance std::vector imported_functions; std::vector imported_globals; - Instance(Module _module, bytes_ptr _memory, Limits _memory_limits, uint32_t _memory_pages_limit, - table_ptr _table, Limits _table_limits, std::vector _globals, - std::vector _imported_functions, + Instance(std::unique_ptr _module, bytes_ptr _memory, Limits _memory_limits, + uint32_t _memory_pages_limit, table_ptr _table, Limits _table_limits, + std::vector _globals, std::vector _imported_functions, std::vector _imported_globals) : module(std::move(_module)), memory(std::move(_memory)), @@ -87,13 +87,19 @@ struct Instance }; // Instantiate a module. -std::unique_ptr instantiate(Module module, +std::unique_ptr instantiate(std::unique_ptr&& module, std::vector imported_functions = {}, std::vector imported_tables = {}, std::vector imported_memories = {}, std::vector imported_globals = {}, uint32_t memory_pages_limit = DefaultMemoryPagesLimit); +std::unique_ptr instantiate(const std::unique_ptr& module, + std::vector imported_functions = {}, + std::vector imported_tables = {}, + std::vector imported_memories = {}, + std::vector imported_globals = {}, + uint32_t memory_pages_limit = DefaultMemoryPagesLimit); // Function that should be used by instantiate as imports, identified by module and function name. struct ImportedFunction diff --git a/lib/fizzy/parser.cpp b/lib/fizzy/parser.cpp index 9f73219ed6..e25d55c448 100644 --- a/lib/fizzy/parser.cpp +++ b/lib/fizzy/parser.cpp @@ -430,14 +430,14 @@ inline parser_result parse(const uint8_t* pos, const uint8_t* end) return {{offset, std::move(init)}, pos}; } -Module parse(bytes_view input) +std::unique_ptr parse(bytes_view input) { if (input.substr(0, wasm_prefix.size()) != wasm_prefix) throw parser_error{"invalid wasm module prefix"}; input.remove_prefix(wasm_prefix.size()); - Module module; + auto module{std::make_unique()}; std::vector code_binaries; SectionId last_id = SectionId::custom; for (auto it = input.begin(); it != input.end();) @@ -460,37 +460,37 @@ Module parse(bytes_view input) switch (id) { case SectionId::type: - std::tie(module.typesec, it) = parse_vec(it, input.end()); + std::tie(module->typesec, it) = parse_vec(it, input.end()); break; case SectionId::import: - std::tie(module.importsec, it) = parse_vec(it, input.end()); + std::tie(module->importsec, it) = parse_vec(it, input.end()); break; case SectionId::function: - std::tie(module.funcsec, it) = parse_vec(it, input.end()); + std::tie(module->funcsec, it) = parse_vec(it, input.end()); break; case SectionId::table: - std::tie(module.tablesec, it) = parse_vec(it, input.end()); + std::tie(module->tablesec, it) = parse_vec
(it, input.end()); break; case SectionId::memory: - std::tie(module.memorysec, it) = parse_vec(it, input.end()); + std::tie(module->memorysec, it) = parse_vec(it, input.end()); break; case SectionId::global: - std::tie(module.globalsec, it) = parse_vec(it, input.end()); + std::tie(module->globalsec, it) = parse_vec(it, input.end()); break; case SectionId::export_: - std::tie(module.exportsec, it) = parse_vec(it, input.end()); + std::tie(module->exportsec, it) = parse_vec(it, input.end()); break; case SectionId::start: - std::tie(module.startfunc, it) = leb128u_decode(it, input.end()); + std::tie(module->startfunc, it) = leb128u_decode(it, input.end()); break; case SectionId::element: - std::tie(module.elementsec, it) = parse_vec(it, input.end()); + std::tie(module->elementsec, it) = parse_vec(it, input.end()); break; case SectionId::code: std::tie(code_binaries, it) = parse_vec(it, input.end()); break; case SectionId::data: - std::tie(module.datasec, it) = parse_vec(it, input.end()); + std::tie(module->datasec, it) = parse_vec(it, input.end()); break; case SectionId::custom: // NOTE: this section can be ignored, but the name must be parseable (and valid UTF-8) @@ -513,80 +513,80 @@ Module parse(bytes_view input) // Validation checks // Split imports by kind - for (const auto& import : module.importsec) + for (const auto& import : module->importsec) { switch (import.kind) { case ExternalKind::Function: - if (import.desc.function_type_index >= module.typesec.size()) + if (import.desc.function_type_index >= module->typesec.size()) throw validation_error{"invalid type index of an imported function"}; - module.imported_function_types.emplace_back( - module.typesec[import.desc.function_type_index]); + module->imported_function_types.emplace_back( + module->typesec[import.desc.function_type_index]); break; case ExternalKind::Table: - module.imported_table_types.emplace_back(import.desc.table); + module->imported_table_types.emplace_back(import.desc.table); break; case ExternalKind::Memory: - module.imported_memory_types.emplace_back(import.desc.memory); + module->imported_memory_types.emplace_back(import.desc.memory); break; case ExternalKind::Global: - module.imported_global_types.emplace_back(import.desc.global); + module->imported_global_types.emplace_back(import.desc.global); break; default: assert(false); } } - for (const auto type_idx : module.funcsec) + for (const auto type_idx : module->funcsec) { - if (type_idx >= module.typesec.size()) + if (type_idx >= module->typesec.size()) throw validation_error{"invalid function type index"}; } - if (module.tablesec.size() > 1) + if (module->tablesec.size() > 1) throw validation_error{"too many table sections (at most one is allowed)"}; - if (module.memorysec.size() > 1) + if (module->memorysec.size() > 1) throw validation_error{"too many memory sections (at most one is allowed)"}; - if (module.imported_memory_types.size() > 1) + if (module->imported_memory_types.size() > 1) throw validation_error{"too many imported memories (at most one is allowed)"}; - if (!module.memorysec.empty() && !module.imported_memory_types.empty()) + if (!module->memorysec.empty() && !module->imported_memory_types.empty()) { throw validation_error{ "both module memory and imported memory are defined (at most one of them is allowed)"}; } - if (!module.datasec.empty() && !module.has_memory()) + if (!module->datasec.empty() && !module->has_memory()) throw validation_error{"data section encountered without a memory section"}; - for (const auto& data : module.datasec) + for (const auto& data : module->datasec) { // Offset expression is required to have i32 result value // https://webassembly.github.io/spec/core/valid/modules.html#data-segments - validate_constant_expression(data.offset, module, ValType::i32); + validate_constant_expression(data.offset, *module, ValType::i32); } - if (module.imported_table_types.size() > 1) + if (module->imported_table_types.size() > 1) throw validation_error{"too many imported tables (at most one is allowed)"}; - if (!module.tablesec.empty() && !module.imported_table_types.empty()) + if (!module->tablesec.empty() && !module->imported_table_types.empty()) { throw validation_error{ "both module table and imported table are defined (at most one of them is allowed)"}; } - if (!module.elementsec.empty() && !module.has_table()) + if (!module->elementsec.empty() && !module->has_table()) throw validation_error{"element section encountered without a table section"}; - const auto total_func_count = module.get_function_count(); + const auto total_func_count = module->get_function_count(); - for (const auto& element : module.elementsec) + for (const auto& element : module->elementsec) { // Offset expression is required to have i32 result value // https://webassembly.github.io/spec/core/valid/modules.html#element-segments - validate_constant_expression(element.offset, module, ValType::i32); + validate_constant_expression(element.offset, *module, ValType::i32); for (const auto func_idx : element.init) { if (func_idx >= total_func_count) @@ -594,15 +594,15 @@ Module parse(bytes_view input) } } - const auto total_global_count = module.get_global_count(); - for (const auto& global : module.globalsec) + const auto total_global_count = module->get_global_count(); + for (const auto& global : module->globalsec) { - validate_constant_expression(global.expression, module, global.type.value_type); + validate_constant_expression(global.expression, *module, global.type.value_type); // Wasm spec section 3.3.7 constrains initialization by another global to const imports only // https://webassembly.github.io/spec/core/valid/instructions.html#expressions if (global.expression.kind == ConstantExpression::Kind::GlobalGet && - global.expression.value.global_index >= module.imported_global_types.size()) + global.expression.value.global_index >= module->imported_global_types.size()) { throw validation_error{ "global can be initialized by another const global only if it's imported"}; @@ -610,12 +610,12 @@ Module parse(bytes_view input) } - if (module.funcsec.size() != code_binaries.size()) + if (module->funcsec.size() != code_binaries.size()) throw parser_error{"malformed binary: number of function and code entries must match"}; // Validate exports. std::unordered_set export_names; - for (const auto& export_ : module.exportsec) + for (const auto& export_ : module->exportsec) { switch (export_.kind) { @@ -624,11 +624,11 @@ Module parse(bytes_view input) throw validation_error{"invalid index of an exported function"}; break; case ExternalKind::Table: - if (export_.index != 0 || !module.has_table()) + if (export_.index != 0 || !module->has_table()) throw validation_error{"invalid index of an exported table"}; break; case ExternalKind::Memory: - if (export_.index != 0 || !module.has_memory()) + if (export_.index != 0 || !module->has_memory()) throw validation_error{"invalid index of an exported memory"}; break; case ExternalKind::Global: @@ -642,20 +642,21 @@ Module parse(bytes_view input) throw validation_error{"duplicate export name " + export_.name}; } - if (module.startfunc) + if (module->startfunc) { - if (*module.startfunc >= total_func_count) + if (*module->startfunc >= total_func_count) throw validation_error{"invalid start function index"}; - const auto& func_type = module.get_function_type(*module.startfunc); + const auto& func_type = module->get_function_type(*module->startfunc); if (!func_type.inputs.empty() || !func_type.outputs.empty()) throw validation_error{"invalid start function type"}; } // Process code. TODO: This can be done lazily. - module.codesec.reserve(code_binaries.size()); + module->codesec.reserve(code_binaries.size()); for (size_t i = 0; i < code_binaries.size(); ++i) - module.codesec.emplace_back(parse_code(code_binaries[i], static_cast(i), module)); + module->codesec.emplace_back( + parse_code(code_binaries[i], static_cast(i), *module)); return module; } diff --git a/lib/fizzy/parser.hpp b/lib/fizzy/parser.hpp index 03d562c7d2..8841265fd1 100644 --- a/lib/fizzy/parser.hpp +++ b/lib/fizzy/parser.hpp @@ -7,6 +7,7 @@ #include "exceptions.hpp" #include "leb128.hpp" #include "module.hpp" +#include namespace fizzy { @@ -16,7 +17,7 @@ constexpr bytes_view wasm_prefix{wasm_prefix_data, sizeof(wasm_prefix_data)}; template using parser_result = std::pair; -Module parse(bytes_view input); +std::unique_ptr parse(bytes_view input); inline parser_result parse_byte(const uint8_t* pos, const uint8_t* end) { diff --git a/test/spectests/spectests.cpp b/test/spectests/spectests.cpp index 96dfd0da7f..234eb127b1 100644 --- a/test/spectests/spectests.cpp +++ b/test/spectests/spectests.cpp @@ -117,9 +117,9 @@ class test_runner const auto wasm_binary = load_wasm_file(path, filename); try { - fizzy::Module module = fizzy::parse(wasm_binary); + auto module = fizzy::parse(wasm_binary); - auto [imports, error] = create_imports(module); + auto [imports, error] = create_imports(*module); if (!error.empty()) { fail(error); @@ -325,9 +325,9 @@ class test_runner const auto wasm_binary = load_wasm_file(path, filename); try { - fizzy::Module module = fizzy::parse(wasm_binary); + auto module = fizzy::parse(wasm_binary); - auto [imports, error] = create_imports(module); + auto [imports, error] = create_imports(*module); if (!error.empty()) { if (type == "assert_unlinkable") @@ -463,7 +463,7 @@ class test_runner return std::nullopt; const auto func_name = action.at("field").get(); - const auto func_idx = fizzy::find_exported_function(instance->module, func_name); + const auto func_idx = fizzy::find_exported_function(*instance->module, func_name); if (!func_idx.has_value()) { skip("Function '" + func_name + "' not found."); diff --git a/test/unittests/api_test.cpp b/test/unittests/api_test.cpp index f1a6fa58b0..955b366f84 100644 --- a/test/unittests/api_test.cpp +++ b/test/unittests/api_test.cpp @@ -89,7 +89,7 @@ TEST(api, resolve_imported_functions) }; const auto external_functions = - resolve_imported_functions(module, std::move(imported_functions)); + resolve_imported_functions(*module, std::move(imported_functions)); EXPECT_EQ(external_functions.size(), 4); @@ -112,7 +112,7 @@ TEST(api, resolve_imported_functions) }; const auto external_functions_reordered = - resolve_imported_functions(module, std::move(imported_functions_reordered)); + resolve_imported_functions(*module, std::move(imported_functions_reordered)); EXPECT_EQ(external_functions_reordered.size(), 4); auto instance_reordered = instantiate(module, external_functions_reordered, {}, {}, @@ -134,7 +134,7 @@ TEST(api, resolve_imported_functions) }; const auto external_functions_extra = - resolve_imported_functions(module, std::move(imported_functions_extra)); + resolve_imported_functions(*module, std::move(imported_functions_extra)); EXPECT_EQ(external_functions_extra.size(), 4); auto instance_extra = instantiate( @@ -152,7 +152,7 @@ TEST(api, resolve_imported_functions) {"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)}, }; - EXPECT_THROW_MESSAGE(resolve_imported_functions(module, std::move(imported_functions_missing)), + EXPECT_THROW_MESSAGE(resolve_imported_functions(*module, std::move(imported_functions_missing)), instantiate_error, "imported function mod2.foo2 is required"); @@ -164,7 +164,7 @@ TEST(api, resolve_imported_functions) }; EXPECT_THROW_MESSAGE( - resolve_imported_functions(module, std::move(imported_functions_invalid_type1)), + resolve_imported_functions(*module, std::move(imported_functions_invalid_type1)), instantiate_error, "function mod1.foo1 input types don't match imported function in module"); @@ -176,7 +176,7 @@ TEST(api, resolve_imported_functions) }; EXPECT_THROW_MESSAGE( - resolve_imported_functions(module, std::move(imported_functions_invalid_type2)), + resolve_imported_functions(*module, std::move(imported_functions_invalid_type2)), instantiate_error, "function mod2.foo2 has output but is defined void in module"); std::vector imported_functions_invalid_type3 = { @@ -187,7 +187,7 @@ TEST(api, resolve_imported_functions) }; EXPECT_THROW_MESSAGE( - resolve_imported_functions(module, std::move(imported_functions_invalid_type3)), + resolve_imported_functions(*module, std::move(imported_functions_invalid_type3)), instantiate_error, "function mod1.foo2 output type doesn't match imported function in module"); } diff --git a/test/unittests/end_to_end_test.cpp b/test/unittests/end_to_end_test.cpp index d6a5fe7a22..c303b6ce92 100644 --- a/test/unittests/end_to_end_test.cpp +++ b/test/unittests/end_to_end_test.cpp @@ -126,7 +126,7 @@ TEST(end_to_end, nested_loops_in_c) const auto module = parse(bin); - const auto func_idx = find_exported_function(module, "test"); + const auto func_idx = find_exported_function(*module, "test"); ASSERT_TRUE(func_idx); auto instance = instantiate(module); @@ -168,7 +168,7 @@ TEST(end_to_end, memset) const auto module = parse(wasm); - const auto func_idx = find_exported_function(module, "test"); + const auto func_idx = find_exported_function(*module, "test"); ASSERT_TRUE(func_idx); auto instance = instantiate(module); diff --git a/test/unittests/execute_call_test.cpp b/test/unittests/execute_call_test.cpp index b1fc21cda4..ac00914b93 100644 --- a/test/unittests/execute_call_test.cpp +++ b/test/unittests/execute_call_test.cpp @@ -105,7 +105,7 @@ TEST(execute_call, call_indirect) "0061736d01000000010e036000017f6000017e60017f017f03070600000001000204050170010505090b010041" "000b0502010003040a2106040041010b040041020b040041030b040042040b0300000b070020001100000b"); - const Module module = parse(bin); + const auto module = parse(bin); for (const auto param : {0u, 1u, 2u}) { @@ -146,7 +146,7 @@ TEST(execute_call, call_indirect_with_argument) "0061736d01000000010c0260027f7f017f60017f017f03050400000101040501700103030909010041000b0300" "01020a25040700200020016e0b0700200020016b0b0700200020006c0b0b00411f410720001100000b"); - const Module module = parse(bin); + const auto module = parse(bin); EXPECT_THAT(execute(module, 3, {0}), Result(31 / 7)); EXPECT_THAT(execute(module, 3, {1}), Result(31 - 7)); @@ -171,7 +171,7 @@ TEST(execute_call, call_indirect_imported_table) "0061736d01000000010a026000017f60017f017f020a01016d01740170010514030201010a0901070020001100" "000b"); - const Module module = parse(bin); + const auto module = parse(bin); auto f1 = [](Instance&, span, int) { return Value{1}; }; auto f2 = [](Instance&, span, int) { return Value{2}; }; @@ -224,7 +224,7 @@ TEST(execute_call, call_indirect_uninited_table) "0061736d01000000010a026000017f60017f017f030504000000010404017000050909010041000b030201000a" "1804040041010b040041020b040041030b070020001100000b"); - const Module module = parse(bin); + const auto module = parse(bin); // elements 3 and 4 are not initialized EXPECT_THAT(execute(module, 3, {3}), Traps()); @@ -273,7 +273,7 @@ TEST(execute_call, imported_function_call) const auto module = parse(wasm); constexpr auto host_foo = [](Instance&, span, int) { return Value{42}; }; - const auto host_foo_type = module.typesec[0]; + const auto host_foo_type = module->typesec[0]; auto instance = instantiate(module, {{host_foo, host_foo_type}}); @@ -300,7 +300,7 @@ TEST(execute_call, imported_function_call_with_arguments) auto host_foo = [](Instance&, span args, int) { return Value{as_uint32(args[0]) * 2}; }; - const auto host_foo_type = module.typesec[0]; + const auto host_foo_type = module->typesec[0]; auto instance = instantiate(module, {{host_foo, host_foo_type}}); @@ -337,9 +337,9 @@ TEST(execute_call, imported_functions_call_indirect) "00000b"); const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 2); - ASSERT_EQ(module.importsec.size(), 2); - ASSERT_EQ(module.codesec.size(), 2); + ASSERT_EQ(module->typesec.size(), 2); + ASSERT_EQ(module->importsec.size(), 2); + ASSERT_EQ(module->codesec.size(), 2); constexpr auto sqr = [](Instance&, span args, int) { const auto x = as_uint32(args[0]); @@ -350,7 +350,7 @@ TEST(execute_call, imported_functions_call_indirect) return Value{(11 + uint64_t{x} / 11) / 2}; }; - auto instance = instantiate(module, {{sqr, module.typesec[0]}, {isqrt, module.typesec[0]}}); + auto instance = instantiate(module, {{sqr, module->typesec[0]}, {isqrt, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 3, {0, 10}), Result(20)); // double(10) EXPECT_THAT(execute(*instance, 3, {1, 9}), Result(81)); // sqr(9) EXPECT_THAT(execute(*instance, 3, {2, 50}), Result(7)); // isqrt(50) @@ -388,14 +388,14 @@ TEST(execute_call, imported_function_from_another_module) "b"); const auto module2 = parse(bin2); - const auto func_idx = fizzy::find_exported_function(module1, "sub"); + const auto func_idx = fizzy::find_exported_function(*module1, "sub"); ASSERT_TRUE(func_idx.has_value()); auto sub = [&instance1, func_idx](Instance&, span args, int) -> ExecutionResult { return fizzy::execute(*instance1, *func_idx, args.data()); }; - auto instance2 = instantiate(module2, {{sub, module1.typesec[0]}}); + auto instance2 = instantiate(module2, {{sub, module1->typesec[0]}}); EXPECT_THAT(execute(*instance2, 1, {44, 2}), Result(42)); } @@ -495,7 +495,7 @@ TEST(execute_call, call_infinite_recursion) */ const auto bin = from_hex("0061736d01000000010401600000030201000a0601040010000b"); - const Module module = parse(bin); + const auto module = parse(bin); EXPECT_THAT(execute(module, 0, {}), Traps()); } @@ -513,7 +513,7 @@ TEST(execute_call, call_indirect_infinite_recursion) "0061736d010000000105016000017f03020100040501700101010907010041000b01000a090107004100110000" "0b"); - const Module module = parse(bin); + const auto module = parse(bin); EXPECT_TRUE(execute(module, 0, {}).trapped); } @@ -572,7 +572,7 @@ TEST(execute_call, call_imported_infinite_recursion) auto host_foo = [](Instance& instance, span, int depth) -> ExecutionResult { return execute(instance, 0, {}, depth + 1); }; - const auto host_foo_type = module.typesec[0]; + const auto host_foo_type = module->typesec[0]; auto instance = instantiate(module, {{host_foo, host_foo_type}}); @@ -635,10 +635,10 @@ TEST(execute_call, drop_call_result) "0a0d02050041b2020b050010001a0b"); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 2); - EXPECT_EQ(module.codesec[0].max_stack_height, 1); - EXPECT_EQ(module.codesec[1].max_stack_height, 1); - const auto func_idx = find_exported_function(module, "drop_call_result"); + ASSERT_EQ(module->codesec.size(), 2); + EXPECT_EQ(module->codesec[0].max_stack_height, 1); + EXPECT_EQ(module->codesec[1].max_stack_height, 1); + const auto func_idx = find_exported_function(*module, "drop_call_result"); auto instance = instantiate(module); EXPECT_THAT(fizzy::execute(*instance, *func_idx, {}), Result()); } diff --git a/test/unittests/execute_control_test.cpp b/test/unittests/execute_control_test.cpp index bbd7c63302..a0d34efd24 100644 --- a/test/unittests/execute_control_test.cpp +++ b/test/unittests/execute_control_test.cpp @@ -668,7 +668,7 @@ TEST(execute_control, br_1_out_of_function_and_imported_function) int) noexcept -> ExecutionResult { return Void; }; const auto module = parse(bin); - auto instance = instantiate(module, {{fake_imported_function, module.typesec[0]}}); + auto instance = instantiate(module, {{fake_imported_function, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 1, {}), Result(1)); } diff --git a/test/unittests/execute_numeric_test.cpp b/test/unittests/execute_numeric_test.cpp index 1d837316ba..191b5dfe54 100644 --- a/test/unittests/execute_numeric_test.cpp +++ b/test/unittests/execute_numeric_test.cpp @@ -16,22 +16,22 @@ namespace { ExecutionResult execute_unary_operation(Instr instr, uint64_t arg) { - Module module; + auto module{std::make_unique()}; // type is currently needed only to get arity of function, so exact value types don't matter - module.typesec.emplace_back(FuncType{{ValType::i32}, {ValType::i32}}); - module.funcsec.emplace_back(TypeIdx{0}); - module.codesec.emplace_back(Code{1, 0, {Instr::local_get, instr, Instr::end}, {0, 0, 0, 0}}); + module->typesec.emplace_back(FuncType{{ValType::i32}, {ValType::i32}}); + module->funcsec.emplace_back(TypeIdx{0}); + module->codesec.emplace_back(Code{1, 0, {Instr::local_get, instr, Instr::end}, {0, 0, 0, 0}}); return execute(module, 0, {arg}); } ExecutionResult execute_binary_operation(Instr instr, uint64_t lhs, uint64_t rhs) { - Module module; + auto module{std::make_unique()}; // type is currently needed only to get arity of function, so exact value types don't matter - module.typesec.emplace_back(FuncType{{ValType::i32, ValType::i32}, {ValType::i32}}); - module.funcsec.emplace_back(TypeIdx{0}); - module.codesec.emplace_back(Code{ + module->typesec.emplace_back(FuncType{{ValType::i32, ValType::i32}, {ValType::i32}}); + module->funcsec.emplace_back(TypeIdx{0}); + module->codesec.emplace_back(Code{ 2, 0, {Instr::local_get, Instr::local_get, instr, Instr::end}, {0, 0, 0, 0, 1, 0, 0, 0}}); return execute(module, 0, {lhs, rhs}); diff --git a/test/unittests/execute_test.cpp b/test/unittests/execute_test.cpp index 79b0b37b28..65620e6e10 100644 --- a/test/unittests/execute_test.cpp +++ b/test/unittests/execute_test.cpp @@ -380,11 +380,11 @@ TEST(execute, i32_load_all_variants) */ const auto wasm = from_hex("0061736d0100000001060160017f017f030201000504010101010a0901070020002802000b"); - auto module = parse(wasm); + const auto module = parse(wasm); - auto& load_instr = module.codesec[0].instructions[1]; + auto& load_instr = module->codesec[0].instructions[1]; ASSERT_EQ(load_instr, Instr::i32_load); - ASSERT_EQ(module.codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. + ASSERT_EQ(module->codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. const auto memory_fill = "deb0b1b2b3ed"_bytes; @@ -418,11 +418,11 @@ TEST(execute, i64_load_all_variants) */ const auto wasm = from_hex("0061736d0100000001060160017f017e030201000504010101010a0901070020002903000b"); - auto module = parse(wasm); + const auto module = parse(wasm); - auto& load_instr = module.codesec[0].instructions[1]; + auto& load_instr = module->codesec[0].instructions[1]; ASSERT_EQ(load_instr, Instr::i64_load); - ASSERT_EQ(module.codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. + ASSERT_EQ(module->codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. const auto memory_fill = "deb0b1b2b3b4b5b6b7ed"_bytes; @@ -529,11 +529,11 @@ TEST(execute, i32_store_all_variants) */ const auto wasm = from_hex("0061736d0100000001060160027f7f00030201000504010101010a0b010900200120003602000b"); - auto module = parse(wasm); + const auto module = parse(wasm); - auto& store_instr = module.codesec[0].instructions[2]; + auto& store_instr = module->codesec[0].instructions[2]; ASSERT_EQ(store_instr, Instr::i32_store); - ASSERT_EQ(module.codesec[0].immediates.substr(8), "00000000"_bytes); // store offset + ASSERT_EQ(module->codesec[0].immediates.substr(8), "00000000"_bytes); // store offset const std::tuple test_cases[]{ {Instr::i32_store8, "ccb0cccccccc"_bytes}, @@ -565,11 +565,11 @@ TEST(execute, i64_store_all_variants) */ const auto wasm = from_hex("0061736d0100000001060160027e7f00030201000504010101010a0b010900200120003703000b"); - auto module = parse(wasm); + const auto module = parse(wasm); - auto& store_instr = module.codesec[0].instructions[2]; + auto& store_instr = module->codesec[0].instructions[2]; ASSERT_EQ(store_instr, Instr::i64_store); - ASSERT_EQ(module.codesec[0].immediates.substr(8), "00000000"_bytes); // store offset + ASSERT_EQ(module->codesec[0].immediates.substr(8), "00000000"_bytes); // store offset const std::tuple test_cases[]{ {Instr::i64_store8, "ccb0cccccccccccccccc"_bytes}, @@ -774,13 +774,13 @@ TEST(execute, imported_function) */ const auto wasm = from_hex("0061736d0100000001070160027f7f017f020b01036d6f6403666f6f0000"); const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 1); + ASSERT_EQ(module->typesec.size(), 1); constexpr auto host_foo = [](Instance&, span args, int) { return Value{as_uint32(args[0]) + as_uint32(args[1])}; }; - auto instance = instantiate(module, {{host_foo, module.typesec[0]}}); + auto instance = instantiate(module, {{host_foo, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 0, {20, 22}), Result(42)); } @@ -794,7 +794,7 @@ TEST(execute, imported_two_functions) const auto wasm = from_hex( "0061736d0100000001070160027f7f017f021702036d6f6404666f6f310000036d6f6404666f6f320000"); const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 1); + ASSERT_EQ(module->typesec.size(), 1); constexpr auto host_foo1 = [](Instance&, span args, int) { return Value{as_uint32(args[0]) + as_uint32(args[1])}; @@ -804,7 +804,7 @@ TEST(execute, imported_two_functions) }; auto instance = - instantiate(module, {{host_foo1, module.typesec[0]}, {host_foo2, module.typesec[0]}}); + instantiate(module, {{host_foo1, module->typesec[0]}, {host_foo2, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 0, {20, 22}), Result(42)); EXPECT_THAT(execute(*instance, 1, {20, 22}), Result(440)); } @@ -831,9 +831,9 @@ TEST(execute, imported_functions_and_regular_one) }; const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 1); + ASSERT_EQ(module->typesec.size(), 1); auto instance = - instantiate(module, {{host_foo1, module.typesec[0]}, {host_foo2, module.typesec[0]}}); + instantiate(module, {{host_foo1, module->typesec[0]}, {host_foo2, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 0, {20, 22}), Result(42)); EXPECT_THAT(execute(*instance, 1, {20, 10}), Result(200)); } @@ -856,9 +856,9 @@ TEST(execute, imported_functions_count_args) }; const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 2); + ASSERT_EQ(module->typesec.size(), 2); auto instance_counter = - instantiate(module, {{count_args, module.typesec[0]}, {count_args, module.typesec[1]}}); + instantiate(module, {{count_args, module->typesec[0]}, {count_args, module->typesec[1]}}); EXPECT_THAT(execute(*instance_counter, 0, {20, 22}), Result(2)); EXPECT_THAT(execute(*instance_counter, 1, {20}), Result(1)); } @@ -886,9 +886,9 @@ TEST(execute, imported_two_functions_different_type) }; const auto module = parse(wasm); - ASSERT_EQ(module.typesec.size(), 2); + ASSERT_EQ(module->typesec.size(), 2); auto instance = - instantiate(module, {{host_foo1, module.typesec[0]}, {host_foo2, module.typesec[1]}}); + instantiate(module, {{host_foo1, module->typesec[0]}, {host_foo2, module->typesec[1]}}); EXPECT_THAT(execute(*instance, 0, {20, 22}), Result(42)); EXPECT_THAT(execute(*instance, 1, {0x3000'0000}), Result(0x900'0000'0000'0000)); @@ -907,7 +907,7 @@ TEST(execute, imported_function_traps) }; const auto module = parse(wasm); - auto instance = instantiate(module, {{host_foo, module.typesec[0]}}); + auto instance = instantiate(module, {{host_foo, module->typesec[0]}}); EXPECT_THAT(execute(*instance, 0, {20, 22}), Traps()); } diff --git a/test/unittests/instantiate_test.cpp b/test/unittests/instantiate_test.cpp index a31366f079..fcd6f5997c 100644 --- a/test/unittests/instantiate_test.cpp +++ b/test/unittests/instantiate_test.cpp @@ -32,7 +32,7 @@ TEST(instantiate, imported_functions) const auto module = parse(bin); auto host_foo = [](Instance&, span, int) { return Trap; }; - auto instance = instantiate(module, {{host_foo, module.typesec[0]}}); + auto instance = instantiate(module, {{host_foo, module->typesec[0]}}); ASSERT_EQ(instance->imported_functions.size(), 1); EXPECT_EQ(*instance->imported_functions[0].function.target(), host_foo); @@ -55,7 +55,7 @@ TEST(instantiate, imported_functions_multiple) auto host_foo1 = [](Instance&, span, int) { return Trap; }; auto host_foo2 = [](Instance&, span, int) { return Trap; }; auto instance = - instantiate(module, {{host_foo1, module.typesec[0]}, {host_foo2, module.typesec[1]}}); + instantiate(module, {{host_foo1, module->typesec[0]}, {host_foo2, module->typesec[1]}}); ASSERT_EQ(instance->imported_functions.size(), 2); EXPECT_EQ(*instance->imported_functions[0].function.target(), host_foo1); @@ -440,7 +440,7 @@ TEST(instantiate, imported_globals_nullptr) TEST(instantiate, memory_default) { - Module module; + auto module{std::make_unique()}; auto instance = instantiate(module); @@ -449,8 +449,8 @@ TEST(instantiate, memory_default) TEST(instantiate, memory_single) { - Module module; - module.memorysec.emplace_back(Memory{{1, 1}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{1, 1}}); auto instance = instantiate(module); @@ -462,8 +462,8 @@ TEST(instantiate, memory_single) TEST(instantiate, memory_single_unspecified_maximum) { - Module module; - module.memorysec.emplace_back(Memory{{1, std::nullopt}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{1, std::nullopt}}); auto instance = instantiate(module); @@ -474,8 +474,8 @@ TEST(instantiate, memory_single_unspecified_maximum) TEST(instantiate, memory_single_large_minimum) { - Module module; - module.memorysec.emplace_back(Memory{{(1024 * 1024 * 1024) / PageSize, std::nullopt}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{(1024 * 1024 * 1024) / PageSize, std::nullopt}}); EXPECT_THROW_MESSAGE(instantiate(module), instantiate_error, "cannot exceed hard memory limit of 268435456 bytes"); @@ -483,8 +483,8 @@ TEST(instantiate, memory_single_large_minimum) TEST(instantiate, memory_single_large_maximum) { - Module module; - module.memorysec.emplace_back(Memory{{1, (1024 * 1024 * 1024) / PageSize}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{1, (1024 * 1024 * 1024) / PageSize}}); EXPECT_THROW_MESSAGE(instantiate(module), instantiate_error, "cannot exceed hard memory limit of 268435456 bytes"); @@ -626,11 +626,11 @@ TEST(instantiate, element_section_offset_from_imported_global) TEST(instantiate, element_section_offset_too_large) { - Module module; - module.tablesec.emplace_back(Table{{3, std::nullopt}}); - module.elementsec.emplace_back( + auto module{std::make_unique()}; + module->tablesec.emplace_back(Table{{3, std::nullopt}}); + module->elementsec.emplace_back( Element{{ConstantExpression::Kind::Constant, {1}}, {0xaa, 0xff}}); - module.elementsec.emplace_back( + module->elementsec.emplace_back( Element{{ConstantExpression::Kind::Constant, {2}}, {0x55, 0x55}}); EXPECT_THROW_MESSAGE( @@ -680,7 +680,7 @@ TEST(instantiate, element_section_out_of_bounds_doesnt_change_imported_table) const auto bin = from_hex( "0061736d010000000105016000017f020b01016d037461620170000303020100090f020041000b020000004102" "0b0200000a0601040041010b"); - Module module = parse(bin); + const auto module = parse(bin); auto f0 = [](Instance&, span, int) { return Value{0}; }; @@ -698,12 +698,12 @@ TEST(instantiate, element_section_out_of_bounds_doesnt_change_imported_table) TEST(instantiate, data_section) { - Module module; - module.memorysec.emplace_back(Memory{{1, 1}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{1, 1}}); // Memory contents: 0, 0xaa, 0xff, 0, ... - module.datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {1}}, {0xaa, 0xff}}); + module->datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {1}}, {0xaa, 0xff}}); // Memory contents: 0, 0xaa, 0x55, 0x55, 0, ... - module.datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {2}}, {0x55, 0x55}}); + module->datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {2}}, {0x55, 0x55}}); auto instance = instantiate(module); @@ -712,12 +712,12 @@ TEST(instantiate, data_section) TEST(instantiate, data_section_offset_from_global) { - Module module; - module.memorysec.emplace_back(Memory{{1, 1}}); - module.globalsec.emplace_back( + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{1, 1}}); + module->globalsec.emplace_back( Global{{ValType::i32, false}, {ConstantExpression::Kind::Constant, {42}}}); // Memory contents: 0, 0xaa, 0xff, 0, ... - module.datasec.emplace_back(Data{{ConstantExpression::Kind::GlobalGet, {0}}, {0xaa, 0xff}}); + module->datasec.emplace_back(Data{{ConstantExpression::Kind::GlobalGet, {0}}, {0xaa, 0xff}}); auto instance = instantiate(module); @@ -745,10 +745,10 @@ TEST(instantiate, data_section_offset_from_imported_global) TEST(instantiate, data_section_offset_too_large) { - Module module; - module.memorysec.emplace_back(Memory{{0, 1}}); + auto module{std::make_unique()}; + module->memorysec.emplace_back(Memory{{0, 1}}); // Memory contents: 0, 0xaa, 0xff, 0, ... - module.datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {1}}, {0xaa, 0xff}}); + module->datasec.emplace_back(Data{{ConstantExpression::Kind::Constant, {1}}, {0xaa, 0xff}}); EXPECT_THROW_MESSAGE( instantiate(module), instantiate_error, "data segment is out of memory bounds"); @@ -782,7 +782,7 @@ TEST(instantiate, data_section_out_of_bounds_doesnt_change_imported_memory) */ const auto bin = from_hex("0061736d01000000020a01016d036d656d0200010b0f020041000b016100418080040b0161"); - Module module = parse(bin); + const auto module = parse(bin); bytes memory(PageSize, 0); EXPECT_THROW_MESSAGE(instantiate(module, {}, {}, {{&memory, {1, 1}}}), instantiate_error, @@ -806,7 +806,7 @@ TEST(instantiate, data_elem_section_errors_dont_change_imports) const auto bin_data_error = from_hex( "0061736d010000000105016000017f021402016d0374616201700003016d036d656d0200010302010009080100" "41000b0200000a0601040041010b0b0f020041000b016100418080040b0161"); - Module module_data_error = parse(bin_data_error); + const auto module_data_error = parse(bin_data_error); table_elements table(3); bytes memory(PageSize, 0); @@ -831,7 +831,7 @@ TEST(instantiate, data_elem_section_errors_dont_change_imports) const auto bin_elem_error = from_hex( "0061736d010000000105016000017f021402016d0374616201700003016d036d656d02000103020100090f0200" "41000b0200000041020b0200000a0601040041010b0b07010041000b0161"); - Module module_elem_error = parse(bin_elem_error); + const auto module_elem_error = parse(bin_elem_error); EXPECT_THROW_MESSAGE( instantiate(module_elem_error, {}, {{&table, {3, std::nullopt}}}, {{&memory, {1, 1}}}), @@ -845,8 +845,8 @@ TEST(instantiate, data_elem_section_errors_dont_change_imports) TEST(instantiate, globals_single) { - Module module; - module.globalsec.emplace_back( + auto module{std::make_unique()}; + module->globalsec.emplace_back( Global{{ValType::i32, true}, {ConstantExpression::Kind::Constant, {42}}}); auto instance = instantiate(module); @@ -857,10 +857,10 @@ TEST(instantiate, globals_single) TEST(instantiate, globals_multiple) { - Module module; - module.globalsec.emplace_back( + auto module{std::make_unique()}; + module->globalsec.emplace_back( Global{{ValType::i32, true}, {ConstantExpression::Kind::Constant, {42}}}); - module.globalsec.emplace_back( + module->globalsec.emplace_back( Global{{ValType::i32, false}, {ConstantExpression::Kind::Constant, {43}}}); auto instance = instantiate(module); diff --git a/test/unittests/module_test.cpp b/test/unittests/module_test.cpp index 93dfd896e7..276a02f323 100644 --- a/test/unittests/module_test.cpp +++ b/test/unittests/module_test.cpp @@ -23,19 +23,19 @@ TEST(module, functions) "110302000b0401017f0b070043000000000b"); const auto module = parse(bin); - ASSERT_EQ(module.get_function_count(), 4); + ASSERT_EQ(module->get_function_count(), 4); EXPECT_EQ( - module.get_function_type(0), (FuncType{{ValType::i32, ValType::i32}, {ValType::i32}})); - EXPECT_EQ(module.get_function_type(1), (FuncType{})); - EXPECT_EQ(module.get_function_type(2), (FuncType{{ValType::i64}, {}})); - EXPECT_EQ(module.get_function_type(3), (FuncType{{}, {ValType::f32}})); - - EXPECT_EQ(module.get_code(1).instructions.size(), 1); - EXPECT_EQ(module.get_code(1).local_count, 0); - EXPECT_EQ(module.get_code(2).instructions.size(), 1); - EXPECT_EQ(module.get_code(2).local_count, 1); - EXPECT_EQ(module.get_code(3).instructions.size(), 2); - EXPECT_EQ(module.get_code(3).local_count, 0); + module->get_function_type(0), (FuncType{{ValType::i32, ValType::i32}, {ValType::i32}})); + EXPECT_EQ(module->get_function_type(1), (FuncType{})); + EXPECT_EQ(module->get_function_type(2), (FuncType{{ValType::i64}, {}})); + EXPECT_EQ(module->get_function_type(3), (FuncType{{}, {ValType::f32}})); + + EXPECT_EQ(module->get_code(1).instructions.size(), 1); + EXPECT_EQ(module->get_code(1).local_count, 0); + EXPECT_EQ(module->get_code(2).instructions.size(), 1); + EXPECT_EQ(module->get_code(2).local_count, 1); + EXPECT_EQ(module->get_code(3).instructions.size(), 2); + EXPECT_EQ(module->get_code(3).local_count, 0); } TEST(module, globals) @@ -51,15 +51,15 @@ TEST(module, globals) "0000f03f0b"); const auto module = parse(bin); - ASSERT_EQ(module.get_global_count(), 4); - EXPECT_EQ(module.get_global_type(0).value_type, ValType::i32); - EXPECT_TRUE(module.get_global_type(0).is_mutable); - EXPECT_EQ(module.get_global_type(1).value_type, ValType::i64); - EXPECT_FALSE(module.get_global_type(1).is_mutable); - EXPECT_EQ(module.get_global_type(2).value_type, ValType::f32); - EXPECT_FALSE(module.get_global_type(2).is_mutable); - EXPECT_EQ(module.get_global_type(3).value_type, ValType::f64); - EXPECT_TRUE(module.get_global_type(3).is_mutable); + ASSERT_EQ(module->get_global_count(), 4); + EXPECT_EQ(module->get_global_type(0).value_type, ValType::i32); + EXPECT_TRUE(module->get_global_type(0).is_mutable); + EXPECT_EQ(module->get_global_type(1).value_type, ValType::i64); + EXPECT_FALSE(module->get_global_type(1).is_mutable); + EXPECT_EQ(module->get_global_type(2).value_type, ValType::f32); + EXPECT_FALSE(module->get_global_type(2).is_mutable); + EXPECT_EQ(module->get_global_type(3).value_type, ValType::f64); + EXPECT_TRUE(module->get_global_type(3).is_mutable); } TEST(module, table) @@ -70,7 +70,7 @@ TEST(module, table) const auto bin1 = from_hex("0061736d01000000040401700001"); const auto module1 = parse(bin1); - EXPECT_TRUE(module1.has_table()); + EXPECT_TRUE(module1->has_table()); /* wat2wasm (table (import "m" "t") 1 funcref) @@ -78,7 +78,7 @@ TEST(module, table) const auto bin2 = from_hex("0061736d01000000020901016d017401700001"); const auto module2 = parse(bin2); - EXPECT_TRUE(module2.has_table()); + EXPECT_TRUE(module2->has_table()); /* wat2wasm (module) @@ -86,7 +86,7 @@ TEST(module, table) const auto bin3 = from_hex("0061736d01000000"); const auto module3 = parse(bin3); - EXPECT_FALSE(module3.has_table()); + EXPECT_FALSE(module3->has_table()); } TEST(module, memory) @@ -97,7 +97,7 @@ TEST(module, memory) const auto bin1 = from_hex("0061736d010000000503010001"); const auto module1 = parse(bin1); - EXPECT_TRUE(module1.has_memory()); + EXPECT_TRUE(module1->has_memory()); /* wat2wasm (memory (import "m" "m") 1) @@ -105,7 +105,7 @@ TEST(module, memory) const auto bin2 = from_hex("0061736d01000000020801016d016d020001"); const auto module2 = parse(bin2); - EXPECT_TRUE(module2.has_memory()); + EXPECT_TRUE(module2->has_memory()); /* wat2wasm (module) @@ -113,5 +113,5 @@ TEST(module, memory) const auto bin3 = from_hex("0061736d01000000"); const auto module3 = parse(bin3); - EXPECT_FALSE(module3.has_memory()); + EXPECT_FALSE(module3->has_memory()); } diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index cd25b312be..eeedae62e8 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -99,9 +99,9 @@ TEST(parser_expr, loop_br) const auto wasm = from_hex("0061736d01000000010401600000030201000a0901070003400c000b0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].instructions, + EXPECT_EQ(module->codesec[0].instructions, (std::vector{Instr::loop, Instr::br, Instr::end, Instr::end})); - EXPECT_EQ(module.codesec[0].immediates, + EXPECT_EQ(module->codesec[0].immediates, "00000000" // code_offset "00000000" // imm_offset "00000000" // stack_drop @@ -118,10 +118,10 @@ TEST(parser_expr, loop_br) from_hex("0061736d01000000010401600000030201000a0c010a00410003400c000b1a0b"); const auto module_parent_stack = parse(wasm_parent_stack); - EXPECT_EQ(module_parent_stack.codesec[0].instructions, + EXPECT_EQ(module_parent_stack->codesec[0].instructions, (std::vector{ Instr::i32_const, Instr::loop, Instr::br, Instr::end, Instr::drop, Instr::end})); - EXPECT_EQ(module_parent_stack.codesec[0].immediates, + EXPECT_EQ(module_parent_stack->codesec[0].immediates, "00000000" // i32.const "00000000" // arity "01000000" // code_offset @@ -141,10 +141,10 @@ TEST(parser_expr, loop_br) from_hex("0061736d01000000010401600000030201000a0c010a00037f41000c000b1a0b"); const auto module_arity = parse(wasm_arity); - EXPECT_EQ( - module_arity.codesec[0].instructions, (std::vector{Instr::loop, Instr::i32_const, Instr::br, - Instr::end, Instr::drop, Instr::end})); - EXPECT_EQ(module_arity.codesec[0].immediates, + EXPECT_EQ(module_arity->codesec[0].instructions, + (std::vector{ + Instr::loop, Instr::i32_const, Instr::br, Instr::end, Instr::drop, Instr::end})); + EXPECT_EQ(module_arity->codesec[0].immediates, "00000000" // i32.const "00000000" // arity - always 0 for loop "00000000" // code_offset @@ -160,9 +160,9 @@ TEST(parser_expr, loop_return) const auto wasm = from_hex("0061736d01000000010401600000030201000a0801060003400f0b0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].instructions, + EXPECT_EQ(module->codesec[0].instructions, (std::vector{Instr::loop, Instr::return_, Instr::end, Instr::end})); - EXPECT_EQ(module.codesec[0].immediates, + EXPECT_EQ(module->codesec[0].immediates, "00000000" // arity "03000000" // code_offset "10000000" // imm_offset @@ -212,10 +212,10 @@ TEST(parser_expr, block_br) from_hex("0061736d01000000010401600000030201000a0c010a00410002400c000b1a0b"); const auto module_parent_stack = parse(wasm_parent_stack); - EXPECT_EQ(module_parent_stack.codesec[0].instructions, + EXPECT_EQ(module_parent_stack->codesec[0].instructions, (std::vector{ Instr::i32_const, Instr::block, Instr::br, Instr::end, Instr::drop, Instr::end})); - EXPECT_EQ(module_parent_stack.codesec[0].immediates, + EXPECT_EQ(module_parent_stack->codesec[0].immediates, "00000000" // i32.const "00000000" // arity "04000000" // code_offset @@ -235,10 +235,10 @@ TEST(parser_expr, block_br) from_hex("0061736d01000000010401600000030201000a0c010a00027f41000c000b1a0b"); const auto module_arity = parse(wasm_arity); - EXPECT_EQ( - module_arity.codesec[0].instructions, (std::vector{Instr::block, Instr::i32_const, - Instr::br, Instr::end, Instr::drop, Instr::end})); - EXPECT_EQ(module_arity.codesec[0].immediates, + EXPECT_EQ(module_arity->codesec[0].instructions, + (std::vector{ + Instr::block, Instr::i32_const, Instr::br, Instr::end, Instr::drop, Instr::end})); + EXPECT_EQ(module_arity->codesec[0].immediates, "00000000" // i32.const "01000000" // arity "04000000" // code_offset @@ -254,9 +254,9 @@ TEST(parser_expr, block_return) const auto wasm = from_hex("0061736d01000000010401600000030201000a0801060002400f0b0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].instructions, + EXPECT_EQ(module->codesec[0].instructions, (std::vector{Instr::block, Instr::return_, Instr::end, Instr::end})); - EXPECT_EQ(module.codesec[0].immediates, + EXPECT_EQ(module->codesec[0].immediates, "00000000" // arity "03000000" // code_offset "10000000" // imm_offset @@ -274,9 +274,9 @@ TEST(parser_expr, if_br) const auto wasm = from_hex("0061736d01000000010401600000030201000a0b010900410004400c000b0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].instructions, + EXPECT_EQ(module->codesec[0].instructions, (std::vector{Instr::i32_const, Instr::if_, Instr::br, Instr::end, Instr::end})); - EXPECT_EQ(module.codesec[0].immediates, + EXPECT_EQ(module->codesec[0].immediates, "00000000" // i32.const "04000000" // else code offset "1c000000" // else imm offset @@ -297,10 +297,10 @@ TEST(parser_expr, if_br) from_hex("0061736d01000000010401600000030201000a0e010c004100410004400c000b1a0b"); const auto module_parent_stack = parse(wasm_parent_stack); - EXPECT_EQ(module_parent_stack.codesec[0].instructions, + EXPECT_EQ(module_parent_stack->codesec[0].instructions, (std::vector{Instr::i32_const, Instr::i32_const, Instr::if_, Instr::br, Instr::end, Instr::drop, Instr::end})); - EXPECT_EQ(module_parent_stack.codesec[0].immediates, + EXPECT_EQ(module_parent_stack->codesec[0].immediates, "00000000" // i32.const "00000000" // i32.const "05000000" // else code offset @@ -339,8 +339,8 @@ TEST(parser_expr, instr_br_table) "e3000f0b41e4000f0b41e5000f0b41e6000f0b41e7000f0b41e8000b"); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 1); - const auto& code = module.codesec[0]; + ASSERT_EQ(module->codesec.size(), 1); + const auto& code = module->codesec[0]; EXPECT_EQ(code.instructions, (std::vector{Instr::block, Instr::block, Instr::block, Instr::block, Instr::block, @@ -401,8 +401,8 @@ TEST(parser_expr, instr_br_table_empty_vector) "0061736d0100000001060160017f017f030201000a13011100024020000e000041e3000f0b41e4000b"); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 1); - const auto& code = module.codesec[0]; + ASSERT_EQ(module->codesec.size(), 1); + const auto& code = module->codesec[0]; EXPECT_EQ(code.instructions, (std::vector{Instr::block, Instr::local_get, Instr::br_table, Instr::i32_const, @@ -575,9 +575,9 @@ TEST(parser_expr, call_0args_1result) from_hex("0061736d010000000105016000017f03030200000a0b02040041000b040010000b"); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 2); - EXPECT_EQ(module.codesec[0].max_stack_height, 1); - EXPECT_EQ(module.codesec[1].max_stack_height, 1); + ASSERT_EQ(module->codesec.size(), 2); + EXPECT_EQ(module->codesec[0].max_stack_height, 1); + EXPECT_EQ(module->codesec[1].max_stack_height, 1); } TEST(parser_expr, call_1arg_1result) @@ -590,9 +590,9 @@ TEST(parser_expr, call_1arg_1result) "0061736d01000000010a0260017f017f6000017f03030200010a0d02040020000b0600410010000b"); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 2); - EXPECT_EQ(module.codesec[0].max_stack_height, 1); - EXPECT_EQ(module.codesec[1].max_stack_height, 1); + ASSERT_EQ(module->codesec.size(), 2); + EXPECT_EQ(module->codesec[0].max_stack_height, 1); + EXPECT_EQ(module->codesec[1].max_stack_height, 1); } TEST(parser_expr, call_nonexisting_typeidx) { diff --git a/test/unittests/parser_test.cpp b/test/unittests/parser_test.cpp index 9cb713abb3..008fb7313d 100644 --- a/test/unittests/parser_test.cpp +++ b/test/unittests/parser_test.cpp @@ -37,13 +37,13 @@ TEST(parser, valtype) auto& valtype_bin = wasm_bin.back(); valtype_bin = 0x7e; - EXPECT_EQ(parse(wasm_bin).typesec.front().outputs.front(), ValType::i64); + EXPECT_EQ(parse(wasm_bin)->typesec.front().outputs.front(), ValType::i64); valtype_bin = 0x7f; - EXPECT_EQ(parse(wasm_bin).typesec.front().outputs.front(), ValType::i32); + EXPECT_EQ(parse(wasm_bin)->typesec.front().outputs.front(), ValType::i32); valtype_bin = 0x7c; - EXPECT_EQ(parse(wasm_bin).typesec.front().outputs.front(), ValType::f64); + EXPECT_EQ(parse(wasm_bin)->typesec.front().outputs.front(), ValType::f64); valtype_bin = 0x7d; - EXPECT_EQ(parse(wasm_bin).typesec.front().outputs.front(), ValType::f32); + EXPECT_EQ(parse(wasm_bin)->typesec.front().outputs.front(), ValType::f32); valtype_bin = 0x7a; EXPECT_THROW_MESSAGE(parse(wasm_bin), parser_error, "invalid valtype 122"); } @@ -60,7 +60,7 @@ TEST(parser, limits_min) { const auto wasm = bytes{wasm_prefix} + make_section(5, make_vec({"007f"_bytes})); const auto module = parse(wasm); - const auto& limits = module.memorysec[0].limits; + const auto& limits = module->memorysec[0].limits; EXPECT_EQ(limits.min, 0x7f); EXPECT_FALSE(limits.max.has_value()); } @@ -69,7 +69,7 @@ TEST(parser, limits_minmax) { const auto wasm = bytes{wasm_prefix} + make_section(5, make_vec({"01207f"_bytes})); const auto module = parse(wasm); - const auto& limits = module.memorysec[0].limits; + const auto& limits = module->memorysec[0].limits; EXPECT_EQ(limits.min, 0x20); EXPECT_TRUE(limits.max.has_value()); EXPECT_EQ(*limits.max, 0x7f); @@ -96,9 +96,9 @@ TEST(parser, limits_invalid) TEST(parser, module_empty) { const auto module = parse(wasm_prefix); - EXPECT_EQ(module.typesec.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, module_with_wrong_prefix) @@ -126,9 +126,9 @@ TEST(parser, custom_section_empty) // Section consists of an empty name const auto bin = bytes{wasm_prefix} + make_section(0, "00"_bytes); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, custom_section_nonempty_name_only) @@ -136,9 +136,9 @@ TEST(parser, custom_section_nonempty_name_only) // Section consists of only the name "abc" const auto bin = bytes{wasm_prefix} + make_section(0, "03616263"_bytes); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, custom_section_name_not_ascii) @@ -146,9 +146,9 @@ TEST(parser, custom_section_name_not_ascii) // Section consists of only the name with some non-ascii characters. const auto bin = bytes{wasm_prefix} + make_section(0, "0670617765c582"_bytes); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, custom_section_nonempty) @@ -157,9 +157,9 @@ TEST(parser, custom_section_nonempty) const auto bin = bytes{wasm_prefix} + make_section(0, "036162630000112233445566778899000099"_bytes); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, custom_section_size_out_of_bounds) @@ -197,7 +197,7 @@ TEST(parser, type_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(1, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 0); + EXPECT_EQ(module->typesec.size(), 0); } TEST(parser, type_section_wrong_prefix) @@ -235,12 +235,12 @@ TEST(parser, type_section_with_single_functype) const auto section_contents = make_vec({make_functype({}, {})}); const auto bin = bytes{wasm_prefix} + make_section(1, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.typesec.size(), 1); - const auto functype = module.typesec[0]; + ASSERT_EQ(module->typesec.size(), 1); + const auto functype = module->typesec[0]; EXPECT_EQ(functype.inputs.size(), 0); EXPECT_EQ(functype.outputs.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, type_section_with_single_functype_params) @@ -249,16 +249,16 @@ TEST(parser, type_section_with_single_functype_params) const auto section_contents = make_vec({make_functype({i32, i64, i32}, {i32})}); const auto bin = bytes{wasm_prefix} + make_section(1, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.typesec.size(), 1); - const auto functype = module.typesec[0]; + ASSERT_EQ(module->typesec.size(), 1); + const auto functype = module->typesec[0]; ASSERT_EQ(functype.inputs.size(), 3); EXPECT_EQ(functype.inputs[0], ValType::i32); EXPECT_EQ(functype.inputs[1], ValType::i64); EXPECT_EQ(functype.inputs[2], ValType::i32); ASSERT_EQ(functype.outputs.size(), 1); EXPECT_EQ(functype.outputs[0], ValType::i32); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, type_section_with_multiple_functypes) @@ -271,22 +271,22 @@ TEST(parser, type_section_with_multiple_functypes) const auto bin = bytes{wasm_prefix} + make_section(1, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.typesec.size(), 3); - const auto functype0 = module.typesec[0]; + ASSERT_EQ(module->typesec.size(), 3); + const auto functype0 = module->typesec[0]; EXPECT_EQ(functype0.inputs.size(), 0); EXPECT_EQ(functype0.outputs.size(), 0); - const auto functype1 = module.typesec[1]; + const auto functype1 = module->typesec[1]; EXPECT_EQ(functype1.inputs.size(), 2); EXPECT_EQ(functype1.inputs[0], ValType::i32); EXPECT_EQ(functype1.inputs[1], ValType::i64); EXPECT_EQ(functype1.outputs.size(), 1); EXPECT_EQ(functype1.outputs[0], ValType::i32); - const auto functype2 = module.typesec[2]; + const auto functype2 = module->typesec[2]; EXPECT_EQ(functype2.inputs.size(), 1); EXPECT_EQ(functype2.inputs[0], ValType::i32); EXPECT_EQ(functype2.outputs.size(), 0); - EXPECT_EQ(module.funcsec.size(), 0); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, type_section_functype_out_of_bounds) @@ -299,7 +299,7 @@ TEST(parser, import_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(2, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.importsec.size(), 0); + EXPECT_EQ(module->importsec.size(), 0); } TEST(parser, import_single_function) @@ -310,11 +310,11 @@ TEST(parser, import_single_function) bytes{wasm_prefix} + make_section(1, type_section) + make_section(2, import_section); const auto module = parse(bin); - ASSERT_EQ(module.importsec.size(), 1); - EXPECT_EQ(module.importsec[0].module, "mod"); - EXPECT_EQ(module.importsec[0].name, "foo"); - EXPECT_EQ(module.importsec[0].kind, ExternalKind::Function); - EXPECT_EQ(module.importsec[0].desc.function_type_index, 1); + ASSERT_EQ(module->importsec.size(), 1); + EXPECT_EQ(module->importsec[0].module, "mod"); + EXPECT_EQ(module->importsec[0].name, "foo"); + EXPECT_EQ(module->importsec[0].kind, ExternalKind::Function); + EXPECT_EQ(module->importsec[0].desc.function_type_index, 1); } TEST(parser, import_multiple) @@ -328,27 +328,27 @@ TEST(parser, import_multiple) bytes{wasm_prefix} + make_section(1, type_section) + make_section(2, import_section); const auto module = parse(bin); - ASSERT_EQ(module.importsec.size(), 4); - EXPECT_EQ(module.importsec[0].module, "m1"); - EXPECT_EQ(module.importsec[0].name, "abc"); - EXPECT_EQ(module.importsec[0].kind, ExternalKind::Function); - EXPECT_EQ(module.importsec[0].desc.function_type_index, 0x01); - EXPECT_EQ(module.importsec[1].module, "m2"); - EXPECT_EQ(module.importsec[1].name, "foo"); - EXPECT_EQ(module.importsec[1].kind, ExternalKind::Memory); - EXPECT_EQ(module.importsec[1].desc.memory.limits.min, 0x7f); - EXPECT_FALSE(module.importsec[1].desc.memory.limits.max); - EXPECT_EQ(module.importsec[2].module, "m3"); - EXPECT_EQ(module.importsec[2].name, "bar"); - EXPECT_EQ(module.importsec[2].kind, ExternalKind::Global); - EXPECT_FALSE(module.importsec[2].desc.global.is_mutable); - EXPECT_EQ(module.importsec[2].desc.global.value_type, ValType::i32); - EXPECT_EQ(module.importsec[3].module, "m4"); - EXPECT_EQ(module.importsec[3].name, "tab"); - EXPECT_EQ(module.importsec[3].kind, ExternalKind::Table); - EXPECT_EQ(module.importsec[3].desc.table.limits.min, 1); - ASSERT_TRUE(module.importsec[3].desc.table.limits.max.has_value()); - EXPECT_EQ(*module.importsec[3].desc.table.limits.max, 0x42); + ASSERT_EQ(module->importsec.size(), 4); + EXPECT_EQ(module->importsec[0].module, "m1"); + EXPECT_EQ(module->importsec[0].name, "abc"); + EXPECT_EQ(module->importsec[0].kind, ExternalKind::Function); + EXPECT_EQ(module->importsec[0].desc.function_type_index, 0x01); + EXPECT_EQ(module->importsec[1].module, "m2"); + EXPECT_EQ(module->importsec[1].name, "foo"); + EXPECT_EQ(module->importsec[1].kind, ExternalKind::Memory); + EXPECT_EQ(module->importsec[1].desc.memory.limits.min, 0x7f); + EXPECT_FALSE(module->importsec[1].desc.memory.limits.max); + EXPECT_EQ(module->importsec[2].module, "m3"); + EXPECT_EQ(module->importsec[2].name, "bar"); + EXPECT_EQ(module->importsec[2].kind, ExternalKind::Global); + EXPECT_FALSE(module->importsec[2].desc.global.is_mutable); + EXPECT_EQ(module->importsec[2].desc.global.value_type, ValType::i32); + EXPECT_EQ(module->importsec[3].module, "m4"); + EXPECT_EQ(module->importsec[3].name, "tab"); + EXPECT_EQ(module->importsec[3].kind, ExternalKind::Table); + EXPECT_EQ(module->importsec[3].desc.table.limits.min, 1); + ASSERT_TRUE(module->importsec[3].desc.table.limits.max.has_value()); + EXPECT_EQ(*module->importsec[3].desc.table.limits.max, 0x42); } TEST(parser, import_invalid_kind) @@ -383,7 +383,7 @@ TEST(parser, function_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(3, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.funcsec.size(), 0); + EXPECT_EQ(module->funcsec.size(), 0); } TEST(parser, function_section_with_single_function) @@ -394,8 +394,8 @@ TEST(parser, function_section_with_single_function) const auto bin = bytes{wasm_prefix} + make_section(1, type_section) + make_section(3, function_section) + make_section(10, code_section); const auto module = parse(bin); - ASSERT_EQ(module.funcsec.size(), 1); - EXPECT_EQ(module.funcsec[0], 0); + ASSERT_EQ(module->funcsec.size(), 1); + EXPECT_EQ(module->funcsec[0], 0); } TEST(parser, function_section_with_multiple_functions) @@ -409,11 +409,11 @@ TEST(parser, function_section_with_multiple_functions) const auto bin = bytes{wasm_prefix} + make_section(1, type_section) + make_section(3, function_section) + make_section(10, code_section); const auto module = parse(bin); - ASSERT_EQ(module.funcsec.size(), 4); - EXPECT_EQ(module.funcsec[0], 0); - EXPECT_EQ(module.funcsec[1], 1); - EXPECT_EQ(module.funcsec[2], 3); - EXPECT_EQ(module.funcsec[3], 4); + ASSERT_EQ(module->funcsec.size(), 4); + EXPECT_EQ(module->funcsec[0], 0); + EXPECT_EQ(module->funcsec[1], 1); + EXPECT_EQ(module->funcsec[2], 3); + EXPECT_EQ(module->funcsec[3], 4); } TEST(parser, function_section_size_128) @@ -427,7 +427,7 @@ TEST(parser, function_section_size_128) const auto wasm_bin = bytes{wasm_prefix} + make_section(1, type_section) + make_section(3, function_section) + make_section(10, code_section); const auto module = parse(wasm_bin); - ASSERT_EQ(module.funcsec.size(), size); + ASSERT_EQ(module->funcsec.size(), size); } TEST(parser, function_section_end_out_of_bounds) @@ -466,7 +466,7 @@ TEST(parser, table_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(4, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.tablesec.size(), 0); + EXPECT_EQ(module->tablesec.size(), 0); } TEST(parser, table_single_min_limit) @@ -475,8 +475,8 @@ TEST(parser, table_single_min_limit) const auto bin = bytes{wasm_prefix} + make_section(4, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.tablesec.size(), 1); - EXPECT_EQ(module.tablesec[0].limits.min, 0x7f); + ASSERT_EQ(module->tablesec.size(), 1); + EXPECT_EQ(module->tablesec[0].limits.min, 0x7f); } TEST(parser, table_single_minmax_limit) @@ -485,9 +485,9 @@ TEST(parser, table_single_minmax_limit) const auto bin = bytes{wasm_prefix} + make_section(4, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.tablesec.size(), 1); - EXPECT_EQ(module.tablesec[0].limits.min, 0x12); - EXPECT_EQ(module.tablesec[0].limits.max, 0x7f); + ASSERT_EQ(module->tablesec.size(), 1); + EXPECT_EQ(module->tablesec[0].limits.min, 0x12); + EXPECT_EQ(module->tablesec[0].limits.max, 0x7f); } // Where minimum exceeds maximum @@ -516,7 +516,7 @@ TEST(parser, memory_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(5, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.memorysec.size(), 0); + EXPECT_EQ(module->memorysec.size(), 0); } TEST(parser, memory_single_min_limit) @@ -525,8 +525,8 @@ TEST(parser, memory_single_min_limit) const auto bin = bytes{wasm_prefix} + make_section(5, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.memorysec.size(), 1); - EXPECT_EQ(module.memorysec[0].limits.min, 0x7f); + ASSERT_EQ(module->memorysec.size(), 1); + EXPECT_EQ(module->memorysec[0].limits.min, 0x7f); } TEST(parser, memory_single_minmax_limit) @@ -535,9 +535,9 @@ TEST(parser, memory_single_minmax_limit) const auto bin = bytes{wasm_prefix} + make_section(5, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.memorysec.size(), 1); - EXPECT_EQ(module.memorysec[0].limits.min, 0x12); - EXPECT_EQ(module.memorysec[0].limits.max, 0x7f); + ASSERT_EQ(module->memorysec.size(), 1); + EXPECT_EQ(module->memorysec[0].limits.min, 0x12); + EXPECT_EQ(module->memorysec[0].limits.max, 0x7f); } // Where minimum exceeds maximum @@ -578,7 +578,7 @@ TEST(parser, global_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(6, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.globalsec.size(), 0); + EXPECT_EQ(module->globalsec.size(), 0); } TEST(parser, global_single_mutable_const_inited) @@ -587,11 +587,11 @@ TEST(parser, global_single_mutable_const_inited) const auto bin = bytes{wasm_prefix} + make_section(6, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.globalsec.size(), 1); - EXPECT_TRUE(module.globalsec[0].type.is_mutable); - EXPECT_EQ(module.globalsec[0].type.value_type, ValType::i32); - EXPECT_EQ(module.globalsec[0].expression.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.globalsec[0].expression.value.constant), 0x10); + ASSERT_EQ(module->globalsec.size(), 1); + EXPECT_TRUE(module->globalsec[0].type.is_mutable); + EXPECT_EQ(module->globalsec[0].type.value_type, ValType::i32); + EXPECT_EQ(module->globalsec[0].expression.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->globalsec[0].expression.value.constant), 0x10); } TEST(parser, global_multi_global_inited) @@ -605,11 +605,11 @@ TEST(parser, global_multi_global_inited) from_hex("0061736d01000000021102016d026731037f00016d026732037f000606017f0023010b"); const auto module = parse(bin); - ASSERT_EQ(module.globalsec.size(), 1); - EXPECT_FALSE(module.globalsec[0].type.is_mutable); - EXPECT_EQ(module.globalsec[0].type.value_type, ValType::i32); - EXPECT_EQ(module.globalsec[0].expression.kind, ConstantExpression::Kind::GlobalGet); - EXPECT_EQ(module.globalsec[0].expression.value.global_index, 0x01); + ASSERT_EQ(module->globalsec.size(), 1); + EXPECT_FALSE(module->globalsec[0].type.is_mutable); + EXPECT_EQ(module->globalsec[0].type.value_type, ValType::i32); + EXPECT_EQ(module->globalsec[0].expression.kind, ConstantExpression::Kind::GlobalGet); + EXPECT_EQ(module->globalsec[0].expression.value.global_index, 0x01); } TEST(parser, global_multi_const_inited) @@ -620,15 +620,15 @@ TEST(parser, global_multi_const_inited) const auto bin = bytes{wasm_prefix} + make_section(6, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.globalsec.size(), 2); - EXPECT_FALSE(module.globalsec[0].type.is_mutable); - EXPECT_EQ(module.globalsec[0].type.value_type, ValType::i32); - EXPECT_EQ(module.globalsec[0].expression.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.globalsec[0].expression.value.constant), 1); - EXPECT_TRUE(module.globalsec[1].type.is_mutable); - EXPECT_EQ(module.globalsec[1].type.value_type, ValType::i32); - EXPECT_EQ(module.globalsec[1].expression.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.globalsec[1].expression.value.constant), uint32_t(-1)); + ASSERT_EQ(module->globalsec.size(), 2); + EXPECT_FALSE(module->globalsec[0].type.is_mutable); + EXPECT_EQ(module->globalsec[0].type.value_type, ValType::i32); + EXPECT_EQ(module->globalsec[0].expression.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->globalsec[0].expression.value.constant), 1); + EXPECT_TRUE(module->globalsec[1].type.is_mutable); + EXPECT_EQ(module->globalsec[1].type.value_type, ValType::i32); + EXPECT_EQ(module->globalsec[1].expression.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->globalsec[1].expression.value.constant), uint32_t(-1)); } TEST(parser, global_float) @@ -645,31 +645,31 @@ TEST(parser, global_float) "33330b400b7c0023010b"); const auto module = parse(bin); - ASSERT_EQ(module.importsec.size(), 2); - EXPECT_EQ(module.importsec[0].kind, ExternalKind::Global); - EXPECT_EQ(module.importsec[0].module, "m"); - EXPECT_EQ(module.importsec[0].name, "g1"); - EXPECT_TRUE(module.importsec[0].desc.global.is_mutable); - EXPECT_EQ(module.importsec[0].desc.global.value_type, ValType::f32); - EXPECT_EQ(module.importsec[1].kind, ExternalKind::Global); - EXPECT_EQ(module.importsec[1].module, "m"); - EXPECT_EQ(module.importsec[1].name, "g2"); - EXPECT_FALSE(module.importsec[1].desc.global.is_mutable); - EXPECT_EQ(module.importsec[1].desc.global.value_type, ValType::f64); - - ASSERT_EQ(module.globalsec.size(), 3); - EXPECT_FALSE(module.globalsec[0].type.is_mutable); - EXPECT_EQ(module.globalsec[0].type.value_type, ValType::f32); - EXPECT_EQ(module.globalsec[0].expression.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(module.globalsec[0].expression.value.constant.f32, 1.2f); - EXPECT_TRUE(module.globalsec[1].type.is_mutable); - EXPECT_EQ(module.globalsec[1].type.value_type, ValType::f64); - EXPECT_EQ(module.globalsec[1].expression.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(module.globalsec[1].expression.value.constant.f64, 3.4); - EXPECT_FALSE(module.globalsec[2].type.is_mutable); - EXPECT_EQ(module.globalsec[2].type.value_type, ValType::f64); - EXPECT_EQ(module.globalsec[2].expression.kind, ConstantExpression::Kind::GlobalGet); - EXPECT_EQ(module.globalsec[2].expression.value.global_index, 1); + ASSERT_EQ(module->importsec.size(), 2); + EXPECT_EQ(module->importsec[0].kind, ExternalKind::Global); + EXPECT_EQ(module->importsec[0].module, "m"); + EXPECT_EQ(module->importsec[0].name, "g1"); + EXPECT_TRUE(module->importsec[0].desc.global.is_mutable); + EXPECT_EQ(module->importsec[0].desc.global.value_type, ValType::f32); + EXPECT_EQ(module->importsec[1].kind, ExternalKind::Global); + EXPECT_EQ(module->importsec[1].module, "m"); + EXPECT_EQ(module->importsec[1].name, "g2"); + EXPECT_FALSE(module->importsec[1].desc.global.is_mutable); + EXPECT_EQ(module->importsec[1].desc.global.value_type, ValType::f64); + + ASSERT_EQ(module->globalsec.size(), 3); + EXPECT_FALSE(module->globalsec[0].type.is_mutable); + EXPECT_EQ(module->globalsec[0].type.value_type, ValType::f32); + EXPECT_EQ(module->globalsec[0].expression.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(module->globalsec[0].expression.value.constant.f32, 1.2f); + EXPECT_TRUE(module->globalsec[1].type.is_mutable); + EXPECT_EQ(module->globalsec[1].type.value_type, ValType::f64); + EXPECT_EQ(module->globalsec[1].expression.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(module->globalsec[1].expression.value.constant.f64, 3.4); + EXPECT_FALSE(module->globalsec[2].type.is_mutable); + EXPECT_EQ(module->globalsec[2].type.value_type, ValType::f64); + EXPECT_EQ(module->globalsec[2].expression.kind, ConstantExpression::Kind::GlobalGet); + EXPECT_EQ(module->globalsec[2].expression.value.global_index, 1); } TEST(parser, global_invalid_mutability) @@ -730,7 +730,7 @@ TEST(parser, export_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(7, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.exportsec.size(), 0); + EXPECT_EQ(module->exportsec.size(), 0); } TEST(parser, export_single_function) @@ -745,10 +745,10 @@ TEST(parser, export_single_function) make_section(10, code_section); const auto module = parse(bin); - ASSERT_EQ(module.exportsec.size(), 1); - EXPECT_EQ(module.exportsec[0].name, "abc"); - EXPECT_EQ(module.exportsec[0].kind, ExternalKind::Function); - EXPECT_EQ(module.exportsec[0].index, 0); + ASSERT_EQ(module->exportsec.size(), 1); + EXPECT_EQ(module->exportsec[0].name, "abc"); + EXPECT_EQ(module->exportsec[0].kind, ExternalKind::Function); + EXPECT_EQ(module->exportsec[0].index, 0); } TEST(parser, export_multiple) @@ -764,19 +764,19 @@ TEST(parser, export_multiple) "0003666f6f01000362617202000378797a03000a05010300010b"); const auto module = parse(wasm); - ASSERT_EQ(module.exportsec.size(), 4); - EXPECT_EQ(module.exportsec[0].name, "abc"); - EXPECT_EQ(module.exportsec[0].kind, ExternalKind::Function); - EXPECT_EQ(module.exportsec[0].index, 0); - EXPECT_EQ(module.exportsec[1].name, "foo"); - EXPECT_EQ(module.exportsec[1].kind, ExternalKind::Table); - EXPECT_EQ(module.exportsec[1].index, 0); - EXPECT_EQ(module.exportsec[2].name, "bar"); - EXPECT_EQ(module.exportsec[2].kind, ExternalKind::Memory); - EXPECT_EQ(module.exportsec[2].index, 0); - EXPECT_EQ(module.exportsec[3].name, "xyz"); - EXPECT_EQ(module.exportsec[3].kind, ExternalKind::Global); - EXPECT_EQ(module.exportsec[3].index, 0); + ASSERT_EQ(module->exportsec.size(), 4); + EXPECT_EQ(module->exportsec[0].name, "abc"); + EXPECT_EQ(module->exportsec[0].kind, ExternalKind::Function); + EXPECT_EQ(module->exportsec[0].index, 0); + EXPECT_EQ(module->exportsec[1].name, "foo"); + EXPECT_EQ(module->exportsec[1].kind, ExternalKind::Table); + EXPECT_EQ(module->exportsec[1].index, 0); + EXPECT_EQ(module->exportsec[2].name, "bar"); + EXPECT_EQ(module->exportsec[2].kind, ExternalKind::Memory); + EXPECT_EQ(module->exportsec[2].index, 0); + EXPECT_EQ(module->exportsec[3].name, "xyz"); + EXPECT_EQ(module->exportsec[3].kind, ExternalKind::Global); + EXPECT_EQ(module->exportsec[3].index, 0); } TEST(parser, export_invalid_kind) @@ -818,8 +818,8 @@ TEST(parser, start) make_section(10, code_section); const auto module = parse(bin); - EXPECT_TRUE(module.startfunc); - EXPECT_EQ(*module.startfunc, 1); + EXPECT_TRUE(module->startfunc); + EXPECT_EQ(*module->startfunc, 1); } TEST(parser, start_invalid_index) @@ -856,8 +856,8 @@ TEST(parser, start_module_with_imports) make_section(8, start_section) + make_section(10, code_section); const auto module = parse(bin); - EXPECT_TRUE(module.startfunc); - EXPECT_EQ(*module.startfunc, 2); + EXPECT_TRUE(module->startfunc); + EXPECT_EQ(*module->startfunc, 2); } TEST(parser, start_module_with_imports_invalid_index) @@ -885,7 +885,7 @@ TEST(parser, element_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(9, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.elementsec.size(), 0); + EXPECT_EQ(module->elementsec.size(), 0); } TEST(parser, element_section) @@ -906,22 +906,22 @@ TEST(parser, element_section) "0200010041020b0202030023000b0200030a0d0402000b02000b02000b02000b"); const auto module = parse(bin); - ASSERT_EQ(module.elementsec.size(), 3); - EXPECT_EQ(module.elementsec[0].offset.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.elementsec[0].offset.value.constant), 1); - ASSERT_EQ(module.elementsec[0].init.size(), 2); - EXPECT_EQ(module.elementsec[0].init[0], 0); - EXPECT_EQ(module.elementsec[0].init[1], 1); - EXPECT_EQ(module.elementsec[1].offset.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.elementsec[1].offset.value.constant), 2); - ASSERT_EQ(module.elementsec[1].init.size(), 2); - EXPECT_EQ(module.elementsec[1].init[0], 2); - EXPECT_EQ(module.elementsec[1].init[1], 3); - EXPECT_EQ(module.elementsec[2].offset.kind, ConstantExpression::Kind::GlobalGet); - EXPECT_EQ(module.elementsec[2].offset.value.global_index, 0); - ASSERT_EQ(module.elementsec[2].init.size(), 2); - EXPECT_EQ(module.elementsec[2].init[0], 0); - EXPECT_EQ(module.elementsec[2].init[1], 3); + ASSERT_EQ(module->elementsec.size(), 3); + EXPECT_EQ(module->elementsec[0].offset.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->elementsec[0].offset.value.constant), 1); + ASSERT_EQ(module->elementsec[0].init.size(), 2); + EXPECT_EQ(module->elementsec[0].init[0], 0); + EXPECT_EQ(module->elementsec[0].init[1], 1); + EXPECT_EQ(module->elementsec[1].offset.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->elementsec[1].offset.value.constant), 2); + ASSERT_EQ(module->elementsec[1].init.size(), 2); + EXPECT_EQ(module->elementsec[1].init[0], 2); + EXPECT_EQ(module->elementsec[1].init[1], 3); + EXPECT_EQ(module->elementsec[2].offset.kind, ConstantExpression::Kind::GlobalGet); + EXPECT_EQ(module->elementsec[2].offset.value.global_index, 0); + ASSERT_EQ(module->elementsec[2].init.size(), 2); + EXPECT_EQ(module->elementsec[2].init[0], 0); + EXPECT_EQ(module->elementsec[2].init[1], 3); } TEST(parser, element_section_tableidx_nonzero) @@ -952,7 +952,7 @@ TEST(parser, code_section_empty) { const auto bin = bytes{wasm_prefix} + make_section(10, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.codesec.size(), 0); + EXPECT_EQ(module->codesec.size(), 0); } TEST(parser, code_locals) @@ -964,8 +964,8 @@ TEST(parser, code_locals) make_section(10, make_vec({add_size_prefix(make_vec({wasm_locals}) + "0b"_bytes)})); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 1); - EXPECT_EQ(module.codesec[0].local_count, 0x81); + ASSERT_EQ(module->codesec.size(), 1); + EXPECT_EQ(module->codesec[0].local_count, 0x81); } TEST(parser, code_locals_2) @@ -982,8 +982,8 @@ TEST(parser, code_locals_2) make_vec({wasm_locals1, wasm_locals2, wasm_locals3, wasm_locals4}) + "0b"_bytes)})); const auto module = parse(wasm); - ASSERT_EQ(module.codesec.size(), 1); - EXPECT_EQ(module.codesec[0].local_count, 1 + 2 + 3 + 4); + ASSERT_EQ(module->codesec.size(), 1); + EXPECT_EQ(module->codesec[0].local_count, 1 + 2 + 3 + 4); } TEST(parser, code_locals_invalid_type) @@ -1023,8 +1023,8 @@ TEST(parser, code_with_empty_expr_2_locals) make_section(3, "0100"_bytes) + make_section(10, make_vec({code_bin})); const auto module = parse(wasm_bin); - ASSERT_EQ(module.codesec.size(), 1); - const auto& code_obj = module.codesec[0]; + ASSERT_EQ(module->codesec.size(), 1); + const auto& code_obj = module->codesec[0]; EXPECT_EQ(code_obj.local_count, 2); ASSERT_EQ(code_obj.instructions.size(), 1); EXPECT_EQ(code_obj.instructions[0], Instr::end); @@ -1040,8 +1040,8 @@ TEST(parser, code_with_empty_expr_5_locals) make_section(3, "0100"_bytes) + make_section(10, make_vec({code_bin})); const auto module = parse(wasm_bin); - ASSERT_EQ(module.codesec.size(), 1); - const auto& code_obj = module.codesec[0]; + ASSERT_EQ(module->codesec.size(), 1); + const auto& code_obj = module->codesec[0]; EXPECT_EQ(code_obj.local_count, 5); ASSERT_EQ(code_obj.instructions.size(), 1); EXPECT_EQ(code_obj.instructions[0], Instr::end); @@ -1057,16 +1057,16 @@ TEST(parser, code_section_with_2_trivial_codes) make_section(3, "020000"_bytes) + make_section(10, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.typesec.size(), 1); - EXPECT_EQ(module.typesec[0].inputs.size(), 0); - EXPECT_EQ(module.typesec[0].outputs.size(), 0); - ASSERT_EQ(module.codesec.size(), 2); - EXPECT_EQ(module.codesec[0].local_count, 0); - ASSERT_EQ(module.codesec[0].instructions.size(), 1); - EXPECT_EQ(module.codesec[0].instructions[0], Instr::end); - EXPECT_EQ(module.codesec[1].local_count, 0); - ASSERT_EQ(module.codesec[1].instructions.size(), 1); - EXPECT_EQ(module.codesec[1].instructions[0], Instr::end); + ASSERT_EQ(module->typesec.size(), 1); + EXPECT_EQ(module->typesec[0].inputs.size(), 0); + EXPECT_EQ(module->typesec[0].outputs.size(), 0); + ASSERT_EQ(module->codesec.size(), 2); + EXPECT_EQ(module->codesec[0].local_count, 0); + ASSERT_EQ(module->codesec[0].instructions.size(), 1); + EXPECT_EQ(module->codesec[0].instructions[0], Instr::end); + EXPECT_EQ(module->codesec[1].local_count, 0); + ASSERT_EQ(module->codesec[1].instructions.size(), 1); + EXPECT_EQ(module->codesec[1].instructions[0], Instr::end); } TEST(parser, code_section_with_basic_instructions) @@ -1086,21 +1086,21 @@ TEST(parser, code_section_with_basic_instructions) make_section(3, "0100"_bytes) + make_section(10, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.typesec.size(), 1); - EXPECT_EQ(module.typesec[0].inputs.size(), 0); - EXPECT_EQ(module.typesec[0].outputs.size(), 0); - ASSERT_EQ(module.codesec.size(), 1); - EXPECT_EQ(module.codesec[0].local_count, 4); - ASSERT_EQ(module.codesec[0].instructions.size(), 7); - EXPECT_EQ(module.codesec[0].instructions[0], Instr::local_get); - EXPECT_EQ(module.codesec[0].instructions[1], Instr::i32_const); - EXPECT_EQ(module.codesec[0].instructions[2], Instr::i32_add); - EXPECT_EQ(module.codesec[0].instructions[3], Instr::local_set); - EXPECT_EQ(module.codesec[0].instructions[4], Instr::nop); - EXPECT_EQ(module.codesec[0].instructions[5], Instr::unreachable); - EXPECT_EQ(module.codesec[0].instructions[6], Instr::end); - ASSERT_EQ(module.codesec[0].immediates.size(), 3 * 4); - EXPECT_EQ(module.codesec[0].immediates, "010000000200000003000000"_bytes); + ASSERT_EQ(module->typesec.size(), 1); + EXPECT_EQ(module->typesec[0].inputs.size(), 0); + EXPECT_EQ(module->typesec[0].outputs.size(), 0); + ASSERT_EQ(module->codesec.size(), 1); + EXPECT_EQ(module->codesec[0].local_count, 4); + ASSERT_EQ(module->codesec[0].instructions.size(), 7); + EXPECT_EQ(module->codesec[0].instructions[0], Instr::local_get); + EXPECT_EQ(module->codesec[0].instructions[1], Instr::i32_const); + EXPECT_EQ(module->codesec[0].instructions[2], Instr::i32_add); + EXPECT_EQ(module->codesec[0].instructions[3], Instr::local_set); + EXPECT_EQ(module->codesec[0].instructions[4], Instr::nop); + EXPECT_EQ(module->codesec[0].instructions[5], Instr::unreachable); + EXPECT_EQ(module->codesec[0].instructions[6], Instr::end); + ASSERT_EQ(module->codesec[0].immediates.size(), 3 * 4); + EXPECT_EQ(module->codesec[0].immediates, "010000000200000003000000"_bytes); } TEST(parser, code_section_with_memory_size) @@ -1114,12 +1114,12 @@ TEST(parser, code_section_with_memory_size) make_section(3, "0100"_bytes) + make_section(5, make_vec({"0000"_bytes})) + make_section(10, section_contents); const auto module = parse(bin); - ASSERT_EQ(module.codesec.size(), 1); - EXPECT_EQ(module.codesec[0].local_count, 0); - ASSERT_EQ(module.codesec[0].instructions.size(), 2); - EXPECT_EQ(module.codesec[0].instructions[0], Instr::memory_size); - EXPECT_EQ(module.codesec[0].instructions[1], Instr::end); - EXPECT_TRUE(module.codesec[0].immediates.empty()); + ASSERT_EQ(module->codesec.size(), 1); + EXPECT_EQ(module->codesec[0].local_count, 0); + ASSERT_EQ(module->codesec[0].instructions.size(), 2); + EXPECT_EQ(module->codesec[0].instructions[0], Instr::memory_size); + EXPECT_EQ(module->codesec[0].instructions[1], Instr::end); + EXPECT_TRUE(module->codesec[0].immediates.empty()); const auto func_bin_invalid = "00" // vec(locals) @@ -1144,14 +1144,14 @@ TEST(parser, code_section_with_memory_grow) make_section(10, code_section); const auto module = parse(bin); - ASSERT_EQ(module.codesec.size(), 1); - EXPECT_EQ(module.codesec[0].local_count, 0); - ASSERT_EQ(module.codesec[0].instructions.size(), 4); - EXPECT_EQ(module.codesec[0].instructions[0], Instr::i32_const); - EXPECT_EQ(module.codesec[0].instructions[1], Instr::memory_grow); - EXPECT_EQ(module.codesec[0].instructions[2], Instr::drop); - EXPECT_EQ(module.codesec[0].instructions[3], Instr::end); - EXPECT_EQ(module.codesec[0].immediates, "00000000"_bytes); + ASSERT_EQ(module->codesec.size(), 1); + EXPECT_EQ(module->codesec[0].local_count, 0); + ASSERT_EQ(module->codesec[0].instructions.size(), 4); + EXPECT_EQ(module->codesec[0].instructions[0], Instr::i32_const); + EXPECT_EQ(module->codesec[0].instructions[1], Instr::memory_grow); + EXPECT_EQ(module->codesec[0].instructions[2], Instr::drop); + EXPECT_EQ(module->codesec[0].instructions[3], Instr::end); + EXPECT_EQ(module->codesec[0].immediates, "00000000"_bytes); const auto func_bin_invalid = "00"_bytes + // vec(locals) i32_const(0) + "40011a0b"_bytes; @@ -1227,7 +1227,7 @@ TEST(parser, code_section_fp_instructions) make_section(5, make_vec({"0000"_bytes})) + make_section(10, code_section); const auto module = parse(bin); - EXPECT_EQ(module.codesec.size(), 1); + EXPECT_EQ(module->codesec.size(), 1); } } @@ -1310,7 +1310,7 @@ TEST(parser, data_section_empty) const auto bin = bytes{wasm_prefix} + make_section(5, make_vec({"0000"_bytes})) + make_section(11, make_vec({})); const auto module = parse(bin); - EXPECT_EQ(module.datasec.size(), 0); + EXPECT_EQ(module->datasec.size(), 0); } TEST(parser, data_section) @@ -1327,16 +1327,16 @@ TEST(parser, data_section) "2424"); const auto module = parse(bin); - ASSERT_EQ(module.datasec.size(), 3); - EXPECT_EQ(module.datasec[0].offset.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.datasec[0].offset.value.constant), 1); - EXPECT_EQ(module.datasec[0].init, "aaff"_bytes); - EXPECT_EQ(module.datasec[1].offset.kind, ConstantExpression::Kind::Constant); - EXPECT_EQ(as_uint32(module.datasec[1].offset.value.constant), 2); - EXPECT_EQ(module.datasec[1].init, "5555"_bytes); - EXPECT_EQ(module.datasec[2].offset.kind, ConstantExpression::Kind::GlobalGet); - EXPECT_EQ(module.datasec[2].offset.value.global_index, 0); - EXPECT_EQ(module.datasec[2].init, "2424"_bytes); + ASSERT_EQ(module->datasec.size(), 3); + EXPECT_EQ(module->datasec[0].offset.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->datasec[0].offset.value.constant), 1); + EXPECT_EQ(module->datasec[0].init, "aaff"_bytes); + EXPECT_EQ(module->datasec[1].offset.kind, ConstantExpression::Kind::Constant); + EXPECT_EQ(as_uint32(module->datasec[1].offset.value.constant), 2); + EXPECT_EQ(module->datasec[1].init, "5555"_bytes); + EXPECT_EQ(module->datasec[2].offset.kind, ConstantExpression::Kind::GlobalGet); + EXPECT_EQ(module->datasec[2].offset.value.global_index, 0); + EXPECT_EQ(module->datasec[2].init, "2424"_bytes); } TEST(parser, data_section_memidx_nonzero) @@ -1409,9 +1409,9 @@ TEST(parser, interleaved_custom_section) make_section(10, code_section); const auto module = parse(bin); - EXPECT_EQ(module.typesec.size(), 1); - EXPECT_EQ(module.funcsec.size(), 1); - EXPECT_EQ(module.codesec.size(), 1); + EXPECT_EQ(module->typesec.size(), 1); + EXPECT_EQ(module->funcsec.size(), 1); + EXPECT_EQ(module->codesec.size(), 1); } TEST(parser, wrongly_ordered_sections) @@ -1464,12 +1464,12 @@ TEST(parser, milestone1) "0061736d0100000001070160027f7f017f030201000a13011101017f200020016a20026a220220006a0b"); const auto m = parse(wasm); - ASSERT_EQ(m.typesec.size(), 1); - EXPECT_EQ(m.typesec[0].inputs, (std::vector{ValType::i32, ValType::i32})); - EXPECT_EQ(m.typesec[0].outputs, (std::vector{ValType::i32})); + ASSERT_EQ(m->typesec.size(), 1); + EXPECT_EQ(m->typesec[0].inputs, (std::vector{ValType::i32, ValType::i32})); + EXPECT_EQ(m->typesec[0].outputs, (std::vector{ValType::i32})); - ASSERT_EQ(m.codesec.size(), 1); - const auto& c = m.codesec[0]; + ASSERT_EQ(m->codesec.size(), 1); + const auto& c = m->codesec[0]; EXPECT_EQ(c.local_count, 1); EXPECT_EQ(c.instructions, (std::vector{Instr::local_get, Instr::local_get, Instr::i32_add, Instr::local_get, diff --git a/test/unittests/validation_stack_test.cpp b/test/unittests/validation_stack_test.cpp index 88bd3558fe..7da5bb3e84 100644 --- a/test/unittests/validation_stack_test.cpp +++ b/test/unittests/validation_stack_test.cpp @@ -144,7 +144,7 @@ TEST(validation_stack, block_with_result) */ const auto wasm = from_hex("0061736d01000000010401600000030201000a0a010800027f417f0b1a0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].max_stack_height, 1); + EXPECT_EQ(module->codesec[0].max_stack_height, 1); } TEST(validation_stack, block_missing_result) @@ -215,7 +215,7 @@ TEST(validation_stack, loop_with_result) */ const auto wasm = from_hex("0061736d01000000010401600000030201000a0a010800037f417f0b1a0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].max_stack_height, 1); + EXPECT_EQ(module->codesec[0].max_stack_height, 1); } TEST(validation_stack, loop_missing_result) @@ -502,7 +502,7 @@ TEST(validation_stack, unreachable) */ const auto wasm = from_hex("0061736d010000000105016000017f030201000a0601040000450b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 0); + EXPECT_THAT(module->codesec[0].max_stack_height, 0); } TEST(validation_stack, unreachable_2) @@ -518,7 +518,7 @@ TEST(validation_stack, unreachable_2) */ const auto wasm = from_hex("0061736d01000000010401600000030201000a09010700006a6a6a1a0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 0); + EXPECT_THAT(module->codesec[0].max_stack_height, 0); } TEST(validation_stack, unreachable_3) @@ -530,7 +530,7 @@ TEST(validation_stack, unreachable_3) */ const auto wasm = from_hex("0061736d010000000105016000017f030201000a08010600027f000b0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 1); + EXPECT_THAT(module->codesec[0].max_stack_height, 1); } TEST(validation_stack, unreachable_4) @@ -544,7 +544,7 @@ TEST(validation_stack, unreachable_4) const auto wasm = from_hex("0061736d010000000105016000017f030201000a0d010b0000047f41000541010b0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 1); + EXPECT_THAT(module->codesec[0].max_stack_height, 1); } TEST(validation_stack, unreachable_5) @@ -558,7 +558,7 @@ TEST(validation_stack, unreachable_5) */ const auto wasm = from_hex("0061736d010000000105016000017f030201000a08010600420000450b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 1); + EXPECT_THAT(module->codesec[0].max_stack_height, 1); } @@ -710,7 +710,7 @@ TEST(validation_stack, br) */ const auto wasm = from_hex("0061736d01000000010401600000030201000a0b01090002400c00451a0b0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 0); + EXPECT_THAT(module->codesec[0].max_stack_height, 0); } TEST(validation_stack, br_table) @@ -731,7 +731,7 @@ TEST(validation_stack, br_table) const auto wasm = from_hex( "0061736d0100000001050160017f00030201000a14011200024041e90720000e0100016c6c6c1a0b0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 2); + EXPECT_THAT(module->codesec[0].max_stack_height, 2); } TEST(validation_stack, return_) @@ -745,7 +745,7 @@ TEST(validation_stack, return_) */ const auto wasm = from_hex("0061736d01000000010401600000030201000a070105000f451a0b"); const auto module = parse(wasm); - EXPECT_THAT(module.codesec[0].max_stack_height, 0); + EXPECT_THAT(module->codesec[0].max_stack_height, 0); } TEST(validation_stack, if_stack_underflow) @@ -984,7 +984,7 @@ TEST(validation_stack, if_else_stack_height) const auto wasm = from_hex("0061736d01000000010401600000030201000a1201100042014102047e42010542030b1a1a0b"); const auto module = parse(wasm); - EXPECT_EQ(module.codesec[0].max_stack_height, 2); + EXPECT_EQ(module->codesec[0].max_stack_height, 2); } TEST(validation_stack, if_invalid_end_stack_height) diff --git a/test/utils/execute_helpers.hpp b/test/utils/execute_helpers.hpp index 7fadf81864..7c69bdf890 100644 --- a/test/utils/execute_helpers.hpp +++ b/test/utils/execute_helpers.hpp @@ -10,7 +10,7 @@ namespace fizzy::test { inline ExecutionResult execute( - const Module& module, FuncIdx func_idx, std::initializer_list args) + const std::unique_ptr& module, FuncIdx func_idx, std::initializer_list args) { auto instance = instantiate(module); return execute(*instance, func_idx, args); diff --git a/test/utils/fizzy_engine.cpp b/test/utils/fizzy_engine.cpp index 59f76b7964..ee23ccaf42 100644 --- a/test/utils/fizzy_engine.cpp +++ b/test/utils/fizzy_engine.cpp @@ -84,13 +84,13 @@ bool FizzyEngine::instantiate(bytes_view wasm_binary) { try { - const auto module = fizzy::parse(wasm_binary); + auto module = fizzy::parse(wasm_binary); auto imports = fizzy::resolve_imported_functions( - module, { - {"env", "adler32", {fizzy::ValType::i32, fizzy::ValType::i32}, - fizzy::ValType::i32, env_adler32}, - }); - m_instance = fizzy::instantiate(module, imports); + *module, { + {"env", "adler32", {fizzy::ValType::i32, fizzy::ValType::i32}, + fizzy::ValType::i32, env_adler32}, + }); + m_instance = fizzy::instantiate(std::move(module), std::move(imports)); } catch (...) { @@ -120,10 +120,10 @@ bytes_view FizzyEngine::get_memory() const std::optional FizzyEngine::find_function( std::string_view name, std::string_view signature) const { - const auto func_idx = fizzy::find_exported_function(m_instance->module, name); + const auto func_idx = fizzy::find_exported_function(*m_instance->module, name); if (func_idx.has_value()) { - const auto func_type = m_instance->module.get_function_type(*func_idx); + const auto func_type = m_instance->module->get_function_type(*func_idx); const auto sig_type = translate_signature(signature); if (sig_type != func_type) return std::nullopt; @@ -137,7 +137,7 @@ WasmEngine::Result FizzyEngine::execute( static_assert(sizeof(uint64_t) == sizeof(Value)); const auto first_arg = reinterpret_cast(args.data()); assert(args.size() == - m_instance->module.get_function_type(static_cast(func_ref)).inputs.size()); + m_instance->module->get_function_type(static_cast(func_ref)).inputs.size()); const auto status = fizzy::execute(*m_instance, static_cast(func_ref), first_arg); if (status.trapped) return {true, std::nullopt}; diff --git a/tools/wasi/wasi.cpp b/tools/wasi/wasi.cpp index 228c09d912..fd2464e036 100644 --- a/tools/wasi/wasi.cpp +++ b/tools/wasi/wasi.cpp @@ -156,12 +156,12 @@ bool run(int argc, const char** argv) fizzy::bytes(std::istreambuf_iterator{wasm_file}, std::istreambuf_iterator{}); auto module = fizzy::parse(wasm_binary); - auto imports = fizzy::resolve_imported_functions(module, wasi_functions); + auto imports = fizzy::resolve_imported_functions(*module, wasi_functions); auto instance = fizzy::instantiate( std::move(module), std::move(imports), {}, {}, {}, fizzy::MemoryPagesValidationLimit); assert(instance != nullptr); - const auto start_function = fizzy::find_exported_function(instance->module, "_start"); + const auto start_function = fizzy::find_exported_function(*instance->module, "_start"); if (!start_function.has_value()) { std::cerr << "File is not WASI compatible (_start not found)\n"; @@ -170,7 +170,7 @@ bool run(int argc, const char** argv) // Manually validate type signature here // TODO: do this in find_exported_function - if (instance->module.get_function_type(*start_function) != fizzy::FuncType{}) + if (instance->module->get_function_type(*start_function) != fizzy::FuncType{}) { std::cerr << "File is not WASI compatible (_start has invalid signature)\n"; return false;