diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 21 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 71 |
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) { |