diff options
author | Sam Clegg <sbc@chromium.org> | 2019-05-10 14:05:16 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-10 14:05:16 -0700 |
commit | 70434ef31994391ae28c4aaaffd0d4f470da7fdc (patch) | |
tree | 0c39bc7be6901d9c32c28c2d7f7d4b131f5d81fb | |
parent | 4b35f384fe753f06c22a04bfa1be056e92f67739 (diff) | |
download | binaryen-70434ef31994391ae28c4aaaffd0d4f470da7fdc.tar.gz binaryen-70434ef31994391ae28c4aaaffd0d4f470da7fdc.tar.bz2 binaryen-70434ef31994391ae28c4aaaffd0d4f470da7fdc.zip |
Generate `dynCall` function for all signature used by `invoke` functions. (#2095)
Previously we were only creating `dynCall` functions for signatures
that we have statically in the table. However for dynamic linking we
may need to invoke functions that we don't have table entries for
(e.g. table entries from a different module).
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 66 |
3 files changed, 46 insertions, 29 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a6885ed13..03e9ec35f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ full changeset diff at the end of each section. Current Trunk ------------- +v84 +--- + +- Generate dynCall thunks for any signatures used in "invoke" calls. + v81 --- diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index 686269a1c..b5673fbd3 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -62,10 +62,14 @@ private: Builder builder; Address stackPointerOffset; bool useStackPointerGlobal; + // Used by generateDynCallThunk to track all the dynCall functions created + // so far. + std::unordered_set<std::string> sigs; Global* getStackPointerGlobal(); Expression* generateLoadStackPointer(); Expression* generateStoreStackPointer(Expression* value); + void generateDynCallThunk(std::string sig); void generateStackSaveFunction(); void generateStackAllocFunction(); void generateStackRestoreFunction(); diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 453780720..57dffb920 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -334,8 +334,36 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) { wasm.addExport(exp); } +void EmscriptenGlueGenerator::generateDynCallThunk(std::string sig) { + auto* funcType = ensureFunctionType(sig, &wasm); + if (!sigs.insert(sig).second) { + return; // sig is already in the set + } + Name name = std::string("dynCall_") + sig; + if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) { + return; // module already contains this dyncall + } + std::vector<NameType> params; + params.emplace_back("fptr", i32); // function pointer param + int p = 0; + for (const auto& ty : funcType->params) { + params.emplace_back(std::to_string(p++), ty); + } + Function* f = + builder.makeFunction(name, std::move(params), funcType->result, {}); + Expression* fptr = builder.makeGetLocal(0, i32); + std::vector<Expression*> args; + for (unsigned i = 0; i < funcType->params.size(); ++i) { + args.push_back(builder.makeGetLocal(i + 1, funcType->params[i])); + } + Expression* call = builder.makeCallIndirect(funcType, fptr, args); + f->body = call; + + wasm.addFunction(f); + exportFunction(wasm, f->name, true); +} + void EmscriptenGlueGenerator::generateDynCallThunks() { - std::unordered_set<std::string> sigs; Builder builder(wasm); std::vector<Name> tableSegmentData; if (wasm.table.segments.size() > 0) { @@ -343,32 +371,7 @@ void EmscriptenGlueGenerator::generateDynCallThunks() { } for (const auto& indirectFunc : tableSegmentData) { std::string sig = getSig(wasm.getFunction(indirectFunc)); - auto* funcType = ensureFunctionType(sig, &wasm); - if (!sigs.insert(sig).second) { - continue; // sig is already in the set - } - Name name = std::string("dynCall_") + sig; - if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) { - continue; // module already contains this dyncall - } - std::vector<NameType> params; - params.emplace_back("fptr", i32); // function pointer param - int p = 0; - for (const auto& ty : funcType->params) { - params.emplace_back(std::to_string(p++), ty); - } - Function* f = - builder.makeFunction(name, std::move(params), funcType->result, {}); - Expression* fptr = builder.makeGetLocal(0, i32); - std::vector<Expression*> args; - for (unsigned i = 0; i < funcType->params.size(); ++i) { - args.push_back(builder.makeGetLocal(i + 1, funcType->params[i])); - } - Expression* call = builder.makeCallIndirect(funcType, fptr, args); - f->body = call; - - wasm.addFunction(f); - exportFunction(wasm, f->name, true); + generateDynCallThunk(sig); } } @@ -769,6 +772,7 @@ struct FixInvokeFunctionNamesWalker std::map<Name, Name> importRenames; std::vector<Name> toRemove; std::set<Name> newImports; + std::set<std::string> invokeSigs; FixInvokeFunctionNamesWalker(Module& _wasm) : wasm(_wasm) {} @@ -791,7 +795,7 @@ struct FixInvokeFunctionNamesWalker // This function converts the names of invoke wrappers based on their lowered // argument types and a return type. In the example above, the resulting new // wrapper name becomes "invoke_vii". - static Name fixEmExceptionInvoke(const Name& name, const std::string& sig) { + Name fixEmExceptionInvoke(const Name& name, const std::string& sig) { std::string nameStr = name.c_str(); if (nameStr.front() == '"' && nameStr.back() == '"') { nameStr = nameStr.substr(1, nameStr.size() - 2); @@ -800,10 +804,11 @@ struct FixInvokeFunctionNamesWalker return name; } std::string sigWoOrigFunc = sig.front() + sig.substr(2, sig.size() - 2); + invokeSigs.insert(sigWoOrigFunc); return Name("invoke_" + sigWoOrigFunc); } - static Name fixEmEHSjLjNames(const Name& name, const std::string& sig) { + Name fixEmEHSjLjNames(const Name& name, const std::string& sig) { if (name == "emscripten_longjmp_jmpbuf") { return "emscripten_longjmp"; } @@ -843,6 +848,9 @@ struct FixInvokeFunctionNamesWalker void EmscriptenGlueGenerator::fixInvokeFunctionNames() { FixInvokeFunctionNamesWalker walker(wasm); walker.walkModule(&wasm); + for (auto sig : walker.invokeSigs) { + generateDynCallThunk(sig); + } } template<class C> void printSet(std::ostream& o, C& c) { |