summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/GenerateDynCalls.cpp92
-rw-r--r--src/wasm-emscripten.h5
-rw-r--r--src/wasm/wasm-emscripten.cpp66
-rw-r--r--test/lld/duplicate_imports.wat.out26
-rw-r--r--test/lld/shared_longjmp.wat.out14
-rw-r--r--test/passes/generate-dyncalls.txt11
-rw-r--r--test/passes/generate-dyncalls.wast1
7 files changed, 129 insertions, 86 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) {
diff --git a/test/lld/duplicate_imports.wat.out b/test/lld/duplicate_imports.wat.out
index 6467c2bab..fcc03c13a 100644
--- a/test/lld/duplicate_imports.wat.out
+++ b/test/lld/duplicate_imports.wat.out
@@ -1,11 +1,13 @@
(module
+ (type $i32_f32_f64_=>_f32 (func (param i32 f32 f64) (result f32)))
+ (type $i32_f64_f64_=>_f32 (func (param i32 f64 f64) (result f32)))
(type $none_=>_none (func))
(type $none_=>_i32 (func (result i32)))
(type $i32_=>_i32 (func (param i32) (result i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $i64_=>_i32 (func (param i64) (result i32)))
- (type $i32_f32_f64_=>_f32 (func (param i32 f32 f64) (result f32)))
- (type $i32_f64_f64_=>_f32 (func (param i32 f64 f64) (result f32)))
+ (type $f32_f64_=>_f32 (func (param f32 f64) (result f32)))
+ (type $f64_f64_=>_f32 (func (param f64 f64) (result f32)))
(import "env" "puts" (func $puts1 (param i32) (result i32)))
(import "env" "invoke_ffd" (func $invoke_ffd (param i32 f32 f64) (result f32)))
(import "env" "invoke_ffd" (func $invoke_ffd2 (param i32 f64 f64) (result f32)))
@@ -21,6 +23,8 @@
(export "main" (func $main))
(export "__heap_base" (global $global$1))
(export "__data_end" (global $global$2))
+ (export "dynCall_ffd" (func $dynCall_ffd))
+ (export "dynCall_fdd" (func $dynCall_fdd))
(func $main (result i32)
(drop
(call $puts1
@@ -32,6 +36,20 @@
(func $__wasm_call_ctors
(nop)
)
+ (func $dynCall_ffd (param $fptr i32) (param $0 f32) (param $1 f64) (result f32)
+ (call_indirect (type $f32_f64_=>_f32)
+ (local.get $0)
+ (local.get $1)
+ (local.get $fptr)
+ )
+ )
+ (func $dynCall_fdd (param $fptr i32) (param $0 f64) (param $1 f64) (result f32)
+ (call_indirect (type $f64_f64_=>_f32)
+ (local.get $0)
+ (local.get $1)
+ (local.get $fptr)
+ )
+ )
(func $legalfunc$puts2 (param $0 i64) (result i32)
(call $legalimport$puts2
(i32.wrap_i64
@@ -61,7 +79,9 @@
],
"exports": [
"__wasm_call_ctors",
- "main"
+ "main",
+ "dynCall_ffd",
+ "dynCall_fdd"
],
"namedGlobals": {
"__heap_base" : "66128",
diff --git a/test/lld/shared_longjmp.wat.out b/test/lld/shared_longjmp.wat.out
index cc42f7368..7d987454a 100644
--- a/test/lld/shared_longjmp.wat.out
+++ b/test/lld/shared_longjmp.wat.out
@@ -143,13 +143,6 @@
)
(unreachable)
)
- (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
- (call_indirect (type $i32_i32_=>_none)
- (local.get $0)
- (local.get $1)
- (local.get $fptr)
- )
- )
(func $__assign_got_enties
(global.set $gimport$13
(call $g$__THREW__)
@@ -161,6 +154,13 @@
(call $fp$emscripten_longjmp_jmpbuf$vii)
)
)
+ (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
+ (call_indirect (type $i32_i32_=>_none)
+ (local.get $0)
+ (local.get $1)
+ (local.get $fptr)
+ )
+ )
(func $__post_instantiate
(call $__assign_got_enties)
(call $0)
diff --git a/test/passes/generate-dyncalls.txt b/test/passes/generate-dyncalls.txt
index 413733ea8..64a04de86 100644
--- a/test/passes/generate-dyncalls.txt
+++ b/test/passes/generate-dyncalls.txt
@@ -1,12 +1,16 @@
(module
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
(type $none_=>_i32 (func (result i32)))
(type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
(type $i32_=>_i32 (func (param i32) (result i32)))
(type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (import "env" "invoke_vii" (func $invoke_vii (param i32 i32 i32)))
(table $0 2 2 funcref)
(elem (i32.const 0) $f1 $f2)
(export "dynCall_i" (func $dynCall_i))
(export "dynCall_ji" (func $dynCall_ji))
+ (export "dynCall_vii" (func $dynCall_vii))
(func $f1 (result i32)
(i32.const 1024)
)
@@ -24,4 +28,11 @@
(local.get $fptr)
)
)
+ (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
+ (call_indirect (type $i32_i32_=>_none)
+ (local.get $0)
+ (local.get $1)
+ (local.get $fptr)
+ )
+ )
)
diff --git a/test/passes/generate-dyncalls.wast b/test/passes/generate-dyncalls.wast
index 6fbfcc331..551d52a21 100644
--- a/test/passes/generate-dyncalls.wast
+++ b/test/passes/generate-dyncalls.wast
@@ -1,4 +1,5 @@
(module
+ (import "env" "invoke_vii" (func $invoke_vii (param i32 i32 i32)))
(func $f1 (result i32)
(i32.const 1024)
)