-
Notifications
You must be signed in to change notification settings - Fork 40
C API execute #533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C API execute #533
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,8 +11,86 @@ | |||||
| extern "C" { | ||||||
| #endif | ||||||
|
|
||||||
| /// The opaque data type representing a module. | ||||||
| struct FizzyModule; | ||||||
|
|
||||||
| /// The opaque data type representing an instance (instantiated module). | ||||||
| struct FizzyInstance; | ||||||
|
|
||||||
| /// The data type representing numeric values. | ||||||
| /// | ||||||
| /// i64 member is used to represent values of both i32 and i64 type. | ||||||
| union FizzyValue | ||||||
| { | ||||||
| uint64_t i64; | ||||||
| float f32; | ||||||
| double f64; | ||||||
| }; | ||||||
|
|
||||||
| /// Result of execution of a function. | ||||||
| typedef struct FizzyExecutionResult | ||||||
| { | ||||||
| /// Whether execution ended with a trap. | ||||||
| bool trapped; | ||||||
| /// Whether function returned a value. Valid only if trapped == false | ||||||
| bool has_value; | ||||||
| /// Value returned from a function. Valid only if has_value == true | ||||||
| union FizzyValue value; | ||||||
| } FizzyExecutionResult; | ||||||
|
|
||||||
|
|
||||||
| /// Pointer to external function. | ||||||
| /// | ||||||
| /// @param context Opaque pointer to execution context. | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// @param instance Pointer to module instance. | ||||||
| /// @param args Pointer to the argument array. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can args be null? |
||||||
| /// @param args_size Size of the argument array. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// @param depth Call stack depth. | ||||||
| typedef struct FizzyExecutionResult (*FizzyExternalFn)(void* context, | ||||||
| struct FizzyInstance* instance, const union FizzyValue* args, size_t args_size, int depth); | ||||||
|
|
||||||
| /// External function. | ||||||
| typedef struct FizzyExternalFunction | ||||||
| { | ||||||
| // TODO function type | ||||||
|
|
||||||
| /// Pointer to function. | ||||||
| FizzyExternalFn function; | ||||||
| /// Opaque pointer to execution context, that will be passed to function. | ||||||
| void* context; | ||||||
| } FizzyExternalFunction; | ||||||
|
|
||||||
| /// Validate binary module. | ||||||
| bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size); | ||||||
|
|
||||||
| /// Parse binary module. | ||||||
| struct FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size); | ||||||
|
|
||||||
| /// Free resources associated with the module. | ||||||
| /// | ||||||
| /// Should be called unless @p module was passed to fizzy_instantiate. | ||||||
| void fizzy_free_module(struct FizzyModule* module); | ||||||
|
|
||||||
| /// Instantiate a module. | ||||||
| /// Takes ownership of module, i.e. @p module is invalidated after this call. | ||||||
| /// | ||||||
| /// @param module Pointer to module. | ||||||
| /// @param imported_functions Pointer to the imported function array. | ||||||
| /// @param imported_functions_size Size of the imported function array. | ||||||
| struct FizzyInstance* fizzy_instantiate(struct FizzyModule* module, | ||||||
| const struct FizzyExternalFunction* imported_functions, size_t imported_functions_size); | ||||||
|
|
||||||
| /// Free resources associated with the instance. | ||||||
| void fizzy_free_instance(struct FizzyInstance* instance); | ||||||
|
|
||||||
| /// Execute module function. | ||||||
| /// | ||||||
| /// @param instance Pointer to module instance. | ||||||
| /// @param args Pointer to the argument array. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can args be null? |
||||||
| /// @param depth Call stack depth. | ||||||
| FizzyExecutionResult fizzy_execute( | ||||||
| struct FizzyInstance* instance, uint32_t func_idx, const union FizzyValue* args, int depth); | ||||||
|
|
||||||
| #ifdef __cplusplus | ||||||
| } | ||||||
| #endif | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,76 @@ | |
| // Copyright 2020 The Fizzy Authors. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| #include "cxx20/bit.hpp" | ||
| #include "execute.hpp" | ||
| #include "instantiate.hpp" | ||
| #include "parser.hpp" | ||
| #include <fizzy/fizzy.h> | ||
| #include <memory> | ||
|
|
||
| namespace | ||
| { | ||
| inline FizzyValue wrap(fizzy::Value value) noexcept | ||
| { | ||
| return fizzy::bit_cast<FizzyValue>(value); | ||
| } | ||
|
|
||
| inline fizzy::Value unwrap(FizzyValue value) noexcept | ||
| { | ||
| return fizzy::bit_cast<fizzy::Value>(value); | ||
| } | ||
|
|
||
| inline const FizzyValue* wrap(const fizzy::Value* values) noexcept | ||
| { | ||
| return reinterpret_cast<const FizzyValue*>(values); | ||
| } | ||
|
|
||
| inline const fizzy::Value* unwrap(const FizzyValue* values) noexcept | ||
| { | ||
| return reinterpret_cast<const fizzy::Value*>(values); | ||
| } | ||
|
|
||
| inline FizzyInstance* wrap(fizzy::Instance* instance) noexcept | ||
| { | ||
| return reinterpret_cast<FizzyInstance*>(instance); | ||
| } | ||
|
|
||
| inline fizzy::Instance* unwrap(FizzyInstance* instance) noexcept | ||
| { | ||
| return reinterpret_cast<fizzy::Instance*>(instance); | ||
| } | ||
|
|
||
| inline FizzyExecutionResult wrap(const fizzy::ExecutionResult& result) noexcept | ||
| { | ||
| return {result.trapped, result.has_value, wrap(result.value)}; | ||
| } | ||
|
|
||
| inline fizzy::ExecutionResult unwrap(FizzyExecutionResult result) noexcept | ||
| { | ||
| if (result.trapped) | ||
| return fizzy::Trap; | ||
| else if (!result.has_value) | ||
| return fizzy::Void; | ||
| else | ||
| return unwrap(result.value); | ||
| } | ||
|
|
||
| inline auto unwrap(FizzyExternalFn func, void* context) noexcept | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure this is a good idea, because 1. corresponding Maybe another name for this?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| { | ||
| return [func, context](fizzy::Instance& instance, fizzy::span<const fizzy::Value> args, | ||
| int depth) noexcept -> fizzy::ExecutionResult { | ||
| const auto result = func(context, wrap(&instance), wrap(args.data()), args.size(), depth); | ||
| return unwrap(result); | ||
| }; | ||
| } | ||
| } // namespace | ||
|
|
||
| extern "C" { | ||
| struct FizzyModule | ||
| { | ||
| fizzy::Module module; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realize now, that this is not going to work for the case when we want to access already instantiated module, i.e. get Module has to be dynamically allocated on the C++ side, then on C side module and instance will be represented similarly. |
||
| }; | ||
|
|
||
| bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size) | ||
| { | ||
| try | ||
|
|
@@ -18,4 +84,67 @@ bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size) | |
| return false; | ||
| } | ||
| } | ||
|
|
||
| FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size) | ||
| { | ||
| try | ||
| { | ||
| auto cmodule = std::make_unique<FizzyModule>(); | ||
| cmodule->module = fizzy::parse({wasm_binary, wasm_binary_size}); | ||
| return cmodule.release(); | ||
| } | ||
| catch (...) | ||
| { | ||
| return nullptr; | ||
| } | ||
| } | ||
|
|
||
| void fizzy_free_module(FizzyModule* module) | ||
| { | ||
| delete module; | ||
| } | ||
|
|
||
| FizzyInstance* fizzy_instantiate(FizzyModule* module, | ||
| const FizzyExternalFunction* imported_functions, size_t imported_functions_size) | ||
| { | ||
| try | ||
| { | ||
| // Convert fizzy_external_function to fizzy::ExternalFunction | ||
| std::vector<fizzy::ExternalFunction> functions(imported_functions_size); | ||
| for (size_t imported_func_idx = 0; imported_func_idx < imported_functions_size; | ||
| ++imported_func_idx) | ||
| { | ||
| const auto& cfunc = imported_functions[imported_func_idx]; | ||
|
|
||
| auto func = unwrap(cfunc.function, cfunc.context); | ||
| // TODO get type from input array | ||
| auto func_type = module->module.imported_function_types[imported_func_idx]; | ||
|
|
||
| functions[imported_func_idx] = | ||
| fizzy::ExternalFunction{std::move(func), std::move(func_type)}; | ||
| } | ||
|
|
||
| auto instance = fizzy::instantiate(std::move(module->module), std::move(functions)); | ||
|
|
||
| fizzy_free_module(module); | ||
| return wrap(instance.release()); | ||
| } | ||
| catch (...) | ||
| { | ||
| fizzy_free_module(module); | ||
| return nullptr; | ||
axic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| void fizzy_free_instance(FizzyInstance* instance) | ||
| { | ||
| delete unwrap(instance); | ||
| } | ||
|
|
||
| FizzyExecutionResult fizzy_execute( | ||
| FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args, int depth) | ||
| { | ||
| const auto result = fizzy::execute(*unwrap(instance), func_idx, unwrap(args), depth); | ||
| return wrap(result); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,9 +4,86 @@ | |
|
|
||
| #include <fizzy/fizzy.h> | ||
|
|
||
| bool dummy(void); | ||
| bool validate(const uint8_t* binary, size_t size); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the future, the "compilation test" is to check if the code in the header is valid
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know, but I can imagine the case when the header compiles, but then calling the function doesn't compile in C like you imagine it would.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are unittests for that.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The ones compiled in |
||
| bool parse(const uint8_t* binary, size_t size); | ||
| bool instantiate(const uint8_t* binary, size_t size); | ||
| struct FizzyExecutionResult dummy_host_func(void* context, struct FizzyInstance* instance, | ||
| const union FizzyValue* args, size_t args_size, int depth); | ||
| bool instantiate_with_host_func(const uint8_t* binary, size_t size); | ||
| bool execute(const uint8_t* binary, size_t size); | ||
|
|
||
| bool dummy() | ||
| bool validate(const uint8_t* binary, size_t size) | ||
| { | ||
| return fizzy_validate(NULL, 0); | ||
| return fizzy_validate(binary, size); | ||
| } | ||
|
|
||
| bool parse(const uint8_t* binary, size_t size) | ||
| { | ||
| struct FizzyModule* module = fizzy_parse(binary, size); | ||
| if (!module) | ||
| return false; | ||
|
|
||
| fizzy_free_module(module); | ||
| return true; | ||
| } | ||
|
|
||
| bool instantiate(const uint8_t* binary, size_t size) | ||
| { | ||
| struct FizzyModule* module = fizzy_parse(binary, size); | ||
| if (!module) | ||
| return false; | ||
|
|
||
| struct FizzyInstance* instance = fizzy_instantiate(module, NULL, 0); | ||
| if (!instance) | ||
| return false; | ||
|
|
||
| fizzy_free_instance(instance); | ||
| return true; | ||
| } | ||
|
|
||
| struct FizzyExecutionResult dummy_host_func(void* context, struct FizzyInstance* instance, | ||
| const union FizzyValue* args, size_t args_size, int depth) | ||
| { | ||
| (void)context; | ||
| (void)instance; | ||
| (void)args; | ||
| (void)args_size; | ||
| (void)depth; | ||
| struct FizzyExecutionResult res = {true, false, {0}}; | ||
| return res; | ||
| } | ||
|
|
||
| bool instantiate_with_host_func(const uint8_t* binary, size_t size) | ||
| { | ||
| struct FizzyModule* module = fizzy_parse(binary, size); | ||
| if (!module) | ||
| return false; | ||
|
|
||
| FizzyExternalFunction host_funcs[] = {{dummy_host_func, NULL}}; | ||
|
|
||
| struct FizzyInstance* instance = fizzy_instantiate(module, host_funcs, 1); | ||
| if (!instance) | ||
| return false; | ||
|
|
||
| fizzy_free_instance(instance); | ||
| return true; | ||
| } | ||
|
|
||
| bool execute(const uint8_t* binary, size_t size) | ||
| { | ||
| struct FizzyModule* module = fizzy_parse(binary, size); | ||
| if (!module) | ||
| return false; | ||
|
|
||
| struct FizzyInstance* instance = fizzy_instantiate(module, NULL, 0); | ||
| if (!instance) | ||
| return false; | ||
|
|
||
| fizzy_execute(instance, 0, NULL, 0); | ||
|
|
||
| union FizzyValue args[] = {{1}, {2}}; | ||
| fizzy_execute(instance, 1, args, 0); | ||
|
|
||
| fizzy_free_instance(instance); | ||
| return true; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.