summaryrefslogtreecommitdiff
path: root/src/passes/GenerateDynCalls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/GenerateDynCalls.cpp')
-rw-r--r--src/passes/GenerateDynCalls.cpp92
1 files changed, 87 insertions, 5 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); }