summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/GenerateDynCalls.cpp7
-rw-r--r--src/passes/pass.cpp5
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp30
-rw-r--r--src/wasm-emscripten.h15
-rw-r--r--src/wasm/wasm-emscripten.cpp20
-rw-r--r--test/passes/generate-i64-dyncalls.txt20
-rw-r--r--test/passes/generate-i64-dyncalls.wast10
8 files changed, 93 insertions, 15 deletions
diff --git a/src/passes/GenerateDynCalls.cpp b/src/passes/GenerateDynCalls.cpp
index b46fdd843..5a602bd79 100644
--- a/src/passes/GenerateDynCalls.cpp
+++ b/src/passes/GenerateDynCalls.cpp
@@ -34,10 +34,12 @@
namespace wasm {
struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
+ GenerateDynCalls(bool onlyI64) : onlyI64(onlyI64) {}
void visitTable(Table* 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(
@@ -45,8 +47,11 @@ struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
}
}
}
+
+ bool onlyI64;
};
-Pass* createGenerateDynCallsPass() { return new GenerateDynCalls; }
+Pass* createGenerateDynCallsPass() { return new GenerateDynCalls(false); }
+Pass* createGenerateI64DynCallsPass() { return new GenerateDynCalls(true); }
} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 73e5094e8..62c4c6452 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -146,6 +146,11 @@ void PassRegistry::registerPasses() {
registerPass("generate-dyncalls",
"generate dynCall fuctions used by emscripten ABI",
createGenerateDynCallsPass);
+ registerPass("generate-i64-dyncalls",
+ "generate dynCall functions used by emscripten ABI, but only for "
+ "functions with i64 in their signature (which cannot be invoked "
+ "via the wasm table without JavaScript BigInt support).",
+ createGenerateI64DynCallsPass);
registerPass(
"generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
registerPass(
diff --git a/src/passes/passes.h b/src/passes/passes.h
index 5eb6cef3c..bee30eebc 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -49,6 +49,7 @@ Pass* createFuncCastEmulationPass();
Pass* createFullPrinterPass();
Pass* createFunctionMetricsPass();
Pass* createGenerateDynCallsPass();
+Pass* createGenerateI64DynCallsPass();
Pass* createGenerateStackIRPass();
Pass* createI64ToI32LoweringPass();
Pass* createInlineMainPass();
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index 1d1ea2247..49f8beabf 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -58,6 +58,8 @@ int main(int argc, const char* argv[]) {
bool standaloneWasm = false;
// TODO: remove after https://github.com/WebAssembly/binaryen/issues/3043
bool minimizeWasmChanges = false;
+ bool noDynCalls = false;
+ bool onlyI64DynCalls = false;
ToolOptions options("wasm-emscripten-finalize",
"Performs Emscripten-specific transforms on .wasm files");
@@ -174,6 +176,18 @@ int main(int argc, const char* argv[]) {
[&minimizeWasmChanges](Options* o, const std::string&) {
minimizeWasmChanges = true;
})
+ .add("--no-dyncalls",
+ "",
+ "",
+ Options::Arguments::Zero,
+ [&noDynCalls](Options* o, const std::string&) { noDynCalls = true; })
+ .add("--dyncalls-i64",
+ "",
+ "",
+ Options::Arguments::Zero,
+ [&onlyI64DynCalls](Options* o, const std::string&) {
+ onlyI64DynCalls = true;
+ })
.add_positional("INFILE",
Options::Arguments::One,
[&infile](Options* o, const std::string& argument) {
@@ -231,9 +245,11 @@ int main(int argc, const char* argv[]) {
}
EmscriptenGlueGenerator generator(wasm);
- generator.setStandalone(standaloneWasm);
- generator.setSideModule(sideModule);
- generator.setMinimizeWasmChanges(minimizeWasmChanges);
+ generator.standalone = standaloneWasm;
+ generator.sideModule = sideModule;
+ generator.minimizeWasmChanges = minimizeWasmChanges;
+ generator.onlyI64DynCalls = onlyI64DynCalls;
+ generator.noDynCalls = noDynCalls;
generator.fixInvokeFunctionNames();
@@ -278,9 +294,13 @@ int main(int argc, const char* argv[]) {
passRunner.add("emscripten-pic-main-module");
}
- if (!standaloneWasm) {
+ if (!noDynCalls && !standaloneWasm) {
// If not standalone wasm then JS is relevant and we need dynCalls.
- passRunner.add("generate-dyncalls");
+ if (onlyI64DynCalls) {
+ passRunner.add("generate-i64-dyncalls");
+ } else {
+ passRunner.add("generate-dyncalls");
+ }
}
// Legalize the wasm, if BigInts don't make that moot.
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index fe8b8ed36..0303af053 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -33,12 +33,6 @@ public:
: wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
useStackPointerGlobal(stackPointerOffset == 0) {}
- void setStandalone(bool standalone_) { standalone = standalone_; }
- void setSideModule(bool sideModule_) { sideModule = sideModule_; }
- void setMinimizeWasmChanges(bool minimizeWasmChanges_) {
- minimizeWasmChanges = minimizeWasmChanges_;
- }
-
Function* generateMemoryGrowthFunction();
Function* generateAssignGOTEntriesFunction();
void generatePostInstantiateFunction();
@@ -67,14 +61,17 @@ public:
void generateDynCallThunk(Signature sig);
+ bool standalone = false;
+ bool sideModule = false;
+ bool minimizeWasmChanges = false;
+ bool noDynCalls = false;
+ bool onlyI64DynCalls = false;
+
private:
Module& wasm;
Builder builder;
Address stackPointerOffset;
bool useStackPointerGlobal;
- bool standalone;
- bool sideModule;
- bool minimizeWasmChanges;
// Used by generateDynCallThunk to track all the dynCall functions created
// so far.
std::unordered_set<Signature> sigs;
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index fd0560fd9..c287087c9 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -143,7 +143,27 @@ inline void exportFunction(Module& wasm, Name name, bool must_export) {
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
}
diff --git a/test/passes/generate-i64-dyncalls.txt b/test/passes/generate-i64-dyncalls.txt
new file mode 100644
index 000000000..c9a282d84
--- /dev/null
+++ b/test/passes/generate-i64-dyncalls.txt
@@ -0,0 +1,20 @@
+(module
+ (type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+ (export "dynCall_ji" (func $dynCall_ji))
+ (func $f1 (result i32)
+ (i32.const 1024)
+ )
+ (func $f2 (param $0 i32) (result i64)
+ (i64.const 42)
+ )
+ (func $dynCall_ji (param $fptr i32) (param $0 i32) (result i64)
+ (call_indirect (type $i32_=>_i64)
+ (local.get $0)
+ (local.get $fptr)
+ )
+ )
+)
diff --git a/test/passes/generate-i64-dyncalls.wast b/test/passes/generate-i64-dyncalls.wast
new file mode 100644
index 000000000..6fbfcc331
--- /dev/null
+++ b/test/passes/generate-i64-dyncalls.wast
@@ -0,0 +1,10 @@
+(module
+ (func $f1 (result i32)
+ (i32.const 1024)
+ )
+ (func $f2 (param i32) (result i64)
+ (i64.const 42)
+ )
+ (table 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+)