Skip to content

Commit

Permalink
capi: Add function to find exported function
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Nov 4, 2020
1 parent 5f164ef commit f09f1f4
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 18 deletions.
21 changes: 21 additions & 0 deletions include/fizzy/fizzy.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ typedef struct FizzyExternalFunction
void* context;
} FizzyExternalFunction;

/// The opaque data type representing a context of an exported function.
typedef struct FizzyExportedFunctionContext FizzyExportedFunctionContext;

/// Global type.
typedef struct FizzyGlobalType
{
Expand Down Expand Up @@ -243,6 +246,24 @@ uint8_t* fizzy_get_instance_memory_data(FizzyInstance* instance);
/// @note Function returns memory size regardless of whether memory is exported or not.
size_t fizzy_get_instance_memory_size(FizzyInstance* instance);

/// Find exported function by name.
///
/// @param instance Pointer to instance.
/// @param name The table name. NULL-terminated string. Cannot be NULL.
/// @param out_function Pointer to output struct to store found table. Cannot be NULL.
/// @param out_context_ptr Pointer to opaque output pointer to a context associated with this
/// exported function. Context must exist as long as the returned function
/// can be called by some other instance, and should be destroyed with
/// fizzy_free_exported_function_context afterwards. Cannot be NULL.
/// @returns true if function was found, false otherwise.
bool fizzy_find_exported_function(FizzyInstance* instance, const char* name,
FizzyExternalFunction* out_function, FizzyExportedFunctionContext** out_context_ptr);

/// Free resources associated with exported function context.
///
/// If passed pointer is NULL, has no effect.
void fizzy_free_exported_function_context(FizzyExportedFunctionContext* context);

/// Find exported table by name.
///
/// @param instance Pointer to instance.
Expand Down
42 changes: 42 additions & 0 deletions lib/fizzy/capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,32 @@ inline auto unwrap(FizzyExternalFn func, void* context) noexcept
};
}

inline FizzyExportedFunctionContext* wrap(fizzy::ExternalFunction* external_func) noexcept
{
return reinterpret_cast<FizzyExportedFunctionContext*>(external_func);
}

inline fizzy::ExternalFunction* unwrap(FizzyExportedFunctionContext* context) noexcept
{
return reinterpret_cast<fizzy::ExternalFunction*>(context);
}

inline std::tuple<FizzyExternalFunction, FizzyExportedFunctionContext*> wrap(
fizzy::ExternalFunction external_func)
{
FizzyExternalFn c_function = [](void* context, FizzyInstance* instance, const FizzyValue* args,
int depth) -> FizzyExecutionResult {
auto* func = static_cast<fizzy::ExternalFunction*>(context);
return wrap((func->function)(*unwrap(instance), unwrap(args), depth));
};

auto context = std::make_unique<fizzy::ExternalFunction>(std::move(external_func));
auto c_type = wrap(context->type);
FizzyExportedFunctionContext* c_context = wrap(context.release());
FizzyExternalFunction func = {c_type, c_function, c_context};
return {func, c_context};
}

