Skip to content

Commit

Permalink
Merge pull request #637 from wasmx/resolve-imports
Browse files Browse the repository at this point in the history
api: resolving imported globals
  • Loading branch information
axic authored Jan 27, 2021
2 parents 4e4d86f + 570e8ef commit db8f714
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 57 deletions.
107 changes: 76 additions & 31 deletions lib/fizzy/instantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,64 @@ Value eval_constant_expression(ConstantExpression expr,
return globals[global_idx - imported_globals.size()];
}

ExternalFunction find_imported_function(const std::string& module, const std::string& name,
const FuncType& module_func_type, const std::vector<ImportedFunction>& imported_functions)
{
const auto it = std::find_if(imported_functions.begin(), imported_functions.end(),
[module, name](const auto& func) { return module == func.module && name == func.name; });

if (it == imported_functions.end())
{
throw instantiate_error{"imported function " + module + "." + name + " is required"};
}

if (module_func_type.inputs != it->inputs)
{
throw instantiate_error{"function " + module + "." + name +
" input types don't match imported function in module"};
}
if (module_func_type.outputs.empty() && it->output.has_value())
{
throw instantiate_error{
"function " + module + "." + name + " has output but is defined void in module"};
}
if (!module_func_type.outputs.empty() &&
(!it->output.has_value() || module_func_type.outputs[0] != *it->output))
{
throw instantiate_error{"function " + module + "." + name +
" output type doesn't match imported function in module"};
}

return {it->function, module_func_type};
}

ExternalGlobal find_imported_global(const std::string& module, const std::string& name,
GlobalType module_global_type, const std::vector<ImportedGlobal>& imported_globals)
{
const auto it = std::find_if(imported_globals.begin(), imported_globals.end(),
[module, name](const auto& func) { return module == func.module && name == func.name; });

if (it == imported_globals.end())
{
throw instantiate_error{"imported global " + module + "." + name + " is required"};
}

if (module_global_type.value_type != it->type)
{
throw instantiate_error{"global " + module + "." + name +
" value type doesn't match imported global in module"};
}
if (module_global_type.is_mutable != it->is_mutable)
{
throw instantiate_error{"global " + module + "." + name +
" mutability doesn't match imported global in module"};
}

// instantiate function will validate whether `it->value` is not nullptr.

return {it->value, module_global_type};
}

std::optional<uint32_t> find_export(const Module& module, ExternalKind kind, std::string_view name)
{
const auto it = std::find_if(module.exportsec.begin(), module.exportsec.end(),
Expand Down Expand Up @@ -375,51 +433,38 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
}

std::vector<ExternalFunction> resolve_imported_functions(
const Module& module, std::vector<ImportedFunction> imported_functions)
const Module& module, const std::vector<ImportedFunction>& imported_functions)
{
std::vector<ExternalFunction> external_functions;
for (const auto& import : module.importsec)
{
if (import.kind != ExternalKind::Function)
continue;

const auto it = std::find_if(
imported_functions.begin(), imported_functions.end(), [&import](const auto& func) {
return import.module == func.module && import.name == func.name;
});

if (it == imported_functions.end())
{
throw instantiate_error{
"imported function " + import.module + "." + import.name + " is required"};
}

assert(import.desc.function_type_index < module.typesec.size());
const auto& module_func_type = module.typesec[import.desc.function_type_index];

if (module_func_type.inputs != it->inputs)
{
throw instantiate_error{"function " + import.module + "." + import.name +
" input types don't match imported function in module"};
}
if (module_func_type.outputs.empty() && it->output.has_value())
{
throw instantiate_error{"function " + import.module + "." + import.name +
" has output but is defined void in module"};
}
if (!module_func_type.outputs.empty() &&
(!it->output.has_value() || module_func_type.outputs[0] != *it->output))
{
throw instantiate_error{"function " + import.module + "." + import.name +
" output type doesn't match imported function in module"};
}

external_functions.emplace_back(ExternalFunction{it->function, module_func_type});
external_functions.emplace_back(find_imported_function(
import.module, import.name, module_func_type, imported_functions));
}

return external_functions;
}

std::vector<ExternalGlobal> resolve_imported_globals(
const Module& module, const std::vector<ImportedGlobal>& imported_globals)
{
std::vector<ExternalGlobal> external_globals;
for (const auto& import : module.importsec)
{
if (import.kind != ExternalKind::Global)
continue;

external_globals.emplace_back(
find_imported_global(import.module, import.name, import.desc.global, imported_globals));
}
return external_globals;
}

std::optional<FuncIdx> find_exported_function(const Module& module, std::string_view name)
{
return find_export(module, ExternalKind::Function, name);
Expand Down
20 changes: 18 additions & 2 deletions lib/fizzy/instantiate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ std::unique_ptr<Instance> instantiate(std::unique_ptr<const Module> module,
std::vector<ExternalGlobal> imported_globals = {},
uint32_t memory_pages_limit = DefaultMemoryPagesLimit);

/// Function that should be used by instantiate as imports, identified by module and function name.
/// Function that should be used by instantiate as import, identified by module and function name.
struct ImportedFunction
{
std::string module;
Expand All @@ -135,7 +135,23 @@ struct ImportedFunction
/// @a imported_functions may be in any order, but must contain functions for all of the imported
/// function names defined in the module.
std::vector<ExternalFunction> resolve_imported_functions(
const Module& module, std::vector<ImportedFunction> imported_functions);
const Module& module, const std::vector<ImportedFunction>& imported_functions);

// Global that should be used by instantiate as import, identified by module and global name.
struct ImportedGlobal
{
std::string module;
std::string name;
Value* value = nullptr;
ValType type = ValType::i32;
bool is_mutable = false;
};

// Create vector of ExternalGlobals ready to be passed to instantiate.
// imported_globals may be in any order, but must contain globals for all of the imported global
// names defined in the module.
std::vector<ExternalGlobal> resolve_imported_globals(
const Module& module, const std::vector<ImportedGlobal>& imported_globals);

/// Find exported function index by name.
std::optional<FuncIdx> find_exported_function(const Module& module, std::string_view name);
Expand Down
Loading

0 comments on commit db8f714

Please sign in to comment.