diff options
Diffstat (limited to 'src/passes/LegalizeJSInterface.cpp')
-rw-r--r-- | src/passes/LegalizeJSInterface.cpp | 86 |
1 files changed, 86 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 |