From e83a9e2a21b35f19fe56a0d375191369b9b67148 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 11 Nov 2019 15:39:45 -0800 Subject: When legalizing, optionally export the original function too with orig$X (#2427) The original is necessary if we want to pass it to wasm, where it will be called directly, without JS legalization. For example the JS dynamic loader in emscripten needs this, emscripten-core/emscripten#9562 --- src/passes/LegalizeJSInterface.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp index 1404f6894..4dc680972 100644 --- a/src/passes/LegalizeJSInterface.cpp +++ b/src/passes/LegalizeJSInterface.cpp @@ -50,17 +50,42 @@ struct LegalizeJSInterface : public Pass { LegalizeJSInterface(bool full) : full(full) {} void run(PassRunner* runner, Module* module) override { + auto exportOriginals = + !runner->options + .getArgumentOrDefault("legalize-js-interface-export-originals", "") + .empty(); // for each illegal export, we must export a legalized stub instead + std::vector newExports; for (auto& ex : module->exports) { if (ex->kind == ExternalKind::Function) { // if it's an import, ignore it auto* func = module->getFunction(ex->value); if (isIllegal(func) && shouldBeLegalized(ex.get(), func)) { + // Provide a legal function for the export. auto legalName = makeLegalStub(func, module); ex->value = legalName; + if (exportOriginals) { + // Also export the original function, before legalization. This is + // not normally useful for JS, except in cases like dynamic linking + // where the JS loader code must copy exported wasm functions into + // the table, and they must not be legalized as other wasm code will + // do an indirect call to them. However, don't do this for imported + // functions, as those would be legalized in their actual module + // anyhow. It also makes no sense to do this for dynCalls, as they + // are only called from JS. + if (!func->imported() && !isDynCall(ex->name)) { + Builder builder(*module); + Name newName = std::string("orig$") + ex->name.str; + newExports.push_back(builder.makeExport( + newName, func->name, ExternalKind::Function)); + } + } } } } + for (auto* ex : newExports) { + module->addExport(ex); + } // Avoid iterator invalidation later. std::vector originalFunctions; for (auto& func : module->functions) { @@ -136,13 +161,15 @@ private: return t->result == i64; } + bool isDynCall(Name name) { return name.startsWith("dynCall_"); } + // Check if an export should be legalized. bool shouldBeLegalized(Export* ex, Function* func) { if (full) { return true; } // We are doing minimal legalization - just what JS needs. - return ex->name.startsWith("dynCall_"); + return isDynCall(ex->name); } // Check if an import should be legalized. -- cgit v1.2.3