summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2020-10-02 09:25:15 -0700
committerGitHub <noreply@github.com>2020-10-02 09:25:15 -0700
commitecaa818922fe2571649a621a00f7f3c40ebb217a (patch)
treedd49e1a4f90beb6853ce9f8900b032cbdf54dd83 /src
parent42aec827c2233eb4adbb56c6d1b23d70399bfac1 (diff)
downloadbinaryen-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.cpp92
-rw-r--r--src/wasm-emscripten.h5
-rw-r--r--src/wasm/wasm-emscripten.cpp66
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) {