-
Notifications
You must be signed in to change notification settings - Fork 39
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
C API execute #533
Conversation
5def5eb
to
7537734
Compare
Codecov Report
@@ Coverage Diff @@
## master #533 +/- ##
========================================
Coverage 98.23% 98.24%
========================================
Files 62 62
Lines 9023 9185 +162
========================================
+ Hits 8864 9024 +160
- Misses 159 161 +2 |
cc3402d
to
a2d0e67
Compare
lib/fizzy/capi.cpp
Outdated
delete instance; | ||
} | ||
|
||
fizzy_execution_result fizzy_execute(fizzy_instance* instance, uint32_t func_idx, |
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.
I don't think depth should be part of the public API, @chfast ?
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.
I think it must be. My plan is to convert it to a more generic opaque "ThreadExecutionContext". This is a sneak peak: 5f08ee2.
Of course this is up to discussion.
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.
Yeah, we discussed it a bit when introducing depth
in C++ API. My argument for it is that without it host functions don't have an option to respect the call depth limit (calls to imported functions would reset depth to 0). For example, this test would fail (go into infinite recursion):
fizzy/test/unittests/execute_call_test.cpp
Line 506 in 84abe56
TEST(execute_call, call_imported_infinite_recursion) |
22ba04d
to
7fcde82
Compare
We need to think about a similar feature as "resolve imports" in C++. wabt/wasm3 have something called"add host function". |
e78a350
to
f23345a
Compare
345af61
to
8ffb157
Compare
lib/fizzy/capi.cpp
Outdated
|
||
auto instance = fizzy::instantiate(std::move(module->module), std::move(functions)); | ||
|
||
auto cinstance = std::make_unique<fizzy_instance>(); |
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.
In case C++ function returns a pointer, it will be better to just convert it to opaque type pointer.
reinterpret_cast<fizzy_instance*>(instance.release())
. This is correct, although looks ugly. You can additionally add wrap
/unwrap
functions to have ugliness under control.
fizzy_instance* wrap(Instance* x) { return reinterpret_cast<fizzy_instance*>(x); }
Instance* unwrap(fizzy_instance* x) { return reinterpret_cast<instance*>(x); }
Or alternatively,
fizzy_instance* wrap(std::unique_ptr<Instance> x) { return reinterpret_cast<fizzy_instance*>(x.release()); }
std::unique_ptr<Instance> unwrap(fizzy_instance* x) { return {reinterpret_cast<instance*>(x)}; }
The second one looks better to me as it is clear that after unwrap()
you own the Instance.
Obviously, the Module
is an exception here, so I'm ok with inspecting it some other day.
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.
Yeah this is better. For some reason I thought having Instance&
in other parts of C++ API would make this not possible, but now I think it should work.
@@ -4,9 +4,86 @@ | |||
|
|||
#include <fizzy/fizzy.h> | |||
|
|||
bool dummy(void); | |||
bool validate(const uint8_t* binary, size_t size); |
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.
For the future, the "compilation test" is to check if the code in the header is valid C99
, C11
. The is no need to add code to it.
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.
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.
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.
There are unittests for that.
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.
The ones compiled in C99
and C11
?
TEST(capi, parse) | ||
{ | ||
uint8_t wasm_prefix[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}; | ||
auto module = fizzy_parse(wasm_prefix, sizeof(wasm_prefix)); |
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.
auto module = fizzy_parse(wasm_prefix, sizeof(wasm_prefix)); | |
auto module = fizzy_parse(wasm_prefix, std::size(wasm_prefix)); |
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.
Why is this better?
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.
Counts number of elements, not number of bytes. Here it is the same, so it does not matter.
include/fizzy/fizzy.h
Outdated
/// @param args_size Size of the argument array. | ||
/// @param depth Call stack depth. | ||
typedef struct fizzy_execution_result (*fizzy_external_fn)(void* context, | ||
struct fizzy_instance* instance, const union fizzy_value* args, uint32_t args_size, int depth); |
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.
The uint32_t
will be annoying to use, let's use size_t
for array sizes for now (as in fizzy_validate
, fizzy_parse
, etc).
struct fizzy_instance* instance, const union fizzy_value* args, uint32_t args_size, int depth); | |
struct fizzy_instance* instance, const union fizzy_value* args, size_t args_size, int depth); |
include/fizzy/fizzy.h
Outdated
|
||
/// Free resources associated with the module. | ||
/// | ||
/// Should be called only unless @p module was passed to fizzy_instantiate. |
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.
Opt 1:
/// Should be called only unless @p module was passed to fizzy_instantiate. | |
/// Should be called unless @p module was passed to fizzy_instantiate. |
Opt 2:
/// Should be called only unless @p module was passed to fizzy_instantiate. | |
/// Should be called only if @p module was passed to fizzy_instantiate. |
include/fizzy/fizzy.h
Outdated
/// @param args Pointer to the argument array. | ||
/// @param args_size Size of the argument array. | ||
/// @param depth Call stack depth. | ||
FizzyExecutionResult fizzy_execute(struct FizzyInstance* instance, uint32_t func_idx, |
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.
Why is depth signed?
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.
In C++ we chose it because it's not defined in the spec, int
is a natural type for value involving some arithmetics. Also UBSan can detect overflows for it in tests.
It might be more natural / user-friendly to make it unsigned ot size_t in C.
This needs to add something like |
6871e47
to
c517410
Compare
|
||
/// Pointer to external function. | ||
/// | ||
/// @param context Opaque pointer to execution context. |
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.
/// @param context Opaque pointer to execution context. | |
/// @param context Opaque pointer to execution context. |
/// | ||
/// @param context Opaque pointer to execution context. | ||
/// @param instance Pointer to module instance. | ||
/// @param args Pointer to the argument array. |
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.
Can args be null?
/// @param context Opaque pointer to execution context. | ||
/// @param instance Pointer to module instance. | ||
/// @param args Pointer to the argument array. | ||
/// @param args_size Size of the argument array. |
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.
/// @param args_size Size of the argument array. | |
/// @param args_size Size of the argument array. |
/// Execute module function. | ||
/// | ||
/// @param instance Pointer to module instance. | ||
/// @param args Pointer to the argument array. |
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.
Can args be null?
|
||
extern "C" { | ||
struct FizzyModule | ||
{ | ||
fizzy::Module module; |
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.
I realize now, that this is not going to work for the case when we want to access already instantiated module, i.e. get FizzyModule*
from FizzyInstance*
which owns it.
Module has to be dynamically allocated on the C++ side, then on C side module and instance will be represented similarly.
dfdbfbf
to
6525b9d
Compare
Closing in favor of #576 |
Possible options to deal with module-instance relationship.
PR currently uses 2.b approach.
Copy module during instantiate
Invalidate module in instantiate
2.a.
fizzy_free_module
required after invalidation, so that any module allocated byfizzy_parse
must be freed in the end by the user.2.b. instatiate calls
fizzy_free_module
, so it must not be called by user afterwards.Reference counting
Different ways to implement this on the C++ side:
3.a. double indirection
3.b.
Module
with enabledshared_from_this
: