From 251f2cf1e88c26458ab8519945c079cd5ddc8cd4 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Mon, 4 Jan 2021 18:20:20 +0100 Subject: [PATCH] capi: Add functions to access import definitions in module --- include/fizzy/fizzy.h | 42 ++++++++++++ lib/fizzy/capi.cpp | 40 ++++++++++++ test/unittests/capi_test.cpp | 121 +++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+) diff --git a/include/fizzy/fizzy.h b/include/fizzy/fizzy.h index 2c39edf9da..e255b0dac2 100644 --- a/include/fizzy/fizzy.h +++ b/include/fizzy/fizzy.h @@ -133,6 +133,32 @@ typedef struct FizzyExternalGlobal FizzyGlobalType type; } FizzyExternalGlobal; +/// External kind. +typedef enum FizzyExternalKind +{ + FizzyExternalKindFunction, + FizzyExternalKindTable, + FizzyExternalKindMemory, + FizzyExternalKindGlobal +} FizzyExternalKind; + +/// Import definition. +/// +/// @note Only one member of `desc` union corresponding to `kind` is defined for each import. +typedef struct FizzyImportType +{ + const char* module; + const char* name; + FizzyExternalKind kind; + union + { + FizzyFunctionType function_type; + FizzyLimits memory_limits; + FizzyLimits table_limits; + FizzyGlobalType global_type; + } desc; +} FizzyImportType; + /// Imported function. typedef struct FizzyImportedFunction { @@ -210,6 +236,22 @@ uint32_t fizzy_get_global_count(const FizzyModule* module); /// @note All module global indices are greater than all imported global indices. FizzyGlobalType fizzy_get_global_type(const FizzyModule* module, uint32_t global_idx); +/// Get number of imports defined in the module. +/// +/// @param module Pointer to module. Cannot be NULL. +/// @return Number of imports in the module. +uint32_t fizzy_get_import_count(const FizzyModule* module); + +/// Get the import type defined in the module. +/// +/// @param module Pointer to module. Cannot be NULL. +/// @param import_idx Import index. Behaviour is undefined if index is not valid according +/// to module definition. +/// @return Type of the import corresponding to the index. `module` and `name` fields +/// point to the string stored inside the module and are valid as long as +/// module is alive. +FizzyImportType fizzy_get_import_type(const FizzyModule* module, uint32_t import_idx); + /// Find index of exported function by name. /// /// @param module Pointer to module. Cannot be NULL. diff --git a/lib/fizzy/capi.cpp b/lib/fizzy/capi.cpp index 2b6f40a229..e1dcb6c130 100644 --- a/lib/fizzy/capi.cpp +++ b/lib/fizzy/capi.cpp @@ -282,6 +282,35 @@ inline std::vector unwrap( external_globals.begin(), unwrap_external_global_fn); return external_globals; } + +inline FizzyExternalKind wrap(fizzy::ExternalKind kind) noexcept +{ + return static_cast(kind); +} + +inline FizzyImportType wrap(const fizzy::Import& import, const fizzy::Module& module) noexcept +{ + FizzyImportType c_import_type; + c_import_type.module = import.module.c_str(); + c_import_type.name = import.name.c_str(); + c_import_type.kind = wrap(import.kind); + switch (c_import_type.kind) + { + case FizzyExternalKindFunction: + c_import_type.desc.function_type = wrap(module.typesec[import.desc.function_type_index]); + break; + case FizzyExternalKindTable: + c_import_type.desc.table_limits = wrap(import.desc.table.limits); + break; + case FizzyExternalKindMemory: + c_import_type.desc.memory_limits = wrap(import.desc.memory.limits); + break; + case FizzyExternalKindGlobal: + c_import_type.desc.global_type = wrap(import.desc.global); + break; + } + return c_import_type; +} } // namespace extern "C" { @@ -354,6 +383,17 @@ FizzyGlobalType fizzy_get_global_type(const FizzyModule* module, uint32_t global return wrap(unwrap(module)->get_global_type(global_idx)); } +uint32_t fizzy_get_import_count(const FizzyModule* module) +{ + return static_cast(unwrap(module)->importsec.size()); +} + +FizzyImportType fizzy_get_import_type(const FizzyModule* c_module, uint32_t import_idx) +{ + const auto* module = unwrap(c_module); + return wrap(module->importsec[import_idx], *module); +} + bool fizzy_find_exported_function_index( const FizzyModule* module, const char* name, uint32_t* out_func_idx) { diff --git a/test/unittests/capi_test.cpp b/test/unittests/capi_test.cpp index ee823aabb3..1fc5275359 100644 --- a/test/unittests/capi_test.cpp +++ b/test/unittests/capi_test.cpp @@ -1185,3 +1185,124 @@ TEST(capi, get_global_type) fizzy_free_module(module_imports); } + +TEST(capi, get_import_count) +{ + /* wat2wasm + (module) + */ + const auto wasm_empty = from_hex("0061736d01000000"); + + const auto* module_empty = fizzy_parse(wasm_empty.data(), wasm_empty.size()); + ASSERT_NE(module_empty, nullptr); + + EXPECT_EQ(fizzy_get_import_count(module_empty), 0); + fizzy_free_module(module_empty); + + /* wat2wasm + (func (import "m" "f") (result i32)) + (global (import "m" "g") i32) + (table (import "m" "t") 0 anyfunc) + (memory (import "m" "m") 1) + */ + const auto wasm = from_hex( + "0061736d010000000105016000017f021d04016d01660000016d0167037f00016d017401700000016d016d0200" + "01"); + + const auto* module = fizzy_parse(wasm.data(), wasm.size()); + ASSERT_NE(module, nullptr); + + EXPECT_EQ(fizzy_get_import_count(module), 4); + fizzy_free_module(module); +} + +TEST(capi, get_import_type) +{ + /* wat2wasm + (func (import "m" "f1") (result i32)) + (func (import "m" "f2") (param i64)) + (global (import "m" "g1") i32) + (global (import "m" "g2") (mut f64)) + (table (import "m" "t") 10 anyfunc) + (memory (import "m" "mem") 1 4) + */ + const auto wasm = from_hex( + "0061736d010000000109026000017f60017e00023106016d0266310000016d0266320001016d026731037f0001" + "6d026732037c01016d01740170000a016d036d656d02010104"); + + const auto* module = fizzy_parse(wasm.data(), wasm.size()); + ASSERT_NE(module, nullptr); + ASSERT_EQ(fizzy_get_import_count(module), 6); + + const auto import0 = fizzy_get_import_type(module, 0); + EXPECT_STREQ(import0.module, "m"); + EXPECT_STREQ(import0.name, "f1"); + EXPECT_EQ(import0.kind, FizzyExternalKindFunction); + EXPECT_EQ(import0.desc.function_type.inputs_size, 0); + EXPECT_EQ(import0.desc.function_type.output, FizzyValueTypeI32); + + const auto import1 = fizzy_get_import_type(module, 1); + EXPECT_STREQ(import1.module, "m"); + EXPECT_STREQ(import1.name, "f2"); + EXPECT_EQ(import1.kind, FizzyExternalKindFunction); + ASSERT_EQ(import1.desc.function_type.inputs_size, 1); + EXPECT_EQ(import1.desc.function_type.inputs[0], FizzyValueTypeI64); + EXPECT_EQ(import1.desc.function_type.output, FizzyValueTypeVoid); + + const auto import2 = fizzy_get_import_type(module, 2); + EXPECT_STREQ(import2.module, "m"); + EXPECT_STREQ(import2.name, "g1"); + EXPECT_EQ(import2.kind, FizzyExternalKindGlobal); + EXPECT_EQ(import2.desc.global_type.value_type, FizzyValueTypeI32); + EXPECT_FALSE(import2.desc.global_type.is_mutable); + + const auto import3 = fizzy_get_import_type(module, 3); + EXPECT_STREQ(import3.module, "m"); + EXPECT_STREQ(import3.name, "g2"); + EXPECT_EQ(import3.kind, FizzyExternalKindGlobal); + EXPECT_EQ(import3.desc.global_type.value_type, FizzyValueTypeF64); + EXPECT_TRUE(import3.desc.global_type.is_mutable); + + const auto import4 = fizzy_get_import_type(module, 4); + EXPECT_STREQ(import4.module, "m"); + EXPECT_STREQ(import4.name, "t"); + EXPECT_EQ(import4.kind, FizzyExternalKindTable); + EXPECT_EQ(import4.desc.table_limits.min, 10); + EXPECT_FALSE(import4.desc.table_limits.has_max); + + const auto import5 = fizzy_get_import_type(module, 5); + EXPECT_STREQ(import5.module, "m"); + EXPECT_STREQ(import5.name, "mem"); + EXPECT_EQ(import5.kind, FizzyExternalKindMemory); + EXPECT_EQ(import5.desc.memory_limits.min, 1); + EXPECT_TRUE(import5.desc.memory_limits.has_max); + EXPECT_EQ(import5.desc.memory_limits.max, 4); + + fizzy_free_module(module); +} + +TEST(capi, import_name_after_instantiate) +{ + /* wat2wasm + (func (import "m" "f1") (result i32)) + */ + const auto wasm = from_hex("0061736d010000000105016000017f020801016d0266310000"); + + const auto* module = fizzy_parse(wasm.data(), wasm.size()); + ASSERT_NE(module, nullptr); + ASSERT_EQ(fizzy_get_import_count(module), 1); + + const auto import0 = fizzy_get_import_type(module, 0); + EXPECT_STREQ(import0.module, "m"); + EXPECT_STREQ(import0.name, "f1"); + + FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, nullptr, 0}, NullFn, nullptr}}; + + auto instance = fizzy_instantiate(module, host_funcs, 1, nullptr, nullptr, nullptr, 0); + EXPECT_NE(instance, nullptr); + + EXPECT_STREQ(import0.module, "m"); + EXPECT_STREQ(import0.name, "f1"); + + fizzy_free_instance(instance); +}