summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/LegalizeJSInterface.cpp86
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--src/passes/passes.h1
3 files changed, 90 insertions, 0 deletions
diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp
index 3ca6b7095..0082ba7ab 100644
--- a/src/passes/LegalizeJSInterface.cpp
+++ b/src/passes/LegalizeJSInterface.cpp
@@ -29,6 +29,12 @@
// across modules, we still want to legalize dynCalls so JS can call into the
// tables even to a signature that is not legal.
//
+// Another variation also "prunes" imports and exports that we cannot yet
+// legalize, like exports and imports with SIMD or multivalue. Until we write
+// the logic to legalize them, removing those imports/exports still allows us to
+// fuzz all the legal imports/exports. (Note that multivalue is supported in
+// exports in newer VMs - node 16+ - so that part is only needed for older VMs.)
+//
#include "asmjs/shared-constants.h"
#include "ir/element-utils.h"
@@ -43,6 +49,8 @@
namespace wasm {
+namespace {
+
// These are aliases for getTempRet0/setTempRet0 which emscripten defines in
// compiler-rt and exports under these names.
static Name GET_TEMP_RET_EXPORT("__get_temp_ret");
@@ -358,10 +366,88 @@ private:
}
};
+struct LegalizeAndPruneJSInterface : public LegalizeJSInterface {
+ // Legalize fully (true) and add pruning on top.
+ LegalizeAndPruneJSInterface() : LegalizeJSInterface(true) {}
+
+ void run(Module* module) override {
+ LegalizeJSInterface::run(module);
+
+ prune(module);
+ }
+
+ void prune(Module* module) {
+ // For each function name, the exported id it is exported with. For
+ // example,
+ //
+ // (func $foo (export "bar")
+ //
+ // Would have exportedFunctions["foo"] = "bar";
+ std::unordered_map<Name, Name> exportedFunctions;
+ for (auto& exp : module->exports) {
+ if (exp->kind == ExternalKind::Function) {
+ exportedFunctions[exp->value] = exp->name;
+ }
+ }
+
+ for (auto& func : module->functions) {
+ // If the function is neither exported nor imported, no problem.
+ auto imported = func->imported();
+ auto exported = exportedFunctions.count(func->name);
+ if (!imported && !exported) {
+ continue;
+ }
+
+ // The params are allowed to be multivalue, but not the results. Otherwise
+ // look for SIMD.
+ auto sig = func->type.getSignature();
+ auto illegal = isIllegal(sig.results);
+ illegal =
+ illegal || std::any_of(sig.params.begin(),
+ sig.params.end(),
+ [&](const Type& t) { return isIllegal(t); });
+ if (!illegal) {
+ continue;
+ }
+
+ // Prune an import by implementing it in a trivial manner.
+ if (imported) {
+ func->module = func->base = Name();
+
+ Builder builder(*module);
+ if (sig.results == Type::none) {
+ func->body = builder.makeNop();
+ } else {
+ func->body =
+ builder.makeConstantExpression(Literal::makeZeros(sig.results));
+ }
+ }
+
+ // Prune an export by just removing it.
+ if (exported) {
+ module->removeExport(exportedFunctions[func->name]);
+ }
+ }
+
+ // TODO: globals etc.
+ }
+
+ bool isIllegal(Type type) {
+ auto features = type.getFeatures();
+ return features.hasSIMD() || features.hasMultivalue();
+ }
+};
+
+} // anonymous namespace
+
Pass* createLegalizeJSInterfacePass() { return new LegalizeJSInterface(true); }
Pass* createLegalizeJSInterfaceMinimallyPass() {
return new LegalizeJSInterface(false);
}
+Pass* createLegalizeAndPruneJSInterfacePass() {
+ return new LegalizeAndPruneJSInterface();
+}
+
} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 1fe81cbfc..6faf77276 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -221,6 +221,9 @@ void PassRegistry::registerPasses() {
"legalizes i64 types on the import/export boundary in a minimal "
"manner, only on things only JS will call",
createLegalizeJSInterfaceMinimallyPass);
+ registerPass("legalize-and-prune-js-interface",
+ "legalizes the import/export boundary and prunes when needed",
+ createLegalizeAndPruneJSInterfacePass);
registerPass("local-cse",
"common subexpression elimination inside basic blocks",
createLocalCSEPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index c3ab7773f..2f188a689 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -67,6 +67,7 @@ Pass* createInliningPass();
Pass* createInliningOptimizingPass();
Pass* createJSPIPass();
Pass* createJ2CLOptsPass();
+Pass* createLegalizeAndPruneJSInterfacePass();
Pass* createLegalizeJSInterfacePass();
Pass* createLegalizeJSInterfaceMinimallyPass();
Pass* createLimitSegmentsPass();