Skip to content

Commit

Permalink
refactor: replace std::function with function pointer + context pointer
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Oct 20, 2020
1 parent d9626d3 commit 34a2a7f
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 303 deletions.
29 changes: 19 additions & 10 deletions lib/fizzy/capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,28 @@ inline fizzy::ExecutionResult unwrap(const FizzyExecutionResult& result) noexcep
return unwrap(result.value);
}

inline auto unwrap(FizzyExternalFn func, void* context) noexcept
// inline auto unwrap(FizzyExternalFn func) noexcept
//{
// return [func](void* context, fizzy::Instance& instance, const fizzy::Value* args,
// int depth) noexcept -> fizzy::ExecutionResult {
// const auto result = func(context, wrap(&instance), wrap(args), depth);
// return unwrap(result);
// };
//}

fizzy::ExecutionResult unwrapped_external_function(
void* context, fizzy::Instance& instance, const fizzy::Value* args, int depth)
{
return [func, context](fizzy::Instance& instance, const fizzy::Value* args,
int depth) noexcept -> fizzy::ExecutionResult {
const auto result = func(context, wrap(&instance), wrap(args), depth);
return unwrap(result);
};
const auto* c_external_function = static_cast<const FizzyExternalFunction*>(context);
return unwrap(c_external_function->function(
c_external_function->context, wrap(&instance), wrap(args), depth));
}


inline fizzy::ExternalFunction unwrap(const FizzyExternalFunction& external_func)
{
return fizzy::ExternalFunction{
unwrap(external_func.function, external_func.context), unwrap(external_func.type)};
return fizzy::ExternalFunction{unwrapped_external_function,
const_cast<FizzyExternalFunction*>(&external_func), unwrap(external_func.type)};
}

inline fizzy::ImportedFunction unwrap(const FizzyImportedFunction& c_imported_func)
Expand All @@ -131,8 +140,8 @@ inline fizzy::ImportedFunction unwrap(const FizzyImportedFunction& c_imported_fu
std::nullopt :
std::make_optional(unwrap(c_type.output));

imported_func.function = unwrap(
c_imported_func.external_function.function, c_imported_func.external_function.context);
imported_func.function = unwrapped_external_function;
imported_func.context = const_cast<FizzyExternalFunction*>(&c_imported_func.external_function);

return imported_func;
}
Expand Down
10 changes: 8 additions & 2 deletions lib/fizzy/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,

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, depth);
return instance.imported_functions[func_idx].function(
instance.imported_functions[func_idx].context, instance, args, depth);

const auto& code = instance.module->get_code(func_idx);
auto* const memory = instance.memory.get();
Expand Down Expand Up @@ -642,7 +643,12 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args,
if (expected_type != actual_type)
goto trap;

if (!invoke_function(actual_type, called_func->function, instance, stack, depth))
// TODO simplify to get rid of lambda
const auto func = [&called_func](Instance&, const Value* called_args, int _depth) {
return execute(*called_func->instance, called_func->func_idx, called_args, _depth);
};

if (!invoke_function(actual_type, func, instance, stack, depth))
goto trap;
break;
}
Expand Down
29 changes: 16 additions & 13 deletions lib/fizzy/instantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,11 +330,13 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
auto it_table = instance->table->begin() + elementsec_offsets[i];
for (const auto idx : instance->module->elementsec[i].init)
{
auto func = [idx, &instance_ref = *instance](fizzy::Instance&, const Value* args,
int depth) { return execute(instance_ref, idx, args, depth); };
// auto func = [idx, &instance_ref = *instance](fizzy::Instance&, const
// Value* args,
// int depth) { return execute(instance_ref, idx, args,
// depth); };

*it_table++ =
ExternalFunction{std::move(func), instance->module->get_function_type(idx)};
TableFunction{instance.get(), idx, instance->module->get_function_type(idx), {}};
}
}

Expand All @@ -360,11 +362,7 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
auto it_table = shared_instance->table->begin() + elementsec_offsets[i];
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;
table_function = [shared_instance, func = std::move(table_function)](
fizzy::Instance& _instance, const Value* args,
int depth) { return func(_instance, args, depth); };
(*it_table)->shared_instance = shared_instance;
++it_table;
}
}
Expand Down Expand Up @@ -417,7 +415,7 @@ std::vector<ExternalFunction> resolve_imported_functions(
}

