-
Notifications
You must be signed in to change notification settings - Fork 39
C API execute with dynamically allocated module #576
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
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,104 @@ | |
| extern "C" { | ||
| #endif | ||
|
|
||
| /// The opaque data type representing a module. | ||
| typedef struct FizzyModule FizzyModule; | ||
|
|
||
| /// The opaque data type representing an instance (instantiated module). | ||
| typedef struct FizzyInstance 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 equals false. | ||
| bool has_value; | ||
| /// Value returned from a function. | ||
| /// Valid only if trapped equals false and has_value equals true. | ||
| union FizzyValue value; | ||
| } FizzyExecutionResult; | ||
|
|
||
|
|
||
| /// Pointer to external function. | ||
| /// | ||
| /// @param context Opaque pointer to execution context. | ||
| /// @param instance Pointer to module instance. | ||
| /// @param args Pointer to the argument array. Can be NULL iff args_size equals 0. | ||
| /// @param args_size Size of the argument array. | ||
| /// @param depth Call stack depth. | ||
| typedef FizzyExecutionResult (*FizzyExternalFn)(void* context, 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. | ||
| /// | ||
| /// @returns non-NULL pointer to module in case of success, NULL otherwise. | ||
| const FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size); | ||
|
|
||
| /// Free resources associated with the module. | ||
|
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. Perhaps mention
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. And the same comments apply to instantiate.
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. This calles |
||
| /// | ||
| /// Should be called unless @p module was passed to fizzy_instantiate. | ||
| /// If passed pointer is NULL, has no effect. | ||
| void fizzy_free_module(const 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. Can be NULL iff | ||
| /// imported_functions_size equals 0. | ||
| /// @param imported_functions_size Size of the imported function array. Can be zero. | ||
| /// @returns non-NULL pointer to instance in case of success, NULL otherwise. | ||
| /// | ||
| /// @note | ||
| /// Function expects @a imported_functions to be in the order of imports defined in the module. | ||
| /// No validation is done on the number of functions passed in, nor on their order. | ||
| /// When number of passed functions or their order is different from the one defined by the | ||
| /// module, behaviour is undefined. | ||
| FizzyInstance* fizzy_instantiate(const FizzyModule* module, | ||
| const FizzyExternalFunction* imported_functions, size_t imported_functions_size); | ||
|
|
||
| /// Free resources associated with the instance. | ||
| /// If passed pointer is NULL, has no effect. | ||
| void fizzy_free_instance(FizzyInstance* instance); | ||
|
|
||
| /// Execute module function. | ||
| /// | ||
| /// @param instance Pointer to module instance. | ||
| /// @param args Pointer to the argument array. Can be NULL if function has 0 inputs. | ||
axic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// @param depth Call stack depth. | ||
| /// | ||
| /// @note | ||
| /// No validation is done on the number of arguments passed in @p args, nor on their types. | ||
| /// When number of passed arguments or their types are different from the ones defined by the | ||
| /// function type, behaviour is undefined. | ||
| FizzyExecutionResult fizzy_execute( | ||
| 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,8 +2,79 @@ | |
| // 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 const FizzyModule* wrap(const fizzy::Module* module) noexcept | ||
| { | ||
| return reinterpret_cast<const FizzyModule*>(module); | ||
| } | ||
|
|
||
| inline const fizzy::Module* unwrap(const FizzyModule* module) noexcept | ||
| { | ||
| return reinterpret_cast<const fizzy::Module*>(module); | ||
| } | ||
|
|
||
| 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(const 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 | ||
| { | ||
| 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); | ||
|
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. This takes
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. Both |
||
| }; | ||
| } | ||
| } // namespace | ||
|
|
||
| extern "C" { | ||
| bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size) | ||
|
|
@@ -18,4 +89,65 @@ bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size) | |
| return false; | ||
| } | ||
| } | ||
|
|
||
| const FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size) | ||
| { | ||
| try | ||
| { | ||
| auto module = fizzy::parse({wasm_binary, wasm_binary_size}); | ||
| return wrap(module.release()); | ||
| } | ||
| catch (...) | ||
| { | ||
| return nullptr; | ||
| } | ||
| } | ||
|
|
||
| void fizzy_free_module(const FizzyModule* module) | ||
| { | ||
| delete unwrap(module); | ||
| } | ||
|
|
||
| FizzyInstance* fizzy_instantiate(const 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 = unwrap(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::unique_ptr<const fizzy::Module>(unwrap(module)), std::move(functions)); | ||
|
|
||
| return wrap(instance.release()); | ||
| } | ||
| catch (...) | ||
| { | ||
| return nullptr; | ||
| } | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps mention this returns a non-null module pointer on success.