diff options
3 files changed, 62 insertions, 1 deletions
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<Export*> 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<Function*> 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. diff --git a/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt b/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt new file mode 100644 index 000000000..bdf304ade --- /dev/null +++ b/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt @@ -0,0 +1,27 @@ +(module + (type $FUNCSIG$j (func (result i64))) + (type $FUNCSIG$vi (func (param i32))) + (import "env" "setTempRet0" (func $setTempRet0 (param i32))) + (export "func" (func $legalstub$func)) + (export "orig$func" (func $func)) + (func $func (; 1 ;) (type $FUNCSIG$j) (result i64) + (unreachable) + ) + (func $legalstub$func (; 2 ;) (result i32) + (local $0 i64) + (local.set $0 + (call $func) + ) + (call $setTempRet0 + (i32.wrap_i64 + (i64.shr_u + (local.get $0) + (i64.const 32) + ) + ) + ) + (i32.wrap_i64 + (local.get $0) + ) + ) +) diff --git a/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast b/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast new file mode 100644 index 000000000..4b55fa920 --- /dev/null +++ b/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast @@ -0,0 +1,7 @@ +(module + (export "func" (func $func)) + (func $func (result i64) + (unreachable) + ) +) + |