-
Notifications
You must be signed in to change notification settings - Fork 34
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
api: resolving imported globals #637
Conversation
a4f6818
to
e466b25
Compare
Codecov Report
@@ Coverage Diff @@
## master #637 +/- ##
=======================================
Coverage 99.31% 99.31%
=======================================
Files 72 72
Lines 10470 10542 +72
=======================================
+ Hits 10398 10470 +72
Misses 72 72
Flags with carried forward coverage won't be shown. Click here to find out more.
|
16202d6
to
11cf068
Compare
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.
Looks ok, but I'm confused how this was done previously.
lib/fizzy/instantiate.hpp
Outdated
// Create vectors of External* ready to be passed to instantiate. | ||
// imported_* may be in any order, | ||
// but must contain imports for all of the import names defined in the module. | ||
Externals resolve_imports(const Module& module, std::vector<ImportedFunction> imported_functions, |
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 std::span
should be used as the parameters type, but I'm not sure how good our implementation is.
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 tried it, and span
doesn't look suitable here, because it's supposed to be created over existing container (it doesn't have an initializer_list
constructor, because initializer_list
is not a container, but just a temporary), so the vector
would need to be explicitly created on the caller side. Whereas now it's possible to pass just an initializer list.
Now:
auto imports = fizzy::resolve_imported_functions(
*module, {
{"env", "adler32", {fizzy::ValType::i32, fizzy::ValType::i32},
fizzy::ValType::i32, env_adler32},
});
With span
:
auto imports = fizzy::resolve_imported_functions(
*module, std::vector<ImportedFunction>{
{"env", "adler32", {fizzy::ValType::i32, fizzy::ValType::i32},
fizzy::ValType::i32, env_adler32},
});
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 I'll leave it as vector const reference.
lib/fizzy/instantiate.hpp
Outdated
// Create vectors of External* ready to be passed to instantiate. | ||
// imported_* may be in any order, | ||
// but must contain imports for all of the import names defined in the module. | ||
Externals resolve_imports(const Module& module, std::vector<ImportedFunction> imported_functions, |
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 would be nice to structure this differently, from a consumer side:
Externals externals(module);
externals.resolve_global(ExternalGlobal);
externals.resolve_globals(...); // with a span
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.
At what point would it check that all required imports are provided? In a separate bool is_complete()
method?
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 thinks I'm still more in favor of simpler functional API like vector<External*> resolve_imported_*(Module, span<Imported*>)
because the rest of the API is mostly functional.
(Otherwise it seems better to make this a full-fledged builder object with instantiate
method in the end, but then there'll probably be some complications around module
and externals being consumed by instantiate
...)
I will split resolve_imports
into 4 functions for now and will try to use span
.
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'm not convinced this is good design, but I don't think this is important right now. Good API is hard to do on paper, so I will accept whatever forks for Rust currently.
Better is to observe how this works in some real-life examples. We have two of these right now: fizzy-wasi
and FizzyEngine
.
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 general I'm not content either with any of the options for resolve proposed so far, and would just pick something good enough.
(fizzy-wasi
and FizzyEngine
are quite simplistic use cases, as they import only functions. I think any of the options would look fine in them)
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.
My point is we should start with something "good enough" and the tune it based on example integrations, not on intuition nor unit tests.
841a720
to
af4d025
Compare
4996a05
to
84c6837
Compare
84c6837
to
94fab2d
Compare
throw instantiate_error{"global " + module + "." + name + | ||
" mutability doesn't match imported global in 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.
Should we check here also that it->value != nullptr
?
(note that it's checked in instantiate
anyway)
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 is fine as is. Perhaps a comment here could be useful to say that instantiate
will validate the presence of a value.
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.
Added a comment.
874b9ba
to
5a8e3a0
Compare
29b4829
to
14e1a39
Compare
Rebased. |
} | ||
|
||
external_functions.emplace_back(ExternalFunction{it->function, module_func_type}); | ||
external_functions.emplace_back(find_imported_function( |
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.
Is this refactoring changing behaviour? i.e. it would have stopped with instantiate_error
in certain cases, but now it will catch an assert?
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.
No, it just changes the order, the checks for instantiate_error
are moved into find_imported_function
.
Assertion is guaranteed to be true by parser.
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.
Yes I see the checks are moved to find_imported_function
, but now they are executed post assertions.
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.
They are independent - if is checking import's name is present in imported_functions
argument, and assertion is checking that import's function index is valid (must be already ensured by validation).
{ | ||
std::string module; | ||
std::string name; | ||
Value* value = nullptr; |
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.
Hmm, /module
/name
value
does not seem to be used ye?
module
/name
is used in find_imported_global
, but where is value
used?
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.
find_imported_global
puts it into returned ExternalGlobal
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.
Ah yes I missed the return value.
test/unittests/api_test.cpp
Outdated
EXPECT_THROW_MESSAGE(resolve_imported_globals(*module, imported_globals_invalid_type1), | ||
instantiate_error, "global mod1.g1 value type doesn't match imported global in module"); | ||
|
||
const std::vector<ImportedGlobal> imported_globals_invalid_type2 = { |
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.
const std::vector<ImportedGlobal> imported_globals_invalid_type2 = { | |
const std::vector<ImportedGlobal> imported_globals_invalid_mutability = { |
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.
Changed.
test/unittests/api_test.cpp
Outdated
EXPECT_THROW_MESSAGE(resolve_imported_globals(*module, imported_globals_missing), | ||
instantiate_error, "imported global mod2.g2 is required"); | ||
|
||
const std::vector<ImportedGlobal> imported_globals_invalid_type1 = { |
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.
const std::vector<ImportedGlobal> imported_globals_invalid_type1 = { | |
const std::vector<ImportedGlobal> imported_globals_invalid_type = { | |
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.
Changed.
They need to be copied, so there's no point in passing by value.
14e1a39
to
73938d1
Compare
73938d1
to
570e8ef
Compare
}; | ||
|
||
// 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 |
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.
Just realised these comments are no doxygen, neither for resolve_imported_functions
. If we want to doxygenize them, lets do it in a new PR.
This extendsresolve_imported_functions
function into supporting all kinds of imports.I decided to leave here only support for imported globals. Resolving imported table and memory doesn't seem very useful, becasue there's always at most one of each. I suggest to postpone that till we see there's real need to resolve them.
C API part will be in another PR.