diff options
author | Sam Clegg <sbc@chromium.org> | 2020-05-20 17:00:36 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-20 14:00:36 -0700 |
commit | e4d1e203c8bf8577e645dbf7ab265d1ec1c68bee (patch) | |
tree | cbf5da712297bf4d8af0bdd21c023e528dd2b03b /src | |
parent | 677a9b8e29ac9088c361b9b20f6d513c76355106 (diff) | |
download | binaryen-e4d1e203c8bf8577e645dbf7ab265d1ec1c68bee.tar.gz binaryen-e4d1e203c8bf8577e645dbf7ab265d1ec1c68bee.tar.bz2 binaryen-e4d1e203c8bf8577e645dbf7ab265d1ec1c68bee.zip |
Remove stackSave/stackAlloc/stackRestore code generation (#2852)
These are now implemented in assembly as part of emscripten's
compiler-rt.
See: https://github.com/emscripten-core/emscripten/pull/11166
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 1 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 6 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 201 |
3 files changed, 43 insertions, 165 deletions
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index ce1729bb9..f7de3af3f 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -251,7 +251,6 @@ int main(int argc, const char* argv[]) { generator.generatePostInstantiateFunction(); } else { BYN_TRACE("finalizing as regular module\n"); - generator.generateRuntimeFunctions(); generator.internalizeStackPointerGlobal(); generator.generateMemoryGrowthFunction(); // For side modules these gets called via __post_instantiate diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index 5ede78375..0fca27056 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -36,7 +36,6 @@ public: void setStandalone(bool standalone_) { standalone = standalone_; } void setSideModule(bool sideModule_) { sideModule = sideModule_; } - void generateRuntimeFunctions(); Function* generateMemoryGrowthFunction(); Function* generateAssignGOTEntriesFunction(); void generatePostInstantiateFunction(); @@ -80,12 +79,7 @@ private: // so far. std::unordered_set<Signature> sigs; - Expression* generateLoadStackPointer(); - Expression* generateStoreStackPointer(Function* func, Expression* value); void generateDynCallThunk(Signature sig); - void generateStackSaveFunction(); - void generateStackAllocFunction(); - void generateStackRestoreFunction(); void generateSetStackLimitFunction(); Name importStackOverflowHandler(); }; diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 34c1f02ee..1d58699ec 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -39,7 +39,6 @@ cashew::IString EM_JS_PREFIX("__em_js__"); static Name STACK_SAVE("stackSave"); static Name STACK_RESTORE("stackRestore"); -static Name STACK_ALLOC("stackAlloc"); static Name STACK_INIT("stack$init"); static Name STACK_LIMIT("__stack_limit"); static Name SET_STACK_LIMIT("__set_stack_limit"); @@ -82,146 +81,6 @@ Global* getStackPointerGlobal(Module& wasm) { return nullptr; } -Expression* EmscriptenGlueGenerator::generateLoadStackPointer() { - if (!useStackPointerGlobal) { - return builder.makeLoad( - /* bytes =*/4, - /* signed =*/false, - /* offset =*/stackPointerOffset, - /* align =*/4, - /* ptr =*/builder.makeConst(Literal(0)), - /* type =*/Type::i32); - } - Global* stackPointer = getStackPointerGlobal(wasm); - if (!stackPointer) { - Fatal() << "stack pointer global not found"; - } - return builder.makeGlobalGet(stackPointer->name, Type::i32); -} - -inline Expression* stackBoundsCheck(Builder& builder, - Function* func, - Expression* value, - Global* stackPointer, - Global* stackLimit, - Name handlerName) { - // Add a local to store the value of the expression. We need the value twice: - // once to check if it has overflowed, and again to assign to store it. - auto newSP = Builder::addVar(func, stackPointer->type); - // If we imported a handler, call it. That can show a nice error in JS. - // Otherwise, just trap. - Expression* handler; - if (handlerName.is()) { - handler = builder.makeCall(handlerName, {}, Type::none); - } else { - handler = builder.makeUnreachable(); - } - // (if (i32.lt_u (local.tee $newSP (...value...)) (global.get $__stack_limit)) - auto check = - builder.makeIf(builder.makeBinary( - BinaryOp::LtUInt32, - builder.makeLocalTee(newSP, value, stackPointer->type), - builder.makeGlobalGet(stackLimit->name, stackLimit->type)), - handler); - // (global.set $__stack_pointer (local.get $newSP)) - auto newSet = builder.makeGlobalSet( - stackPointer->name, builder.makeLocalGet(newSP, stackPointer->type)); - return builder.blockify(check, newSet); -} - -Expression* -EmscriptenGlueGenerator::generateStoreStackPointer(Function* func, - Expression* value) { - BYN_TRACE("generateStoreStackPointer\n"); - if (!useStackPointerGlobal) { - return builder.makeStore( - /* bytes =*/4, - /* offset =*/stackPointerOffset, - /* align =*/4, - /* ptr =*/builder.makeConst(Literal(0)), - /* value =*/value, - /* type =*/Type::i32); - } - Global* stackPointer = getStackPointerGlobal(wasm); - if (!stackPointer) { - Fatal() << "stack pointer global not found"; - } - if (auto* stackLimit = wasm.getGlobalOrNull(STACK_LIMIT)) { - return stackBoundsCheck(builder, - func, - value, - stackPointer, - stackLimit, - importStackOverflowHandler()); - } - return builder.makeGlobalSet(stackPointer->name, value); -} - -void EmscriptenGlueGenerator::generateStackSaveFunction() { - if (wasm.getExportOrNull(STACK_SAVE)) { - return; - } - BYN_TRACE("generateStackSaveFunction\n"); - std::vector<NameType> params{}; - Function* function = - builder.makeFunction(STACK_SAVE, std::move(params), Type::i32, {}); - - function->body = generateLoadStackPointer(); - - addExportedFunction(wasm, function); -} - -void EmscriptenGlueGenerator::generateStackAllocFunction() { - if (wasm.getExportOrNull(STACK_ALLOC)) { - return; - } - BYN_TRACE("generateStackAllocFunction\n"); - std::vector<NameType> params{{"0", Type::i32}}; - Function* function = builder.makeFunction( - STACK_ALLOC, std::move(params), Type::i32, {{"1", Type::i32}}); - Expression* loadStack = generateLoadStackPointer(); - LocalGet* getSizeArg = builder.makeLocalGet(0, Type::i32); - Binary* sub = builder.makeBinary(SubInt32, loadStack, getSizeArg); - const static uint32_t bitAlignment = 16; - const static uint32_t bitMask = bitAlignment - 1; - Const* subConst = builder.makeConst(Literal(~bitMask)); - Binary* maskedSub = builder.makeBinary(AndInt32, sub, subConst); - LocalSet* teeStackLocal = builder.makeLocalTee(1, maskedSub, Type::i32); - Expression* storeStack = generateStoreStackPointer(function, teeStackLocal); - - Block* block = builder.makeBlock(); - block->list.push_back(storeStack); - LocalGet* getStackLocal2 = builder.makeLocalGet(1, Type::i32); - block->list.push_back(getStackLocal2); - block->type = Type::i32; - function->body = block; - - addExportedFunction(wasm, function); -} - -void EmscriptenGlueGenerator::generateStackRestoreFunction() { - if (wasm.getExportOrNull(STACK_RESTORE)) { - return; - } - BYN_TRACE("generateStackRestoreFunction\n"); - std::vector<NameType> params{{"0", Type::i32}}; - Function* function = - builder.makeFunction(STACK_RESTORE, std::move(params), Type::none, {}); - LocalGet* getArg = builder.makeLocalGet(0, Type::i32); - Expression* store = generateStoreStackPointer(function, getArg); - - function->body = store; - - addExportedFunction(wasm, function); -} - -void EmscriptenGlueGenerator::generateRuntimeFunctions() { - BYN_TRACE("generateRuntimeFunctions\n"); - generateStackSaveFunction(); - generateStackAllocFunction(); - generateStackRestoreFunction(); -} - static Function* ensureFunctionImport(Module* module, Name name, Signature sig) { // See if its already imported. @@ -526,12 +385,21 @@ struct RemoveStackPointer : public PostWalker<RemoveStackPointer> { } } - bool needStackSave = false; - bool needStackRestore = false; + void visitModule(Module* curr) { + if (needStackSave) { + ensureFunctionImport(curr, STACK_SAVE, Signature(Type::none, Type::i32)); + } + if (needStackRestore) { + ensureFunctionImport( + curr, STACK_RESTORE, Signature(Type::i32, Type::none)); + } + } private: std::unique_ptr<Builder> builder; Global* stackPointer; + bool needStackSave = false; + bool needStackRestore = false; }; // lld can sometimes produce a build with an imported mutable __stack_pointer @@ -567,15 +435,7 @@ void EmscriptenGlueGenerator::replaceStackPointerGlobal() { } // Replace all uses of stack pointer global - RemoveStackPointer walker(stackPointer); - walker.walkModule(&wasm); - if (walker.needStackSave) { - ensureFunctionImport(&wasm, STACK_SAVE, Signature(Type::none, Type::i32)); - } - if (walker.needStackRestore) { - ensureFunctionImport( - &wasm, STACK_RESTORE, Signature(Type::i32, Type::none)); - } + RemoveStackPointer(stackPointer).walkModule(&wasm); // Finally remove the stack pointer global itself. This avoids importing // a mutable global. @@ -596,14 +456,39 @@ struct StackLimitEnforcer : public WalkerPass<PostWalker<StackLimitEnforcer>> { return new StackLimitEnforcer(stackPointer, stackLimit, builder, handler); } + Expression* stackBoundsCheck(Function* func, + Expression* value, + Global* stackPointer, + Global* stackLimit) { + // Add a local to store the value of the expression. We need the value + // twice: once to check if it has overflowed, and again to assign to store + // it. + auto newSP = Builder::addVar(func, stackPointer->type); + // If we imported a handler, call it. That can show a nice error in JS. + // Otherwise, just trap. + Expression* handlerExpr; + if (handler.is()) { + handlerExpr = builder.makeCall(handler, {}, Type::none); + } else { + handlerExpr = builder.makeUnreachable(); + } + // (if (i32.lt_u (local.tee $newSP (...val...)) (global.get $__stack_limit)) + auto check = builder.makeIf( + builder.makeBinary( + BinaryOp::LtUInt32, + builder.makeLocalTee(newSP, value, stackPointer->type), + builder.makeGlobalGet(stackLimit->name, stackLimit->type)), + handlerExpr); + // (global.set $__stack_pointer (local.get $newSP)) + auto newSet = builder.makeGlobalSet( + stackPointer->name, builder.makeLocalGet(newSP, stackPointer->type)); + return builder.blockify(check, newSet); + } + void visitGlobalSet(GlobalSet* curr) { if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { - replaceCurrent(stackBoundsCheck(builder, - getFunction(), - curr->value, - stackPointer, - stackLimit, - handler)); + replaceCurrent( + stackBoundsCheck(getFunction(), curr->value, stackPointer, stackLimit)); } } |