From 6d487190697fd9e58e8993aa6aa41cde18305e2c Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Wed, 5 Apr 2023 00:54:07 +0330 Subject: [PATCH] Utilities: Add support for loading the WASI module to wasm --- Userland/Utilities/wasm.cpp | 66 +++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 2443fe4e07..8e15cbac52 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -278,9 +280,12 @@ ErrorOr serenity_main(Main::Arguments arguments) bool debug = false; bool export_all_imports = false; bool shell_mode = false; + bool wasi = false; DeprecatedString exported_function_to_execute; Vector values_to_push; Vector modules_to_link_in; + Vector args_if_wasi; + Vector wasi_preopened_mappings; Core::ArgsParser parser; parser.add_positional_argument(filename, "File name to parse", "file"); @@ -290,6 +295,21 @@ ErrorOr serenity_main(Main::Arguments arguments) parser.add_option(exported_function_to_execute, "Attempt to execute the named exported function from the module (implies -i)", "execute", 'e', "name"); parser.add_option(export_all_imports, "Export noop functions corresponding to imports", "export-noop", 0); parser.add_option(shell_mode, "Launch a REPL in the module's context (implies -i)", "shell", 's'); + parser.add_option(wasi, "Enable WASI", "wasi", 'w'); + parser.add_option(Core::ArgsParser::Option { + .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, + .help_string = "Directory mappings to expose via WASI", + .long_name = "wasi-map-dir", + .short_name = 0, + .value_name = "path[:path]", + .accept_value = [&](StringView str) { + if (!str.is_empty()) { + wasi_preopened_mappings.append(str); + return true; + } + return false; + }, + }); parser.add_option(Core::ArgsParser::Option { .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, .help_string = "Extra modules to link with, use to resolve imports", @@ -318,6 +338,7 @@ ErrorOr serenity_main(Main::Arguments arguments) return false; }, }); + parser.add_positional_argument(args_if_wasi, "Arguments to pass to the WASI module", "args", Core::ArgsParser::Required::No); parser.parse(arguments); if (shell_mode) { @@ -351,6 +372,34 @@ ErrorOr serenity_main(Main::Arguments arguments) if (attempt_instantiate) { Wasm::AbstractMachine machine; + Optional wasi_impl; + + if (wasi) { + wasi_impl.emplace(Wasm::Wasi::Implementation::Details { + .provide_arguments = [&] { + Vector strings; + for (auto& string : args_if_wasi) + strings.append(String::from_utf8(string).release_value_but_fixme_should_propagate_errors()); + return strings; }, + .provide_environment = {}, + .provide_preopened_directories = [&] { + Vector paths; + for (auto& string : wasi_preopened_mappings) { + auto split_index = string.find(':'); + if (split_index.has_value()) { + LexicalPath host_path { Core::DeprecatedFile::real_path_for(string.substring_view(0, *split_index)) }; + LexicalPath mapped_path { string.substring_view(*split_index + 1) }; + paths.append({move(host_path), move(mapped_path)}); + } else { + LexicalPath host_path { Core::DeprecatedFile::real_path_for(string) }; + LexicalPath mapped_path { string }; + paths.append({move(host_path), move(mapped_path)}); + } + } + return paths; }, + }); + } + Core::EventLoop main_loop; if (debug) { g_line_editor = Line::Editor::construct(); @@ -389,6 +438,23 @@ ErrorOr serenity_main(Main::Arguments arguments) for (auto& instance : linked_instances) linker.link(*instance); + if (wasi) { + HashMap wasi_exports; + for (auto& entry : linker.unresolved_imports()) { + if (entry.module != "wasi_snapshot_preview1"sv) + continue; + auto function = wasi_impl->function_by_name(entry.name); + if (function.is_error()) { + dbgln("wasi function {} not implemented :(", entry.name); + continue; + } + auto address = machine.store().allocate(function.release_value()); + wasi_exports.set(entry, *address); + } + + linker.link(wasi_exports); + } + if (export_all_imports) { HashMap exports; for (auto& entry : linker.unresolved_imports()) {