external_functions.emplace_back(
ExternalFunction{std::move(it->function), module_func_type});
ExternalFunction{it->function, it->context, module_func_type});
}

return external_functions;
Expand All @@ -428,18 +426,23 @@ std::optional<FuncIdx> find_exported_function(const Module& module, std::string_
return find_export(module, ExternalKind::Function, name);
}

std::optional<ExternalFunction> find_exported_function(Instance& instance, std::string_view name)
std::optional<ExportedFunction> find_exported_function(Instance& instance, std::string_view name)
{
const auto opt_index = find_export(*instance.module, ExternalKind::Function, name);
if (!opt_index.has_value())
return std::nullopt;

const auto idx = *opt_index;
auto func = [idx, &instance](fizzy::Instance&, const Value* args, int depth) {
return execute(instance, idx, args, depth);
auto func = [](void* context, fizzy::Instance&, const Value* args, int depth) {
auto* instance_and_idx = static_cast<std::pair<Instance*, FuncIdx>*>(context);
return execute(*instance_and_idx->first, instance_and_idx->second, args, depth);
};

return ExternalFunction{std::move(func), instance.module->get_function_type(idx)};
ExportedFunction exported_func;
exported_func.context.reset(new std::pair(&instance, idx));
exported_func.external_function = {
std::move(func), exported_func.context.get(), instance.module->get_function_type(idx)};
return exported_func;
}

std::optional<ExternalGlobal> find_exported_global(Instance& instance, std::string_view name)
Expand Down
26 changes: 22 additions & 4 deletions lib/fizzy/instantiate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,24 @@ namespace fizzy
struct ExecutionResult;
struct Instance;

using ExternalFunctionPtr = ExecutionResult (*)(void* context, Instance&, const Value*, int depth);

struct ExternalFunction
{
std::function<ExecutionResult(Instance&, const Value*, int depth)> function;
ExternalFunctionPtr function;
void* context;
FuncType type;
};

struct TableFunction
{
Instance* instance;
FuncIdx func_idx;
FuncType type;
std::shared_ptr<Instance> shared_instance;
};

using table_elements = std::vector<std::optional<ExternalFunction>>;
using table_elements = std::vector<std::optional<TableFunction>>;
using table_ptr = std::unique_ptr<table_elements, void (*)(table_elements*)>;

struct ExternalTable
Expand Down Expand Up @@ -101,7 +112,8 @@ struct ImportedFunction
std::string name;
std::vector<ValType> inputs;
std::optional<ValType> output;
std::function<ExecutionResult(Instance&, const Value*, int depth)> function;
ExternalFunctionPtr function;
void* context;
};

