-
Notifications
You must be signed in to change notification settings - Fork 701
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
wasm-interp: Add multi-module support #2009
base: main
Are you sure you want to change the base?
Conversation
module-loading works, but it will give an error! (and crash)
unnecessary lines were removed, mostly commented out stuff for testing. guarded the exports, so it wont throw an error with `--dummy-import-func`
clear maps again. fixes error on exit (and removved excess whitespace)
removed the hint, for `BindImports`to do the same as `PopulateImports``
Clear the maps in the proper place. Also removed more notes, and expanded the documentation
linting and improve documentation. test now include new module directive, too.
How can I write a test, to check for it to work porperly. |
src/tools/wasm-interp.cc
Outdated
@@ -110,6 +117,13 @@ static void ParseOptions(int argc, char** argv) { | |||
parser.AddOption( | |||
'd', "dir", "DIR", "Pass the given directory the the WASI runtime", | |||
[](const std::string& argument) { s_wasi_dirs.push_back(argument); }); | |||
parser.AddOption( | |||
'm', "module", "[(@|$)NAME:]FILE", |
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 wonder if we can come up with better name for this parameter? How about something like --preload
?
Also perhaps we could just get away without adding a new option here at all and just treat these module like main binary we are running. i.e could we just allow wasm-interp to take any number of binaries as arguments rather than the current limit of just one?
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 wanted module to be used for the import/exprot because thats what its called in the docs of WebAssembly. --preload
would not be to far fetched, but I still think --module
(or just --mod
) would still be best. (You can choose, just wanted to give my reasoning).
Sadly if we want it to interoperate with --wasi
(and as long as we don't have a glue for native libraries) a new option is a must.
I was thinking about multiple different ways, but the OptionParser does not really like them. I cannot specify multiple modules, then a main one, and then optional parameters without some new option to mark the main module. I guessed -m
for conveniance á la '-L"path" -llibname' would be best and in the end just stuck to the -m
/--module
to be more like the other options available.
I was thinking about something to glue native libraries and just have --wasi
be an indicator which native library to give the optional arguments to.
references:
https://webassembly.github.io/spec/core/valid/modules.html#imports
https://webassembly.github.io/spec/core/text/modules.html#imports
https://webassembly.github.io/spec/core/syntax/modules.html#imports
https://webassembly.github.io/spec/core/binary/modules.html#import-section
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.
Still a new option, but if I waht you want, this would be better suited:
we could have an -a, --arg
parameter right before the arguments. I just don't know how to make it optional and still have a list of arguments following 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 now why I did this, only the main module has access to --wasi
the other ones don't.
I first need to figure out how to provide wasi support to all of them, then how to do the --arg
thingy and then I don't mind.
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.
Speaking of -L
.. I wonder if we could have wasi-interp automatically looks for wasm files in certain locations and load them on demand to satisfy imports?
We could even do something fancy like JS import maps: https://github.com/WICG/import-maps
But all that is farther down the line after we land this initial support.
@@ -239,6 +346,37 @@ static Result ReadAndRunModule(const char* module_filename) { | |||
|
|||
RefVec imports; | |||
|
|||
// if we only have dummy imports, we wont need to reghister anything | |||
// but we still want to load them. | |||
std::vector<Module::Ptr> modules_loaded(s_modules.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.
Can we unify the loading of the main module_filename
above with the loading of s_modules
here?
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 was thinking about it early, but dropped it, because I did not understand how it would make it work.
Probably why I have that vector in the first place.
Now on my TODO. After I figure out how to do the module option thingy.
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 I add a Divider to Option Parser?
parser.AddArgument("filename", OptionParser::ArgumentCount::OneOrMore, [...]);
// parser.AddDivider("--", OptionParser::Divider::Optional);
parser.AddArgument("arg", OptionParser::ArgumentCount::ZeroOrMore, [...]);
This way I could distinguish between modules and wasi arguments.
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 think using --
to distinguish between arguments passed to wasi and argument to wasm-interp itself is good idea.
In general I'm a fan of the direction of this PR, and I think we could probably even land with without too much more iteration, but I would also like to be able to iterate on the ergonomics of it. But perhaps we can do a lot of that iteration after first landing 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.
Well: Off I go to find out how to implement that... Possibly wihtout implementing a whole Divider thing.
src/tools/wasm-interp.cc
Outdated
|
||
// return the override_name (remove leading '$' if present) | ||
bool leading_dollar = override_name[0] == '$'; | ||
return override_name.substr(leading_dollar ? 1 : 0); |
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.
Do we need this dollar sign syntax? What about this simpler scheme:
- Override name, if present
- Debug name, if present
- Fall back to file name
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.
We need something to explicitly go for the debug name. I dont want something unexpected. Like downloading a module from the web, and not have it use the filename, because you might not check for the debug name. (just for convenience)
I came up with
override_name
if present- if
override_name == "$"
debug_name if present - Fall back to file_name
if (!override_name.empty()) {
// prefer override_name unless its just "$"
if (override_name != "$") {
return override_name;
}
// prefer debug_name if override_name == "$"
if (!debug_name.empty()) {
return debug_name;
}
}
// fall back to file-name
return FileNameOfPath(path_name);
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.
or we go for this:
- if
override_name == "@"
usefile_name
overriide_name
if presentdebug_name
if present- Fall back to
file_name
Binary compatibility would then be prefered
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 just don't think we need a way to force the file name to be used over the debug name. If you really want to first the filename why not just use the override mechism. e.g -m libfoo:libfoo.wasm.
In other words, always prefer the debug name, but give users an opt out to override if they want to. That would avoid the magic @
thing.
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.
was just for conveniance... But tbh I don't care to much.
Its done already. I removed the magic thingy.
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.
Oh I also can't find a way to get the DebugName, my best guess was it's hidden somewhere in Instance
, but I cant find 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.
@sbc100 minor question, wouldn't it make sense to just ... use all three? Like: Always register by file_name
, if exists register by debug_name
, if exists register by override_name
.
This could be an idea for a revision. And as soon as I findout how to get debug_name
. (It seems like I need to query it manually from the file? The other approaches used in other files are ... complicated)
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 the main thing we need to do before landing this is figure out a way to start testing this.
We can bikeshed the name of the argument as a followup. I would like to remove the magic @
syntax though, since that seems unnecessary for v1.
made wasi work again. older version would only allow wasi in last module.
help is now updated to reflect the changes
wasi is working now. and i change unordered_map and the file fallback. I really tried to make the arguments work, but I would need another argument to parser.AddArgument("arg-name", OptionParser, [callback], std::string stopper); I could also just add it to |
What do you think about renaming this PR to "wasm-interp: Add multi-module support"? |
Awesome, I don't think we need to worry about getting the option separator thing in as part of this change. |
s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str()); | ||
} | ||
argv.push_back(s.c_str()); | ||
result = InitWasi(&uvwasi); |
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.
What do you think aInitWasibout making a separate NFC (non-functional change) which would just refactor all this wasi stuff. i.e. InitWasi, RegisterWasiInstance, etc?
That would make this change much simpler to understand I think.
src/interp/interp-wasi.h
Outdated
Stream* stream, | ||
Stream* trace_stream); | ||
|
||
void UnregisterWasiInstance(const Instance::Ptr& 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.
Can we make all these function symbols start with Wasi
?
Don't have much time for today,
Will revert the hack later.
I have a simple test ready. will add 4 more simple ones at least. Already have them in mind. CU tomorrow. |
rsolving conflicts
I... do not remember how I had planned the tests... I need help again. |
src/interp/interp-wasi.cc
Outdated
@@ -35,6 +35,7 @@ | |||
|
|||
#include "uvwasi.h" | |||
|
|||
#include <cstdio> |
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 needed?
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.
was for testing and finding a memory-leak culprit. is removed. Thanks for the notice ._.
src/tools/wasm-interp.cc
Outdated
} | ||
#endif | ||
// unregister all; | ||
for (auto&& instance : instance_loaded) { |
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 the double &
needed here?
src/tools/wasm-interp.cc
Outdated
return module_arg.substr(path_at); | ||
} | ||
|
||
static std::string FileNameOfPath(std::string path_name) { |
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 you can use GetBasename
+ StripExtension
from wabt/filenames.h
?
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.
Thanks for the notice. I did not even know that exists already.
src/interp/interp-wasi.cc
Outdated
} | ||
|
||
WasiInstance* wasi = new WasiInstance(instance, uvwasi, std::move(memory).get(), trace_stream); | ||
wasiInstances[instance.get()] = std::move(wasi); |
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 std::move
is meaningful on raw pointer.
Maybe just avoid the local and do wasiInstances[instance.get()] = new WasiInstance...
goto found; \ | ||
void WasiUnregisterInstance(const Instance::Ptr& instance) { | ||
WasiInstance* wasi = wasiInstances[instance.get()]; | ||
if (wasi) { |
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.
How about assert(wasi);
and skip the if
check?
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.
It might already be deleted. The main file gets a delete before this happens, which might not be cleared, if _start
was not found or used. See WasiRunStart
. Its just for later, when I might load and clear without any order.
src/interp/interp-wasi.cc
Outdated
@@ -753,7 +756,7 @@ Result WasiRunStart(const Instance::Ptr& instance, | |||
} | |||
|
|||
// Unregister memory | |||
wasiInstances.erase(instance.get()); | |||
UnregisterWasiInstance(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.
This needs to be renamed I think.
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 this line be removed now that the registration and unregistration now all seems to be taken care in wasm-interp.cc?
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.
Nope, You might use it elsewhere (in spec-test for example). I did not want to monolith wasm-interp.cc
.
EDIT: also see: WasiRunStart
adjust whitespace and indentation according to linter
resorted includes according to linter
corrected and expanded based on the comments of WebAssembly#2009 removed redundant function and adjusted imports.
forgot to check builds without wasi support.
I added back in `called host` which I removed to better find debugging prompts.
removed the dot which was to distinguish between arguments and modules
sorry for the many mails... I am still setting stuff up, I moved and did not have my pc set up untill now. |
#2005 feature is finally implemented.
Modules can be loaded via
-m --module=NAME:PATH
Maybe I will expand it in the future to accept dll/so/dylib/bundle as well. I am open for suggestions.
-N --native=mod:lib.so
would be nice, or make--module
more dynamic? *'@' will override the module name
'$' is reserved to prefer prefer the debug name if provided in the name section.
providing no NAME use the file-name. again reserved for the future is to use the debug name given in the name section
* note that native libraries either need some witx glue, or ffi or an API to bind against.