inline fizzy::ExternalFunction unwrap(const FizzyExternalFunction& external_func)
{
return fizzy::ExternalFunction{
Expand Down Expand Up @@ -380,6 +406,22 @@ size_t fizzy_get_instance_memory_size(FizzyInstance* instance)
return memory->size();
}

bool fizzy_find_exported_function(FizzyInstance* instance, const char* name,
FizzyExternalFunction* out_external_function, FizzyExportedFunctionContext** out_context_ptr)
{
auto optional_func = fizzy::find_exported_function(*unwrap(instance), name);
if (!optional_func)
return false;

std::tie(*out_external_function, *out_context_ptr) = wrap(std::move(*optional_func));
return true;
}

void fizzy_free_exported_function_context(FizzyExportedFunctionContext* context)
{
delete unwrap(context);
}

FizzyExecutionResult fizzy_execute(
FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args, int depth)
{
Expand Down
63 changes: 45 additions & 18 deletions test/unittests/capi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,45 @@ TEST(capi, find_exported_function_index)
fizzy_free_module(module);
}

TEST(capi, find_exported_function)
{
/* wat2wasm
(module
(func $f (export "foo") (result i32) (i32.const 42))
(global (export "g1") i32 (i32.const 42))
(table (export "tab") 10 30 anyfunc)
(memory (export "mem") 1 2)
)
*/
const auto wasm = from_hex(
"0061736d010000000105016000017f0302010004050170010a1e0504010101020606017f00412a0b0718040366"
"6f6f00000267310300037461620100036d656d02000a06010400412a0b");

auto module = fizzy_parse(wasm.data(), wasm.size());
ASSERT_NE(module, nullptr);

auto instance = fizzy_instantiate(module, nullptr, 0, nullptr, nullptr, 0);
ASSERT_NE(instance, nullptr);

FizzyExternalFunction function;
FizzyExportedFunctionContext* context;
ASSERT_TRUE(fizzy_find_exported_function(instance, "foo", &function, &context));
EXPECT_EQ(function.type.inputs_size, 0);
EXPECT_EQ(function.type.output, FizzyValueTypeI32);
EXPECT_EQ(function.context, context);
ASSERT_NE(function.function, nullptr);
EXPECT_THAT(function.function(context, instance, nullptr, 0), CResult(42));

fizzy_free_exported_function_context(context);

EXPECT_FALSE(fizzy_find_exported_function(instance, "foo2", &function, &context));
EXPECT_FALSE(fizzy_find_exported_function(instance, "g1", &function, &context));
EXPECT_FALSE(fizzy_find_exported_function(instance, "tab", &function, &context));
EXPECT_FALSE(fizzy_find_exported_function(instance, "mem", &function, &context));

fizzy_free_instance(instance);
}

TEST(capi, find_exported_table)
{
/* wat2wasm
Expand Down Expand Up @@ -623,6 +662,10 @@ TEST(capi, imported_function_from_another_module)
auto instance1 = fizzy_instantiate(module1, nullptr, 0, nullptr, nullptr, 0);
ASSERT_NE(instance1, nullptr);

FizzyExternalFunction func;
FizzyExportedFunctionContext* context;
ASSERT_TRUE(fizzy_find_exported_function(instance1, "sub", &func, &context));

/* wat2wasm
(module
(func $sub (import "m1" "sub") (param $lhs i32) (param $rhs i32) (result i32))
Expand All @@ -640,29 +683,13 @@ TEST(capi, imported_function_from_another_module)
auto module2 = fizzy_parse(bin2.data(), bin2.size());
ASSERT_NE(module2, nullptr);

uint32_t func_idx;
ASSERT_TRUE(fizzy_find_exported_function_index(module1, "sub", &func_idx));

auto host_context = std::make_pair(instance1, func_idx);

auto sub = [](void* context, FizzyInstance*, const FizzyValue* args,
int depth) -> FizzyExecutionResult {
const auto* instance_and_func_idx =
static_cast<std::pair<FizzyInstance*, uint32_t>*>(context);
return fizzy_execute(
instance_and_func_idx->first, instance_and_func_idx->second, args, depth + 1);
};

const FizzyValueType inputs[] = {FizzyValueTypeI32, FizzyValueTypeI32};

FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, &inputs[0], 2}, sub, &host_context}};

auto instance2 = fizzy_instantiate(module2, host_funcs, 1, nullptr, nullptr, 0);
auto instance2 = fizzy_instantiate(module2, &func, 1, nullptr, nullptr, 0);
ASSERT_NE(instance2, nullptr);

FizzyValue args[] = {{44}, {2}};
EXPECT_THAT(fizzy_execute(instance2, 1, args, 0), CResult(42));

fizzy_free_exported_function_context(context);
fizzy_free_instance(instance2);
fizzy_free_instance(instance1);
}
Expand Down

0 comments on commit f09f1f4

Please sign in to comment.