// Create vector of ExternalFunctions ready to be passed to instantiate.
Expand All @@ -113,8 +125,14 @@ std::vector<ExternalFunction> resolve_imported_functions(
// Find exported function index by name.
std::optional<FuncIdx> find_exported_function(const Module& module, std::string_view name);

struct ExportedFunction
{
std::unique_ptr<std::pair<Instance*, FuncIdx>> context;
ExternalFunction external_function;
};

// Find exported function by name.
std::optional<ExternalFunction> find_exported_function(Instance& instance, std::string_view name);
std::optional<ExportedFunction> find_exported_function(Instance& instance, std::string_view name);

// Find exported global by name.
std::optional<ExternalGlobal> find_exported_global(Instance& instance, std::string_view name);
Expand Down
55 changes: 43 additions & 12 deletions test/spectests/spectests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct test_results

struct imports
{
std::vector<fizzy::ExternalFunction> functions;
std::vector<fizzy::ExportedFunction> functions;
std::vector<fizzy::ExternalTable> tables;
std::vector<fizzy::ExternalMemory> memories;
std::vector<fizzy::ExternalGlobal> globals;
Expand Down Expand Up @@ -128,8 +128,17 @@ class test_runner
continue;
}


std::vector<fizzy::ExternalFunction> external_functions(
imports.functions.size());
std::transform(imports.functions.begin(), imports.functions.end(),
external_functions.begin(),
[](const auto& imported_func) { return imported_func.external_function; });

m_instances_external_functions[name] = std::move(imports.functions);

m_instances[name] =
fizzy::instantiate(std::move(module), std::move(imports.functions),
fizzy::instantiate(std::move(module), std::move(external_functions),
std::move(imports.tables), std::move(imports.memories),
std::move(imports.globals), TestMemoryPagesLimit);

Expand All @@ -139,20 +148,23 @@ class test_runner
{
fail(std::string{"Parsing failed with error: "} + ex.what());
m_instances.erase(name);
m_instances_external_functions.erase(name);
m_last_module_name.clear();
continue;
}
catch (const fizzy::validation_error& ex)
{
fail(std::string{"Validation failed with error: "} + ex.what());
m_instances.erase(name);
m_instances_external_functions.erase(name);
m_last_module_name.clear();
continue;
}
catch (const fizzy::instantiate_error& ex)
{
fail(std::string{"Instantiation failed with error: "} + ex.what());
m_instances.erase(name);
m_instances_external_functions.erase(name);
m_last_module_name.clear();
continue;
}
Expand Down Expand Up @@ -338,7 +350,13 @@ class test_runner
continue;
}

fizzy::instantiate(std::move(module), std::move(imports.functions),
std::vector<fizzy::ExternalFunction> external_functions(
imports.functions.size());
std::transform(imports.functions.begin(), imports.functions.end(),
external_functions.begin(),
[](const auto& imported_func) { return imported_func.external_function; });

fizzy::instantiate(std::move(module), std::move(external_functions),
std::move(imports.tables), std::move(imports.memories),
std::move(imports.globals));
}
Expand Down Expand Up @@ -564,32 +582,41 @@ class test_runner
{
const auto it_registered = m_registered_names.find(import.module);
if (it_registered == m_registered_names.end())
return {{}, "Module \"" + import.module + "\" not registered."};
{
imports empty_imports;
return {
std::move(empty_imports), "Module \"" + import.module + "\" not registered."};
}

const auto module_name = it_registered->second;
const auto it_instance = m_instances.find(module_name);
if (it_instance == m_instances.end())
return {{}, "Module not instantiated."};
{
imports empty_imports;
return {std::move(empty_imports), "Module not instantiated."};
}

auto& instance = it_instance->second;

if (import.kind == fizzy::ExternalKind::Function)
{
const auto func = fizzy::find_exported_function(*instance, import.name);
auto func = fizzy::find_exported_function(*instance, import.name);
if (!func.has_value())
{
return {{},
imports empty_imports;
return {std::move(empty_imports),
"Function \"" + import.name + "\" not found in \"" + import.module + "\"."};
}

result.functions.emplace_back(*func);
result.functions.emplace_back(std::move(*func));
}
else if (import.kind == fizzy::ExternalKind::Table)
{
const auto table = fizzy::find_exported_table(*instance, import.name);
if (!table.has_value())
{
return {{},
imports empty_imports;
return {std::move(empty_imports),
"Table \"" + import.name + "\" not found in \"" + import.module + "\"."};
}

Expand All @@ -600,7 +627,8 @@ class test_runner
const auto memory = fizzy::find_exported_memory(*instance, import.name);
if (!memory.has_value())
{
return {{},
imports empty_imports;
return {std::move(empty_imports),
"Memory \"" + import.name + "\" not found in \"" + import.module + "\"."};
}

Expand All @@ -611,15 +639,16 @@ class test_runner
const auto global = fizzy::find_exported_global(*instance, import.name);
if (!global.has_value())
{
return {{},
imports empty_imports;
return {std::move(empty_imports),
"Global \"" + import.name + "\" not found in \"" + import.module + "\"."};
}

result.globals.emplace_back(*global);
}
}

return {result, ""};
return {std::move(result), ""};
}

void pass()
Expand Down Expand Up @@ -661,6 +690,8 @@ class test_runner

test_settings m_settings;
std::unordered_map<std::string, std::unique_ptr<fizzy::Instance>> m_instances;
std::unordered_map<std::string, std::vector<fizzy::ExportedFunction>>
m_instances_external_functions;
std::unordered_map<std::string, std::string> m_registered_names;
std::string m_last_module_name;
test_results m_results;
Expand Down
Loading

0 comments on commit 34a2a7f

Please sign in to comment.