summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/LegalizeJSInterface.cpp29
-rw-r--r--test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt27
-rw-r--r--test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast7
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)
+ )
+)
+