/* * 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 "replace-stack-pointer" namespace wasm { static Name STACK_SAVE("stackSave"); static Name STACK_RESTORE("stackRestore"); struct ReplaceStackPointer : public WalkerPass> { void visitGlobalGet(GlobalGet* curr) { if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { needStackSave = true; if (!builder) { builder = make_unique(*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(*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; Global* stackPointer = nullptr; bool needStackSave = false; bool needStackRestore = false; }; Pass* createReplaceStackPointerPass() { return new ReplaceStackPointer; } } // namespace wasm