summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/GenerateDynCalls.cpp52
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp4
-rw-r--r--src/wasm-emscripten.h8
-rw-r--r--src/wasm/wasm-emscripten.cpp11
-rw-r--r--test/passes/generate-dyncalls.txt27
-rw-r--r--test/passes/generate-dyncalls.wast10
9 files changed, 99 insertions, 18 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index ecf9d6a59..059f1d62c 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -28,6 +28,7 @@ set(passes_SOURCES
ExtractFunction.cpp
Flatten.cpp
FuncCastEmulation.cpp
+ GenerateDynCalls.cpp
I64ToI32Lowering.cpp
Inlining.cpp
InstrumentLocals.cpp
diff --git a/src/passes/GenerateDynCalls.cpp b/src/passes/GenerateDynCalls.cpp
new file mode 100644
index 000000000..b46fdd843
--- /dev/null
+++ b/src/passes/GenerateDynCalls.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Create `dynCall` helper functions used by emscripten. These allow JavaScript
+// to call back into WebAssembly given a function pointer (table index). These
+// are used primarily to implement the `invoke` functions which in turn are used
+// to implment exceptions handling and setjmp/longjmp. Creates one for each
+// signature in the indirect function table.
+//
+
+#include "abi/js.h"
+#include "asm_v_wasm.h"
+#include "ir/import-utils.h"
+#include "pass.h"
+#include "support/debug.h"
+#include "wasm-emscripten.h"
+
+#define DEBUG_TYPE "generate-dyncalls"
+
+namespace wasm {
+
+struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
+
+ void visitTable(Table* table) {
+ if (table->segments.size() > 0) {
+ EmscriptenGlueGenerator generator(*getModule());
+ std::vector<Name> tableSegmentData;
+ for (const auto& indirectFunc : table->segments[0].data) {
+ generator.generateDynCallThunk(
+ getModule()->getFunction(indirectFunc)->sig);
+ }
+ }
+ }
+};
+
+Pass* createGenerateDynCallsPass() { return new GenerateDynCalls; }
+
+} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 6dcc58b50..d94e454c3 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -143,6 +143,9 @@ void PassRegistry::registerPasses() {
createFuncCastEmulationPass);
registerPass(
"func-metrics", "reports function metrics", createFunctionMetricsPass);
+ registerPass("generate-dyncalls",
+ "generate dynCall fuctions used by emscripten ABI",
+ createGenerateDynCallsPass);
registerPass(
"generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
registerPass(
diff --git a/src/passes/passes.h b/src/passes/passes.h
index a22e979af..89b0c0d01 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -48,6 +48,7 @@ Pass* createFlattenPass();
Pass* createFuncCastEmulationPass();
Pass* createFullPrinterPass();
Pass* createFunctionMetricsPass();
+Pass* createGenerateDynCallsPass();
Pass* createGenerateStackIRPass();
Pass* createI64ToI32LoweringPass();
Pass* createInlineMainPass();
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index cc57c9311..8ca10b79b 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -287,7 +287,9 @@ int main(int argc, const char* argv[]) {
if (!standaloneWasm) {
// If not standalone wasm then JS is relevant and we need dynCalls.
- generator.generateDynCallThunks();
+ PassRunner passRunner(&wasm);
+ passRunner.add("generate-dyncalls");
+ passRunner.run();
// This is also not needed in standalone mode since standalone mode uses
// crt1.c to invoke the main and is aware of __main_argc_argv mangling.
generator.renameMainArgcArgv();
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index ba956ee39..395c76a16 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -40,10 +40,6 @@ public:
Function* generateAssignGOTEntriesFunction();
void generatePostInstantiateFunction();
- // Create thunks for use with emscripten Runtime.dynCall. Creates one for each
- // signature in the indirect function table.
- void generateDynCallThunks();
-
// Remove the import of a mutable __stack_pointer and instead initialize the
// stack pointer from an immutable import.
void internalizeStackPointerGlobal();
@@ -66,6 +62,8 @@ public:
// the file).
void separateDataSegments(Output* outfile, Address base);
+ void generateDynCallThunk(Signature sig);
+
private:
Module& wasm;
Builder builder;
@@ -76,8 +74,6 @@ private:
// Used by generateDynCallThunk to track all the dynCall functions created
// so far.
std::unordered_set<Signature> sigs;
-
- void generateDynCallThunk(Signature sig);
};
} // namespace wasm
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index f37bfe907..e4664e645 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -171,17 +171,6 @@ void EmscriptenGlueGenerator::generateDynCallThunk(Signature sig) {
exportFunction(wasm, f->name, true);
}
-void EmscriptenGlueGenerator::generateDynCallThunks() {
- Builder builder(wasm);
- std::vector<Name> tableSegmentData;
- if (wasm.table.segments.size() > 0) {
- tableSegmentData = wasm.table.segments[0].data;
- }
- for (const auto& indirectFunc : tableSegmentData) {
- generateDynCallThunk(wasm.getFunction(indirectFunc)->sig);
- }
-}
-
// 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.
diff --git a/test/passes/generate-dyncalls.txt b/test/passes/generate-dyncalls.txt
new file mode 100644
index 000000000..413733ea8
--- /dev/null
+++ b/test/passes/generate-dyncalls.txt
@@ -0,0 +1,27 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $i32_=>_i32 (func (param i32) (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_i" (func $dynCall_i))
+ (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_i (param $fptr i32) (result i32)
+ (call_indirect (type $none_=>_i32)
+ (local.get $fptr)
+ )
+ )
+ (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-dyncalls.wast b/test/passes/generate-dyncalls.wast
new file mode 100644
index 000000000..6fbfcc331
--- /dev/null
+++ b/test/passes/generate-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)
+)