summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp21
-rw-r--r--src/wasm-emscripten.h4
-rw-r--r--src/wasm/wasm-emscripten.cpp71
3 files changed, 82 insertions, 14 deletions
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index 6814ae032..1a3499757 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -155,11 +155,6 @@ int main(int argc, const char *argv[]) {
dataSize = dataEndConst->value.geti32() - globalBase;
}
- std::vector<Name> initializerFunctions;
- if (wasm.getFunctionOrNull("__wasm_call_ctors")) {
- initializerFunctions.push_back("__wasm_call_ctors");
- }
-
EmscriptenGlueGenerator generator(wasm);
generator.fixInvokeFunctionNames();
@@ -171,10 +166,24 @@ int main(int argc, const char *argv[]) {
passRunner.run();
}
- if (!isSideModule) {
+ std::vector<Name> initializerFunctions;
+
+ if (isSideModule) {
+ generator.replaceStackPointerGlobal();
+ // rename __wasm_call_ctors to __post_instantiate which is what
+ // emscripten expects.
+ // TODO(sbc): Unify these two names
+ if (Export* ex = wasm.getExportOrNull("__wasm_call_ctors")) {
+ ex->name = "__post_instantiate";
+ }
+ } else {
generator.generateRuntimeFunctions();
generator.generateMemoryGrowthFunction();
+ if (wasm.getFunctionOrNull("__wasm_call_ctors")) {
+ initializerFunctions.push_back("__wasm_call_ctors");
+ }
}
+
generator.generateDynCallThunks();
generator.generateJSCallThunks(numReservedFunctionPointers);
std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions, numReservedFunctionPointers);
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index aa42b86b2..c15a4b8af 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -41,6 +41,10 @@ public:
// signature in the indirect function table.
void generateDynCallThunks();
+ // Convert stack pointer access from get_global/set_global to calling save
+ // and restore functions.
+ void replaceStackPointerGlobal();
+
// Create thunks to support emscripten's addFunction functionality. Creates (#
// of reserved function pointers) thunks for each indirectly called function
// signature.
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index 14104c1eb..a43fc1fe7 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -25,6 +25,7 @@
#include "wasm-traversal.h"
#include "wasm.h"
#include "ir/function-type-utils.h"
+#include "ir/import-utils.h"
#include "ir/module-utils.h"
namespace wasm {
@@ -32,7 +33,10 @@ namespace wasm {
cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
cashew::IString EM_JS_PREFIX("__em_js__");
-static constexpr const char* dummyFunction = "__wasm_nullptr";
+static Name STACK_SAVE("stackSave"),
+ STACK_RESTORE("stackRestore"),
+ STACK_ALLOC("stackAlloc"),
+ DUMMY_FUNC("__wasm_nullptr");
void addExportedFunction(Module& wasm, Function* function) {
wasm.addFunction(function);
@@ -80,10 +84,9 @@ Expression* EmscriptenGlueGenerator::generateStoreStackPointer(Expression* value
}
void EmscriptenGlueGenerator::generateStackSaveFunction() {
- Name name("stackSave");
std::vector<NameType> params { };
Function* function = builder.makeFunction(
- name, std::move(params), i32, {}
+ STACK_SAVE, std::move(params), i32, {}
);
function->body = generateLoadStackPointer();
@@ -92,10 +95,9 @@ void EmscriptenGlueGenerator::generateStackSaveFunction() {
}
void EmscriptenGlueGenerator::generateStackAllocFunction() {
- Name name("stackAlloc");
std::vector<NameType> params { { "0", i32 } };
Function* function = builder.makeFunction(
- name, std::move(params), i32, { { "1", i32 } }
+ STACK_ALLOC, std::move(params), i32, { { "1", i32 } }
);
Expression* loadStack = generateLoadStackPointer();
GetLocal* getSizeArg = builder.makeGetLocal(0, i32);
@@ -118,10 +120,9 @@ void EmscriptenGlueGenerator::generateStackAllocFunction() {
}
void EmscriptenGlueGenerator::generateStackRestoreFunction() {
- Name name("stackRestore");
std::vector<NameType> params { { "0", i32 } };
Function* function = builder.makeFunction(
- name, std::move(params), none, {}
+ STACK_RESTORE, std::move(params), none, {}
);
GetLocal* getArg = builder.makeGetLocal(0, i32);
Expression* store = generateStoreStackPointer(getArg);
@@ -182,7 +183,7 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
tableSegmentData = wasm.table.segments[0].data;
}
for (const auto& indirectFunc : tableSegmentData) {
- if (indirectFunc == dummyFunction) {
+ if (indirectFunc == DUMMY_FUNC) {
continue;
}
std::string sig = getSig(wasm.getFunction(indirectFunc));
@@ -207,6 +208,60 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
}
}
+static Function* ensureFunctionImport(Module* module, Name name, std::string sig) {
+ // Then see if its already imported
+ ImportInfo info(*module);
+ if (Function* f = info.getImportedFunction(ENV, name)) {
+ return f;
+ }
+ // Failing that create a new function import.
+ auto import = new Function;
+ import->name = name;
+ import->module = ENV;
+ import->base = name;
+ auto* functionType = ensureFunctionType(sig, module);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ module->addFunction(import);
+ return import;
+}
+
+struct RemoveStackPointer : public PostWalker<RemoveStackPointer> {
+ RemoveStackPointer(Global* StackPointer) : StackPointer(StackPointer) {}
+
+ void visitGetGlobal(GetGlobal* curr) {
+ if (getModule()->getGlobalOrNull(curr->name) == StackPointer) {
+ ensureFunctionImport(getModule(), STACK_SAVE, "i");
+ if (!builder) builder = make_unique<Builder>(*getModule());
+ replaceCurrent(builder->makeCall(STACK_SAVE, {}, i32));
+ }
+ }
+
+ void visitSetGlobal(SetGlobal* curr) {
+ if (getModule()->getGlobalOrNull(curr->name) == StackPointer) {
+ ensureFunctionImport(getModule(), STACK_RESTORE, "vi");
+ if (!builder) builder = make_unique<Builder>(*getModule());
+ replaceCurrent(builder->makeCall(STACK_RESTORE, {curr->value}, none));
+ }
+ }
+
+private:
+ std::unique_ptr<Builder> builder;
+ Global* StackPointer;
+};
+
+void EmscriptenGlueGenerator::replaceStackPointerGlobal() {
+ Global* stackPointer = getStackPointerGlobal();
+
+ // Replace all uses of stack pointer global
+ RemoveStackPointer walker(stackPointer);
+ walker.walkModule(&wasm);
+
+ // Finally remove the stack pointer global itself. This avoids importing
+ // a mutable global.
+ wasm.removeGlobal(stackPointer->name);
+}
+
struct JSCallWalker : public PostWalker<JSCallWalker> {
Module &wasm;
JSCallWalker(Module &_wasm) : wasm(_wasm) {