diff options
Diffstat (limited to 'src/passes/ReplaceStackPointer.cpp')
-rw-r--r-- | src/passes/ReplaceStackPointer.cpp | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/passes/ReplaceStackPointer.cpp b/src/passes/ReplaceStackPointer.cpp new file mode 100644 index 000000000..d6a85c3e2 --- /dev/null +++ b/src/passes/ReplaceStackPointer.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ + +// +// Convert llvm's stack pointer usage from from global.get/global.set into +// cals to external stackSave/stackRestore. +// This is needed to emscripten SIDE_MODULE code where mutable global imports +// are not yet permitted by default. +// + +#include "abi/js.h" +#include "ir/import-utils.h" +#include "pass.h" +#include "support/debug.h" +#include "wasm-emscripten.h" + +#define DEBUG_TYPE "binary" + +namespace wasm { + +static Name STACK_SAVE("stackSave"); +static Name STACK_RESTORE("stackRestore"); + +struct ReplaceStackPointer + : public WalkerPass<PostWalker<ReplaceStackPointer>> { + void visitGlobalGet(GlobalGet* curr) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { + needStackSave = true; + if (!builder) { + builder = make_unique<Builder>(*getModule()); + } + replaceCurrent(builder->makeCall(STACK_SAVE, {}, Type::i32)); + } + } + + void visitGlobalSet(GlobalSet* curr) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { + needStackRestore = true; + if (!builder) { + builder = make_unique<Builder>(*getModule()); + } + replaceCurrent( + builder->makeCall(STACK_RESTORE, {curr->value}, Type::none)); + } + } + + void doWalkModule(Module* module) { + stackPointer = getStackPointerGlobal(*module); + if (!stackPointer) { + BYN_DEBUG(std::cerr << "no stack pointer found\n"); + return; + } + BYN_DEBUG(std::cerr << "stack pointer found\n"); + super::doWalkModule(module); + if (needStackSave) { + ensureFunctionImport( + module, STACK_SAVE, Signature(Type::none, Type::i32)); + } + if (needStackRestore) { + ensureFunctionImport( + module, STACK_RESTORE, Signature(Type::i32, Type::none)); + } + // Finally remove the stack pointer global itself. This avoids importing + // a mutable global. + module->removeGlobal(stackPointer->name); + } + + void ensureFunctionImport(Module* module, Name name, Signature sig) { + ImportInfo info(*module); + if (info.getImportedFunction(ENV, name)) { + return; + } + auto import = new Function; + import->name = name; + import->module = ENV; + import->base = name; + import->sig = sig; + module->addFunction(import); + } + +private: + std::unique_ptr<Builder> builder; + Global* stackPointer = nullptr; + bool needStackSave = false; + bool needStackRestore = false; +}; + +Pass* createReplaceStackPointerPass() { return new ReplaceStackPointer; } + +} // namespace wasm |