summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Clegg <sbc@chromium.org>2019-05-10 14:05:16 -0700
committerGitHub <noreply@github.com>2019-05-10 14:05:16 -0700
commit70434ef31994391ae28c4aaaffd0d4f470da7fdc (patch)
tree0c39bc7be6901d9c32c28c2d7f7d4b131f5d81fb
parent4b35f384fe753f06c22a04bfa1be056e92f67739 (diff)
downloadbinaryen-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.md5
-rw-r--r--src/wasm-emscripten.h4
-rw-r--r--src/wasm/wasm-emscripten.cpp66
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) {