Skip to content
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

Merged
merged 4 commits into from
Jan 27, 2021
Merged

api: resolving imported globals #637

merged 4 commits into from
Jan 27, 2021

Conversation

gumb0
Copy link
Collaborator

@gumb0 gumb0 commented Nov 10, 2020

This extends resolve_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.

@gumb0 gumb0 force-pushed the resolve-imports branch 4 times, most recently from a4f6818 to e466b25 Compare November 11, 2020 11:15
@codecov
Copy link

codecov bot commented Nov 11, 2020

Codecov Report

Merging #637 (570e8ef) into master (4e4d86f) will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master     #637   +/-   ##
=======================================
  Coverage   99.31%   99.31%           
=======================================
  Files          72       72           
  Lines       10470    10542   +72     
=======================================
+ Hits        10398    10470   +72     
  Misses         72       72           
Flag Coverage Δ
spectests 90.84% <0.00%> (-0.66%) ⬇️
unittests 99.31% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
lib/fizzy/instantiate.hpp 100.00% <ø> (ø)
lib/fizzy/instantiate.cpp 100.00% <100.00%> (ø)
test/unittests/api_test.cpp 100.00% <100.00%> (ø)

@gumb0 gumb0 force-pushed the resolve-imports branch 4 times, most recently from 16202d6 to 11cf068 Compare November 12, 2020 11:02
@gumb0 gumb0 requested review from chfast and axic November 12, 2020 11:09
@gumb0
Copy link
Collaborator Author

gumb0 commented Nov 12, 2020

@chfast @axic Please check that it's an ok direction for resolve API.

I will add tests and header comments next.

lib/fizzy/instantiate.hpp Outdated Show resolved Hide resolved
@chfast
Copy link
Collaborator

chfast commented Nov 12, 2020

@chfast @axic Please check that it's an ok direction for resolve API.

Add description first.

@gumb0
Copy link
Collaborator Author

gumb0 commented Nov 12, 2020

@chfast @axic Please check that it's an ok direction for resolve API.

Add description first.

Added.

Copy link
Collaborator

@chfast chfast left a 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.

// 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,
Copy link
Collaborator

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.

Copy link
Collaborator Author

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},
                     });

Copy link
Collaborator Author

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.

// 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,
Copy link
Member

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

Copy link
Collaborator Author

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?

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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)

Copy link
Collaborator

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.

@gumb0 gumb0 force-pushed the resolve-imports branch 5 times, most recently from 841a720 to af4d025 Compare November 17, 2020 13:27
@gumb0 gumb0 force-pushed the resolve-imports branch 4 times, most recently from 4996a05 to 84c6837 Compare November 18, 2020 18:08
@gumb0 gumb0 changed the title api: resolving imports api: resolving impored globals Nov 18, 2020
throw instantiate_error{"global " + module + "." + name +
" mutability doesn't match imported global in module"};
}

Copy link
Collaborator Author

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)

Copy link
Member

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment.

@gumb0 gumb0 marked this pull request as ready for review November 18, 2020 18:35
@gumb0 gumb0 requested review from axic and chfast November 18, 2020 18:37
@axic axic changed the title api: resolving impored globals api: resolving imported globals Jan 4, 2021
@gumb0 gumb0 force-pushed the resolve-imports branch 3 times, most recently from 29b4829 to 14e1a39 Compare January 5, 2021 15:26
@gumb0
Copy link
Collaborator Author

gumb0 commented Jan 5, 2021

Rebased.

}

external_functions.emplace_back(ExternalFunction{it->function, module_func_type});
external_functions.emplace_back(find_imported_function(
Copy link
Member

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?

Copy link
Collaborator Author

@gumb0 gumb0 Jan 27, 2021

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.

Copy link
Member

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.

Copy link
Collaborator Author

@gumb0 gumb0 Jan 27, 2021

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;
Copy link
Member

@axic axic Jan 27, 2021

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?

Copy link
Collaborator Author

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

Copy link
Member

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.

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 = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const std::vector<ImportedGlobal> imported_globals_invalid_type2 = {
const std::vector<ImportedGlobal> imported_globals_invalid_mutability = {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

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 = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const std::vector<ImportedGlobal> imported_globals_invalid_type1 = {
const std::vector<ImportedGlobal> imported_globals_invalid_type = {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

};

// 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
Copy link
Member

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.

@axic axic merged commit db8f714 into master Jan 27, 2021
@axic axic deleted the resolve-imports branch January 27, 2021 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants