diff options
author | Heejin Ahn <aheejin@gmail.com> | 2020-10-02 09:25:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-02 09:25:15 -0700 |
commit | ecaa818922fe2571649a621a00f7f3c40ebb217a (patch) | |
tree | dd49e1a4f90beb6853ce9f8900b032cbdf54dd83 /src | |
parent | 42aec827c2233eb4adbb56c6d1b23d70399bfac1 (diff) | |
download | binaryen-ecaa818922fe2571649a621a00f7f3c40ebb217a.tar.gz binaryen-ecaa818922fe2571649a621a00f7f3c40ebb217a.tar.bz2 binaryen-ecaa818922fe2571649a621a00f7f3c40ebb217a.zip |
Let GenerateDynCalls generate dynCalls for invokes (#3192)
This moves dynCall generating functionaity for invokes from
`EmscriptenGlueGenerator` to `GenerateDynCalls` pass. So now
`GenerateDynCalls` pass will take care of all cases we need dynCalls:
functions in tables and invokes.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/GenerateDynCalls.cpp | 92 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 5 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 66 |
3 files changed, 87 insertions, 76 deletions
diff --git a/src/passes/GenerateDynCalls.cpp b/src/passes/GenerateDynCalls.cpp index 5a602bd79..8269f6f78 100644 --- a/src/passes/GenerateDynCalls.cpp +++ b/src/passes/GenerateDynCalls.cpp @@ -27,7 +27,7 @@ #include "ir/import-utils.h" #include "pass.h" #include "support/debug.h" -#include "wasm-emscripten.h" +#include "wasm-builder.h" #define DEBUG_TYPE "generate-dyncalls" @@ -36,21 +36,103 @@ namespace wasm { struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> { GenerateDynCalls(bool onlyI64) : onlyI64(onlyI64) {} + void doWalkModule(Module* wasm) { + PostWalker<GenerateDynCalls>::doWalkModule(wasm); + for (auto& sig : invokeSigs) { + generateDynCallThunk(sig); + } + } + void visitTable(Table* table) { + // Generate dynCalls for functions in the table if (table->segments.size() > 0) { - EmscriptenGlueGenerator generator(*getModule()); - generator.onlyI64DynCalls = onlyI64; std::vector<Name> tableSegmentData; for (const auto& indirectFunc : table->segments[0].data) { - generator.generateDynCallThunk( - getModule()->getFunction(indirectFunc)->sig); + generateDynCallThunk(getModule()->getFunction(indirectFunc)->sig); } } } + void visitFunction(Function* func) { + // Generate dynCalls for invokes + if (func->imported() && func->base.startsWith("invoke_")) { + Signature sig = func->sig; + // The first parameter is a pointer to the original function that's called + // by the invoke, so skip it + std::vector<Type> newParams(sig.params.begin() + 1, sig.params.end()); + invokeSigs.insert(Signature(Type(newParams), sig.results)); + } + } + + void generateDynCallThunk(Signature sig); + bool onlyI64; + // The set of all invokes' signatures + std::set<Signature> invokeSigs; }; +static bool hasI64(Signature sig) { + // We only generate dynCall functions for signatures that contain i64. This is + // because any other function can be called directly from JavaScript using the + // wasm table. + for (auto t : sig.results) { + if (t.getID() == Type::i64) { + return true; + } + } + for (auto t : sig.params) { + if (t.getID() == Type::i64) { + return true; + } + } + return false; +} + +static void exportFunction(Module& wasm, Name name, bool must_export) { + if (!wasm.getFunctionOrNull(name)) { + assert(!must_export); + return; + } + if (wasm.getExportOrNull(name)) { + return; // Already exported + } + auto exp = new Export; + exp->name = exp->value = name; + exp->kind = ExternalKind::Function; + wasm.addExport(exp); +} + +void GenerateDynCalls::generateDynCallThunk(Signature sig) { + if (onlyI64 && !hasI64(sig)) { + return; + } + + Module* wasm = getModule(); + Builder builder(*wasm); + Name name = std::string("dynCall_") + getSig(sig.results, sig.params); + if (wasm->getFunctionOrNull(name) || wasm->getExportOrNull(name)) { + return; // module already contains this dyncall + } + std::vector<NameType> params; + params.emplace_back("fptr", Type::i32); // function pointer param + int p = 0; + for (const auto& param : sig.params) { + params.emplace_back(std::to_string(p++), param); + } + Function* f = builder.makeFunction(name, std::move(params), sig.results, {}); + Expression* fptr = builder.makeLocalGet(0, Type::i32); + std::vector<Expression*> args; + Index i = 0; + for (const auto& param : sig.params) { + args.push_back(builder.makeLocalGet(++i, param)); + } + Expression* call = builder.makeCallIndirect(fptr, args, sig); + f->body = call; + + wasm->addFunction(f); + exportFunction(*wasm, f->name, true); +} + Pass* createGenerateDynCallsPass() { return new GenerateDynCalls(false); } Pass* createGenerateI64DynCallsPass() { return new GenerateDynCalls(true); } diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index 7318b01fb..dd5c2009f 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -58,8 +58,6 @@ public: // the file). void separateDataSegments(Output* outfile, Address base); - void generateDynCallThunk(Signature sig); - bool standalone = false; bool sideModule = false; bool minimizeWasmChanges = false; @@ -71,9 +69,6 @@ private: Builder builder; Address stackPointerOffset; bool useStackPointerGlobal; - // Used by generateDynCallThunk to track all the dynCall functions created - // so far. - std::unordered_set<Signature> sigs; }; } // namespace wasm diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 178a0865b..0406ebcb6 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -116,68 +116,6 @@ void EmscriptenGlueGenerator::generatePostInstantiateFunction() { wasm.addExport(ex); } -inline void exportFunction(Module& wasm, Name name, bool must_export) { - if (!wasm.getFunctionOrNull(name)) { - assert(!must_export); - return; - } - if (wasm.getExportOrNull(name)) { - return; // Already exported - } - auto exp = new Export; - exp->name = exp->value = name; - exp->kind = ExternalKind::Function; - wasm.addExport(exp); -} - -static bool hasI64(Signature sig) { - // We only generate dynCall functions for signatures that contain - // i64. This is because any other function can be called directly - // from JavaScript using the wasm table. - for (auto t : sig.results) { - if (t.getID() == Type::i64) { - return true; - } - } - for (auto t : sig.params) { - if (t.getID() == Type::i64) { - return true; - } - } - return false; -} - -void EmscriptenGlueGenerator::generateDynCallThunk(Signature sig) { - if (noDynCalls || (onlyI64DynCalls && !hasI64(sig))) { - return; - } - if (!sigs.insert(sig).second) { - return; // sig is already in the set - } - Name name = std::string("dynCall_") + getSig(sig.results, sig.params); - if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) { - return; // module already contains this dyncall - } - std::vector<NameType> params; - params.emplace_back("fptr", Type::i32); // function pointer param - int p = 0; - for (const auto& param : sig.params) { - params.emplace_back(std::to_string(p++), param); - } - Function* f = builder.makeFunction(name, std::move(params), sig.results, {}); - Expression* fptr = builder.makeLocalGet(0, Type::i32); - std::vector<Expression*> args; - Index i = 0; - for (const auto& param : sig.params) { - args.push_back(builder.makeLocalGet(++i, param)); - } - Expression* call = builder.makeCallIndirect(fptr, args, sig); - f->body = call; - - wasm.addFunction(f); - exportFunction(wasm, f->name, true); -} - // lld can sometimes produce a build with an imported mutable __stack_pointer // (i.e. when linking with -fpie). This method internalizes the // __stack_pointer and initializes it from an immutable global instead. @@ -675,10 +613,6 @@ void EmscriptenGlueGenerator::fixInvokeFunctionNames() { BYN_TRACE("fixInvokeFunctionNames\n"); FixInvokeFunctionNamesWalker walker(wasm); walker.walkModule(&wasm); - BYN_TRACE("generating dyncall thunks\n"); - for (auto sig : walker.invokeSigs) { - generateDynCallThunk(sig); - } } void printSignatures(std::ostream& o, const std::set<Signature>& c) { |