From d53a1e99ee3b856d56545bbbaeb123a1034ebcda Mon Sep 17 00:00:00 2001 From: tDwtp Date: Wed, 28 Sep 2022 22:14:23 +0200 Subject: [PATCH 01/19] module-loading works, but errors! module-loading works, but it will give an error! (and crash) --- src/tools/wasm-interp.cc | 223 +++++++++++++++++++++++++++++++++++---- 1 file changed, 204 insertions(+), 19 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 465ad6116..5ef100ff0 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "src/binary-reader.h" #include "src/error-formatter.h" @@ -39,6 +40,9 @@ using namespace wabt; using namespace wabt::interp; +using ExportMap = std::map; +using Registry = std::map; + static int s_verbose; static const char* s_infile; static Thread::Options s_thread_options; @@ -48,6 +52,7 @@ static bool s_host_print; static bool s_dummy_import_func; static Features s_features; static bool s_wasi; +static std::vector s_modules; static std::vector s_wasi_env; static std::vector s_wasi_argv; static std::vector s_wasi_dirs; @@ -56,6 +61,8 @@ static std::unique_ptr s_log_stream; static std::unique_ptr s_stdout_stream; static std::unique_ptr s_stderr_stream; +static Registry s_registry; + static Store s_store; static const char s_description[] = @@ -110,6 +117,10 @@ 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]:PATH", + "load wasm-module PATH and provide all exports via module-name NAME for imports of following modules", + [](const std::string& argument) { s_modules.push_back(argument); }); parser.AddOption( "run-all-exports", "Run all the exported functions, in order. Useful for testing", @@ -161,33 +172,169 @@ Result RunAllExports(const Instance::Ptr& instance, Errors* errors) { return result; } -static void BindImports(const Module::Ptr& module, RefVec& imports) { +static bool IsHostPrint(const ImportDesc &import) { + return import.type.type->kind == ExternKind::Func && + ((s_host_print && import.type.module == "host" && + import.type.name == "print") || + s_dummy_import_func); +} + +static Ref GenerateHostPrint(const ImportDesc &import) { auto* stream = s_stdout_stream.get(); + auto func_type = *cast(import.type.type.get()); + auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), + import.type.name.c_str()); + + auto host_func = HostFunc::New( + s_store, func_type, + [=](Thread& thread, const Values& params, Values& results, + Trap::Ptr* trap) -> Result { + printf("called host "); + WriteCall(stream, import_name, func_type, params, results, *trap); + return Result::Ok; + }); + + return host_func.ref(); +} + +static Extern::Ptr GetImport(const std::string& module, + const std::string& name) { + auto mod_iter = s_registry.find(module); + if (mod_iter != s_registry.end()) { + auto extern_iter = mod_iter->second.find(name); + if (extern_iter != mod_iter->second.end()) { + return extern_iter->second; + } + } + return {}; +} + +/*static void PopulateImports(const Module::Ptr& module, + RefVec* imports) { + for (auto&& import : module->desc().imports) { + if (IsHostPrint(import)) { + imports->push_back(GenerateHostPrint(import)); + continue; + } + auto extern_ = GetImport(import.type.module, import.type.name); + imports->push_back(extern_ ? extern_.ref() : Ref::Null); + } +}//*/ + +static void PopulateExports(const Instance::Ptr& instance, + Module::Ptr &module, + ExportMap &map) { + map.clear(); + // Module::Ptr module{s_store, instance->module()}; + for (size_t i = 0; i < module->export_types().size(); ++i) { + const ExportType& export_type = module->export_types()[i]; + auto export_ = s_store.UnsafeGet(instance->exports()[i]); + map[export_type.name] = export_; // this is causing me problems + } +} + +/* +void CommandRunner::PopulateExports(const Instance::Ptr& instance, + ExportMap* map) { + map->clear(); + interp::Module::Ptr module{store_, instance->module()}; + for (size_t i = 0; i < module->export_types().size(); ++i) { + const ExportType& export_type = module->export_types()[i]; + (*map)[export_type.name] = store_.UnsafeGet(instance->exports()[i]); + } +} + +wabt::Result CommandRunner::OnModuleCommand(const ModuleCommand* command) { + Errors errors; + auto module = ReadModule(command->filename, &errors); + FormatErrorsToFile(errors, Location::Type::Binary); + + if (!module) { + PrintError(command->line, "error reading module: \"%s\"", + command->filename.c_str()); + return wabt::Result::Error; + } + + RefVec imports; + PopulateImports(module, &imports); + + Trap::Ptr trap; + auto instance = Instance::Instantiate(store_, module.ref(), imports, &trap); + if (trap) { + assert(!instance); + PrintError(command->line, "error instantiating module: \"%s\"", + trap->message().c_str()); + return wabt::Result::Error; + } + + PopulateExports(instance, &last_instance_); + if (!command->name.empty()) { + instances_[command->name] = last_instance_; + } + + return wabt::Result::Ok; +} +//*/ + +static std::string GetPathName(std::string module_arg) { + size_t path_at = module_arg.find_first_of(':'); + + path_at = path_at == std::string::npos ? 0 : path_at+1; + + return module_arg.substr(path_at); +} + +static std::string GetRegistryName(std::string module_arg, + const Module::Ptr& module) { + size_t split_pos = module_arg.find_first_of(':'); + std::string override_name = module_arg.substr(0, split_pos); + std::string path_name = module_arg.substr(split_pos + 1); + std::string debug_name = ""; //GetDebugName(module); + + // check if override_name starts with @ and return override_name + if (override_name[0] == '@') { + return override_name.substr(1); + } + + // if no override_name is provided -> use debug name or filename + if (override_name.empty()) { + // prefer debug_name, if no override_name is provided + if (!debug_name.empty()) { + return debug_name; + } + + // use file_name (without extension) + size_t fstart = path_name.find_last_of("/\\"); + size_t fend = path_name.find_last_of("."); + fstart = fstart == std::string::npos ? 0 : fstart; + fend = fend < fstart ? std::string::npos : fend; + + return path_name.substr(fstart, fend); + } + + // prefer debug_name if override_name starts with '$' + if (override_name[0] == '$' && !debug_name.empty()) { + return debug_name; + } + + // return the override_name (remove leading '$' if present) + bool leading_dollar = override_name[0] == '$'; + return override_name.substr(leading_dollar ? 1:0); +} + +static void BindImports(const Module::Ptr& module, RefVec& imports) { for (auto&& import : module->desc().imports) { - if (import.type.type->kind == ExternKind::Func && - ((s_host_print && import.type.module == "host" && - import.type.name == "print") || - s_dummy_import_func)) { - auto func_type = *cast(import.type.type.get()); - auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), - import.type.name.c_str()); - - auto host_func = HostFunc::New( - s_store, func_type, - [=](Thread& thread, const Values& params, Values& results, - Trap::Ptr* trap) -> Result { - printf("called host "); - WriteCall(stream, import_name, func_type, params, results, *trap); - return Result::Ok; - }); - imports.push_back(host_func.ref()); + if (IsHostPrint(import)) { + imports.push_back(GenerateHostPrint(import)); continue; } // By default, just push an null reference. This won't resolve, and // instantiation will fail. - imports.push_back(Ref::Null); + + Extern::Ptr extern_ = GetImport(import.type.module, import.type.name); + imports.push_back(extern_ ? extern_.ref() : Ref::Null); } } @@ -239,6 +386,43 @@ static Result ReadAndRunModule(const char* module_filename) { RefVec imports; + std::vector modules_loaded(s_modules.size()); + ExportMap load_map; + for (auto import_module : s_modules) { + std::string module_path = GetPathName(import_module); + + Module::Ptr load_module; + result = ReadModule(module_path.c_str(), &errors, &load_module); + if (!Succeeded(result)) { + FormatErrorsToFile(errors, Location::Type::Binary); + return result; + } + + RefVec load_imports; + // PopulateImports(module, &imports); + BindImports(load_module, load_imports); + + /* // this is how wasm-interp.exe does it + Instance::Ptr load_instance; + CHECK_RESULT(InstantiateModule(load_imports, load_module, &load_instance)); + /*/ // this is how spectest-interp.exe does it + Trap::Ptr trap; + auto load_instance = Instance::Instantiate(s_store, load_module.ref(), load_imports, &trap); + if (trap) { + assert(!load_instance); + s_stderr_stream.get()->Writef("error instantiating module: \"%s\"", + trap->message().c_str()); + return wabt::Result::Error; + } + //*/ + + std::string reg_name = GetRegistryName(import_module, load_module); + PopulateExports(load_instance, load_module, load_map); + s_registry[reg_name] = std::move(load_map); + + modules_loaded.push_back(load_module); + } + #if WITH_WASI uvwasi_t uvwasi; #endif @@ -299,6 +483,7 @@ static Result ReadAndRunModule(const char* module_filename) { return Result::Error; #endif } else { + // PopulateImports(module, &imports); BindImports(module, imports); } From b9da00bf983917493ca1b20754911e07ff67be24 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Wed, 28 Sep 2022 23:11:29 +0200 Subject: [PATCH 02/19] removed unnecessary lines and guarded exports unnecessary lines were removed, mostly commented out stuff for testing. guarded the exports, so it wont throw an error with `--dummy-import-func` --- src/tools/wasm-interp.cc | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 5ef100ff0..3cbfeb607 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -210,18 +210,6 @@ static Extern::Ptr GetImport(const std::string& module, return {}; } -/*static void PopulateImports(const Module::Ptr& module, - RefVec* imports) { - for (auto&& import : module->desc().imports) { - if (IsHostPrint(import)) { - imports->push_back(GenerateHostPrint(import)); - continue; - } - auto extern_ = GetImport(import.type.module, import.type.name); - imports->push_back(extern_ ? extern_.ref() : Ref::Null); - } -}//*/ - static void PopulateExports(const Instance::Ptr& instance, Module::Ptr &module, ExportMap &map) { @@ -386,9 +374,11 @@ 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 modules_loaded(s_modules.size()); - ExportMap load_map; for (auto import_module : s_modules) { + ExportMap load_map; std::string module_path = GetPathName(import_module); Module::Ptr load_module; @@ -399,26 +389,18 @@ static Result ReadAndRunModule(const char* module_filename) { } RefVec load_imports; - // PopulateImports(module, &imports); BindImports(load_module, load_imports); - /* // this is how wasm-interp.exe does it + // this is how wasm-interp.exe does it Instance::Ptr load_instance; CHECK_RESULT(InstantiateModule(load_imports, load_module, &load_instance)); - /*/ // this is how spectest-interp.exe does it - Trap::Ptr trap; - auto load_instance = Instance::Instantiate(s_store, load_module.ref(), load_imports, &trap); - if (trap) { - assert(!load_instance); - s_stderr_stream.get()->Writef("error instantiating module: \"%s\"", - trap->message().c_str()); - return wabt::Result::Error; - } - //*/ - std::string reg_name = GetRegistryName(import_module, load_module); - PopulateExports(load_instance, load_module, load_map); - s_registry[reg_name] = std::move(load_map); + // we wont need to register anything, if we only have dummy imports anyway + if (!s_dummy_import_func) { + std::string reg_name = GetRegistryName(import_module, load_module); + PopulateExports(load_instance, load_module, load_map); + s_registry[reg_name] = std::move(load_map); + } modules_loaded.push_back(load_module); } From ff68a0b58bac0001afaa748d04f2fe39c963feb9 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Wed, 28 Sep 2022 23:13:54 +0200 Subject: [PATCH 03/19] forgot to clear the maps clear maps again. fixes error on exit (and removved excess whitespace) --- src/tools/wasm-interp.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 3cbfeb607..c886d9042 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -194,7 +194,7 @@ static Ref GenerateHostPrint(const ImportDesc &import) { WriteCall(stream, import_name, func_type, params, results, *trap); return Result::Ok; }); - + return host_func.ref(); } @@ -482,6 +482,11 @@ static Result ReadAndRunModule(const char* module_filename) { } #endif + for (auto &pair : s_registry) { + pair.second.clear(); + } + s_registry.clear(); + return Result::Ok; } From f1d7371380a38af03443650702090bbf5041d326 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Wed, 28 Sep 2022 23:16:43 +0200 Subject: [PATCH 04/19] no hints needed anymore removed the hint, for `BindImports`to do the same as `PopulateImports`` --- src/tools/wasm-interp.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index c886d9042..0392a2d79 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -465,7 +465,6 @@ static Result ReadAndRunModule(const char* module_filename) { return Result::Error; #endif } else { - // PopulateImports(module, &imports); BindImports(module, imports); } From 86eb626f43b473945edb6b44461ccef69c3a2a82 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Wed, 28 Sep 2022 23:38:52 +0200 Subject: [PATCH 05/19] removed more notes expanded documentation properly clear the maps Clear the maps in the proper place. Also removed more notes, and expanded the documentation --- src/tools/wasm-interp.cc | 67 +++++++++------------------------------- 1 file changed, 15 insertions(+), 52 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 0392a2d79..8619a72e7 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -119,7 +119,9 @@ static void ParseOptions(int argc, char** argv) { [](const std::string& argument) { s_wasi_dirs.push_back(argument); }); parser.AddOption( 'm', "module", "[(@|$)NAME]:PATH", - "load wasm-module PATH and provide all exports via module-name NAME for imports of following modules", + "load wasm-module PATH and provide all exports via module-name NAME for imports of following modules. " + "@ will always use NAME"/*", $ will prefer a given debug-name in the namesection"*/ ". " + "if NAME isn't provided, the file-name without the extension will be used.", [](const std::string& argument) { s_modules.push_back(argument); }); parser.AddOption( "run-all-exports", @@ -222,49 +224,6 @@ static void PopulateExports(const Instance::Ptr& instance, } } -/* -void CommandRunner::PopulateExports(const Instance::Ptr& instance, - ExportMap* map) { - map->clear(); - interp::Module::Ptr module{store_, instance->module()}; - for (size_t i = 0; i < module->export_types().size(); ++i) { - const ExportType& export_type = module->export_types()[i]; - (*map)[export_type.name] = store_.UnsafeGet(instance->exports()[i]); - } -} - -wabt::Result CommandRunner::OnModuleCommand(const ModuleCommand* command) { - Errors errors; - auto module = ReadModule(command->filename, &errors); - FormatErrorsToFile(errors, Location::Type::Binary); - - if (!module) { - PrintError(command->line, "error reading module: \"%s\"", - command->filename.c_str()); - return wabt::Result::Error; - } - - RefVec imports; - PopulateImports(module, &imports); - - Trap::Ptr trap; - auto instance = Instance::Instantiate(store_, module.ref(), imports, &trap); - if (trap) { - assert(!instance); - PrintError(command->line, "error instantiating module: \"%s\"", - trap->message().c_str()); - return wabt::Result::Error; - } - - PopulateExports(instance, &last_instance_); - if (!command->name.empty()) { - instances_[command->name] = last_instance_; - } - - return wabt::Result::Ok; -} -//*/ - static std::string GetPathName(std::string module_arg) { size_t path_at = module_arg.find_first_of(':'); @@ -276,9 +235,12 @@ static std::string GetPathName(std::string module_arg) { static std::string GetRegistryName(std::string module_arg, const Module::Ptr& module) { size_t split_pos = module_arg.find_first_of(':'); - std::string override_name = module_arg.substr(0, split_pos); - std::string path_name = module_arg.substr(split_pos + 1); - std::string debug_name = ""; //GetDebugName(module); + if (split_pos == std::string::npos) { + split_pos = 0; + } + std::string override_name = module_arg.substr(0, split_pos ? split_pos : 0); + std::string path_name = module_arg.substr(split_pos); + std::string debug_name = ""; // GetDebugName(module); // check if override_name starts with @ and return override_name if (override_name[0] == '@') { @@ -481,11 +443,6 @@ static Result ReadAndRunModule(const char* module_filename) { } #endif - for (auto &pair : s_registry) { - pair.second.clear(); - } - s_registry.clear(); - return Result::Ok; } @@ -498,6 +455,12 @@ int ProgramMain(int argc, char** argv) { s_store.setFeatures(s_features); wabt::Result result = ReadAndRunModule(s_infile); + + for (auto &pair : s_registry) { + pair.second.clear(); + } + s_registry.clear(); + return result != wabt::Result::Ok; } From daab8eda8c4573517849be31b46b13030fc64df9 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Thu, 29 Sep 2022 16:20:14 +0200 Subject: [PATCH 06/19] linting and better doc, test expanded linting and improve documentation. test now include new module directive, too. --- src/tools/wasm-interp.cc | 56 +++++++++++++++++++++++---------------- test/help/wasm-interp.txt | 1 + 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 8619a72e7..0f3e1ae85 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -18,10 +18,10 @@ #include #include #include +#include #include #include #include -#include #include "src/binary-reader.h" #include "src/error-formatter.h" @@ -118,10 +118,11 @@ static void ParseOptions(int argc, char** argv) { '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]:PATH", - "load wasm-module PATH and provide all exports via module-name NAME for imports of following modules. " - "@ will always use NAME"/*", $ will prefer a given debug-name in the namesection"*/ ". " - "if NAME isn't provided, the file-name without the extension will be used.", + 'm', "module", "[(@|$)NAME:]FILE", + "load module FILE and provide all exports under NAME for upcoming " + "imports. if NAME is empty, the preference will be used. " + /*"$ prefers the debug-name in the name section, "*/ + "@ prefers file name (without extension).", [](const std::string& argument) { s_modules.push_back(argument); }); parser.AddOption( "run-all-exports", @@ -174,14 +175,14 @@ Result RunAllExports(const Instance::Ptr& instance, Errors* errors) { return result; } -static bool IsHostPrint(const ImportDesc &import) { +static bool IsHostPrint(const ImportDesc& import) { return import.type.type->kind == ExternKind::Func && ((s_host_print && import.type.module == "host" && import.type.name == "print") || - s_dummy_import_func); + s_dummy_import_func); } -static Ref GenerateHostPrint(const ImportDesc &import) { +static Ref GenerateHostPrint(const ImportDesc& import) { auto* stream = s_stdout_stream.get(); auto func_type = *cast(import.type.type.get()); @@ -213,25 +214,36 @@ static Extern::Ptr GetImport(const std::string& module, } static void PopulateExports(const Instance::Ptr& instance, - Module::Ptr &module, - ExportMap &map) { + Module::Ptr& module, + ExportMap& map) { map.clear(); // Module::Ptr module{s_store, instance->module()}; for (size_t i = 0; i < module->export_types().size(); ++i) { const ExportType& export_type = module->export_types()[i]; auto export_ = s_store.UnsafeGet(instance->exports()[i]); - map[export_type.name] = export_; // this is causing me problems + map[export_type.name] = export_; } } static std::string GetPathName(std::string module_arg) { size_t path_at = module_arg.find_first_of(':'); - path_at = path_at == std::string::npos ? 0 : path_at+1; + path_at = path_at == std::string::npos ? 0 : path_at + 1; return module_arg.substr(path_at); } +static std::string FileNameOfPath(std::string path_name) { + // use file_name (without extension) + size_t fstart = path_name.find_last_of("/\\"); + size_t fend = path_name.find_last_of("."); + + fstart = fstart == std::string::npos ? 0 : fstart; + fend = fend < fstart ? std::string::npos : fend; + + return path_name.substr(fstart, fend); +} + static std::string GetRegistryName(std::string module_arg, const Module::Ptr& module) { size_t split_pos = module_arg.find_first_of(':'); @@ -240,11 +252,15 @@ static std::string GetRegistryName(std::string module_arg, } std::string override_name = module_arg.substr(0, split_pos ? split_pos : 0); std::string path_name = module_arg.substr(split_pos); - std::string debug_name = ""; // GetDebugName(module); + std::string debug_name = ""; // GetDebugName(module); // check if override_name starts with @ and return override_name if (override_name[0] == '@') { - return override_name.substr(1); + if (override_name.size() > 1) { + return override_name.substr(1); + } + // ignore debug-name and use filename + return FileNameOfPath(path_name); } // if no override_name is provided -> use debug name or filename @@ -253,14 +269,8 @@ static std::string GetRegistryName(std::string module_arg, if (!debug_name.empty()) { return debug_name; } - // use file_name (without extension) - size_t fstart = path_name.find_last_of("/\\"); - size_t fend = path_name.find_last_of("."); - fstart = fstart == std::string::npos ? 0 : fstart; - fend = fend < fstart ? std::string::npos : fend; - - return path_name.substr(fstart, fend); + return FileNameOfPath(path_name); } // prefer debug_name if override_name starts with '$' @@ -270,7 +280,7 @@ static std::string GetRegistryName(std::string module_arg, // return the override_name (remove leading '$' if present) bool leading_dollar = override_name[0] == '$'; - return override_name.substr(leading_dollar ? 1:0); + return override_name.substr(leading_dollar ? 1 : 0); } static void BindImports(const Module::Ptr& module, RefVec& imports) { @@ -456,7 +466,7 @@ int ProgramMain(int argc, char** argv) { wabt::Result result = ReadAndRunModule(s_infile); - for (auto &pair : s_registry) { + for (auto& pair : s_registry) { pair.second.clear(); } s_registry.clear(); diff --git a/test/help/wasm-interp.txt b/test/help/wasm-interp.txt index f6dc26b70..cf8f77c4a 100644 --- a/test/help/wasm-interp.txt +++ b/test/help/wasm-interp.txt @@ -48,6 +48,7 @@ options: --wasi Assume input module is WASI compliant (Export WASI API the the module and invoke _start function) -e, --env=ENV Pass the given environment string in the WASI runtime -d, --dir=DIR Pass the given directory the the WASI runtime + -m, --module=[(@|$)NAME:]FILE load module FILE and provide all exports under NAME for upcoming imports. if NAME is empty, the preference will be used. @ prefers file name (without extension). --run-all-exports Run all the exported functions, in order. Useful for testing --host-print Include an importable function named "host.print" for printing to stdout --dummy-import-func Provide a dummy implementation of all imported functions. The function will log the call and return an appropriate zero value. From d77a735000a911c8dc63730316c8edbdceb940ef Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 1 Oct 2022 19:01:25 +0200 Subject: [PATCH 07/19] wasi working again made wasi work again. older version would only allow wasi in last module. --- src/interp/interp-wasi.cc | 125 +++++++++--------- src/interp/interp-wasi.h | 12 +- src/tools/wasm-interp.cc | 258 +++++++++++++++++++++----------------- 3 files changed, 215 insertions(+), 180 deletions(-) diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index 61b6f71d0..e3e1b4a7f 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -35,6 +35,7 @@ #include "uvwasi.h" +#include #include #include @@ -652,85 +653,90 @@ std::unordered_map wasiInstances; namespace wabt { namespace interp { -Result WasiBindImports(const Module::Ptr& module, - RefVec& imports, - Stream* stream, - Stream* trace_stream) { - Store* store = module.store(); - for (auto&& import : module->desc().imports) { - if (import.type.type->kind != ExternKind::Func) { - stream->Writef("wasi error: invalid import type: %s\n", - import.type.name.c_str()); - return Result::Error; +Result RegisterWasiInstance(const Instance::Ptr& instance, + uvwasi_s* uvwasi, + Stream* err_stream, + Stream* trace_stream) { + Store* store = instance.store(); + auto module = store->UnsafeGet(instance->module()); + auto&& module_desc = module->desc(); + + Memory::Ptr memory; + for (auto&& export_ : module_desc.exports) { + if (export_.type.name == "memory") { + if (export_.type.type->kind != ExternalKind::Memory) { + err_stream->Writef("wasi error: memory export has incorrect type\n"); + return Result::Error; + } + memory = store->UnsafeGet(instance->memories()[export_.index]); + break; } + } - if (import.type.module != "wasi_snapshot_preview1" && - import.type.module != "wasi_unstable") { - stream->Writef("wasi error: unknown module import: `%s`\n", - import.type.module.c_str()); - return Result::Error; - } + if (!memory) { + err_stream->Writef("wasi error: memory export not found\n"); + return Result::Error; + } + + WasiInstance* wasi = new WasiInstance(instance, uvwasi, std::move(memory).get(), trace_stream); + wasiInstances[instance.get()] = std::move(wasi); - auto func_type = *cast(import.type.type.get()); - auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), - import.type.name.c_str()); - HostFunc::Ptr host_func; + return Result::Ok; +} - // TODO(sbc): Validate signatures of imports. -#define WASI_FUNC(NAME) \ - if (import.type.name == #NAME) { \ - host_func = HostFunc::New(*store, func_type, NAME); \ - goto found; \ +void UnregisterWasiInstance(const Instance::Ptr& instance) { + WasiInstance* wasi = wasiInstances[instance.get()]; + if (wasi) { + wasiInstances.erase(instance.get()); + delete wasi; } -#include "wasi_api.def" -#undef WASI_FUNC +} - stream->Writef("unknown wasi API import: `%s`\n", import.type.name.c_str()); - return Result::Error; - found: - imports.push_back(host_func.ref()); +Ref WasiGetImport(const Module::Ptr& module, const ImportDesc& import) { + auto func_type = *cast(import.type.type.get()); + HostFunc::Ptr host_func; + Store* store = module.store(); + + // TODO(sbc): Validate signatures of imports. +#define WASI_FUNC(NAME) \ + if (import.type.name == #NAME) { \ + return HostFunc::New(*store, func_type, NAME).ref(); \ } +#include "wasi_api.def" +#undef WASI_FUNC - return Result::Ok; + return Ref::Null; } -Result WasiRunStart(const Instance::Ptr& instance, - uvwasi_s* uvwasi, - Stream* err_stream, - Stream* trace_stream) { +static Result FindWasiEntryPoint(const Instance::Ptr& instance, + Stream* err_stream, + Func::Ptr* entry_func) { Store* store = instance.store(); auto module = store->UnsafeGet(instance->module()); auto&& module_desc = module->desc(); - Func::Ptr start; - Memory::Ptr memory; for (auto&& export_ : module_desc.exports) { - if (export_.type.name == "memory") { - if (export_.type.type->kind != ExternalKind::Memory) { - err_stream->Writef("wasi error: memory export has incorrect type\n"); - return Result::Error; - } - memory = store->UnsafeGet(instance->memories()[export_.index]); - } if (export_.type.name == "_start") { if (export_.type.type->kind != ExternalKind::Func) { err_stream->Writef("wasi error: _start export is not a function\n"); return Result::Error; } - start = store->UnsafeGet(instance->funcs()[export_.index]); + *entry_func = store->UnsafeGet(instance->funcs()[export_.index]); + return Result::Ok; } - if (start && memory) { - break; - } - } - - if (!start) { - err_stream->Writef("wasi error: _start export not found\n"); - return Result::Error; } + return Result::Error; +} - if (!memory) { - err_stream->Writef("wasi error: memory export not found\n"); +Result WasiRunStart(const Instance::Ptr& instance, + uvwasi_s* uvwasi, + Stream* err_stream, + Stream* trace_stream) { + Func::Ptr start; + Result found = FindWasiEntryPoint(instance, err_stream, &start); + if (found == Result::Error) { + err_stream->Writef("wasi error: " + "_start export not a function or not found\n"); return Result::Error; } @@ -739,11 +745,8 @@ Result WasiRunStart(const Instance::Ptr& instance, return Result::Error; } - // Register memory - WasiInstance wasi(instance, uvwasi, memory.get(), trace_stream); - wasiInstances[instance.get()] = &wasi; - // Call start ([] -> []) + Store* store = instance.store(); Values params; Values results; Trap::Ptr trap; @@ -753,7 +756,7 @@ Result WasiRunStart(const Instance::Ptr& instance, } // Unregister memory - wasiInstances.erase(instance.get()); + UnregisterWasiInstance(instance); return res; } diff --git a/src/interp/interp-wasi.h b/src/interp/interp-wasi.h index 465d176c6..a3e0de471 100644 --- a/src/interp/interp-wasi.h +++ b/src/interp/interp-wasi.h @@ -28,10 +28,14 @@ struct uvwasi_s; namespace wabt { namespace interp { -Result WasiBindImports(const Module::Ptr& module, - RefVec& imports, - Stream* err_stream, - Stream* trace_stream); +Result RegisterWasiInstance(const Instance::Ptr& instance, + uvwasi_s* uvwasi, + Stream* stream, + Stream* trace_stream); + +void UnregisterWasiInstance(const Instance::Ptr& instance); + +Ref WasiGetImport(const Module::Ptr& module, const ImportDesc& import); Result WasiRunStart(const Instance::Ptr& instance, uvwasi_s* uvwasi, diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 0f3e1ae85..c1d0105f1 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -40,14 +40,15 @@ using namespace wabt; using namespace wabt::interp; -using ExportMap = std::map; -using Registry = std::map; +using ExportMap = std::unordered_map; +using Registry = std::unordered_map; static int s_verbose; static const char* s_infile; static Thread::Options s_thread_options; static Stream* s_trace_stream; static bool s_run_all_exports; +static bool s_continue_wasi_argv = false; static bool s_host_print; static bool s_dummy_import_func; static Features s_features; @@ -139,7 +140,10 @@ static void ParseOptions(int argc, char** argv) { []() { s_dummy_import_func = true; }); parser.AddArgument("filename", OptionParser::ArgumentCount::One, - [](const char* argument) { s_infile = argument; }); + [](const char* argument) { + s_modules.push_back(argument); + s_infile = argument; + }); parser.AddArgument( "arg", OptionParser::ArgumentCount::ZeroOrMore, [](const char* argument) { s_wasi_argv.push_back(argument); }); @@ -177,11 +181,28 @@ Result RunAllExports(const Instance::Ptr& instance, Errors* errors) { static bool IsHostPrint(const ImportDesc& import) { return import.type.type->kind == ExternKind::Func && - ((s_host_print && import.type.module == "host" && - import.type.name == "print") || - s_dummy_import_func); + (s_host_print && + import.type.module == "host" && + import.type.name == "print"); } +#if WITH_WASI +static bool IsWasiImport(const ImportDesc& import) { + return import.type.type->kind == ExternKind::Func && + (import.type.module == "wasi_snapshot_preview1" || + import.type.module == "wasi_unstable"); +} + +static bool HasWasiImport(const Module::Ptr module) { + for (auto&& import : module->desc().imports) { + if (IsWasiImport(import)) { + return true; + } + } + return false; +} +#endif + static Ref GenerateHostPrint(const ImportDesc& import) { auto* stream = s_stdout_stream.get(); @@ -193,7 +214,6 @@ static Ref GenerateHostPrint(const ImportDesc& import) { s_store, func_type, [=](Thread& thread, const Values& params, Values& results, Trap::Ptr* trap) -> Result { - printf("called host "); WriteCall(stream, import_name, func_type, params, results, *trap); return Result::Ok; }); @@ -244,43 +264,33 @@ static std::string FileNameOfPath(std::string path_name) { return path_name.substr(fstart, fend); } +static std::string GetDebugName(const Module::Ptr& module) { + // TODO: query debug_name + return ""; +} + static std::string GetRegistryName(std::string module_arg, const Module::Ptr& module) { size_t split_pos = module_arg.find_first_of(':'); if (split_pos == std::string::npos) { split_pos = 0; } - std::string override_name = module_arg.substr(0, split_pos ? split_pos : 0); - std::string path_name = module_arg.substr(split_pos); - std::string debug_name = ""; // GetDebugName(module); - - // check if override_name starts with @ and return override_name - if (override_name[0] == '@') { - if (override_name.size() > 1) { - return override_name.substr(1); - } - // ignore debug-name and use filename - return FileNameOfPath(path_name); - } + std::string override_name = module_arg.substr(0, split_pos); + std::string path_name = module_arg.substr(split_pos ? split_pos + 1 : split_pos); + std::string debug_name = GetDebugName(module); - // if no override_name is provided -> use debug name or filename - if (override_name.empty()) { - // prefer debug_name, if no override_name is provided - if (!debug_name.empty()) { - return debug_name; - } - // use file_name (without extension) - return FileNameOfPath(path_name); + // use override_name if present + if (!override_name.empty()) { + return override_name; } - // prefer debug_name if override_name starts with '$' - if (override_name[0] == '$' && !debug_name.empty()) { + // prefer debug_name + if (!debug_name.empty()) { return debug_name; } - // return the override_name (remove leading '$' if present) - bool leading_dollar = override_name[0] == '$'; - return override_name.substr(leading_dollar ? 1 : 0); + // fall back to file-name + return FileNameOfPath(path_name); } static void BindImports(const Module::Ptr& module, RefVec& imports) { @@ -290,11 +300,26 @@ static void BindImports(const Module::Ptr& module, RefVec& imports) { continue; } +#if WITH_WASI + // If there are wasi imports, we need to make a new instance for it + if (IsWasiImport(import)) { + imports.push_back(WasiGetImport(module, import)); + continue; + } +#endif + // By default, just push an null reference. This won't resolve, and // instantiation will fail. Extern::Ptr extern_ = GetImport(import.type.module, import.type.name); - imports.push_back(extern_ ? extern_.ref() : Ref::Null); + if (extern_) { + imports.push_back(extern_.ref()); + continue; + } + + // only populate missing imports for dummy-import-func + imports.push_back(s_dummy_import_func ? + GenerateHostPrint(import) : Ref::Null); } } @@ -335,20 +360,84 @@ static Result InstantiateModule(RefVec& imports, return Result::Ok; } +static Result InitWasi(uvwasi_t* uvwasi) { + uvwasi_errno_t err; + uvwasi_options_t init_options; + + std::vector argv; + argv.push_back(s_infile); + for (auto& s : s_wasi_argv) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str()); + } + argv.push_back(s.c_str()); + } + argv.push_back(nullptr); + + std::vector envp; + for (auto& s : s_wasi_env) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: env: \"%s\"\n", s.c_str()); + } + envp.push_back(s.c_str()); + } + envp.push_back(nullptr); + + std::vector dirs; + for (auto& dir : s_wasi_dirs) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: dir: \"%s\"\n", dir.c_str()); + } + dirs.push_back({dir.c_str(), dir.c_str()}); + } + + /* Setup the initialization options. */ + init_options.in = 0; + init_options.out = 1; + init_options.err = 2; + init_options.fd_table_size = 3; + init_options.argc = argv.size() - 1; + init_options.argv = argv.data(); + init_options.envp = envp.data(); + init_options.preopenc = dirs.size(); + init_options.preopens = dirs.data(); + init_options.allocator = NULL; + + err = uvwasi_init(uvwasi, &init_options); + if (err != UVWASI_ESUCCESS) { + s_stderr_stream.get()->Writef("error initialiazing uvwasi: %d\n", err); + return Result::Error; + } + return Result::Ok; +} + static Result ReadAndRunModule(const char* module_filename) { Errors errors; - Module::Ptr module; - Result result = ReadModule(module_filename, &errors, &module); - if (!Succeeded(result)) { - FormatErrorsToFile(errors, Location::Type::Binary); - return result; - } + Result result; +#if WITH_WASI + uvwasi_t uvwasi; +#endif - RefVec imports; + if (s_wasi) { +#if WITH_WASI + result = InitWasi(&uvwasi); + if (result == Result::Error) { + return result; + } + // CHECK_RESULT(WasiBindImports(modules_loaded.back(), imports, s_stderr_stream.get(), + // s_trace_stream)); +#else + s_stderr_stream.get()->Writef("wasi support not compiled in\n"); + return Result::Error; +#endif + } + // First PopulateExports + // then reference all BindImports // if we only have dummy imports, we wont need to reghister anything // but we still want to load them. std::vector modules_loaded(s_modules.size()); + std::vector instance_loaded(s_modules.size()); for (auto import_module : s_modules) { ExportMap load_map; std::string module_path = GetPathName(import_module); @@ -363,95 +452,37 @@ static Result ReadAndRunModule(const char* module_filename) { RefVec load_imports; BindImports(load_module, load_imports); - // this is how wasm-interp.exe does it Instance::Ptr load_instance; CHECK_RESULT(InstantiateModule(load_imports, load_module, &load_instance)); - // we wont need to register anything, if we only have dummy imports anyway - if (!s_dummy_import_func) { - std::string reg_name = GetRegistryName(import_module, load_module); - PopulateExports(load_instance, load_module, load_map); - s_registry[reg_name] = std::move(load_map); - } - - modules_loaded.push_back(load_module); - } - -#if WITH_WASI - uvwasi_t uvwasi; -#endif + instance_loaded.push_back(load_instance); - if (s_wasi) { #if WITH_WASI - uvwasi_errno_t err; - uvwasi_options_t init_options; - - std::vector argv; - argv.push_back(module_filename); - for (auto& s : s_wasi_argv) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str()); - } - argv.push_back(s.c_str()); - } - argv.push_back(nullptr); - - std::vector envp; - for (auto& s : s_wasi_env) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: env: \"%s\"\n", s.c_str()); - } - envp.push_back(s.c_str()); + if (HasWasiImport(load_module)) { + RegisterWasiInstance(load_instance, &uvwasi, s_stderr_stream.get(), s_trace_stream); } - envp.push_back(nullptr); +#endif - std::vector dirs; - for (auto& dir : s_wasi_dirs) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: dir: \"%s\"\n", dir.c_str()); - } - dirs.push_back({dir.c_str(), dir.c_str()}); - } + std::string reg_name = GetRegistryName(import_module, load_module); + PopulateExports(load_instance, load_module, load_map); + s_registry[reg_name] = std::move(load_map); - /* Setup the initialization options. */ - init_options.in = 0; - init_options.out = 1; - init_options.err = 2; - init_options.fd_table_size = 3; - init_options.argc = argv.size() - 1; - init_options.argv = argv.data(); - init_options.envp = envp.data(); - init_options.preopenc = dirs.size(); - init_options.preopens = dirs.data(); - init_options.allocator = NULL; - - err = uvwasi_init(&uvwasi, &init_options); - if (err != UVWASI_ESUCCESS) { - s_stderr_stream.get()->Writef("error initialiazing uvwasi: %d\n", err); - return Result::Error; - } - CHECK_RESULT(WasiBindImports(module, imports, s_stderr_stream.get(), - s_trace_stream)); -#else - s_stderr_stream.get()->Writef("wasi support not compiled in\n"); - return Result::Error; -#endif - } else { - BindImports(module, imports); + modules_loaded.push_back(load_module); } - Instance::Ptr instance; - CHECK_RESULT(InstantiateModule(imports, module, &instance)); - if (s_run_all_exports) { - RunAllExports(instance, &errors); + RunAllExports(instance_loaded.back(), &errors); } #ifdef WITH_WASI if (s_wasi) { CHECK_RESULT( - WasiRunStart(instance, &uvwasi, s_stderr_stream.get(), s_trace_stream)); + WasiRunStart(instance_loaded.back(), &uvwasi, s_stderr_stream.get(), s_trace_stream)); } #endif + // unregister all; + for (auto&& instance : instance_loaded) { + UnregisterWasiInstance(instance); + } return Result::Ok; } @@ -466,9 +497,6 @@ int ProgramMain(int argc, char** argv) { wabt::Result result = ReadAndRunModule(s_infile); - for (auto& pair : s_registry) { - pair.second.clear(); - } s_registry.clear(); return result != wabt::Result::Ok; From b2a63ba6cf08acebc7c0e66331af457ac7e1adf7 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 1 Oct 2022 19:23:37 +0200 Subject: [PATCH 08/19] updated help and test file help is now updated to reflect the changes --- src/tools/wasm-interp.cc | 28 ++++++++++++++++++++-------- test/help/wasm-interp.txt | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index c1d0105f1..6e7cf8c50 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -119,11 +119,10 @@ static void ParseOptions(int argc, char** argv) { '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", + 'm', "module", "[NAME:]FILE", "load module FILE and provide all exports under NAME for upcoming " - "imports. if NAME is empty, the preference will be used. " - /*"$ prefers the debug-name in the name section, "*/ - "@ prefers file name (without extension).", + "imports. if NAME is empty, the debug-name from the name section " + "will be used if present, the filename elsewise.", [](const std::string& argument) { s_modules.push_back(argument); }); parser.AddOption( "run-all-exports", @@ -139,14 +138,27 @@ static void ParseOptions(int argc, char** argv) { "will log the call and return an appropriate zero value.", []() { s_dummy_import_func = true; }); - parser.AddArgument("filename", OptionParser::ArgumentCount::One, + parser.AddArgument("filename+", OptionParser::ArgumentCount::One, [](const char* argument) { s_modules.push_back(argument); s_infile = argument; - }); + }); parser.AddArgument( - "arg", OptionParser::ArgumentCount::ZeroOrMore, - [](const char* argument) { s_wasi_argv.push_back(argument); }); + ". arg", OptionParser::ArgumentCount::ZeroOrMore, + [](const char* argument) { + if (s_continue_wasi_argv) { + s_wasi_argv.push_back(argument); + return; + } + + if (std::string(argument) == ".") { + s_continue_wasi_argv = true; + return; + } + + s_modules.push_back(argument); + s_infile = argument; + }); parser.Parse(argc, argv); } diff --git a/test/help/wasm-interp.txt b/test/help/wasm-interp.txt index cf8f77c4a..d2409c159 100644 --- a/test/help/wasm-interp.txt +++ b/test/help/wasm-interp.txt @@ -48,7 +48,7 @@ options: --wasi Assume input module is WASI compliant (Export WASI API the the module and invoke _start function) -e, --env=ENV Pass the given environment string in the WASI runtime -d, --dir=DIR Pass the given directory the the WASI runtime - -m, --module=[(@|$)NAME:]FILE load module FILE and provide all exports under NAME for upcoming imports. if NAME is empty, the preference will be used. @ prefers file name (without extension). + -m, --module=[NAME:]FILE load module FILE and provide all exports under NAME for upcoming imports. if NAME is empty, the debug-name from the name section will be used if present, the filename elsewise. --run-all-exports Run all the exported functions, in order. Useful for testing --host-print Include an importable function named "host.print" for printing to stdout --dummy-import-func Provide a dummy implementation of all imported functions. The function will log the call and return an appropriate zero value. From 307e91c97c627d55e9827cd75de99333247bc33f Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 18:50:16 +0200 Subject: [PATCH 09/19] resolve conflicts rsolving conflicts --- {src => include/wabt}/interp/interp-wasi.h | 4 ++-- src/interp/interp-wasi.cc | 4 ++-- src/tools/wasm-interp.cc | 27 +++++----------------- 3 files changed, 10 insertions(+), 25 deletions(-) rename {src => include/wabt}/interp/interp-wasi.h (91%) diff --git a/src/interp/interp-wasi.h b/include/wabt/interp/interp-wasi.h similarity index 91% rename from src/interp/interp-wasi.h rename to include/wabt/interp/interp-wasi.h index a3e0de471..fec64c682 100644 --- a/src/interp/interp-wasi.h +++ b/include/wabt/interp/interp-wasi.h @@ -28,12 +28,12 @@ struct uvwasi_s; namespace wabt { namespace interp { -Result RegisterWasiInstance(const Instance::Ptr& instance, +Result WasiRegisterInstance(const Instance::Ptr& instance, uvwasi_s* uvwasi, Stream* stream, Stream* trace_stream); -void UnregisterWasiInstance(const Instance::Ptr& instance); +void WasiUnregisterInstance(const Instance::Ptr& instance); Ref WasiGetImport(const Module::Ptr& module, const ImportDesc& import); diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index e3e1b4a7f..e9b4a98f8 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -653,7 +653,7 @@ std::unordered_map wasiInstances; namespace wabt { namespace interp { -Result RegisterWasiInstance(const Instance::Ptr& instance, +Result WasiRegisterInstance(const Instance::Ptr& instance, uvwasi_s* uvwasi, Stream* err_stream, Stream* trace_stream) { @@ -684,7 +684,7 @@ Result RegisterWasiInstance(const Instance::Ptr& instance, return Result::Ok; } -void UnregisterWasiInstance(const Instance::Ptr& instance) { +void WasiUnregisterInstance(const Instance::Ptr& instance) { WasiInstance* wasi = wasiInstances[instance.get()]; if (wasi) { wasiInstances.erase(instance.get()); diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 6e7cf8c50..b13541fd5 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -138,27 +138,11 @@ static void ParseOptions(int argc, char** argv) { "will log the call and return an appropriate zero value.", []() { s_dummy_import_func = true; }); - parser.AddArgument("filename+", OptionParser::ArgumentCount::One, - [](const char* argument) { - s_modules.push_back(argument); - s_infile = argument; - }); + parser.AddArgument("filename", OptionParser::ArgumentCount::One, + [](const char* argument) { s_infile = argument; }); parser.AddArgument( ". arg", OptionParser::ArgumentCount::ZeroOrMore, - [](const char* argument) { - if (s_continue_wasi_argv) { - s_wasi_argv.push_back(argument); - return; - } - - if (std::string(argument) == ".") { - s_continue_wasi_argv = true; - return; - } - - s_modules.push_back(argument); - s_infile = argument; - }); + [](const char* argument) { s_wasi_argv.push_back(argument); }); parser.Parse(argc, argv); } @@ -448,6 +432,7 @@ static Result ReadAndRunModule(const char* module_filename) { // then reference all BindImports // if we only have dummy imports, we wont need to reghister anything // but we still want to load them. + s_modules.push_back(s_infile); std::vector modules_loaded(s_modules.size()); std::vector instance_loaded(s_modules.size()); for (auto import_module : s_modules) { @@ -471,7 +456,7 @@ static Result ReadAndRunModule(const char* module_filename) { #if WITH_WASI if (HasWasiImport(load_module)) { - RegisterWasiInstance(load_instance, &uvwasi, s_stderr_stream.get(), s_trace_stream); + WasiRegisterInstance(load_instance, &uvwasi, s_stderr_stream.get(), s_trace_stream); } #endif @@ -493,7 +478,7 @@ static Result ReadAndRunModule(const char* module_filename) { #endif // unregister all; for (auto&& instance : instance_loaded) { - UnregisterWasiInstance(instance); + WasiUnregisterInstance(instance); } return Result::Ok; From d4e483338e462d595d8c39d7ead3af2a5095614c Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 21:47:35 +0200 Subject: [PATCH 10/19] satisfy linter adjust whitespace and indentation according to linter --- src/interp/interp-wasi.cc | 10 ++++++---- src/tools/wasm-interp.cc | 21 ++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index e9b4a98f8..7ca2d8ecb 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -660,7 +660,7 @@ Result WasiRegisterInstance(const Instance::Ptr& instance, Store* store = instance.store(); auto module = store->UnsafeGet(instance->module()); auto&& module_desc = module->desc(); - + Memory::Ptr memory; for (auto&& export_ : module_desc.exports) { if (export_.type.name == "memory") { @@ -678,7 +678,8 @@ Result WasiRegisterInstance(const Instance::Ptr& instance, return Result::Error; } - WasiInstance* wasi = new WasiInstance(instance, uvwasi, std::move(memory).get(), trace_stream); + WasiInstance* wasi = + new WasiInstance(instance, uvwasi, std::move(memory).get(), trace_stream); wasiInstances[instance.get()] = std::move(wasi); return Result::Ok; @@ -735,8 +736,9 @@ Result WasiRunStart(const Instance::Ptr& instance, Func::Ptr start; Result found = FindWasiEntryPoint(instance, err_stream, &start); if (found == Result::Error) { - err_stream->Writef("wasi error: " - "_start export not a function or not found\n"); + err_stream->Writef( + "wasi error: " + "_start export not a function or not found\n"); return Result::Error; } diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index b13541fd5..4dd819e57 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -177,14 +177,13 @@ Result RunAllExports(const Instance::Ptr& instance, Errors* errors) { static bool IsHostPrint(const ImportDesc& import) { return import.type.type->kind == ExternKind::Func && - (s_host_print && - import.type.module == "host" && + (s_host_print && import.type.module == "host" && import.type.name == "print"); } #if WITH_WASI static bool IsWasiImport(const ImportDesc& import) { - return import.type.type->kind == ExternKind::Func && + return import.type.type->kind == ExternKind::Func && (import.type.module == "wasi_snapshot_preview1" || import.type.module == "wasi_unstable"); } @@ -272,7 +271,8 @@ static std::string GetRegistryName(std::string module_arg, split_pos = 0; } std::string override_name = module_arg.substr(0, split_pos); - std::string path_name = module_arg.substr(split_pos ? split_pos + 1 : split_pos); + std::string path_name = + module_arg.substr(split_pos ? split_pos + 1 : split_pos); std::string debug_name = GetDebugName(module); // use override_name if present @@ -314,8 +314,8 @@ static void BindImports(const Module::Ptr& module, RefVec& imports) { } // only populate missing imports for dummy-import-func - imports.push_back(s_dummy_import_func ? - GenerateHostPrint(import) : Ref::Null); + imports.push_back(s_dummy_import_func ? GenerateHostPrint(import) + : Ref::Null); } } @@ -420,8 +420,6 @@ static Result ReadAndRunModule(const char* module_filename) { if (result == Result::Error) { return result; } - // CHECK_RESULT(WasiBindImports(modules_loaded.back(), imports, s_stderr_stream.get(), - // s_trace_stream)); #else s_stderr_stream.get()->Writef("wasi support not compiled in\n"); return Result::Error; @@ -456,7 +454,8 @@ static Result ReadAndRunModule(const char* module_filename) { #if WITH_WASI if (HasWasiImport(load_module)) { - WasiRegisterInstance(load_instance, &uvwasi, s_stderr_stream.get(), s_trace_stream); + WasiRegisterInstance(load_instance, &uvwasi, s_stderr_stream.get(), + s_trace_stream); } #endif @@ -472,8 +471,8 @@ static Result ReadAndRunModule(const char* module_filename) { } #ifdef WITH_WASI if (s_wasi) { - CHECK_RESULT( - WasiRunStart(instance_loaded.back(), &uvwasi, s_stderr_stream.get(), s_trace_stream)); + CHECK_RESULT(WasiRunStart(instance_loaded.back(), &uvwasi, + s_stderr_stream.get(), s_trace_stream)); } #endif // unregister all; From baa0e5c4e79dacf6c3cd9ae339aef42ead519367 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 21:50:19 +0200 Subject: [PATCH 11/19] satisfy linter resorted includes according to linter --- src/interp/interp-wasi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index 7e586cc8a..1bdcab7db 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -35,8 +35,8 @@ #include "uvwasi.h" -#include #include +#include #include using namespace wabt; From 523aaa4f9bc917320e826505d679e8a1605843b9 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 22:03:37 +0200 Subject: [PATCH 12/19] correction due to comments on #2009 and the linter corrected and expanded based on the comments of #2009 removed redundant function and adjusted imports. --- src/interp/interp-wasi.cc | 4 +--- src/tools/wasm-interp.cc | 18 ++++-------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index 1bdcab7db..6cf74872a 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -36,7 +36,6 @@ #include "uvwasi.h" #include -#include #include using namespace wabt; @@ -678,9 +677,8 @@ Result WasiRegisterInstance(const Instance::Ptr& instance, return Result::Error; } - WasiInstance* wasi = + wasiInstances[instance.get()] = new WasiInstance(instance, uvwasi, std::move(memory).get(), trace_stream); - wasiInstances[instance.get()] = std::move(wasi); return Result::Ok; } diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 2deab0aec..d51179a2d 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -18,14 +18,15 @@ #include #include #include -#include #include #include +#include #include #include "wabt/binary-reader.h" #include "wabt/error-formatter.h" #include "wabt/feature.h" +#include "wabt/filenames.h" #include "wabt/interp/binary-reader-interp.h" #include "wabt/interp/interp-util.h" #include "wabt/interp/interp-wasi.h" @@ -248,17 +249,6 @@ static std::string GetPathName(std::string module_arg) { return module_arg.substr(path_at); } -static std::string FileNameOfPath(std::string path_name) { - // use file_name (without extension) - size_t fstart = path_name.find_last_of("/\\"); - size_t fend = path_name.find_last_of("."); - - fstart = fstart == std::string::npos ? 0 : fstart; - fend = fend < fstart ? std::string::npos : fend; - - return path_name.substr(fstart, fend); -} - static std::string GetDebugName(const Module::Ptr& module) { // TODO: query debug_name return ""; @@ -286,7 +276,7 @@ static std::string GetRegistryName(std::string module_arg, } // fall back to file-name - return FileNameOfPath(path_name); + return StripExtension(GetBasename(path_name)); } static void BindImports(const Module::Ptr& module, RefVec& imports) { @@ -476,7 +466,7 @@ static Result ReadAndRunModule(const char* module_filename) { } #endif // unregister all; - for (auto&& instance : instance_loaded) { + for (auto& instance : instance_loaded) { WasiUnregisterInstance(instance); } From 18b09f15341cc13c7afe2ac435e6007dcc55ef28 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 22:13:13 +0200 Subject: [PATCH 13/19] type and spelling correction --- src/interp/interp-wasi.cc | 2 +- src/tools/wasm-interp.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interp/interp-wasi.cc b/src/interp/interp-wasi.cc index 6cf74872a..bfdd75812 100644 --- a/src/interp/interp-wasi.cc +++ b/src/interp/interp-wasi.cc @@ -756,7 +756,7 @@ Result WasiRunStart(const Instance::Ptr& instance, } // Unregister memory - UnregisterWasiInstance(instance); + WasiUnregisterInstance(instance); return res; } diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index d51179a2d..b994ecaf6 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -276,7 +276,7 @@ static std::string GetRegistryName(std::string module_arg, } // fall back to file-name - return StripExtension(GetBasename(path_name)); + return std::string(StripExtension(GetBasename(path_name))); } static void BindImports(const Module::Ptr& module, RefVec& imports) { From ba49f1401830a41f765cc7583e65842c567d71f2 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 23:33:45 +0200 Subject: [PATCH 14/19] removed the flag from argumentl ist handling --- src/tools/wasm-interp.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index b994ecaf6..3b38af7b9 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -49,7 +49,6 @@ static const char* s_infile; static Thread::Options s_thread_options; static Stream* s_trace_stream; static bool s_run_all_exports; -static bool s_continue_wasi_argv = false; static bool s_host_print; static bool s_dummy_import_func; static Features s_features; From 50db7e0fd4c52623265e5b570028a995a9ef0c26 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Fri, 14 Oct 2022 23:52:20 +0200 Subject: [PATCH 15/19] place InitWasi correctly inside macro-block forgot to check builds without wasi support. --- src/tools/wasm-interp.cc | 102 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 3b38af7b9..16cdd7a9b 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -196,6 +196,57 @@ static bool HasWasiImport(const Module::Ptr module) { } return false; } + +static Result InitWasi(uvwasi_t* uvwasi) { + uvwasi_errno_t err; + uvwasi_options_t init_options; + + std::vector argv; + argv.push_back(s_infile); + for (auto& s : s_wasi_argv) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str()); + } + argv.push_back(s.c_str()); + } + argv.push_back(nullptr); + + std::vector envp; + for (auto& s : s_wasi_env) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: env: \"%s\"\n", s.c_str()); + } + envp.push_back(s.c_str()); + } + envp.push_back(nullptr); + + std::vector dirs; + for (auto& dir : s_wasi_dirs) { + if (s_trace_stream) { + s_trace_stream->Writef("wasi: dir: \"%s\"\n", dir.c_str()); + } + dirs.push_back({dir.c_str(), dir.c_str()}); + } + + /* Setup the initialization options. */ + init_options.in = 0; + init_options.out = 1; + init_options.err = 2; + init_options.fd_table_size = 3; + init_options.argc = argv.size() - 1; + init_options.argv = argv.data(); + init_options.envp = envp.data(); + init_options.preopenc = dirs.size(); + init_options.preopens = dirs.data(); + init_options.allocator = NULL; + + err = uvwasi_init(uvwasi, &init_options); + if (err != UVWASI_ESUCCESS) { + s_stderr_stream.get()->Writef("error initialiazing uvwasi: %d\n", err); + return Result::Error; + } + return Result::Ok; +} #endif static Ref GenerateHostPrint(const ImportDesc& import) { @@ -345,57 +396,6 @@ static Result InstantiateModule(RefVec& imports, return Result::Ok; } -static Result InitWasi(uvwasi_t* uvwasi) { - uvwasi_errno_t err; - uvwasi_options_t init_options; - - std::vector argv; - argv.push_back(s_infile); - for (auto& s : s_wasi_argv) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str()); - } - argv.push_back(s.c_str()); - } - argv.push_back(nullptr); - - std::vector envp; - for (auto& s : s_wasi_env) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: env: \"%s\"\n", s.c_str()); - } - envp.push_back(s.c_str()); - } - envp.push_back(nullptr); - - std::vector dirs; - for (auto& dir : s_wasi_dirs) { - if (s_trace_stream) { - s_trace_stream->Writef("wasi: dir: \"%s\"\n", dir.c_str()); - } - dirs.push_back({dir.c_str(), dir.c_str()}); - } - - /* Setup the initialization options. */ - init_options.in = 0; - init_options.out = 1; - init_options.err = 2; - init_options.fd_table_size = 3; - init_options.argc = argv.size() - 1; - init_options.argv = argv.data(); - init_options.envp = envp.data(); - init_options.preopenc = dirs.size(); - init_options.preopens = dirs.data(); - init_options.allocator = NULL; - - err = uvwasi_init(uvwasi, &init_options); - if (err != UVWASI_ESUCCESS) { - s_stderr_stream.get()->Writef("error initialiazing uvwasi: %d\n", err); - return Result::Error; - } - return Result::Ok; -} - static Result ReadAndRunModule(const char* module_filename) { Errors errors; Result result; From ca6aa99c0c5f53276fc83a6d3a4d6e73c14d3198 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 15 Oct 2022 00:16:54 +0200 Subject: [PATCH 16/19] again fixed non-wasi build --- src/tools/wasm-interp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 16cdd7a9b..8690c8e35 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -463,11 +463,11 @@ static Result ReadAndRunModule(const char* module_filename) { CHECK_RESULT(WasiRunStart(instance_loaded.back(), &uvwasi, s_stderr_stream.get(), s_trace_stream)); } -#endif // unregister all; for (auto& instance : instance_loaded) { WasiUnregisterInstance(instance); } +#endif return Result::Ok; } From 7f0489a2701a06e815d50eaa16d2416252eb4d72 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 15 Oct 2022 01:03:24 +0200 Subject: [PATCH 17/19] reverted something i removed for testing I added back in `called host` which I removed to better find debugging prompts. --- src/tools/wasm-interp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 8690c8e35..bb20fde07 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -253,7 +253,7 @@ static Ref GenerateHostPrint(const ImportDesc& import) { auto* stream = s_stdout_stream.get(); auto func_type = *cast(import.type.type.get()); - auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), + auto import_name = StringPrintf("called host %s.%s", import.type.module.c_str(), import.type.name.c_str()); auto host_func = HostFunc::New( From 1ed7b4586b05b63afb6dd0206df7c88b96971507 Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 15 Oct 2022 01:05:33 +0200 Subject: [PATCH 18/19] dot removed from old parsing checks removed the dot which was to distinguish between arguments and modules --- src/tools/wasm-interp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index bb20fde07..7d9fb82f8 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -141,7 +141,7 @@ static void ParseOptions(int argc, char** argv) { parser.AddArgument("filename", OptionParser::ArgumentCount::One, [](const char* argument) { s_infile = argument; }); parser.AddArgument( - ". arg", OptionParser::ArgumentCount::ZeroOrMore, + "arg", OptionParser::ArgumentCount::ZeroOrMore, [](const char* argument) { s_wasi_argv.push_back(argument); }); parser.Parse(argc, argv); } From f7160d28788852b366ebcb16d08e22d5fc78e4fe Mon Sep 17 00:00:00 2001 From: tDwtp Date: Sat, 15 Oct 2022 01:44:13 +0200 Subject: [PATCH 19/19] linter update --- src/tools/wasm-interp.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 7d9fb82f8..182c8afa8 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -253,8 +253,9 @@ static Ref GenerateHostPrint(const ImportDesc& import) { auto* stream = s_stdout_stream.get(); auto func_type = *cast(import.type.type.get()); - auto import_name = StringPrintf("called host %s.%s", import.type.module.c_str(), - import.type.name.c_str()); + auto import_name = + StringPrintf("called host %s.%s", import.type.module.c_str(), + import.type.name.c_str()); auto host_func = HostFunc::New( s_store, func_type,